📄 sed.c
字号:
if ((rp->name != NULL) && (strcmp(rp->name, ptr->name) == 0)) return(rp); return(NULL);}static void resolve(){ /* uses global lablst */ /* Write label links into the compiled-command space */ register label *lptr; register sedcmd *rptr, *trptr; /* Loop through the label table */ for (lptr = lablst; lptr < lab; lptr++) if (lptr->address == NULL) { /* barf if not defined */ fprintf(stderr, ULABL, lptr->name); quit(2); } else if (lptr->last) {/* if last is non-null */ rptr = lptr->last; /* chase it */ while (trptr = rptr->u.link) { /* resolve refs */ rptr->u.link = lptr->address; rptr = trptr; } rptr->u.link = lptr->address; }}static char *ycomp(ep, delim)/* Compile a y (transliterate) command */register char *ep; /* where to compile to */char delim; /* end delimiter to look for */{ register char *tp, *sp; register int c; /* Scan the 'from' section for invalid chars */ for (sp = tp = cp; *tp != delim; tp++) { if (*tp == '\\') tp++; if ((*tp == '\n') || (*tp == '\0')) return (BAD); } tp++; /* tp now points at first char of 'to' * section */ /* Now rescan the 'from' section */ while ((c = *sp++ & 0x7F) != delim) { if (c == '\\' && *sp == 'n') { sp++; c = '\n'; } if ((ep[c] = *tp++) == '\\' && *tp == 'n') { ep[c] = '\n'; tp++; } if ((ep[c] == delim) || (ep[c] == '\0')) return(BAD); } if (*tp != delim) /* 'to', 'from' parts have unequal lengths */ return(BAD); cp = ++tp; /* point compile ptr past translit */ for (c = 0; c < 128; c++) /* fill in self-map entries in table */ if (ep[c] == 0) ep[c] = c; return(ep + 0x80); /* return first free location past table end */}void quit(n)int n;{/* Flush buffers and exit. Now a historical relic. Rely on exit to flush * the buffers. */ exit(n);}/*+++++++++++++++*//* sedexec.c -- execute compiled form of stream editor commands The single entry point of this module is the function execute(). It may take a string argument (the name of a file to be used as text) or the argument NULL which tells it to filter standard input. It executes the compiled commands in cmds[] on each line in turn. The function command() does most of the work. Match() and advance() are used for matching text against precompiled regular expressions and dosub() does right-hand-side substitution. Getline() does text input; readout() and Memcmp() are output and string-comparison utilities.*//* #include <stdio.h> *//* #include <ctype.h> *//* #include "sed.h" *//***** shared variables imported from the main ******//* Main data areas */extern char linebuf[]; /* current-line buffer */extern sedcmd cmds[]; /* hold compiled commands */extern long linenum[]; /* numeric-addresses table *//* Miscellaneous shared variables */extern int nflag; /* -n option flag */extern int eargc; /* scratch copy of argument count */extern char **eargv; /* scratch copy of argument list */extern char bits[]; /* the bits table *//***** end of imported stuff *****/#define MAXHOLD MAXBUF /* size of the hold space */#define GENSIZ MAXBUF /* maximum genbuf size */#define TRUE 1#define FALSE 0static char LTLMSG[] = "sed: line too long\n";static char *spend; /* current end-of-line-buffer pointer */static long lnum = 0L; /* current source line number *//* Append buffer maintenance */static sedcmd *appends[MAXAPPENDS]; /* array of ptrs to a,i,c commands */static sedcmd **aptr = appends; /* ptr to current append *//* Genbuf and its pointers */static char genbuf[GENSIZ];static char *loc1;static char *loc2;static char *locs;/* Command-logic flags */static int lastline; /* do-line flag */static int jump; /* jump to cmd's link address if set */static int delete; /* delete command flag *//* Tagged-pattern tracking */static char *bracend[MAXTAGS]; /* tagged pattern start pointers */static char *brastart[MAXTAGS]; /* tagged pattern end pointers */static int anysub; /* true if any s on current line succeeded */void execute()/* Execute the compiled commands in cmds[] */{ register char *p1; /* dummy copy ptrs */ register sedcmd *ipc; /* ptr to current command */ char *execp; /* ptr to source */ initget(); /* Here's the main command-execution loop */ for (;;) { /* Get next line to filter */ if ((execp = getline(linebuf)) == BAD) return; spend = execp; anysub = FALSE; /* Loop through compiled commands, executing them */ for (ipc = cmds; ipc->command;) { if (!selected(ipc)) { ipc++; continue; } command(ipc); /* execute the command pointed at */ if (delete) /* if delete flag is set */ break; /* don't exec rest of compiled cmds */ if (jump) { /* if jump set, follow cmd's link */ jump = FALSE; if ((ipc = ipc->u.link) == 0) { ipc = cmds; break; } } else /* normal goto next command */ ipc++; } /* We've now done all modification commands on the line */ /* Here's where the transformed line is output */ if (!nflag && !delete) { for (p1 = linebuf; p1 < spend; p1++) putc(*p1, stdout); putc('\n', stdout); } /* If we've been set up for append, emit the text from it */ if (aptr > appends) readout(); delete = FALSE; /* clear delete flag; about to get next cmd */ }}static int selected(ipc)/* Is current command selected */sedcmd *ipc;{ register char *p1 = ipc->addr1; /* point p1 at first address */ register char *p2 = ipc->addr2; /* and p2 at second */ int c; int sel = TRUE; /* select by default */ if (!p1) /* No addresses: always selected */ ; else if (ipc->flags.inrange) { if (*p2 == CEND); else if (*p2 == CLNUM) { c = p2[1] & CMASK; if (lnum >= linenum[c]) { ipc->flags.inrange = FALSE; if (lnum > linenum[c]) sel = FALSE; } } else if (match(p2, 0)) ipc->flags.inrange = FALSE; } else if (*p1 == CEND) { if (!lastline) sel = FALSE; } else if (*p1 == CLNUM) { c = p1[1] & CMASK; if (lnum != linenum[c]) sel = FALSE; else if (p2) ipc->flags.inrange = TRUE; } else if (match(p1, 0)) { if (p2) ipc->flags.inrange = TRUE; } else sel = FALSE; return ipc->flags.allbut ? !sel : sel;}static int match(expbuf, gf) /* uses genbuf */ /* Match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */char *expbuf;int gf;{ register char *p1, *p2, c; if (gf) { if (*expbuf) return(FALSE); p1 = linebuf; p2 = genbuf; while (*p1++ = *p2++); locs = p1 = loc2; } else { p1 = linebuf; locs = FALSE; } p2 = expbuf; if (*p2++) { loc1 = p1; if (*p2 == CCHR && p2[1] != *p1) /* 1st char is wrong */ return(FALSE); /* so fail */ return(advance(p1, p2));/* else try to match rest */ } /* Quick check for 1st character if it's literal */ if (*p2 == CCHR) { c = p2[1]; /* pull out character to search for */ do { if (*p1 != c) continue; /* scan the source string */ if (advance(p1, p2)) /* found it, match the rest */ return(loc1 = p1, 1); } while (*p1++); return(FALSE); /* didn't find that first char */ } /* Else try for unanchored match of the pattern */ do { if (advance(p1, p2)) return(loc1 = p1, 1); } while (*p1++); /* If got here, didn't match either way */ return(FALSE);}static int advance(lp, ep)/* Attempt to advance match pointer by one pattern element */register char *lp; /* source (linebuf) ptr */register char *ep; /* regular expression element ptr */{ register char *curlp; /* save ptr for closures */ char c; /* scratch character holder */ char *bbeg; int ct; for (;;) switch (*ep++) { case CCHR: /* literal character */ if (*ep++ == *lp++) /* if chars are equal */ continue; /* matched */ return(FALSE); /* else return false */ case CDOT: /* anything but newline */ if (*lp++) /* first NUL is at EOL */ continue; /* keep going if didn't find */ return(FALSE); /* else return false */ case CNL: /* start-of-line */ case CDOL: /* end-of-line */ if (*lp == 0) /* found that first NUL? */ continue; /* yes, keep going */ return(FALSE); /* else return false */ case CEOF: /* end-of-address mark */ loc2 = lp; /* set second loc */ return(TRUE); /* return true */ case CCL: /* a closure */ c = *lp++ & 0177; if (ep[c >> 3] & bits[c & 07]) { /* is char in set? */ ep += 16; /* then skip rest of bitmask */ continue; /* and keep going */ } return(FALSE); /* else return false */ case CBRA: /* start of tagged pattern */ brastart[*ep++] = lp; /* mark it */ continue; /* and go */ case CKET: /* end of tagged pattern */ bracend[*ep++] = lp; /* mark it */ continue; /* and go */ case CBACK: bbeg = brastart[*ep]; ct = bracend[*ep++] - bbeg; if (Memcmp(bbeg, lp, ct)) { lp += ct; continue; } return(FALSE); case CBACK | STAR: bbeg = brastart[*ep]; ct = bracend[*ep++] - bbeg; curlp = lp; while (Memcmp(bbeg, lp, ct)) lp += ct; while (lp >= curlp) { if (advance(lp, ep)) return(TRUE); lp -= ct; } return(FALSE); case CDOT | STAR: /* match .* */ curlp = lp; /* save closure start loc */ while (*lp++); /* match anything */ goto star; /* now look for followers */ case CCHR | STAR: /* match <literal char>* */ curlp = lp; /* save closure start loc */ while (*lp++ == *ep); /* match many of that char */ ep++; /* to start of next element */ goto star; /* match it and followers */ case CCL | STAR: /* match [...]* */ curlp = lp; /* save closure start loc */ do { c = *lp++ & 0x7F; /* match any in set */ } while (ep[c >> 3] & bits[c & 07]); ep += 16; /* skip past the set */ goto star; /* match followers */ star: /* the recursion part of a * or + match */ if (--lp == curlp) /* 0 matches */ continue; if (*ep == CCHR) { c = ep[1]; do { if (*lp != c) continue; if (advance(lp, ep)) return (TRUE); } while (lp-- > curlp); return(FALSE); } if (*ep == CBACK) { c = *(brastart[ep[1]]); do { if (*lp != c) continue; if (advance(lp, ep)) return (TRUE); } while (lp-- > curlp); return(FALSE); } do { if (lp == locs) break; if (advance(lp, ep)) return (TRUE); } while (lp-- > curlp); return(FALSE); default: fprintf(stderr, "sed: RE error, %o\n", *--ep); quit(2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -