📄 sed.c
字号:
c = '\n'; /* fake an end-of-line */ prog.curr = 0; } } else c = -1; } else if ((c = Bgetrune(prog.bp)) < 0) Bterm(prog.bp); return c;}voidaddress(Addr *ap){ int c; long lno; if((c = *cp++) == '$') ap->type = A_DOL; else if(c == '/') { seof = c; if (ap->rp = compile()) ap->type = A_RE; else ap->type = A_LAST; } else if (c >= '0' && c <= '9') { lno = c-'0'; while ((c = *cp) >= '0' && c <= '9') lno = lno*10 + *cp++-'0'; if(!lno) quit("line number 0 is illegal",0); ap->type = A_LINE; ap->line = lno; } else { cp--; ap->type = A_NONE; }}cmp(char *a, char *b) /* compare characters */{ while(*a == *b++) if (*a == '\0') return(0); else a++; return(1);}rcmp(Rune *a, Rune *b) /* compare runes */{ while(*a == *b++) if (*a == '\0') return(0); else a++; return(1);}char *text(char *p) /* extract character string */{ Rune r; while(*cp == '\t' || *cp == ' ') cp++; while (*cp) { if ((r = *cp++) == '\\') if ((r = *cp++) == 0) break;; if (r == '\n') while (*cp == '\t' || *cp == ' ') cp++; p += runetochar(p, &r); } *p++ = '\0'; return p;}Rune *stext(Rune *p, Rune *end) /* extract rune string */{ while(*cp == '\t' || *cp == ' ') cp++; while (*cp) { if (*cp == '\\') if (*++cp == 0) break; if (p >= end-1) quit(TMMES, (char *) linebuf); if ((*p++ = *cp++) == '\n') while(*cp == '\t' || *cp == ' ') cp++; } *p++ = 0; return p;}Label *search (Label *ptr){ Label *rp; for (rp = ltab; rp < ptr; rp++) if(rcmp(rp->asc, ptr->asc) == 0) return(rp); return(0);}voiddechain(void){ Label *lptr; SedCom *rptr, *trptr; for(lptr = ltab; lptr < lab; lptr++) { if(lptr->address == 0) quit("Undefined label: %S", (char *) lptr->asc); if(lptr->chain) { rptr = lptr->chain; while(trptr = rptr->lb1) { rptr->lb1 = lptr->address; rptr = trptr; } rptr->lb1 = lptr->address; } }}intycomp(SedCom *r){ int i; Rune *rp; Rune c, *tsp, highc; Rune *sp; highc = 0; for(tsp = cp; *tsp != seof; tsp++) { if(*tsp == '\\') tsp++; if(*tsp == '\n' || *tsp == '\0') return(0); if (*tsp > highc) highc = *tsp; } tsp++; if ((rp = r->text = (Rune *) malloc(sizeof(Rune)*(highc+2))) == 0) quit("Out of memory", 0); *rp++ = highc; /* save upper bound */ for (i = 0; i <= highc; i++) rp[i] = i; sp = cp; while((c = *sp++) != seof) { if(c == '\\' && *sp == 'n') { sp++; c = '\n'; } if((rp[c] = *tsp++) == '\\' && *tsp == 'n') { rp[c] = '\n'; tsp++; } if(rp[c] == seof || rp[c] == '\0') { free(r->re1); r->re1 = 0; return(0); } } if(*tsp != seof) { free(r->re1); r->re1 = 0; return(0); } cp = tsp+1; return(1);}voidexecute(void){ SedCom *ipc; while (spend = gline(linebuf)){ for(ipc = pspace; ipc->command; ) { if (!executable(ipc)) { ipc++; continue; } command(ipc); if(delflag) break; if(jflag) { jflag = 0; if((ipc = ipc->lb1) == 0) break; } else ipc++; } if(!nflag && !delflag) putline(&fout, linebuf, spend-linebuf); if(aptr > abuf) { arout(); } delflag = 0; }} /* determine if a statement should be applied to an input line */intexecutable(SedCom *ipc){ if (ipc->active) { /* Addr1 satisfied - accept until Addr2 */ if (ipc->active == 1) /* Second line */ ipc->active = 2; switch(ipc->ad2.type) { case A_NONE: /* No second addr; use first */ ipc->active = 0; break; case A_DOL: /* Accept everything */ return !ipc->negfl; case A_LINE: /* Line at end of range? */ if (lnum <= ipc->ad2.line) { if (ipc->ad2.line == lnum) ipc->active = 0; return !ipc->negfl; } ipc->active = 0; /* out of range */ return ipc->negfl; case A_RE: /* Check for matching R.E. */ if (match(ipc->ad2.rp, linebuf)) ipc->active = 0; return !ipc->negfl; default: /* internal error */ quit("Internal error", 0); } } switch (ipc->ad1.type) { /* Check first address */ case A_NONE: /* Everything matches */ return !ipc->negfl; case A_DOL: /* Only last line */ if (dolflag) return !ipc->negfl; break; case A_LINE: /* Check line number */ if (ipc->ad1.line == lnum) { ipc->active = 1; /* In range */ return !ipc->negfl; } break; case A_RE: /* Check R.E. */ if (match(ipc->ad1.rp, linebuf)) { ipc->active = 1; /* In range */ return !ipc->negfl; } break; default: quit("Internal error", 0); } return ipc->negfl;}match(Reprog *pattern, Rune *buf){ if (!pattern) return 0; subexp[0].rsp = buf; subexp[0].ep = 0; if (rregexec(pattern, linebuf, subexp, MAXSUB)) { loc1 = subexp[0].rsp; loc2 = subexp[0].rep; return 1; } loc1 = loc2 = 0; return 0;}substitute(SedCom *ipc){ int len; if(!match(ipc->re1, linebuf)) return 0; /* * we have at least one match. some patterns, e.g. '$' or '^', can * produce zero-length matches, so during a global substitute we * must bump to the character after a zero-length match to keep from looping. */ sflag = 1; if(ipc->gfl == 0) /* single substitution */ dosub(ipc->rhs); else do{ /* global substitution */ len = loc2-loc1; /* length of match */ dosub(ipc->rhs); /* dosub moves loc2 */ if(*loc2 == 0) /* end of string */ break; if(len == 0) /* zero-length R.E. match */ loc2++; /* bump over zero-length match */ if(*loc2 == 0) /* end of string */ break; } while(match(ipc->re1, loc2)); return 1;}voiddosub(Rune *rhsbuf){ Rune *lp, *sp; Rune *rp; int c, n; lp = linebuf; sp = genbuf; rp = rhsbuf; while (lp < loc1) *sp++ = *lp++; while(c = *rp++) { if (c == '&') { sp = place(sp, loc1, loc2); continue; } if (c == 0xFFFF && (c = *rp++) >= '1' && c < MAXSUB+'0') { n = c-'0'; if (subexp[n].rsp && subexp[n].rep) { sp = place(sp, subexp[n].rsp, subexp[n].rep); continue; } else { fprint(2, "sed: Invalid back reference \\%d\n",n); errexit(); } } *sp++ = c; if (sp >= &genbuf[LBSIZE]) fprint(2, "sed: Output line too long.\n"); } lp = loc2; loc2 = sp - genbuf + linebuf; while (*sp++ = *lp++) if (sp >= &genbuf[LBSIZE]) fprint(2, "sed: Output line too long.\n"); lp = linebuf; sp = genbuf; while (*lp++ = *sp++) ; spend = lp-1;}Rune *place(Rune *sp, Rune *l1, Rune *l2){ while (l1 < l2) { *sp++ = *l1++; if (sp >= &genbuf[LBSIZE]) fprint(2, "sed: Output line too long.\n"); } return(sp);}char *trans(int c){ static char buf[] = "\\x0000"; static char hex[] = "0123456789abcdef"; switch(c) { case '\b': return "\\b"; case '\n': return "\\n"; case '\r': return "\\r"; case '\t': return "\\t"; case '\\': return "\\\\"; } buf[2] = hex[(c>>12)&0xF]; buf[3] = hex[(c>>8)&0xF]; buf[4] = hex[(c>>4)&0xF]; buf[5] = hex[c&0xF]; return buf;}voidcommand(SedCom *ipc){ int i, c; Rune *p1, *p2; char *ucp; Rune *rp; Rune *execp; switch(ipc->command) { case ACOM: *aptr++ = ipc; if(aptr >= abuf+MAXADDS) { quit("sed: Too many appends after line %ld\n", (char *) lnum); } *aptr = 0; break; case CCOM: delflag = 1; if(ipc->active == 1) { for(rp = ipc->text; *rp; rp++) Bputrune(&fout, *rp); Bputc(&fout, '\n'); } break; case DCOM: delflag++; break; case CDCOM: p1 = p2 = linebuf; while(*p1 != '\n') { if(*p1++ == 0) { delflag++; return; } } p1++; while(*p2++ = *p1++) ; spend = p2-1; jflag++; break; case EQCOM: Bprint(&fout, "%ld\n", lnum); break; case GCOM: p1 = linebuf; p2 = holdsp; while(*p1++ = *p2++) ; spend = p1-1; break; case CGCOM: *spend++ = '\n'; p1 = spend; p2 = holdsp; while(*p1++ = *p2++) if(p1 >= lbend) break; spend = p1-1; break; case HCOM: p1 = holdsp; p2 = linebuf; while(*p1++ = *p2++); hspend = p1-1; break; case CHCOM: *hspend++ = '\n'; p1 = hspend; p2 = linebuf; while(*p1++ = *p2++) if(p1 >= hend) break; hspend = p1-1; break; case ICOM: for(rp = ipc->text; *rp; rp++) Bputrune(&fout, *rp); Bputc(&fout, '\n'); break; case BCOM: jflag = 1; break; case LCOM: c = 0; for (i = 0, rp = linebuf; *rp; rp++) { c = *rp; if(c >= 0x20 && c < 0x7F && c != '\\') { Bputc(&fout, c); if(i++ > 71) { Bprint(&fout, "\\\n"); i = 0; } } else { for (ucp = trans(*rp); *ucp; ucp++){ c = *ucp; Bputc(&fout, c); if(i++ > 71) { Bprint(&fout, "\\\n"); i = 0; } } } } if(c == ' ') Bprint(&fout, "\\n"); Bputc(&fout, '\n'); break; case NCOM: if(!nflag) putline(&fout, linebuf, spend-linebuf); if(aptr > abuf) arout(); if((execp = gline(linebuf)) == 0) { delflag = 1; break; } spend = execp; break; case CNCOM: if(aptr > abuf) arout(); *spend++ = '\n'; if((execp = gline(spend)) == 0) { delflag = 1; break; } spend = execp; break; case PCOM: putline(&fout, linebuf, spend-linebuf); break; case CPCOM: cpcom: for(rp = linebuf; *rp && *rp != '\n'; rp++) Bputc(&fout, *rp); Bputc(&fout, '\n'); break; case QCOM: if(!nflag) putline(&fout, linebuf, spend-linebuf); if(aptr > abuf) arout(); exits(0); case RCOM: *aptr++ = ipc; if(aptr >= &abuf[MAXADDS]) quit("sed: Too many reads after line %ld\n", (char *) lnum); *aptr = 0; break; case SCOM: i = substitute(ipc); if(i && ipc->pfl) if(ipc->pfl == 1) putline(&fout, linebuf, spend-linebuf); else goto cpcom; if(i && ipc->fcode) goto wcom; break; case TCOM: if(sflag == 0) break; sflag = 0; jflag = 1; break; wcom: case WCOM: putline(ipc->fcode,linebuf, spend-linebuf); break; case XCOM: p1 = linebuf; p2 = genbuf; while(*p2++ = *p1++); p1 = holdsp; p2 = linebuf; while(*p2++ = *p1++); spend = p2 - 1; p1 = genbuf; p2 = holdsp; while(*p2++ = *p1++); hspend = p2 - 1; break; case YCOM: p1 = linebuf; p2 = ipc->text; for (i = *p2++; *p1; p1++){ if (*p1 <= i) *p1 = p2[*p1]; } break; }}voidputline(Biobuf *bp, Rune *buf, int n){ while (n--) Bputrune(bp, *buf++); Bputc(bp, '\n');}ecmp(Rune *a, Rune *b, int count){ while(count--) if(*a++ != *b++) return(0); return(1);}voidarout(void){ Rune *p1; Biobuf *fi; int c; char *s; char buf[128]; for (aptr = abuf; *aptr; aptr++) { if((*aptr)->command == ACOM) { for(p1 = (*aptr)->text; *p1; p1++ ) Bputrune(&fout, *p1); Bputc(&fout, '\n'); } else { for(s = buf, p1= (*aptr)->text; *p1; p1++) s += runetochar(s, p1); *s = '\0'; if((fi = Bopen(buf, OREAD)) == 0) continue; while((c = Bgetc(fi)) >= 0) Bputc(&fout, c); Bterm(fi); } } aptr = abuf; *aptr = 0;}voiderrexit(void){ exits("error");}voidquit (char *msg, char *arg){ fprint(2, "sed: "); fprint(2, msg, arg); fprint(2, "\n"); errexit();}Rune *gline(Rune *addr){ long c; Rune *p; static long peekc = 0; if (f == 0 && opendata() < 0) return 0; sflag = 0; lnum++;/* Bflush(&fout);********* dumped 4/30/92 - bobf****/ do { p = addr; for (c = (peekc ? peekc : Bgetrune(f)); c >= 0; c = Bgetrune(f)) { if (c == '\n') { if ((peekc = Bgetrune(f)) < 0) { if (fhead == 0) dolflag = 1; } *p = '\0'; return p; } if (c && p < lbend) *p++ = c; } /* return partial final line, adding implicit newline */ if(p != addr) { *p = '\0'; peekc = -1; if (fhead == 0) dolflag = 1; return p; } peekc = 0; Bterm(f); } while (opendata() > 0); /* Switch to next stream */ f = 0; return 0;} /* Data file input section - the intent is to transparently * catenate all data input streams. */voidenroll(char *filename) /* Add a file to the input file cache */{ FileCache *fp; if ((fp = (FileCache *) malloc(sizeof (FileCache))) == 0) quit("Out of memory", 0); if (ftail == 0) fhead = fp; else ftail->next = fp; ftail = fp; fp->next = 0; fp->name = filename; /* 0 => stdin */}intopendata(void){ if (fhead == 0) return -1; if (fhead->name) { if ((f = Bopen(fhead->name, OREAD)) == 0) quit("Can't open %s", fhead->name); } else { Binit(&stdin, 0, OREAD); f = &stdin; } fhead = fhead->next; return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -