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
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:
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
27 cc -T. -i -o ed $(OBJS)
30 #include <sys/types.h>
38 /****************************/
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 */
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 */
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.
100 #define CCL '[' /* Character class: [...] */
103 #define NCCL '!' /* Negative character class [^...] */
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.)
116 * Tokens are used to hold pattern templates. (see makepat())
120 typedef struct token
{
127 #define TOKSIZE sizeof (TOKEN)
130 * An absolute maximun for strings.
133 #define MAXSTR 132 /* Maximum numbers of characters in a line */
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)
142 #define FATAL (ERR-1)
144 int l_stat
; /* empty, mark */
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
159 /* max file name size */
160 #define MAXFNAME (sizeof(int) == 2 ? 256 : 1024)
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)
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];
248 char *amatch(lin
, pat
, boln
)
256 lin
= match(lin
, pat
, boln
);
258 if (between
) return 0;
261 paropen
[parnum
] = parclose
[parnum
] = "";
267 static char *match(lin
, pat
, boln
)
272 register char *bocl
, *rval
, *strstart
;
274 if (pat
== 0) return 0;
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. */
286 /* Now match as many occurrences of the closure
287 * pattern as possible. */
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
)) {
319 return(0); /* match failed */
321 } else if (pat
->tok
== OPEN
) {
322 if (between
|| parnum
>= 9) return 0;
323 paropen
[parnum
] = lin
;
326 } else if (pat
->tok
== CLOSE
) {
327 if (!between
) return 0;
328 parclose
[parnum
++] = lin
;
331 } else if (omatch(&lin
, pat
, boln
)) {
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
353 return((char *) max(strstart
, lin
));
357 /* #include <stdio.h> */
358 /* #include "tools.h" */
359 /* #include "ed.h" */
361 int append(line
, glob
)
367 if (glob
) return(ERR
);
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);
375 if (stat
< 0) return(ERR
);
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.
391 /* #include <stdio.h> */
394 /* #include "tools.h" */
397 BITMAP
*makebitmap(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);
410 printf("Making a %d bit map (%d bytes required)\n", size
, numbytes
);
413 if (map
= (unsigned *) malloc(numbytes
+ sizeof(unsigned))) {
415 memset(map
+ 1, 0, numbytes
);
418 return((BITMAP
*) map
);
421 int setbit(c
, map
, val
)
425 /* Set bit c in the map to val. If c > map-size, 0 is returned, else
428 if (c
>= *(unsigned *) map
) /* if c >= map size */
431 map
+= sizeof(unsigned); /* skip past size */
434 map
[c
>> 3] |= 1 << (c
& 0x07);
436 map
[c
>> 3] &= ~(1 << (c
& 0x07));
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)));
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
;
466 for (cp
= new; *sub
!= EOS
&& cp
< newend
;) {
467 if (*sub
== DITTO
) for (cp2
= from
; cp2
< to
;) {
469 if (cp
>= newend
) break;
471 else if (*sub
== ESCAPE
) {
473 if ('1' <= *sub
&& *sub
<= '9') {
474 char *parcl
= parclose
[*sub
- '1'];
476 for (cp2
= paropen
[*sub
- '1']; cp2
< parcl
;) {
478 if (cp
>= newend
) break;
492 /* #include <stdio.h> */
493 /* #include "tools.h" */
494 /* #include "ed.h" */
506 if (c
!= 'g' && c
!= 'v') return(0);
508 if (deflt(1, lastln
) < 0) return(ERR
);
511 if (delim
<= ' ') return(ERR
);
515 if (*inptr
== delim
) inptr
++;
518 for (num
= 1; num
<= lastln
; num
++) {
519 ptr
->l_stat
&= ~LGLOB
;
520 if (line1
<= num
&& num
<= line2
) {
521 strcpy(lin
, ptr
->l_buff
);
523 if (matchs(lin
, glbpat
, 0)) {
524 if (c
== 'g') ptr
->l_stat
|= LGLOB
;
526 if (c
== 'v') ptr
->l_stat
|= LGLOB
;
535 /* #include <stdio.h> */
536 /* #include "tools.h" */
537 /* #include "ed.h" */
539 int deflt(def1
, def2
)
546 if (line1
> line2
|| line1
<= 0) return(ERR
);
551 /* #include <stdio.h> */
552 /* #include "tools.h" */
553 /* #include "ed.h" */
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
) {
569 relink(first
, last
, first
, last
);
570 lastln
-= (to
- from
) + 1;
571 curln
= prevln(from
);
576 /* #include <stdio.h> */
577 /* #include "tools.h" */
578 /* #include "ed.h" */
580 char fname
[MAXFNAME
];
589 static char rhs
[MAXPAT
];
592 int apflg
, pflag
, gflag
;
597 while (*inptr
== SP
&& *inptr
== HT
) inptr
++;
604 if ((line2
= nextln(curln
)) == 0) return(ERR
);
610 case '=': printf("%d\n", line2
); break;
613 if (*inptr
!= NL
|| nlines
> 1) return(ERR
);
615 if (append(line1
, glob
) < 0) return(ERR
);;
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
);
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
);
640 if (nlines
> 0) return(ERR
);
648 if (nlines
> 0) return(ERR
);
650 if (*inptr
!= ' ' && *inptr
!= HT
&& *inptr
!= NL
) return(ERR
);
652 if ((fptr
= getfn()) == NULL
) return(ERR
);
655 if ((err
= doread(0, fptr
)) < 0) return(err
);
662 if (nlines
> 0) return(ERR
);
664 if (*inptr
!= ' ' && *inptr
!= HT
&& *inptr
!= NL
) return(ERR
);
666 if ((fptr
= getfn()) == NULL
) return(ERR
);
669 printf("%s\n", fname
);
675 if (*inptr
!= NL
|| nlines
> 1) return(ERR
);
677 if (append(prevln(line1
), glob
) < 0) return(ERR
);
682 if (*inptr
!= NL
|| deflt(curln
, curln
+ 1) < 0) return(ERR
);
684 if (join(line1
, line2
) < 0) return(ERR
);
688 while (*inptr
== ' ' || *inptr
== HT
) inptr
++;
690 if (*inptr
< 'a' || *inptr
> 'z') return ERR
;
693 if (*inptr
!= ' ' && *inptr
!= HT
&& *inptr
!= NL
) return(ERR
);
695 mark
[c
- 'a'] = line1
;
699 if (*inptr
!= NL
) return(ERR
);
700 if (deflt(curln
, curln
) < 0) return (ERR
);
701 if (dolst(line1
, line2
) < 0) return (ERR
);
705 if ((line3
= getone()) < 0) return(ERR
);
706 if (deflt(curln
, curln
) < 0) return (ERR
);
707 if (move(line3
) < 0) return (ERR
);
713 if (*inptr
!= NL
) return(ERR
);
714 if (deflt(curln
, curln
) < 0) return (ERR
);
715 if (doprnt(line1
, line2
) < 0) return (ERR
);
726 if (*inptr
== NL
&& nlines
== 0 && !glob
)
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
);
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
;
756 if ((line3
= getone()) < 0) return(ERR
);
757 if (deflt(curln
, curln
) < 0) return (ERR
);
758 if (transfer(line3
) < 0) return (ERR
);
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
);
776 if (*inptr
== NL
&& nlines
== 0 && !glob
) {
777 if ((fptr
= getfn()) == NULL
) return(ERR
);
778 if (dowrite(1, lastln
, fptr
, 0) >= 0) return (EOF
);
783 if (deflt(curln
, curln
) < 0) return(ERR
);
787 if (doprnt(line1
- 21, line1
) < 0) return(ERR
);
791 if (doprnt(line1
- 11, line1
+ 10) < 0) return(ERR
);
796 if (doprnt(line1
, line1
+ 21) < 0) return(ERR
);
801 default: return(ERR
);
806 int dolst(line1
, line2
)
809 int oldlflg
= lflg
, p
;
812 p
= doprnt(line1
, line2
);
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
)
839 register int first
, last
;
844 while (*src
&& *src
!= delim
) {
845 if (*src
!= '-') setbit(esc(&src
), map
, 1);
847 else if (src
== start
|| *(src
+ 1) == delim
)
852 if (*src
< *(src
- 2)) {
860 while (++first
<= last
) setbit(first
, map
, 1);
869 /* #include <stdio.h> */
870 /* #include "tools.h" */
871 /* #include "ed.h" */
883 for (lin
= 1; lin
<= lastln
; lin
++) {
884 if (ptr
->l_stat
& LGLOB
) break;
887 if (lin
> lastln
) break;
889 ptr
->l_stat
&= ~LGLOB
;
892 if ((stat
= getlst()) < 0) return(stat
);
893 if ((stat
= docmd(1)) < 0) return (stat
);
899 /* #include <stdio.h> */
900 /* #include "tools.h" */
901 /* #include "ed.h" */
909 from
= from
< 1 ? 1 : from
;
910 to
= to
> lastln
? lastln
: to
;
914 for (i
= from
; i
<= to
; i
++) {
915 prntln(lptr
->l_buff
, lflg
, (nflg
? i
: 0));
923 void prntln(str
, vflg
, lin
)
927 if (lin
) printf("%7d ", lin
);
928 while (*str
&& *str
!= NL
) {
929 if (*str
< ' ' || *str
>= 0x7f) {
933 putcntl(*str
, stdout
);
944 putcntl(*str
, stdout
);
951 if (vflg
) putc('$', stdout
);
955 void putcntl(c
, stream
)
960 putc((c
& 31) | '@', stream
);
964 /* #include <stdio.h> */
965 /* #include "tools.h" */
966 /* #include "ed.h" */
970 int doread(lin
, fname
)
978 static char str
[MAXLINE
];
981 nonascii
= nullchar
= truncated
= 0;
983 if (diag
) printf("\"%s\" ", fname
);
984 if ((fp
= fopen(fname
, "r")) == NULL
) {
985 printf("file open err\n");
989 for (lines
= 0, bytes
= 0; (err
= egets(str
, MAXLINE
, fp
)) > 0;) {
990 bytes
+= strlen(str
);
992 printf("file insert error\n");
999 if (err
< 0) return(err
);
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
);
1011 /* #include <stdio.h> */
1012 /* #include "tools.h" */
1013 /* #include "ed.h" */
1015 int dowrite(from
, to
, fname
, apflg
)
1030 if (diag
) printf("\"%s\" ", fname
);
1031 if ((fp
= fopen(fname
, (apflg
? "a" : "w"))) == NULL
) {
1032 printf("file open error\n");
1035 lptr
= getptr(from
);
1036 for (lin
= from
; lin
<= to
; lin
++) {
1039 bytes
+= strlen(str
) + 1;
1040 if (fputs(str
, fp
) == EOF
) {
1041 printf("file write error\n");
1046 lptr
= lptr
->l_next
;
1048 if (diag
) printf("%d lines %ld bytes\n", lines
, bytes
);
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
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" */
1078 static char inlin
[MAXLINE
];
1080 int line1
, line2
, nlines
;
1081 extern char fname
[];
1092 int main(argc
, argv
)
1096 int stat
, i
, doflush
;
1099 doflush
= isatty(1);
1101 if (argc
> 1 && (strcmp(argv
[1], "-") == 0 || strcmp(argv
[1], "-s") == 0)) {
1107 for (i
= 1; i
< argc
; i
++) {
1108 if (doread(0, argv
[i
]) == 0) {
1110 strcpy(fname
, argv
[i
]);
1117 if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
) signal(SIGINT
, intr
);
1119 if (doflush
) fflush(stdout
);
1121 if (fgets(inlin
, sizeof(inlin
), stdin
) == NULL
) {
1125 inptr
= strchr(inlin
, EOS
);
1126 if (inptr
>= inlin
+2 && inptr
[-2] == '\\' && inptr
[-1] == NL
) {
1128 if (fgets(inptr
, sizeof(inlin
) - (inptr
- inlin
),
1129 stdin
) == NULL
) break;
1134 if (*inlin
== '!') {
1135 if ((inptr
= strchr(inlin
, NL
)) != NULL
) *inptr
= EOS
;
1141 if ((stat
= ckglob()) != 0) {
1142 if (stat
>= 0 && (stat
= doglob()) >= 0) {
1147 if ((stat
= docmd(0)) >= 0) {
1148 if (stat
== 1) doprnt(curln
, curln
);
1155 if (stat
== FATAL
) {
1156 fputs("FATAL ERROR\n", stderr
);
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
)
1179 for (count
= 0, cp
= str
; size
> count
;) {
1185 printf("[Incomplete last line]\n");
1195 if (!eightbit
) /* if not saving eighth bit */
1196 c
= c
& 127; /* strip eigth bit */
1197 nonascii
++; /* count it */
1200 *cp
++ = c
; /* not null, keep it */
1203 nullchar
++; /* count nulls */
1205 str
[count
- 1] = EOS
;
1207 printf("truncating line\n");
1209 while ((c
= getc(stream
)) != EOF
)
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.
1230 if (**s
!= ESCAPE
) {
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;
1250 /* #include <stdio.h> */
1251 /* #include "tools.h" */
1252 /* #include "ed.h" */
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
++) {
1268 num
= (dir
? nextln(num
) : prevln(num
));
1269 ptr
= (dir
? ptr
->l_next
: ptr
->l_prev
);
1271 strcpy(lin
, ptr
->l_buff
);
1273 if (matchs(lin
, pat
, 0)) {
1276 num
= (dir
? nextln(num
) : prevln(num
));
1277 ptr
= (dir
? ptr
->l_next
: ptr
->l_prev
);
1283 /* #include <stdio.h> */
1284 /* #include "tools.h" */
1285 /* #include "ed.h" */
1287 extern char fname
[MAXFNAME
];
1292 static char file
[256];
1297 strcpy(file
, fname
);
1300 while (*inptr
== SP
|| *inptr
== HT
) inptr
++;
1303 while (*inptr
&& *inptr
!= NL
&& *inptr
!= SP
&& *inptr
!= HT
) {
1308 if (strlen(file
) == 0) {
1309 printf("bad file name\n");
1314 if (strlen(file
) == 0) {
1315 printf("no file name\n");
1322 /* #include <stdio.h> */
1323 /* #include "tools.h" */
1324 /* #include "ed.h" */
1331 for (nlines
= 0; (num
= getone()) >= 0;) {
1335 if (*inptr
!= ',' && *inptr
!= ';') break;
1336 if (*inptr
== ';') curln
= num
;
1339 nlines
= min(nlines
, 2);
1340 if (nlines
== 0) line2
= curln
;
1341 if (nlines
<= 1) line1
= line2
;
1350 /* #include <stdio.h> */
1351 /* #include "tools.h" */
1352 /* #include "ed.h" */
1354 int mark
['z' - 'a' + 1];
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';
1372 switch (c
= *inptr
) {
1384 if (*inptr
== c
) inptr
++;
1385 return(find(srchpat
, c
== '/' ? 1 : 0));
1389 return(first
? curln
: 1);
1393 if (*inptr
< 'a' || *inptr
> 'z') return(EOF
);
1395 return mark
[*inptr
++ - 'a'];
1398 return(first
? EOF
: 1);/* unknown address */
1403 /* #include <stdio.h> */
1404 /* #include "tools.h" */
1405 /* #include "ed.h" */
1414 if ((num
= getnum(FIRST
)) >= 0) {
1416 while (*inptr
== SP
|| *inptr
== HT
) inptr
++;
1418 if (*inptr
!= '+' && *inptr
!= '-') break;
1421 if ((i
= getnum(NOTFIRST
)) < 0) return(i
);
1430 return(num
> lastln
? ERR
: num
);
1434 /* #include <stdio.h> */
1435 /* #include "tools.h" */
1437 /* Translate arg into a TOKEN string */
1443 return(makepat(arg
, '\000'));
1447 /* #include <stdio.h> */
1448 /* #include "tools.h" */
1449 /* #include "ed.h" */
1458 if (2 * num
> lastln
&& num
<= lastln
) { /* high line numbers */
1460 for (j
= lastln
; j
> num
; j
--) ptr
= ptr
->l_prev
;
1461 } else { /* low line numbers */
1463 for (j
= 0; j
< num
; j
++) ptr
= ptr
->l_next
;
1469 /* #include <stdio.h> */
1470 /* #include "tools.h" */
1471 /* #include "ed.h" */
1476 if (inptr
[0] == NL
|| inptr
[1] == NL
) /* check for eol */
1479 if (maksub(sub
, MAXPAT
) == NULL
) return(ERR
);
1481 inptr
++; /* skip over delimter */
1482 while (*inptr
== SP
|| *inptr
== HT
) inptr
++;
1483 if (*inptr
== 'g') {
1491 /* #include <stdio.h> */
1492 /* #include "tools.h" */
1493 /* #include "ed.h" */
1500 static char txtbuf
[MAXLINE
];
1503 strcpy(txtbuf
, lin
->l_buff
);
1504 strcat(txtbuf
, "\n");
1509 /* #include <stdio.h> */
1510 /* #include "tools.h" */
1511 /* #include "ed.h" */
1516 char buf
[MAXLINE
], *cp
;
1517 LINE
*new, *cur
, *nxt
;
1521 if ((*cp
= *str
++) == NL
) *cp
= EOS
;
1526 if ((new = (LINE
*) malloc(sizeof(LINE
) + strlen(buf
))) == NULL
)
1527 return(ERR
); /* no memory */
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);
1538 if (*str
== EOS
) /* end of line ? */
1546 /* #include <stdio.h> */
1547 /* #include "tools.h" */
1548 /* #include "ed.h" */
1550 extern int fchanged
;
1552 int join(first
, last
)
1556 char *cp
= buf
, *str
;
1559 if (first
<= 0 || first
> last
|| last
> lastln
) return(ERR
);
1560 if (first
== last
) {
1564 for (num
= first
; num
<= last
; num
++) {
1567 while (*str
!= NL
&& cp
< buf
+ MAXLINE
- 1) *cp
++ = *str
++;
1569 if (cp
== buf
+ MAXLINE
- 1) {
1570 printf("line too long\n");
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.
1608 TOKEN
*head
, *tail
, *ntok
;
1611 /* Check for characters that aren't legal at the beginning of a template. */
1613 if (*arg
== '\0' || *arg
== delim
|| *arg
== '\n' || *arg
== CLOSURE
)
1619 while (*arg
&& *arg
!= delim
&& *arg
!= '\n' && !error
) {
1620 ntok
= (TOKEN
*) malloc(TOKSIZE
);
1621 ntok
->lchar
= '\000';
1625 case ANY
: ntok
->tok
= ANY
; break;
1628 if (head
== 0) /* then this is the first symbol */
1631 ntok
->tok
= LITCHAR
;
1636 if (*(arg
+ 1) == delim
|| *(arg
+ 1) == '\000' ||
1637 *(arg
+ 1) == '\n') {
1640 ntok
->tok
= LITCHAR
;
1647 switch (tail
->tok
) {
1654 ntok
->tok
= CLOSURE
;
1661 if (*(arg
+ 1) == NEGATE
) {
1669 if (ntok
->bitmap
= makebitmap(CLS_SIZE
))
1670 arg
= dodash(CCLEND
, arg
, ntok
->bitmap
);
1672 fprintf(stderr
, "Not enough memory for pat\n");
1678 if (*arg
== ESCAPE
&& *(arg
+ 1) == OPEN
) {
1681 } else if (*arg
== ESCAPE
&& *(arg
+ 1) == CLOSE
) {
1685 ntok
->tok
= LITCHAR
;
1686 ntok
->lchar
= esc(&arg
);
1690 if (error
|| ntok
== 0) {
1693 } else if (head
== 0) {
1694 /* This is the first node in the chain. */
1698 } else if (ntok
->tok
!= CLOSURE
) {
1699 /* Insert at end of list (after tail) */
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
;
1711 /* Only one node in the chain, Insert the CLOSURE
1712 * node at the head of the linked list. */
1726 /* #include <stdio.h> */
1727 /* #include "tools.h" */
1728 /* #include "ed.h" */
1742 for (size
= 0; *inptr
!= delim
&& *inptr
!= NL
&& size
< subsz
; size
++) {
1743 if (*inptr
== '&') {
1746 } else if ((*cp
++ = *inptr
++) == ESCAPE
) {
1747 if (size
>= subsz
) return(NULL
);
1749 switch (toupper(*inptr
)) {
1750 case NL
: *cp
++ = ESCAPE
; break;
1776 if (*++inptr
< '0' || *inptr
> '7')
1779 *cp
= (*cp
<< 3) | (*inptr
- '0');
1783 default: *cp
++ = *inptr
++; break;
1787 if (size
>= subsz
) return(NULL
);
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().
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
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'.
1817 matchs(line
, pat
, ret_endp
)
1833 if (pat
&& pat
->tok
== LITCHAR
) {
1837 if (*line2
!= pat2
->lchar
) {
1839 while (*line2
&& *line2
!= c
) ++line2
;
1841 if (*line2
== '\0') break;
1846 while (pat2
&& pat2
->tok
== LITCHAR
) {
1847 if (*line2
!= pat2
->lchar
) {
1863 if (*line
== '\0') return(0);
1868 if ((rval
= amatch(line2
, pat2
, bptr
)) == 0) {
1869 if (pat
&& pat
->tok
== BOL
) break;
1872 if (rval
> bptr
&& rval
> line
)
1873 rval
--; /* point to last char matched */
1874 rval
= ret_endp
? rval
: line
;
1882 /* #include <stdio.h> */
1883 /* #include "tools.h" */
1884 /* #include "ed.h" */
1889 LINE
*k0
, *k1
, *k2
, *k3
;
1891 if (line1
<= 0 || line2
< line1
|| (line1
<= num
&& num
<= line2
))
1893 k0
= getptr(prevln(line1
));
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);
1906 k3
= getptr(nextln(num
));
1908 relink(k0
, k1
, k2
, k3
);
1909 relink(k2
, k3
, k0
, k1
);
1910 lastln
+= line2
- line1
+ 1;
1918 int mid
, lin
, ntrans
;
1920 if (line1
<= 0 || line1
> line2
) return(ERR
);
1922 mid
= num
< line2
? num
: line2
;
1927 for (lin
= line1
; lin
<= mid
; lin
++) {
1934 for (; lin
<= line2
; lin
+= 2) {
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
)
1958 register int advance
;
1965 if (**linp
== pat
->lchar
) advance
= 1;
1969 if (*linp
== boln
) advance
= 0;
1973 if (**linp
!= '\n') advance
= 1;
1977 if (**linp
== '\n') advance
= 0;
1981 if (testbit(**linp
, pat
->bitmap
)) advance
= 1;
1985 if (!testbit(**linp
, pat
->bitmap
)) advance
= 1;
1989 if (advance
>= 0) *linp
+= advance
;
1995 /* #include <stdio.h> */
1996 /* #include "tools.h" */
1997 /* #include "ed.h" */
2004 char delim
, str
[MAXPAT
], *cp
;
2008 while (*inptr
!= delim
&& *inptr
!= NL
) {
2009 if (*inptr
== ESCAPE
&& inptr
[1] != NL
) *cp
++ = *inptr
++;
2014 if (*str
== EOS
) return(oldpat
);
2015 if (oldpat
) unmakepat(oldpat
);
2016 oldpat
= getpat(str
);
2021 /* #include <stdio.h> */
2022 /* #include "tools.h" */
2023 /* #include "ed.h" */
2031 "number", &nflg
, TRUE
,
2032 "nonumber", &nflg
, FALSE
,
2033 "list", &lflg
, TRUE
,
2034 "nolist", &lflg
, FALSE
,
2035 "eightbit", &eightbit
, TRUE
,
2036 "noeightbit", &eightbit
, FALSE
,
2046 if (*inptr
!= 't') {
2047 if (*inptr
!= SP
&& *inptr
!= HT
&& *inptr
!= NL
) return(ERR
);
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
++;
2058 for (t
= tbl
; t
->t_str
; t
++) {
2059 if (strcmp(word
, t
->t_str
) == 0) {
2060 *t
->t_ptr
= t
->t_val
;
2071 printf("ed version %d.%d\n", version
/ 100, version
% 100);
2072 printf("number %s, list %s\n", nflg
? "ON" : "OFF", lflg
? "ON" : "OFF");
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
;
2095 relink(&line0
, &line0
, &line0
, &line0
);
2100 /* #include <stdio.h> */
2101 /* #include "tools.h" */
2102 /* #include "ed.h" */
2104 int subst(pat
, sub
, gflg
, pflag
)
2109 int lin
, chngd
, nchngd
;
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
);
2122 m
= amatch(txtptr
, pat
, txt
);
2125 if (m
!= NULL
&& lastm
!= m
) {
2127 new = catsub(txtptr
, m
, sub
, new,
2131 if (m
== NULL
|| m
== txtptr
) {
2138 if (new >= buf
+ MAXLINE
) return(ERR
);
2143 if (pflag
) doprnt(curln
, curln
);
2146 if (nchngd
== 0 && !gflg
) {
2153 #define SHELL "/bin/sh"
2154 #define SHELL2 "/usr/bin/sh"
2161 switch (pid
= fork()) {
2165 execl(SHELL
, "sh", "-c", c
, (char *) 0);
2166 execl(SHELL2
, "sh", "-c", c
, (char *) 0);
2168 default: while (wait(&status
) != pid
);
2174 /* #include <stdio.h> */
2175 /* #include "tools.h" */
2177 /* Free up the memory usde for token string */
2178 void unmakepat(head
)
2182 register TOKEN
*old_head
;
2185 switch (head
->tok
) {
2189 /* Fall through to default */
2194 free((char *) old_head
);