home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / SED106AS.ZIP / SED.C < prev   
Encoding:
C/C++ Source or Header  |  1992-02-22  |  43.7 KB  |  1,987 lines

  1. /*  GNU SED, a batch stream editor.
  2.     Copyright (C) 1989, Free Software Foundation, Inc.
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 1, or (at your option)
  7.     any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /*  MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  19.     This port is also distributed under the terms of the
  20.     GNU General Public License as published by the
  21.     Free Software Foundation.
  22.  
  23.     Please note that this file is not identical to the
  24.     original GNU release, you should have received this
  25.     code as patch to the official release.  */
  26.  
  27. #ifdef MSDOS
  28. static char RCS_Id[] =
  29.   "$Header: e:/gnu/sed/RCS/sed.c 1.6.1.2 90/09/22 17:14:48 tho Exp $";
  30. #endif
  31.  
  32. #include <stdio.h>
  33. #include <ctype.h>
  34.  
  35. #include <regex.h>
  36.  
  37. /* Compile with 'gcc [-g] [-DHAS_UTILS] [-O] -o sed sed.c [-lutils]' */
  38. /* Use '-DHAS_UTILS', -lutils if you if you have hack's utils library */
  39. /* Add '-I. regex.c' if regex is not in the system include dir/library */
  40.  
  41. /* This is a good idea */
  42.  
  43. #ifdef MSDOS
  44.  
  45. static char Program_Id[] = "sed";
  46. static char RCS_Revision[] = "$Revision: 1.6.1.2 $";
  47.  
  48. #define VERSION \
  49.   "GNU %s, Version %.*s (compiled %s %s for MS-DOS)\n", Program_Id, \
  50.   (sizeof RCS_Revision - 14), (RCS_Revision + 11), __DATE__, __TIME__
  51.  
  52. #define COPYING \
  53.   "This is free software, distributed under the terms of the\n" \
  54.   "GNU General Public License.  For details, see the file COPYING.\n"
  55.  
  56. #else /* not MSDOS */
  57.  
  58. char *version_string = "GNU sed version 1.06 (or so)";
  59.  
  60. #endif /* not MSDOS */
  61. /*
  62.     1.00    Began (thinking about) distributing this file
  63.     1.01    Added s/re/rep/[digits]
  64.         added #n as first line of script
  65.         added filename globbing
  66.         added 'l' command
  67.         All in the name of POSIX
  68.     1.02    Fixed 't', 'b', ':' to trim leading spaces and tabs
  69.         Fixed \\ in replacement of 's' command
  70.         Added comments
  71.     1.03    Fixes from Mike Haertelfor regexps that match the
  72.         empty string, and for Ritchie stdio (non-sticky EOF)
  73.     1.04    Fixed s/re/rep/[number]
  74.     1.05    Fixed error in 'r' (now does things in the right order)
  75.  */
  76.  
  77. #ifdef USG
  78. #define bcopy( s, d, n) ((void)memmove((d), (s), (n)))
  79. #endif
  80.  
  81. /* Struct vector is used to describe a chunk of a sed program.  There is one
  82.    vector for the main program, and one for each { } pair.
  83.  */
  84. struct vector {
  85.     struct sed_cmd *v;
  86.     int v_length;
  87.     int v_allocated;
  88.     struct vector *up_one;
  89.     struct vector *next_one;
  90. };
  91.  
  92.  
  93. /* Goto structure is used to hold both GOTO's and labels.  There are two
  94.    separate lists, one of goto's, called 'jumps', and one of labels, called
  95.    'labels'.
  96.    the V element points to the descriptor for the program-chunk in which the
  97.    goto was encountered.
  98.    the v_index element counts which element of the vector actually IS the
  99.    goto/label.  The first element of the vector is zero.
  100.    the NAME element is the null-terminated name of the label.
  101.    next is the next goto/label in the list
  102. */
  103.  
  104. struct sed_label {
  105.     struct vector *v;
  106.     int v_index;
  107.     char *name;
  108.     struct sed_label *next;
  109. };
  110.  
  111. /* ADDR_TYPE is zero for a null address,
  112.    one if addr_number is valid, or
  113.    two if addr_regex is valid,
  114.    three, if the address is '$'
  115.  
  116.    Other values are undefined.
  117.  */
  118.  
  119. #define ADDR_NULL    0
  120. #define ADDR_NUM    1
  121. #define ADDR_REGEX    2
  122. #define ADDR_LAST    3
  123.     
  124. struct addr {
  125.     int    addr_type;
  126.     struct re_pattern_buffer *addr_regex;
  127.     int    addr_number;
  128. };
  129.  
  130.  
  131. /* Aflags:  If the low order bit is set, a1 has been
  132.    matched; apply this command until a2 matches.
  133.    If the next bit is set, apply this command to all
  134.    lines that DON'T match the address(es).
  135.  */
  136.  
  137. #define A1_MATCHED_BIT    01
  138. #define ADDR_BANG_BIT    02
  139.  
  140.  
  141. struct sed_cmd {
  142.     struct addr a1,a2;
  143.     int aflags;
  144.  
  145.     char cmd;
  146.  
  147.     union {
  148.         /* This structure is used for a, i, and c commands */
  149.         struct {
  150.             char *text;
  151.             int text_len;
  152.         } cmd_txt;
  153.  
  154.         /* This is used for b and t commands */
  155.         struct sed_cmd *label;
  156.  
  157.         /* This for r and w commands */
  158.         FILE *io_file;
  159.  
  160.         /* This for the hairy s command */
  161.         /* For the flags var:
  162.            low order bit means the 'g' option was given,
  163.            next bit means the 'p' option was given,
  164.            and the next bit means a 'w' option was given,
  165.               and wio_file contains the file to write to. */
  166.  
  167. #define S_GLOBAL_BIT    01
  168. #define S_PRINT_BIT    02
  169. #define S_WRITE_BIT    04
  170. #define S_NUM_BIT    010
  171.  
  172.         struct {
  173.             struct re_pattern_buffer *regx;
  174.             char *replacement;
  175.             int replace_length;
  176.             int flags;
  177.             int numb;
  178.             FILE *wio_file;
  179.         } cmd_regex;
  180.  
  181.         /* This for the y command */
  182.         unsigned char *translate;
  183.  
  184.         /* For { and } */
  185.         struct vector *sub;
  186.         struct sed_label *jump;
  187.     } x;
  188. };
  189.  
  190. /* Sed operates a line at a time. */
  191. struct line {
  192.     char *text;        /* Pointer to line allocated by malloc. */
  193.     int length;        /* Length of text. */
  194.     int alloc;        /* Allocated space for text. */
  195. };
  196.  
  197. /* This structure holds information about files opend by the 'r', 'w', and 's///w'
  198.    commands.  In paticular, it holds the FILE pointer to use, the files name,
  199.    a flag that is non-zero if the file is being read instead of written. */
  200.  
  201. #define NUM_FPS    32
  202. struct {
  203.     FILE *phile;
  204.     char *name;
  205.     int readit;
  206. } file_ptrs[NUM_FPS];
  207.  
  208.  
  209. /* This for all you losing compilers out there that can't handle void * */
  210. #if defined( __GNU__ ) || defined( MSDOS )
  211. #define VOID void
  212. #else
  213. #define VOID char
  214. #endif
  215.  
  216. #include "getopt.h"
  217.  
  218. #ifdef MSDOS
  219.  
  220. #include <stdlib.h>
  221. #include <string.h>
  222.  
  223. #include <gnulib.h>
  224.  
  225. #ifndef STDIO_BUFSIZE
  226. #define STDIO_BUFSIZE    0x4000
  227. #endif
  228.  
  229. extern  void main (int argc, char **argv);
  230.  
  231. static  char *get_buffer (VOID *);
  232. static  char *__fp_name (FILE *);
  233. static  FILE *ck_fopen (char *, char *);
  234. static  FILE *compile_filename (int);
  235. static  int compile_address (struct addr *);
  236. static  int inchar (void);
  237. static  int match_address (struct addr *);
  238. static  int read_pattern_space (void);
  239. static  int size_buffer (VOID *);
  240. static  struct sed_label *setup_jump(struct sed_label *, struct sed_cmd *,
  241.                      struct vector *);
  242. static  struct vector *compile_program (struct vector *);
  243. static  VOID *ck_malloc (int);
  244. static  VOID *ck_realloc (VOID *, int);
  245. static  VOID *init_buffer (void);
  246. static  void add1_buffer (VOID *, int);
  247. static  void add_buffer (VOID *, VOID *, int);
  248. static  void append_pattern_space (void);
  249. static  void bad_prog (char *);
  250. static  void ck_fclose (FILE *);
  251. static  void ck_fwrite (char *, int, int, FILE *);
  252. static  void compile_file (char *);
  253. static  void compile_string (char *);
  254. static  void compile_regex (int);
  255. static  void execute_program (struct vector *);
  256. static  void flush_buffer (VOID *);
  257. static  void line_append (struct line *, struct line *);
  258. static  void line_copy (struct line *, struct line *);
  259. static  void panic (char *,...);
  260. static  void read_file (char *);
  261. static  void savchar (int);
  262. static  void str_append (struct line *, char *, int);
  263.  
  264. #else /* not MSDOS */
  265.  
  266. extern char *memchr();
  267. extern VOID *memmove();
  268.  
  269. extern VOID *ck_malloc(),*ck_realloc();
  270. extern VOID *init_buffer();
  271. extern char *get_buffer();
  272. extern FILE *ck_fopen();
  273. extern void ck_fclose();
  274. extern void ck_fwrite();
  275. extern void flush_buffer();
  276. extern void add1_buffer();
  277.  
  278. extern char *strdup();
  279.  
  280. struct vector *compile_program();
  281. void savchar();
  282. struct sed_label *setup_jump();
  283. void line_copy();
  284. void line_append();
  285. void append_pattern_space();
  286. void read_file();
  287. void execute_program();
  288. void compile_regex ();
  289.  
  290. #endif /* not MSDOS */
  291.  
  292. #ifndef HAS_UTILS
  293. char *myname;
  294. #else
  295. extern char *myname;
  296. #endif
  297.  
  298. /* If set, don't write out the line unless explictly told to */
  299. int no_default_output = 0;
  300.  
  301. /* Current input line # */
  302. int input_line_number = 0;
  303.  
  304. /* Are we on the last input file? */
  305. int last_input_file = 0;
  306.  
  307. /* Have we hit EOF on the last input file?  This is used to decide if we
  308.    have hit the '$' address yet. */
  309. int input_EOF = 0;
  310.  
  311. /* non-zero if a quit command has been executed. */
  312. int quit_cmd = 0;
  313.  
  314. /* Have we done any replacements lately?  This is used by the 't' command. */
  315. int replaced = 0;
  316.  
  317. /* How many '{'s are we executing at the moment */
  318. int program_depth = 0;
  319.  
  320. /* The complete compiled SED program that we are going to run */
  321. struct vector *the_program = 0;
  322.  
  323. /* information about labels and jumps-to-labels.  This is used to do
  324.    the required backpatching after we have compiled all the scripts. */
  325. struct sed_label *jumps = 0;
  326. struct sed_label *labels = 0;
  327.  
  328. /* The 'current' input line. */
  329. struct line line;
  330.  
  331. /* An input line that's been stored by later use by the program */
  332. struct line hold;
  333.  
  334. /* A 'line' to append to the current line when it comes time to write it out */
  335. struct line append;
  336.  
  337.  
  338. /* When we're reading a script command from a string, 'prog_start' and 'prog_end' point
  339.    to the beginning and end of the string.  This would allow us to compile
  340.    script strings that contain nulls, except that script strings are only read
  341.    from the command line, which is null-terminated */
  342. char *prog_start;
  343. char *prog_end;
  344.  
  345. /* When we're reading a script command from a string, 'prog_cur' points
  346.    to the current character in the string */
  347. char *prog_cur;
  348.  
  349. /* This is the name of the current script file.  It is used for error messages. */
  350. char *prog_name;
  351.  
  352. /* This is the current script file.  If it is zero, we are reading from a string
  353.    stored in 'prog_start' instead.  If both 'prog_file' and 'prog_start' are
  354.    zero, we're in trouble! */
  355. FILE *prog_file;
  356.  
  357. /* this is the number of the current script line that we're compiling.  It is
  358.    used to give out useful and informative error messages. */
  359. int prog_line = 1;
  360.  
  361. /* This is the file pointer that we're currently reading data from.  It may
  362.    be stdin */
  363. FILE *input_file;
  364.  
  365. /* If this variable is non-zero at exit, one or more of the input files couldn't
  366.    be opend. */
  367.  
  368. int bad_input = 0;
  369.  
  370. /* 'an empty regular expression is equivelent to the last regular expression read'
  371.    so  we have to keep track of the last regex used.  Here's where we store a
  372.    pointer to it (it is only malloc()'d once) */
  373. struct re_pattern_buffer *last_regex;
  374.  
  375. /* Various error messages we may want to print */
  376. static char ONE_ADDR[] = "Command only uses one address";
  377. static char NO_ADDR[] = "Command doesn't take any addresses";
  378. static char LINE_JUNK[] ="Extra characters after command";
  379. static char BAD_EOF[] =  "Unexpected End-of-file";
  380. #ifdef MSDOS
  381. static char USAGE[] =
  382.   "Usage: %s [-CV] [-n] [-e script...] [-f sfile...] [file...]\n";
  383. #else
  384. static char USAGE[] =   "Usage: %s [-n] [-e script...] [-f sfile...] [file...]\n";
  385. #endif
  386. static char NO_REGEX[] = "No previous regular expression";
  387.  
  388. /* Yes, the main program, which parses arguments, and does the right thing with them,
  389.    It also inits the temporary storage, etc. */
  390. void
  391. main (argc, argv)
  392.   int argc;
  393.   char **argv;
  394. {
  395.     int opt;
  396.     int compiled = 0;
  397.     struct sed_label *go,*lbl;
  398.  
  399.     myname=argv[0];
  400.  
  401. #ifdef MSDOS
  402.     while((opt=getopt(argc,argv,"ne:f:CV"))!=EOF) {
  403. #else
  404.     while((opt=getopt(argc,argv,"ne:f:"))!=EOF) {
  405. #endif
  406.         switch(opt) {
  407.         case 'n':
  408.             if(no_default_output)
  409.                 panic(USAGE);
  410.             no_default_output++;
  411.             break;
  412.         case 'e':
  413.             compile_string(optarg);
  414.             compiled++;
  415.             break;
  416.         case 'f':
  417.             compile_file(optarg);
  418.             compiled++;
  419.             break;
  420. #ifdef MSDOS
  421.         case 'C':
  422.             fprintf (stderr, COPYING);
  423.             exit (0);
  424.             break;
  425.         case 'V':
  426.             fprintf (stderr, VERSION);
  427.             exit (0);
  428.             break;
  429.         default:
  430.             fprintf (stderr, USAGE, myname);
  431.             exit (4);
  432.             break;
  433. #endif /* MSDOS */
  434.         }
  435.     }
  436. #ifdef MSDOS
  437.     if (setvbuf (stdout, NULL, _IOFBF, STDIO_BUFSIZE) != 0)
  438.       panic ("can't adjust buffering for /dev/stdout");
  439. #endif
  440.     if(!compiled) {
  441.         if(argc<=optind)
  442.             panic("No program to run\n");
  443.         compile_string(argv[optind]);
  444.         optind++;
  445.     }
  446.  
  447.     for(go=jumps;go;go=go->next) {
  448.         for(lbl=labels;lbl;lbl=lbl->next)
  449.             if(!strcmp(lbl->name,go->name))
  450.                 break;
  451.         if(!lbl)
  452.             panic("Can't find label for jump to '%s'\n",go->name);
  453.         go->v->v[go->v_index].x.jump=lbl;
  454.     }
  455.  
  456.     line.length=0;
  457.     line.alloc=50;
  458.     line.text=ck_malloc(50);
  459.  
  460.     append.length=0;
  461.     append.alloc=50;
  462.     append.text=ck_malloc(50);
  463.  
  464.     hold.length=0;
  465.     hold.alloc=50;
  466.     hold.text=ck_malloc(50);
  467.  
  468.     if(argc<=optind) {
  469.         last_input_file++;
  470.         read_file("-");
  471.     } else while(optind<argc) {
  472.         if(optind==argc-1)
  473.             last_input_file++;
  474.         read_file(argv[optind]);
  475.         optind++;
  476.         if(quit_cmd)
  477.             break;
  478.     }
  479.     if(bad_input)
  480.         exit(2);
  481.     exit(0);
  482. }
  483.  
  484. /* 'str' is a string (from the command line) that contains a sed command.
  485.    Compile the command, and add it to the end of 'the_program' */
  486. void
  487. compile_string(str)
  488. char *str;
  489. {
  490.     prog_file = 0;
  491.     prog_line=0;
  492.     prog_start=prog_cur=str;
  493.     prog_end=str+strlen(str);
  494.     the_program=compile_program(the_program);
  495. }
  496.  
  497. /* 'str' is the name of a file containing sed commands.  Read them in
  498.    and add them to the end of 'the_program' */
  499. void
  500. compile_file(str)
  501. char *str;
  502. {
  503.     FILE *file;
  504.     int ch;
  505.  
  506.     prog_start=prog_cur=prog_end=0;
  507.     prog_name=str;
  508.     prog_line=1;
  509.     if(str[0]=='-' && str[1]=='\0')
  510.         prog_file=stdin;
  511.     else
  512.         prog_file=ck_fopen(str,"r");
  513.     ch=getc(prog_file);
  514.     if(ch=='#') {
  515.         ch=getc(prog_file);
  516.         if(ch=='n')
  517.             no_default_output++;
  518.         while(ch!=EOF && ch!='\n')
  519.             ch=getc(prog_file);
  520.     } else if(ch!=EOF)
  521.         ungetc(ch,prog_file);
  522.     the_program=compile_program(the_program);
  523. }
  524.  
  525. #define MORE_CMDS 40
  526.  
  527. /* Read a program (or a subprogram within '{' '}' pairs) in and store
  528.    the compiled form in *'vector'  Return a pointer to the new vector.  */
  529. struct vector *
  530. compile_program(vector)
  531. struct vector *vector;
  532. {
  533.     struct sed_cmd *cur_cmd;
  534.     int    ch;
  535.     int    slash;
  536.     VOID    *b;
  537.     unsigned char    *string;
  538.     int    num;
  539.  
  540.     FILE *compile_filename();
  541.  
  542.     if(!vector) {
  543.         vector=(struct vector *)ck_malloc(sizeof(struct vector));
  544.         vector->v=(struct sed_cmd *)ck_malloc(MORE_CMDS*sizeof(struct sed_cmd));
  545.         vector->v_allocated=MORE_CMDS;
  546.         vector->v_length=0;
  547.         vector->up_one = 0;
  548.         vector->next_one = 0;
  549.     }
  550.     for(;;) {
  551.         do ch=inchar();
  552.         while(ch!=EOF && (isspace(ch) || ch=='\n' || ch==';'));
  553.         if(ch==EOF)
  554.             break;
  555.         savchar(ch);
  556.  
  557.         if(vector->v_length==vector->v_allocated) {
  558.             vector->v=(struct sed_cmd *)ck_realloc((VOID *)vector->v,(vector->v_length+MORE_CMDS)*sizeof(struct sed_cmd));
  559.             vector->v_allocated+=MORE_CMDS;
  560.         }
  561.         cur_cmd=vector->v+vector->v_length;
  562.         vector->v_length++;
  563.  
  564.         cur_cmd->a1.addr_type=0;
  565.         cur_cmd->a2.addr_type=0;
  566.         cur_cmd->aflags=0;
  567.         cur_cmd->cmd=0;
  568.  
  569.     skip_comment:
  570.         if(compile_address(&(cur_cmd->a1))) {
  571.             ch=inchar();
  572.             if(ch==',') {
  573.                 do ch=inchar();
  574.                 while(ch!=EOF && isspace(ch));
  575.                 savchar(ch);
  576.                 if(compile_address(&(cur_cmd->a2)))
  577.                     ;
  578.                 else
  579.                     bad_prog("Unexpected ','");
  580.             } else
  581.                 savchar(ch);
  582.         }
  583.         ch=inchar();
  584.         if(ch==EOF)
  585.             break;
  586.  new_cmd:
  587.         switch(ch) {
  588.         case '#':
  589.             if(cur_cmd->a1.addr_type!=0)
  590.                 bad_prog(NO_ADDR);
  591.             do ch=inchar();
  592.             while(ch!=EOF && ch!='\n');
  593.             goto skip_comment;
  594.         case '!':
  595.             if(cur_cmd->aflags & ADDR_BANG_BIT)
  596.                 bad_prog("Multiple '!'s");
  597.             cur_cmd->aflags|= ADDR_BANG_BIT;
  598.             do ch=inchar();
  599.             while(ch!=EOF && isspace(ch));
  600.             if(ch==EOF)
  601.                 bad_prog(BAD_EOF);
  602.             /* savchar(ch); */
  603.             goto new_cmd;
  604.         case 'a':
  605.         case 'i':
  606.             if(cur_cmd->a2.addr_type!=0)
  607.                 bad_prog(ONE_ADDR);
  608.             /* Fall Through */
  609.         case 'c':
  610.             cur_cmd->cmd=ch;
  611.             if(inchar()!='\\' || inchar()!='\n')
  612.                 bad_prog(LINE_JUNK);
  613.             b=init_buffer();
  614.             while((ch=inchar())!=EOF && ch!='\n') {
  615.                 if(ch=='\\')
  616.                     ch=inchar();
  617.                 add1_buffer(b,ch);
  618.             }
  619.             if(ch!=EOF)
  620.                 add1_buffer(b,ch);
  621.             num=size_buffer(b);
  622.             string=(unsigned char *)ck_malloc(num);
  623.             bcopy(get_buffer(b),string,num);
  624.             flush_buffer(b);
  625.             cur_cmd->x.cmd_txt.text_len=num;
  626.             cur_cmd->x.cmd_txt.text=(char *)string;
  627.             break;
  628.         case '{':
  629.             cur_cmd->cmd=ch;
  630.             program_depth++;
  631.             /* while((ch=inchar())!=EOF && ch!='\n')
  632.                 if(!isspace(ch))
  633.                     bad_prog(LINE_JUNK); */
  634.             cur_cmd->x.sub=compile_program((struct vector *)0);
  635.             /* FOO JF is this the right thing to do? */
  636.             break;
  637.         case '}':
  638.             if(!program_depth)
  639.                 bad_prog("Unexpected '}'");
  640.             --(vector->v_length);
  641.             while((ch=inchar())!=EOF && ch!='\n' && ch!=';')
  642.                 if(!isspace(ch))
  643.                     bad_prog(LINE_JUNK);
  644.             return vector;
  645.         case ':':
  646.             cur_cmd->cmd=ch;
  647.             if(cur_cmd->a1.addr_type!=0)
  648.                 bad_prog(": doesn't want any addresses");
  649.             labels=setup_jump(labels,cur_cmd,vector);
  650.             break;
  651.         case 'b':
  652.         case 't':
  653.             cur_cmd->cmd=ch;
  654.             jumps=setup_jump(jumps,cur_cmd,vector);
  655.             break;
  656.         case 'q':
  657.         case '=':
  658.             if(cur_cmd->a2.addr_type)
  659.                 bad_prog(ONE_ADDR);
  660.             /* Fall Through */
  661.         case 'd':
  662.         case 'D':
  663.         case 'g':
  664.         case 'G':
  665.         case 'h':
  666.         case 'H':
  667.         case 'l':
  668.         case 'n':
  669.         case 'N':
  670.         case 'p':
  671.         case 'P':
  672.         case 'x':
  673.             cur_cmd->cmd=ch;
  674.             do    ch=inchar();
  675.             while(ch!=EOF && isspace(ch) && ch!='\n' && ch!=';');
  676.             if(ch!='\n' && ch!=';' && ch!=EOF)
  677.                 bad_prog(LINE_JUNK);
  678.             break;
  679.  
  680.         case 'r':
  681.             if(cur_cmd->a2.addr_type!=0)
  682.                 bad_prog(ONE_ADDR);
  683.             /* FALL THROUGH */
  684.         case 'w':
  685.             cur_cmd->cmd=ch;
  686.             cur_cmd->x.io_file=compile_filename(ch=='r');
  687.             break;
  688.  
  689.         case 's':
  690.             cur_cmd->cmd=ch;
  691.             slash=inchar();
  692.             compile_regex(slash);
  693.  
  694.             cur_cmd->x.cmd_regex.regx=last_regex;
  695.  
  696.             b=init_buffer();
  697.             while((ch=inchar())!=EOF && ch!=slash) {
  698.                 if(ch=='\\') {
  699.                     int ci;
  700.  
  701.                     ci=inchar();
  702.                     if(ci!=EOF) {
  703.                         if(ci!='\n')
  704.                             add1_buffer(b,ch);
  705.                         add1_buffer(b,ci);
  706.                     }
  707.                 } else
  708.                     add1_buffer(b,ch);
  709.             }
  710.             cur_cmd->x.cmd_regex.replace_length=size_buffer(b);
  711.             cur_cmd->x.cmd_regex.replacement=ck_malloc(cur_cmd->x.cmd_regex.replace_length);
  712.             bcopy(get_buffer(b),cur_cmd->x.cmd_regex.replacement,cur_cmd->x.cmd_regex.replace_length);
  713.             flush_buffer(b);
  714.  
  715.             cur_cmd->x.cmd_regex.flags=0;
  716.             cur_cmd->x.cmd_regex.numb=0;
  717.  
  718.             if(ch==EOF)
  719.                 break;
  720.             do {
  721.                 ch=inchar();
  722.                 switch(ch) {
  723.                 case 'p':
  724.                     if(cur_cmd->x.cmd_regex.flags&S_PRINT_BIT)
  725.                         bad_prog("multiple 'p' options to 's' command");
  726.                     cur_cmd->x.cmd_regex.flags|=S_PRINT_BIT;
  727.                     break;
  728.                 case 'g':
  729.                     if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT)
  730.                         cur_cmd->x.cmd_regex.flags&= ~S_NUM_BIT;
  731.                     if(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT)
  732.                         bad_prog("multiple 'g' options to 's' command");
  733.                     cur_cmd->x.cmd_regex.flags|=S_GLOBAL_BIT;
  734.                     break;
  735.                 case 'w':
  736.                     cur_cmd->x.cmd_regex.flags|=S_WRITE_BIT;
  737.                     cur_cmd->x.cmd_regex.wio_file=compile_filename(0);
  738.                     ch='\n';
  739.                     break;
  740.                 case '0': case '1': case '2': case '3':
  741.                 case '4': case '5': case '6': case '7':
  742.                 case '8': case '9':
  743.                     if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT)
  744.                         bad_prog("multiple number options to 's' command");
  745.                     if((cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT)==0)
  746.                         cur_cmd->x.cmd_regex.flags|=S_NUM_BIT;
  747.                     num = 0;
  748.                     while(isdigit(ch)) {
  749.                         num=num*10+ch-'0';
  750.                         ch=inchar();
  751.                     }
  752.                     savchar(ch);
  753.                     cur_cmd->x.cmd_regex.numb=num;
  754.                     break;
  755.                 case '\n':
  756.                 case ';':
  757.                 case EOF:
  758.                     break;
  759.                 default:
  760.                     bad_prog("Unknown option to 's'");
  761.                     break;
  762.                 }
  763.             } while(ch!=EOF && ch!='\n' && ch!=';');
  764.             if(ch==EOF)
  765.                 break;
  766.             break;
  767.  
  768.         case 'y':
  769.             cur_cmd->cmd=ch;
  770.             string=(unsigned char *)ck_malloc(256);
  771.             for(num=0;num<256;num++)
  772.                 string[num]=num;
  773.             b=init_buffer();
  774.             slash=inchar();
  775.             while((ch=inchar())!=EOF && ch!=slash)
  776.                 add1_buffer(b,ch);
  777.             cur_cmd->x.translate=string;
  778.             string=(unsigned char *)get_buffer(b);
  779.             for(num=size_buffer(b);num;--num) {
  780.                 ch=inchar();
  781.                 if(ch==EOF)
  782.                     bad_prog(BAD_EOF);
  783.                 if(ch==slash)
  784.                     bad_prog("strings for y command are different lengths");
  785.                 cur_cmd->x.translate[*string++]=ch;
  786.             }
  787.             flush_buffer(b);
  788.             if(inchar()!=slash || ((ch=inchar())!=EOF && ch!='\n' && ch!=';'))
  789.                 bad_prog(LINE_JUNK);
  790.             break;
  791.  
  792.         default:
  793.             bad_prog("Unknown command");
  794.         }
  795.     }
  796.     return vector;
  797. }
  798.  
  799. /* Complain about a programming error and exit. */
  800. void
  801. bad_prog(why)
  802. char *why;
  803. {
  804.     if(prog_line)
  805.         fprintf(stderr,"%s: file %s line %d: %s\n",myname,prog_name,prog_line,why);
  806.     else
  807.         fprintf(stderr,"%s: %s\n",myname,why);
  808.     exit(1);
  809. }
  810.  
  811. /* Read the next character from the program.  Return EOF if there isn't
  812.    anything to read.  Keep prog_line up to date, so error messages can
  813.    be meaningful. */
  814. int
  815. inchar()
  816. {
  817.     int    ch;
  818.     if(prog_file) {
  819.         if(feof(prog_file))
  820.             return EOF;
  821.         else
  822.             ch=getc(prog_file);
  823.     } else {
  824.         if(!prog_cur)
  825.             return EOF;
  826.         else if(prog_cur==prog_end) {
  827.             ch=EOF;
  828.             prog_cur=0;
  829.         } else
  830.             ch= *prog_cur++;
  831.     }
  832.     if(ch=='\n' && prog_line)
  833.         prog_line++;
  834.     return ch;
  835. }
  836.  
  837. /* unget 'ch' so the next call to inchar will return it.  'ch' must not be
  838.    EOF or anything nasty like that. */
  839. void
  840. savchar(ch)
  841. int ch;
  842. {
  843.     if(ch==EOF)
  844.         return;
  845.     if(ch=='\n' && prog_line>1)
  846.         --prog_line;
  847.     if(prog_file)
  848.         ungetc(ch,prog_file);
  849.     else
  850.         *--prog_cur=ch;
  851. }
  852.  
  853.  
  854. /* Try to read an address for a sed command.  If it succeeeds,
  855.    return non-zero and store the resulting address in *'addr'.
  856.    If the input doesn't look like an address read nothing
  857.    and return zero. */
  858. int
  859. compile_address(addr)
  860. struct addr *addr;
  861. {
  862.     int    ch;
  863.     int    num;
  864. #ifdef MSDOS
  865.     char    *b;
  866. #else
  867.     char    *b,*init_buffer();
  868. #endif
  869.  
  870.     ch=inchar();
  871.  
  872.     if(isdigit(ch)) {
  873.         num=ch-'0';
  874.         while((ch=inchar())!=EOF && isdigit(ch))
  875.             num=num*10+ch-'0';
  876.         while(ch!=EOF && isspace(ch))
  877.             ch=inchar();
  878.         savchar(ch);
  879.         addr->addr_type=ADDR_NUM;
  880.         addr->addr_number = num;
  881.         return 1;
  882.     } else if(ch=='/') {
  883.         addr->addr_type=ADDR_REGEX;
  884.         compile_regex('/');
  885.         addr->addr_regex=last_regex;
  886.         do ch=inchar();
  887.         while(ch!=EOF && isspace(ch));
  888.         savchar(ch);
  889.         return 1;
  890.     } else if(ch=='$') {
  891.         addr->addr_type=ADDR_LAST;
  892.         do ch=inchar();
  893.         while(ch!=EOF && isspace(ch));
  894.         savchar(ch);
  895.         return 1;
  896.     } else
  897.         savchar(ch);
  898.     return 0;
  899. }
  900.  
  901. void
  902. compile_regex (slash)
  903.   int slash;
  904. {
  905.     VOID *b;
  906.     int ch;
  907.  
  908.     b=init_buffer();
  909.     while((ch=inchar())!=EOF && ch!=slash) {
  910.         if(ch=='^') {
  911.             if(size_buffer(b)==0) {
  912.                 add1_buffer(b,'\\');
  913.                 add1_buffer(b,'`');
  914.             } else
  915.                 add1_buffer(b,ch);
  916.             continue;
  917.         } else if(ch=='$') {
  918.             ch=inchar();
  919.             savchar(ch);
  920.             if(ch==slash) {
  921.                 add1_buffer(b,'\\');
  922.                 add1_buffer(b,'\'');
  923.             } else
  924.                 add1_buffer(b,'$');
  925.             continue;
  926.         } else if(ch!='\\') {
  927.             add1_buffer(b,ch);
  928.             continue;
  929.         }
  930.         ch=inchar();
  931.         switch(ch) {
  932.         case 'n':
  933.             add1_buffer(b,'\n');
  934.             break;
  935.         /* case 'b':
  936.             add1_buffer(b,'\b');
  937.             break;
  938.         case 'f':
  939.             add1_buffer(b,'\f');
  940.             break;
  941.         case 'r':
  942.             add1_buffer(b,'\r');
  943.             break;
  944.         case 't':
  945.             add1_buffer(b,'\t');
  946.             break; */
  947.         case EOF:
  948.             break;
  949.         default:
  950.             add1_buffer(b,'\\');
  951.             add1_buffer(b,ch);
  952.             break;
  953.         }
  954.     }
  955.     if(ch==EOF)
  956.         bad_prog(BAD_EOF);
  957.     if(size_buffer(b)) {
  958.         last_regex=(struct re_pattern_buffer *)ck_malloc(sizeof(struct re_pattern_buffer));
  959.         last_regex->allocated=size_buffer(b);
  960. #ifdef MSDOS
  961.         last_regex->buffer
  962.           = ck_malloc ((size_t) last_regex->allocated);
  963. #else
  964.         last_regex->buffer=ck_malloc(last_regex->allocated);
  965. #endif
  966. #ifdef __LOOSE_WITHOUT_FASTMAP__    /* who would want to ??? */
  967.         last_regex->fastmap=0;
  968. #else
  969.         last_regex->fastmap = ck_malloc (1 << BYTEWIDTH);
  970. #endif
  971.         last_regex->translate=0;
  972.         re_compile_pattern(get_buffer(b),size_buffer(b),last_regex);
  973.     } else if(!last_regex)
  974.         bad_prog(NO_REGEX);
  975.     flush_buffer(b);
  976. }
  977.  
  978. /* Store a label (or label reference) created by a ':', 'b', or 't'
  979.    comand so that the jump to/from the lable can be backpatched after
  980.    compilation is complete */
  981. struct sed_label *
  982. setup_jump(list,cmd,vec)
  983. struct sed_label *list;
  984. struct sed_cmd *cmd;
  985. struct vector *vec;
  986. {
  987.     struct sed_label *tmp;
  988.     VOID *b;
  989.     int ch;
  990.  
  991.     b=init_buffer();
  992.     while((ch=inchar())==' ' || ch=='\t')
  993.         ;
  994.     do add1_buffer(b,ch);
  995.     while((ch=inchar())!=EOF && ch!='\n');
  996.     add1_buffer(b,'\0');
  997.     tmp=(struct sed_label *)ck_malloc(sizeof(struct sed_label));
  998.     tmp->v=vec;
  999.     tmp->v_index=cmd-vec->v;
  1000.     tmp->name=strdup(get_buffer(b));
  1001.     tmp->next=list;
  1002.     flush_buffer(b);
  1003.     return tmp;
  1004. }
  1005.  
  1006. /* read in a filename for a 'r', 'w', or 's///w' command, and
  1007.    update the internal structure about files.  The file is
  1008.    opened if it isn't already open. */
  1009. FILE *
  1010. compile_filename(readit)
  1011.   int readit;
  1012. {
  1013.     char *file_name;
  1014.     int n;
  1015.     VOID *b;
  1016.     int ch;
  1017.     char **globbed;
  1018.     extern char **glob_filename();
  1019.  
  1020.     if(inchar()!=' ')
  1021.         bad_prog("missing ' ' before filename");
  1022.     b=init_buffer();
  1023.     while((ch=inchar())!=EOF && ch!='\n')
  1024.         add1_buffer(b,ch);
  1025.     add1_buffer(b,'\0');
  1026.     file_name=get_buffer(b);
  1027.     globbed=glob_filename(file_name);
  1028.     if(globbed==0 || globbed==(char **)-1)
  1029.         bad_prog("can't parse filename");
  1030.     if(globbed[0] && globbed[1]!=0)
  1031.         bad_prog("multiple files");
  1032.     if(globbed[0])
  1033.         file_name=globbed[0];
  1034.     for(n=0;n<NUM_FPS;n++) {
  1035.         if(!file_ptrs[n].name)
  1036.             break;
  1037.         if(!strcmp(file_ptrs[n].name,file_name)) {
  1038.             if(file_ptrs[n].readit!=readit)
  1039.                 bad_prog("Can't open file for both reading and writing");
  1040.             flush_buffer(b);
  1041.             return file_ptrs[n].phile;
  1042.         }
  1043.     }
  1044.     if(n<NUM_FPS) {
  1045.         file_ptrs[n].name=strdup(file_name);
  1046.         file_ptrs[n].readit=readit;
  1047.         file_ptrs[n].phile=ck_fopen(file_name,readit ? "r" : "a");
  1048.         flush_buffer(b);
  1049.         return file_ptrs[n].phile;
  1050.     } else {
  1051.         bad_prog("Hopelessely evil compiled in limit on number of open files.  re-compile sed\n");
  1052.         return 0;
  1053.     }
  1054. }
  1055.  
  1056. /* Parse a filename given by a 'r' 'w' or 's///w' command. */
  1057. void
  1058. read_file(name)
  1059. char *name;
  1060. {
  1061.     if(*name=='-' && name[1]=='\0')
  1062.         input_file=stdin;
  1063.     else {
  1064.         input_file=fopen(name,"r");
  1065.         if(input_file==0) {
  1066. #ifndef MSDOS
  1067.             extern int errno;
  1068.             extern char *sys_errlist[];
  1069.             extern int sys_nerr;
  1070. #endif
  1071.  
  1072.             char *ptr;
  1073.  
  1074.             ptr=(errno>=0 && errno<sys_nerr) ? sys_errlist[errno] : "Unknown error code";
  1075.             bad_input++;
  1076.             fprintf(stderr,"%s: can't read %s: %s\n",myname,name,ptr);
  1077.  
  1078.             return;
  1079.         }
  1080.     }
  1081. #ifdef MSDOS
  1082.     if (setvbuf (input_file, NULL, _IOFBF, STDIO_BUFSIZE) != 0)
  1083.       panic ("can't adjust buffering for %s",
  1084.          (*name=='-' && name[1]=='\0') ? "/dev/stdin" : name);
  1085. #endif
  1086.     while(read_pattern_space()) {
  1087.         execute_program(the_program);
  1088.         if(!no_default_output)
  1089.             ck_fwrite(line.text,1,line.length,stdout);
  1090.         if(append.length) {
  1091.             ck_fwrite(append.text,1,append.length,stdout);
  1092.             append.length=0;
  1093.         }
  1094.         if(quit_cmd)
  1095.             break;
  1096.     }
  1097.     ck_fclose(input_file);
  1098. }
  1099.  
  1100. /* Execute the program 'vec' on the current input line. */
  1101. void
  1102. execute_program(vec)
  1103. struct vector *vec;
  1104. {
  1105.     struct sed_cmd *cur_cmd;
  1106.     int    n;
  1107.     int addr_matched;
  1108.     static int end_cycle;
  1109.  
  1110.     int start;
  1111.     int remain;
  1112.     int offset;
  1113.  
  1114.     static struct line tmp;
  1115.     struct line t;
  1116.     char *rep,*rep_end,*rep_next,*rep_cur;
  1117.  
  1118.     struct re_registers regs;
  1119.     int count = 0;
  1120.     void str_append();
  1121.  
  1122.  
  1123.     end_cycle = 0;
  1124.  
  1125.     for(cur_cmd=vec->v,n=vec->v_length;n;cur_cmd++,n--) {
  1126.  
  1127.     exe_loop:
  1128.         addr_matched=0;
  1129.         if(cur_cmd->aflags&A1_MATCHED_BIT) {
  1130.             addr_matched=1;
  1131.             if(match_address(&(cur_cmd->a2)))
  1132.                 cur_cmd->aflags&=~A1_MATCHED_BIT;
  1133.         } else if(match_address(&(cur_cmd->a1))) {
  1134.             addr_matched=1;
  1135.             if(cur_cmd->a2.addr_type!=ADDR_NULL)
  1136.                 cur_cmd->aflags|=A1_MATCHED_BIT;
  1137.         }
  1138.         if(cur_cmd->aflags&ADDR_BANG_BIT)
  1139.             addr_matched= !addr_matched;
  1140.         if(!addr_matched)
  1141.             continue;
  1142.         switch(cur_cmd->cmd) {
  1143.         case '{':    /* Execute sub-program */
  1144.             execute_program(cur_cmd->x.sub);
  1145.             break;
  1146.  
  1147.         case ':':    /* Executing labels is easy. */
  1148.             break;
  1149.  
  1150.         case '=':
  1151.             printf("%d\n",input_line_number);
  1152.             break;
  1153.  
  1154.         case 'a':
  1155.             if(append.alloc-append.length<cur_cmd->x.cmd_txt.text_len) {
  1156.                 append.text=ck_realloc(append.text,append.alloc+cur_cmd->x.cmd_txt.text_len);
  1157.                 append.alloc+=cur_cmd->x.cmd_txt.text_len;
  1158.             }
  1159.             bcopy(cur_cmd->x.cmd_txt.text,append.text+append.length,cur_cmd->x.cmd_txt.text_len);
  1160.             append.length+=cur_cmd->x.cmd_txt.text_len;
  1161.             break;
  1162.  
  1163.         case 'b':
  1164.             if(!cur_cmd->x.jump)
  1165.                 end_cycle++;
  1166.             else {
  1167.                 struct sed_label *j = cur_cmd->x.jump;
  1168.  
  1169.                 n= j->v->v_length - j->v_index;
  1170.                 cur_cmd= j->v->v + j->v_index;
  1171.                 goto exe_loop;
  1172.             }
  1173.             break;
  1174.  
  1175.         case 'c':
  1176.             line.length=0;
  1177.             if(!(cur_cmd->aflags&A1_MATCHED_BIT))
  1178.                 ck_fwrite(cur_cmd->x.cmd_txt.text,1,cur_cmd->x.cmd_txt.text_len,stdout);
  1179.             end_cycle++;
  1180.             break;
  1181.  
  1182.         case 'd':
  1183.             line.length=0;
  1184.             end_cycle++;
  1185.             break;
  1186.  
  1187.         case 'D':
  1188.             {
  1189.                 char *tmp;
  1190.                 int newlength;
  1191.  
  1192.                 tmp=memchr(line.text,'\n',line.length);
  1193.                 newlength=line.length-(tmp-line.text);
  1194.                 if(newlength)
  1195.                     memmove(line.text,tmp,newlength);
  1196.                 line.length=newlength;
  1197.             }
  1198.             end_cycle++;
  1199.             break;
  1200.  
  1201.         case 'g':
  1202.             line_copy(&hold,&line);
  1203.             break;
  1204.  
  1205.         case 'G':
  1206.             line_append(&hold,&line);
  1207.             break;
  1208.  
  1209.         case 'h':
  1210.             line_copy(&line,&hold);
  1211.             break;
  1212.  
  1213.         case 'H':
  1214.             line_append(&line,&hold);
  1215.             break;
  1216.  
  1217.         case 'i':
  1218.             ck_fwrite(cur_cmd->x.cmd_txt.text,1,cur_cmd->x.cmd_txt.text_len,stdout);
  1219.             break;
  1220.  
  1221.         case 'l':
  1222.             {
  1223.                 char *tmp;
  1224.                 int n;
  1225.                 int width = 0;
  1226.  
  1227.                 n=line.length;
  1228.                 tmp=line.text;
  1229.                 /* Use --n so this'll skip the trailing newline */
  1230.                 while(--n) {
  1231.                     if(width>77) {
  1232.                         width=0;
  1233.                         putchar('\n');
  1234.                     }
  1235.                     if(isprint(*tmp)) {
  1236.                         putchar(*tmp);
  1237.                         width++;
  1238.                     } else switch(*tmp) {
  1239.                     case '\0':
  1240.                         printf("\\0");
  1241.                         width+=2;
  1242.                         break;
  1243.                     case '\a':
  1244.                         printf("\\a");
  1245.                         width+=2;
  1246.                         break;
  1247.                     case '\b':
  1248.                         printf("\\b");
  1249.                         width+=2;
  1250.                         break;
  1251.                     case '\f':
  1252.                         printf("\\f");
  1253.                         width+=2;
  1254.                         break;
  1255.                     case '\n':
  1256.                         printf("\\n");
  1257.                         width+=2;
  1258.                         break;
  1259.                     case '\r':
  1260.                         printf("\\r");
  1261.                         width+=2;
  1262.                         break;
  1263.                     case '\t':
  1264.                         printf("\\t");
  1265.                         width+=2;
  1266.                         break;
  1267.                     case '\v':
  1268.                         printf("\\v");
  1269.                         width+=2;
  1270.                         break;
  1271.                     default:
  1272.                         printf("/%02x",(*tmp)&0xFF);
  1273.                         width+=2;
  1274.                         break;
  1275.                     }
  1276.                     tmp++;
  1277.                 }
  1278.                 putchar('\n');
  1279.             }
  1280.             break;
  1281.  
  1282.         case 'n':
  1283.             ck_fwrite(line.text,1,line.length,stdout);
  1284.             read_pattern_space();
  1285.             break;
  1286.  
  1287.         case 'N':
  1288.             append_pattern_space();
  1289.             break;
  1290.  
  1291.         case 'p':
  1292.             ck_fwrite(line.text,1,line.length,stdout);
  1293.             break;
  1294.  
  1295.         case 'P':
  1296.             {
  1297.                 char *tmp;
  1298.  
  1299.                 tmp=memchr(line.text,'\n',line.length);
  1300. #ifdef __BUG__
  1301.                 /* this can't be true! obviously copied from 'D'
  1302.                    (where it is correct). [tho] */
  1303.                 ck_fwrite(line.text,1,line.length-(tmp-line.text),stdout);
  1304. #else /* FIXED */
  1305.                 ck_fwrite(line.text,1,tmp-line.text,stdout);
  1306. #endif /* FIXED */
  1307.             }
  1308.             break;
  1309.  
  1310.         case 'q':
  1311.             quit_cmd++;
  1312.             end_cycle++;
  1313.             break;
  1314.  
  1315.         case 'r':
  1316.             {
  1317.                 int n;
  1318.                 char tmp_buf[1024];
  1319.  
  1320.                 rewind(cur_cmd->x.io_file);
  1321.                 while((n=fread(append.text+append.length,sizeof(char),append.alloc-append.length,cur_cmd->x.io_file))>0) {
  1322.                     append.length += n;
  1323.                     if(append.length==append.alloc) {
  1324.                         append.text = ck_realloc(append.text, append.alloc + cur_cmd->x.cmd_txt.text_len);
  1325.                         append.alloc += cur_cmd->x.cmd_txt.text_len;
  1326.                     }
  1327.                 }
  1328.                 if(ferror(cur_cmd->x.io_file))
  1329.                     panic("Read error on input file to 'r' command\n");
  1330.             }
  1331.             break;
  1332.  
  1333.         case 's':
  1334.             if(!tmp.alloc) {
  1335.                 tmp.alloc=50;
  1336.                 tmp.text=ck_malloc(50);
  1337.             }
  1338.             count=0;
  1339.             start = 0;
  1340.             remain=line.length-1;
  1341.             tmp.length=0;
  1342.             rep = cur_cmd->x.cmd_regex.replacement;
  1343.             rep_end=rep+cur_cmd->x.cmd_regex.replace_length;
  1344.  
  1345.             while((offset = re_search(cur_cmd->x.cmd_regex.regx,
  1346.                           line.text,
  1347.                           line.length-1,
  1348.                           start,
  1349.                           remain,
  1350.                           ®s))>=0) {
  1351.                 count++;
  1352.                 if(offset-start)
  1353.                     str_append(&tmp,line.text+start,offset-start);
  1354.  
  1355.                 if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT) {
  1356.                     if(count!=cur_cmd->x.cmd_regex.numb) {
  1357.                         str_append(&tmp,line.text+regs.start[0],regs.end[0]-regs.start[0]);
  1358.                         start = (offset == regs.end[0] ? offset + 1 : regs.end[0]);
  1359.                         remain = (line.length-1) - start;
  1360.                         continue;
  1361.                     }
  1362.                 }
  1363.  
  1364.                 for(rep_next=rep_cur=rep;rep_next<rep_end;rep_next++) {
  1365.                     if(*rep_next=='&') {
  1366.                         if(rep_next-rep_cur)
  1367.                             str_append(&tmp,rep_cur,rep_next-rep_cur);
  1368.                         str_append(&tmp,line.text+regs.start[0],regs.end[0]-regs.start[0]);
  1369.                         rep_cur=rep_next+1;
  1370.                     } else if(*rep_next=='\\') {
  1371.                         if(rep_next-rep_cur)
  1372.                             str_append(&tmp,rep_cur,rep_next-rep_cur);
  1373.                         rep_next++;
  1374.                         if(rep_next!=rep_end) {
  1375.                             int n;
  1376.  
  1377.                             if(*rep_next>='0' && *rep_next<='9') {
  1378.                                 n= *rep_next -'0';
  1379.                                 str_append(&tmp,line.text+regs.start[n],regs.end[n]-regs.start[n]);
  1380.                             } else
  1381.                                 str_append(&tmp,rep_next,1);
  1382.                         }
  1383.                         rep_cur=rep_next+1;
  1384.                     }
  1385.                 }
  1386.                 if(rep_next-rep_cur)
  1387.                     str_append(&tmp,rep_cur,rep_next-rep_cur);
  1388.                 if (offset == regs.end[0]) {
  1389.                     str_append(&tmp, line.text + offset, 1);
  1390.                     ++regs.end[0];
  1391.                 }
  1392.                 start = regs.end[0];
  1393.  
  1394.                 remain = (line.length-1) - start;
  1395.                 if(remain<0)
  1396.                     break;
  1397.                 if(!(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT))
  1398.                     break;
  1399.             }
  1400.             if(!count)
  1401.                 break;
  1402.             replaced=1;
  1403. #ifdef __BUG__
  1404.             /* This is wrong (at least with the new regex library)
  1405.                after the last (failed!) re_search() the registers
  1406.                will be set to -1!  [tho] */
  1407.             str_append(&tmp,line.text+regs.end[0],line.length-regs.end[0]);
  1408. #else /* FIXED */
  1409.             str_append(&tmp,line.text+start,line.length-start);
  1410. #endif /* FIXED */
  1411.             t.text=line.text;
  1412.             t.length=line.length;
  1413.             t.alloc=line.alloc;
  1414.             line.text=tmp.text;
  1415.             line.length=tmp.length;
  1416.             line.alloc=tmp.alloc;
  1417.             tmp.text=t.text;
  1418.             tmp.length=t.length;
  1419.             tmp.alloc=t.alloc;
  1420.             if(cur_cmd->x.cmd_regex.flags&S_WRITE_BIT)
  1421.                 ck_fwrite(line.text,1,line.length,cur_cmd->x.cmd_regex.wio_file);
  1422.             if(cur_cmd->x.cmd_regex.flags&S_PRINT_BIT)
  1423.                 ck_fwrite(line.text,1,line.length,stdout);
  1424.             break;
  1425.  
  1426.         case 't':
  1427.             if(replaced) {
  1428.                 replaced = 0;
  1429.                 if(!cur_cmd->x.jump)
  1430.                     end_cycle++;
  1431.                 else {
  1432.                     struct sed_label *j = cur_cmd->x.jump;
  1433.  
  1434.                     n= j->v->v_length - j->v_index;
  1435.                     cur_cmd= j->v->v + j->v_index;
  1436.                     goto exe_loop;
  1437.                 }
  1438.             }
  1439.             break;
  1440.  
  1441.         case 'w':
  1442.             ck_fwrite(line.text,1,line.length,cur_cmd->x.io_file);
  1443.             break;
  1444.  
  1445.         case 'x':
  1446.             {
  1447.                 struct line tmp;
  1448.  
  1449.                 tmp=line;
  1450.                 line=hold;
  1451.                 hold=tmp;
  1452.             }
  1453.             break;
  1454.  
  1455.         case 'y':
  1456.             {
  1457.                 unsigned char *p,*e;
  1458.  
  1459.                 for(p=(unsigned char *)(line.text),e=p+line.length;p<e;p++)
  1460.                     *p=cur_cmd->x.translate[*p];
  1461.             }
  1462.             break;
  1463.  
  1464.         default:
  1465.             panic("INTERNAL ERROR: Bad cmd %c\n",cur_cmd->cmd);
  1466.         }
  1467.         if(end_cycle)
  1468.             break;
  1469.     }
  1470. }
  1471.  
  1472.  
  1473. /* Return non-zero if the current line matches the address
  1474.    pointed to by 'addr'. */
  1475. match_address(addr)
  1476. struct addr *addr;
  1477. {
  1478.     switch(addr->addr_type) {
  1479.     case ADDR_NULL:
  1480.         return 1;
  1481.     case ADDR_NUM:
  1482.         return (input_line_number==addr->addr_number);
  1483.  
  1484.     case ADDR_REGEX:
  1485.         return (re_search(addr->addr_regex,
  1486.                   line.text,
  1487.                   line.length-1,
  1488.                   0,
  1489.                   line.length-1,
  1490.                   0)>=0) ? 1 : 0;
  1491.  
  1492.     case ADDR_LAST:
  1493.         return (input_EOF) ? 1 : 0;
  1494.  
  1495.     default:
  1496.         panic("INTERNAL ERROR: bad address type\n");
  1497.         break;
  1498.     }
  1499.     return -1;
  1500. }
  1501.  
  1502. /* Read in the next line of input, and store it in the
  1503.    pattern space.  Return non-zero if this is the last line of input */
  1504.  
  1505. int
  1506. read_pattern_space()
  1507. {
  1508.     int n;
  1509.     char *p;
  1510.     int ch;
  1511.  
  1512.     p=line.text;
  1513.     n=line.alloc;
  1514.  
  1515.     if(feof(input_file))
  1516.         return 0;
  1517.     input_line_number++;
  1518.     replaced=0;
  1519.     for(;;) {
  1520.         ch=getc(input_file);
  1521.         if(ch==EOF) {
  1522.             if(n==line.alloc)
  1523.                 return 0;
  1524.             *p++='\n';
  1525.             --n;
  1526.             line.length=line.alloc-n;
  1527.             if(last_input_file)
  1528.                 input_EOF++;
  1529.             return 1;
  1530.         }
  1531.         *p++=ch;
  1532.         --n;
  1533.         if(ch=='\n') {
  1534.             line.length=line.alloc-n;
  1535.             break;
  1536.         }
  1537.         if(n==0) {
  1538.             line.text=ck_realloc(line.text,line.alloc*2);
  1539.             p=line.text+line.alloc;
  1540.             n=line.alloc;
  1541.             line.alloc*=2;
  1542.         }
  1543.     }
  1544.     ch=getc(input_file);
  1545.     if(ch!=EOF)
  1546.         ungetc(ch,input_file);
  1547.     else if(last_input_file)
  1548.         input_EOF++;
  1549.     return 1;
  1550. }
  1551.  
  1552. /* Inplement the 'N' command, which appends the next line of input to
  1553.    the pattern space. */
  1554. void
  1555. append_pattern_space()
  1556. {
  1557.     char *p;
  1558.     int n;
  1559.     int ch;
  1560.  
  1561.     p=line.text+line.length;
  1562.     n=line.alloc-line.length;
  1563.  
  1564.     input_line_number++;
  1565.     replaced=0;
  1566.     if(feof(input_file))
  1567.         return;
  1568.     for(;;) {
  1569.         ch=getc(input_file);
  1570.         if(ch==EOF) {
  1571.             if(n==line.alloc)
  1572.                 return;
  1573.             *p++='\n';
  1574.             --n;
  1575.             line.length=line.alloc-n;
  1576.             if(last_input_file)
  1577.                 input_EOF++;
  1578.             return;
  1579.         }
  1580.         *p++=ch;
  1581.         --n;
  1582.         if(ch=='\n') {
  1583.             line.length=line.alloc-n;
  1584.             break;
  1585.         }
  1586.         if(n==0) {
  1587.             line.text=ck_realloc(line.text,line.alloc*2);
  1588.             p=line.text+line.alloc;
  1589.             n=line.alloc;
  1590.             line.alloc*=2;
  1591.         }
  1592.     }
  1593.     ch=getc(input_file);
  1594.     if(ch!=EOF)
  1595.         ungetc(ch,input_file);
  1596.     else if(last_input_file)
  1597.         input_EOF++;
  1598. }
  1599.  
  1600. /* Copy the contents of the line 'from' into the line 'to'.
  1601.    This destroys the old contents of 'to'.  It will still work
  1602.    if the line 'from' contains nulls. */
  1603. void
  1604. line_copy(from,to)
  1605. struct line *from,*to;
  1606. {
  1607.     if(from->length>to->alloc) {
  1608.         to->alloc=from->length;
  1609.         to->text=ck_realloc(to->text,to->alloc);
  1610.     }
  1611.     bcopy(from->text,to->text,from->length);
  1612.     to->length=from->length;
  1613. }
  1614.  
  1615. /* Append the contents of the line 'from' to the line 'to'.
  1616.    This routine will work even if the line 'from' contains nulls */
  1617. void
  1618. line_append(from,to)
  1619. struct line *from,*to;
  1620. {
  1621.     if(from->length>(to->alloc-to->length)) {
  1622.         to->alloc+=from->length;
  1623.         to->text=ck_realloc(to->text,to->alloc);
  1624.     }
  1625.     bcopy(from->text,to->text+to->length,from->length);
  1626.     to->length+=from->length;
  1627. }
  1628.  
  1629. /* Append 'length' bytes from 'string' to the line 'to'
  1630.    This routine *will* append bytes with nulls in them, without
  1631.    failing. */
  1632. void
  1633. str_append(to,string,length)
  1634. struct line *to;
  1635. char *string;
  1636. int length;
  1637. {
  1638.     if(length>to->alloc-to->length) {
  1639.         to->alloc+=length;
  1640.         to->text=ck_realloc(to->text,to->alloc);
  1641.     }
  1642.     bcopy(string,to->text+to->length,length);
  1643.     to->length+=length;
  1644. }
  1645.  
  1646. #ifndef HAS_UTILS
  1647. /* These routines were written as part of a library (by me), but since most
  1648.    people don't have the library, here they are.  */
  1649.  
  1650. #ifdef __STDC__
  1651. #include "stdarg.h"
  1652.  
  1653. /* Print an error message and exit */
  1654. #ifdef MSDOS
  1655. void
  1656. panic (char *str, ...)
  1657. #else /* not MSDOS */
  1658. void
  1659. panic(str)
  1660. char *str;
  1661. #endif /* not MSDOS */
  1662. {
  1663.     va_list iggy;
  1664.  
  1665.     va_start(iggy,str);
  1666.     fprintf(stderr,"%s: ",myname);
  1667. #ifdef NO_VFPRINTF
  1668.     _doprnt(str,&iggy,stderr);
  1669. #else
  1670.     vfprintf(stderr,str,iggy);
  1671. #endif
  1672.     putc('\n',stderr);
  1673.     va_end(iggy);
  1674.     exit(4);
  1675. }
  1676.  
  1677. #else /* not __STDC__ */
  1678. #include "varargs.h"
  1679.  
  1680. panic(str,va_alist)
  1681. char *str;
  1682. va_dcl
  1683. {
  1684.     va_list iggy;
  1685.  
  1686.     va_start(iggy);
  1687.     fprintf(stderr,"%s: ",myname);
  1688. #ifdef NO_VFPRINTF
  1689.     _doprnt(str,&iggy,stderr);
  1690. #else
  1691.     vfprintf(stderr,str,iggy);
  1692. #endif
  1693.     putc('\n',stderr);
  1694.     va_end(iggy);
  1695.     exit(4);
  1696. }
  1697.  
  1698. #endif /* not __STDC__ */
  1699.  
  1700. /* Store information about files opened with ck_fopen
  1701.    so that error messages from ck_fread, etc can print the
  1702.    name of the file that had the error */
  1703. #define N_FILE 32
  1704.  
  1705. struct id {
  1706.     FILE *fp;
  1707.     char *name;
  1708. };
  1709.  
  1710. static struct id __id_s[N_FILE];
  1711.  
  1712. /* Internal routine to get a filename from __id_s */
  1713. char *
  1714. __fp_name(fp)
  1715. FILE *fp;
  1716. {
  1717.     int n;
  1718.  
  1719.     for(n=0;n<N_FILE;n++) {
  1720.         if(__id_s[n].fp==fp)
  1721.             return __id_s[n].name;
  1722.     }
  1723.     return "{Unknown file pointer}";
  1724. }
  1725.  
  1726. /* Panic on failing fopen */
  1727. FILE *
  1728. ck_fopen(name,mode)
  1729. char *name;
  1730. char *mode;
  1731. {
  1732.     FILE    *ret;
  1733.     int    n;
  1734.  
  1735.     ret=fopen(name,mode);
  1736.     if(ret==(FILE *)0)
  1737.         panic("Couldn't open file %s\n",name);
  1738.     for(n=0;n<N_FILE;n++) {
  1739.         if(ret==__id_s[n].fp) {
  1740.             free((VOID *)__id_s[n].name);
  1741.             __id_s[n].name=(char *)ck_malloc(strlen(name)+1);
  1742.             strcpy(__id_s[n].name,name);
  1743.             break;
  1744.         }
  1745.     }
  1746.     if(n==N_FILE) {
  1747.         for(n=0;n<N_FILE;n++)
  1748.             if(__id_s[n].fp==(FILE *)0)
  1749.                 break;
  1750.         if(n==N_FILE)
  1751.             panic("Internal error: too many files open\n");
  1752.         __id_s[n].fp=ret;
  1753.         __id_s[n].name=(char *)ck_malloc(strlen(name)+1);
  1754.         strcpy(__id_s[n].name,name);
  1755.     }
  1756. #ifdef MSDOS
  1757.     if (setvbuf (ret, NULL, _IOFBF, STDIO_BUFSIZE) != 0)
  1758.       panic ("can't adjust buffering for %s", name);
  1759. #endif
  1760.     return ret;
  1761. }
  1762.  
  1763. /* Panic on failing fwrite */
  1764. void
  1765. ck_fwrite(ptr,size,nmemb,stream)
  1766. char *ptr;
  1767. int size,nmemb;
  1768. FILE *stream;
  1769. {
  1770.     if(fwrite(ptr,size,nmemb,stream)!=nmemb)
  1771.         panic("couldn't write %d items to %s",nmemb,__fp_name(stream));
  1772. }
  1773.  
  1774. /* Panic on failing fclose */
  1775. void
  1776. ck_fclose(stream)
  1777. FILE *stream;
  1778. {
  1779.     if(fclose(stream)==EOF)
  1780.         panic("Couldn't close %s\n",__fp_name(stream));
  1781. }
  1782.  
  1783. /* Panic on failing malloc */
  1784. VOID *
  1785. ck_malloc(size)
  1786. int size;
  1787. {
  1788.     VOID *ret;
  1789. #ifndef MSDOS
  1790.     VOID *malloc();
  1791. #endif
  1792.  
  1793.     ret=malloc(size);
  1794.     if(ret==(VOID *)0)
  1795.         panic("Couldn't allocate memory\n");
  1796.     return ret;
  1797. }
  1798.  
  1799. /* Panic on failing realloc */
  1800. VOID *
  1801. ck_realloc(ptr,size)
  1802. VOID *ptr;
  1803. int size;
  1804. {
  1805.     VOID *ret;
  1806. #ifndef MSDOS
  1807.     VOID *realloc();
  1808. #endif
  1809.  
  1810.     ret=realloc(ptr,size);
  1811.     if(ret==(VOID *)0)
  1812.         panic("Couldn't re-allocate memory\n");
  1813.     return ret;
  1814. }
  1815.  
  1816. #ifndef MSDOS
  1817.  
  1818. /* Return a malloc()'d copy of a string */
  1819. char *
  1820. strdup(str)
  1821. char *str;
  1822. {
  1823.     char *ret;
  1824.  
  1825.     ret=(char *)ck_malloc(strlen(str)+2);
  1826.     strcpy(ret,str);
  1827.     return ret;
  1828. }
  1829.  
  1830.  
  1831. /*
  1832.  * memchr - search for a byte
  1833.  *
  1834.  */
  1835.  
  1836. VOID *
  1837. memchr(s, ucharwanted, size)
  1838. VOID *s;
  1839. int ucharwanted;
  1840. int size;
  1841. {
  1842.     register char *scan;
  1843.     register n;
  1844.     register uc;
  1845.  
  1846.     scan = (char *)s;
  1847.     uc = (ucharwanted&0xFF);
  1848.     for (n = size; n > 0; n--)
  1849. #ifdef __BUG__
  1850.         /* Nope, '==' has higher precedence than '&' ... [tho]  */
  1851.         if ((*scan)&0xFF == uc)
  1852. #else /* FIXED */
  1853.         if ( ((*scan)&0xFF) == uc)
  1854. #endif /* FIXED */
  1855.             return((VOID *)scan);
  1856.         else
  1857.             scan++;
  1858.  
  1859.     return 0;
  1860. }
  1861.  
  1862. /*
  1863.  * memmove - copy bytes, being careful about overlap.
  1864.  */
  1865.  
  1866. VOID *
  1867. memmove(dst, src, size)
  1868. VOID *dst;
  1869. VOID *src;
  1870. int size;
  1871. {
  1872.     register char *d;
  1873.     register char *s;
  1874.     register int n;
  1875.  
  1876.     if (size <= 0)
  1877.         return(dst);
  1878.  
  1879.     s = (char *)src;
  1880.     d = (char *)dst;
  1881.     if (s <= d && s + (size-1) >= d) {
  1882.         /* Overlap, must copy right-to-left. */
  1883.         s += size-1;
  1884.         d += size-1;
  1885.         for (n = size; n > 0; n--)
  1886.             *d-- = *s--;
  1887.     } else
  1888.         for (n = size; n > 0; n--)
  1889.             *d++ = *s++;
  1890.  
  1891.     return(dst);
  1892. }
  1893.  
  1894. #endif /* not MSDOS */
  1895.  
  1896. /* Implement a variable sized buffer of 'stuff'.  We don't know what it is,
  1897.    nor do we care, as long as it doesn't mind being aligned by malloc. */
  1898.  
  1899. struct buffer {
  1900.     int    allocated;
  1901.     int    length;
  1902.     char    *b;
  1903. };
  1904.  
  1905. #define MIN_ALLOCATE 50
  1906.  
  1907. VOID *
  1908. init_buffer()
  1909. {
  1910.     struct buffer *b;
  1911.  
  1912.     b=(struct buffer *)ck_malloc(sizeof(struct buffer));
  1913.     b->allocated=MIN_ALLOCATE;
  1914.     b->b=(char *)ck_malloc(MIN_ALLOCATE);
  1915.     b->length=0;
  1916.     return (VOID *)b;
  1917. }
  1918.  
  1919. void
  1920. flush_buffer(bb)
  1921. VOID *bb;
  1922. {
  1923.     struct buffer *b;
  1924.  
  1925.     b=(struct buffer *)bb;
  1926.     free(b->b);
  1927.     b->b=0;
  1928.     b->allocated=0;
  1929.     b->length=0;
  1930.     free(b);
  1931. }
  1932.  
  1933. int
  1934. size_buffer(b)
  1935. VOID *b;
  1936. {
  1937.     struct buffer *bb;
  1938.  
  1939.     bb=(struct buffer *)b;
  1940.     return bb->length;
  1941. }
  1942.  
  1943. void
  1944. add_buffer(bb,p,n)
  1945. VOID *bb;
  1946. char *p;
  1947. int n;
  1948. {
  1949.     struct buffer *b;
  1950.  
  1951.     b=(struct buffer *)bb;
  1952.     if(b->length+n>b->allocated) {
  1953.         b->allocated*=2;
  1954.         b->b=(char *)ck_realloc(b->b,b->allocated);
  1955.     }
  1956.     bcopy(p,b->b+b->length,n);
  1957.     b->length+=n;
  1958. }
  1959.  
  1960. void
  1961. add1_buffer(bb,ch)
  1962. VOID *bb;
  1963. int ch;
  1964. {
  1965.     struct buffer *b;
  1966.  
  1967.     b=(struct buffer *)bb;
  1968.     if(b->length+1>b->allocated) {
  1969.         b->allocated*=2;
  1970.         b->b=(char *)ck_realloc(b->b,b->allocated);
  1971.     }
  1972.     b->b[b->length]=ch;
  1973.     b->length++;
  1974. }
  1975.  
  1976. char *
  1977. get_buffer(bb)
  1978. VOID *bb;
  1979. {
  1980.     struct buffer *b;
  1981.  
  1982.     b=(struct buffer *)bb;
  1983.     return b->b;
  1984. }
  1985.  
  1986. #endif
  1987.