📄 ed.c
字号:
/* Copyright 1987 Brian Beattie Rights Reserved. * * Permission to copy and/or distribute granted under the * following conditions: * * 1). No charge may be made other than resonable charges * for reproduction. * * 2). This notice must remain intact. * * 3). No further restrictions may be added. * *//* This program used to be in many little pieces, with this makefile:.SUFFIXES: .c .sCFLAGS = -FOBJS = append.s catsub.s ckglob.s deflt.s del.s docmd.s doglob.s\ doprnt.s doread.s dowrite.s ed.s egets.s find.s getfn.s getlst.s\ getnum.s getone.s getptr.s getrhs.s gettxt.s ins.s join.s maksub.s\ move.s optpat.s set.s setbuf.s subst.s getpat.s matchs.s amatch.s\ unmkpat.s omatch.s makepat.s bitmap.s dodash.s esc.s System.sed: $(OBJS) cc -T. -i -o ed $(OBJS)*/#include <sys/types.h>#include <signal.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/wait.h>#include <stdio.h>/****************************//* tools.h *//* * #defines for non-printing ASCII characters */#define NUL 0x00 /* ^@ */#define EOS 0x00 /* end of string */#define SOH 0x01 /* ^A */#define STX 0x02 /* ^B */#define ETX 0x03 /* ^C */#define EOT 0x04 /* ^D */#define ENQ 0x05 /* ^E */#define ACK 0x06 /* ^F */#define BEL 0x07 /* ^G */#define BS 0x08 /* ^H */#define HT 0x09 /* ^I */#define LF 0x0a /* ^J */#define NL '\n'#define VT 0x0b /* ^K */#define FF 0x0c /* ^L */#define CR 0x0d /* ^M */#define SO 0x0e /* ^N */#define SI 0x0f /* ^O */#define DLE 0x10 /* ^P */#define DC1 0x11 /* ^Q */#define DC2 0x12 /* ^R */#define DC3 0x13 /* ^S */#define DC4 0x14 /* ^T */#define NAK 0x15 /* ^U */#define SYN 0x16 /* ^V */#define ETB 0x17 /* ^W */#define CAN 0x18 /* ^X */#define EM 0x19 /* ^Y */#define SUB 0x1a /* ^Z */#define ESC 0x1b /* ^[ */#define FS 0x1c /* ^\ */#define GS 0x1d /* ^] */#define RS 0x1e /* ^^ */#define US 0x1f /* ^_ */#define SP 0x20 /* space */#define DEL 0x7f /* DEL */#define TRUE 1#define FALSE 0#define ERR -2/* Definitions of meta-characters used in pattern matching * routines. LITCHAR & NCCL are only used as token identifiers; * all the others are also both token identifier and actual symbol * used in the regular expression. */#define BOL '^'#define EOL '$'#define ANY '.'#define LITCHAR 'L'#define ESCAPE '\\'#define CCL '[' /* Character class: [...] */#define CCLEND ']'#define NEGATE '~'#define NCCL '!' /* Negative character class [^...] */#define CLOSURE '*'#define OR_SYM '|'#define DITTO '&'#define OPEN '('#define CLOSE ')'/* Largest permitted size for an expanded character class. (i.e. the class * [a-z] will expand into 26 symbols; [a-z0-9] will expand into 36.) */#define CLS_SIZE 128/* * Tokens are used to hold pattern templates. (see makepat()) */typedef char BITMAP;typedef struct token { char tok; char lchar; BITMAP *bitmap; struct token *next;} TOKEN;#define TOKSIZE sizeof (TOKEN)/* * An absolute maximun for strings. */#define MAXSTR 132 /* Maximum numbers of characters in a line *//* Macros */#define max(a,b) ((a>b)?a:b)#define min(a,b) ((a<b)?a:b)#define toupper(c) (c>='a'&&c<='z'?c-32:c)/* ed.h */#define FATAL (ERR-1)struct line { int l_stat; /* empty, mark */ struct line *l_prev; struct line *l_next; char l_buff[1];};typedef struct line LINE;#define LINFREE 1 /* entry not in use */#define LGLOB 2 /* line marked global */ /* max number of chars per line */#define MAXLINE (sizeof(int) == 2 ? 256 : 8192)#define MAXPAT 256 /* max number of chars per replacement * pattern */ /* max file name size */#define MAXFNAME (sizeof(int) == 2 ? 256 : 1024)extern LINE line0;extern int curln, lastln, line1, line2, nlines;extern int nflg; /* print line number flag */extern int lflg; /* print line in verbose mode */extern char *inptr; /* tty input buffer */extern char linbuf[], *linptr; /* current line */extern int truncflg; /* truncate long line flag */extern int eightbit; /* save eighth bit */extern int nonascii; /* count of non-ascii chars read */extern int nullchar; /* count of null chars read */extern int truncated; /* count of lines truncated */extern int fchanged; /* file changed */#define nextln(l) ((l)+1 > lastln ? 0 : (l)+1)#define prevln(l) ((l)-1 < 0 ? lastln : (l)-1)/* amatch.c *//* #include <stdio.h> *//* #include "tools.h" */_PROTOTYPE(int main, (int argc, char **argv));_PROTOTYPE(static char *match, (char *lin, TOKEN *pat, char *boln));_PROTOTYPE(char *amatch, (char *lin, TOKEN *pat, char *boln));_PROTOTYPE(int append, (int line, int glob));_PROTOTYPE(BITMAP *makebitmap, (unsigned size));_PROTOTYPE(int setbit, (unsigned c, char *map, unsigned val));_PROTOTYPE(int testbit, (unsigned c, char *map));_PROTOTYPE(char *catsub, (char *from, char *to, char *sub, char *new, char *newend));_PROTOTYPE(int ckglob, (void));_PROTOTYPE(int deflt, (int def1, int def2));_PROTOTYPE(int del, (int from, int to));_PROTOTYPE(int docmd, (int glob));_PROTOTYPE(int dolst, (int line1, int line2));_PROTOTYPE(char *dodash, (int delim, char *src, char *map));_PROTOTYPE(int doglob, (void));_PROTOTYPE(int doprnt, (int from, int to));_PROTOTYPE(void prntln, (char *str, int vflg, int lin));_PROTOTYPE(void putcntl, (int c, FILE *stream));_PROTOTYPE(int doread, (int lin, char *fname));_PROTOTYPE(int dowrite, (int from, int to, char *fname, int apflg));_PROTOTYPE(void intr, (int sig));_PROTOTYPE(int egets, (char *str, int size, FILE *stream));_PROTOTYPE(int esc, (char **s));_PROTOTYPE(int find, (TOKEN *pat, int dir));_PROTOTYPE(char *getfn, (void));_PROTOTYPE(int getlst, (void));_PROTOTYPE(int getnum, (int first));_PROTOTYPE(int getone, (void));_PROTOTYPE(TOKEN *getpat, (char *arg));_PROTOTYPE(LINE *getptr, (int num));_PROTOTYPE(int getrhs, (char *sub));_PROTOTYPE(char *gettxt, (int num));_PROTOTYPE(int ins, (char *str));_PROTOTYPE(int System, (char *c));_PROTOTYPE(int join, (int first, int last));_PROTOTYPE(TOKEN *makepat, (char *arg, int delim));_PROTOTYPE(char *maksub, (char *sub, int subsz));_PROTOTYPE(char *matchs, (char *line, TOKEN *pat, int ret_endp));_PROTOTYPE(int move, (int num));_PROTOTYPE(int transfer, (int num));_PROTOTYPE(int omatch, (char **linp, TOKEN *pat, char *boln));_PROTOTYPE(TOKEN *optpat, (void));_PROTOTYPE(int set, (void));_PROTOTYPE(int show, (void));_PROTOTYPE(void relink, (LINE *a, LINE *x, LINE *y, LINE *b));_PROTOTYPE(void clrbuf, (void));_PROTOTYPE(void set_buf, (void));_PROTOTYPE(int subst, (TOKEN *pat, char *sub, int gflg, int pflag));_PROTOTYPE(void unmakepat, (TOKEN *head));/* Scans throught the pattern template looking for a match * with lin. Each element of lin is compared with the template * until either a mis-match is found or the end of the template * is reached. In the former case a 0 is returned; in the latter, * a pointer into lin (pointing to the character following the * matched pattern) is returned. * * "lin" is a pointer to the line being searched. * "pat" is a pointer to a template made by makepat(). * "boln" is a pointer into "lin" which points at the * character at the beginning of the line. */char *paropen[9], *parclose[9];int between, parnum;char *amatch(lin, pat, boln)char *lin;TOKEN *pat;char *boln;{ between = 0; parnum = 0; lin = match(lin, pat, boln); if (between) return 0; while (parnum < 9) { paropen[parnum] = parclose[parnum] = ""; parnum++; } return lin;}static char *match(lin, pat, boln)char *lin;TOKEN *pat;char *boln;{ register char *bocl, *rval, *strstart; if (pat == 0) return 0; strstart = lin; while (pat) { if (pat->tok == CLOSURE && pat->next) { /* Process a closure: first skip over the closure * token to the object to be repeated. This object * can be a character class. */ pat = pat->next; /* Now match as many occurrences of the closure * pattern as possible. */ bocl = lin; while (*lin && omatch(&lin, pat, boln)); /* 'Lin' now points to the character that made made * us fail. Now go on to process the rest of the * string. A problem here is a character following * the closure which could have been in the closure. * For example, in the pattern "[a-z]*t" (which * matches any lower-case word ending in a t), the * final 't' will be sucked up in the while loop. * So, if the match fails, we back up a notch and try * to match the rest of the string again, repeating * this process recursively until we get back to the * beginning of the closure. The recursion goes, at * most two levels deep. */ if (pat = pat->next) { int savbtwn = between; int savprnm = parnum; while (bocl <= lin) { if (rval = match(lin, pat, boln)) { /* Success */ return(rval); } else { --lin; between = savbtwn; parnum = savprnm; } } return(0); /* match failed */ } } else if (pat->tok == OPEN) { if (between || parnum >= 9) return 0; paropen[parnum] = lin; between = 1; pat = pat->next; } else if (pat->tok == CLOSE) { if (!between) return 0; parclose[parnum++] = lin; between = 0; pat = pat->next; } else if (omatch(&lin, pat, boln)) { pat = pat->next; } else { return(0); } } /* Note that omatch() advances lin to point at the next character to * be matched. Consequently, when we reach the end of the template, * lin will be pointing at the character following the last character * matched. The exceptions are templates containing only a BOLN or * EOLN token. In these cases omatch doesn't advance. * * A philosophical point should be mentioned here. Is $ a position or a * character? (i.e. does $ mean the EOL character itself or does it * mean the character at the end of the line.) I decided here to * make it mean the former, in order to make the behavior of match() * consistent. If you give match the pattern ^$ (match all lines * consisting only of an end of line) then, since something has to be * returned, a pointer to the end of line character itself is * returned. */ return((char *) max(strstart, lin));}/* append.c *//* #include <stdio.h> *//* #include "tools.h" *//* #include "ed.h" */int append(line, glob)int line, glob;{ int stat; char lin[MAXLINE]; if (glob) return(ERR); curln = line; while (1) { if (nflg) printf("%6d. ", curln + 1); if (fgets(lin, MAXLINE, stdin) == NULL) return(EOF); if (lin[0] == '.' && lin[1] == '\n') return (0); stat = ins(lin); if (stat < 0) return(ERR); }}/* bitmap.c *//* * BITMAP.C - makebitmap, setbit, testbit * bit-map manipulation routines. * * Copyright (c) Allen I. Holub, all rights reserved. This program may * for copied for personal, non-profit use only. * */#ifdef DEBUG/* #include <stdio.h> */#endif/* #include "tools.h" */BITMAP *makebitmap(size)unsigned size;{ /* Make a bit map with "size" bits. The first entry in the map is an * "unsigned int" representing the maximum bit. The map itself is * concatenated to this integer. Return a pointer to a map on * success, 0 if there's not enough memory. */ unsigned *map, numbytes; numbytes = (size >> 3) + ((size & 0x07) ? 1 : 0);#ifdef DEBUG printf("Making a %d bit map (%d bytes required)\n", size, numbytes);#endif if (map = (unsigned *) malloc(numbytes + sizeof(unsigned))) *map = size; return((BITMAP *) map);}int setbit(c, map, val)unsigned c, val;char *map;{ /* Set bit c in the map to val. If c > map-size, 0 is returned, else * 1 is returned. */ if (c >= *(unsigned *) map) /* if c >= map size */ return 0; map += sizeof(unsigned); /* skip past size */ if (val) map[c >> 3] |= 1 << (c & 0x07); else map[c >> 3] &= ~(1 << (c & 0x07)); return 1;}int testbit(c, map)unsigned c;char *map;{ /* Return 1 if the bit corresponding to c in map is set. 0 if it is not. */ if (c >= *(unsigned *) map) return 0; map += sizeof(unsigned); return(map[c >> 3] & (1 << (c & 0x07)));}/* catsub.c *//* #include <stdio.h> *//* #include "tools.h" *//* #include "ed.h" */extern char *paropen[9], *parclose[9];char *catsub(from, to, sub, new, newend)char *from, *to, *sub, *new, *newend;{ char *cp, *cp2; for (cp = new; *sub != EOS && cp < newend;) { if (*sub == DITTO) for (cp2 = from; cp2 < to;) { *cp++ = *cp2++; if (cp >= newend) break; } else if (*sub == ESCAPE) { sub++; if ('1' <= *sub && *sub <= '9') { char *parcl = parclose[*sub - '1']; for (cp2 = paropen[*sub - '1']; cp2 < parcl;) { *cp++ = *cp2++; if (cp >= newend) break; } } else *cp++ = *sub; } else *cp++ = *sub; sub++; } return(cp);}/* ckglob.c *//* #include <stdio.h> *//* #include "tools.h" *//* #include "ed.h" */int ckglob(){ TOKEN *glbpat; char c, delim; char lin[MAXLINE]; int num; LINE *ptr; c = *inptr; if (c != 'g' && c != 'v') return(0); if (deflt(1, lastln) < 0) return(ERR); delim = *++inptr; if (delim <= ' ') return(ERR); glbpat = optpat(); if (*inptr == delim) inptr++; ptr = getptr(1); for (num = 1; num <= lastln; num++) { ptr->l_stat &= ~LGLOB; if (line1 <= num && num <= line2) { strcpy(lin, ptr->l_buff); strcat(lin, "\n"); if (matchs(lin, glbpat, 0)) { if (c == 'g') ptr->l_stat |= LGLOB; } else { if (c == 'v') ptr->l_stat |= LGLOB; } } ptr = ptr->l_next; } return(1);}/* deflt.c *//* #include <stdio.h> *//* #include "tools.h" *//* #include "ed.h" */int deflt(def1, def2)int def1, def2;{ if (nlines == 0) { line1 = def1; line2 = def2; } if (line1 > line2 || line1 <= 0) return(ERR); return(0);}/* del.c *//* #include <stdio.h> *//* #include "tools.h" *//* #include "ed.h" */int del(from, to)int from, to;{ LINE *first, *last, *next, *tmp; if (from < 1) from = 1; first = getptr(prevln(from)); last = getptr(nextln(to)); next = first->l_next; while (next != last && next != &line0) { tmp = next->l_next; free((char *) next); next = tmp; } relink(first, last, first, last); lastln -= (to - from) + 1; curln = prevln(from); return(0);}/* docmd.c *//* #include <stdio.h> *//* #include "tools.h" *//* #include "ed.h" */char fname[MAXFNAME];int fchanged;extern int nofname;extern int mark[];int docmd(glob)int glob;{ static char rhs[MAXPAT]; TOKEN *subpat; int c, err, line3; int apflg, pflag, gflag; int nchng; char *fptr; pflag = FALSE; while (*inptr == SP && *inptr == HT) inptr++; c = *inptr++; switch (c) { case NL: if (nlines == 0) { if ((line2 = nextln(curln)) == 0) return(ERR); } curln = line2; return(1); break; case '=': printf("%d\n", line2); break; case 'a': if (*inptr != NL || nlines > 1) return(ERR); if (append(line1, glob) < 0) return(ERR);; fchanged = TRUE; break; case 'c': if (*inptr != NL) return(ERR); if (deflt(curln, curln) < 0) return(ERR); if (del(line1, line2) < 0) return(ERR); if (append(curln, glob) < 0) return (ERR); fchanged = TRUE; break; case 'd': if (*inptr != NL) return(ERR); if (deflt(curln, curln) < 0) return(ERR); if (del(line1, line2) < 0) return(ERR); if (nextln(curln) != 0) curln = nextln(curln); fchanged = TRUE; break; case 'e': if (nlines > 0) return(ERR); if (fchanged) { fchanged = FALSE; return(ERR); } /* FALL THROUGH */ case 'E': if (nlines > 0) return(ERR); if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR); if ((fptr = getfn()) == NULL) return(ERR); clrbuf(); if ((err = doread(0, fptr)) < 0) return(err); strcpy(fname, fptr); fchanged = FALSE; break; case 'f': if (nlines > 0) return(ERR); if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR); if ((fptr = getfn()) == NULL) return(ERR); if (nofname) printf("%s\n", fname); else strcpy(fname, fptr); break; case 'i': if (*inptr != NL || nlines > 1) return(ERR); if (append(prevln(line1), glob) < 0) return(ERR); fchanged = TRUE; break; case 'j': if (*inptr != NL || deflt(curln, curln + 1) < 0) return(ERR); if (join(line1, line2) < 0) return(ERR); break; case 'k': while (*inptr == ' ' || *inptr == HT) inptr++; if (*inptr < 'a' || *inptr > 'z') return ERR; c = *inptr++; if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR); mark[c - 'a'] = line1; break; case 'l': if (*inptr != NL) return(ERR); if (deflt(curln, curln) < 0) return (ERR); if (dolst(line1, line2) < 0) return (ERR); break; case 'm': if ((line3 = getone()) < 0) return(ERR); if (deflt(curln, curln) < 0) return (ERR); if (move(line3) < 0) return (ERR); fchanged = TRUE; break; case 'P': case 'p': if (*inptr != NL) return(ERR); if (deflt(curln, curln) < 0) return (ERR); if (doprnt(line1, line2) < 0) return (ERR); break; case 'q': if (fchanged) { fchanged = FALSE; return(ERR); } /* FALL THROUGH */ case 'Q': if (*inptr == NL && nlines == 0 && !glob) return(EOF); else return(ERR); case 'r': if (nlines > 1) return(ERR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -