home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume02 / subst < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  8.6 KB

  1. From mipos3!intelca!oliveb!ames!husc6!necntc!ncoast!allbery Sat Jan 23 19:37:30 PST 1988
  2. Article 258 of comp.sources.misc:
  3. Path: td2cad!mipos3!intelca!oliveb!ames!husc6!necntc!ncoast!allbery
  4. From: aeb@cwi.nl (Andries Brouwer)
  5. Newsgroups: comp.sources.misc
  6. Subject: v02i008: subst - substitute strings for strings
  7. Message-ID: <7102@ncoast.UUCP>
  8. Date: 20 Jan 88 01:03:39 GMT
  9. Sender: allbery@ncoast.UUCP
  10. Organization: CWI, Amsterdam
  11. Lines: 370
  12. Approved: allbery@ncoast.UUCP
  13. X-Archive: comp.sources.misc/8801/9
  14. Comp.Sources.Misc: Volume 2, Issue 9
  15. Submitted-By: Andries Brouwer <aeb@cwi.nl>
  16. Archive-Name: subst
  17.  
  18. Comp.sources.misc: Volume 2, Issue 9
  19. Submitted-By: Andries Brouwer <aeb@cwi.nl>
  20. Archive-Name: subst
  21.  
  22. [The next few postings are from rs's slush pile.  At least we know he's still
  23. alive.  ;-)  Also -- you will have noticed that there are occasional irregular
  24. headers -- I aadding the compatible headers manually while trying to finish
  25. the generalized posting program, I occasionally mess up.  Sorry!  ++bsa]
  26.  
  27. This program does unlimited string substitution.
  28. I needed it because of the limits built into sed
  29. (this program has no limits on string sizes or
  30. number of strings), and the awkwardness of worrying
  31. about the special characters of sed.
  32. Maybe it is useful to others as well.
  33.  
  34. The program header documents it.
  35.  
  36. ---------------------------------------------------
  37. /* subst: substitute fixed strings for other fixed strings - aeb@cwi.nl */
  38. /* written 11 Nov. 1987 - placed in public domain - do not delete header */
  39. /*
  40.  * Call: subst [-acs] sfile [ifile]
  41.  * Here sfile is the file with descriptions of the substitutions
  42.  * to be performed and ifile is the input file.
  43.  * If ifile is not given, then stdin is read.
  44.  * If the option -c is given, then the following argument is itself the
  45.  * substitution description.
  46.  * The description has the format:
  47.  *    <old><tab><new>
  48.  * and different description lines are separated by newlines.
  49.  * In cases where <old> might contain tabs or <new> might contain
  50.  * newlines, one can use subst -s .
  51.  * Now description lines have the format
  52.  *    <sep><old><sep><tab><sep2><old><sep2>
  53.  * and again different description lines are separated by newlines.
  54.  * (Here <sep> and <sep2> denote arbitrary single characters.)
  55.  * By default, only the places where <old> occurs as "keyword",
  56.  * i.e., not preceded or followed by a letter or digit, are substituted,
  57.  * but the option -a causes substitution for all occurrences.
  58.  */
  59.  
  60. /*
  61.    Why not use sed or /lib/cpp or m4 or ... ? Well, m4 and /lib/cpp
  62.    react to special characters in the file, but I want to leave the
  63.    file as it is, except for these substitutions. What about sed?
  64.    This is not so bad, but requires some preprocessing of sfile
  65.    in case the strings may contain . or & etc. When both sfile and
  66.    ifile are computer generated, this is a hassle, and the present
  67.    solution is much cleaner. Moreover, subst has no built-in limits.
  68.    Note: this program works reasonably well when the number of
  69.    substitution strings is not too large. It uses a linear list, and
  70.    this becomes very slow when there are thousands of substitution strings.
  71. */
  72.  
  73. #include <stdio.h>
  74. extern char *malloc(), *realloc(), *strcpy(), *grow(), *alloc(), *input();
  75.  
  76. int opta, optc, opts;
  77. FILE *inf, *sf;
  78. char *sin, *iname, *sname;
  79. int eoi;
  80. struct repl {
  81.     char *in;
  82.     char *out;
  83.     struct repl *next;
  84. } *replhead, *repltail;
  85.  
  86. char speedup[256];    /* let us hope that characters have 8 bits ... */
  87.  
  88. usage(){
  89.     fprintf(stderr, "subst: Usage is  subst [-cs] sfile [ifile]\n");
  90.     exit(2);
  91. }
  92.  
  93. main(argc,argv) int argc; char **argv; {
  94.     while(argc > 1 && argv[1][0] == '-') {
  95.         do {
  96.             switch(argv[1][1]) {
  97.             case 's':
  98.                 opts++;
  99.                 break;
  100.             case 'c':
  101.                 optc++;
  102.                 break;
  103.             case 'a':
  104.                 opta++;
  105.                 break;
  106.             default:
  107.                 usage();
  108.                 exit(2);
  109.             }
  110.             argv[1]++;
  111.         } while(argv[1][1]);
  112.         argv++;
  113.         argc--;
  114.     }
  115.     if(argc > 3 || argc < 2)
  116.         usage();
  117.     if(argc == 3) {
  118.         iname = argv[2];
  119.         inf = fopen(iname,"r");
  120.         if(inf == NULL) {
  121.             perror(iname);
  122.             exit(1);
  123.         }
  124.     } else {
  125.         inf = stdin;
  126.         iname = "<stdin>";
  127.     }
  128.     if(!optc) {
  129.         sname = argv[1];
  130.         sf = fopen(sname,"r");
  131.         if(sf == NULL) {
  132.             perror(sname);
  133.             exit(1);
  134.         }
  135.     } else {
  136.         sin = argv[1];
  137.         sname = "<argin>";
  138.     }
  139.     getsfile();
  140.     do_it();
  141.     return(0);
  142. }
  143.  
  144. unsigned maxilth, maxolth;
  145.  
  146. getsfile(){
  147.  
  148. #define    LSIZ    4
  149.  
  150. #define put_in_buf(c) {\
  151.     if(bufp >= buf + bsz) {\
  152.         buf = grow(buf, bsz + LSIZ);\
  153.         bufp = buf + bsz;\
  154.         bsz += LSIZ;\
  155.     }\
  156.     *bufp++ = c;\
  157. }
  158.  
  159. #define put_in_repl(inout,max) {\
  160.     register unsigned lth = strlen(buf) + 1;\
  161.     if(lth > max) max = lth;\
  162.     replp->inout = alloc(lth);\
  163.     (void) strcpy(replp->inout,buf);\
  164. }
  165.  
  166. #define put_in_chain    {\
  167.     replp->next = NULL;\
  168.     if(replhead == NULL)\
  169.         replhead = replp;\
  170.     else\
  171.         repltail->next = replp;\
  172.     repltail = replp;\
  173.     replp = (struct repl *) alloc(sizeof(struct repl));\
  174. }
  175.  
  176.     char line[LSIZ],  *buf;
  177.     register char *lp, *bufp;
  178.     register int state = 0, bsz = 0, eos = 0;
  179.     register struct repl *replp;
  180.     char sep;
  181.  
  182.     if(optc)
  183.         lp = sin;
  184.     else {
  185.         lp = line;
  186.         line[0] = 0;
  187.     }
  188.  
  189.     replp = (struct repl *) alloc(sizeof(struct repl));
  190.  
  191.     buf = alloc(LSIZ);
  192.     bufp = buf;
  193.     bsz = LSIZ;
  194.  
  195.     while(!eos) {
  196.         if(!*lp) {
  197.             if(optc) {
  198.                 lp = "\n";
  199.                 eos++;
  200.             } else {
  201.                 if(fgets(line, sizeof(line), sf) == NULL) {
  202.                     if(ferror(sf)) {
  203.                         perror(sname);
  204.                         exit(1);
  205.                     }
  206.                     break;
  207.                 }
  208.                 lp = line;
  209.                 if(!*lp) return;    /* strange ... */
  210.             }
  211.         }
  212.         switch(state) {
  213.         case 0:        /* before in */
  214.             state = 1;
  215.             if(opts) {
  216.                 sep = *lp++;
  217.                 continue;
  218.             }
  219.             sep = '\t';
  220.             /* fall through */
  221.         case 1:        /* reading in */
  222.             if(*lp != sep) {
  223.                 put_in_buf(*lp++);
  224.                 continue;
  225.             }
  226.             lp++;
  227.             put_in_buf(0);
  228.             put_in_repl(in,maxilth);
  229.             bufp = buf;
  230.             state = (opts ? 2 : 3);
  231.             continue;
  232.         case 2:        /* waiting for tab */
  233.             if(*lp++ == '\t') state = 3;
  234.             continue;
  235.         case 3:        /* before out */
  236.             state = 4;
  237.             if(opts) {
  238.                 sep = *lp++;
  239.                 continue;
  240.             }
  241.             sep = '\n';
  242.             /* fall through */
  243.         case 4:        /* reading out */
  244.             if(*lp != sep) {
  245.                 put_in_buf(*lp++);
  246.                 continue;
  247.             }
  248.             lp++;
  249.             put_in_buf(0);
  250.             put_in_repl(out,maxolth);
  251.             bufp = buf;
  252.             put_in_chain;
  253.             state = (opts ? 5 : 0);
  254.             continue;
  255.         case 5:        /* waiting for newline */
  256.             if(*lp++ == '\n') state = 0;
  257.             continue;
  258.         }
  259.     }
  260.  
  261.     free((char *) replp);
  262.     free(buf);
  263. }
  264.  
  265.  
  266. do_it(){
  267.  
  268. #define    ISIZ    16384
  269.  
  270. #define is_ok(c) (c < '0' || (c < '@' && c > '9') || (c < 'a' && c > 'Z') || c > 'z')
  271.  
  272. #define    assure_ip    if(ip == ibuf1) {\
  273.     register char *tp;\
  274.     if(eoi)\
  275.         goto nxt;\
  276.     output(ibuf, ibufp-ibuf);\
  277.     tp = ibufp;\
  278.     ip = ibufp = ibuf = ibuf0;\
  279.     while(tp < ibuf1)\
  280.         *ip++ = *tp++;\
  281.     ibuf1 = input(ip, ibuf1-ip);\
  282.     if(ip == ibuf1)\
  283.         goto nxt;\
  284. }
  285.  
  286.     register struct repl *replp;
  287.     register char *ibuf, *ibuf0, *ibuf1, *ibufp, *cp, *ip;
  288.     register unsigned ilth;
  289.     int prevc_is_ok = 1;
  290.  
  291.     /* small speedup: remember first char of all in-strings */
  292.     /* [this changes the semantics slightly: we do no longer
  293.         replace the empty string by something, but that would
  294.         otherwise lead to an infinite loop, so is useless anyway] */
  295.     for(replp = replhead; replp; replp = replp->next)
  296.         speedup[replp->in[0]] = 1;
  297.  
  298.     ilth = 2*maxilth;
  299.     if(ISIZ > ilth)
  300.         ilth = ISIZ;
  301.     ibuf0 = alloc(ilth);
  302.     ibufp = ibuf = ibuf1 = ibuf0 + ilth;
  303.  
  304.     while(1) {
  305.  
  306.         if(ibufp == ibuf1) {
  307.             output(ibuf, ibufp-ibuf);
  308.             if(eoi)
  309.                 return;
  310.             ibufp = ibuf = ibuf0;
  311.             ibuf1 = input(ibuf, ibuf1-ibuf);
  312.             if(ibuf == ibuf1)
  313.                 return;
  314.         }
  315.  
  316.         if(prevc_is_ok && speedup[*ibufp])
  317.         for(replp = replhead; replp; replp = replp->next) {
  318.             cp = replp->in;
  319.             ip = ibufp;
  320.             while (*cp) {
  321.                 assure_ip;
  322.                 if(*cp++ != *ip++)
  323.                     goto nxt;
  324.             }
  325.             /* found a match! */
  326.             if(!opta) {
  327.                 assure_ip;
  328.                 if(!is_ok(*ip))
  329.                     goto nxt;
  330.             }
  331.             output(ibuf, ibufp-ibuf);
  332.             fputs(replp->out, stdout);
  333.             ibufp = ibuf = ip;
  334.             goto nxt2;
  335.         nxt:    ;
  336.         }
  337.         if(!opta)
  338.             prevc_is_ok = is_ok (*ibufp);
  339.         ibufp++;
  340.     nxt2:    ;
  341.     }
  342. }
  343.  
  344. char *
  345. input(ibuf,n) char *ibuf; register int n; {
  346.     register int nn = fread(ibuf, sizeof(char), n, inf);
  347.     if(nn < n) {
  348.         if(feof(inf))
  349.             eoi++;
  350.         else {
  351.             perror("subst: input error: ");
  352.             exit(1);
  353.         }
  354.     }
  355.     return(ibuf + nn);
  356. }
  357.  
  358. output(obuf,n) char *obuf; register int n; {
  359.     if(n > 0) {
  360.         if(fwrite(obuf, sizeof(char), n, stdout) != n) {
  361.             perror("subst: write error: ");
  362.             exit(1);    /* probably file system full? */
  363.         }
  364.     }
  365. }
  366.  
  367. char *
  368. alloc(n) unsigned n; {
  369.     register char *a = malloc(n);
  370.     if(a == NULL) {
  371.         fprintf(stderr, "subst: out of memory\n");
  372.         exit(1);
  373.     }
  374.     return(a);
  375. }
  376.  
  377. char *
  378. grow(a,n) register char *a; register int n; {
  379.     a = realloc(a, (unsigned) n);
  380.     if(a == NULL) {
  381.         fprintf(stderr, "subst: realloc failed\n");
  382.         exit(1);
  383.     }
  384.     return(a);
  385. }
  386. -- 
  387.       Andries Brouwer -- CWI, Amsterdam -- uunet!mcvax!aeb -- aeb@cwi.nl
  388.  
  389.  
  390.