copt.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. /*
  2. **************************************************************************
  3. *
  4. * Utility program to optimize the output of the BCC compiler
  5. *
  6. * Module: copt.c
  7. * Purpose: Optimize BCC assembler output
  8. * Entries: main
  9. *
  10. * This program is based on an idea from Christopher W. Fraser.
  11. *
  12. **************************************************************************
  13. *
  14. * Copyright (C) 1995,1996,1997 Gero Kuhlmann <gero@gkminix.han.de>
  15. *
  16. * This program is free software; you can redistribute it and/or modify
  17. * it under the terms of the GNU General Public License as published by
  18. * the Free Software Foundation; either version 2 of the License, or
  19. * any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. */
  30. /*
  31. #include "utility.h"
  32. #include "../../headers/general.h"
  33. #include "../../headers/version.h"
  34. */
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <ctype.h>
  39. #define KEEPCOMMENTS
  40. #define MAXLINE 1024
  41. #ifdef __BCC__
  42. #define HASHSIZE 107
  43. #else
  44. #define HASHSIZE 1999
  45. #endif
  46. #define NOCHAR '\177'
  47. #define VARNUM 10
  48. /* Struct containing each string of an input file */
  49. struct line_s {
  50. char *text;
  51. struct line_s *prev;
  52. struct line_s *next;
  53. int comment_flg;
  54. };
  55. /* Struct containing one rule */
  56. struct rule_s {
  57. struct line_s *old;
  58. struct line_s *new;
  59. struct rule_s *next;
  60. };
  61. /* Hash table to store strings in a space saving way */
  62. struct hash_s {
  63. char *text;
  64. struct hash_s *next;
  65. };
  66. /*
  67. * Global variables
  68. */
  69. static struct rule_s *first = NULL; /* first rule */
  70. static struct rule_s *last = NULL; /* last rule */
  71. static struct line_s *infile = NULL; /* list of strings in input file */
  72. static struct hash_s *htab[HASHSIZE]; /* string hash table */
  73. static int hash_init = 0; /* flag if hash table initialized */
  74. static char *vars[VARNUM]; /* variable table */
  75. static char *progname; /* program name */
  76. /*
  77. * Allocate memory and print error if none available
  78. */
  79. static void *mymalloc(int size)
  80. {
  81. void *p;
  82. if ((p = malloc(size)) == NULL) {
  83. fprintf(stderr, "%s: no memory\n", progname);
  84. exit(1);
  85. }
  86. return(p);
  87. }
  88. /*
  89. * Insert a string into the hash table. If the string is already in there
  90. * just return the pointer to that string.
  91. */
  92. static char *install(char *str, int slen)
  93. {
  94. struct hash_s *hp;
  95. char *chkstr;
  96. char *cp;
  97. unsigned int hashval;
  98. /* Clear the hashing table if not already done */
  99. if (!hash_init) {
  100. for (hashval = 0; hashval < HASHSIZE; hashval++)
  101. htab[hashval] = NULL;
  102. hash_init++;
  103. }
  104. /* Get check string */
  105. if (slen < 0)
  106. slen = strlen(str);
  107. chkstr = mymalloc(slen + 1);
  108. strncpy(chkstr, str, slen);
  109. chkstr[slen] = '\0';
  110. /* Determine hashing value of string */
  111. hashval = 0;
  112. for (cp = chkstr; *cp; cp++)
  113. hashval = hashval*75 + *cp;
  114. hashval %= HASHSIZE;
  115. /* Check if the string is already in the hashing table */
  116. for (hp = htab[hashval]; hp != NULL; hp = hp->next)
  117. if (!strcmp(chkstr, hp->text)) {
  118. free(chkstr);
  119. return(hp->text);
  120. }
  121. /* String is not in hash table, so create a new entry */
  122. hp = (struct hash_s *)mymalloc(sizeof(struct hash_s));
  123. hp->text = chkstr;
  124. hp->next = htab[hashval];
  125. htab[hashval] = hp;
  126. return(hp->text);
  127. }
  128. /*
  129. * Read one line from input file and skip all blanks at the beginning
  130. */
  131. static char *readline(FILE *fp)
  132. {
  133. static char buf[MAXLINE];
  134. char *cp;
  135. /* Read line from input file */
  136. if (fgets(buf, MAXLINE-1, fp) == NULL)
  137. return(NULL);
  138. buf[MAXLINE-1] = '\0';
  139. /* Delete trailing newline */
  140. if ((cp = strchr(buf, '\n')) != NULL)
  141. *cp = '\0';
  142. /* Delete leading white spaces */
  143. for (cp = buf; *cp && isspace(*cp); cp++) ;
  144. if (cp != buf && *cp)
  145. memmove(buf, cp, strlen(cp) + 1);
  146. return(buf);
  147. }
  148. /*
  149. * Read a list of input lines. Terminate reading when the 'quit' character
  150. * has been found in the first column of the input line. All lines with the
  151. * 'comment' character in the first position will be skipped.
  152. *
  153. * If 'havequit' is non-null, then the boolean '*havequit' says whether we
  154. * saw an input line with the 'quit' character.
  155. */
  156. static struct line_s *readlist(FILE *fp, int quit, int comment, int *havequit)
  157. {
  158. struct line_s *lp;
  159. struct line_s *first_line = NULL;
  160. struct line_s *last_line = NULL;
  161. char *cp;
  162. while ((cp = readline(fp)) != NULL) {
  163. if (quit != NOCHAR && quit == *cp)
  164. break;
  165. if (comment != NOCHAR && comment == *cp)
  166. if (quit != NOCHAR)
  167. continue;
  168. if (*cp == '\0')
  169. continue;
  170. lp = mymalloc(sizeof(struct line_s));
  171. lp->text = install(cp, -1);
  172. lp->prev = last_line;
  173. lp->next = NULL;
  174. lp->comment_flg = (comment != NOCHAR && *cp == comment);
  175. if (first_line == NULL)
  176. first_line = lp;
  177. if (last_line != NULL)
  178. last_line->next = lp;
  179. last_line = lp;
  180. }
  181. if (havequit)
  182. *havequit = (cp != NULL);
  183. return(first_line);
  184. }
  185. /*
  186. * Read pattern file
  187. */
  188. static void readpattern(char *rulesdir, char *filename)
  189. {
  190. static char path[MAXLINE];
  191. int havequit;
  192. struct rule_s *rp;
  193. FILE *fp;
  194. /* Open pattern file */
  195. if (rulesdir != NULL)
  196. sprintf(path, "%s/%s", rulesdir, filename);
  197. else
  198. sprintf(path, "%s", filename);
  199. if ((fp = fopen(path, "r")) == NULL) {
  200. fprintf(stderr, "%s: can't open pattern file %s\n", progname, path);
  201. exit(1);
  202. }
  203. /* Read every line of the pattern file */
  204. while (!feof(fp)) {
  205. rp = (struct rule_s *)mymalloc(sizeof(struct rule_s));
  206. rp->old = readlist(fp, '=', '#', &havequit);
  207. rp->new = readlist(fp, '\0', '#', NULL);
  208. if (rp->old == NULL || !havequit) {
  209. free(rp);
  210. break;
  211. }
  212. /* This put the rules into the table in reverse order; this is confusing *
  213. rp->next = first;
  214. first = rp;
  215. if (last == NULL)
  216. last = rp;
  217. */
  218. rp->next = NULL;
  219. if (last) {
  220. last->next = rp;
  221. last = rp;
  222. } else {
  223. first = last = rp;
  224. }
  225. }
  226. /* Close pattern file */
  227. (void)fclose(fp);
  228. }
  229. /*
  230. * Clear pattern list to allow for another run
  231. */
  232. static void clearpattern(void)
  233. {
  234. struct rule_s *rp1, *rp2;
  235. struct line_s *lp1, *lp2;
  236. rp1 = first;
  237. while (rp1 != NULL) {
  238. /* Clear old rule text list */
  239. lp1 = rp1->old;
  240. while (lp1 != NULL) {
  241. lp2 = lp1;
  242. lp1 = lp1->next;
  243. free(lp2);
  244. }
  245. /* Clear new rule text list */
  246. lp1 = rp1->new;
  247. while (lp1 != NULL) {
  248. lp2 = lp1;
  249. lp1 = lp1->next;
  250. free(lp2);
  251. }
  252. /* Clear rule itself */
  253. rp2 = rp1;
  254. rp1 = rp1->next;
  255. free(rp2);
  256. }
  257. first = NULL;
  258. last = NULL;
  259. }
  260. /*
  261. * Read input file
  262. */
  263. static void readinfile(char *filename, int comment)
  264. {
  265. FILE *fp;
  266. fp = stdin;
  267. if (filename != NULL && (fp = fopen(filename, "r")) == NULL) {
  268. fprintf(stderr, "%s: can't open input file %s\n", progname, filename);
  269. exit(1);
  270. }
  271. infile = readlist(fp, NOCHAR, comment, NULL);
  272. if (fp != stdin)
  273. (void)fclose(fp);
  274. }
  275. #define NO_OP 0
  276. #define ADD_OP 1
  277. #define SUB_OP 2
  278. #define MUL_OP 3
  279. #define DIV_OP 4
  280. #define SHL_OP 5
  281. #define SHR_OP 6
  282. long retval = 0;
  283. long num = 0;
  284. int sign = 1;
  285. int base = 10;
  286. int op = NO_OP;
  287. /* Apply operation to current numeric value */
  288. static void doretval(void)
  289. {
  290. switch (op) {
  291. case NO_OP: retval = num * sign;
  292. break;
  293. case ADD_OP: retval += num * sign;
  294. break;
  295. case SUB_OP: retval -= num * sign;
  296. break;
  297. case MUL_OP: retval *= num * sign;
  298. break;
  299. case DIV_OP: retval /= num * sign;
  300. break;
  301. case SHL_OP: retval <<= num;
  302. break;
  303. case SHR_OP: retval >>= num;
  304. break;
  305. }
  306. op = NO_OP;
  307. num = 0;
  308. sign = 1;
  309. base = 10;
  310. }
  311. /*
  312. * Eval an expression into an integer number
  313. */
  314. static long eval(char *str, int len)
  315. {
  316. char *cp, c;
  317. int state = 0;
  318. int i, varnum;
  319. retval = 0;
  320. num = 0;
  321. sign = 1;
  322. base = 10;
  323. op = NO_OP;
  324. /* Scan through whole string and decode it */
  325. for (cp = str, i = 0; *cp && i < len; cp++, i++) {
  326. c = toupper(*cp);
  327. if (c == '-' && (state == 0 || state == 5)) {
  328. state = 1;
  329. sign = -1;
  330. } else if (c == '+' && (state == 0 || state == 5)) {
  331. state = 1;
  332. sign = 1;
  333. } else if (c == '%' && isdigit(*(cp + 1)) && (state < 2 || state == 5)) {
  334. state = 4;
  335. varnum = *(cp + 1) - '0';
  336. if (vars[varnum] == NULL || i >= len)
  337. return(0);
  338. num = eval(vars[varnum], strlen(vars[varnum]));
  339. doretval();
  340. cp++; i++;
  341. } else if (c == '$' && (state < 2 || state == 5)) {
  342. state = 2;
  343. base = 16;
  344. } else if (base == 10 && (c >= '0' && c <= '9') &&
  345. (state <= 3 || state == 5)) {
  346. state = 3;
  347. num = num * 10 + (c - '0');
  348. } else if (base == 16 &&
  349. ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) &&
  350. (state <= 3 || state == 5)) {
  351. state = 3;
  352. num = num * 16 + (c >= 'A' ? c - '0' - 7 : c - '0');
  353. } else if (c == ' ' && (state == 3 || state == 4 || state == 5)) {
  354. if (state == 3) {
  355. doretval();
  356. state = 4;
  357. }
  358. } else if (strchr("+-*/<>", c) != NULL && (state == 3 || state == 4)) {
  359. if (state == 3)
  360. doretval();
  361. state = 5;
  362. switch (c) {
  363. case '+': op = ADD_OP;
  364. break;
  365. case '-': op = SUB_OP;
  366. break;
  367. case '*': op = MUL_OP;
  368. break;
  369. case '/': op = DIV_OP;
  370. break;
  371. case '<': op = SHL_OP;
  372. break;
  373. case '>': op = SHR_OP;
  374. break;
  375. }
  376. } else
  377. return(0);
  378. }
  379. /* Check if the string has been terminated correctly */
  380. if (state != 3 && state != 4)
  381. return(0);
  382. if (state == 3)
  383. doretval();
  384. return(retval);
  385. }
  386. /*
  387. * Compare an infile string with a pattern string. If there is any variable
  388. * defined, it will be inserted into the variable list from the pattern
  389. * string.
  390. */
  391. static int match(char *ins, char *pat)
  392. {
  393. char *cp, *oldpat;
  394. long val;
  395. int varnum;
  396. int len = 0;
  397. while (*ins && *pat)
  398. {
  399. if (pat[0] != '%')
  400. {
  401. if (*pat++ != *ins++)
  402. return(0);
  403. else
  404. continue;
  405. }
  406. if (pat[1] == '%') {
  407. /* '%%' actually means '%' */
  408. if (*ins != '%')
  409. return(0);
  410. pat += 2;
  411. } else if ((pat[1] == '*' || isdigit(pat[1]))) {
  412. /* Copy variable text into vars array */
  413. pat += 2;
  414. for (cp = ins; *ins && !match(ins, pat); ins++) ;
  415. if (pat[-1] == '*')
  416. continue;
  417. len = ins - cp;
  418. varnum = pat[-1] - '0';
  419. if (vars[varnum] == NULL)
  420. vars[varnum] = install(cp, len);
  421. else if (strlen(vars[varnum]) != len ||
  422. strncmp(vars[varnum], cp, len))
  423. return(0);
  424. } else if (pat[1] == '[') {
  425. /* Copy only specific variable text into vars array */
  426. if ((cp = strchr(pat + 2, ']')) == NULL ||
  427. (*(cp + 1) != '*' && !isdigit(*(cp + 1)))) {
  428. if (*ins != '[')
  429. return(0);
  430. pat += 2;
  431. continue;
  432. }
  433. oldpat = pat + 1;
  434. pat = cp + 2;
  435. /* Seperate allowable patterns and compare them with ins */
  436. while (*oldpat && *oldpat != ']') {
  437. oldpat++;
  438. len = strcspn(oldpat, "|]");
  439. if (!strncmp(ins, oldpat, len))
  440. break;
  441. oldpat += len;
  442. }
  443. if (!*oldpat || *oldpat == ']')
  444. return(0);
  445. ins += len;
  446. if (!match(ins, pat))
  447. return(0);
  448. /* Install new string into variable table */
  449. if (*(cp + 1) == '*')
  450. continue;
  451. varnum = *(cp + 1) - '0';
  452. if (vars[varnum] == NULL)
  453. vars[varnum] = install(oldpat, len);
  454. else if (strlen(vars[varnum]) != len ||
  455. strncmp(vars[varnum], oldpat, len))
  456. return(0);
  457. } else if (pat[1] == '!') {
  458. /* Match only if the pattern string is not found */
  459. if (pat[2] != '[' || (cp = strchr(pat + 3, ']')) == NULL) {
  460. if (*ins != '!')
  461. return(0);
  462. pat += 3;
  463. continue;
  464. }
  465. oldpat = pat + 2;
  466. pat = cp + 1;
  467. /* Seperate allowable patterns and compare them with ins */
  468. while (*oldpat && *oldpat != ']') {
  469. oldpat++;
  470. len = strcspn(oldpat, "|]");
  471. if (!strncmp(ins, oldpat, len))
  472. return(0);
  473. oldpat += len;
  474. }
  475. } else if (pat[1] == '(') {
  476. /* Match ins with expression */
  477. if ((cp = strchr(pat + 2, ')')) == NULL) {
  478. if (*ins != '(')
  479. return(0);
  480. pat += 2;
  481. continue;
  482. }
  483. oldpat = pat + 2;
  484. pat = cp + 1;
  485. len = cp - oldpat;
  486. val = eval(oldpat, len);
  487. for (cp = ins; *ins && !match(ins, pat); ins++) ;
  488. len = ins - cp;
  489. if (val != eval(cp, len))
  490. return(0);
  491. }
  492. else /* Bad % format cannot match */
  493. return(0);
  494. }
  495. return(*ins == *pat);
  496. }
  497. /*
  498. * Substitute variables in a string
  499. */
  500. static char *subst(char *pat)
  501. {
  502. char buf[MAXLINE];
  503. char *cp, *cp1, *cp2, *varptr;
  504. long num;
  505. int i = 0;
  506. int j, pos;
  507. while (*pat)
  508. if (pat[0] == '%' && isdigit(pat[1])) {
  509. /* Substitute with value of variable */
  510. cp = vars[pat[1] - '0'];
  511. while (cp != NULL && *cp) {
  512. buf[i++] = *cp++;
  513. if (i >= MAXLINE - 1) {
  514. fprintf(stderr, "%s: line too long\n", progname);
  515. exit(1);
  516. }
  517. }
  518. pat += 2;
  519. } else if (pat[0] == '%' && pat[1] == '(') {
  520. /* Substitute with expression */
  521. cp = pat + 2;
  522. if ((pat = strchr(cp, ')')) == NULL || pat - cp <= 0)
  523. num = 0;
  524. else
  525. num = eval(cp, pat - cp);
  526. if (i >= MAXLINE - 20) {
  527. fprintf(stderr, "%s: line too long\n", progname);
  528. exit(1);
  529. }
  530. i += sprintf(&buf[i], "%s$%lx", num < 0 ? "-" : "", labs(num));
  531. pat++;
  532. } else if (pat[0] == '%' && pat[1] == '=') {
  533. /* Substitute with converted variable */
  534. /* First seperate all parts of the pattern string */
  535. cp = pat + 2;
  536. cp1 = cp2 = varptr = NULL;
  537. if (*cp == '[') {
  538. cp1 = ++cp;
  539. while (*cp && *cp != ']')
  540. cp++;
  541. if (cp[0] == ']' && cp[1] == '[') {
  542. cp += 2;
  543. cp2 = cp;
  544. while (*cp && *cp != ']')
  545. cp++;
  546. if (cp[0] == ']' && isdigit(cp[1]))
  547. varptr = vars[cp[1] - '0'];
  548. }
  549. }
  550. if (cp1 == NULL || cp2 == NULL || varptr == NULL) {
  551. buf[i++] = *pat++;
  552. if (i >= MAXLINE - 1) {
  553. fprintf(stderr, "%s: line too long\n", progname);
  554. exit(1);
  555. }
  556. continue;
  557. }
  558. pat = cp + 2;
  559. /* Now scan through the first string to find variable value */
  560. cp1--;
  561. pos = 0;
  562. while (*cp1 != ']') {
  563. cp1++;
  564. j = strcspn(cp1, "|]");
  565. if (strlen(varptr) == j && !strncmp(cp1, varptr, j))
  566. break;
  567. pos++;
  568. cp1 += j;
  569. }
  570. if (*cp1 == ']')
  571. continue;
  572. /* Scan through the second string to find the conversion */
  573. cp2--;
  574. while (*cp2 != ']' && pos > 0) {
  575. cp2++;
  576. j = strcspn(cp2, "|]");
  577. pos--;
  578. cp2 += j;
  579. }
  580. if (*cp2 == ']' || pos != 0)
  581. continue;
  582. /* Insert conversion string into destination */
  583. cp2++;
  584. while (*cp2 != '|' && *cp2 != ']') {
  585. buf[i++] = *cp2++;
  586. if (i >= MAXLINE - 1) {
  587. fprintf(stderr, "%s: line too long\n", progname);
  588. exit(1);
  589. }
  590. }
  591. } else {
  592. buf[i++] = *pat++;
  593. if (i >= MAXLINE - 1) {
  594. fprintf(stderr, "%s: line too long\n", progname);
  595. exit(1);
  596. }
  597. }
  598. buf[i] = '\0';
  599. return(install(buf, i));
  600. }
  601. /*
  602. * Optimize one line of the input file
  603. */
  604. static struct line_s *optline(struct line_s *cur)
  605. {
  606. struct rule_s *rp;
  607. struct line_s *ins, *pat;
  608. struct line_s *lp1, *lp2;
  609. int i;
  610. for (rp = first; rp != NULL; rp = rp->next) {
  611. /* Clear variable array */
  612. for (i = 0; i < VARNUM; i++)
  613. vars[i] = NULL;
  614. /* Scan through pattern texts and match them against the input file */
  615. ins = cur;
  616. pat = rp->old;
  617. while (ins != NULL
  618. && pat != NULL
  619. && ( ins->comment_flg ||
  620. ( /* (pat->text[0]=='%' || ins->text[0]==pat->text[0]) && */
  621. match(ins->text, pat->text)))) {
  622. if (!ins->comment_flg)
  623. pat = pat->next;
  624. else if (ins->text[0]==pat->text[0]) /* Matching a comment! */
  625. {
  626. if (match(ins->text, pat->text))
  627. pat = pat->next;
  628. }
  629. ins = ins->next;
  630. }
  631. /* Current pattern matched input line, so replace input with new */
  632. if (pat == NULL) {
  633. /* Clear all lines in the source file for this pattern */
  634. lp1 = cur;
  635. cur = cur->prev;
  636. while (lp1 != ins) {
  637. #if 0
  638. if( lp1->comment_flg )
  639. {
  640. lp2 = lp1;
  641. lp1 = lp1->next;
  642. lp2->next = cur->next;
  643. cur->next = lp2;
  644. lp2->prev = cur;
  645. cur=cur->next;
  646. }
  647. else
  648. #endif
  649. {
  650. lp2 = lp1;
  651. lp1 = lp1->next;
  652. free(lp2);
  653. }
  654. }
  655. /* Insert new lines into list */
  656. pat = rp->new;
  657. lp1 = cur;
  658. lp2 = NULL;
  659. while (pat != NULL) {
  660. lp2 = mymalloc(sizeof(struct line_s));
  661. lp2->text = subst(pat->text);
  662. lp2->next = NULL;
  663. lp2->prev = lp1;
  664. lp2->comment_flg = 0;
  665. if (lp1 != NULL)
  666. lp1->next = lp2;
  667. else
  668. infile = lp2;
  669. lp1 = lp2;
  670. pat = pat->next;
  671. }
  672. if (ins != NULL)
  673. ins->prev = lp2;
  674. if (lp2 != NULL)
  675. lp2->next = ins;
  676. else if (lp1 != NULL)
  677. lp1->next = NULL;
  678. else
  679. infile = NULL;
  680. return(cur);
  681. }
  682. }
  683. return(cur->next);
  684. }
  685. /*
  686. * Actually optimize all strings in the input file
  687. */
  688. static void optimize(int backup)
  689. {
  690. struct line_s *cur, *lp;
  691. int i;
  692. int in_asm = 0;
  693. /* Scan through all lines in the input file */
  694. cur = infile;
  695. while (cur != NULL) {
  696. if (cur->comment_flg || in_asm)
  697. {
  698. lp=cur->next;
  699. if (memcmp(cur->text, "!BCC_", 5) == 0)
  700. in_asm = (memcmp(cur->text+5, "ASM", 3) == 0);
  701. }
  702. else
  703. if ((lp = optline(cur)) != NULL && lp != cur->next) {
  704. for (i = 0; i < backup && lp != NULL; i++)
  705. lp = lp->prev;
  706. if (lp == NULL)
  707. lp = infile;
  708. }
  709. cur = lp;
  710. }
  711. }
  712. /*
  713. * Write out into destination file
  714. */
  715. static void writeoutf(char *filename, char *headstr)
  716. {
  717. FILE *fp;
  718. struct line_s *lp;
  719. fp = stdout;
  720. if (filename != NULL && (fp = fopen(filename, "w")) == NULL) {
  721. fprintf(stderr, "%s: can't open output file %s\n", progname, filename);
  722. exit(1);
  723. }
  724. if (headstr != NULL) {
  725. fprintf(fp, "%s", headstr);
  726. fprintf(fp, "\n");
  727. }
  728. for (lp = infile; lp != NULL; lp = lp->next)
  729. fprintf(fp, "%s\n", lp->text);
  730. if (fp != stdout)
  731. (void)fclose(fp);
  732. }
  733. /*
  734. * Print usage
  735. */
  736. static void usage(void)
  737. {
  738. fprintf(stderr, "usage: %s [-c<comment-char>] [-f<src-file>] [-o<out-file>]\n"
  739. "\t\t[-b<backup-num>] [-h<head-str>] [-d<ruls-dir>] "
  740. "<rules-file> ...\n", progname);
  741. exit(1);
  742. }
  743. /*
  744. * Main program
  745. */
  746. int
  747. main(int argc, char **argv)
  748. {
  749. char comment = NOCHAR;
  750. char *srcfile = NULL;
  751. char *outfile = NULL;
  752. char *headstr = NULL;
  753. char *rulesdir = NULL;
  754. int backup = 0;
  755. int i;
  756. /* Get program name */
  757. if ((progname = strrchr(argv[0], '/')) == NULL)
  758. progname = argv[0];
  759. else
  760. progname++;
  761. /* Make life easy for bcc */
  762. if ( argc > 4 && strcmp(argv[2], "-o") == 0 && argv[1][0] != '-' )
  763. {
  764. srcfile = argv[1];
  765. argv++,argc--;
  766. }
  767. /* Get options from command line */
  768. for (i = 1; i < argc; i++)
  769. if (!strncmp(argv[i], "-c", 2))
  770. comment = argv[i][2];
  771. else if (!strncmp(argv[i], "-b", 2))
  772. backup = atoi(&(argv[i][3]));
  773. else if (!strncmp(argv[i], "-f", 2))
  774. srcfile = &(argv[i][2]);
  775. else if (!strncmp(argv[i], "-o", 2))
  776. {
  777. if(argv[i][2])
  778. outfile = &(argv[i][2]);
  779. else if(++i<argc)
  780. outfile = argv[i];
  781. else
  782. usage();
  783. }
  784. else if (!strncmp(argv[i], "-h", 2))
  785. headstr = &(argv[i][2]);
  786. else if (!strncmp(argv[i], "-d", 2))
  787. rulesdir = &(argv[i][2]);
  788. else if (argv[i][0] == '-')
  789. usage();
  790. else
  791. break;
  792. /* Have to have enough parameters for rule file names */
  793. if ((argc - i) < 1)
  794. usage();
  795. /* Read source file and optimze it with every rules file */
  796. readinfile(srcfile, comment);
  797. for ( ; i < argc; i++) {
  798. readpattern(rulesdir, argv[i]);
  799. optimize(backup);
  800. clearpattern();
  801. }
  802. writeoutf(outfile, headstr);
  803. exit(0);
  804. }