📄 sed.c
字号:
num=size_buffer(b);
string=(unsigned 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=(char *)string;
break;
case '{':
cur_cmd->cmd=ch;
program_depth++;
#if 0
while((ch=inchar())!=EOF && ch!='\n')
if(!isblank(ch))
bad_prog(LINE_JUNK);
#endif
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' && ch!=';')
if(!isblank(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 && isblank(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;
slash=inchar();
compile_regex(slash);
cur_cmd->x.cmd_regex.regx=last_regex;
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=(unsigned char *)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=(unsigned char *)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 || ((ch=inchar())!=EOF && ch!='\n' && ch!=';'))
bad_prog(LINE_JUNK);
break;
default:
bad_prog("Unknown command");
}
}
return vector;
}
/* Complain about a programming error and exit. */
void
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);
}
/* Read the next character from the program. Return EOF if there isn't
anything to read. Keep prog_line up to date, so error messages can
be meaningful. */
int
inchar()
{
int ch;
if(prog_file) {
if(feof(prog_file))
return EOF;
else
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;
}
/* unget 'ch' so the next call to inchar will return it. 'ch' must not be
EOF or anything nasty like that. */
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;
}
/* Try to read an address for a sed command. If it succeeeds,
return non-zero and store the resulting address in *'addr'.
If the input doesn't look like an address read nothing
and return zero. */
int
compile_address(addr)
struct addr *addr;
{
int ch;
int num;
ch=inchar();
if(isdigit(ch)) {
num=ch-'0';
while((ch=inchar())!=EOF && isdigit(ch))
num=num*10+ch-'0';
while(ch!=EOF && isblank(ch))
ch=inchar();
savchar(ch);
addr->addr_type=ADDR_NUM;
addr->addr_number = num;
return 1;
} else if(ch=='/') {
addr->addr_type=ADDR_REGEX;
compile_regex('/');
addr->addr_regex=last_regex;
do ch=inchar();
while(ch!=EOF && isblank(ch));
savchar(ch);
return 1;
} else if(ch=='$') {
addr->addr_type=ADDR_LAST;
do ch=inchar();
while(ch!=EOF && isblank(ch));
savchar(ch);
return 1;
} else
savchar(ch);
return 0;
}
void
compile_regex (slash)
int slash;
{
VOID *b;
int ch;
int in_char_class = 0;
b=init_buffer();
while((ch=inchar())!=EOF && (ch!=slash || in_char_class)) {
if(ch=='^') {
if(size_buffer(b)==0) {
add1_buffer(b,'\\');
add1_buffer(b,'`');
} else
add1_buffer(b,ch);
continue;
} else if(ch=='$') {
ch=inchar();
savchar(ch);
if(ch==slash) {
add1_buffer(b,'\\');
add1_buffer(b,'\'');
} else
add1_buffer(b,'$');
continue;
} else if(ch == '[') {
add1_buffer(b,ch);
in_char_class = 1;
continue;
} else if(ch == ']') {
add1_buffer(b,ch);
in_char_class = 0;
continue;
} else if(ch!='\\') {
add1_buffer(b,ch);
continue;
}
ch=inchar();
switch(ch) {
case 'n':
add1_buffer(b,'\n');
break;
#if 0
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;
#endif /* 0 */
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)+10;
last_regex->buffer=ck_malloc(last_regex->allocated);
last_regex->fastmap=ck_malloc(256);
last_regex->translate=0;
re_compile_pattern(get_buffer(b),size_buffer(b),last_regex);
} else if(!last_regex)
bad_prog(NO_REGEX);
flush_buffer(b);
}
/* Store a label (or label reference) created by a ':', 'b', or 't'
comand so that the jump to/from the lable can be backpatched after
compilation is complete */
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 && isblank(ch))
;
while(ch!=EOF && ch!='\n') {
add1_buffer(b,ch);
ch=inchar();
}
savchar(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=ck_strdup(get_buffer(b));
tmp->next=list;
flush_buffer(b);
return tmp;
}
/* read in a filename for a 'r', 'w', or 's///w' command, and
update the internal structure about files. The file is
opened if it isn't already open. */
FILE *
compile_filename(readit)
int readit;
{
char *file_name;
int n;
VOID *b;
int ch;
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);
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=ck_strdup(file_name);
file_ptrs[n].readit=readit;
if (!readit)
file_ptrs[n].phile=ck_fopen(file_name,"a");
else if (access(file_name, 4) == 0)
file_ptrs[n].phile=ck_fopen(file_name,"r");
else if (access(file_name, 4) == 0)
file_ptrs[n].phile=ck_fopen(file_name,"r");
else
file_ptrs[n].phile=ck_fopen("/dev/null", "r");
flush_buffer(b);
return file_ptrs[n].phile;
} else {
bad_prog("Hopelessely evil compiled in limit on number of open files. re-compile sed");
return 0;
}
}
/* Parse a filename given by a 'r' 'w' or 's///w' command. */
void
read_file(name)
char *name;
{
if(*name=='-' && name[1]=='\0')
input_file=stdin;
else {
input_file=fopen(name,"r");
if(input_file==0) {
extern int errno;
extern char *sys_errlist[];
extern int sys_nerr;
char *ptr;
ptr=(errno>=0 && errno<sys_nerr) ? sys_errlist[errno] : "Unknown error code";
bad_input++;
fprintf(stderr,"%s: can't read %s: %s\n",myname,name,ptr);
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 the program 'vec' on the current input line. */
void
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;
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':
while(append.alloc-append.length<cur_cmd->x.cmd_txt.text_len) {
append.alloc *= 2;
append.text=ck_realloc(append.text,append.alloc);
}
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':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -