source: trunk/minix/commands/simple/ed.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 43.0 KB
Line 
1/* Copyright 1987 Brian Beattie Rights Reserved.
2 *
3 * Permission to copy and/or distribute granted under the
4 * following conditions:
5 *
6 * 1). No charge may be made other than resonable charges
7 * for reproduction.
8 *
9 * 2). This notice must remain intact.
10 *
11 * 3). No further restrictions may be added.
12 *
13 */
14
15/* This program used to be in many little pieces, with this makefile:
16.SUFFIXES: .c .s
17
18CFLAGS = -F
19
20OBJS = 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
25
26ed: $(OBJS)
27 cc -T. -i -o ed $(OBJS)
28*/
29
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>
37
38/****************************/
39
40/* tools.h */
41/*
42 * #defines for non-printing ASCII characters
43 */
44
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 */
81
82
83#define TRUE 1
84#define FALSE 0
85#define ERR -2
86
87
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.
92 */
93
94
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 ')'
109
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.)
112 */
113#define CLS_SIZE 128
114
115/*
116 * Tokens are used to hold pattern templates. (see makepat())
117 */
118typedef char BITMAP;
119
120typedef struct token {
121 char tok;
122 char lchar;
123 BITMAP *bitmap;
124 struct token *next;
125} TOKEN;
126
127#define TOKSIZE sizeof (TOKEN)
128
129/*
130 * An absolute maximun for strings.
131 */
132
133#define MAXSTR 132 /* Maximum numbers of characters in a line */
134
135
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)
140
141/* ed.h */
142#define FATAL (ERR-1)
143struct line {
144 int l_stat; /* empty, mark */
145 struct line *l_prev;
146 struct line *l_next;
147 char l_buff[1];
148};
149
150typedef struct line LINE;
151
152#define LINFREE 1 /* entry not in use */
153#define LGLOB 2 /* line marked global */
154
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)
161
162extern LINE line0;
163extern int curln, lastln, line1, line2, nlines;
164extern int nflg; /* print line number flag */
165extern int lflg; /* print line in verbose mode */
166extern char *inptr; /* tty input buffer */
167extern char linbuf[], *linptr; /* current line */
168extern int truncflg; /* truncate long line flag */
169extern int eightbit; /* save eighth bit */
170extern int nonascii; /* count of non-ascii chars read */
171extern int nullchar; /* count of null chars read */
172extern int truncated; /* count of lines truncated */
173extern int fchanged; /* file changed */
174
175#define nextln(l) ((l)+1 > lastln ? 0 : (l)+1)
176#define prevln(l) ((l)-1 < 0 ? lastln : (l)-1)
177
178/* amatch.c */
179/* #include <stdio.h> */
180/* #include "tools.h" */
181
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));
231
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.
238 *
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.
243 */
244
245char *paropen[9], *parclose[9];
246int between, parnum;
247
248char *amatch(lin, pat, boln)
249char *lin;
250TOKEN *pat;
251char *boln;
252{
253 between = 0;
254 parnum = 0;
255
256 lin = match(lin, pat, boln);
257
258 if (between) return 0;
259
260 while (parnum < 9) {
261 paropen[parnum] = parclose[parnum] = "";
262 parnum++;
263 }
264 return lin;
265}
266
267static char *match(lin, pat, boln)
268char *lin;
269TOKEN *pat;
270char *boln;
271{
272 register char *bocl, *rval, *strstart;
273
274 if (pat == 0) return 0;
275
276 strstart = lin;
277
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. */
283
284 pat = pat->next;
285
286 /* Now match as many occurrences of the closure
287 * pattern as possible. */
288 bocl = lin;
289
290 while (*lin && omatch(&lin, pat, boln));
291
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. */
304
305 if (pat = pat->next) {
306 int savbtwn = between;
307 int savprnm = parnum;
308
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;
317 }
318 }
319 return(0); /* match failed */
320 }
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);
335 }
336 }
337
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.
343 *
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. */
352
353 return((char *) max(strstart, lin));
354}
355
356/* append.c */
357/* #include <stdio.h> */
358/* #include "tools.h" */
359/* #include "ed.h" */
360
361int append(line, glob)
362int line, glob;
363{
364 int stat;
365 char lin[MAXLINE];
366
367 if (glob) return(ERR);
368 curln = line;
369 while (1) {
370 if (nflg) printf("%6d. ", curln + 1);
371
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);
376
377 }
378}
379
380/* bitmap.c */
381/*
382 * BITMAP.C - makebitmap, setbit, testbit
383 * bit-map manipulation routines.
384 *
385 * Copyright (c) Allen I. Holub, all rights reserved. This program may
386 * for copied for personal, non-profit use only.
387 *
388 */
389
390#ifdef DEBUG
391/* #include <stdio.h> */
392#endif
393
394/* #include "tools.h" */
395
396
397BITMAP *makebitmap(size)
398unsigned size;
399{
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. */
404
405 unsigned *map, numbytes;
406
407 numbytes = (size >> 3) + ((size & 0x07) ? 1 : 0);
408
409#ifdef DEBUG
410 printf("Making a %d bit map (%d bytes required)\n", size, numbytes);
411#endif
412
413 if (map = (unsigned *) malloc(numbytes + sizeof(unsigned))) {
414 *map = size;
415 memset(map + 1, 0, numbytes);
416 }
417
418 return((BITMAP *) map);
419}
420
421int setbit(c, map, val)
422unsigned c, val;
423char *map;
424{
425 /* Set bit c in the map to val. If c > map-size, 0 is returned, else
426 * 1 is returned. */
427
428 if (c >= *(unsigned *) map) /* if c >= map size */
429 return 0;
430
431 map += sizeof(unsigned); /* skip past size */
432
433 if (val)
434 map[c >> 3] |= 1 << (c & 0x07);
435 else
436 map[c >> 3] &= ~(1 << (c & 0x07));
437
438 return 1;
439}
440
441int testbit(c, map)
442unsigned c;
443char *map;
444{
445 /* Return 1 if the bit corresponding to c in map is set. 0 if it is not. */
446
447 if (c >= *(unsigned *) map) return 0;
448
449 map += sizeof(unsigned);
450
451 return(map[c >> 3] & (1 << (c & 0x07)));
452}
453
454/* catsub.c */
455/* #include <stdio.h> */
456/* #include "tools.h" */
457/* #include "ed.h" */
458
459extern char *paropen[9], *parclose[9];
460
461char *catsub(from, to, sub, new, newend)
462char *from, *to, *sub, *new, *newend;
463{
464 char *cp, *cp2;
465
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;
470 }
471 else if (*sub == ESCAPE) {
472 sub++;
473 if ('1' <= *sub && *sub <= '9') {
474 char *parcl = parclose[*sub - '1'];
475
476 for (cp2 = paropen[*sub - '1']; cp2 < parcl;) {
477 *cp++ = *cp2++;
478 if (cp >= newend) break;
479 }
480 } else
481 *cp++ = *sub;
482 } else
483 *cp++ = *sub;
484
485 sub++;
486 }
487
488 return(cp);
489}
490
491/* ckglob.c */
492/* #include <stdio.h> */
493/* #include "tools.h" */
494/* #include "ed.h" */
495
496int ckglob()
497{
498 TOKEN *glbpat;
499 char c, delim;
500 char lin[MAXLINE];
501 int num;
502 LINE *ptr;
503
504 c = *inptr;
505
506 if (c != 'g' && c != 'v') return(0);
507
508 if (deflt(1, lastln) < 0) return(ERR);
509
510 delim = *++inptr;
511 if (delim <= ' ') return(ERR);
512
513 glbpat = optpat();
514
515 if (*inptr == delim) inptr++;
516
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;
527 }
528 }
529 ptr = ptr->l_next;
530 }
531 return(1);
532}
533
534/* deflt.c */
535/* #include <stdio.h> */
536/* #include "tools.h" */
537/* #include "ed.h" */
538
539int deflt(def1, def2)
540int def1, def2;
541{
542 if (nlines == 0) {
543 line1 = def1;
544 line2 = def2;
545 }
546 if (line1 > line2 || line1 <= 0) return(ERR);
547 return(0);
548}
549
550/* del.c */
551/* #include <stdio.h> */
552/* #include "tools.h" */
553/* #include "ed.h" */
554
555int del(from, to)
556int from, to;
557{
558 LINE *first, *last, *next, *tmp;
559
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;
568 }
569 relink(first, last, first, last);
570 lastln -= (to - from) + 1;
571 curln = prevln(from);
572 return(0);
573}
574
575/* docmd.c */
576/* #include <stdio.h> */
577/* #include "tools.h" */
578/* #include "ed.h" */
579
580char fname[MAXFNAME];
581int fchanged;
582extern int nofname;
583
584extern int mark[];
585
586int docmd(glob)
587int glob;
588{
589 static char rhs[MAXPAT];
590 TOKEN *subpat;
591 int c, err, line3;
592 int apflg, pflag, gflag;
593 int nchng;
594 char *fptr;
595
596 pflag = FALSE;
597 while (*inptr == SP && *inptr == HT) inptr++;
598
599 c = *inptr++;
600
601 switch (c) {
602 case NL:
603 if (nlines == 0) {
604 if ((line2 = nextln(curln)) == 0) return(ERR);
605 }
606 curln = line2;
607 return(1);
608 break;
609
610 case '=': printf("%d\n", line2); break;
611
612 case 'a':
613 if (*inptr != NL || nlines > 1) return(ERR);
614
615 if (append(line1, glob) < 0) return(ERR);;
616 fchanged = TRUE;
617 break;
618
619 case 'c':
620 if (*inptr != NL) return(ERR);
621
622 if (deflt(curln, curln) < 0) return(ERR);
623
624 if (del(line1, line2) < 0) return(ERR);
625 if (append(curln, glob) < 0) return (ERR);
626 fchanged = TRUE;
627 break;
628
629 case 'd':
630 if (*inptr != NL) return(ERR);
631
632 if (deflt(curln, curln) < 0) return(ERR);
633
634 if (del(line1, line2) < 0) return(ERR);
635 if (nextln(curln) != 0) curln = nextln(curln);
636 fchanged = TRUE;
637 break;
638
639 case 'e':
640 if (nlines > 0) return(ERR);
641 if (fchanged) {
642 fchanged = FALSE;
643 return(ERR);
644 }
645
646 /* FALL THROUGH */
647 case 'E':
648 if (nlines > 0) return(ERR);
649
650 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
651
652 if ((fptr = getfn()) == NULL) return(ERR);
653
654 clrbuf();
655 if ((err = doread(0, fptr)) < 0) return(err);
656
657 strcpy(fname, fptr);
658 fchanged = FALSE;
659 break;
660
661 case 'f':
662 if (nlines > 0) return(ERR);
663
664 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
665
666 if ((fptr = getfn()) == NULL) return(ERR);
667
668 if (nofname)
669 printf("%s\n", fname);
670 else
671 strcpy(fname, fptr);
672 break;
673
674 case 'i':
675 if (*inptr != NL || nlines > 1) return(ERR);
676
677 if (append(prevln(line1), glob) < 0) return(ERR);
678 fchanged = TRUE;
679 break;
680
681 case 'j':
682 if (*inptr != NL || deflt(curln, curln + 1) < 0) return(ERR);
683
684 if (join(line1, line2) < 0) return(ERR);
685 break;
686
687 case 'k':
688 while (*inptr == ' ' || *inptr == HT) inptr++;
689
690 if (*inptr < 'a' || *inptr > 'z') return ERR;
691 c = *inptr++;
692
693 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
694
695 mark[c - 'a'] = line1;
696 break;
697
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;
703
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;
710
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;
717
718 case 'q':
719 if (fchanged) {
720 fchanged = FALSE;
721 return(ERR);
722 }
723
724 /* FALL THROUGH */
725 case 'Q':
726 if (*inptr == NL && nlines == 0 && !glob)
727 return(EOF);
728 else
729 return(ERR);
730
731 case 'r':
732 if (nlines > 1) return(ERR);
733
734 if (nlines == 0) line2 = lastln;
735
736 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
737
738 if ((fptr = getfn()) == NULL) return(ERR);
739
740 if ((err = doread(line2, fptr)) < 0) return(err);
741 fchanged = TRUE;
742 break;
743
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;
754
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;
761
762 case 'W':
763 case 'w':
764 apflg = (c == 'W');
765
766 if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
767
768 if ((fptr = getfn()) == NULL) return(ERR);
769
770 if (deflt(1, lastln) < 0) return(ERR);
771 if (dowrite(line1, line2, fptr, apflg) < 0) return (ERR);
772 fchanged = FALSE;
773 break;
774
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);
779 }
780 return(ERR);
781
782 case 'z':
783 if (deflt(curln, curln) < 0) return(ERR);
784
785 switch (*inptr) {
786 case '-':
787 if (doprnt(line1 - 21, line1) < 0) return(ERR);
788 break;
789
790 case '.':
791 if (doprnt(line1 - 11, line1 + 10) < 0) return(ERR);
792 break;
793
794 case '+':
795 case '\n':
796 if (doprnt(line1, line1 + 21) < 0) return(ERR);
797 break;
798 }
799 break;
800
801 default: return(ERR);
802}
803 return(0);
804}
805
806int dolst(line1, line2)
807int line1, line2;
808{
809 int oldlflg = lflg, p;
810
811 lflg = 1;
812 p = doprnt(line1, line2);
813 lflg = oldlflg;
814
815 return p;
816}
817
818/* dodash.c */
819/* #include <stdio.h> */
820/* #include "tools.h" */
821
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.
833 */
834char *dodash(delim, src, map)
835int delim;
836char *src, *map;
837{
838
839 register int first, last;
840 char *start;
841
842 start = src;
843
844 while (*src && *src != delim) {
845 if (*src != '-') setbit(esc(&src), map, 1);
846
847 else if (src == start || *(src + 1) == delim)
848 setbit('-', map, 1);
849 else {
850 src++;
851
852 if (*src < *(src - 2)) {
853 first = *src;
854 last = *(src - 2);
855 } else {
856 first = *(src - 2);
857 last = *src;
858 }
859
860 while (++first <= last) setbit(first, map, 1);
861
862 }
863 src++;
864 }
865 return(src);
866}
867
868/* doglob.c */
869/* #include <stdio.h> */
870/* #include "tools.h" */
871/* #include "ed.h" */
872
873int doglob()
874{
875 int lin, stat;
876 char *cmd;
877 LINE *ptr;
878
879 cmd = inptr;
880
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;
886 }
887 if (lin > lastln) break;
888
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);
894 }
895 return(curln);
896}
897
898/* doprnt.c */
899/* #include <stdio.h> */
900/* #include "tools.h" */
901/* #include "ed.h" */
902
903int doprnt(from, to)
904int from, to;
905{
906 int i;
907 LINE *lptr;
908
909 from = from < 1 ? 1 : from;
910 to = to > lastln ? lastln : to;
911
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;
917 }
918 curln = to;
919 }
920 return(0);
921}
922
923void prntln(str, vflg, lin)
924char *str;
925int vflg, lin;
926{
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;
937
938 case DEL:
939 putc('^', stdout);
940 putc('?', stdout);
941 break;
942
943 default:
944 putcntl(*str, stdout);
945 break;
946 }
947 } else
948 putc(*str, stdout);
949 str++;
950 }
951 if (vflg) putc('$', stdout);
952 putc('\n', stdout);
953}
954
955void putcntl(c, stream)
956char c;
957FILE *stream;
958{
959 putc('^', stream);
960 putc((c & 31) | '@', stream);
961}
962
963/* doread.c */
964/* #include <stdio.h> */
965/* #include "tools.h" */
966/* #include "ed.h" */
967
968extern int diag;
969
970int doread(lin, fname)
971int lin;
972char *fname;
973{
974 FILE *fp;
975 int err;
976 long bytes;
977 int lines;
978 static char str[MAXLINE];
979
980 err = 0;
981 nonascii = nullchar = truncated = 0;
982
983 if (diag) printf("\"%s\" ", fname);
984 if ((fp = fopen(fname, "r")) == NULL) {
985 printf("file open err\n");
986 return(ERR);
987 }
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;
995 }
996 lines++;
997 }
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");
1006 }
1007 return(err);
1008}
1009
1010/* dowrite.c */
1011/* #include <stdio.h> */
1012/* #include "tools.h" */
1013/* #include "ed.h" */
1014
1015int dowrite(from, to, fname, apflg)
1016int from, to;
1017char *fname;
1018int apflg;
1019{
1020 FILE *fp;
1021 int lin, err;
1022 int lines;
1023 long bytes;
1024 char *str;
1025 LINE *lptr;
1026
1027 err = 0;
1028
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);
1034 }
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;
1044 }
1045 fputc('\n', fp);
1046 lptr = lptr->l_next;
1047 }
1048 if (diag) printf("%d lines %ld bytes\n", lines, bytes);
1049 fclose(fp);
1050 return(err);
1051}
1052
1053/* ed.c */
1054/* Copyright 1987 Brian Beattie Rights Reserved.
1055 *
1056 * Permission to copy and/or distribute granted under the
1057 * following conditions:
1058 *
1059 * 1). No charge may be made other than resonable charges
1060 * for reproduction.
1061 *
1062 * 2). This notice must remain intact.
1063 *
1064 * 3). No further restrictions may be added.
1065 *
1066 */
1067/* #include <stdio.h> */
1068/* #include <signal.h> */
1069/* #include "tools.h" */
1070/* #include "ed.h" */
1071#include <setjmp.h>
1072jmp_buf env;
1073
1074LINE line0;
1075int curln = 0;
1076int lastln = 0;
1077char *inptr;
1078static char inlin[MAXLINE];
1079int nflg, lflg;
1080int line1, line2, nlines;
1081extern char fname[];
1082int version = 1;
1083int diag = 1;
1084
1085void intr(sig)
1086int sig;
1087{
1088 printf("?\n");
1089 longjmp(env, 1);
1090}
1091
1092int main(argc, argv)
1093int argc;
1094char **argv;
1095{
1096 int stat, i, doflush;
1097
1098 set_buf();
1099 doflush = isatty(1);
1100
1101 if (argc > 1 && (strcmp(argv[1], "-") == 0 || strcmp(argv[1], "-s") == 0)) {
1102 diag = 0;
1103 argc--;
1104 argv++;
1105 }
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;
1112 }
1113 }
1114 }
1115 while (1) {
1116 setjmp(env);
1117 if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, intr);
1118
1119 if (doflush) fflush(stdout);
1120
1121 if (fgets(inlin, sizeof(inlin), stdin) == NULL) {
1122 break;
1123 }
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;
1132 }
1133 }
1134 if (*inlin == '!') {
1135 if ((inptr = strchr(inlin, NL)) != NULL) *inptr = EOS;
1136 System(inlin + 1);
1137 continue;
1138 }
1139 inptr = inlin;
1140 if (getlst() >= 0)
1141 if ((stat = ckglob()) != 0) {
1142 if (stat >= 0 && (stat = doglob()) >= 0) {
1143 curln = stat;
1144 continue;
1145 }
1146 } else {
1147 if ((stat = docmd(0)) >= 0) {
1148 if (stat == 1) doprnt(curln, curln);
1149 continue;
1150 }
1151 }
1152 if (stat == EOF) {
1153 exit(0);
1154 }
1155 if (stat == FATAL) {
1156 fputs("FATAL ERROR\n", stderr);
1157 exit(1);
1158 }
1159 printf("?\n");
1160 }
1161 return(0);
1162}
1163
1164/* egets.c */
1165/* #include <stdio.h> */
1166/* #include "tools.h" */
1167/* #include "ed.h" */
1168
1169int eightbit = 1; /* save eight bit */
1170int nonascii, nullchar, truncated;
1171int egets(str, size, stream)
1172char *str;
1173int size;
1174FILE *stream;
1175{
1176 int c, count;
1177 char *cp;
1178
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");
1186 }
1187 return(count);
1188 }
1189 if (c == NL) {
1190 *cp++ = c;
1191 *cp = EOS;
1192 return(++count);
1193 }
1194 if (c > 127) {
1195 if (!eightbit) /* if not saving eighth bit */
1196 c = c & 127; /* strip eigth bit */
1197 nonascii++; /* count it */
1198 }
1199 if (c) {
1200 *cp++ = c; /* not null, keep it */
1201 count++;
1202 } else
1203 nullchar++; /* count nulls */
1204 }
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;
1211 }
1212 return(count);
1213}
1214
1215/* esc.c */
1216/* #include <stdio.h> */
1217/* #include "tools.h" */
1218
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.
1223 */
1224int esc(s)
1225char **s;
1226{
1227 register int rval;
1228
1229
1230 if (**s != ESCAPE) {
1231 rval = **s;
1232 } else {
1233 (*s)++;
1234
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;
1243 }
1244 }
1245
1246 return(rval);
1247}
1248
1249/* find.c */
1250/* #include <stdio.h> */
1251/* #include "tools.h" */
1252/* #include "ed.h" */
1253
1254int find(pat, dir)
1255TOKEN *pat;
1256int dir;
1257{
1258 int i, num;
1259 char lin[MAXLINE];
1260 LINE *ptr;
1261
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);
1270 }
1271 strcpy(lin, ptr->l_buff);
1272 strcat(lin, "\n");
1273 if (matchs(lin, pat, 0)) {
1274 return(num);
1275 }
1276 num = (dir ? nextln(num) : prevln(num));
1277 ptr = (dir ? ptr->l_next : ptr->l_prev);
1278 }
1279 return(ERR);
1280}
1281
1282/* getfn.c */
1283/* #include <stdio.h> */
1284/* #include "tools.h" */
1285/* #include "ed.h" */
1286
1287extern char fname[MAXFNAME];
1288int nofname;
1289
1290char *getfn()
1291{
1292 static char file[256];
1293 char *cp;
1294
1295 if (*inptr == NL) {
1296 nofname = TRUE;
1297 strcpy(file, fname);
1298 } else {
1299 nofname = FALSE;
1300 while (*inptr == SP || *inptr == HT) inptr++;
1301
1302 cp = file;
1303 while (*inptr && *inptr != NL && *inptr != SP && *inptr != HT) {
1304 *cp++ = *inptr++;
1305 }
1306 *cp = '\0';
1307
1308 if (strlen(file) == 0) {
1309 printf("bad file name\n");
1310 return(NULL);
1311 }
1312 }
1313
1314 if (strlen(file) == 0) {
1315 printf("no file name\n");
1316 return(NULL);
1317 }
1318 return(file);
1319}
1320
1321/* getlst.c */
1322/* #include <stdio.h> */
1323/* #include "tools.h" */
1324/* #include "ed.h" */
1325
1326int getlst()
1327{
1328 int num;
1329
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++;
1338 }
1339 nlines = min(nlines, 2);
1340 if (nlines == 0) line2 = curln;
1341 if (nlines <= 1) line1 = line2;
1342
1343 if (num == ERR)
1344 return(num);
1345 else
1346 return(nlines);
1347}
1348
1349/* getnum.c */
1350/* #include <stdio.h> */
1351/* #include "tools.h" */
1352/* #include "ed.h" */
1353
1354int mark['z' - 'a' + 1];
1355
1356int getnum(first)
1357int first;
1358{
1359 TOKEN *srchpat;
1360 int num;
1361 char c;
1362
1363 while (*inptr == SP || *inptr == HT) inptr++;
1364
1365 if (*inptr >= '0' && *inptr <= '9') { /* line number */
1366 for (num = 0; *inptr >= '0' && *inptr <= '9';) {
1367 num = (num * 10) + *inptr - '0';
1368 inptr++;
1369 }
1370 return num;
1371 }
1372 switch (c = *inptr) {
1373 case '.':
1374 inptr++;
1375 return(curln);
1376
1377 case '$':
1378 inptr++;
1379 return(lastln);
1380
1381 case '/':
1382 case '?':
1383 srchpat = optpat();
1384 if (*inptr == c) inptr++;
1385 return(find(srchpat, c == '/' ? 1 : 0));
1386
1387 case '-':
1388 case '+':
1389 return(first ? curln : 1);
1390
1391 case '\'':
1392 inptr++;
1393 if (*inptr < 'a' || *inptr > 'z') return(EOF);
1394
1395 return mark[*inptr++ - 'a'];
1396
1397 default:
1398 return(first ? EOF : 1);/* unknown address */
1399 }
1400}
1401
1402/* getone.c */
1403/* #include <stdio.h> */
1404/* #include "tools.h" */
1405/* #include "ed.h" */
1406
1407#define FIRST 1
1408#define NOTFIRST 0
1409
1410int getone()
1411{
1412 int c, i, num;
1413
1414 if ((num = getnum(FIRST)) >= 0) {
1415 while (1) {
1416 while (*inptr == SP || *inptr == HT) inptr++;
1417
1418 if (*inptr != '+' && *inptr != '-') break;
1419 c = *inptr++;
1420
1421 if ((i = getnum(NOTFIRST)) < 0) return(i);
1422
1423 if (c == '+') {
1424 num += i;
1425 } else {
1426 num -= i;
1427 }
1428 }
1429 }
1430 return(num > lastln ? ERR : num);
1431}
1432
1433/* getpat.c */
1434/* #include <stdio.h> */
1435/* #include "tools.h" */
1436
1437/* Translate arg into a TOKEN string */
1438TOKEN *
1439 getpat(arg)
1440char *arg;
1441{
1442
1443 return(makepat(arg, '\000'));
1444}
1445
1446/* getptr.c */
1447/* #include <stdio.h> */
1448/* #include "tools.h" */
1449/* #include "ed.h" */
1450
1451LINE *
1452 getptr(num)
1453int num;
1454{
1455 LINE *ptr;
1456 int j;
1457
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;
1464 }
1465 return(ptr);
1466}
1467
1468/* getrhs.c */
1469/* #include <stdio.h> */
1470/* #include "tools.h" */
1471/* #include "ed.h" */
1472
1473int getrhs(sub)
1474char *sub;
1475{
1476 if (inptr[0] == NL || inptr[1] == NL) /* check for eol */
1477 return(ERR);
1478
1479 if (maksub(sub, MAXPAT) == NULL) return(ERR);
1480
1481 inptr++; /* skip over delimter */
1482 while (*inptr == SP || *inptr == HT) inptr++;
1483 if (*inptr == 'g') {
1484 inptr++;
1485 return(1);
1486 }
1487 return(0);
1488}
1489
1490/* gettxt.c */
1491/* #include <stdio.h> */
1492/* #include "tools.h" */
1493/* #include "ed.h" */
1494
1495char *
1496 gettxt(num)
1497int num;
1498{
1499 LINE *lin;
1500 static char txtbuf[MAXLINE];
1501
1502 lin = getptr(num);
1503 strcpy(txtbuf, lin->l_buff);
1504 strcat(txtbuf, "\n");
1505 return(txtbuf);
1506}
1507
1508/* ins.c */
1509/* #include <stdio.h> */
1510/* #include "tools.h" */
1511/* #include "ed.h" */
1512
1513int ins(str)
1514char *str;
1515{
1516 char buf[MAXLINE], *cp;
1517 LINE *new, *cur, *nxt;
1518
1519 cp = buf;
1520 while (1) {
1521 if ((*cp = *str++) == NL) *cp = EOS;
1522 if (*cp) {
1523 cp++;
1524 continue;
1525 }
1526 if ((new = (LINE *) malloc(sizeof(LINE) + strlen(buf))) == NULL)
1527 return(ERR); /* no memory */
1528
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++;
1537
1538 if (*str == EOS) /* end of line ? */
1539 return(1);
1540
1541 cp = buf;
1542 }
1543}
1544
1545/* join.c */
1546/* #include <stdio.h> */
1547/* #include "tools.h" */
1548/* #include "ed.h" */
1549
1550extern int fchanged;
1551
1552int join(first, last)
1553int first, last;
1554{
1555 char buf[MAXLINE];
1556 char *cp = buf, *str;
1557 int num;
1558
1559 if (first <= 0 || first > last || last > lastln) return(ERR);
1560 if (first == last) {
1561 curln = first;
1562 return 0;
1563 }
1564 for (num = first; num <= last; num++) {
1565 str = gettxt(num);
1566
1567 while (*str != NL && cp < buf + MAXLINE - 1) *cp++ = *str++;
1568
1569 if (cp == buf + MAXLINE - 1) {
1570 printf("line too long\n");
1571 return(ERR);
1572 }
1573 }
1574 *cp++ = NL;
1575 *cp = EOS;
1576 del(first, last);
1577 curln = first - 1;
1578 ins(buf);
1579 fchanged = TRUE;
1580 return 0;
1581}
1582
1583/* makepat.c */
1584/* #include <stdio.h> */
1585/* #include "tools.h" */
1586
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.
1590 *
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.
1596 *
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.
1602 */
1603TOKEN *
1604 makepat(arg, delim)
1605char *arg;
1606int delim;
1607{
1608 TOKEN *head, *tail, *ntok;
1609 int error;
1610
1611 /* Check for characters that aren't legal at the beginning of a template. */
1612
1613 if (*arg == '\0' || *arg == delim || *arg == '\n' || *arg == CLOSURE)
1614 return(0);
1615
1616 error = 0;
1617 tail = head = NULL;
1618
1619 while (*arg && *arg != delim && *arg != '\n' && !error) {
1620 ntok = (TOKEN *) malloc(TOKSIZE);
1621 ntok->lchar = '\000';
1622 ntok->next = 0;
1623
1624 switch (*arg) {
1625 case ANY: ntok->tok = ANY; break;
1626
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;
1634
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;
1642 }
1643 break;
1644
1645 case CLOSURE:
1646 if (head != 0) {
1647 switch (tail->tok) {
1648 case BOL:
1649 case EOL:
1650 case CLOSURE:
1651 return(0);
1652
1653 default:
1654 ntok->tok = CLOSURE;
1655 }
1656 }
1657 break;
1658
1659 case CCL:
1660
1661 if (*(arg + 1) == NEGATE) {
1662 ntok->tok = NCCL;
1663 arg += 2;
1664 } else {
1665 ntok->tok = CCL;
1666 arg++;
1667 }
1668
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;
1674 }
1675 break;
1676
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);
1687 }
1688 }
1689
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. */
1695
1696 ntok->next = 0;
1697 head = tail = ntok;
1698 } else if (ntok->tok != CLOSURE) {
1699 /* Insert at end of list (after tail) */
1700
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. */
1707
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. */
1713
1714 ntok->next = head;
1715 tail->next = ntok;
1716 head = ntok;
1717 }
1718 arg++;
1719 }
1720
1721 tail->next = 0;
1722 return(head);
1723}
1724
1725/* maksub.c */
1726/* #include <stdio.h> */
1727/* #include "tools.h" */
1728/* #include "ed.h" */
1729
1730char *
1731 maksub(sub, subsz)
1732char *sub;
1733int subsz;
1734{
1735 int size;
1736 char delim, *cp;
1737
1738 size = 0;
1739 cp = sub;
1740
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);
1748
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;
1778
1779 *cp = (*cp << 3) | (*inptr - '0');
1780 } while (--i != 0);
1781 cp++;
1782 } break;
1783 default: *cp++ = *inptr++; break;
1784 }
1785 }
1786 }
1787 if (size >= subsz) return(NULL);
1788
1789 *cp = EOS;
1790 return(sub);
1791}
1792
1793/* matchs.c */
1794/* #include <stdio.h> */
1795/* #include "tools.h" */
1796
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.
1801 *
1802 * 2. A pointer to the last character satisfing the match
1803 * if ret_endp is non-zero.
1804 *
1805 * 3. A pointer to the beginning of the matched string if
1806 * ret_endp is zero.
1807 *
1808 * e.g.:
1809 *
1810 * matchs ("1234567890", getpat("4[0-9]*7), 0);
1811 * will return a pointer to the '4', while:
1812 *
1813 * matchs ("1234567890", getpat("4[0-9]*7), 1);
1814 * will return a pointer to the '7'.
1815 */
1816char *
1817 matchs(line, pat, ret_endp)
1818char *line;
1819TOKEN *pat;
1820int ret_endp;
1821{
1822
1823 char *rval, *bptr;
1824 char *line2;
1825 TOKEN *pat2;
1826 char c;
1827 short ok;
1828
1829 bptr = line;
1830
1831 while (*line) {
1832
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;
1842 }
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;
1850 }
1851 ++line2;
1852 pat2 = pat2->next;
1853 }
1854 if (!pat2) {
1855 if (ret_endp)
1856 return(--line2);
1857 else
1858 return(line);
1859 } else if (ok)
1860 break;
1861 ++line;
1862 }
1863 if (*line == '\0') return(0);
1864 } else {
1865 line2 = line;
1866 pat2 = pat;
1867 }
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;
1876 }
1877 }
1878 return(rval);
1879}
1880
1881/* move.c */
1882/* #include <stdio.h> */
1883/* #include "tools.h" */
1884/* #include "ed.h" */
1885
1886int move(num)
1887int num;
1888{
1889 LINE *k0, *k1, *k2, *k3;
1890
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));
1897
1898 relink(k0, k3, k0, k3);
1899 lastln -= line2 - line1 + 1;
1900
1901 if (num > line1) num -= line2 - line1 + 1;
1902
1903 curln = num + (line2 - line1 + 1);
1904
1905 k0 = getptr(num);
1906 k3 = getptr(nextln(num));
1907
1908 relink(k0, k1, k2, k3);
1909 relink(k2, k3, k0, k1);
1910 lastln += line2 - line1 + 1;
1911
1912 return(1);
1913}
1914
1915int transfer(num)
1916int num;
1917{
1918 int mid, lin, ntrans;
1919
1920 if (line1 <= 0 || line1 > line2) return(ERR);
1921
1922 mid = num < line2 ? num : line2;
1923
1924 curln = num;
1925 ntrans = 0;
1926
1927 for (lin = line1; lin <= mid; lin++) {
1928 ins(gettxt(lin));
1929 ntrans++;
1930 }
1931 lin += ntrans;
1932 line2 += ntrans;
1933
1934 for (; lin <= line2; lin += 2) {
1935 ins(gettxt(lin));
1936 line2++;
1937 }
1938 return(1);
1939}
1940
1941/* omatch.c */
1942/* #include <stdio.h> */
1943/* #include "tools.h" */
1944
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.
1951 */
1952int omatch(linp, pat, boln)
1953char **linp;
1954TOKEN *pat;
1955char *boln;
1956{
1957
1958 register int advance;
1959
1960 advance = -1;
1961
1962 if (**linp) {
1963 switch (pat->tok) {
1964 case LITCHAR:
1965 if (**linp == pat->lchar) advance = 1;
1966 break;
1967
1968 case BOL:
1969 if (*linp == boln) advance = 0;
1970 break;
1971
1972 case ANY:
1973 if (**linp != '\n') advance = 1;
1974 break;
1975
1976 case EOL:
1977 if (**linp == '\n') advance = 0;
1978 break;
1979
1980 case CCL:
1981 if (testbit(**linp, pat->bitmap)) advance = 1;
1982 break;
1983
1984 case NCCL:
1985 if (!testbit(**linp, pat->bitmap)) advance = 1;
1986 break;
1987 }
1988 }
1989 if (advance >= 0) *linp += advance;
1990
1991 return(++advance);
1992}
1993
1994/* optpat.c */
1995/* #include <stdio.h> */
1996/* #include "tools.h" */
1997/* #include "ed.h" */
1998
1999TOKEN *oldpat;
2000
2001TOKEN *
2002 optpat()
2003{
2004 char delim, str[MAXPAT], *cp;
2005
2006 delim = *inptr++;
2007 cp = str;
2008 while (*inptr != delim && *inptr != NL) {
2009 if (*inptr == ESCAPE && inptr[1] != NL) *cp++ = *inptr++;
2010 *cp++ = *inptr++;
2011 }
2012
2013 *cp = EOS;
2014 if (*str == EOS) return(oldpat);
2015 if (oldpat) unmakepat(oldpat);
2016 oldpat = getpat(str);
2017 return(oldpat);
2018}
2019
2020/* set.c */
2021/* #include <stdio.h> */
2022/* #include "tools.h" */
2023/* #include "ed.h" */
2024
2025struct tbl {
2026 char *t_str;
2027 int *t_ptr;
2028 int t_val;
2029} *t, tbl[] = {
2030
2031 "number", &nflg, TRUE,
2032 "nonumber", &nflg, FALSE,
2033 "list", &lflg, TRUE,
2034 "nolist", &lflg, FALSE,
2035 "eightbit", &eightbit, TRUE,
2036 "noeightbit", &eightbit, FALSE,
2037 0
2038};
2039
2040int set()
2041{
2042 char word[16];
2043 int i;
2044
2045 inptr++;
2046 if (*inptr != 't') {
2047 if (*inptr != SP && *inptr != HT && *inptr != NL) return(ERR);
2048 } else
2049 inptr++;
2050
2051 if (*inptr == NL) return(show());
2052 /* Skip white space */
2053 while (*inptr == SP || *inptr == HT) inptr++;
2054
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);
2062 }
2063 }
2064 return(0);
2065}
2066
2067int show()
2068{
2069 extern int version;
2070
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);
2074}
2075
2076/* setbuf.c */
2077/* #include <stdio.h> */
2078/* #include "tools.h" */
2079/* #include "ed.h" */
2080
2081void relink(a, x, y, b)
2082LINE *a, *x, *y, *b;
2083{
2084 x->l_prev = a;
2085 y->l_next = b;
2086}
2087
2088void clrbuf()
2089{
2090 del(1, lastln);
2091}
2092
2093void set_buf()
2094{
2095 relink(&line0, &line0, &line0, &line0);
2096 curln = lastln = 0;
2097}
2098
2099/* subst.c */
2100/* #include <stdio.h> */
2101/* #include "tools.h" */
2102/* #include "ed.h" */
2103
2104int subst(pat, sub, gflg, pflag)
2105TOKEN *pat;
2106char *sub;
2107int gflg, pflag;
2108{
2109 int lin, chngd, nchngd;
2110 char *txtptr, *txt;
2111 char *lastm, *m, *new, buf[MAXLINE];
2112
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;
2130 }
2131 if (m == NULL || m == txtptr) {
2132 *new++ = *txtptr++;
2133 } else {
2134 txtptr = m;
2135 }
2136 }
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);
2144 }
2145 }
2146 if (nchngd == 0 && !gflg) {
2147 return(ERR);
2148 }
2149 return(nchngd);
2150}
2151
2152/* System.c */
2153#define SHELL "/bin/sh"
2154#define SHELL2 "/usr/bin/sh"
2155
2156int System(c)
2157char *c;
2158{
2159 int pid, status;
2160
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);
2169}
2170 return status;
2171}
2172
2173/* unmkpat.c */
2174/* #include <stdio.h> */
2175/* #include "tools.h" */
2176
2177/* Free up the memory usde for token string */
2178void unmakepat(head)
2179TOKEN *head;
2180{
2181
2182 register TOKEN *old_head;
2183
2184 while (head) {
2185 switch (head->tok) {
2186 case CCL:
2187 case NCCL:
2188 free(head->bitmap);
2189 /* Fall through to default */
2190
2191 default:
2192 old_head = head;
2193 head = head->next;
2194 free((char *) old_head);
2195 break;
2196 }
2197 }
2198}
Note: See TracBrowser for help on using the repository browser.