📄 sed.c
字号:
fout[0] = stdout; switch (cchar) { case '{': /* start command group */ cmdp->flags.allbut = !cmdp->flags.allbut; cmpstk[bdepth++] = &(cmdp->u.link); if (++cmdp >= cmds + MAXCMDS) ABORT(TMCDS); return(1); case '}': /* end command group */ if (cmdp->addr1) ABORT(AD1NG); /* no addresses allowed */ if (--bdepth < 0) ABORT(TMRBR); /* too many right braces */ *cmpstk[bdepth] = cmdp; /* set the jump address */ return(1); case '=': /* print current source line number */ case 'q': /* exit the stream editor */ if (cmdp->addr2) ABORT(AD2NG); break; case ':': /* label declaration */ if (cmdp->addr1) ABORT(AD1NG); /* no addresses allowed */ fp = gettext(lab->name = fp); /* get the label name */ if (lpt = search(lab)) {/* does it have a double? */ if (lpt->address) ABORT(DLABL); /* yes, abort */ } else { /* check that it doesn't overflow label table */ lab->last = NULL; lpt = lab; if (++lab >= labels + MAXLABS) ABORT(TMLAB); } lpt->address = cmdp; return(1); case 'b': /* branch command */ case 't': /* branch-on-succeed command */ case 'T': /* branch-on-fail command */ SKIPWS(cp); if (*cp == '\0') { /* if branch is to start of cmds... */ /* Add current command to end of label last */ if (sp1 = lablst->last) { while (sp2 = sp1->u.link) sp1 = sp2; sp1->u.link = cmdp; } else /* lablst->last == NULL */ lablst->last = cmdp; break; } fp = gettext(lab->name = fp); /* else get label into pool */ if (lpt = search(lab)) {/* enter branch to it */ if (lpt->address) cmdp->u.link = lpt->address; else { sp1 = lpt->last; while (sp2 = sp1->u.link) sp1 = sp2; sp1->u.link = cmdp; } } else { /* matching named label not found */ lab->last = cmdp; /* add the new label */ lab->address = NULL; /* it's forward of here */ if (++lab >= labels + MAXLABS) /* overflow if last */ ABORT(TMLAB); } break; case 'a': /* append text */ case 'i': /* insert text */ case 'r': /* read file into stream */ if (cmdp->addr2) ABORT(AD2NG); case 'c': /* change text */ if ((*cp == '\\') && (*++cp == '\n')) cp++; fp = gettext(cmdp->u.lhs = fp); break; case 'D': /* delete current line in hold space */ cmdp->u.link = cmds; break; case 's': /* substitute regular expression */ redelim = *cp++; /* get delimiter from 1st ch */ if ((fp = recomp(cmdp->u.lhs = fp, redelim)) == BAD) ABORT(CGMSG); if (fp == cmdp->u.lhs) /* if compiled RE zero len */ cmdp->u.lhs = lastre; /* use the previous one */ else /* otherwise */ lastre = cmdp->u.lhs; /* save the one just found */ if ((cmdp->rhs = fp) > poolend) ABORT(TMTXT); if ((fp = rhscomp(cmdp->rhs, redelim)) == BAD) ABORT(CGMSG); if (gflag) cmdp->flags.global ++; while (*cp == 'g' || *cp == 'p' || *cp == 'P') { IFEQ(cp, 'g') cmdp->flags.global ++; IFEQ(cp, 'p') cmdp->flags.print = 1; IFEQ(cp, 'P') cmdp->flags.print = 2; } case 'l': /* list pattern space */ if (*cp == 'w') cp++; /* and execute a w command! */ else break; /* s or l is done */ case 'w': /* write-pattern-space command */ case 'W': /* write-first-line command */ if (nwfiles >= WFILES) ABORT(TMWFI); fp = gettext(fname[nwfiles] = fp); /* filename will be in pool */ for (i = nwfiles - 1; i >= 0; i--) /* match it in table */ if ((fname[i] != NULL) && (strcmp(fname[nwfiles], fname[i]) == 0)) { cmdp->fout = fout[i]; return(0); } /* If didn't find one, open new out file */ if ((cmdp->fout = fopen(fname[nwfiles], "w")) == NULL) { fprintf(stderr, CCOFI, fname[nwfiles]); quit(2); } fout[nwfiles++] = cmdp->fout; break; case 'y': /* transliterate text */ fp = ycomp(cmdp->u.lhs = fp, *cp++); /* compile translit */ if (fp == BAD) ABORT(CGMSG); /* fail on bad form */ if (fp > poolend) ABORT(TMTXT); /* fail on overflow */ break; } return(0); /* succeeded in interpreting one command */}static char *rhscomp(rhsp, delim) /* uses bcount */ /* Generate replacement string for substitute command right hand side */register char *rhsp; /* place to compile expression to */register char delim; /* regular-expression end-mark to look for */{ register char *p = cp; /* strictly for speed */ for (;;) if ((*rhsp = *p++) == '\\') { /* copy; if it's a \, */ *rhsp = *p++; /* copy escaped char */ /* Check validity of pattern tag */ if (*rhsp > bcount + '0' && *rhsp <= '9') return(BAD); *rhsp++ |= 0x80;/* mark the good ones */ continue; } else if (*rhsp == delim) { /* found RE end, hooray... */ *rhsp++ = '\0'; /* cap the expression string */ cp = p; return(rhsp); /* pt at 1 past the RE */ } else if (*rhsp++ == '\0') /* last ch not RE end, help! */ return(BAD);}static char *recomp(expbuf, redelim) /* uses cp, bcount */ /* Compile a regular expression to internal form */char *expbuf; /* place to compile it to */char redelim; /* RE end-marker to look for */{ register char *ep = expbuf; /* current-compiled-char pointer */ register char *sp = cp; /* source-character ptr */ register int c; /* current-character pointer */ char negclass; /* all-but flag */ char *lastep; /* ptr to last expr compiled */ char *svclass; /* start of current char class */ char brnest[MAXTAGS]; /* bracket-nesting array */ char *brnestp; /* ptr to current bracket-nest */ int classct; /* class element count */ int tags; /* # of closed tags */ if (*cp == redelim) /* if first char is RE endmarker */ return(cp++, expbuf); /* leave existing RE unchanged */ lastep = NULL; /* there's no previous RE */ brnestp = brnest; /* initialize ptr to brnest array */ tags = bcount = 0; /* initialize counters */ if (*ep++ = (*sp == '^')) /* check for start-of-line syntax */ sp++; for (;;) { if (ep >= expbuf + RELIMIT) /* match is too large */ return(cp = sp, BAD); if ((c = *sp++) == redelim) { /* found the end of the RE */ cp = sp; if (brnestp != brnest) /* \(, \) unbalanced */ return(BAD); *ep++ = CEOF; /* write end-of-pattern mark */ return(ep); /* return ptr to compiled RE */ } if (c != '*') /* if we're a postfix op */ lastep = ep; /* get ready to match last */ switch (c) { case '\\': if ((c = *sp++) == '(') { /* start tagged section */ if (bcount >= MAXTAGS) return(cp = sp, BAD); *brnestp++ = bcount; /* update tag stack */ *ep++ = CBRA; /* enter tag-start */ *ep++ = bcount++; /* bump tag count */ continue; } else if (c == ')') { /* end tagged section */ if (brnestp <= brnest) /* extra \) */ return(cp = sp, BAD); *ep++ = CKET; /* enter end-of-tag */ *ep++ = *--brnestp; /* pop tag stack */ tags++; /* count closed tags */ continue; } else if (c >= '1' && c <= '9') { /* tag use */ if ((c -= '1') >= tags) /* too few */ return(BAD); *ep++ = CBACK; /* enter tag mark */ *ep++ = c; /* and the number */ continue; } else if (c == '\n') /* escaped newline no good */ return(cp = sp, BAD); else if (c == 'n') /* match a newline */ c = '\n'; else if (c == 't') /* match a tab */ c = '\t'; else if (c == 'r') /* match a return */ c = '\r'; goto defchar; case '\0': /* ignore nuls */ continue; case '\n': /* trailing pattern delimiter is missing */ return(cp = sp, BAD); case '.': /* match any char except newline */ *ep++ = CDOT; continue; case '*': /* 0..n repeats of previous pattern */ if (lastep == NULL) /* if * isn't first on line */ goto defchar; /* match a literal * */ if (*lastep == CKET) /* can't iterate a tag */ return(cp = sp, BAD); *lastep |= STAR;/* flag previous pattern */ continue; case '$': /* match only end-of-line */ if (*sp != redelim) /* if we're not at end of RE */ goto defchar; /* match a literal $ */ *ep++ = CDOL; /* insert end-symbol mark */ continue; case '[': /* begin character set pattern */ if (ep + 17 >= expbuf + RELIMIT) ABORT(REITL); *ep++ = CCL; /* insert class mark */ if (negclass = ((c = *sp++) == '^')) c = *sp++; svclass = sp; /* save ptr to class start */ do { if (c == '\0') ABORT(CGMSG); /* Handle character ranges */ if (c == '-' && sp > svclass && *sp != ']') for (c = sp[-2]; c < *sp; c++) ep[c >> 3] |= bits[c & 7]; /* Handle escape sequences in sets */ if (c == '\\') if ((c = *sp++) == 'n') c = '\n'; else if (c == 't') c = '\t'; else if (c == 'r') c = '\r'; /* Enter (possibly translated) char in set */ ep[c >> 3] |= bits[c & 7]; } while ((c = *sp++) != ']'); /* Invert the bitmask if all-but was specified */ if (negclass) for (classct = 0; classct < 16; classct++) ep[classct] ^= 0xFF; ep[0] &= 0xFE; /* never match ASCII 0 */ ep += 16; /* advance ep past set mask */ continue; defchar: /* match literal character */ default: /* which is what we'd do by default */ *ep++ = CCHR; /* insert character mark */ *ep++ = c; } }}static int cmdline(cbuf) /* uses eflag, eargc, cmdf */ /* Read next command from -e argument or command file */register char *cbuf;{ register int inc; /* not char because must hold EOF */ *cbuf-- = 0; /* so pre-increment points us at cbuf */ /* E command flag is on */ if (eflag) { register char *p; /* ptr to current -e argument */ static char *savep; /* saves previous value of p */ if (eflag > 0) { /* there are pending -e arguments */ eflag = -1; if (eargc-- <= 0) quit(2); /* if no arguments, barf */ /* Else transcribe next e argument into cbuf */ p = *++eargv; while (*++cbuf = *p++) if (*cbuf == '\\') { if ((*++cbuf = *p++) == '\0') return(savep = NULL, -1); else continue; } else if (*cbuf == '\n') { /* end of 1 cmd line */ *cbuf = '\0'; return(savep = p, 1); /* We'll be back for the rest... */ } /* Found end-of-string; can advance to next argument */ return(savep = NULL, 1); } if ((p = savep) == NULL) return(-1); while (*++cbuf = *p++) if (*cbuf == '\\') { if ((*++cbuf = *p++) == '0') return(savep = NULL, -1); else continue; } else if (*cbuf == '\n') { *cbuf = '\0'; return(savep = p, 1); } return(savep = NULL, 1); } /* If no -e flag read from command file descriptor */ while ((inc = getc(cmdf)) != EOF) /* get next char */ if ((*++cbuf = inc) == '\\') /* if it's escape */ *++cbuf = inc = getc(cmdf); /* get next char */ else if (*cbuf == '\n') /* end on newline */ return(*cbuf = '\0', 1); /* cap the string */ return(*++cbuf = '\0', -1); /* end-of-file, no more chars */}static char *address(expbuf) /* uses cp, linenum */ /* Expand an address at *cp... into expbuf, return ptr at following char */register char *expbuf;{ static int numl = 0; /* current ind in addr-number table */ register char *rcp; /* temp compile ptr for forwd look */ long lno; /* computed value of numeric address */ if (*cp == '$') { /* end-of-source address */ *expbuf++ = CEND; /* write symbolic end address */ *expbuf++ = CEOF; /* and the end-of-address mark (!) */ cp++; /* go to next source character */ return(expbuf); /* we're done */ } if (*cp == '/' || *cp == '\\') { /* start of regular-expression match */ if (*cp == '\\') cp++; return(recomp(expbuf, *cp++)); /* compile the RE */ } rcp = cp; lno = 0; /* now handle a numeric address */ while (*rcp >= '0' && *rcp <= '9') /* collect digits */ lno = lno * 10 + *rcp++ - '0'; /* compute their value */ if (rcp > cp) { /* if we caught a number... */ *expbuf++ = CLNUM; /* put a numeric-address marker */ *expbuf++ = numl; /* and the address table index */ linenum[numl++] = lno; /* and set the table entry */ if (numl >= MAXLINES) /* oh-oh, address table overflow */ ABORT(TMLNR); /* abort with error message */ *expbuf++ = CEOF; /* write the end-of-address marker */ cp = rcp; /* point compile past the address */ return(expbuf); /* we're done */ } return(NULL); /* no legal address was found */}static char *gettext(txp) /* uses global cp */ /* Accept multiline input from *cp..., discarding leading whitespace */register char *txp; /* where to put the text */{ register char *p = cp; /* this is for speed */ SKIPWS(p); /* discard whitespace */ do { if ((*txp = *p++) == '\\') /* handle escapes */ *txp = *p++; if (*txp == '\0') /* we're at end of input */ return(cp = --p, ++txp); else if (*txp == '\n') /* also SKIPWS after newline */ SKIPWS(p); } while (txp++); /* keep going till we find that nul */ return(txp);}static label *search(ptr) /* uses global lablst */ /* Find the label matching *ptr, return NULL if none */register label *ptr;{ register label *rp; for (rp = lablst; rp < ptr; rp++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -