home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / fileutil / sed.lzh / SED / SED.C < prev    next >
C/C++ Source or Header  |  1991-08-16  |  59KB  |  1,790 lines

  1. /* sed.c        emulate the UN*X sed command.
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.  
  4.                        NO WARRANTY
  5.  
  6.   BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
  7. NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
  8. WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
  9. RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
  10. WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  11. BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
  13. AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
  14. DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
  15. CORRECTION.
  16.  
  17.  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
  18. STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
  19. WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
  20. LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
  21. OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
  22. USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
  23. DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
  24. A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
  25. PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
  26. DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  27.  
  28.                 GENERAL PUBLIC LICENSE TO COPY
  29.  
  30.   1. You may copy and distribute verbatim copies of this source file
  31. as you receive it, in any medium, provided that you conspicuously
  32. and appropriately publish on each copy a valid copyright notice
  33. "Copyright (C) 1989 Free Software Foundation, Inc.", and include
  34. following the copyright notice a verbatim copy of the above disclaimer
  35. of warranty and of this License.
  36.  
  37.   2. You may modify your copy or copies of this source file or
  38. any portion of it, and copy and distribute such modifications under
  39. the terms of Paragraph 1 above, provided that you also do the following:
  40.  
  41.     a) cause the modified files to carry prominent notices stating
  42.     that you changed the files and the date of any change; and
  43.  
  44.     b) cause the whole of any work that you distribute or publish,
  45.     that in whole or in part contains or is a derivative of this
  46.     program or any part thereof, to be licensed at no charge to all
  47.     third parties on terms identical to those contained in this
  48.     License Agreement (except that you may choose to grant more
  49.     extensive warranty protection to third parties, at your option).
  50.  
  51.     c) You may charge a distribution fee for the physical act of
  52.     transferring a copy, and you may at your option offer warranty
  53.     protection in exchange for a fee.
  54.  
  55.   3. You may copy and distribute this program or any portion of it in
  56. compiled, executable or object code form under the terms of Paragraphs
  57. 1 and 2 above provided that you do the following:
  58.  
  59.     a) cause each such copy to be accompanied by the
  60.     corresponding machine-readable source code, which must
  61.     be distributed under the terms of Paragraphs 1 and 2 above; or,
  62.  
  63.     b) cause each such copy to be accompanied by a
  64.     written offer, with no time limit, to give any third party
  65.     free (except for a nominal shipping charge) a machine readable
  66.     copy of the corresponding source code, to be distributed
  67.     under the terms of Paragraphs 1 and 2 above; or,
  68.  
  69.     c) in the case of a recipient of this program in compiled, executable
  70.     or object code form (without the corresponding source code) you
  71.     shall cause copies you distribute to be accompanied by a copy
  72.     of the written offer of source code which you received along
  73.     with the copy you received.
  74.  
  75.   4. You may not copy, sublicense, distribute or transfer this program
  76. except as expressly provided under this License Agreement.  Any attempt
  77. otherwise to copy, sublicense, distribute or transfer this program is void and
  78. your rights to use the program under this License agreement shall be
  79. automatically terminated.  However, parties who have received computer
  80. software programs from you with this License Agreement will not have
  81. their licenses terminated so long as such parties remain in full compliance.
  82.  
  83.   5. If you wish to incorporate parts of this program into other free
  84. programs whose distribution conditions are different, write to the Free
  85. Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
  86. worked out a simple rule that can be stated here, but we will often permit
  87. this.  We will be guided by the two goals of preserving the free status of
  88. all derivatives of our free software and of promoting the sharing and reuse of
  89. software.
  90.  
  91.  In other words, you are welcome to use, share and improve this program.
  92.  You are forbidden to forbid anyone else to use, share and improve
  93.  what you give them.   Help stamp out software-hoarding!  */
  94.  
  95. #include <stdio.h>
  96. #include <ctype.h>
  97. #include "regex.h"
  98.  
  99. #ifdef AZTEC_C
  100. #define memcpy(dst,src,n) movmem((src),(dst),(n))
  101. #define memset(src,value,howmany) setmem((src),(howmany),(value))
  102. #define bcopy(s, d, n) movmem((s),(d),(n))
  103. #endif
  104.  
  105. /* Compile with 'gcc [-g] [-DHAS_UTILS] [-O] -o sed sed.c [-lutils]' */
  106. /* Use '-DHAS_UTILS', -lutils if you if you have hack's utils library */
  107. /* Add '-I. regex.c' if regex is not in the system include dir/library */
  108. #ifdef USG
  109. #define bcopy(s, d, n) ((void)memcpy((d),(s), (n)))
  110. #endif
  111.  
  112. /* Struct vector is used to describe a chunk of a sed program.  There is one
  113.    vector for the main program, and one for each { } pair.
  114.  */
  115. struct vector {
  116.         struct sed_cmd *v;
  117.         int v_length;
  118.         int v_allocated;
  119.         struct vector *up_one;
  120.         struct vector *next_one;
  121. };
  122.  
  123.  
  124. /* Goto structure is used to hold both GOTO's and labels.  There are two
  125.    separate lists, one of goto's, called 'jumps', and one of labels, called
  126.    'labels'.
  127.    the V element points to the descriptor for the program-chunk in which the
  128.    goto was encountered.
  129.    the v_index element counts which element of the vector actually IS the
  130.    goto/label.  The first element of the vector is zero.
  131.    the NAME element is the null-terminated name of the label.
  132.    next is the next goto/label in the list
  133. */
  134.  
  135. struct sed_label {
  136.         struct vector *v;
  137.         int v_index;
  138.         char *name;
  139.         struct sed_label *next;
  140. };
  141.  
  142. /* ADDR_TYPE is zero for a null address,
  143.    one if addr_number is valid, or
  144.    two if addr_regex is valid,
  145.    three, if the address is '$'
  146.  
  147.    Other values are undefined.
  148.  */
  149.  
  150. #define ADDR_NULL       0
  151. #define ADDR_NUM        1
  152. #define ADDR_REGEX      2
  153. #define ADDR_LAST       3
  154.  
  155. struct addr {
  156.         int     addr_type;
  157.         struct re_pattern_buffer *addr_regex;
  158.         int     addr_number;
  159. };
  160.  
  161.  
  162. /* Aflags:  If the low order bit is set, a1 has been
  163.    matched; apply this command until a2 matches.
  164.    If the next bit is set, apply this command to all
  165.    lines that DON'T match the address(es).
  166.  */
  167.  
  168. #define A1_MATCHED_BIT  01
  169. #define ADDR_BANG_BIT   02
  170.  
  171.  
  172. struct sed_cmd {
  173.         struct addr a1,a2;
  174.         int aflags;
  175.  
  176.         char cmd;
  177.  
  178.         union {
  179.                 /* This structure is used for a, i, and c commands */
  180.                 struct {
  181.                         char *text;
  182.                         int text_len;
  183.                 } cmd_txt;
  184.  
  185.                 /* This is used for b and t commands */
  186.                 struct sed_cmd *label;
  187.  
  188.                 /* This for r and w commands */
  189.                 FILE *io_file;
  190.  
  191.                 /* This for the hairy s command */
  192.                 /* For the flags var:
  193.                    low order bit means the 'g' option was given,
  194.                    next bit means the 'p' option was given,
  195.                    and the next bit means a 'w' option was given,
  196.                       and wio_file contains the file to write to. */
  197.  
  198. #define S_GLOBAL_BIT    01
  199. #define S_PRINT_BIT     02
  200. #define S_WRITE_BIT     04
  201. #define S_NUM_BIT       010
  202.  
  203.                 struct {
  204.                         struct re_pattern_buffer *regx;
  205.                         char *replacement;
  206.                         int replace_length;
  207.                         int flags;
  208.                         int numb;
  209.                         FILE *wio_file;
  210.                 } cmd_regex;
  211.  
  212.                 /* This for the y command */
  213.                 char *translate;
  214.  
  215.                 /* For { and } */
  216.                 struct vector *sub;
  217.                 struct sed_label *jump;
  218.         } x;
  219. };
  220.  
  221. /* Sed operates a line at a time. */
  222. struct line {
  223.         char *text;             /* Pointer to line allocated by malloc. */
  224.         int length;             /* Length of text. */
  225.         int alloc;              /* Allocated space for text. */
  226. };
  227.  
  228. /* This for all you losing compilers out there that can't handle void * */
  229. #ifdef __GNU__
  230. #define VOID void
  231. #else
  232. #define VOID char
  233. #endif
  234.  
  235. extern int optind;
  236. extern char *optarg;
  237. extern int getopt();
  238.  
  239. extern char *memchr();
  240. extern VOID *memmove();
  241.  
  242. extern VOID *ck_malloc(),*ck_realloc();
  243. extern VOID *init_buffer();
  244. extern char *get_buffer();
  245. extern FILE *ck_fopen();
  246. extern void ck_fclose();
  247. extern void ck_fwrite();
  248. extern void flush_buffer();
  249. extern void add1_buffer();
  250.  
  251. extern char *strdup();
  252.  
  253. struct vector *compile_program();
  254. void savchar();
  255. struct sed_label *setup_jump();
  256. void line_copy();
  257. void line_append();
  258. void append_pattern_space();
  259.  
  260. #ifndef HAS_UTILS
  261. char *myname;
  262. #else
  263. extern char *myname;
  264. #endif
  265. /* This is a good idea */
  266. char *version_string = "GNU sed version 1.02 (or so)";
  267. /*      1.00    Began distributing this file
  268.  *      1.01    Added s/re/rep/[digits]
  269.  *              added #n as first line of script
  270.  *              added filename globbing
  271.  *              added 'l' command
  272.  *              All in the name of POSIX
  273.  *      1.02    Fixed D command
  274.  *              Added Amiga porting ifdefs
  275.  *              Edwin Hoogerbeets 1989
  276.  */
  277.  
  278. /* If set, don't write out the line unless explictly told to */
  279. int no_default_output = 0;
  280.  
  281. /* Current input line # */
  282. int input_line_number = 0;
  283.  
  284. /* Are we on the last input file? */
  285. int last_input_file = 0;
  286.  
  287. /* Have we hit EOF on the last input file? */
  288. int input_EOF = 0;
  289.  
  290. /* non-zero if a quit command has been hit */
  291. int quit_cmd = 0;
  292.  
  293. /* Have we done any replacements lately? */
  294. int replaced = 0;
  295.  
  296. /* How many '{'s are we executing at the moment */
  297. int program_depth = 0;
  298.  
  299. /* The current SED program */
  300. struct vector *the_program = 0;
  301.  
  302. /* */
  303. struct sed_label *jumps = 0;
  304. struct sed_label *labels = 0;
  305.  
  306. /* The 'current' input line. */
  307. struct line line;
  308.  
  309. /* An input line that's been stored by later use by the program */
  310. struct line hold;
  311.  
  312. /* A 'line' to append to the current line when it comes time to write it out */
  313. struct line append;
  314.  
  315. static char ONE_ADDR[] = "Command only uses one address";
  316. static char NO_ADDR[] = "Command doesn't take any addresses";
  317. static char LINE_JUNK[] ="Extra characters after command";
  318. static char BAD_EOF[] =  "Unexpected End-of-file";
  319. static char USAGE[] =   "Usage: %s [-n] [-e script...] [-f sfile...] [file...]\n";
  320. static char NO_REGEX[] = "No previous regular expression";
  321.  
  322. struct re_pattern_buffer *last_regex;
  323.  
  324. FILE *input_file;
  325.  
  326. int bad_input = 0;
  327.  
  328. main(argc,argv)
  329. char **argv;
  330. {
  331.         int opt;
  332.         int compiled = 0;
  333.         struct sed_label *go,*lbl;
  334.  
  335. #ifdef AZTEC_C
  336.         extern long _Heapsize;
  337.  
  338.         _Heapsize = 80 * 1024;
  339. #endif
  340.  
  341.         myname=argv[0];
  342.         while((opt=getopt(argc,argv,"ne:f:"))!=EOF) {
  343.                 switch(opt) {
  344.                 case 'n':
  345.                         if(no_default_output)
  346.                                 panic(USAGE);
  347.                         no_default_output++;
  348.                         break;
  349.                 case 'e':
  350.                         compile_string(optarg);
  351.                         compiled++;
  352.                         break;
  353.                 case 'f':
  354.                         compile_file(optarg);
  355.                         compiled++;
  356.                         break;
  357.                 }
  358.         }
  359.         if(!compiled) {
  360.                 if(argc<=optind)
  361.                         panic("No program to run\n");
  362.                 compile_string(argv[optind]);
  363.                 optind++;
  364.         }
  365.  
  366.         for(go=jumps;go;go=go->next) {
  367.                 for(lbl=labels;lbl;lbl=lbl->next)
  368.                         if(!strcmp(lbl->name,go->name))
  369.                                 break;
  370.                 if(!lbl)
  371.                         panic("Can't find label for jump to '%s'\n",go->name);
  372.                 go->v->v[go->v_index].x.jump=lbl;
  373.         }
  374.  
  375.         line.length=0;
  376.         line.alloc=50;
  377.         line.text=ck_malloc(50);
  378.  
  379.         append.length=0;
  380.         append.alloc=50;
  381.         append.text=ck_malloc(50);
  382.  
  383.         hold.length=0;
  384.         hold.alloc=50;
  385.         hold.text=ck_malloc(50);
  386.  
  387.         if(argc<=optind) {
  388.                 last_input_file++;
  389.                 read_file("-");
  390.         } else while(optind<argc) {
  391.                 if(optind==argc-1)
  392.                         last_input_file++;
  393.                 read_file(argv[optind]);
  394.                 optind++;
  395.                 if(quit_cmd)
  396.                         break;
  397.         }
  398.         if(bad_input)
  399.                 exit(2);
  400.         exit(0);
  401. }
  402.  
  403. char *prog_start;
  404. char *prog_end;
  405. char *prog_cur;
  406.  
  407. char *prog_name;
  408. FILE *prog_file;
  409.  
  410. int prog_line = 1;
  411.  
  412. compile_string(str)
  413. char *str;
  414. {
  415.         prog_file = 0;
  416.         prog_line=0;
  417.         prog_start=prog_cur=str;
  418.         prog_end=str+strlen(str);
  419.         the_program=compile_program(the_program);
  420. }
  421.  
  422. compile_file(str)
  423. char *str;
  424. {
  425.         FILE *file;
  426.         int ch;
  427.  
  428.         prog_start=prog_cur=prog_end=0;
  429.         prog_name=str;
  430.         prog_line=1;
  431.         if(str[0]=='-' && str[1]=='\0')
  432.                 prog_file=stdin;
  433.         else
  434.                 prog_file=ck_fopen(str,"r");
  435.         ch=getc(prog_file);
  436.         if(ch=='#') {
  437.                 ch=getc(prog_file);
  438.                 if(ch=='n')
  439.                         no_default_output++;
  440.                 while(ch!=EOF && ch!='\n')
  441.                         ch=getc(prog_file);
  442.         } else if(ch!=EOF)
  443.                 ungetc(ch,prog_file);
  444.         the_program=compile_program(the_program);
  445. }
  446.  
  447. #define MORE_CMDS 40
  448.  
  449. struct vector *
  450. compile_program(vector)
  451. struct vector *vector;
  452. {
  453.         struct sed_cmd *cur_cmd;
  454.         int     ch;
  455.         int     slash;
  456.         VOID    *b;
  457.         char    *string;
  458.         int     num;
  459.  
  460.         FILE *compile_filename();
  461.  
  462.         if(!vector) {
  463.                 vector=(struct vector *)ck_malloc(sizeof(struct vector));
  464.                 vector->v=(struct sed_cmd *)ck_malloc(MORE_CMDS*sizeof(struct sed_cmd));
  465.                 vector->v_allocated=MORE_CMDS;
  466.                 vector->v_length=0;
  467.                 vector->up_one = 0;
  468.                 vector->next_one = 0;
  469.         }
  470.         for(;;) {
  471.                 do ch=inchar();
  472.                 while(ch!=EOF && (isspace(ch) || ch=='\n' || ch==';'));
  473.                 if(ch==EOF)
  474.                         break;
  475.                 savchar(ch);
  476.  
  477.                 if(vector->v_length==vector->v_allocated) {
  478.                         vector->v=(struct sed_cmd *)ck_realloc((VOID *)vector->v,(vector->v_length+MORE_CMDS)*sizeof(struct sed_cmd));
  479.                         vector->v_allocated+=MORE_CMDS;
  480.                 }
  481.                 cur_cmd=vector->v+vector->v_length;
  482.                 vector->v_length++;
  483.  
  484.                 cur_cmd->a1.addr_type=0;
  485.                 cur_cmd->a2.addr_type=0;
  486.                 cur_cmd->aflags=0;
  487.                 cur_cmd->cmd=0;
  488.  
  489.         skip_comment:
  490.                 if(compile_address(&(cur_cmd->a1))) {
  491.                         ch=inchar();
  492.                         if(ch==',') {
  493.                                 do ch=inchar();
  494.                                 while(ch!=EOF && isspace(ch));
  495.                                 savchar(ch);
  496.                                 if(compile_address(&(cur_cmd->a2)))
  497.                                         ;
  498.                                 else
  499.                                         bad_prog("Unexpected ','");
  500.                         } else
  501.                                 savchar(ch);
  502.                 }
  503.                 ch=inchar();
  504.                 if(ch==EOF)
  505.                         break;
  506.  new_cmd:
  507.                 switch(ch) {
  508.                 case '#':
  509.                         if(cur_cmd->a1.addr_type!=0)
  510.                                 bad_prog(NO_ADDR);
  511.                         do ch=inchar();
  512.                         while(ch!=EOF && ch!='\n');
  513.                         goto skip_comment;
  514.                 case '!':
  515.                         if(cur_cmd->aflags & ADDR_BANG_BIT)
  516.                                 bad_prog("Multiple '!'s");
  517.                         cur_cmd->aflags|= ADDR_BANG_BIT;
  518.                         do ch=inchar();
  519.                         while(ch!=EOF && isspace(ch));
  520.                         if(ch==EOF)
  521.                                 bad_prog(BAD_EOF);
  522.                         /* savchar(ch); */
  523.                         goto new_cmd;
  524.                 case 'a':
  525.                 case 'i':
  526.                         if(cur_cmd->a2.addr_type!=0)
  527.                                 bad_prog(ONE_ADDR);
  528.                         /* Fall Through */
  529.                 case 'c':
  530.                         cur_cmd->cmd=ch;
  531.                         if(inchar()!='\\' || inchar()!='\n')
  532.                                 bad_prog(LINE_JUNK);
  533.                         b=init_buffer();
  534.                         while((ch=inchar())!=EOF && ch!='\n') {
  535.                                 if(ch=='\\')
  536.                                         ch=inchar();
  537.                                 add1_buffer(b,ch);
  538.                         }
  539.                         if(ch!=EOF)
  540.                                 add1_buffer(b,ch);
  541.                         num=size_buffer(b);
  542.                         string=(char *)ck_malloc(num);
  543.                         bcopy(get_buffer(b),string,num);
  544.                         flush_buffer(b);
  545.                         cur_cmd->x.cmd_txt.text_len=num;
  546.                         cur_cmd->x.cmd_txt.text=string;
  547.                         break;
  548.                 case '{':
  549.                         cur_cmd->cmd=ch;
  550.                         program_depth++;
  551.                         /* while((ch=inchar())!=EOF && ch!='\n')
  552.                                 if(!isspace(ch))
  553.                                         bad_prog(LINE_JUNK); */
  554.                         cur_cmd->x.sub=compile_program((struct vector *)0);
  555.                         /* FOO JF is this the right thing to do? */
  556.                         break;
  557.                 case '}':
  558.                         if(!program_depth)
  559.                                 bad_prog("Unexpected '}'");
  560.                         --(vector->v_length);
  561.                         while((ch=inchar())!=EOF && ch!='\n')
  562.                                 if(!isspace(ch))
  563.                                         bad_prog(LINE_JUNK);
  564.                         return vector;
  565.                 case ':':
  566.                         cur_cmd->cmd=ch;
  567.                         if(cur_cmd->a1.addr_type!=0)
  568.                                 bad_prog(": doesn't want any addresses");
  569.                         labels=setup_jump(labels,cur_cmd,vector);
  570.                         break;
  571.                 case 'b':
  572.                 case 't':
  573.                         cur_cmd->cmd=ch;
  574.                         jumps=setup_jump(jumps,cur_cmd,vector);
  575.                         break;
  576.                 case 'q':
  577.                 case '=':
  578.                         if(cur_cmd->a2.addr_type)
  579.                                 bad_prog(ONE_ADDR);
  580.                         /* Fall Through */
  581.                 case 'd':
  582.                 case 'D':
  583.                 case 'g':
  584.                 case 'G':
  585.                 case 'h':
  586.                 case 'H':
  587.                 case 'l':
  588.                 case 'n':
  589.                 case 'N':
  590.                 case 'p':
  591.                 case 'P':
  592.                 case 'x':
  593.                         cur_cmd->cmd=ch;
  594.                         do      ch=inchar();
  595.                         while(ch!=EOF && isspace(ch) && ch!='\n' && ch!=';');
  596.                         if(ch!='\n' && ch!=';' && ch!=EOF)
  597.                                 bad_prog(LINE_JUNK);
  598.                         break;
  599.  
  600.                 case 'r':
  601.                         if(cur_cmd->a2.addr_type!=0)
  602.                                 bad_prog(ONE_ADDR);
  603.                         /* FALL THROUGH */
  604.                 case 'w':
  605.                         cur_cmd->cmd=ch;
  606.                         cur_cmd->x.io_file=compile_filename(ch=='r');
  607.                         break;
  608.  
  609.                 case 's':
  610.                         cur_cmd->cmd=ch;
  611.                         b=init_buffer();
  612.                         slash=inchar();
  613.                         while((ch=inchar())!=EOF && ch!=slash) {
  614.                                 if(ch!='\\') {
  615.                                         add1_buffer(b,ch);
  616.                                         continue;
  617.                                 }
  618.                                 ch=inchar();
  619.                                 switch(ch) {
  620.                                 case 'n':
  621.                                         add1_buffer(b,'\n');
  622.                                         break;
  623.                                 /* case 'b':
  624.                                         add1_buffer(b,'\b');
  625.                                         break;
  626.                                 case 'f':
  627.                                         add1_buffer(b,'\f');
  628.                                         break;
  629.                                 case 'r':
  630.                                         add1_buffer(b,'\r');
  631.                                         break;
  632.                                 case 't':
  633.                                         add1_buffer(b,'\t');
  634.                                         break; */
  635.                                 case EOF:
  636.                                         break;
  637.                                 default:
  638.                                         add1_buffer(b,'\\');
  639.                                         add1_buffer(b,ch);
  640.                                         break;
  641.                                 }
  642.                         }
  643.                         if(ch==EOF)
  644.                                 bad_prog(BAD_EOF);
  645.                         if(size_buffer(b)) {
  646.                                 last_regex=(struct re_pattern_buffer *)ck_malloc(sizeof(struct re_pattern_buffer));
  647.                                 last_regex->allocated=size_buffer(b);
  648.                                 last_regex->buffer=ck_malloc(last_regex->allocated);
  649.                                 last_regex->fastmap=0;
  650.                                 last_regex->translate=0;
  651.                                 re_compile_pattern(get_buffer(b),size_buffer(b),last_regex);
  652.                         } else if(!last_regex)
  653.                                 bad_prog(NO_REGEX);
  654.                         cur_cmd->x.cmd_regex.regx=last_regex;
  655.                         flush_buffer(b);
  656.  
  657.                         b=init_buffer();
  658.                         while((ch=inchar())!=EOF && ch!=slash) {
  659.                                 if(ch=='\\') {
  660.                                         int ci;
  661.  
  662.                                         ci=inchar();
  663.                                         if(ci!=EOF) {
  664.                                                 if(ci!='\n')
  665.                                                         add1_buffer(b,ch);
  666.                                                 add1_buffer(b,ci);
  667.                                         }
  668.                                 } else
  669.                                         add1_buffer(b,ch);
  670.                         }
  671.                         cur_cmd->x.cmd_regex.replace_length=size_buffer(b);
  672.                         cur_cmd->x.cmd_regex.replacement=ck_malloc(cur_cmd->x.cmd_regex.replace_length);
  673.                         bcopy(get_buffer(b),cur_cmd->x.cmd_regex.replacement,cur_cmd->x.cmd_regex.replace_length);
  674.                         flush_buffer(b);
  675.  
  676.                         cur_cmd->x.cmd_regex.flags=0;
  677.                         cur_cmd->x.cmd_regex.numb=0;
  678.  
  679.                         if(ch==EOF)
  680.                                 break;
  681.                         do {
  682.                                 ch=inchar();
  683.                                 switch(ch) {
  684.                                 case 'p':
  685.                                         if(cur_cmd->x.cmd_regex.flags&S_PRINT_BIT)
  686.                                                 bad_prog("multiple 'p' options to 's' command");
  687.                                         cur_cmd->x.cmd_regex.flags|=S_PRINT_BIT;
  688.                                         break;
  689.                                 case 'g':
  690.                                         if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT)
  691.                                                 cur_cmd->x.cmd_regex.flags&= ~S_NUM_BIT;
  692.                                         if(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT)
  693.                                                 bad_prog("multiple 'g' options to 's' command");
  694.                                         cur_cmd->x.cmd_regex.flags|=S_GLOBAL_BIT;
  695.                                         break;
  696.                                 case 'w':
  697.                                         cur_cmd->x.cmd_regex.flags|=S_WRITE_BIT;
  698.                                         cur_cmd->x.cmd_regex.wio_file=compile_filename(0);
  699.                                         ch='\n';
  700.                                         break;
  701.                                 case '0': case '1': case '2': case '3':
  702.                                 case '4': case '5': case '6': case '7':
  703.                                 case '8': case '9':
  704.                                         if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT)
  705.                                                 bad_prog("multiple number options to 's' command");
  706.                                         if(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT==0)
  707.                                                 cur_cmd->x.cmd_regex.flags|=S_NUM_BIT;
  708.                                         num = 0;
  709.                                         while(isdigit(ch)) {
  710.                                                 num=num*10+ch-'0';
  711.                                                 ch=inchar();
  712.                                         }
  713.                                         savchar(ch);
  714.                                         cur_cmd->x.cmd_regex.numb=num;
  715.                                         break;
  716.                                 case '\n':
  717.                                 case ';':
  718.                                 case EOF:
  719.                                         break;
  720.                                 default:
  721.                                         bad_prog("Unknown option to 's'");
  722.                                         break;
  723.                                 }
  724.                         } while(ch!=EOF && ch!='\n' && ch!=';');
  725.                         if(ch==EOF)
  726.                                 break;
  727.                         break;
  728.  
  729.                 case 'y':
  730.                         cur_cmd->cmd=ch;
  731.                         string=ck_malloc(256);
  732.                         for(num=0;num<256;num++)
  733.                                 string[num]=num;
  734.                         b=init_buffer();
  735.                         slash=inchar();
  736.                         while((ch=inchar())!=EOF && ch!=slash)
  737.                                 add1_buffer(b,ch);
  738.                         cur_cmd->x.translate=string;
  739.                         string=get_buffer(b);
  740.                         for(num=size_buffer(b);num;--num) {
  741.                                 ch=inchar();
  742.                                 if(ch==EOF)
  743.                                         bad_prog(BAD_EOF);
  744.                                 if(ch==slash)
  745.                                         bad_prog("strings for y command are different lengths");
  746.                                 cur_cmd->x.translate[*string++]=ch;
  747.                         }
  748.                         flush_buffer(b);
  749.                         if(inchar()!=slash || inchar()!='\n')
  750.                                 bad_prog(LINE_JUNK);
  751.                         break;
  752.  
  753.                 default:
  754.                         fprintf(stderr,"sed: Command: %c\n",ch);
  755.                         bad_prog("Unknown command");
  756.                 }
  757.         }
  758.         return vector;
  759. }
  760.  
  761. bad_prog(why)
  762. char *why;
  763. {
  764.         if(prog_line)
  765.                 fprintf(stderr,"%s: file %s line %d: %s\n",myname,prog_name,prog_line,why);
  766.         else
  767.                 fprintf(stderr,"%s: %s\n",myname,why);
  768.         exit(1);
  769. }
  770.  
  771. int
  772. inchar()
  773. {
  774.         int     ch;
  775.         if(prog_file)
  776.                 ch=getc(prog_file);
  777.         else {
  778.                 if(!prog_cur)
  779.                         return EOF;
  780.                 else if(prog_cur==prog_end) {
  781.                         ch=EOF;
  782.                         prog_cur=0;
  783.                 } else
  784.                         ch= *prog_cur++;
  785.         }
  786.         if(ch=='\n' && prog_line)
  787.                 prog_line++;
  788.         return ch;
  789. }
  790.  
  791. void
  792. savchar(ch)
  793. int ch;
  794. {
  795.         if(ch==EOF)
  796.                 return;
  797.         if(ch=='\n' && prog_line>1)
  798.                 --prog_line;
  799.         if(prog_file)
  800.                 ungetc(ch,prog_file);
  801.         else
  802.                 *--prog_cur=ch;
  803. }
  804.  
  805.  
  806. compile_address(addr)
  807. struct addr *addr;
  808. {
  809.         int     ch;
  810.         int     num;
  811.         char    *b,*init_buffer();
  812.  
  813.         ch=inchar();
  814.  
  815.         if(isdigit(ch)) {
  816.                 num=ch-'0';
  817.                 while((ch=inchar())!=EOF && isdigit(ch))
  818.                         num=num*10+ch-'0';
  819.                 while(ch!=EOF && isspace(ch))
  820.                         ch=inchar();
  821.                 savchar(ch);
  822.                 addr->addr_type=ADDR_NUM;
  823.                 addr->addr_number = num;
  824.                 return 1;
  825.         } else if(ch=='/') {
  826.                 addr->addr_type=ADDR_REGEX;
  827.                 b=init_buffer();
  828.                 while((ch=inchar())!=EOF && ch!='/') {
  829.                         add1_buffer(b,ch);
  830.                         if(ch=='\\') {
  831.                                 ch=inchar();
  832.                                 if(ch!=EOF)
  833.                                         add1_buffer(b,ch);
  834.                         }
  835.                 }
  836.                 if(size_buffer(b)) {
  837.                         last_regex=(struct re_pattern_buffer *)ck_malloc(sizeof(struct re_pattern_buffer));
  838.                         last_regex->allocated=size_buffer(b);
  839.                         last_regex->buffer=ck_malloc(last_regex->allocated);
  840.                         last_regex->fastmap=0;
  841.                         last_regex->translate=0;
  842.                         re_compile_pattern(get_buffer(b),size_buffer(b),last_regex);
  843.                 } else if(!last_regex)
  844.                         bad_prog(NO_REGEX);
  845.  
  846.                 addr->addr_regex=last_regex;
  847.                 flush_buffer(b);
  848.                 do ch=inchar();
  849.                 while(ch!=EOF && isspace(ch));
  850.                 savchar(ch);
  851.                 return 1;
  852.         } else if(ch=='$') {
  853.                 addr->addr_type=ADDR_LAST;
  854.                 do ch=inchar();
  855.                 while(ch!=EOF && isspace(ch));
  856.                 savchar(ch);
  857.                 return 1;
  858.         } else
  859.                 savchar(ch);
  860.         return 0;
  861. }
  862.  
  863. struct sed_label *
  864. setup_jump(list,cmd,vec)
  865. struct sed_label *list;
  866. struct sed_cmd *cmd;
  867. struct vector *vec;
  868. {
  869.         struct sed_label *tmp;
  870.         VOID *b;
  871.         int ch;
  872.  
  873.         b=init_buffer();
  874.         while((ch=inchar())!=EOF && ch!='\n')
  875.                 add1_buffer(b,ch);
  876.         add1_buffer(b,'\0');
  877.         tmp=(struct sed_label *)ck_malloc(sizeof(struct sed_label));
  878.         tmp->v=vec;
  879.         tmp->v_index=cmd-vec->v;
  880.         tmp->name=strdup(get_buffer(b));
  881.         tmp->next=list;
  882.         flush_buffer(b);
  883.         return tmp;
  884. }
  885.  
  886. #define NUM_FPS 32
  887. struct {
  888.         FILE *phile;
  889.         char *name;
  890.         int readit;
  891. } file_ptrs[NUM_FPS];
  892.  
  893. FILE *
  894. compile_filename(readit)
  895. {
  896.         char *file_name;
  897.         int n;
  898.         VOID *b;
  899.         int ch;
  900.         char **globbed;
  901.         extern char **glob_filename();
  902.  
  903.         if(inchar()!=' ')
  904.                 bad_prog("missing ' ' before filename");
  905.         b=init_buffer();
  906.         while((ch=inchar())!=EOF && ch!='\n')
  907.                 add1_buffer(b,ch);
  908.         add1_buffer(b,'\0');
  909.         file_name=get_buffer(b);
  910.         globbed=glob_filename(file_name);
  911.         if(globbed==0 || globbed==(char **)-1)
  912.                 bad_prog("can't parse filename");
  913.         if(globbed[0] && globbed[1]!=0)
  914.                 bad_prog("multiple files");
  915.         if(globbed[0])
  916.                 file_name=globbed[0];
  917.         for(n=0;n<NUM_FPS;n++) {
  918.                 if(!file_ptrs[n].name)
  919.                         break;
  920.                 if(!strcmp(file_ptrs[n].name,file_name)) {
  921.                         if(file_ptrs[n].readit!=readit)
  922.                                 bad_prog("Can't open file for both reading and writing");
  923.                         flush_buffer(b);
  924.                         return file_ptrs[n].phile;
  925.                 }
  926.         }
  927.         if(n<NUM_FPS) {
  928.                 file_ptrs[n].name=strdup(file_name);
  929.                 file_ptrs[n].readit=readit;
  930.                 file_ptrs[n].phile=ck_fopen(file_name,readit ? "r" : "a");
  931.                 flush_buffer(b);
  932.                 return file_ptrs[n].phile;
  933.         } else {
  934.                 bad_prog("Hopelessely evil compiled in limit on number of open files.  re-compile sed\n");
  935.                 return 0;
  936.         }
  937. }
  938.  
  939. read_file(name)
  940. char *name;
  941. {
  942.         if(*name=='-' && name[1]=='\0')
  943.                 input_file=stdin;
  944.         else {
  945.                 input_file=fopen(name,"r");
  946.                 if(input_file==0) {
  947.                         bad_input++;
  948.                         return;
  949.                 }
  950.         }
  951.         while(read_pattern_space()) {
  952.                 execute_program(the_program);
  953.                 if(!no_default_output)
  954.                         ck_fwrite(line.text,1,line.length,stdout);
  955.                 if(append.length) {
  956.                         ck_fwrite(append.text,1,append.length,stdout);
  957.                         append.length=0;
  958.                 }
  959.                 if(quit_cmd)
  960.                         break;
  961.         }
  962.         ck_fclose(input_file);
  963. }
  964.  
  965. execute_program(vec)
  966. struct vector *vec;
  967. {
  968.         struct sed_cmd *cur_cmd;
  969.         int     n;
  970.         int addr_matched;
  971.         static int end_cycle;
  972.  
  973.         int start;
  974.         int remain;
  975.         int offset;
  976.  
  977.         static struct line tmp;
  978.         struct line t;
  979.         char *rep,*rep_end,*rep_next,*rep_cur;
  980.  
  981.         struct re_registers regs;
  982.         int count = 0;
  983.         void str_append();
  984.  
  985.  
  986.         end_cycle = 0;
  987.  
  988.         for(cur_cmd=vec->v,n=vec->v_length;n;cur_cmd++,n--) {
  989.  
  990.         exe_loop:
  991.                 addr_matched=0;
  992.                 if(cur_cmd->aflags&A1_MATCHED_BIT) {
  993.                         addr_matched=1;
  994.                         if(match_address(&(cur_cmd->a2)))
  995.                                 cur_cmd->aflags&=~A1_MATCHED_BIT;
  996.                 } else if(match_address(&(cur_cmd->a1))) {
  997.                         addr_matched=1;
  998.                         if(cur_cmd->a2.addr_type!=ADDR_NULL)
  999.                                 cur_cmd->aflags|=A1_MATCHED_BIT;
  1000.                 }
  1001.                 if(cur_cmd->aflags&ADDR_BANG_BIT)
  1002.                         addr_matched= !addr_matched;
  1003.                 if(!addr_matched)
  1004.                         continue;
  1005.                 switch(cur_cmd->cmd) {
  1006.                 case '{':       /* Execute sub-program */
  1007.                         execute_program(cur_cmd->x.sub);
  1008.                         break;
  1009.  
  1010.                 case ':':       /* Executing labels is easy. */
  1011.                         break;
  1012.  
  1013.                 case '=':
  1014.                         printf("%d\n",input_line_number);
  1015.                         break;
  1016.  
  1017.                 case 'a':
  1018.                         if(append.alloc-append.length<cur_cmd->x.cmd_txt.text_len) {
  1019.                                 append.text=ck_realloc(append.text,append.alloc+cur_cmd->x.cmd_txt.text_len);
  1020.                                 append.alloc+=cur_cmd->x.cmd_txt.text_len;
  1021.                         }
  1022.                         bcopy(cur_cmd->x.cmd_txt.text,append.text+append.length,cur_cmd->x.cmd_txt.text_len);
  1023.                         append.length+=cur_cmd->x.cmd_txt.text_len;
  1024.                         break;
  1025.  
  1026.                 case 'b':
  1027.                         if(!cur_cmd->x.jump)
  1028.                                 end_cycle++;
  1029.                         else {
  1030.                                 struct sed_label *j = cur_cmd->x.jump;
  1031.  
  1032.                                 n= j->v->v_length - j->v_index;
  1033.                                 cur_cmd= j->v->v + j->v_index;
  1034.                                 goto exe_loop;
  1035.                         }
  1036.                         break;
  1037.  
  1038.                 case 'c':
  1039.                         line.length=0;
  1040.                         if(!(cur_cmd->aflags&A1_MATCHED_BIT))
  1041.                                 ck_fwrite(cur_cmd->x.cmd_txt.text,1,cur_cmd->x.cmd_txt.text_len,stdout);
  1042.                         end_cycle++;
  1043.                         break;
  1044.  
  1045.                 case 'd':
  1046.                         line.length=0;
  1047.                         end_cycle++;
  1048.                         break;
  1049.  
  1050.                 case 'D':
  1051.                         {
  1052.                                 char *tmp;
  1053.                                 int newlength;
  1054.  
  1055.                                 tmp=memchr(line.text,'\n',line.length);
  1056.                                 newlength=line.length-(tmp-line.text+1);
  1057.                                 if(newlength)
  1058.                                         memmove(line.text,tmp,newlength);
  1059.                                 line.length=newlength;
  1060.                         }
  1061.                         end_cycle++;
  1062.                         break;
  1063.  
  1064.                 case 'g':
  1065.                         line_copy(&hold,&line);
  1066.                         break;
  1067.  
  1068.                 case 'G':
  1069.                         line_append(&hold,&line);
  1070.                         break;
  1071.  
  1072.                 case 'h':
  1073.                         line_copy(&line,&hold);
  1074.                         break;
  1075.  
  1076.                 case 'H':
  1077.                         line_append(&line,&hold);
  1078.                         break;
  1079.  
  1080.                 case 'i':
  1081.                         ck_fwrite(cur_cmd->x.cmd_txt.text,1,cur_cmd->x.cmd_txt.text_len,stdout);
  1082.                         break;
  1083.  
  1084.                 case 'l':
  1085.                         {
  1086.                                 char *tmp;
  1087.                                 int n;
  1088.                                 int width = 0;
  1089.  
  1090.                                 n=line.length;
  1091.                                 tmp=line.text;
  1092.                                 /* Use --n so this'll skip the trailing newline */
  1093.                                 while(--n) {
  1094.                                         if(width>77) {
  1095.                                                 width=0;
  1096.                                                 putchar('\n');
  1097.                                         }
  1098.                                         if(isprint(*tmp)) {
  1099.                                                 putchar(*tmp);
  1100.                                                 width++;
  1101.                                         } else switch(*tmp) {
  1102.                                         case '\0':
  1103.                                                 printf("\\0");
  1104.                                                 width+=2;
  1105.                                                 break;
  1106.                                         case '\a':
  1107.                                                 printf("\\a");
  1108.                                                 width+=2;
  1109.                                                 break;
  1110.                                         case '\b':
  1111.                                                 printf("\\b");
  1112.                                                 width+=2;
  1113.                                                 break;
  1114.                                         case '\f':
  1115.                                                 printf("\\f");
  1116.                                                 width+=2;
  1117.                                                 break;
  1118.                                         case '\n':
  1119.                                                 printf("\\n");
  1120.                                                 width+=2;
  1121.                                                 break;
  1122.                                         case '\r':
  1123.                                                 printf("\\r");
  1124.                                                 width+=2;
  1125.                                                 break;
  1126.                                         case '\t':
  1127.                                                 printf("\\t");
  1128.                                                 width+=2;
  1129.                                                 break;
  1130.                                         case '\v':
  1131.                                                 printf("\\v");
  1132.                                                 width+=2;
  1133.                                                 break;
  1134.                                         default:
  1135.                                                 printf("/%02x",(*tmp)&0xFF);
  1136.                                                 width+=2;
  1137.                                                 break;
  1138.                                         }
  1139.                                         tmp++;
  1140.                                 }
  1141.                                 putchar('\n');
  1142.                         }
  1143.                         break;
  1144.  
  1145.                 case 'n':
  1146.                         ck_fwrite(line.text,1,line.length,stdout);
  1147.                         read_pattern_space();
  1148.                         break;
  1149.  
  1150.                 case 'N':
  1151.                         append_pattern_space();
  1152.                         break;
  1153.  
  1154.                 case 'p':
  1155.                         ck_fwrite(line.text,1,line.length,stdout);
  1156.                         break;
  1157.  
  1158.                 case 'P':
  1159.                         {
  1160.                                 char *tmp;
  1161.  
  1162.                                 tmp=memchr(line.text,'\n',line.length);
  1163.                                 ck_fwrite(line.text,1,line.length-(tmp-line.text),stdout);
  1164.                         }
  1165.                         break;
  1166.  
  1167.                 case 'q':
  1168.                         quit_cmd++;
  1169.                         end_cycle++;
  1170.                         break;
  1171.  
  1172.                 case 'r':
  1173.                         {
  1174.                                 int n;
  1175.                                 char tmp_buf[1024];
  1176.  
  1177.                                 rewind(cur_cmd->x.io_file);
  1178.                                 while((n=fread(tmp_buf,sizeof(char),1024,cur_cmd->x.io_file))>0)
  1179.                                         ck_fwrite(tmp_buf,sizeof(char),n,stdout);
  1180.                                 if(ferror(cur_cmd->x.io_file))
  1181.                                         panic("Read error on input file to 'r' command\n");
  1182.                         }
  1183.                         break;
  1184.  
  1185.                 case 's':
  1186.                         if(!tmp.alloc) {
  1187.                                 tmp.alloc=50;
  1188.                                 tmp.text=ck_malloc(50);
  1189.                         }
  1190.                         count=0;
  1191.                         start = 0;
  1192.                         remain=line.length-1;
  1193.                         tmp.length=0;
  1194.                         rep = cur_cmd->x.cmd_regex.replacement;
  1195.                         rep_end=rep+cur_cmd->x.cmd_regex.replace_length;
  1196.  
  1197.                         while((offset = re_search(cur_cmd->x.cmd_regex.regx,
  1198.                                                   line.text,
  1199.                                                   line.length-1,
  1200.                                                   start,
  1201.                                                   remain,
  1202.                                                   ®s))>=0) {
  1203.                                 count++;
  1204.                                 if(offset-start)
  1205.                                         str_append(&tmp,line.text+start,offset-start);
  1206.  
  1207.                                 if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT) {
  1208.                                         if(count!=cur_cmd->x.cmd_regex.numb) {
  1209.                                                 str_append(&tmp,line.text+regs.start[0],regs.end[0]-regs.start[0]);
  1210.                                                 start = (offset == regs.end[0] ? offset + 1 : regs.end[0]);
  1211.                                                 remain = (line.length-1) - start;
  1212.                                                 continue;
  1213.                                         }
  1214.                                 }
  1215.  
  1216.                                 for(rep_next=rep_cur=rep;rep_next<rep_end;rep_next++) {
  1217.                                         if(*rep_next=='&') {
  1218.                                                 if(rep_next-rep_cur)
  1219.                                                         str_append(&tmp,rep_cur,rep_next-rep_cur);
  1220.                                                 str_append(&tmp,line.text+regs.start[0],regs.end[0]-regs.start[0]);
  1221.                                                 rep_cur=rep_next+1;
  1222.                                         } else if(*rep_next=='\\') {
  1223.                                                 if(rep_next-rep_cur)
  1224.                                                         str_append(&tmp,rep_cur,rep_next-rep_cur);
  1225.                                                 rep_next++;
  1226.                                                 if(rep_next!=rep_end) {
  1227.                                                         int n;
  1228.  
  1229.                                                         if(*rep_next>='0' && *rep_next<='9') {
  1230.                                                                 n= *rep_next -'0';
  1231.                                                                 str_append(&tmp,line.text+regs.start[n],regs.end[n]-regs.start[n]);
  1232.                                                         } else
  1233.                                                                 str_append(&tmp,&rep_next,1);
  1234.                                                 }
  1235.                                                 rep_cur=rep_next+1;
  1236.                                         }
  1237.                                 }
  1238.                                 if(rep_next-rep_cur)
  1239.                                         str_append(&tmp,rep_cur,rep_next-rep_cur);
  1240.                                 start = (offset == regs.end[0] ? offset + 1 : regs.end[0]);
  1241.                                 remain = (line.length-1) - start;
  1242.                                 if(!(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT))
  1243.                                         break;
  1244.                         }
  1245.                         if(!count)
  1246.                                 break;
  1247.                         replaced=1;
  1248.                         str_append(&tmp,line.text+regs.end[0],line.length-regs.end[0]);
  1249.                         t.text=line.text;
  1250.                         t.length=line.length;
  1251.                         t.alloc=line.alloc;
  1252.                         line.text=tmp.text;
  1253.                         line.length=tmp.length;
  1254.                         line.alloc=tmp.alloc;
  1255.                         tmp.text=t.text;
  1256.                         tmp.length=t.length;
  1257.                         tmp.alloc=t.alloc;
  1258.                         if(cur_cmd->x.cmd_regex.flags&S_WRITE_BIT)
  1259.                                 ck_fwrite(line.text,1,line.length,cur_cmd->x.cmd_regex.wio_file);
  1260.                         if(cur_cmd->x.cmd_regex.flags&S_PRINT_BIT)
  1261.                                 ck_fwrite(line.text,1,line.length,stdout);
  1262.                         break;
  1263.  
  1264.                 case 't':
  1265.                         if(replaced) {
  1266.                                 replaced = 0;
  1267.                                 if(!cur_cmd->x.jump)
  1268.                                         end_cycle++;
  1269.                                 else {
  1270.                                         struct sed_label *j = cur_cmd->x.jump;
  1271.  
  1272.                                         n= j->v->v_length - j->v_index;
  1273.                                         cur_cmd= j->v->v + j->v_index;
  1274.                                         goto exe_loop;
  1275.                                 }
  1276.                         }
  1277.                         break;
  1278.  
  1279.                 case 'w':
  1280.                         ck_fwrite(line.text,1,line.length,cur_cmd->x.io_file);
  1281.                         break;
  1282.  
  1283.                 case 'x':
  1284.                         {
  1285.                                 struct line tmp;
  1286.  
  1287.                                 tmp=line;
  1288.                                 line=hold;
  1289.                                 hold=tmp;
  1290.                         }
  1291.                         break;
  1292.  
  1293.                 case 'y':
  1294.                         {
  1295.                                 unsigned char *p,*e;
  1296.  
  1297.                                 for(p=(unsigned char *)(line.text),e=p+line.length;p<e;p++)
  1298.                                         *p=cur_cmd->x.translate[*p];
  1299.                         }
  1300.                         break;
  1301.  
  1302.                 default:
  1303.                         panic("INTERNAL ERROR: Bad cmd %c\n",cur_cmd->cmd);
  1304.                 }
  1305.                 if(end_cycle)
  1306.                         break;
  1307.         }
  1308. }
  1309.  
  1310.  
  1311. match_address(addr)
  1312. struct addr *addr;
  1313. {
  1314.         switch(addr->addr_type) {
  1315.         case ADDR_NULL:
  1316.                 return 1;
  1317.         case ADDR_NUM:
  1318.                 return (input_line_number==addr->addr_number);
  1319.  
  1320.         case ADDR_REGEX:
  1321.                 return (re_search(addr->addr_regex,
  1322.                                   line.text,
  1323.                                   line.length-1,
  1324.                                   0,
  1325.                                   line.length-1,
  1326.                                   0)>=0) ? 1 : 0;
  1327.  
  1328.         case ADDR_LAST:
  1329.                 return (input_EOF) ? 1 : 0;
  1330.  
  1331.         default:
  1332.                 panic("INTERNAL ERROR: bad address type\n");
  1333.                 break;
  1334.         }
  1335.         return -1;
  1336. }
  1337.  
  1338. int
  1339. read_pattern_space()
  1340. {
  1341.         int n;
  1342.         char *p;
  1343.         int ch;
  1344.  
  1345.         p=line.text;
  1346.         n=line.alloc;
  1347.  
  1348.         input_line_number++;
  1349.         replaced=0;
  1350.         for(;;) {
  1351.                 ch=getc(input_file);
  1352.                 if(ch==EOF) {
  1353.                         if(n==line.alloc)
  1354.                                 return 0;
  1355.                         *p++='\n';
  1356.                         --n;
  1357.                         line.length=line.alloc-n;
  1358.                         break;
  1359.                 }
  1360.                 *p++=ch;
  1361.                 --n;
  1362.                 if(ch=='\n') {
  1363.                         line.length=line.alloc-n;
  1364.                         break;
  1365.                 }
  1366.                 if(n==0) {
  1367.                         line.text=ck_realloc(line.text,line.alloc*2);
  1368.                         p=line.text+line.alloc;
  1369.                         n=line.alloc;
  1370.                         line.alloc*=2;
  1371.                 }
  1372.         }
  1373.         ch=getc(input_file);
  1374.         if(ch!=EOF)
  1375.                 ungetc(ch,input_file);
  1376.         else if(last_input_file)
  1377.                 input_EOF++;
  1378.         return 1;
  1379. }
  1380.  
  1381. void
  1382. append_pattern_space()
  1383. {
  1384.         char *p;
  1385.         int n;
  1386.         int ch;
  1387.  
  1388.         p=line.text+line.length;
  1389.         n=line.alloc-line.length;
  1390.  
  1391.         input_line_number++;
  1392.         replaced=0;
  1393.         for(;;) {
  1394.                 ch=getc(input_file);
  1395.                 if(ch==EOF) {
  1396.                         if(n==line.alloc)
  1397.                                 return;
  1398.                         *p++='\n';
  1399.                         --n;
  1400.                         line.length=line.alloc-n;
  1401.                         break;
  1402.                 }
  1403.                 *p++=ch;
  1404.                 --n;
  1405.                 if(ch=='\n') {
  1406.                         line.length=line.alloc-n;
  1407.                         break;
  1408.                 }
  1409.                 if(n==0) {
  1410.                         line.text=ck_realloc(line.text,line.alloc*2);
  1411.                         p=line.text+line.alloc;
  1412.                         n=line.alloc;
  1413.                         line.alloc*=2;
  1414.                 }
  1415.         }
  1416.         ch=getc(input_file);
  1417.         if(ch!=EOF)
  1418.                 ungetc(ch,input_file);
  1419.         else if(last_input_file)
  1420.                 input_EOF++;
  1421. }
  1422.  
  1423. void
  1424. line_copy(from,to)
  1425. struct line *from,*to;
  1426. {
  1427.         if(from->length>to->alloc) {
  1428.                 to->alloc=from->length;
  1429.                 to->text=ck_realloc(to->text,to->alloc);
  1430.         }
  1431.         bcopy(from->text,to->text,from->length);
  1432.         to->length=from->length;
  1433. }
  1434.  
  1435. void
  1436. line_append(from,to)
  1437. struct line *from,*to;
  1438. {
  1439.         if(from->length>(to->alloc-to->length)) {
  1440.                 to->alloc+=from->length;
  1441.                 to->text=ck_realloc(to->text,to->alloc);
  1442.         }
  1443.         bcopy(from->text,to->text+to->length,from->length);
  1444.         to->length+=from->length;
  1445. }
  1446.  
  1447. void
  1448. str_append(to,string,length)
  1449. struct line *to;
  1450. char *string;
  1451. int length;
  1452. {
  1453.         if(length>to->alloc-to->length) {
  1454.                 to->alloc+=length;
  1455.                 to->text=ck_realloc(to->text,to->alloc);
  1456.         }
  1457.         bcopy(string,to->text+to->length,length);
  1458.         to->length+=length;
  1459. }
  1460.  
  1461. #ifndef HAS_UTILS
  1462.  
  1463. #ifdef __STDC__
  1464. #include "stdarg.h"
  1465.  
  1466. panic(str)
  1467. char *str;
  1468. {
  1469.         va_list iggy;
  1470.  
  1471.         va_start(iggy,str);
  1472.         fprintf(stderr,"%s: ",myname);
  1473. #ifdef NO_VFPRINTF
  1474.         _doprnt(str,&iggy,stderr);
  1475. #else
  1476.         vfprintf(stderr,str,iggy);
  1477. #endif
  1478.         putc('\n',stderr);
  1479.         va_end(iggy);
  1480.         exit(4);
  1481. }
  1482.  
  1483. #else
  1484. #ifdef AZTEC_C
  1485.  
  1486. /* this kludge inserted because of lack of vfprintf or _doprnt in the
  1487.  * Manx libs, and this was easier than rewriting printf, which I have
  1488.  * no source to! Delete this if and when vfprintf is written on the Amiga.
  1489.  */
  1490. panic(str,arg1,arg2,arg3)
  1491. char *str;
  1492. int arg1,arg2,arg3;
  1493. {
  1494.   fprintf(stderr,"%s: ",myname);
  1495.   fprintf(stderr,str,arg1,arg2,arg3);
  1496.   fprintf(stderr,"\n");
  1497.   exit(4);
  1498. }
  1499. #else
  1500. #include "varargs.h"
  1501.  
  1502. panic(str,va_alist)
  1503. char *str;
  1504. va_dcl
  1505. {
  1506.         va_list iggy;
  1507.  
  1508.         va_start(iggy);
  1509.         fprintf(stderr,"%s: ",myname);
  1510. #ifdef NO_VFPRINTF
  1511.         _doprnt(str,&iggy,stderr);
  1512. #else
  1513.         vfprintf(stderr,str,iggy);
  1514. #endif
  1515.         putc('\n',stderr);
  1516.         va_end(iggy);
  1517.         exit(4);
  1518. }
  1519.  
  1520. #endif
  1521. #endif
  1522.  
  1523. #define N_FILE 20
  1524.  
  1525. struct id {
  1526.         FILE *fp;
  1527.         char *name;
  1528. };
  1529.  
  1530. static struct id __id_s[N_FILE];
  1531.  
  1532. char *
  1533. __fp_name(fp)
  1534. FILE *fp;
  1535. {
  1536.         int n;
  1537.  
  1538.         for(n=0;n<N_FILE;n++) {
  1539.                 if(__id_s[n].fp==fp)
  1540.                         return __id_s[n].name;
  1541.         }
  1542.         return "{Unknown file pointer}";
  1543. }
  1544.  
  1545. /* Panic on failing fopen */
  1546. FILE *
  1547. ck_fopen(name,mode)
  1548. char *name;
  1549. char *mode;
  1550. {
  1551.         FILE    *ret;
  1552.         int     n;
  1553.  
  1554.         ret=fopen(name,mode);
  1555.         if(ret==(FILE *)0)
  1556.                 panic("Couldn't open file %s\n",name);
  1557.         for(n=0;n<N_FILE;n++) {
  1558.                 if(ret==__id_s[n].fp) {
  1559.                         free((VOID *)__id_s[n].name);
  1560.                         __id_s[n].name=(char *)ck_malloc(strlen(name)+1);
  1561.                         strcpy(__id_s[n].name,name);
  1562.                         break;
  1563.                 }
  1564.         }
  1565.         if(n==N_FILE) {
  1566.                 for(n=0;n<N_FILE;n++)
  1567.                         if(__id_s[n].fp==(FILE *)0)
  1568.                                 break;
  1569.                 if(n==N_FILE)
  1570.                         panic("Internal error: too many files open\n");
  1571.                 __id_s[n].fp=ret;
  1572.                 __id_s[n].name=(char *)ck_malloc(strlen(name)+1);
  1573.                 strcpy(__id_s[n].name,name);
  1574.         }
  1575.         return ret;
  1576. }
  1577.  
  1578. void
  1579. ck_fwrite(ptr,size,nmemb,stream)
  1580. char *ptr;
  1581. int size,nmemb;
  1582. FILE *stream;
  1583. {
  1584.         if(fwrite(ptr,size,nmemb,stream)!=nmemb)
  1585.                 panic("couldn't write %d items to %s",nmemb,__fp_name(stream));
  1586. }
  1587.  
  1588. void
  1589. ck_fclose(stream)
  1590. FILE *stream;
  1591. {
  1592.         if(fclose(stream)==EOF)
  1593.                 panic("Couldn't close %s\n",__fp_name(stream));
  1594. }
  1595.  
  1596. VOID *
  1597. ck_malloc(size)
  1598. int size;
  1599. {
  1600.         VOID *ret;
  1601.         VOID *malloc();
  1602.  
  1603.         ret=malloc(size);
  1604.         if(ret==(VOID *)0)
  1605.                 panic("Couldn't allocate memory\n");
  1606.         return ret;
  1607. }
  1608.  
  1609. VOID *
  1610. ck_realloc(ptr,size)
  1611. VOID *ptr;
  1612. int size;
  1613. {
  1614.         VOID *ret;
  1615.         VOID *realloc();
  1616.  
  1617.         ret=realloc(ptr,size);
  1618.         if(ret==(VOID *)0)
  1619.                 panic("Couldn't re-allocate memory\n");
  1620.         return ret;
  1621. }
  1622.  
  1623. char *
  1624. strdup(str)
  1625. char *str;
  1626. {
  1627.         char *ret;
  1628.  
  1629.         ret=(char *)ck_malloc(strlen(str)+2);
  1630.         strcpy(ret,str);
  1631.         return ret;
  1632. }
  1633.  
  1634.  
  1635. #ifndef AZTEC_C
  1636. /*
  1637.  * memmove - copy bytes, being careful about overlap.
  1638.  */
  1639.  
  1640. VOID *
  1641. memmove(dst, src, size)
  1642. VOID *dst;
  1643. VOID *src;
  1644. int size;
  1645. {
  1646.         register char *d;
  1647.         register char *s;
  1648.         register int n;
  1649.  
  1650.         if (size <= 0)
  1651.                 return(dst);
  1652.  
  1653.         s = (char *)src;
  1654.         d = (char *)dst;
  1655.         if (s <= d && s + (size-1) >= d) {
  1656.                 /* Overlap, must copy right-to-left. */
  1657.                 s += size-1;
  1658.                 d += size-1;
  1659.                 for (n = size; n > 0; n--)
  1660.                         *d-- = *s--;
  1661.         } else
  1662.                 for (n = size; n > 0; n--)
  1663.                         *d++ = *s++;
  1664.  
  1665.         return(dst);
  1666. }
  1667. #else
  1668.  
  1669. VOID *
  1670. memmove(dst,src,size)
  1671. VOID *dst;
  1672. VOID *src;
  1673. int size;
  1674. {
  1675.   return ( (VOID *) movmem(src,dst,size) );
  1676. }
  1677.  
  1678. VOID *memchr(mem,val,len)
  1679. char *mem;
  1680. int val,len;
  1681. {
  1682.   register int index = 0;
  1683.  
  1684.   while ( index < len ) {
  1685.     if ( mem[index] == (char) val ) {
  1686.       return(&mem[index]);
  1687.     }
  1688.     ++index;
  1689.   }
  1690.  
  1691.   return(NULL);
  1692. }
  1693.  
  1694. #endif
  1695.  
  1696. /* Implement a variable sized buffer of 'stuff'.  We don't know what it is,
  1697.    nor do we care, as long as it doesn't mind being aligned on a char boundry.
  1698.    'b' could be made non-global, with a little work, so we could have more
  1699.    than one buffer, but we don't need more than one, so why bother? */
  1700.  
  1701.  
  1702. struct buffer {
  1703.         int     allocated;
  1704.         int     length;
  1705.         char    *b;
  1706. };
  1707.  
  1708. #define MIN_ALLOCATE 50
  1709.  
  1710. VOID *
  1711. init_buffer()
  1712. {
  1713.         struct buffer *b;
  1714.  
  1715.         b=(struct buffer *)ck_malloc(sizeof(struct buffer));
  1716.         b->allocated=MIN_ALLOCATE;
  1717.         b->b=(char *)ck_malloc(MIN_ALLOCATE);
  1718.         b->length=0;
  1719.         return (VOID *)b;
  1720. }
  1721.  
  1722. void
  1723. flush_buffer(bb)
  1724. VOID *bb;
  1725. {
  1726.         struct buffer *b;
  1727.  
  1728.         b=(struct buffer *)bb;
  1729.         free(b->b);
  1730.         b->b=0;
  1731.         b->allocated=0;
  1732.         b->length=0;
  1733.         free(b);
  1734. }
  1735.  
  1736. int
  1737. size_buffer(b)
  1738. VOID *b;
  1739. {
  1740.         struct buffer *bb;
  1741.  
  1742.         bb=(struct buffer *)b;
  1743.         return bb->length;
  1744. }
  1745.  
  1746. void
  1747. add_buffer(bb,p,n)
  1748. VOID *bb;
  1749. char *p;
  1750. int n;
  1751. {
  1752.         struct buffer *b;
  1753.  
  1754.         b=(struct buffer *)bb;
  1755.         if(b->length+n>b->allocated) {
  1756.                 b->allocated*=2;
  1757.                 b->b=(char *)ck_realloc(b->b,b->allocated);
  1758.         }
  1759.         bcopy(p,b->b+b->length,n);
  1760.         b->length+=n;
  1761. }
  1762.  
  1763. void
  1764. add1_buffer(bb,ch)
  1765. VOID *bb;
  1766. int ch;
  1767. {
  1768.         struct buffer *b;
  1769.  
  1770.         b=(struct buffer *)bb;
  1771.         if(b->length+1>b->allocated) {
  1772.                 b->allocated*=2;
  1773.                 b->b=(char *)ck_realloc(b->b,b->allocated);
  1774.         }
  1775.         b->b[b->length]=ch;
  1776.         b->length++;
  1777. }
  1778.  
  1779. char *
  1780. get_buffer(bb)
  1781. VOID *bb;
  1782. {
  1783.         struct buffer *b;
  1784.  
  1785.         b=(struct buffer *)bb;
  1786.         return b->b;
  1787. }
  1788.  
  1789. #endif
  1790.