added sccs, Bill put in more buffers
[unix-history] / usr / src / usr.bin / ex / ex_subr.c
CommitLineData
b6ea9402
MH
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
11any(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
23backtab(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
37change()
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 */
50column(cp)
51 register char *cp;
52{
53
54 if (cp == 0)
55 cp = &linebuf[LBSIZE - 2];
56 return (qcolumn(cp, (char *) 0));
57}
58
d266c416
MH
59/*
60 * Ignore a comment to the end of the line.
61 * This routine eats the trailing newline so don't call newline().
62 */
63comment()
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
b6ea9402
MH
74Copy(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
85copyw(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
96copywR(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
105ctlof(c)
106 int c;
107{
108
109 return (c == TRIM ? '?' : c | ('A' - 1));
110}
111
112dingdong()
113{
114
115 if (VB)
116 putpad(VB);
117 else if (value(ERRORBELLS))
118 putch('\207');
119}
120
121fixindent(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
137filioerr(cp)
138 char *cp;
139{
140 register int oerrno = errno;
141
142 lprintf("\"%s\"", cp);
143 errno = oerrno;
144 syserror();
145}
146
147char *
148genindent(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
160getDOT()
161{
162
163 getline(*dot);
164}
165
166line *
167getmark(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
179getn(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
191ignnEOF()
192{
193 register int c = getchar();
194
195 if (c == EOF)
196 ungetchar(c);
d266c416
MH
197 else if (c=='"')
198 comment();
b6ea9402
MH
199}
200
201iswhite(c)
202 int c;
203{
204
205 return (c == ' ' || c == '\t');
206}
207
208junk(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
228killed()
229{
230
231 killcnt(addr2 - addr1 + 1);
232}
233
234killcnt(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
255lineno(a)
256 line *a;
257{
258
259 return (a - zero);
260}
261
262lineDOL()
263{
264
265 return (lineno(dol));
266}
267
268lineDOT()
269{
270
271 return (lineno(dot));
272}
273
274markDOT()
275{
276
277 markpr(dot);
278}
279
280markpr(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
291markreg(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 */
308char *
309mesg(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*/
335merror(seekpt, i)
44232d5b 336#ifdef VMUNIX
b6ea9402
MH
337 char *seekpt;
338#else
44232d5b
MH
339# ifdef lint
340 char *seekpt;
341# else
b6ea9402 342 int seekpt;
44232d5b 343# endif
b6ea9402
MH
344#endif
345 int i;
346{
347 register char *cp = linebuf;
348
349 if (seekpt == 0)
350 return;
351 merror1(seekpt);
352 if (*cp == '\n')
353 putnl(), cp++;
354 if (inopen && CE)
355 vclreol();
356 if (SO && SE)
357 putpad(SO);
358 printf(mesg(cp), i);
359 if (SO && SE)
360 putpad(SE);
361}
362
363merror1(seekpt)
44232d5b 364#ifdef VMUNIX
b6ea9402
MH
365 char *seekpt;
366#else
44232d5b
MH
367# ifdef lint
368 char *seekpt;
369# else
b6ea9402 370 int seekpt;
44232d5b 371# endif
b6ea9402
MH
372#endif
373{
374
44232d5b
MH
375#ifdef VMUNIX
376 strcpy(linebuf, seekpt);
377#else
b6ea9402
MH
378 lseek(erfile, (long) seekpt, 0);
379 if (read(erfile, linebuf, 128) < 2)
380 CP(linebuf, "ERROR");
44232d5b 381#endif
b6ea9402
MH
382}
383
384morelines()
385{
386
387 if ((int) sbrk(1024 * sizeof (line)) == -1)
388 return (-1);
389 endcore += 1024;
390 return (0);
391}
392
393nonzero()
394{
395
396 if (addr1 == zero) {
397 notempty();
398 error("Nonzero address required@on this command");
399 }
400}
401
402notable(i)
403 int i;
404{
405
406 return (hush == 0 && !inglobal && i > value(REPORT));
407}
408
409
410notempty()
411{
412
413 if (dol == zero)
414 error("No lines@in the buffer");
415}
416
417
418netchHAD(cnt)
419 int cnt;
420{
421
422 netchange(lineDOL() - cnt);
423}
424
425netchange(i)
426 register int i;
427{
428 register char *cp;
429
430 if (i > 0)
431 notesgn = cp = "more ";
432 else
433 notesgn = cp = "fewer ", i = -i;
434 if (inopen) {
435 notecnt = i;
436 notenam = "";
437 return;
438 }
439 if (!notable(i))
440 return;
441 printf(mesg("%d %slines@in file after %s"), i, cp, Command);
442 putNFL();
443}
444
445putmark(addr)
446 line *addr;
447{
448
449 putmk1(addr, putline());
450}
451
452putmk1(addr, n)
453 register line *addr;
454 int n;
455{
456 register line *markp;
d266c416 457 register oldglobmk;
b6ea9402 458
d266c416 459 oldglobmk = *addr & 1;
b6ea9402
MH
460 *addr &= ~1;
461 for (markp = (anymarks ? names : &names['z'-'a'+1]);
462 markp <= &names['z'-'a'+1]; markp++)
463 if (*markp == *addr)
464 *markp = n;
d266c416 465 *addr = n | oldglobmk;
b6ea9402
MH
466}
467
468char *
469plural(i)
470 long i;
471{
472
473 return (i == 1 ? "" : "s");
474}
475
476int qcount();
477short vcntcol;
478
479qcolumn(lim, gp)
480 register char *lim, *gp;
481{
482 register int x;
483 int (*OO)();
484
485 OO = Outchar;
486 Outchar = qcount;
487 vcntcol = 0;
488 if (lim != NULL)
489 x = lim[1], lim[1] = 0;
490 pline(0);
491 if (lim != NULL)
492 lim[1] = x;
493 if (gp)
494 while (*gp)
495 putchar(*gp++);
496 Outchar = OO;
497 return (vcntcol);
498}
499
500int
501qcount(c)
502 int c;
503{
504
505 if (c == '\t') {
506 vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP);
507 return;
508 }
509 vcntcol++;
510}
511
512reverse(a1, a2)
513 register line *a1, *a2;
514{
515 register line t;
516
517 for (;;) {
518 t = *--a2;
519 if (a2 <= a1)
520 return;
521 *a2 = *a1;
522 *a1++ = t;
523 }
524}
525
526save(a1, a2)
527 line *a1;
528 register line *a2;
529{
530 register int more;
531
887e3e0d
MH
532 if (!FIXUNDO)
533 return;
534#ifdef TRACE
535 if (trace)
536 vudump("before save");
537#endif
b6ea9402
MH
538 undkind = UNDNONE;
539 undadot = dot;
540 more = (a2 - a1 + 1) - (unddol - dol);
541 while (more > (endcore - truedol))
542 if (morelines() < 0)
543 error("Out of memory@saving lines for undo - try using ed or re");
544 if (more)
545 (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1,
546 (truedol - unddol));
547 unddol += more;
548 truedol += more;
549 copyw(dol + 1, a1, a2 - a1 + 1);
550 undkind = UNDALL;
551 unddel = a1 - 1;
552 undap1 = a1;
553 undap2 = a2 + 1;
887e3e0d
MH
554#ifdef TRACE
555 if (trace)
556 vudump("after save");
557#endif
b6ea9402
MH
558}
559
560save12()
561{
562
563 save(addr1, addr2);
564}
565
566saveall()
567{
568
569 save(one, dol);
570}
571
572span()
573{
574
575 return (addr2 - addr1 + 1);
576}
577
578sync()
579{
580
581 chng = 0;
582 tchng = 0;
583 xchng = 0;
584}
585
586
587skipwh()
588{
589 register int wh;
590
591 wh = 0;
592 while (iswhite(peekchar())) {
593 wh++;
594 ignchar();
595 }
596 return (wh);
597}
598
599/*VARARGS2*/
600smerror(seekpt, cp)
601#ifdef lint
602 char *seekpt;
603#else
604 int seekpt;
605#endif
606 char *cp;
607{
608
609 if (seekpt == 0)
610 return;
611 merror1(seekpt);
612 if (inopen && CE)
613 vclreol();
614 if (SO && SE)
615 putpad(SO);
616 lprintf(mesg(linebuf), cp);
617 if (SO && SE)
618 putpad(SE);
619}
620
621#define std_nerrs (sizeof std_errlist / sizeof std_errlist[0])
622
623#define error(i) i
624
625#ifdef lint
626char *std_errlist[] = {
627#else
887e3e0d 628# ifdef VMUNIX
44232d5b 629char *std_errlist[] = {
887e3e0d 630# else
b6ea9402 631short std_errlist[] = {
887e3e0d 632# endif
b6ea9402
MH
633#endif
634 error("Error 0"),
635 error("Not super-user"),
636 error("No such file or directory"),
637 error("No such process"),
638 error("Interrupted system call"),
639 error("Physical I/O error"),
640 error("No such device or address"),
641 error("Argument list too long"),
642 error("Exec format error"),
643 error("Bad file number"),
644 error("No children"),
645 error("No more processes"),
646 error("Not enough core"),
647 error("Permission denied"),
648 error("Bad address"),
649 error("Block device required"),
650 error("Mount device busy"),
651 error("File exists"),
652 error("Cross-device link"),
653 error("No such device"),
654 error("Not a directory"),
655 error("Is a directory"),
656 error("Invalid argument"),
657 error("File table overflow"),
658 error("Too many open files"),
659 error("Not a typewriter"),
660 error("Text file busy"),
661 error("File too large"),
662 error("No space left on device"),
663 error("Illegal seek"),
664 error("Read-only file system"),
665 error("Too many links"),
666 error("Broken pipe")
667#ifndef QUOTA
668 , error("Math argument")
669 , error("Result too large")
670#else
671 , error("Quota exceeded")
672#endif
673};
674
675#undef error
676
677char *
678strend(cp)
679 register char *cp;
680{
681
682 while (*cp)
683 cp++;
684 return (cp);
685}
686
687strcLIN(dp)
688 char *dp;
689{
690
691 CP(linebuf, dp);
692}
693
694syserror()
695{
696 register int e = errno;
697
698 dirtcnt = 0;
699 putchar(' ');
700 if (e >= 0 && errno <= std_nerrs)
701 error(std_errlist[e]);
702 else
703 error("System error %d", e);
704}
705
d266c416
MH
706/*
707 * Return the column number that results from being in column col and
708 * hitting a tab, where tabs are set every ts columns. Work right for
709 * the case where col > COLUMNS, even if ts does not divide COLUMNS.
710 */
711tabcol(col, ts)
712int col, ts;
713{
714 int offset, result;
715
716 if (col >= COLUMNS) {
717 offset = COLUMNS * (col/COLUMNS);
718 col -= offset;
719 } else
720 offset = 0;
721 result = col + ts - (col % ts) + offset;
722 return (result);
723}
724
b6ea9402
MH
725char *
726vfindcol(i)
727 int i;
728{
729 register char *cp;
730 register int (*OO)() = Outchar;
731
732 Outchar = qcount;
733 ignore(qcolumn(linebuf - 1, NOSTR));
734 for (cp = linebuf; *cp && vcntcol < i; cp++)
735 putchar(*cp);
736 if (cp != linebuf)
737 cp--;
738 Outchar = OO;
739 return (cp);
740}
741
742char *
743vskipwh(cp)
744 register char *cp;
745{
746
747 while (iswhite(*cp) && cp[1])
748 cp++;
749 return (cp);
750}
751
752
753char *
754vpastwh(cp)
755 register char *cp;
756{
757
758 while (iswhite(*cp))
759 cp++;
760 return (cp);
761}
762
763whitecnt(cp)
764 register char *cp;
765{
766 register int i;
767
768 i = 0;
769 for (;;)
770 switch (*cp++) {
771
772 case '\t':
773 i += value(TABSTOP) - i % value(TABSTOP);
774 break;
775
776 case ' ':
777 i++;
778 break;
779
780 default:
781 return (i);
782 }
783}
784
785#ifdef lint
786Ignore(a)
787 char *a;
788{
789
790 a = a;
791}
792
793Ignorf(a)
794 int (*a)();
795{
796
797 a = a;
798}
799#endif
800
801markit(addr)
802 line *addr;
803{
804
805 if (addr != dot && addr >= one && addr <= dol)
806 markDOT();
807}