PageRenderTime 28ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/usr.bin/rdist/gram.y

https://bitbucket.org/cooljeanius/dragonflybsd
Happy | 508 lines | 458 code | 50 blank | 0 comment | 0 complexity | 4edda9260305b0993940052075ba0733 MD5 | raw file
  1. %{
  2. /*
  3. * Copyright (c) 1983, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. All advertising materials mentioning features or use of this software
  15. * must display the following acknowledgement:
  16. * This product includes software developed by the University of
  17. * California, Berkeley and its contributors.
  18. * 4. Neither the name of the University nor the names of its contributors
  19. * may be used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. *
  34. * @(#)gram.y 8.1 (Berkeley) 6/9/93
  35. * $FreeBSD: src/usr.bin/rdist/gram.y,v 1.6 1999/08/28 01:05:07 peter Exp $
  36. * $DragonFly: src/usr.bin/rdist/gram.y,v 1.5 2008/10/16 01:52:33 swildner Exp $
  37. */
  38. #include <sys/types.h>
  39. #include <limits.h>
  40. #include <regex.h>
  41. #include "defs.h"
  42. struct cmd *cmds = NULL;
  43. struct cmd *last_cmd;
  44. struct namelist *last_n;
  45. struct subcmd *last_sc;
  46. static char *makestr(char *);
  47. %}
  48. %term EQUAL 1
  49. %term LP 2
  50. %term RP 3
  51. %term SM 4
  52. %term ARROW 5
  53. %term COLON 6
  54. %term DCOLON 7
  55. %term NAME 8
  56. %term STRING 9
  57. %term INSTALL 10
  58. %term NOTIFY 11
  59. %term EXCEPT 12
  60. %term PATTERN 13
  61. %term SPECIAL 14
  62. %term OPTION 15
  63. %union {
  64. int intval;
  65. char *string;
  66. struct subcmd *subcmd;
  67. struct namelist *namel;
  68. }
  69. %type <intval> OPTION, options
  70. %type <string> NAME, STRING
  71. %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
  72. %type <namel> namelist, names, opt_namelist
  73. %%
  74. file: /* VOID */
  75. | file command
  76. ;
  77. command: NAME EQUAL namelist = {
  78. (void) lookup($1, INSERT, $3);
  79. }
  80. | namelist ARROW namelist cmdlist = {
  81. insert(NULL, $1, $3, $4);
  82. }
  83. | NAME COLON namelist ARROW namelist cmdlist = {
  84. insert($1, $3, $5, $6);
  85. }
  86. | namelist DCOLON NAME cmdlist = {
  87. append(NULL, $1, $3, $4);
  88. }
  89. | NAME COLON namelist DCOLON NAME cmdlist = {
  90. append($1, $3, $5, $6);
  91. }
  92. | error
  93. ;
  94. namelist: NAME = {
  95. $$ = makenl($1);
  96. }
  97. | LP names RP = {
  98. $$ = $2;
  99. }
  100. ;
  101. names: /* VOID */ {
  102. $$ = last_n = NULL;
  103. }
  104. | names NAME = {
  105. if (last_n == NULL)
  106. $$ = last_n = makenl($2);
  107. else {
  108. last_n->n_next = makenl($2);
  109. last_n = last_n->n_next;
  110. $$ = $1;
  111. }
  112. }
  113. ;
  114. cmdlist: /* VOID */ {
  115. $$ = last_sc = NULL;
  116. }
  117. | cmdlist cmd = {
  118. if (last_sc == NULL)
  119. $$ = last_sc = $2;
  120. else {
  121. last_sc->sc_next = $2;
  122. last_sc = $2;
  123. $$ = $1;
  124. }
  125. }
  126. ;
  127. cmd: INSTALL options opt_namelist SM = {
  128. struct namelist *nl;
  129. $1->sc_options = $2 | options;
  130. if ($3 != NULL) {
  131. nl = expand($3, E_VARS);
  132. if (nl) {
  133. if (nl->n_next != NULL)
  134. yyerror("only one name allowed\n");
  135. $1->sc_name = nl->n_name;
  136. free(nl);
  137. } else
  138. $1->sc_name = NULL;
  139. }
  140. $$ = $1;
  141. }
  142. | NOTIFY namelist SM = {
  143. if ($2 != NULL)
  144. $1->sc_args = expand($2, E_VARS);
  145. $$ = $1;
  146. }
  147. | EXCEPT namelist SM = {
  148. if ($2 != NULL)
  149. $1->sc_args = expand($2, E_ALL);
  150. $$ = $1;
  151. }
  152. | PATTERN namelist SM = {
  153. struct namelist *nl;
  154. regex_t rx;
  155. int val;
  156. char errbuf[_POSIX2_LINE_MAX];
  157. for (nl = $2; nl != NULL; nl = nl->n_next) {
  158. if ((val = regcomp(&rx, nl->n_name,
  159. REG_EXTENDED))) {
  160. regerror(val, &rx, errbuf,
  161. sizeof errbuf);
  162. yyerror(errbuf);
  163. }
  164. regfree(&rx);
  165. }
  166. $1->sc_args = expand($2, E_VARS);
  167. $$ = $1;
  168. }
  169. | SPECIAL opt_namelist STRING SM = {
  170. if ($2 != NULL)
  171. $1->sc_args = expand($2, E_ALL);
  172. $1->sc_name = $3;
  173. $$ = $1;
  174. }
  175. ;
  176. options: /* VOID */ = {
  177. $$ = 0;
  178. }
  179. | options OPTION = {
  180. $$ |= $2;
  181. }
  182. ;
  183. opt_namelist: /* VOID */ = {
  184. $$ = NULL;
  185. }
  186. | namelist = {
  187. $$ = $1;
  188. }
  189. ;
  190. %%
  191. int yylineno = 1;
  192. extern FILE *fin;
  193. int
  194. yylex(void)
  195. {
  196. static char yytext[INMAX];
  197. int c;
  198. char *cp1, *cp2;
  199. static char quotechars[] = "[]{}*?$";
  200. again:
  201. switch (c = getc(fin)) {
  202. case EOF: /* end of file */
  203. return(0);
  204. case '#': /* start of comment */
  205. while ((c = getc(fin)) != EOF && c != '\n')
  206. ;
  207. if (c == EOF)
  208. return(0);
  209. case '\n':
  210. yylineno++;
  211. case ' ':
  212. case '\t': /* skip blanks */
  213. goto again;
  214. case '=': /* EQUAL */
  215. return(EQUAL);
  216. case '(': /* LP */
  217. return(LP);
  218. case ')': /* RP */
  219. return(RP);
  220. case ';': /* SM */
  221. return(SM);
  222. case '-': /* -> */
  223. if ((c = getc(fin)) == '>')
  224. return(ARROW);
  225. ungetc(c, fin);
  226. c = '-';
  227. break;
  228. case '"': /* STRING */
  229. cp1 = yytext;
  230. cp2 = &yytext[INMAX - 1];
  231. for (;;) {
  232. if (cp1 >= cp2) {
  233. yyerror("command string too long\n");
  234. break;
  235. }
  236. c = getc(fin);
  237. if (c == EOF || c == '"')
  238. break;
  239. if (c == '\\') {
  240. if ((c = getc(fin)) == EOF) {
  241. *cp1++ = '\\';
  242. break;
  243. }
  244. }
  245. if (c == '\n') {
  246. yylineno++;
  247. c = ' '; /* can't send '\n' */
  248. }
  249. *cp1++ = c;
  250. }
  251. if (c != '"')
  252. yyerror("missing closing '\"'\n");
  253. *cp1 = '\0';
  254. yylval.string = makestr(yytext);
  255. return(STRING);
  256. case ':': /* : or :: */
  257. if ((c = getc(fin)) == ':')
  258. return(DCOLON);
  259. ungetc(c, fin);
  260. return(COLON);
  261. }
  262. cp1 = yytext;
  263. cp2 = &yytext[INMAX - 1];
  264. for (;;) {
  265. if (cp1 >= cp2) {
  266. yyerror("input line too long\n");
  267. break;
  268. }
  269. if (c == '\\') {
  270. if ((c = getc(fin)) != EOF) {
  271. if (any(c, quotechars))
  272. c |= QUOTE;
  273. } else {
  274. *cp1++ = '\\';
  275. break;
  276. }
  277. }
  278. *cp1++ = c;
  279. c = getc(fin);
  280. if (c == EOF || any(c, " \"'\t()=;:\n")) {
  281. ungetc(c, fin);
  282. break;
  283. }
  284. }
  285. *cp1 = '\0';
  286. if (yytext[0] == '-' && yytext[2] == '\0') {
  287. switch (yytext[1]) {
  288. case 'b':
  289. yylval.intval = COMPARE;
  290. return(OPTION);
  291. case 'R':
  292. yylval.intval = REMOVE;
  293. return(OPTION);
  294. case 'v':
  295. yylval.intval = VERIFY;
  296. return(OPTION);
  297. case 'w':
  298. yylval.intval = WHOLE;
  299. return(OPTION);
  300. case 'y':
  301. yylval.intval = YOUNGER;
  302. return(OPTION);
  303. case 'h':
  304. yylval.intval = FOLLOW;
  305. return(OPTION);
  306. case 'i':
  307. yylval.intval = IGNLNKS;
  308. return(OPTION);
  309. }
  310. }
  311. if (!strcmp(yytext, "install"))
  312. c = INSTALL;
  313. else if (!strcmp(yytext, "notify"))
  314. c = NOTIFY;
  315. else if (!strcmp(yytext, "except"))
  316. c = EXCEPT;
  317. else if (!strcmp(yytext, "except_pat"))
  318. c = PATTERN;
  319. else if (!strcmp(yytext, "special"))
  320. c = SPECIAL;
  321. else {
  322. yylval.string = makestr(yytext);
  323. return(NAME);
  324. }
  325. yylval.subcmd = makesubcmd(c);
  326. return(c);
  327. }
  328. int
  329. any(int c, char *str)
  330. {
  331. while (*str)
  332. if (c == *str++)
  333. return(1);
  334. return(0);
  335. }
  336. /*
  337. * Insert or append ARROW command to list of hosts to be updated.
  338. */
  339. void
  340. insert(char *label, struct namelist *files, struct namelist *hosts, struct subcmd *subcmds)
  341. {
  342. struct cmd *c, *prev, *nc;
  343. struct namelist *h, *next_h;
  344. files = expand(files, E_VARS|E_SHELL);
  345. hosts = expand(hosts, E_ALL);
  346. for (h = hosts; h != NULL; next_h = h->n_next, free(h), h = next_h) {
  347. /*
  348. * Search command list for an update to the same host.
  349. */
  350. for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
  351. if (strcmp(c->c_name, h->n_name) == 0) {
  352. do {
  353. prev = c;
  354. c = c->c_next;
  355. } while (c != NULL &&
  356. strcmp(c->c_name, h->n_name) == 0);
  357. break;
  358. }
  359. }
  360. /*
  361. * Insert new command to update host.
  362. */
  363. nc = ALLOC(cmd);
  364. if (nc == NULL)
  365. fatal("ran out of memory\n");
  366. nc->c_type = ARROW;
  367. nc->c_name = h->n_name;
  368. nc->c_label = label;
  369. nc->c_files = files;
  370. nc->c_cmds = subcmds;
  371. nc->c_next = c;
  372. if (prev == NULL)
  373. cmds = nc;
  374. else
  375. prev->c_next = nc;
  376. /* update last_cmd if appending nc to cmds */
  377. if (c == NULL)
  378. last_cmd = nc;
  379. }
  380. }
  381. /*
  382. * Append DCOLON command to the end of the command list since these are always
  383. * executed in the order they appear in the distfile.
  384. */
  385. void
  386. append(char *label, struct namelist *files, char *stamp, struct subcmd *subcmds)
  387. {
  388. struct cmd *c;
  389. c = ALLOC(cmd);
  390. if (c == NULL)
  391. fatal("ran out of memory\n");
  392. c->c_type = DCOLON;
  393. c->c_name = stamp;
  394. c->c_label = label;
  395. c->c_files = expand(files, E_ALL);
  396. c->c_cmds = subcmds;
  397. c->c_next = NULL;
  398. if (cmds == NULL)
  399. cmds = last_cmd = c;
  400. else {
  401. last_cmd->c_next = c;
  402. last_cmd = c;
  403. }
  404. }
  405. /*
  406. * Error printing routine in parser.
  407. */
  408. void
  409. yyerror(char *s)
  410. {
  411. ++nerrs;
  412. fflush(stdout);
  413. fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
  414. }
  415. /*
  416. * Return a copy of the string.
  417. */
  418. static char *
  419. makestr(char *str)
  420. {
  421. char *cp, *s;
  422. str = cp = malloc(strlen(s = str) + 1);
  423. if (cp == NULL)
  424. fatal("ran out of memory\n");
  425. while ((*cp++ = *s++))
  426. ;
  427. return(str);
  428. }
  429. /*
  430. * Allocate a namelist structure.
  431. */
  432. struct namelist *
  433. makenl(char *name)
  434. {
  435. struct namelist *nl;
  436. nl = ALLOC(namelist);
  437. if (nl == NULL)
  438. fatal("ran out of memory\n");
  439. nl->n_name = name;
  440. nl->n_next = NULL;
  441. return(nl);
  442. }
  443. /*
  444. * Make a sub command for lists of variables, commands, etc.
  445. */
  446. struct subcmd *
  447. makesubcmd(int type)
  448. {
  449. struct subcmd *sc;
  450. sc = ALLOC(subcmd);
  451. if (sc == NULL)
  452. fatal("ran out of memory\n");
  453. sc->sc_type = type;
  454. sc->sc_args = NULL;
  455. sc->sc_next = NULL;
  456. sc->sc_name = NULL;
  457. return(sc);
  458. }