pci: don't do sanity check for missing pci bus, the check can misfire.
[minix.git] / commands / simple / ed.c
blobcd58e614e6d5c63855b8c34a88bf8bb1141606e5
1 /* Copyright 1987 Brian Beattie Rights Reserved.
3 * Permission to copy and/or distribute granted under the
4 * following conditions:
6 * 1). No charge may be made other than resonable charges
7 * for reproduction.
9 * 2). This notice must remain intact.
11 * 3). No further restrictions may be added.
15 /* This program used to be in many little pieces, with this makefile:
16 .SUFFIXES: .c .s
18 CFLAGS = -F
20 OBJS = append.s catsub.s ckglob.s deflt.s del.s docmd.s doglob.s\
21 doprnt.s doread.s dowrite.s ed.s egets.s find.s getfn.s getlst.s\
22 getnum.s getone.s getptr.s getrhs.s gettxt.s ins.s join.s maksub.s\
23 move.s optpat.s set.s setbuf.s subst.s getpat.s matchs.s amatch.s\
24 unmkpat.s omatch.s makepat.s bitmap.s dodash.s esc.s System.s
26 ed: $(OBJS)
27 cc -T. -i -o ed $(OBJS)
30 #include <sys/types.h>
31 #include <signal.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <sys/wait.h>
36 #include <stdio.h>
38 /****************************/
40 /* tools.h */
42 * #defines for non-printing ASCII characters
45 #define NUL 0x00 /* ^@ */
46 #define EOS 0x00 /* end of string */
47 #define SOH 0x01 /* ^A */
48 #define STX 0x02 /* ^B */
49 #define ETX 0x03 /* ^C */
50 #define EOT 0x04 /* ^D */
51 #define ENQ 0x05 /* ^E */
52 #define ACK 0x06 /* ^F */
53 #define BEL 0x07 /* ^G */
54 #define BS 0x08 /* ^H */
55 #define HT 0x09 /* ^I */
56 #define LF 0x0a /* ^J */
57 #define NL '\n'
58 #define VT 0x0b /* ^K */
59 #define FF 0x0c /* ^L */
60 #define CR 0x0d /* ^M */
61 #define SO 0x0e /* ^N */
62 #define SI 0x0f /* ^O */
63 #define DLE 0x10 /* ^P */
64 #define DC1 0x11 /* ^Q */
65 #define DC2 0x12 /* ^R */
66 #define DC3 0x13 /* ^S */
67 #define DC4 0x14 /* ^T */
68 #define NAK 0x15 /* ^U */
69 #define SYN 0x16 /* ^V */
70 #define ETB 0x17 /* ^W */
71 #define CAN 0x18 /* ^X */
72 #define EM 0x19 /* ^Y */
73 #define SUB 0x1a /* ^Z */
74 #define ESC 0x1b /* ^[ */
75 #define FS 0x1c /* ^\ */
76 #define GS 0x1d /* ^] */
77 #define RS 0x1e /* ^^ */
78 #define US 0x1f /* ^_ */
79 #define SP 0x20 /* space */
80 #define DEL 0x7f /* DEL */
83 #define TRUE 1
84 #define FALSE 0
85 #define ERR -2
88 /* Definitions of meta-characters used in pattern matching
89 * routines. LITCHAR & NCCL are only used as token identifiers;
90 * all the others are also both token identifier and actual symbol
91 * used in the regular expression.
95 #define BOL '^'
96 #define EOL '$'
97 #define ANY '.'
98 #define LITCHAR 'L'
99 #define ESCAPE '\\'
100 #define CCL '[' /* Character class: [...] */
101 #define CCLEND ']'
102 #define NEGATE '^'
103 #define NCCL '!' /* Negative character class [^...] */
104 #define CLOSURE '*'
105 #define OR_SYM '|'
106 #define DITTO '&'
107 #define OPEN '('
108 #define CLOSE ')'
110 /* Largest permitted size for an expanded character class. (i.e. the class
111 * [a-z] will expand into 26 symbols; [a-z0-9] will expand into 36.)
113 #define CLS_SIZE 128
116 * Tokens are used to hold pattern templates. (see makepat())
118 typedef char BITMAP;
120 typedef struct token {
121 char tok;
122 char lchar;
123 BITMAP *bitmap;
124 struct token *next;
125 } TOKEN;
127 #define TOKSIZE sizeof (TOKEN)
130 * An absolute maximun for strings.
133 #define MAXSTR 132 /* Maximum numbers of characters in a line */
136 /* Macros */
137 #define max(a,b) ((a>b)?a:b)
138 #define min(a,b) ((a<b)?a:b)
139 #define toupper(c) (c>='a'&&c<='z'?c-32:c)
141 /* ed.h */
142 #define FATAL (ERR-1)
143 struct line {
144 int l_stat; /* empty, mark */
145 struct line *l_prev;
146 struct line *l_next;
147 char l_buff[1];
150 typedef struct line LINE;
152 #define LINFREE 1 /* entry not in use */
153 #define LGLOB 2 /* line marked global */
155 /* max number of chars per line */
156 #define MAXLINE (sizeof(int) == 2 ? 256 : 8192)
157 #define MAXPAT 256 /* max number of chars per replacement
158 * pattern */
159 /* max file name size */
160 #define MAXFNAME (sizeof(int) == 2 ? 256 : 1024)
162 extern LINE line0;
163 extern int curln, lastln, line1, line2, nlines;
164 extern int nflg; /* print line number flag */
165 extern int lflg; /* print line in verbose mode */
166 extern char *inptr; /* tty input buffer */
167 extern char linbuf[], *linptr; /* current line */
168 extern int truncflg; /* truncate long line flag */
169 extern int eightbit; /* save eighth bit */
170 extern int nonascii; /* count of non-ascii chars read */
171 extern int nullchar; /* count of null chars read */
172 extern int truncated; /* count of lines truncated */
173 extern int fchanged; /* file changed */
175 #define nextln(l) ((l)+1 > lastln ? 0 : (l)+1)
176 #define prevln(l) ((l)-1 < 0 ? lastln : (l)-1)
178 /* amatch.c */
179 /* #include <stdio.h> */
180 /* #include "tools.h" */
182 _PROTOTYPE(int main, (int argc, char **argv));
183 _PROTOTYPE(static char *match, (char *lin, TOKEN *pat, char *boln));
184 _PROTOTYPE(char *amatch, (char *lin, TOKEN *pat, char *boln));
185 _PROTOTYPE(int append, (int line, int glob));
186 _PROTOTYPE(BITMAP *makebitmap, (unsigned size));
187 _PROTOTYPE(int setbit, (unsigned c, char *map, unsigned val));
188 _PROTOTYPE(int testbit, (unsigned c, char *map));
189 _PROTOTYPE(char *catsub, (char *from, char *to, char *sub, char *new, char *newend));
190 _PROTOTYPE(int ckglob, (void));
191 _PROTOTYPE(int deflt, (int def1, int def2));
192 _PROTOTYPE(int del, (int from, int to));
193 _PROTOTYPE(int docmd, (int glob));
194 _PROTOTYPE(int dolst, (int line1, int line2));
195 _PROTOTYPE(char *dodash, (int delim, char *src, char *map));
196 _PROTOTYPE(int doglob, (void));
197 _PROTOTYPE(int doprnt, (int from, int to));
198 _PROTOTYPE(void prntln, (char *str, int vflg, int lin));
199 _PROTOTYPE(void putcntl, (int c, FILE *stream));
200 _PROTOTYPE(int doread, (int lin, char *fname));
201 _PROTOTYPE(int dowrite, (int from, int to, char *fname, int apflg));
202 _PROTOTYPE(void intr, (int sig));
203 _PROTOTYPE(int egets, (char *str, int size, FILE *stream));
204 _PROTOTYPE(int esc, (char **s));
205 _PROTOTYPE(int find, (TOKEN *pat, int dir));
206 _PROTOTYPE(char *getfn, (void));
207 _PROTOTYPE(int getlst, (void));
208 _PROTOTYPE(int getnum, (int first));
209 _PROTOTYPE(int getone, (void));
210 _PROTOTYPE(TOKEN *getpat, (char *arg));
211 _PROTOTYPE(LINE *getptr, (int num));
212 _PROTOTYPE(int getrhs, (char *sub));
213 _PROTOTYPE(char *gettxt, (int num));
214 _PROTOTYPE(int ins, (char *str));
215 _PROTOTYPE(int System, (char *c));
216 _PROTOTYPE(int join, (int first, int last));
217 _PROTOTYPE(TOKEN *makepat, (char *arg, int delim));
218 _PROTOTYPE(char *maksub, (char *sub, int subsz));
219 _PROTOTYPE(char *matchs, (char *line, TOKEN *pat, int ret_endp));
220 _PROTOTYPE(int move, (int num));
221 _PROTOTYPE(int transfer, (int num));
222 _PROTOTYPE(int omatch, (char **linp, TOKEN *pat, char *boln));
223 _PROTOTYPE(TOKEN *optpat, (void));
224 _PROTOTYPE(int set, (void));
225 _PROTOTYPE(int show, (void));
226 _PROTOTYPE(void relink, (LINE *a, LINE *x, LINE *y, LINE *b));
227 _PROTOTYPE(void clrbuf, (void));
228 _PROTOTYPE(void set_buf, (void));
229 _PROTOTYPE(int subst, (TOKEN *pat, char *sub, int gflg, int pflag));
230 _PROTOTYPE(void unmakepat, (TOKEN *head));
232 /* Scans throught the pattern template looking for a match
233 * with lin. Each element of lin is compared with the template
234 * until either a mis-match is found or the end of the template
235 * is reached. In the former case a 0 is returned; in the latter,
236 * a pointer into lin (pointing to the character following the
237 * matched pattern) is returned.
239 * "lin" is a pointer to the line being searched.
240 * "pat" is a pointer to a template made by makepat().
241 * "boln" is a pointer into "lin" which points at the
242 * character at the beginning of the line.
245 char *paropen[9], *parclose[9];
246 int between, parnum;
248 char *amatch(lin, pat, boln)
249 char *lin;
250 TOKEN *pat;
251 char *boln;
253 between = 0;
254 parnum = 0;
256 lin = match(lin, pat, boln);
258 if (between) return 0;
260 while (parnum < 9) {
261 paropen[parnum] = parclose[parnum] = "";
262 parnum++;
264 return lin;
267 static char *match(lin, pat, boln)
268 char *lin;
269 TOKEN *pat;
270 char *boln;
272 register char *bocl, *rval, *strstart;
274 if (pat == 0) return 0;
276 strstart = lin;
278 while (pat) {
279 if (pat->tok == CLOSURE && pat->next) {
280 /* Process a closure: first skip over the closure
281 * token to the object to be repeated. This object
282 * can be a character class. */
284 pat = pat->next;
286 /* Now match as many occurrences of the closure
287 * pattern as possible. */
288 bocl = lin;
290 while (*lin && omatch(&lin, pat, boln));
292 /* 'Lin' now points to the character that made made
293 * us fail. Now go on to process the rest of the
294 * string. A problem here is a character following
295 * the closure which could have been in the closure.
296 * For example, in the pattern "[a-z]*t" (which
297 * matches any lower-case word ending in a t), the
298 * final 't' will be sucked up in the while loop.
299 * So, if the match fails, we back up a notch and try
300 * to match the rest of the string again, repeating
301 * this process recursively until we get back to the
302 * beginning of the closure. The recursion goes, at
303 * most two levels deep. */
305 if (pat = pat->next) {
306 int savbtwn = between;
307 int savprnm = parnum;
309 while (bocl <= lin) {
310 if (rval = match(lin, pat, boln)) {
311 /* Success */
312 return(rval);
313 } else {
314 --lin;
315 between = savbtwn;
316 parnum = savprnm;
319 return(0); /* match failed */
321 } else if (pat->tok == OPEN) {
322 if (between || parnum >= 9) return 0;
323 paropen[parnum] = lin;
324 between = 1;
325 pat = pat->next;
326 } else if (pat->tok == CLOSE) {
327 if (!between) return 0;
328 parclose[parnum++] = lin;
329 between = 0;
330 pat = pat->next;
331 } else if (omatch(&lin, pat, boln)) {
332 pat = pat->next;
333 } else {
334 return(0);
338 /* Note that omatch() advances lin to point at the next character to
339 * be matched. Consequently, when we reach the end of the template,
340 * lin will be pointing at the character following the last character
341 * matched. The exceptions are templates containing only a BOLN or
342 * EOLN token. In these cases omatch doesn't advance.
344 * A philosophical point should be mentioned here. Is $ a position or a
345 * character? (i.e. does $ mean the EOL character itself or does it
346 * mean the character at the end of the line.) I decided here to
347 * make it mean the former, in order to make the behavior of match()
348 * consistent. If you give match the pattern ^$ (match all lines
349 * consisting only of an end of line) then, since something has to be
350 * returned, a pointer to the end of line character itself is
351 * returned. */
353 return((char *) max(strstart, lin));
356 /* append.c */
357 /* #include <stdio.h> */
358 /* #include "tools.h" */
359 /* #include "ed.h" */
361 int append(line, glob)
362 int line, glob;
364 int stat;
365 char lin[MAXLINE];
367 if (glob) return(ERR);
368 curln = line;
369 while (1) {
370 if (nflg) printf("%6d. ", curln + 1);
372 if (fgets(lin, MAXLINE, stdin) == NULL) return(EOF);
373 if (lin[0] == '.' && lin[1] == '\n') return (0);
374 stat = ins(lin);
375 if (stat < 0) return(ERR);
380 /* bitmap.c */
382 * BITMAP.C - makebitmap, setbit, testbit
383 * bit-map manipulation routines.
385 * Copyright (c) Allen I. Holub, all rights reserved. This program may
386 * for copied for personal, non-profit use only.
390 #ifdef DEBUG
391 /* #include <stdio.h> */
392 #endif
394 /* #include "tools.h" */
397 BITMAP *makebitmap(size)
398 unsigned size;
400 /* Make a bit map with "size" bits. The first entry in the map is an
401 * "unsigned int" representing the maximum bit. The map itself is
402 * concatenated to this integer. Return a pointer to a map on
403 * success, 0 if there's not enough memory. */
405 unsigned *map, numbytes;
407 numbytes = (size >> 3) + ((size & 0x07) ? 1 : 0);
409 #ifdef DEBUG
410 printf("Making a %d bit map (%d bytes required)\n", size, numbytes);
411 #endif
413 if (map = (unsigned *) malloc(numbytes + sizeof(unsigned))) {
414 *map = size;
415 memset(map + 1, 0, numbytes);
418 return((BITMAP *) map);
421 int setbit(c, map, val)
422 unsigned c, val;
423 char *map;
425 /* Set bit c in the map to val. If c > map-size, 0 is returned, else
426 * 1 is returned. */
428 if (c >= *(unsigned *) map) /* if c >= map size */
429 return 0;
431 map += sizeof(unsigned); /* skip past size */
433 if (val)
434 map[c >> 3] |= 1 << (c & 0x07);
435 else
436 map[c >> 3] &= ~(1 << (c & 0x07));
438 return 1;
441 int testbit(c, map)
442 unsigned c;
443 char *map;
445 /* Return 1 if the bit corresponding to c in map is set. 0 if it is not. */
447 if (c >= *(unsigned *) map) return 0;
449 map += sizeof(unsigned);
451 return(map[c >> 3] & (1 << (c & 0x07)));
454 /* catsub.c */
455 /* #include <stdio.h> */
456 /* #include "tools.h" */
457 /* #include "ed.h" */
459 extern char *paropen[9], *parclose[9];
461 char *catsub(from, to, sub, new, newend)
462 char *from, *to, *sub, *new, *newend;
464 char *cp, *cp2;
466 for (cp = new; *sub != EOS && cp < newend;) {
467 if (*sub == DITTO) for (cp2 = from; cp2 < to;) {
468 *cp++ = *cp2++;
469 if (cp >= newend) break;
471 else if (*sub == ESCAPE) {
472 sub++;
473 if ('1' <= *sub && *sub <= '9') {
474 char *parcl = parclose[*sub - '1'];
476 for (cp2 = paropen[*sub - '1']; cp2 < parcl;) {
477 *cp++ = *cp2++;
478 if (cp >= newend) break;
480 } else
481 *cp++ = *sub;
482 } else
483 *cp++ = *sub;
485 sub++;
488 return(cp);
491 /* ckglob.c */
492 /* #include <stdio.h> */
493 /* #include "tools.h" */
494 /* #include "ed.h" */
496 int ckglob()
498 TOKEN *glbpat;
499 char c, delim;
500 char lin[MAXLINE];
501 int num;
502 LINE *ptr;
504 c = *inptr;
506 if (c != 'g' && c != 'v') return(0);
508 if (deflt(1, lastln) < 0) return(ERR);
510 delim = *++inptr;
511 if (delim <= ' ') return(ERR);
513 glbpat = optpat();
515 if (*inptr == delim) inptr++;
517 ptr = getptr(1);
518 for (num = 1; num <= lastln; num++) {
519 ptr->l_stat &= ~LGLOB;
520 if (line1 <= num && num <= line2) {
521 strcpy(lin, ptr->l_buff);
522 strcat(lin, "\n");
523 if (matchs(lin, glbpat, 0)) {
524 if (c == 'g') ptr->l_stat |= LGLOB;
525 } else {
526 if (c == 'v') ptr->l_stat |= LGLOB;
529 ptr = ptr->l_next;
531 return(1);
534 /* deflt.c */
535 /* #include <stdio.h> */
536 /* #include "tools.h" */
537 /* #include "ed.h" */
539 int deflt(def1, def2)
540 int def1, def2;
542 if (nlines == 0) {
543 line1 = def1;
544 line2 = def2;
546 if (line1 > line2 || line1 <= 0) return(ERR);
547 return(0);
550 /* del.c */
551 /* #include <stdio.h> */
552 /* #include "tools.h" */
553 /* #include "ed.h" */
555 int del(from, to)
556 int from, to;
558 LINE *first, *last, *next, *tmp;
560 if (from < 1) from = 1;
561 first = getptr(prevln(from));
562 last = getptr(nextln(to));
563 next = first->l_next;
564 while (next != last && next != &line0) {
565 tmp = next->l_next;
566 free((char *) next);
567 next = tmp;
569 relink(first, last, first, last);
570 lastln -= (to - from) + 1;
571 curln = prevln(from);
572 return(0);
575 /* docmd.c */
576 /* #include <stdio.h> */
577 /* #include "tools.h" */
578 /* #include "ed.h" */
580 char fname[MAXFNAME];
581 int fchanged;
582 extern int nofname;
584 extern int mark[];
586 int docmd(glob)
587 int glob;
589 static char rhs[MAXPAT];
590 TOKEN *subpat;
591 int c, err, line3;
592 int apflg, pflag, gflag;
593 int nchng;
594 char *fptr;
596 pflag = FALSE;
597 while (*inptr == SP && *inptr == HT) inptr++;
599 c = *inptr++;
601 switch (c) {
602 case NL:
603 if (nlines == 0) {
604 if ((line2 = nextln(curln)) == 0) return(ERR);
606 curln = line2;
607 return(1);
608 break;
610 case '=': printf("%d\n", line2); break;
612 case 'a':
613 if (*inptr != NL || nlines > 1) return(ERR);
615 if (append(line1, glob) < 0) return(ERR);;
616 fchanged = TRUE;
617 break;
619 case 'c':
620 if (*inptr != NL) return(ERR);
622 if (deflt(curln, curln) < 0) return(ERR);
624 if (del(line1, line2) < 0) return(ERR);
625 if (append(curln, glob) < 0) return (ERR);
626 fchanged = TRUE;
627 break;
629 case 'd':
630 if (*inptr != NL) return(ERR);
632 if (deflt(curln, curln) < 0) return(ERR);
634 if (del(line1, line2) < 0) return(ERR);
635 if (nextln(curln) != 0) curln = nextln(curln);
636 fchanged = TRUE;
637 break;
639 case 'e':
640 if (nlines > 0) return(ERR);
641 if (fchanged) {
642 fchanged = FALSE;
643 return(ERR);
646 /* FALL THROUGH */
647 case 'E':
648 if (nlines > 0) return(ERR);
650 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
652 if ((fptr = getfn()) == NULL) return(ERR);
654 clrbuf();
655 if ((err = doread(0, fptr)) < 0) return(err);
657 strcpy(fname, fptr);
658 fchanged = FALSE;
659 break;
661 case 'f':
662 if (nlines > 0) return(ERR);
664 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
666 if ((fptr = getfn()) == NULL) return(ERR);
668 if (nofname)
669 printf("%s\n", fname);
670 else
671 strcpy(fname, fptr);
672 break;
674 case 'i':
675 if (*inptr != NL || nlines > 1) return(ERR);
677 if (append(prevln(line1), glob) < 0) return(ERR);
678 fchanged = TRUE;
679 break;
681 case 'j':
682 if (*inptr != NL || deflt(curln, curln + 1) < 0) return(ERR);
684 if (join(line1, line2) < 0) return(ERR);
685 break;
687 case 'k':
688 while (*inptr == ' ' || *inptr == HT) inptr++;
690 if (*inptr < 'a' || *inptr > 'z') return ERR;
691 c = *inptr++;
693 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
695 mark[c - 'a'] = line1;
696 break;
698 case 'l':
699 if (*inptr != NL) return(ERR);
700 if (deflt(curln, curln) < 0) return (ERR);
701 if (dolst(line1, line2) < 0) return (ERR);
702 break;
704 case 'm':
705 if ((line3 = getone()) < 0) return(ERR);
706 if (deflt(curln, curln) < 0) return (ERR);
707 if (move(line3) < 0) return (ERR);
708 fchanged = TRUE;
709 break;
711 case 'P':
712 case 'p':
713 if (*inptr != NL) return(ERR);
714 if (deflt(curln, curln) < 0) return (ERR);
715 if (doprnt(line1, line2) < 0) return (ERR);
716 break;
718 case 'q':
719 if (fchanged) {
720 fchanged = FALSE;
721 return(ERR);
724 /* FALL THROUGH */
725 case 'Q':
726 if (*inptr == NL && nlines == 0 && !glob)
727 return(EOF);
728 else
729 return(ERR);
731 case 'r':
732 if (nlines > 1) return(ERR);
734 if (nlines == 0) line2 = lastln;
736 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
738 if ((fptr = getfn()) == NULL) return(ERR);
740 if ((err = doread(line2, fptr)) < 0) return(err);
741 fchanged = TRUE;
742 break;
744 case 's':
745 if (*inptr == 'e') return(set());
746 while (*inptr == SP || *inptr == HT) inptr++;
747 if ((subpat = optpat()) == NULL) return (ERR);
748 if ((gflag = getrhs(rhs)) < 0) return (ERR);
749 if (*inptr == 'p') pflag++;
750 if (deflt(curln, curln) < 0) return (ERR);
751 if ((nchng = subst(subpat, rhs, gflag, pflag)) < 0) return (ERR);
752 if (nchng) fchanged = TRUE;
753 break;
755 case 't':
756 if ((line3 = getone()) < 0) return(ERR);
757 if (deflt(curln, curln) < 0) return (ERR);
758 if (transfer(line3) < 0) return (ERR);
759 fchanged = TRUE;
760 break;
762 case 'W':
763 case 'w':
764 apflg = (c == 'W');
766 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
768 if ((fptr = getfn()) == NULL) return(ERR);
770 if (deflt(1, lastln) < 0) return(ERR);
771 if (dowrite(line1, line2, fptr, apflg) < 0) return (ERR);
772 fchanged = FALSE;
773 break;
775 case 'x':
776 if (*inptr == NL && nlines == 0 && !glob) {
777 if ((fptr = getfn()) == NULL) return(ERR);
778 if (dowrite(1, lastln, fptr, 0) >= 0) return (EOF);
780 return(ERR);
782 case 'z':
783 if (deflt(curln, curln) < 0) return(ERR);
785 switch (*inptr) {
786 case '-':
787 if (doprnt(line1 - 21, line1) < 0) return(ERR);
788 break;
790 case '.':
791 if (doprnt(line1 - 11, line1 + 10) < 0) return(ERR);
792 break;
794 case '+':
795 case '\n':
796 if (doprnt(line1, line1 + 21) < 0) return(ERR);
797 break;
799 break;
801 default: return(ERR);
803 return(0);
806 int dolst(line1, line2)
807 int line1, line2;
809 int oldlflg = lflg, p;
811 lflg = 1;
812 p = doprnt(line1, line2);
813 lflg = oldlflg;
815 return p;
818 /* dodash.c */
819 /* #include <stdio.h> */
820 /* #include "tools.h" */
822 /* Expand the set pointed to by *src into dest.
823 * Stop at delim. Return 0 on error or size of
824 * character class on success. Update *src to
825 * point at delim. A set can have one element
826 * {x} or several elements ( {abcdefghijklmnopqrstuvwxyz}
827 * and {a-z} are equivalent ). Note that the dash
828 * notation is expanded as sequential numbers.
829 * This means (since we are using the ASCII character
830 * set) that a-Z will contain the entire alphabet
831 * plus the symbols: [\]^_`. The maximum number of
832 * characters in a character class is defined by maxccl.
834 char *dodash(delim, src, map)
835 int delim;
836 char *src, *map;
839 register int first, last;
840 char *start;
842 start = src;
844 while (*src && *src != delim) {
845 if (*src != '-') setbit(esc(&src), map, 1);
847 else if (src == start || *(src + 1) == delim)
848 setbit('-', map, 1);
849 else {
850 src++;
852 if (*src < *(src - 2)) {
853 first = *src;
854 last = *(src - 2);
855 } else {
856 first = *(src - 2);
857 last = *src;
860 while (++first <= last) setbit(first, map, 1);
863 src++;
865 return(src);
868 /* doglob.c */
869 /* #include <stdio.h> */
870 /* #include "tools.h" */
871 /* #include "ed.h" */
873 int doglob()
875 int lin, stat;
876 char *cmd;
877 LINE *ptr;
879 cmd = inptr;
881 while (1) {
882 ptr = getptr(1);
883 for (lin = 1; lin <= lastln; lin++) {
884 if (ptr->l_stat & LGLOB) break;
885 ptr = ptr->l_next;
887 if (lin > lastln) break;
889 ptr->l_stat &= ~LGLOB;
890 curln = lin;
891 inptr = cmd;
892 if ((stat = getlst()) < 0) return(stat);
893 if ((stat = docmd(1)) < 0) return (stat);
895 return(curln);
898 /* doprnt.c */
899 /* #include <stdio.h> */
900 /* #include "tools.h" */
901 /* #include "ed.h" */
903 int doprnt(from, to)
904 int from, to;
906 int i;
907 LINE *lptr;
909 from = from < 1 ? 1 : from;
910 to = to > lastln ? lastln : to;
912 if (to != 0) {
913 lptr = getptr(from);
914 for (i = from; i <= to; i++) {
915 prntln(lptr->l_buff, lflg, (nflg ? i : 0));
916 lptr = lptr->l_next;
918 curln = to;
920 return(0);
923 void prntln(str, vflg, lin)
924 char *str;
925 int vflg, lin;
927 if (lin) printf("%7d ", lin);
928 while (*str && *str != NL) {
929 if (*str < ' ' || *str >= 0x7f) {
930 switch (*str) {
931 case '\t':
932 if (vflg)
933 putcntl(*str, stdout);
934 else
935 putc(*str, stdout);
936 break;
938 case DEL:
939 putc('^', stdout);
940 putc('?', stdout);
941 break;
943 default:
944 putcntl(*str, stdout);
945 break;
947 } else
948 putc(*str, stdout);
949 str++;
951 if (vflg) putc('$', stdout);
952 putc('\n', stdout);
955 void putcntl(c, stream)
956 char c;
957 FILE *stream;
959 putc('^', stream);
960 putc((c & 31) | '@', stream);
963 /* doread.c */
964 /* #include <stdio.h> */
965 /* #include "tools.h" */
966 /* #include "ed.h" */
968 extern int diag;
970 int doread(lin, fname)
971 int lin;
972 char *fname;
974 FILE *fp;
975 int err;
976 long bytes;
977 int lines;
978 static char str[MAXLINE];
980 err = 0;
981 nonascii = nullchar = truncated = 0;
983 if (diag) printf("\"%s\" ", fname);
984 if ((fp = fopen(fname, "r")) == NULL) {
985 printf("file open err\n");
986 return(ERR);
988 curln = lin;
989 for (lines = 0, bytes = 0; (err = egets(str, MAXLINE, fp)) > 0;) {
990 bytes += strlen(str);
991 if (ins(str) < 0) {
992 printf("file insert error\n");
993 err++;
994 break;
996 lines++;
998 fclose(fp);
999 if (err < 0) return(err);
1000 if (diag) {
1001 printf("%d lines %ld bytes", lines, bytes);
1002 if (nonascii) printf(" [%d non-ascii]", nonascii);
1003 if (nullchar) printf(" [%d nul]", nullchar);
1004 if (truncated) printf(" [%d lines truncated]", truncated);
1005 printf("\n");
1007 return(err);
1010 /* dowrite.c */
1011 /* #include <stdio.h> */
1012 /* #include "tools.h" */
1013 /* #include "ed.h" */
1015 int dowrite(from, to, fname, apflg)
1016 int from, to;
1017 char *fname;
1018 int apflg;
1020 FILE *fp;
1021 int lin, err;
1022 int lines;
1023 long bytes;
1024 char *str;
1025 LINE *lptr;
1027 err = 0;
1029 lines = bytes = 0;
1030 if (diag) printf("\"%s\" ", fname);
1031 if ((fp = fopen(fname, (apflg ? "a" : "w"))) == NULL) {
1032 printf("file open error\n");
1033 return(ERR);
1035 lptr = getptr(from);
1036 for (lin = from; lin <= to; lin++) {
1037 str = lptr->l_buff;
1038 lines++;
1039 bytes += strlen(str) + 1;
1040 if (fputs(str, fp) == EOF) {
1041 printf("file write error\n");
1042 err++;
1043 break;
1045 fputc('\n', fp);
1046 lptr = lptr->l_next;
1048 if (diag) printf("%d lines %ld bytes\n", lines, bytes);
1049 fclose(fp);
1050 return(err);
1053 /* ed.c */
1054 /* Copyright 1987 Brian Beattie Rights Reserved.
1056 * Permission to copy and/or distribute granted under the
1057 * following conditions:
1059 * 1). No charge may be made other than resonable charges
1060 * for reproduction.
1062 * 2). This notice must remain intact.
1064 * 3). No further restrictions may be added.
1067 /* #include <stdio.h> */
1068 /* #include <signal.h> */
1069 /* #include "tools.h" */
1070 /* #include "ed.h" */
1071 #include <setjmp.h>
1072 jmp_buf env;
1074 LINE line0;
1075 int curln = 0;
1076 int lastln = 0;
1077 char *inptr;
1078 static char inlin[MAXLINE];
1079 int nflg, lflg;
1080 int line1, line2, nlines;
1081 extern char fname[];
1082 int version = 1;
1083 int diag = 1;
1085 void intr(sig)
1086 int sig;
1088 printf("?\n");
1089 longjmp(env, 1);
1092 int main(argc, argv)
1093 int argc;
1094 char **argv;
1096 int stat, i, doflush;
1098 set_buf();
1099 doflush = isatty(1);
1101 if (argc > 1 && (strcmp(argv[1], "-") == 0 || strcmp(argv[1], "-s") == 0)) {
1102 diag = 0;
1103 argc--;
1104 argv++;
1106 if (argc > 1) {
1107 for (i = 1; i < argc; i++) {
1108 if (doread(0, argv[i]) == 0) {
1109 curln = 1;
1110 strcpy(fname, argv[i]);
1111 break;
1115 while (1) {
1116 setjmp(env);
1117 if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, intr);
1119 if (doflush) fflush(stdout);
1121 if (fgets(inlin, sizeof(inlin), stdin) == NULL) {
1122 break;
1124 for (;;) {
1125 inptr = strchr(inlin, EOS);
1126 if (inptr >= inlin+2 && inptr[-2] == '\\' && inptr[-1] == NL) {
1127 inptr[-1] = 'n';
1128 if (fgets(inptr, sizeof(inlin) - (inptr - inlin),
1129 stdin) == NULL) break;
1130 } else {
1131 break;
1134 if (*inlin == '!') {
1135 if ((inptr = strchr(inlin, NL)) != NULL) *inptr = EOS;
1136 System(inlin + 1);
1137 continue;
1139 inptr = inlin;
1140 if (getlst() >= 0)
1141 if ((stat = ckglob()) != 0) {
1142 if (stat >= 0 && (stat = doglob()) >= 0) {
1143 curln = stat;
1144 continue;
1146 } else {
1147 if ((stat = docmd(0)) >= 0) {
1148 if (stat == 1) doprnt(curln, curln);
1149 continue;
1152 if (stat == EOF) {
1153 exit(0);
1155 if (stat == FATAL) {
1156 fputs("FATAL ERROR\n", stderr);
1157 exit(1);
1159 printf("?\n");
1161 return(0);
1164 /* egets.c */
1165 /* #include <stdio.h> */
1166 /* #include "tools.h" */
1167 /* #include "ed.h" */
1169 int eightbit = 1; /* save eight bit */
1170 int nonascii, nullchar, truncated;
1171 int egets(str, size, stream)
1172 char *str;
1173 int size;
1174 FILE *stream;
1176 int c, count;
1177 char *cp;
1179 for (count = 0, cp = str; size > count;) {
1180 c = getc(stream);
1181 if (c == EOF) {
1182 *cp++ = '\n';
1183 *cp = EOS;
1184 if (count) {
1185 printf("[Incomplete last line]\n");
1187 return(count);
1189 if (c == NL) {
1190 *cp++ = c;
1191 *cp = EOS;
1192 return(++count);
1194 if (c > 127) {
1195 if (!eightbit) /* if not saving eighth bit */
1196 c = c & 127; /* strip eigth bit */
1197 nonascii++; /* count it */
1199 if (c) {
1200 *cp++ = c; /* not null, keep it */
1201 count++;
1202 } else
1203 nullchar++; /* count nulls */
1205 str[count - 1] = EOS;
1206 if (c != NL) {
1207 printf("truncating line\n");
1208 truncated++;
1209 while ((c = getc(stream)) != EOF)
1210 if (c == NL) break;
1212 return(count);
1215 /* esc.c */
1216 /* #include <stdio.h> */
1217 /* #include "tools.h" */
1219 /* Map escape sequences into their equivalent symbols. Returns the
1220 * correct ASCII character. If no escape prefix is present then s
1221 * is untouched and *s is returned, otherwise **s is advanced to point
1222 * at the escaped character and the translated character is returned.
1224 int esc(s)
1225 char **s;
1227 register int rval;
1230 if (**s != ESCAPE) {
1231 rval = **s;
1232 } else {
1233 (*s)++;
1235 switch (toupper(**s)) {
1236 case '\000': rval = ESCAPE; break;
1237 case 'S': rval = ' '; break;
1238 case 'N': rval = '\n'; break;
1239 case 'T': rval = '\t'; break;
1240 case 'B': rval = '\b'; break;
1241 case 'R': rval = '\r'; break;
1242 default: rval = **s; break;
1246 return(rval);
1249 /* find.c */
1250 /* #include <stdio.h> */
1251 /* #include "tools.h" */
1252 /* #include "ed.h" */
1254 int find(pat, dir)
1255 TOKEN *pat;
1256 int dir;
1258 int i, num;
1259 char lin[MAXLINE];
1260 LINE *ptr;
1262 num = curln;
1263 ptr = getptr(curln);
1264 num = (dir ? nextln(num) : prevln(num));
1265 ptr = (dir ? ptr->l_next : ptr->l_prev);
1266 for (i = 0; i < lastln; i++) {
1267 if (num == 0) {
1268 num = (dir ? nextln(num) : prevln(num));
1269 ptr = (dir ? ptr->l_next : ptr->l_prev);
1271 strcpy(lin, ptr->l_buff);
1272 strcat(lin, "\n");
1273 if (matchs(lin, pat, 0)) {
1274 return(num);
1276 num = (dir ? nextln(num) : prevln(num));
1277 ptr = (dir ? ptr->l_next : ptr->l_prev);
1279 return(ERR);
1282 /* getfn.c */
1283 /* #include <stdio.h> */
1284 /* #include "tools.h" */
1285 /* #include "ed.h" */
1287 extern char fname[MAXFNAME];
1288 int nofname;
1290 char *getfn()
1292 static char file[256];
1293 char *cp;
1295 if (*inptr == NL) {
1296 nofname = TRUE;
1297 strcpy(file, fname);
1298 } else {
1299 nofname = FALSE;
1300 while (*inptr == SP || *inptr == HT) inptr++;
1302 cp = file;
1303 while (*inptr && *inptr != NL && *inptr != SP && *inptr != HT) {
1304 *cp++ = *inptr++;
1306 *cp = '\0';
1308 if (strlen(file) == 0) {
1309 printf("bad file name\n");
1310 return(NULL);
1314 if (strlen(file) == 0) {
1315 printf("no file name\n");
1316 return(NULL);
1318 return(file);
1321 /* getlst.c */
1322 /* #include <stdio.h> */
1323 /* #include "tools.h" */
1324 /* #include "ed.h" */
1326 int getlst()
1328 int num;
1330 line2 = 0;
1331 for (nlines = 0; (num = getone()) >= 0;) {
1332 line1 = line2;
1333 line2 = num;
1334 nlines++;
1335 if (*inptr != ',' && *inptr != ';') break;
1336 if (*inptr == ';') curln = num;
1337 inptr++;
1339 nlines = min(nlines, 2);
1340 if (nlines == 0) line2 = curln;
1341 if (nlines <= 1) line1 = line2;
1343 if (num == ERR)
1344 return(num);
1345 else
1346 return(nlines);
1349 /* getnum.c */
1350 /* #include <stdio.h> */
1351 /* #include "tools.h" */
1352 /* #include "ed.h" */
1354 int mark['z' - 'a' + 1];
1356 int getnum(first)
1357 int first;
1359 TOKEN *srchpat;
1360 int num;
1361 char c;
1363 while (*inptr == SP || *inptr == HT) inptr++;
1365 if (*inptr >= '0' && *inptr <= '9') { /* line number */
1366 for (num = 0; *inptr >= '0' && *inptr <= '9';) {
1367 num = (num * 10) + *inptr - '0';
1368 inptr++;
1370 return num;
1372 switch (c = *inptr) {
1373 case '.':
1374 inptr++;
1375 return(curln);
1377 case '$':
1378 inptr++;
1379 return(lastln);
1381 case '/':
1382 case '?':
1383 srchpat = optpat();
1384 if (*inptr == c) inptr++;
1385 return(find(srchpat, c == '/' ? 1 : 0));
1387 case '-':
1388 case '+':
1389 return(first ? curln : 1);
1391 case '\'':
1392 inptr++;
1393 if (*inptr < 'a' || *inptr > 'z') return(EOF);
1395 return mark[*inptr++ - 'a'];
1397 default:
1398 return(first ? EOF : 1);/* unknown address */
1402 /* getone.c */
1403 /* #include <stdio.h> */
1404 /* #include "tools.h" */
1405 /* #include "ed.h" */
1407 #define FIRST 1
1408 #define NOTFIRST 0
1410 int getone()
1412 int c, i, num;
1414 if ((num = getnum(FIRST)) >= 0) {
1415 while (1) {
1416 while (*inptr == SP || *inptr == HT) inptr++;
1418 if (*inptr != '+' && *inptr != '-') break;
1419 c = *inptr++;
1421 if ((i = getnum(NOTFIRST)) < 0) return(i);
1423 if (c == '+') {
1424 num += i;
1425 } else {
1426 num -= i;
1430 return(num > lastln ? ERR : num);
1433 /* getpat.c */
1434 /* #include <stdio.h> */
1435 /* #include "tools.h" */
1437 /* Translate arg into a TOKEN string */
1438 TOKEN *
1439 getpat(arg)
1440 char *arg;
1443 return(makepat(arg, '\000'));
1446 /* getptr.c */
1447 /* #include <stdio.h> */
1448 /* #include "tools.h" */
1449 /* #include "ed.h" */
1451 LINE *
1452 getptr(num)
1453 int num;
1455 LINE *ptr;
1456 int j;
1458 if (2 * num > lastln && num <= lastln) { /* high line numbers */
1459 ptr = line0.l_prev;
1460 for (j = lastln; j > num; j--) ptr = ptr->l_prev;
1461 } else { /* low line numbers */
1462 ptr = &line0;
1463 for (j = 0; j < num; j++) ptr = ptr->l_next;
1465 return(ptr);
1468 /* getrhs.c */
1469 /* #include <stdio.h> */
1470 /* #include "tools.h" */
1471 /* #include "ed.h" */
1473 int getrhs(sub)
1474 char *sub;
1476 if (inptr[0] == NL || inptr[1] == NL) /* check for eol */
1477 return(ERR);
1479 if (maksub(sub, MAXPAT) == NULL) return(ERR);
1481 inptr++; /* skip over delimter */
1482 while (*inptr == SP || *inptr == HT) inptr++;
1483 if (*inptr == 'g') {
1484 inptr++;
1485 return(1);
1487 return(0);
1490 /* gettxt.c */
1491 /* #include <stdio.h> */
1492 /* #include "tools.h" */
1493 /* #include "ed.h" */
1495 char *
1496 gettxt(num)
1497 int num;
1499 LINE *lin;
1500 static char txtbuf[MAXLINE];
1502 lin = getptr(num);
1503 strcpy(txtbuf, lin->l_buff);
1504 strcat(txtbuf, "\n");
1505 return(txtbuf);
1508 /* ins.c */
1509 /* #include <stdio.h> */
1510 /* #include "tools.h" */
1511 /* #include "ed.h" */
1513 int ins(str)
1514 char *str;
1516 char buf[MAXLINE], *cp;
1517 LINE *new, *cur, *nxt;
1519 cp = buf;
1520 while (1) {
1521 if ((*cp = *str++) == NL) *cp = EOS;
1522 if (*cp) {
1523 cp++;
1524 continue;
1526 if ((new = (LINE *) malloc(sizeof(LINE) + strlen(buf))) == NULL)
1527 return(ERR); /* no memory */
1529 new->l_stat = 0;
1530 strcpy(new->l_buff, buf); /* build new line */
1531 cur = getptr(curln); /* get current line */
1532 nxt = cur->l_next; /* get next line */
1533 relink(cur, new, new, nxt); /* add to linked list */
1534 relink(new, nxt, cur, new);
1535 lastln++;
1536 curln++;
1538 if (*str == EOS) /* end of line ? */
1539 return(1);
1541 cp = buf;
1545 /* join.c */
1546 /* #include <stdio.h> */
1547 /* #include "tools.h" */
1548 /* #include "ed.h" */
1550 extern int fchanged;
1552 int join(first, last)
1553 int first, last;
1555 char buf[MAXLINE];
1556 char *cp = buf, *str;
1557 int num;
1559 if (first <= 0 || first > last || last > lastln) return(ERR);
1560 if (first == last) {
1561 curln = first;
1562 return 0;
1564 for (num = first; num <= last; num++) {
1565 str = gettxt(num);
1567 while (*str != NL && cp < buf + MAXLINE - 1) *cp++ = *str++;
1569 if (cp == buf + MAXLINE - 1) {
1570 printf("line too long\n");
1571 return(ERR);
1574 *cp++ = NL;
1575 *cp = EOS;
1576 del(first, last);
1577 curln = first - 1;
1578 ins(buf);
1579 fchanged = TRUE;
1580 return 0;
1583 /* makepat.c */
1584 /* #include <stdio.h> */
1585 /* #include "tools.h" */
1587 /* Make a pattern template from the strinng pointed to by arg. Stop
1588 * when delim or '\000' or '\n' is found in arg. Return a pointer to
1589 * the pattern template.
1591 * The pattern template used here are somewhat different than those
1592 * used in the "Software Tools" book; each token is a structure of
1593 * the form TOKEN (see tools.h). A token consists of an identifier,
1594 * a pointer to a string, a literal character and a pointer to another
1595 * token. This last is 0 if there is no subsequent token.
1597 * The one strangeness here is caused (again) by CLOSURE which has
1598 * to be put in front of the previous token. To make this insertion a
1599 * little easier, the 'next' field of the last to point at the chain
1600 * (the one pointed to by 'tail) is made to point at the previous node.
1601 * When we are finished, tail->next is set to 0.
1603 TOKEN *
1604 makepat(arg, delim)
1605 char *arg;
1606 int delim;
1608 TOKEN *head, *tail, *ntok;
1609 int error;
1611 /* Check for characters that aren't legal at the beginning of a template. */
1613 if (*arg == '\0' || *arg == delim || *arg == '\n' || *arg == CLOSURE)
1614 return(0);
1616 error = 0;
1617 tail = head = NULL;
1619 while (*arg && *arg != delim && *arg != '\n' && !error) {
1620 ntok = (TOKEN *) malloc(TOKSIZE);
1621 ntok->lchar = '\000';
1622 ntok->next = 0;
1624 switch (*arg) {
1625 case ANY: ntok->tok = ANY; break;
1627 case BOL:
1628 if (head == 0) /* then this is the first symbol */
1629 ntok->tok = BOL;
1630 else
1631 ntok->tok = LITCHAR;
1632 ntok->lchar = BOL;
1633 break;
1635 case EOL:
1636 if (*(arg + 1) == delim || *(arg + 1) == '\000' ||
1637 *(arg + 1) == '\n') {
1638 ntok->tok = EOL;
1639 } else {
1640 ntok->tok = LITCHAR;
1641 ntok->lchar = EOL;
1643 break;
1645 case CLOSURE:
1646 if (head != 0) {
1647 switch (tail->tok) {
1648 case BOL:
1649 case EOL:
1650 case CLOSURE:
1651 return(0);
1653 default:
1654 ntok->tok = CLOSURE;
1657 break;
1659 case CCL:
1661 if (*(arg + 1) == NEGATE) {
1662 ntok->tok = NCCL;
1663 arg += 2;
1664 } else {
1665 ntok->tok = CCL;
1666 arg++;
1669 if (ntok->bitmap = makebitmap(CLS_SIZE))
1670 arg = dodash(CCLEND, arg, ntok->bitmap);
1671 else {
1672 fprintf(stderr, "Not enough memory for pat\n");
1673 error = 1;
1675 break;
1677 default:
1678 if (*arg == ESCAPE && *(arg + 1) == OPEN) {
1679 ntok->tok = OPEN;
1680 arg++;
1681 } else if (*arg == ESCAPE && *(arg + 1) == CLOSE) {
1682 ntok->tok = CLOSE;
1683 arg++;
1684 } else {
1685 ntok->tok = LITCHAR;
1686 ntok->lchar = esc(&arg);
1690 if (error || ntok == 0) {
1691 unmakepat(head);
1692 return(0);
1693 } else if (head == 0) {
1694 /* This is the first node in the chain. */
1696 ntok->next = 0;
1697 head = tail = ntok;
1698 } else if (ntok->tok != CLOSURE) {
1699 /* Insert at end of list (after tail) */
1701 tail->next = ntok;
1702 ntok->next = tail;
1703 tail = ntok;
1704 } else if (head != tail) {
1705 /* More than one node in the chain. Insert the
1706 * CLOSURE node immediately in front of tail. */
1708 (tail->next)->next = ntok;
1709 ntok->next = tail;
1710 } else {
1711 /* Only one node in the chain, Insert the CLOSURE
1712 * node at the head of the linked list. */
1714 ntok->next = head;
1715 tail->next = ntok;
1716 head = ntok;
1718 arg++;
1721 tail->next = 0;
1722 return(head);
1725 /* maksub.c */
1726 /* #include <stdio.h> */
1727 /* #include "tools.h" */
1728 /* #include "ed.h" */
1730 char *
1731 maksub(sub, subsz)
1732 char *sub;
1733 int subsz;
1735 int size;
1736 char delim, *cp;
1738 size = 0;
1739 cp = sub;
1741 delim = *inptr++;
1742 for (size = 0; *inptr != delim && *inptr != NL && size < subsz; size++) {
1743 if (*inptr == '&') {
1744 *cp++ = DITTO;
1745 inptr++;
1746 } else if ((*cp++ = *inptr++) == ESCAPE) {
1747 if (size >= subsz) return(NULL);
1749 switch (toupper(*inptr)) {
1750 case NL: *cp++ = ESCAPE; break;
1751 break;
1752 case 'S':
1753 *cp++ = SP;
1754 inptr++;
1755 break;
1756 case 'N':
1757 *cp++ = NL;
1758 inptr++;
1759 break;
1760 case 'T':
1761 *cp++ = HT;
1762 inptr++;
1763 break;
1764 case 'B':
1765 *cp++ = BS;
1766 inptr++;
1767 break;
1768 case 'R':
1769 *cp++ = CR;
1770 inptr++;
1771 break;
1772 case '0':{
1773 int i = 3;
1774 *cp = 0;
1775 do {
1776 if (*++inptr < '0' || *inptr > '7')
1777 break;
1779 *cp = (*cp << 3) | (*inptr - '0');
1780 } while (--i != 0);
1781 cp++;
1782 } break;
1783 default: *cp++ = *inptr++; break;
1787 if (size >= subsz) return(NULL);
1789 *cp = EOS;
1790 return(sub);
1793 /* matchs.c */
1794 /* #include <stdio.h> */
1795 /* #include "tools.h" */
1797 /* Compares line and pattern. Line is a character string while pat
1798 * is a pattern template made by getpat().
1799 * Returns:
1800 * 1. A zero if no match was found.
1802 * 2. A pointer to the last character satisfing the match
1803 * if ret_endp is non-zero.
1805 * 3. A pointer to the beginning of the matched string if
1806 * ret_endp is zero.
1808 * e.g.:
1810 * matchs ("1234567890", getpat("4[0-9]*7), 0);
1811 * will return a pointer to the '4', while:
1813 * matchs ("1234567890", getpat("4[0-9]*7), 1);
1814 * will return a pointer to the '7'.
1816 char *
1817 matchs(line, pat, ret_endp)
1818 char *line;
1819 TOKEN *pat;
1820 int ret_endp;
1823 char *rval, *bptr;
1824 char *line2;
1825 TOKEN *pat2;
1826 char c;
1827 short ok;
1829 bptr = line;
1831 while (*line) {
1833 if (pat && pat->tok == LITCHAR) {
1834 while (*line) {
1835 pat2 = pat;
1836 line2 = line;
1837 if (*line2 != pat2->lchar) {
1838 c = pat2->lchar;
1839 while (*line2 && *line2 != c) ++line2;
1840 line = line2;
1841 if (*line2 == '\0') break;
1843 ok = 1;
1844 ++line2;
1845 pat2 = pat2->next;
1846 while (pat2 && pat2->tok == LITCHAR) {
1847 if (*line2 != pat2->lchar) {
1848 ok = 0;
1849 break;
1851 ++line2;
1852 pat2 = pat2->next;
1854 if (!pat2) {
1855 if (ret_endp)
1856 return(--line2);
1857 else
1858 return(line);
1859 } else if (ok)
1860 break;
1861 ++line;
1863 if (*line == '\0') return(0);
1864 } else {
1865 line2 = line;
1866 pat2 = pat;
1868 if ((rval = amatch(line2, pat2, bptr)) == 0) {
1869 if (pat && pat->tok == BOL) break;
1870 line++;
1871 } else {
1872 if (rval > bptr && rval > line)
1873 rval--; /* point to last char matched */
1874 rval = ret_endp ? rval : line;
1875 break;
1878 return(rval);
1881 /* move.c */
1882 /* #include <stdio.h> */
1883 /* #include "tools.h" */
1884 /* #include "ed.h" */
1886 int move(num)
1887 int num;
1889 LINE *k0, *k1, *k2, *k3;
1891 if (line1 <= 0 || line2 < line1 || (line1 <= num && num <= line2))
1892 return(ERR);
1893 k0 = getptr(prevln(line1));
1894 k1 = getptr(line1);
1895 k2 = getptr(line2);
1896 k3 = getptr(nextln(line2));
1898 relink(k0, k3, k0, k3);
1899 lastln -= line2 - line1 + 1;
1901 if (num > line1) num -= line2 - line1 + 1;
1903 curln = num + (line2 - line1 + 1);
1905 k0 = getptr(num);
1906 k3 = getptr(nextln(num));
1908 relink(k0, k1, k2, k3);
1909 relink(k2, k3, k0, k1);
1910 lastln += line2 - line1 + 1;
1912 return(1);
1915 int transfer(num)
1916 int num;
1918 int mid, lin, ntrans;
1920 if (line1 <= 0 || line1 > line2) return(ERR);
1922 mid = num < line2 ? num : line2;
1924 curln = num;
1925 ntrans = 0;
1927 for (lin = line1; lin <= mid; lin++) {
1928 ins(gettxt(lin));
1929 ntrans++;
1931 lin += ntrans;
1932 line2 += ntrans;
1934 for (; lin <= line2; lin += 2) {
1935 ins(gettxt(lin));
1936 line2++;
1938 return(1);
1941 /* omatch.c */
1942 /* #include <stdio.h> */
1943 /* #include "tools.h" */
1945 /* Match one pattern element, pointed at by pat, with the character at
1946 * **linp. Return non-zero on match. Otherwise, return 0. *Linp is
1947 * advanced to skip over the matched character; it is not advanced on
1948 * failure. The amount of advance is 0 for patterns that match null
1949 * strings, 1 otherwise. "boln" should point at the position that will
1950 * match a BOL token.
1952 int omatch(linp, pat, boln)
1953 char **linp;
1954 TOKEN *pat;
1955 char *boln;
1958 register int advance;
1960 advance = -1;
1962 if (**linp) {
1963 switch (pat->tok) {
1964 case LITCHAR:
1965 if (**linp == pat->lchar) advance = 1;
1966 break;
1968 case BOL:
1969 if (*linp == boln) advance = 0;
1970 break;
1972 case ANY:
1973 if (**linp != '\n') advance = 1;
1974 break;
1976 case EOL:
1977 if (**linp == '\n') advance = 0;
1978 break;
1980 case CCL:
1981 if (testbit(**linp, pat->bitmap)) advance = 1;
1982 break;
1984 case NCCL:
1985 if (!testbit(**linp, pat->bitmap)) advance = 1;
1986 break;
1989 if (advance >= 0) *linp += advance;
1991 return(++advance);
1994 /* optpat.c */
1995 /* #include <stdio.h> */
1996 /* #include "tools.h" */
1997 /* #include "ed.h" */
1999 TOKEN *oldpat;
2001 TOKEN *
2002 optpat()
2004 char delim, str[MAXPAT], *cp;
2006 delim = *inptr++;
2007 cp = str;
2008 while (*inptr != delim && *inptr != NL) {
2009 if (*inptr == ESCAPE && inptr[1] != NL) *cp++ = *inptr++;
2010 *cp++ = *inptr++;
2013 *cp = EOS;
2014 if (*str == EOS) return(oldpat);
2015 if (oldpat) unmakepat(oldpat);
2016 oldpat = getpat(str);
2017 return(oldpat);
2020 /* set.c */
2021 /* #include <stdio.h> */
2022 /* #include "tools.h" */
2023 /* #include "ed.h" */
2025 struct tbl {
2026 char *t_str;
2027 int *t_ptr;
2028 int t_val;
2029 } *t, tbl[] = {
2031 "number", &nflg, TRUE,
2032 "nonumber", &nflg, FALSE,
2033 "list", &lflg, TRUE,
2034 "nolist", &lflg, FALSE,
2035 "eightbit", &eightbit, TRUE,
2036 "noeightbit", &eightbit, FALSE,
2040 int set()
2042 char word[16];
2043 int i;
2045 inptr++;
2046 if (*inptr != 't') {
2047 if (*inptr != SP && *inptr != HT && *inptr != NL) return(ERR);
2048 } else
2049 inptr++;
2051 if (*inptr == NL) return(show());
2052 /* Skip white space */
2053 while (*inptr == SP || *inptr == HT) inptr++;
2055 for (i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
2056 word[i++] = *inptr++;
2057 word[i] = EOS;
2058 for (t = tbl; t->t_str; t++) {
2059 if (strcmp(word, t->t_str) == 0) {
2060 *t->t_ptr = t->t_val;
2061 return(0);
2064 return(0);
2067 int show()
2069 extern int version;
2071 printf("ed version %d.%d\n", version / 100, version % 100);
2072 printf("number %s, list %s\n", nflg ? "ON" : "OFF", lflg ? "ON" : "OFF");
2073 return(0);
2076 /* setbuf.c */
2077 /* #include <stdio.h> */
2078 /* #include "tools.h" */
2079 /* #include "ed.h" */
2081 void relink(a, x, y, b)
2082 LINE *a, *x, *y, *b;
2084 x->l_prev = a;
2085 y->l_next = b;
2088 void clrbuf()
2090 del(1, lastln);
2093 void set_buf()
2095 relink(&line0, &line0, &line0, &line0);
2096 curln = lastln = 0;
2099 /* subst.c */
2100 /* #include <stdio.h> */
2101 /* #include "tools.h" */
2102 /* #include "ed.h" */
2104 int subst(pat, sub, gflg, pflag)
2105 TOKEN *pat;
2106 char *sub;
2107 int gflg, pflag;
2109 int lin, chngd, nchngd;
2110 char *txtptr, *txt;
2111 char *lastm, *m, *new, buf[MAXLINE];
2113 if (line1 <= 0) return(ERR);
2114 nchngd = 0; /* reset count of lines changed */
2115 for (lin = line1; lin <= line2; lin++) {
2116 txt = txtptr = gettxt(lin);
2117 new = buf;
2118 chngd = 0;
2119 lastm = NULL;
2120 while (*txtptr) {
2121 if (gflg || !chngd)
2122 m = amatch(txtptr, pat, txt);
2123 else
2124 m = NULL;
2125 if (m != NULL && lastm != m) {
2126 chngd++;
2127 new = catsub(txtptr, m, sub, new,
2128 buf + MAXLINE);
2129 lastm = m;
2131 if (m == NULL || m == txtptr) {
2132 *new++ = *txtptr++;
2133 } else {
2134 txtptr = m;
2137 if (chngd) {
2138 if (new >= buf + MAXLINE) return(ERR);
2139 *new++ = EOS;
2140 del(lin, lin);
2141 ins(buf);
2142 nchngd++;
2143 if (pflag) doprnt(curln, curln);
2146 if (nchngd == 0 && !gflg) {
2147 return(ERR);
2149 return(nchngd);
2152 /* System.c */
2153 #define SHELL "/bin/sh"
2154 #define SHELL2 "/usr/bin/sh"
2156 int System(c)
2157 char *c;
2159 int pid, status;
2161 switch (pid = fork()) {
2162 case -1:
2163 return -1;
2164 case 0:
2165 execl(SHELL, "sh", "-c", c, (char *) 0);
2166 execl(SHELL2, "sh", "-c", c, (char *) 0);
2167 exit(-1);
2168 default: while (wait(&status) != pid);
2170 return status;
2173 /* unmkpat.c */
2174 /* #include <stdio.h> */
2175 /* #include "tools.h" */
2177 /* Free up the memory usde for token string */
2178 void unmakepat(head)
2179 TOKEN *head;
2182 register TOKEN *old_head;
2184 while (head) {
2185 switch (head->tok) {
2186 case CCL:
2187 case NCCL:
2188 free(head->bitmap);
2189 /* Fall through to default */
2191 default:
2192 old_head = head;
2193 head = head->next;
2194 free((char *) old_head);
2195 break;