home *** CD-ROM | disk | FTP | other *** search
- /* sed.c emulate the UN*X sed command.
- Copyright (C) 1989 Free Software Foundation, Inc.
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
- NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
- WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
- RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
- DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
- CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
- STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
- WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
- LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
- OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
- USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
- DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
- A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
- PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
- as you receive it, in any medium, provided that you conspicuously
- and appropriately publish on each copy a valid copyright notice
- "Copyright (C) 1989 Free Software Foundation, Inc.", and include
- following the copyright notice a verbatim copy of the above disclaimer
- of warranty and of this License.
-
- 2. You may modify your copy or copies of this source file or
- any portion of it, and copy and distribute such modifications under
- the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more
- extensive warranty protection to third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
- 3. You may copy and distribute this program or any portion of it in
- compiled, executable or object code form under the terms of Paragraphs
- 1 and 2 above provided that you do the following:
-
- a) cause each such copy to be accompanied by the
- corresponding machine-readable source code, which must
- be distributed under the terms of Paragraphs 1 and 2 above; or,
-
- b) cause each such copy to be accompanied by a
- written offer, with no time limit, to give any third party
- free (except for a nominal shipping charge) a machine readable
- copy of the corresponding source code, to be distributed
- under the terms of Paragraphs 1 and 2 above; or,
-
- c) in the case of a recipient of this program in compiled, executable
- or object code form (without the corresponding source code) you
- shall cause copies you distribute to be accompanied by a copy
- of the written offer of source code which you received along
- with the copy you received.
-
- 4. You may not copy, sublicense, distribute or transfer this program
- except as expressly provided under this License Agreement. Any attempt
- otherwise to copy, sublicense, distribute or transfer this program is void and
- your rights to use the program under this License agreement shall be
- automatically terminated. However, parties who have received computer
- software programs from you with this License Agreement will not have
- their licenses terminated so long as such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of this program into other free
- programs whose distribution conditions are different, write to the Free
- Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
- worked out a simple rule that can be stated here, but we will often permit
- this. We will be guided by the two goals of preserving the free status of
- all derivatives of our free software and of promoting the sharing and reuse of
- software.
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
-
- #include <stdio.h>
- #include <ctype.h>
- #include "regex.h"
-
- #ifdef AZTEC_C
- #define memcpy(dst,src,n) movmem((src),(dst),(n))
- #define memset(src,value,howmany) setmem((src),(howmany),(value))
- #define bcopy(s, d, n) movmem((s),(d),(n))
- #endif
-
- /* Compile with 'gcc [-g] [-DHAS_UTILS] [-O] -o sed sed.c [-lutils]' */
- /* Use '-DHAS_UTILS', -lutils if you if you have hack's utils library */
- /* Add '-I. regex.c' if regex is not in the system include dir/library */
- #ifdef USG
- #define bcopy(s, d, n) ((void)memcpy((d),(s), (n)))
- #endif
-
- /* Struct vector is used to describe a chunk of a sed program. There is one
- vector for the main program, and one for each { } pair.
- */
- struct vector {
- struct sed_cmd *v;
- int v_length;
- int v_allocated;
- struct vector *up_one;
- struct vector *next_one;
- };
-
-
- /* Goto structure is used to hold both GOTO's and labels. There are two
- separate lists, one of goto's, called 'jumps', and one of labels, called
- 'labels'.
- the V element points to the descriptor for the program-chunk in which the
- goto was encountered.
- the v_index element counts which element of the vector actually IS the
- goto/label. The first element of the vector is zero.
- the NAME element is the null-terminated name of the label.
- next is the next goto/label in the list
- */
-
- struct sed_label {
- struct vector *v;
- int v_index;
- char *name;
- struct sed_label *next;
- };
-
- /* ADDR_TYPE is zero for a null address,
- one if addr_number is valid, or
- two if addr_regex is valid,
- three, if the address is '$'
-
- Other values are undefined.
- */
-
- #define ADDR_NULL 0
- #define ADDR_NUM 1
- #define ADDR_REGEX 2
- #define ADDR_LAST 3
-
- struct addr {
- int addr_type;
- struct re_pattern_buffer *addr_regex;
- int addr_number;
- };
-
-
- /* Aflags: If the low order bit is set, a1 has been
- matched; apply this command until a2 matches.
- If the next bit is set, apply this command to all
- lines that DON'T match the address(es).
- */
-
- #define A1_MATCHED_BIT 01
- #define ADDR_BANG_BIT 02
-
-
- struct sed_cmd {
- struct addr a1,a2;
- int aflags;
-
- char cmd;
-
- union {
- /* This structure is used for a, i, and c commands */
- struct {
- char *text;
- int text_len;
- } cmd_txt;
-
- /* This is used for b and t commands */
- struct sed_cmd *label;
-
- /* This for r and w commands */
- FILE *io_file;
-
- /* This for the hairy s command */
- /* For the flags var:
- low order bit means the 'g' option was given,
- next bit means the 'p' option was given,
- and the next bit means a 'w' option was given,
- and wio_file contains the file to write to. */
-
- #define S_GLOBAL_BIT 01
- #define S_PRINT_BIT 02
- #define S_WRITE_BIT 04
- #define S_NUM_BIT 010
-
- struct {
- struct re_pattern_buffer *regx;
- char *replacement;
- int replace_length;
- int flags;
- int numb;
- FILE *wio_file;
- } cmd_regex;
-
- /* This for the y command */
- char *translate;
-
- /* For { and } */
- struct vector *sub;
- struct sed_label *jump;
- } x;
- };
-
- /* Sed operates a line at a time. */
- struct line {
- char *text; /* Pointer to line allocated by malloc. */
- int length; /* Length of text. */
- int alloc; /* Allocated space for text. */
- };
-
- /* This for all you losing compilers out there that can't handle void * */
- #ifdef __GNU__
- #define VOID void
- #else
- #define VOID char
- #endif
-
- extern int optind;
- extern char *optarg;
- extern int getopt();
-
- extern char *memchr();
- extern VOID *memmove();
-
- extern VOID *ck_malloc(),*ck_realloc();
- extern VOID *init_buffer();
- extern char *get_buffer();
- extern FILE *ck_fopen();
- extern void ck_fclose();
- extern void ck_fwrite();
- extern void flush_buffer();
- extern void add1_buffer();
-
- extern char *strdup();
-
- struct vector *compile_program();
- void savchar();
- struct sed_label *setup_jump();
- void line_copy();
- void line_append();
- void append_pattern_space();
-
- #ifndef HAS_UTILS
- char *myname;
- #else
- extern char *myname;
- #endif
- /* This is a good idea */
- char *version_string = "GNU sed version 1.02 (or so)";
- /* 1.00 Began distributing this file
- * 1.01 Added s/re/rep/[digits]
- * added #n as first line of script
- * added filename globbing
- * added 'l' command
- * All in the name of POSIX
- * 1.02 Fixed D command
- * Added Amiga porting ifdefs
- * Edwin Hoogerbeets 1989
- */
-
- /* If set, don't write out the line unless explictly told to */
- int no_default_output = 0;
-
- /* Current input line # */
- int input_line_number = 0;
-
- /* Are we on the last input file? */
- int last_input_file = 0;
-
- /* Have we hit EOF on the last input file? */
- int input_EOF = 0;
-
- /* non-zero if a quit command has been hit */
- int quit_cmd = 0;
-
- /* Have we done any replacements lately? */
- int replaced = 0;
-
- /* How many '{'s are we executing at the moment */
- int program_depth = 0;
-
- /* The current SED program */
- struct vector *the_program = 0;
-
- /* */
- struct sed_label *jumps = 0;
- struct sed_label *labels = 0;
-
- /* The 'current' input line. */
- struct line line;
-
- /* An input line that's been stored by later use by the program */
- struct line hold;
-
- /* A 'line' to append to the current line when it comes time to write it out */
- struct line append;
-
- static char ONE_ADDR[] = "Command only uses one address";
- static char NO_ADDR[] = "Command doesn't take any addresses";
- static char LINE_JUNK[] ="Extra characters after command";
- static char BAD_EOF[] = "Unexpected End-of-file";
- static char USAGE[] = "Usage: %s [-n] [-e script...] [-f sfile...] [file...]\n";
- static char NO_REGEX[] = "No previous regular expression";
-
- struct re_pattern_buffer *last_regex;
-
- FILE *input_file;
-
- int bad_input = 0;
-
- main(argc,argv)
- char **argv;
- {
- int opt;
- int compiled = 0;
- struct sed_label *go,*lbl;
-
- #ifdef AZTEC_C
- extern long _Heapsize;
-
- _Heapsize = 80 * 1024;
- #endif
-
- myname=argv[0];
- while((opt=getopt(argc,argv,"ne:f:"))!=EOF) {
- switch(opt) {
- case 'n':
- if(no_default_output)
- panic(USAGE);
- no_default_output++;
- break;
- case 'e':
- compile_string(optarg);
- compiled++;
- break;
- case 'f':
- compile_file(optarg);
- compiled++;
- break;
- }
- }
- if(!compiled) {
- if(argc<=optind)
- panic("No program to run\n");
- compile_string(argv[optind]);
- optind++;
- }
-
- for(go=jumps;go;go=go->next) {
- for(lbl=labels;lbl;lbl=lbl->next)
- if(!strcmp(lbl->name,go->name))
- break;
- if(!lbl)
- panic("Can't find label for jump to '%s'\n",go->name);
- go->v->v[go->v_index].x.jump=lbl;
- }
-
- line.length=0;
- line.alloc=50;
- line.text=ck_malloc(50);
-
- append.length=0;
- append.alloc=50;
- append.text=ck_malloc(50);
-
- hold.length=0;
- hold.alloc=50;
- hold.text=ck_malloc(50);
-
- if(argc<=optind) {
- last_input_file++;
- read_file("-");
- } else while(optind<argc) {
- if(optind==argc-1)
- last_input_file++;
- read_file(argv[optind]);
- optind++;
- if(quit_cmd)
- break;
- }
- if(bad_input)
- exit(2);
- exit(0);
- }
-
- char *prog_start;
- char *prog_end;
- char *prog_cur;
-
- char *prog_name;
- FILE *prog_file;
-
- int prog_line = 1;
-
- compile_string(str)
- char *str;
- {
- prog_file = 0;
- prog_line=0;
- prog_start=prog_cur=str;
- prog_end=str+strlen(str);
- the_program=compile_program(the_program);
- }
-
- compile_file(str)
- char *str;
- {
- FILE *file;
- int ch;
-
- prog_start=prog_cur=prog_end=0;
- prog_name=str;
- prog_line=1;
- if(str[0]=='-' && str[1]=='\0')
- prog_file=stdin;
- else
- prog_file=ck_fopen(str,"r");
- ch=getc(prog_file);
- if(ch=='#') {
- ch=getc(prog_file);
- if(ch=='n')
- no_default_output++;
- while(ch!=EOF && ch!='\n')
- ch=getc(prog_file);
- } else if(ch!=EOF)
- ungetc(ch,prog_file);
- the_program=compile_program(the_program);
- }
-
- #define MORE_CMDS 40
-
- struct vector *
- compile_program(vector)
- struct vector *vector;
- {
- struct sed_cmd *cur_cmd;
- int ch;
- int slash;
- VOID *b;
- char *string;
- int num;
-
- FILE *compile_filename();
-
- if(!vector) {
- vector=(struct vector *)ck_malloc(sizeof(struct vector));
- vector->v=(struct sed_cmd *)ck_malloc(MORE_CMDS*sizeof(struct sed_cmd));
- vector->v_allocated=MORE_CMDS;
- vector->v_length=0;
- vector->up_one = 0;
- vector->next_one = 0;
- }
- for(;;) {
- do ch=inchar();
- while(ch!=EOF && (isspace(ch) || ch=='\n' || ch==';'));
- if(ch==EOF)
- break;
- savchar(ch);
-
- if(vector->v_length==vector->v_allocated) {
- vector->v=(struct sed_cmd *)ck_realloc((VOID *)vector->v,(vector->v_length+MORE_CMDS)*sizeof(struct sed_cmd));
- vector->v_allocated+=MORE_CMDS;
- }
- cur_cmd=vector->v+vector->v_length;
- vector->v_length++;
-
- cur_cmd->a1.addr_type=0;
- cur_cmd->a2.addr_type=0;
- cur_cmd->aflags=0;
- cur_cmd->cmd=0;
-
- skip_comment:
- if(compile_address(&(cur_cmd->a1))) {
- ch=inchar();
- if(ch==',') {
- do ch=inchar();
- while(ch!=EOF && isspace(ch));
- savchar(ch);
- if(compile_address(&(cur_cmd->a2)))
- ;
- else
- bad_prog("Unexpected ','");
- } else
- savchar(ch);
- }
- ch=inchar();
- if(ch==EOF)
- break;
- new_cmd:
- switch(ch) {
- case '#':
- if(cur_cmd->a1.addr_type!=0)
- bad_prog(NO_ADDR);
- do ch=inchar();
- while(ch!=EOF && ch!='\n');
- goto skip_comment;
- case '!':
- if(cur_cmd->aflags & ADDR_BANG_BIT)
- bad_prog("Multiple '!'s");
- cur_cmd->aflags|= ADDR_BANG_BIT;
- do ch=inchar();
- while(ch!=EOF && isspace(ch));
- if(ch==EOF)
- bad_prog(BAD_EOF);
- /* savchar(ch); */
- goto new_cmd;
- case 'a':
- case 'i':
- if(cur_cmd->a2.addr_type!=0)
- bad_prog(ONE_ADDR);
- /* Fall Through */
- case 'c':
- cur_cmd->cmd=ch;
- if(inchar()!='\\' || inchar()!='\n')
- bad_prog(LINE_JUNK);
- b=init_buffer();
- while((ch=inchar())!=EOF && ch!='\n') {
- if(ch=='\\')
- ch=inchar();
- add1_buffer(b,ch);
- }
- if(ch!=EOF)
- add1_buffer(b,ch);
- num=size_buffer(b);
- string=(char *)ck_malloc(num);
- bcopy(get_buffer(b),string,num);
- flush_buffer(b);
- cur_cmd->x.cmd_txt.text_len=num;
- cur_cmd->x.cmd_txt.text=string;
- break;
- case '{':
- cur_cmd->cmd=ch;
- program_depth++;
- /* while((ch=inchar())!=EOF && ch!='\n')
- if(!isspace(ch))
- bad_prog(LINE_JUNK); */
- cur_cmd->x.sub=compile_program((struct vector *)0);
- /* FOO JF is this the right thing to do? */
- break;
- case '}':
- if(!program_depth)
- bad_prog("Unexpected '}'");
- --(vector->v_length);
- while((ch=inchar())!=EOF && ch!='\n')
- if(!isspace(ch))
- bad_prog(LINE_JUNK);
- return vector;
- case ':':
- cur_cmd->cmd=ch;
- if(cur_cmd->a1.addr_type!=0)
- bad_prog(": doesn't want any addresses");
- labels=setup_jump(labels,cur_cmd,vector);
- break;
- case 'b':
- case 't':
- cur_cmd->cmd=ch;
- jumps=setup_jump(jumps,cur_cmd,vector);
- break;
- case 'q':
- case '=':
- if(cur_cmd->a2.addr_type)
- bad_prog(ONE_ADDR);
- /* Fall Through */
- case 'd':
- case 'D':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- case 'l':
- case 'n':
- case 'N':
- case 'p':
- case 'P':
- case 'x':
- cur_cmd->cmd=ch;
- do ch=inchar();
- while(ch!=EOF && isspace(ch) && ch!='\n' && ch!=';');
- if(ch!='\n' && ch!=';' && ch!=EOF)
- bad_prog(LINE_JUNK);
- break;
-
- case 'r':
- if(cur_cmd->a2.addr_type!=0)
- bad_prog(ONE_ADDR);
- /* FALL THROUGH */
- case 'w':
- cur_cmd->cmd=ch;
- cur_cmd->x.io_file=compile_filename(ch=='r');
- break;
-
- case 's':
- cur_cmd->cmd=ch;
- b=init_buffer();
- slash=inchar();
- while((ch=inchar())!=EOF && ch!=slash) {
- if(ch!='\\') {
- add1_buffer(b,ch);
- continue;
- }
- ch=inchar();
- switch(ch) {
- case 'n':
- add1_buffer(b,'\n');
- break;
- /* case 'b':
- add1_buffer(b,'\b');
- break;
- case 'f':
- add1_buffer(b,'\f');
- break;
- case 'r':
- add1_buffer(b,'\r');
- break;
- case 't':
- add1_buffer(b,'\t');
- break; */
- case EOF:
- break;
- default:
- add1_buffer(b,'\\');
- add1_buffer(b,ch);
- break;
- }
- }
- if(ch==EOF)
- bad_prog(BAD_EOF);
- if(size_buffer(b)) {
- last_regex=(struct re_pattern_buffer *)ck_malloc(sizeof(struct re_pattern_buffer));
- last_regex->allocated=size_buffer(b);
- last_regex->buffer=ck_malloc(last_regex->allocated);
- last_regex->fastmap=0;
- last_regex->translate=0;
- re_compile_pattern(get_buffer(b),size_buffer(b),last_regex);
- } else if(!last_regex)
- bad_prog(NO_REGEX);
- cur_cmd->x.cmd_regex.regx=last_regex;
- flush_buffer(b);
-
- b=init_buffer();
- while((ch=inchar())!=EOF && ch!=slash) {
- if(ch=='\\') {
- int ci;
-
- ci=inchar();
- if(ci!=EOF) {
- if(ci!='\n')
- add1_buffer(b,ch);
- add1_buffer(b,ci);
- }
- } else
- add1_buffer(b,ch);
- }
- cur_cmd->x.cmd_regex.replace_length=size_buffer(b);
- cur_cmd->x.cmd_regex.replacement=ck_malloc(cur_cmd->x.cmd_regex.replace_length);
- bcopy(get_buffer(b),cur_cmd->x.cmd_regex.replacement,cur_cmd->x.cmd_regex.replace_length);
- flush_buffer(b);
-
- cur_cmd->x.cmd_regex.flags=0;
- cur_cmd->x.cmd_regex.numb=0;
-
- if(ch==EOF)
- break;
- do {
- ch=inchar();
- switch(ch) {
- case 'p':
- if(cur_cmd->x.cmd_regex.flags&S_PRINT_BIT)
- bad_prog("multiple 'p' options to 's' command");
- cur_cmd->x.cmd_regex.flags|=S_PRINT_BIT;
- break;
- case 'g':
- if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT)
- cur_cmd->x.cmd_regex.flags&= ~S_NUM_BIT;
- if(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT)
- bad_prog("multiple 'g' options to 's' command");
- cur_cmd->x.cmd_regex.flags|=S_GLOBAL_BIT;
- break;
- case 'w':
- cur_cmd->x.cmd_regex.flags|=S_WRITE_BIT;
- cur_cmd->x.cmd_regex.wio_file=compile_filename(0);
- ch='\n';
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9':
- if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT)
- bad_prog("multiple number options to 's' command");
- if(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT==0)
- cur_cmd->x.cmd_regex.flags|=S_NUM_BIT;
- num = 0;
- while(isdigit(ch)) {
- num=num*10+ch-'0';
- ch=inchar();
- }
- savchar(ch);
- cur_cmd->x.cmd_regex.numb=num;
- break;
- case '\n':
- case ';':
- case EOF:
- break;
- default:
- bad_prog("Unknown option to 's'");
- break;
- }
- } while(ch!=EOF && ch!='\n' && ch!=';');
- if(ch==EOF)
- break;
- break;
-
- case 'y':
- cur_cmd->cmd=ch;
- string=ck_malloc(256);
- for(num=0;num<256;num++)
- string[num]=num;
- b=init_buffer();
- slash=inchar();
- while((ch=inchar())!=EOF && ch!=slash)
- add1_buffer(b,ch);
- cur_cmd->x.translate=string;
- string=get_buffer(b);
- for(num=size_buffer(b);num;--num) {
- ch=inchar();
- if(ch==EOF)
- bad_prog(BAD_EOF);
- if(ch==slash)
- bad_prog("strings for y command are different lengths");
- cur_cmd->x.translate[*string++]=ch;
- }
- flush_buffer(b);
- if(inchar()!=slash || inchar()!='\n')
- bad_prog(LINE_JUNK);
- break;
-
- default:
- fprintf(stderr,"sed: Command: %c\n",ch);
- bad_prog("Unknown command");
- }
- }
- return vector;
- }
-
- bad_prog(why)
- char *why;
- {
- if(prog_line)
- fprintf(stderr,"%s: file %s line %d: %s\n",myname,prog_name,prog_line,why);
- else
- fprintf(stderr,"%s: %s\n",myname,why);
- exit(1);
- }
-
- int
- inchar()
- {
- int ch;
- if(prog_file)
- ch=getc(prog_file);
- else {
- if(!prog_cur)
- return EOF;
- else if(prog_cur==prog_end) {
- ch=EOF;
- prog_cur=0;
- } else
- ch= *prog_cur++;
- }
- if(ch=='\n' && prog_line)
- prog_line++;
- return ch;
- }
-
- void
- savchar(ch)
- int ch;
- {
- if(ch==EOF)
- return;
- if(ch=='\n' && prog_line>1)
- --prog_line;
- if(prog_file)
- ungetc(ch,prog_file);
- else
- *--prog_cur=ch;
- }
-
-
- compile_address(addr)
- struct addr *addr;
- {
- int ch;
- int num;
- char *b,*init_buffer();
-
- ch=inchar();
-
- if(isdigit(ch)) {
- num=ch-'0';
- while((ch=inchar())!=EOF && isdigit(ch))
- num=num*10+ch-'0';
- while(ch!=EOF && isspace(ch))
- ch=inchar();
- savchar(ch);
- addr->addr_type=ADDR_NUM;
- addr->addr_number = num;
- return 1;
- } else if(ch=='/') {
- addr->addr_type=ADDR_REGEX;
- b=init_buffer();
- while((ch=inchar())!=EOF && ch!='/') {
- add1_buffer(b,ch);
- if(ch=='\\') {
- ch=inchar();
- if(ch!=EOF)
- add1_buffer(b,ch);
- }
- }
- if(size_buffer(b)) {
- last_regex=(struct re_pattern_buffer *)ck_malloc(sizeof(struct re_pattern_buffer));
- last_regex->allocated=size_buffer(b);
- last_regex->buffer=ck_malloc(last_regex->allocated);
- last_regex->fastmap=0;
- last_regex->translate=0;
- re_compile_pattern(get_buffer(b),size_buffer(b),last_regex);
- } else if(!last_regex)
- bad_prog(NO_REGEX);
-
- addr->addr_regex=last_regex;
- flush_buffer(b);
- do ch=inchar();
- while(ch!=EOF && isspace(ch));
- savchar(ch);
- return 1;
- } else if(ch=='$') {
- addr->addr_type=ADDR_LAST;
- do ch=inchar();
- while(ch!=EOF && isspace(ch));
- savchar(ch);
- return 1;
- } else
- savchar(ch);
- return 0;
- }
-
- struct sed_label *
- setup_jump(list,cmd,vec)
- struct sed_label *list;
- struct sed_cmd *cmd;
- struct vector *vec;
- {
- struct sed_label *tmp;
- VOID *b;
- int ch;
-
- b=init_buffer();
- while((ch=inchar())!=EOF && ch!='\n')
- add1_buffer(b,ch);
- add1_buffer(b,'\0');
- tmp=(struct sed_label *)ck_malloc(sizeof(struct sed_label));
- tmp->v=vec;
- tmp->v_index=cmd-vec->v;
- tmp->name=strdup(get_buffer(b));
- tmp->next=list;
- flush_buffer(b);
- return tmp;
- }
-
- #define NUM_FPS 32
- struct {
- FILE *phile;
- char *name;
- int readit;
- } file_ptrs[NUM_FPS];
-
- FILE *
- compile_filename(readit)
- {
- char *file_name;
- int n;
- VOID *b;
- int ch;
- char **globbed;
- extern char **glob_filename();
-
- if(inchar()!=' ')
- bad_prog("missing ' ' before filename");
- b=init_buffer();
- while((ch=inchar())!=EOF && ch!='\n')
- add1_buffer(b,ch);
- add1_buffer(b,'\0');
- file_name=get_buffer(b);
- globbed=glob_filename(file_name);
- if(globbed==0 || globbed==(char **)-1)
- bad_prog("can't parse filename");
- if(globbed[0] && globbed[1]!=0)
- bad_prog("multiple files");
- if(globbed[0])
- file_name=globbed[0];
- for(n=0;n<NUM_FPS;n++) {
- if(!file_ptrs[n].name)
- break;
- if(!strcmp(file_ptrs[n].name,file_name)) {
- if(file_ptrs[n].readit!=readit)
- bad_prog("Can't open file for both reading and writing");
- flush_buffer(b);
- return file_ptrs[n].phile;
- }
- }
- if(n<NUM_FPS) {
- file_ptrs[n].name=strdup(file_name);
- file_ptrs[n].readit=readit;
- file_ptrs[n].phile=ck_fopen(file_name,readit ? "r" : "a");
- flush_buffer(b);
- return file_ptrs[n].phile;
- } else {
- bad_prog("Hopelessely evil compiled in limit on number of open files. re-compile sed\n");
- return 0;
- }
- }
-
- read_file(name)
- char *name;
- {
- if(*name=='-' && name[1]=='\0')
- input_file=stdin;
- else {
- input_file=fopen(name,"r");
- if(input_file==0) {
- bad_input++;
- return;
- }
- }
- while(read_pattern_space()) {
- execute_program(the_program);
- if(!no_default_output)
- ck_fwrite(line.text,1,line.length,stdout);
- if(append.length) {
- ck_fwrite(append.text,1,append.length,stdout);
- append.length=0;
- }
- if(quit_cmd)
- break;
- }
- ck_fclose(input_file);
- }
-
- execute_program(vec)
- struct vector *vec;
- {
- struct sed_cmd *cur_cmd;
- int n;
- int addr_matched;
- static int end_cycle;
-
- int start;
- int remain;
- int offset;
-
- static struct line tmp;
- struct line t;
- char *rep,*rep_end,*rep_next,*rep_cur;
-
- struct re_registers regs;
- int count = 0;
- void str_append();
-
-
- end_cycle = 0;
-
- for(cur_cmd=vec->v,n=vec->v_length;n;cur_cmd++,n--) {
-
- exe_loop:
- addr_matched=0;
- if(cur_cmd->aflags&A1_MATCHED_BIT) {
- addr_matched=1;
- if(match_address(&(cur_cmd->a2)))
- cur_cmd->aflags&=~A1_MATCHED_BIT;
- } else if(match_address(&(cur_cmd->a1))) {
- addr_matched=1;
- if(cur_cmd->a2.addr_type!=ADDR_NULL)
- cur_cmd->aflags|=A1_MATCHED_BIT;
- }
- if(cur_cmd->aflags&ADDR_BANG_BIT)
- addr_matched= !addr_matched;
- if(!addr_matched)
- continue;
- switch(cur_cmd->cmd) {
- case '{': /* Execute sub-program */
- execute_program(cur_cmd->x.sub);
- break;
-
- case ':': /* Executing labels is easy. */
- break;
-
- case '=':
- printf("%d\n",input_line_number);
- break;
-
- case 'a':
- if(append.alloc-append.length<cur_cmd->x.cmd_txt.text_len) {
- append.text=ck_realloc(append.text,append.alloc+cur_cmd->x.cmd_txt.text_len);
- append.alloc+=cur_cmd->x.cmd_txt.text_len;
- }
- bcopy(cur_cmd->x.cmd_txt.text,append.text+append.length,cur_cmd->x.cmd_txt.text_len);
- append.length+=cur_cmd->x.cmd_txt.text_len;
- break;
-
- case 'b':
- if(!cur_cmd->x.jump)
- end_cycle++;
- else {
- struct sed_label *j = cur_cmd->x.jump;
-
- n= j->v->v_length - j->v_index;
- cur_cmd= j->v->v + j->v_index;
- goto exe_loop;
- }
- break;
-
- case 'c':
- line.length=0;
- if(!(cur_cmd->aflags&A1_MATCHED_BIT))
- ck_fwrite(cur_cmd->x.cmd_txt.text,1,cur_cmd->x.cmd_txt.text_len,stdout);
- end_cycle++;
- break;
-
- case 'd':
- line.length=0;
- end_cycle++;
- break;
-
- case 'D':
- {
- char *tmp;
- int newlength;
-
- tmp=memchr(line.text,'\n',line.length);
- newlength=line.length-(tmp-line.text+1);
- if(newlength)
- memmove(line.text,tmp,newlength);
- line.length=newlength;
- }
- end_cycle++;
- break;
-
- case 'g':
- line_copy(&hold,&line);
- break;
-
- case 'G':
- line_append(&hold,&line);
- break;
-
- case 'h':
- line_copy(&line,&hold);
- break;
-
- case 'H':
- line_append(&line,&hold);
- break;
-
- case 'i':
- ck_fwrite(cur_cmd->x.cmd_txt.text,1,cur_cmd->x.cmd_txt.text_len,stdout);
- break;
-
- case 'l':
- {
- char *tmp;
- int n;
- int width = 0;
-
- n=line.length;
- tmp=line.text;
- /* Use --n so this'll skip the trailing newline */
- while(--n) {
- if(width>77) {
- width=0;
- putchar('\n');
- }
- if(isprint(*tmp)) {
- putchar(*tmp);
- width++;
- } else switch(*tmp) {
- case '\0':
- printf("\\0");
- width+=2;
- break;
- case '\a':
- printf("\\a");
- width+=2;
- break;
- case '\b':
- printf("\\b");
- width+=2;
- break;
- case '\f':
- printf("\\f");
- width+=2;
- break;
- case '\n':
- printf("\\n");
- width+=2;
- break;
- case '\r':
- printf("\\r");
- width+=2;
- break;
- case '\t':
- printf("\\t");
- width+=2;
- break;
- case '\v':
- printf("\\v");
- width+=2;
- break;
- default:
- printf("/%02x",(*tmp)&0xFF);
- width+=2;
- break;
- }
- tmp++;
- }
- putchar('\n');
- }
- break;
-
- case 'n':
- ck_fwrite(line.text,1,line.length,stdout);
- read_pattern_space();
- break;
-
- case 'N':
- append_pattern_space();
- break;
-
- case 'p':
- ck_fwrite(line.text,1,line.length,stdout);
- break;
-
- case 'P':
- {
- char *tmp;
-
- tmp=memchr(line.text,'\n',line.length);
- ck_fwrite(line.text,1,line.length-(tmp-line.text),stdout);
- }
- break;
-
- case 'q':
- quit_cmd++;
- end_cycle++;
- break;
-
- case 'r':
- {
- int n;
- char tmp_buf[1024];
-
- rewind(cur_cmd->x.io_file);
- while((n=fread(tmp_buf,sizeof(char),1024,cur_cmd->x.io_file))>0)
- ck_fwrite(tmp_buf,sizeof(char),n,stdout);
- if(ferror(cur_cmd->x.io_file))
- panic("Read error on input file to 'r' command\n");
- }
- break;
-
- case 's':
- if(!tmp.alloc) {
- tmp.alloc=50;
- tmp.text=ck_malloc(50);
- }
- count=0;
- start = 0;
- remain=line.length-1;
- tmp.length=0;
- rep = cur_cmd->x.cmd_regex.replacement;
- rep_end=rep+cur_cmd->x.cmd_regex.replace_length;
-
- while((offset = re_search(cur_cmd->x.cmd_regex.regx,
- line.text,
- line.length-1,
- start,
- remain,
- ®s))>=0) {
- count++;
- if(offset-start)
- str_append(&tmp,line.text+start,offset-start);
-
- if(cur_cmd->x.cmd_regex.flags&S_NUM_BIT) {
- if(count!=cur_cmd->x.cmd_regex.numb) {
- str_append(&tmp,line.text+regs.start[0],regs.end[0]-regs.start[0]);
- start = (offset == regs.end[0] ? offset + 1 : regs.end[0]);
- remain = (line.length-1) - start;
- continue;
- }
- }
-
- for(rep_next=rep_cur=rep;rep_next<rep_end;rep_next++) {
- if(*rep_next=='&') {
- if(rep_next-rep_cur)
- str_append(&tmp,rep_cur,rep_next-rep_cur);
- str_append(&tmp,line.text+regs.start[0],regs.end[0]-regs.start[0]);
- rep_cur=rep_next+1;
- } else if(*rep_next=='\\') {
- if(rep_next-rep_cur)
- str_append(&tmp,rep_cur,rep_next-rep_cur);
- rep_next++;
- if(rep_next!=rep_end) {
- int n;
-
- if(*rep_next>='0' && *rep_next<='9') {
- n= *rep_next -'0';
- str_append(&tmp,line.text+regs.start[n],regs.end[n]-regs.start[n]);
- } else
- str_append(&tmp,&rep_next,1);
- }
- rep_cur=rep_next+1;
- }
- }
- if(rep_next-rep_cur)
- str_append(&tmp,rep_cur,rep_next-rep_cur);
- start = (offset == regs.end[0] ? offset + 1 : regs.end[0]);
- remain = (line.length-1) - start;
- if(!(cur_cmd->x.cmd_regex.flags&S_GLOBAL_BIT))
- break;
- }
- if(!count)
- break;
- replaced=1;
- str_append(&tmp,line.text+regs.end[0],line.length-regs.end[0]);
- t.text=line.text;
- t.length=line.length;
- t.alloc=line.alloc;
- line.text=tmp.text;
- line.length=tmp.length;
- line.alloc=tmp.alloc;
- tmp.text=t.text;
- tmp.length=t.length;
- tmp.alloc=t.alloc;
- if(cur_cmd->x.cmd_regex.flags&S_WRITE_BIT)
- ck_fwrite(line.text,1,line.length,cur_cmd->x.cmd_regex.wio_file);
- if(cur_cmd->x.cmd_regex.flags&S_PRINT_BIT)
- ck_fwrite(line.text,1,line.length,stdout);
- break;
-
- case 't':
- if(replaced) {
- replaced = 0;
- if(!cur_cmd->x.jump)
- end_cycle++;
- else {
- struct sed_label *j = cur_cmd->x.jump;
-
- n= j->v->v_length - j->v_index;
- cur_cmd= j->v->v + j->v_index;
- goto exe_loop;
- }
- }
- break;
-
- case 'w':
- ck_fwrite(line.text,1,line.length,cur_cmd->x.io_file);
- break;
-
- case 'x':
- {
- struct line tmp;
-
- tmp=line;
- line=hold;
- hold=tmp;
- }
- break;
-
- case 'y':
- {
- unsigned char *p,*e;
-
- for(p=(unsigned char *)(line.text),e=p+line.length;p<e;p++)
- *p=cur_cmd->x.translate[*p];
- }
- break;
-
- default:
- panic("INTERNAL ERROR: Bad cmd %c\n",cur_cmd->cmd);
- }
- if(end_cycle)
- break;
- }
- }
-
-
- match_address(addr)
- struct addr *addr;
- {
- switch(addr->addr_type) {
- case ADDR_NULL:
- return 1;
- case ADDR_NUM:
- return (input_line_number==addr->addr_number);
-
- case ADDR_REGEX:
- return (re_search(addr->addr_regex,
- line.text,
- line.length-1,
- 0,
- line.length-1,
- 0)>=0) ? 1 : 0;
-
- case ADDR_LAST:
- return (input_EOF) ? 1 : 0;
-
- default:
- panic("INTERNAL ERROR: bad address type\n");
- break;
- }
- return -1;
- }
-
- int
- read_pattern_space()
- {
- int n;
- char *p;
- int ch;
-
- p=line.text;
- n=line.alloc;
-
- input_line_number++;
- replaced=0;
- for(;;) {
- ch=getc(input_file);
- if(ch==EOF) {
- if(n==line.alloc)
- return 0;
- *p++='\n';
- --n;
- line.length=line.alloc-n;
- break;
- }
- *p++=ch;
- --n;
- if(ch=='\n') {
- line.length=line.alloc-n;
- break;
- }
- if(n==0) {
- line.text=ck_realloc(line.text,line.alloc*2);
- p=line.text+line.alloc;
- n=line.alloc;
- line.alloc*=2;
- }
- }
- ch=getc(input_file);
- if(ch!=EOF)
- ungetc(ch,input_file);
- else if(last_input_file)
- input_EOF++;
- return 1;
- }
-
- void
- append_pattern_space()
- {
- char *p;
- int n;
- int ch;
-
- p=line.text+line.length;
- n=line.alloc-line.length;
-
- input_line_number++;
- replaced=0;
- for(;;) {
- ch=getc(input_file);
- if(ch==EOF) {
- if(n==line.alloc)
- return;
- *p++='\n';
- --n;
- line.length=line.alloc-n;
- break;
- }
- *p++=ch;
- --n;
- if(ch=='\n') {
- line.length=line.alloc-n;
- break;
- }
- if(n==0) {
- line.text=ck_realloc(line.text,line.alloc*2);
- p=line.text+line.alloc;
- n=line.alloc;
- line.alloc*=2;
- }
- }
- ch=getc(input_file);
- if(ch!=EOF)
- ungetc(ch,input_file);
- else if(last_input_file)
- input_EOF++;
- }
-
- void
- line_copy(from,to)
- struct line *from,*to;
- {
- if(from->length>to->alloc) {
- to->alloc=from->length;
- to->text=ck_realloc(to->text,to->alloc);
- }
- bcopy(from->text,to->text,from->length);
- to->length=from->length;
- }
-
- void
- line_append(from,to)
- struct line *from,*to;
- {
- if(from->length>(to->alloc-to->length)) {
- to->alloc+=from->length;
- to->text=ck_realloc(to->text,to->alloc);
- }
- bcopy(from->text,to->text+to->length,from->length);
- to->length+=from->length;
- }
-
- void
- str_append(to,string,length)
- struct line *to;
- char *string;
- int length;
- {
- if(length>to->alloc-to->length) {
- to->alloc+=length;
- to->text=ck_realloc(to->text,to->alloc);
- }
- bcopy(string,to->text+to->length,length);
- to->length+=length;
- }
-
- #ifndef HAS_UTILS
-
- #ifdef __STDC__
- #include "stdarg.h"
-
- panic(str)
- char *str;
- {
- va_list iggy;
-
- va_start(iggy,str);
- fprintf(stderr,"%s: ",myname);
- #ifdef NO_VFPRINTF
- _doprnt(str,&iggy,stderr);
- #else
- vfprintf(stderr,str,iggy);
- #endif
- putc('\n',stderr);
- va_end(iggy);
- exit(4);
- }
-
- #else
- #ifdef AZTEC_C
-
- /* this kludge inserted because of lack of vfprintf or _doprnt in the
- * Manx libs, and this was easier than rewriting printf, which I have
- * no source to! Delete this if and when vfprintf is written on the Amiga.
- */
- panic(str,arg1,arg2,arg3)
- char *str;
- int arg1,arg2,arg3;
- {
- fprintf(stderr,"%s: ",myname);
- fprintf(stderr,str,arg1,arg2,arg3);
- fprintf(stderr,"\n");
- exit(4);
- }
- #else
- #include "varargs.h"
-
- panic(str,va_alist)
- char *str;
- va_dcl
- {
- va_list iggy;
-
- va_start(iggy);
- fprintf(stderr,"%s: ",myname);
- #ifdef NO_VFPRINTF
- _doprnt(str,&iggy,stderr);
- #else
- vfprintf(stderr,str,iggy);
- #endif
- putc('\n',stderr);
- va_end(iggy);
- exit(4);
- }
-
- #endif
- #endif
-
- #define N_FILE 20
-
- struct id {
- FILE *fp;
- char *name;
- };
-
- static struct id __id_s[N_FILE];
-
- char *
- __fp_name(fp)
- FILE *fp;
- {
- int n;
-
- for(n=0;n<N_FILE;n++) {
- if(__id_s[n].fp==fp)
- return __id_s[n].name;
- }
- return "{Unknown file pointer}";
- }
-
- /* Panic on failing fopen */
- FILE *
- ck_fopen(name,mode)
- char *name;
- char *mode;
- {
- FILE *ret;
- int n;
-
- ret=fopen(name,mode);
- if(ret==(FILE *)0)
- panic("Couldn't open file %s\n",name);
- for(n=0;n<N_FILE;n++) {
- if(ret==__id_s[n].fp) {
- free((VOID *)__id_s[n].name);
- __id_s[n].name=(char *)ck_malloc(strlen(name)+1);
- strcpy(__id_s[n].name,name);
- break;
- }
- }
- if(n==N_FILE) {
- for(n=0;n<N_FILE;n++)
- if(__id_s[n].fp==(FILE *)0)
- break;
- if(n==N_FILE)
- panic("Internal error: too many files open\n");
- __id_s[n].fp=ret;
- __id_s[n].name=(char *)ck_malloc(strlen(name)+1);
- strcpy(__id_s[n].name,name);
- }
- return ret;
- }
-
- void
- ck_fwrite(ptr,size,nmemb,stream)
- char *ptr;
- int size,nmemb;
- FILE *stream;
- {
- if(fwrite(ptr,size,nmemb,stream)!=nmemb)
- panic("couldn't write %d items to %s",nmemb,__fp_name(stream));
- }
-
- void
- ck_fclose(stream)
- FILE *stream;
- {
- if(fclose(stream)==EOF)
- panic("Couldn't close %s\n",__fp_name(stream));
- }
-
- VOID *
- ck_malloc(size)
- int size;
- {
- VOID *ret;
- VOID *malloc();
-
- ret=malloc(size);
- if(ret==(VOID *)0)
- panic("Couldn't allocate memory\n");
- return ret;
- }
-
- VOID *
- ck_realloc(ptr,size)
- VOID *ptr;
- int size;
- {
- VOID *ret;
- VOID *realloc();
-
- ret=realloc(ptr,size);
- if(ret==(VOID *)0)
- panic("Couldn't re-allocate memory\n");
- return ret;
- }
-
- char *
- strdup(str)
- char *str;
- {
- char *ret;
-
- ret=(char *)ck_malloc(strlen(str)+2);
- strcpy(ret,str);
- return ret;
- }
-
-
- #ifndef AZTEC_C
- /*
- * memmove - copy bytes, being careful about overlap.
- */
-
- VOID *
- memmove(dst, src, size)
- VOID *dst;
- VOID *src;
- int size;
- {
- register char *d;
- register char *s;
- register int n;
-
- if (size <= 0)
- return(dst);
-
- s = (char *)src;
- d = (char *)dst;
- if (s <= d && s + (size-1) >= d) {
- /* Overlap, must copy right-to-left. */
- s += size-1;
- d += size-1;
- for (n = size; n > 0; n--)
- *d-- = *s--;
- } else
- for (n = size; n > 0; n--)
- *d++ = *s++;
-
- return(dst);
- }
- #else
-
- VOID *
- memmove(dst,src,size)
- VOID *dst;
- VOID *src;
- int size;
- {
- return ( (VOID *) movmem(src,dst,size) );
- }
-
- VOID *memchr(mem,val,len)
- char *mem;
- int val,len;
- {
- register int index = 0;
-
- while ( index < len ) {
- if ( mem[index] == (char) val ) {
- return(&mem[index]);
- }
- ++index;
- }
-
- return(NULL);
- }
-
- #endif
-
- /* Implement a variable sized buffer of 'stuff'. We don't know what it is,
- nor do we care, as long as it doesn't mind being aligned on a char boundry.
- 'b' could be made non-global, with a little work, so we could have more
- than one buffer, but we don't need more than one, so why bother? */
-
-
- struct buffer {
- int allocated;
- int length;
- char *b;
- };
-
- #define MIN_ALLOCATE 50
-
- VOID *
- init_buffer()
- {
- struct buffer *b;
-
- b=(struct buffer *)ck_malloc(sizeof(struct buffer));
- b->allocated=MIN_ALLOCATE;
- b->b=(char *)ck_malloc(MIN_ALLOCATE);
- b->length=0;
- return (VOID *)b;
- }
-
- void
- flush_buffer(bb)
- VOID *bb;
- {
- struct buffer *b;
-
- b=(struct buffer *)bb;
- free(b->b);
- b->b=0;
- b->allocated=0;
- b->length=0;
- free(b);
- }
-
- int
- size_buffer(b)
- VOID *b;
- {
- struct buffer *bb;
-
- bb=(struct buffer *)b;
- return bb->length;
- }
-
- void
- add_buffer(bb,p,n)
- VOID *bb;
- char *p;
- int n;
- {
- struct buffer *b;
-
- b=(struct buffer *)bb;
- if(b->length+n>b->allocated) {
- b->allocated*=2;
- b->b=(char *)ck_realloc(b->b,b->allocated);
- }
- bcopy(p,b->b+b->length,n);
- b->length+=n;
- }
-
- void
- add1_buffer(bb,ch)
- VOID *bb;
- int ch;
- {
- struct buffer *b;
-
- b=(struct buffer *)bb;
- if(b->length+1>b->allocated) {
- b->allocated*=2;
- b->b=(char *)ck_realloc(b->b,b->allocated);
- }
- b->b[b->length]=ch;
- b->length++;
- }
-
- char *
- get_buffer(bb)
- VOID *bb;
- {
- struct buffer *b;
-
- b=(struct buffer *)bb;
- return b->b;
- }
-
- #endif
-