1: /* Copyright (c) 1979 Regents of the University of California */
2: #include "ex.h"
3: #include "ex_re.h"
4: #include "ex_tty.h"
5: #include "ex_vis.h"
6:
7: /*
8: * Random routines, in alphabetical order.
9: */
10:
11: any(c, s)
12: int c;
13: register char *s;
14: {
15: register int x;
16:
17: while (x = *s++)
18: if (x == c)
19: return (1);
20: return (0);
21: }
22:
23: backtab(i)
24: register int i;
25: {
26: register int j;
27:
28: j = i % value(SHIFTWIDTH);
29: if (j == 0)
30: j = value(SHIFTWIDTH);
31: i -= j;
32: if (i < 0)
33: i = 0;
34: return (i);
35: }
36:
37: change()
38: {
39:
40: tchng++;
41: chng = tchng;
42: }
43:
44: /*
45: * Column returns the number of
46: * columns occupied by printing the
47: * characters through position cp of the
48: * current line.
49: */
50: column(cp)
51: register char *cp;
52: {
53:
54: if (cp == 0)
55: cp = &linebuf[LBSIZE - 2];
56: return (qcolumn(cp, (char *) 0));
57: }
58:
59: /*
60: * Ignore a comment to the end of the line.
61: * This routine eats the trailing newline so don't call newline().
62: */
63: ()
64: {
65: register int c;
66:
67: do {
68: c = getchar();
69: } while (c != '\n' && c != EOF);
70: if (c == EOF)
71: ungetchar(c);
72: }
73:
74: Copy(to, from, size)
75: register char *from, *to;
76: register int size;
77: {
78:
79: if (size > 0)
80: do
81: *to++ = *from++;
82: while (--size > 0);
83: }
84:
85: copyw(to, from, size)
86: register line *from, *to;
87: register int size;
88: {
89:
90: if (size > 0)
91: do
92: *to++ = *from++;
93: while (--size > 0);
94: }
95:
96: copywR(to, from, size)
97: register line *from, *to;
98: register int size;
99: {
100:
101: while (--size >= 0)
102: to[size] = from[size];
103: }
104:
105: ctlof(c)
106: int c;
107: {
108:
109: return (c == TRIM ? '?' : c | ('A' - 1));
110: }
111:
112: dingdong()
113: {
114:
115: if (VB)
116: putpad(VB);
117: else if (value(ERRORBELLS))
118: putch('\207');
119: }
120:
121: fixindent(indent)
122: int indent;
123: {
124: register int i;
125: register char *cp;
126:
127: i = whitecnt(genbuf);
128: cp = vpastwh(genbuf);
129: if (*cp == 0 && i == indent && linebuf[0] == 0) {
130: genbuf[0] = 0;
131: return (i);
132: }
133: CP(genindent(i), cp);
134: return (i);
135: }
136:
137: filioerr(cp)
138: char *cp;
139: {
140: register int oerrno = errno;
141:
142: lprintf("\"%s\"", cp);
143: errno = oerrno;
144: syserror();
145: }
146:
147: char *
148: genindent(indent)
149: register int indent;
150: {
151: register char *cp;
152:
153: for (cp = genbuf; indent >= value(TABSTOP); indent -= value(TABSTOP))
154: *cp++ = '\t';
155: for (; indent > 0; indent--)
156: *cp++ = ' ';
157: return (cp);
158: }
159:
160: getDOT()
161: {
162:
163: getline(*dot);
164: }
165:
166: line *
167: getmark(c)
168: register int c;
169: {
170: register line *addr;
171:
172: for (addr = one; addr <= dol; addr++)
173: if (names[c - 'a'] == (*addr &~ 01)) {
174: return (addr);
175: }
176: return (0);
177: }
178:
179: getn(cp)
180: register char *cp;
181: {
182: register int i = 0;
183:
184: while (isdigit(*cp))
185: i = i * 10 + *cp++ - '0';
186: if (*cp)
187: return (0);
188: return (i);
189: }
190:
191: ignnEOF()
192: {
193: register int c = getchar();
194:
195: if (c == EOF)
196: ungetchar(c);
197: else if (c=='"')
198: comment();
199: }
200:
201: iswhite(c)
202: int c;
203: {
204:
205: return (c == ' ' || c == '\t');
206: }
207:
208: junk(c)
209: register int c;
210: {
211:
212: if (c && !value(BEAUTIFY))
213: return (0);
214: if (c >= ' ' && c != TRIM)
215: return (0);
216: switch (c) {
217:
218: case '\t':
219: case '\n':
220: case '\f':
221: return (0);
222:
223: default:
224: return (1);
225: }
226: }
227:
228: killed()
229: {
230:
231: killcnt(addr2 - addr1 + 1);
232: }
233:
234: killcnt(cnt)
235: register int cnt;
236: {
237:
238: if (inopen) {
239: notecnt = cnt;
240: notenam = notesgn = "";
241: return;
242: }
243: if (!notable(cnt))
244: return;
245: printf("%d lines", cnt);
246: if (value(TERSE) == 0) {
247: printf(" %c%s", Command[0] | ' ', Command + 1);
248: if (Command[strlen(Command) - 1] != 'e')
249: putchar('e');
250: putchar('d');
251: }
252: putNFL();
253: }
254:
255: lineno(a)
256: line *a;
257: {
258:
259: return (a - zero);
260: }
261:
262: lineDOL()
263: {
264:
265: return (lineno(dol));
266: }
267:
268: lineDOT()
269: {
270:
271: return (lineno(dot));
272: }
273:
274: markDOT()
275: {
276:
277: markpr(dot);
278: }
279:
280: markpr(which)
281: line *which;
282: {
283:
284: if ((inglobal == 0 || inopen) && which <= endcore) {
285: names['z'-'a'+1] = *which & ~01;
286: if (inopen)
287: ncols['z'-'a'+1] = cursor;
288: }
289: }
290:
291: markreg(c)
292: register int c;
293: {
294:
295: if (c == '\'' || c == '`')
296: return ('z' + 1);
297: if (c >= 'a' && c <= 'z')
298: return (c);
299: return (0);
300: }
301:
302: /*
303: * Mesg decodes the terse/verbose strings. Thus
304: * 'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy'
305: * 'xxx|yyy' -> 'xxx' if terse, else 'yyy'
306: * All others map to themselves.
307: */
308: char *
309: mesg(str)
310: register char *str;
311: {
312: register char *cp;
313:
314: str = strcpy(genbuf, str);
315: for (cp = str; *cp; cp++)
316: switch (*cp) {
317:
318: case '@':
319: if (value(TERSE))
320: *cp = 0;
321: else
322: *cp = ' ';
323: break;
324:
325: case '|':
326: if (value(TERSE) == 0)
327: return (cp + 1);
328: *cp = 0;
329: break;
330: }
331: return (str);
332: }
333:
334: /*VARARGS2*/
335: merror(seekpt, i)
336: #ifdef lint
337: char *seekpt;
338: #else
339: int seekpt;
340: #endif
341: int i;
342: {
343: register char *cp = linebuf;
344:
345: if (seekpt == 0)
346: return;
347: merror1(seekpt);
348: if (*cp == '\n')
349: putnl(), cp++;
350: if (inopen && CE)
351: vclreol();
352: if (SO && SE)
353: putpad(SO);
354: printf(mesg(cp), i);
355: if (SO && SE)
356: putpad(SE);
357: }
358:
359: merror1(seekpt)
360: #ifdef lint
361: char *seekpt;
362: #else
363: int seekpt;
364: #endif
365: {
366:
367: lseek(erfile, (long) seekpt, 0);
368: if (read(erfile, linebuf, 128) < 2)
369: CP(linebuf, "ERROR");
370: }
371:
372: morelines()
373: {
374:
375: if ((int) sbrk(1024 * sizeof (line)) == -1)
376: return (-1);
377: endcore += 1024;
378: return (0);
379: }
380:
381: nonzero()
382: {
383:
384: if (addr1 == zero) {
385: notempty();
386: error("Nonzero address required@on this command");
387: }
388: }
389:
390: notable(i)
391: int i;
392: {
393:
394: return (hush == 0 && !inglobal && i > value(REPORT));
395: }
396:
397:
398: notempty()
399: {
400:
401: if (dol == zero)
402: error("No lines@in the buffer");
403: }
404:
405:
406: netchHAD(cnt)
407: int cnt;
408: {
409:
410: netchange(lineDOL() - cnt);
411: }
412:
413: netchange(i)
414: register int i;
415: {
416: register char *cp;
417:
418: if (i > 0)
419: notesgn = cp = "more ";
420: else
421: notesgn = cp = "fewer ", i = -i;
422: if (inopen) {
423: notecnt = i;
424: notenam = "";
425: return;
426: }
427: if (!notable(i))
428: return;
429: printf(mesg("%d %slines@in file after %s"), i, cp, Command);
430: putNFL();
431: }
432:
433: putmark(addr)
434: line *addr;
435: {
436:
437: putmk1(addr, putline());
438: }
439:
440: putmk1(addr, n)
441: register line *addr;
442: int n;
443: {
444: register line *markp;
445:
446: *addr &= ~1;
447: for (markp = (anymarks ? names : &names['z'-'a'+1]);
448: markp <= &names['z'-'a'+1]; markp++)
449: if (*markp == *addr)
450: *markp = n;
451: *addr = n;
452: }
453:
454: char *
455: plural(i)
456: long i;
457: {
458:
459: return (i == 1 ? "" : "s");
460: }
461:
462: int qcount();
463: short vcntcol;
464:
465: qcolumn(lim, gp)
466: register char *lim, *gp;
467: {
468: register int x;
469: int (*OO)();
470:
471: OO = Outchar;
472: Outchar = qcount;
473: vcntcol = 0;
474: if (lim != NULL)
475: x = lim[1], lim[1] = 0;
476: pline(0);
477: if (lim != NULL)
478: lim[1] = x;
479: if (gp)
480: while (*gp)
481: putchar(*gp++);
482: Outchar = OO;
483: return (vcntcol);
484: }
485:
486: int
487: qcount(c)
488: int c;
489: {
490:
491: if (c == '\t') {
492: vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP);
493: return;
494: }
495: vcntcol++;
496: }
497:
498: reverse(a1, a2)
499: register line *a1, *a2;
500: {
501: register line t;
502:
503: for (;;) {
504: t = *--a2;
505: if (a2 <= a1)
506: return;
507: *a2 = *a1;
508: *a1++ = t;
509: }
510: }
511:
512: save(a1, a2)
513: line *a1;
514: register line *a2;
515: {
516: register int more;
517:
518: undkind = UNDNONE;
519: undadot = dot;
520: more = (a2 - a1 + 1) - (unddol - dol);
521: while (more > (endcore - truedol))
522: if (morelines() < 0)
523: error("Out of memory@saving lines for undo - try using ed or re");
524: if (more)
525: (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1,
526: (truedol - unddol));
527: unddol += more;
528: truedol += more;
529: copyw(dol + 1, a1, a2 - a1 + 1);
530: undkind = UNDALL;
531: unddel = a1 - 1;
532: undap1 = a1;
533: undap2 = a2 + 1;
534: }
535:
536: save12()
537: {
538:
539: save(addr1, addr2);
540: }
541:
542: saveall()
543: {
544:
545: save(one, dol);
546: }
547:
548: span()
549: {
550:
551: return (addr2 - addr1 + 1);
552: }
553:
554: sync()
555: {
556:
557: chng = 0;
558: tchng = 0;
559: xchng = 0;
560: }
561:
562:
563: skipwh()
564: {
565: register int wh;
566:
567: wh = 0;
568: while (iswhite(peekchar())) {
569: wh++;
570: ignchar();
571: }
572: return (wh);
573: }
574:
575: /*VARARGS2*/
576: smerror(seekpt, cp)
577: #ifdef lint
578: char *seekpt;
579: #else
580: int seekpt;
581: #endif
582: char *cp;
583: {
584:
585: if (seekpt == 0)
586: return;
587: merror1(seekpt);
588: if (inopen && CE)
589: vclreol();
590: if (SO && SE)
591: putpad(SO);
592: lprintf(mesg(linebuf), cp);
593: if (SO && SE)
594: putpad(SE);
595: }
596:
597: #define std_nerrs (sizeof std_errlist / sizeof std_errlist[0])
598:
599: #define error(i) i
600:
601: #ifdef lint
602: char *std_errlist[] = {
603: #else
604: short std_errlist[] = {
605: #endif
606: error("Error 0"),
607: error("Not super-user"),
608: error("No such file or directory"),
609: error("No such process"),
610: error("Interrupted system call"),
611: error("Physical I/O error"),
612: error("No such device or address"),
613: error("Argument list too long"),
614: error("Exec format error"),
615: error("Bad file number"),
616: error("No children"),
617: error("No more processes"),
618: error("Not enough core"),
619: error("Permission denied"),
620: error("Bad address"),
621: error("Block device required"),
622: error("Mount device busy"),
623: error("File exists"),
624: error("Cross-device link"),
625: error("No such device"),
626: error("Not a directory"),
627: error("Is a directory"),
628: error("Invalid argument"),
629: error("File table overflow"),
630: error("Too many open files"),
631: error("Not a typewriter"),
632: error("Text file busy"),
633: error("File too large"),
634: error("No space left on device"),
635: error("Illegal seek"),
636: error("Read-only file system"),
637: error("Too many links"),
638: error("Broken pipe"),
639: #ifndef V6
640: error("Math argument"),
641: error("Result too large"),
642: #endif
643: error("Quota exceeded") /* Berkeley quota systems only */
644: };
645:
646: #undef error
647:
648: char *
649: strend(cp)
650: register char *cp;
651: {
652:
653: while (*cp)
654: cp++;
655: return (cp);
656: }
657:
658: strcLIN(dp)
659: char *dp;
660: {
661:
662: CP(linebuf, dp);
663: }
664:
665: syserror()
666: {
667: register int e = errno;
668:
669: dirtcnt = 0;
670: putchar(' ');
671: if (e >= 0 && errno <= std_nerrs)
672: error(std_errlist[e]);
673: else
674: error("System error %d", e);
675: }
676:
677: char *
678: vfindcol(i)
679: int i;
680: {
681: register char *cp;
682: register int (*OO)() = Outchar;
683:
684: Outchar = qcount;
685: ignore(qcolumn(linebuf - 1, NOSTR));
686: for (cp = linebuf; *cp && vcntcol < i; cp++)
687: putchar(*cp);
688: if (cp != linebuf)
689: cp--;
690: Outchar = OO;
691: return (cp);
692: }
693:
694: char *
695: vskipwh(cp)
696: register char *cp;
697: {
698:
699: while (iswhite(*cp) && cp[1])
700: cp++;
701: return (cp);
702: }
703:
704:
705: char *
706: vpastwh(cp)
707: register char *cp;
708: {
709:
710: while (iswhite(*cp))
711: cp++;
712: return (cp);
713: }
714:
715: whitecnt(cp)
716: register char *cp;
717: {
718: register int i;
719:
720: i = 0;
721: for (;;)
722: switch (*cp++) {
723:
724: case '\t':
725: i += value(TABSTOP) - i % value(TABSTOP);
726: break;
727:
728: case ' ':
729: i++;
730: break;
731:
732: default:
733: return (i);
734: }
735: }
736:
737: #ifdef lint
738: Ignore(a)
739: char *a;
740: {
741:
742: a = a;
743: }
744:
745: Ignorf(a)
746: int (*a)();
747: {
748:
749: a = a;
750: }
751: #endif
752:
753: markit(addr)
754: line *addr;
755: {
756:
757: if (addr != dot && addr >= one && addr <= dol)
758: markDOT();
759: }