Commit | Line | Data |
---|---|---|
2791ff57 KB |
1 | /*- |
2 | * Copyright (c) 1980 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.proprietary.c% | |
19d73a0e DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
2791ff57 KB |
9 | static char sccsid[] = "@(#)ex_cmdsub.c 7.12 (Berkeley) %G%"; |
10 | #endif /* not lint */ | |
19d73a0e | 11 | |
4beab9c4 MH |
12 | #include "ex.h" |
13 | #include "ex_argv.h" | |
14 | #include "ex_temp.h" | |
15 | #include "ex_tty.h" | |
d266c416 | 16 | #include "ex_vis.h" |
4beab9c4 MH |
17 | |
18 | /* | |
19 | * Command mode subroutines implementing | |
20 | * append, args, copy, delete, join, move, put, | |
21 | * shift, tag, yank, z and undo | |
22 | */ | |
23 | ||
24 | bool endline = 1; | |
25 | line *tad1; | |
d266c416 | 26 | static jnoop(); |
4beab9c4 MH |
27 | |
28 | /* | |
29 | * Append after line a lines returned by function f. | |
30 | * Be careful about intermediate states to avoid scramble | |
31 | * if an interrupt comes in. | |
32 | */ | |
33 | append(f, a) | |
34 | int (*f)(); | |
35 | line *a; | |
36 | { | |
37 | register line *a1, *a2, *rdot; | |
38 | int nline; | |
39 | ||
40 | nline = 0; | |
41 | dot = a; | |
887e3e0d | 42 | if(FIXUNDO && !inopen && f!=getsub) { |
4beab9c4 MH |
43 | undap1 = undap2 = dot + 1; |
44 | undkind = UNDCHANGE; | |
45 | } | |
46 | while ((*f)() == 0) { | |
47 | if (truedol >= endcore) { | |
48 | if (morelines() < 0) { | |
887e3e0d | 49 | if (FIXUNDO && f == getsub) { |
4beab9c4 MH |
50 | undap1 = addr1; |
51 | undap2 = addr2 + 1; | |
52 | } | |
53 | error("Out of memory@- too many lines in file"); | |
54 | } | |
55 | } | |
56 | nline++; | |
57 | a1 = truedol + 1; | |
58 | a2 = a1 + 1; | |
59 | dot++; | |
60 | undap2++; | |
61 | dol++; | |
62 | unddol++; | |
63 | truedol++; | |
64 | for (rdot = dot; a1 > rdot;) | |
65 | *--a2 = *--a1; | |
66 | *rdot = 0; | |
67 | putmark(rdot); | |
68 | if (f == gettty) { | |
69 | dirtcnt++; | |
70 | TSYNC(); | |
71 | } | |
72 | } | |
73 | return (nline); | |
74 | } | |
75 | ||
76 | appendnone() | |
77 | { | |
78 | ||
887e3e0d | 79 | if(FIXUNDO) { |
4beab9c4 MH |
80 | undkind = UNDCHANGE; |
81 | undap1 = undap2 = addr1; | |
82 | } | |
83 | } | |
84 | ||
85 | /* | |
86 | * Print out the argument list, with []'s around the current name. | |
87 | */ | |
88 | pargs() | |
89 | { | |
90 | register char **av = argv0, *as = args0; | |
91 | register int ac; | |
92 | ||
93 | for (ac = 0; ac < argc0; ac++) { | |
94 | if (ac != 0) | |
5a6c967e | 95 | ex_putchar(' ' | QUOTE); |
4beab9c4 | 96 | if (ac + argc == argc0 - 1) |
5a6c967e | 97 | ex_printf("["); |
4beab9c4 MH |
98 | lprintf("%s", as); |
99 | if (ac + argc == argc0 - 1) | |
5a6c967e | 100 | ex_printf("]"); |
4beab9c4 MH |
101 | as = av ? *++av : strend(as) + 1; |
102 | } | |
103 | noonl(); | |
104 | } | |
105 | ||
106 | /* | |
107 | * Delete lines; two cases are if we are really deleting, | |
108 | * more commonly we are just moving lines to the undo save area. | |
109 | */ | |
5a6c967e | 110 | ex_delete(hush) |
4beab9c4 MH |
111 | bool hush; |
112 | { | |
113 | register line *a1, *a2; | |
114 | ||
115 | nonzero(); | |
887e3e0d | 116 | if(FIXUNDO) { |
d5652bc2 | 117 | register void (*dsavint)(); |
4beab9c4 | 118 | |
04379bab MH |
119 | #ifdef TRACE |
120 | if (trace) | |
121 | vudump("before delete"); | |
122 | #endif | |
4beab9c4 MH |
123 | change(); |
124 | dsavint = signal(SIGINT, SIG_IGN); | |
125 | undkind = UNDCHANGE; | |
126 | a1 = addr1; | |
127 | squish(); | |
128 | a2 = addr2; | |
129 | if (a2++ != dol) { | |
130 | reverse(a1, a2); | |
131 | reverse(a2, dol + 1); | |
132 | reverse(a1, dol + 1); | |
133 | } | |
134 | dol -= a2 - a1; | |
135 | unddel = a1 - 1; | |
136 | if (a1 > dol) | |
137 | a1 = dol; | |
138 | dot = a1; | |
139 | pkill[0] = pkill[1] = 0; | |
140 | signal(SIGINT, dsavint); | |
04379bab MH |
141 | #ifdef TRACE |
142 | if (trace) | |
143 | vudump("after delete"); | |
144 | #endif | |
4beab9c4 MH |
145 | } else { |
146 | register line *a3; | |
147 | register int i; | |
148 | ||
149 | change(); | |
150 | a1 = addr1; | |
151 | a2 = addr2 + 1; | |
152 | a3 = truedol; | |
153 | i = a2 - a1; | |
154 | unddol -= i; | |
155 | undap2 -= i; | |
156 | dol -= i; | |
157 | truedol -= i; | |
158 | do | |
159 | *a1++ = *a2++; | |
160 | while (a2 <= a3); | |
161 | a1 = addr1; | |
162 | if (a1 > dol) | |
163 | a1 = dol; | |
164 | dot = a1; | |
165 | } | |
166 | if (!hush) | |
167 | killed(); | |
168 | } | |
169 | ||
170 | deletenone() | |
171 | { | |
172 | ||
887e3e0d | 173 | if(FIXUNDO) { |
4beab9c4 MH |
174 | undkind = UNDCHANGE; |
175 | squish(); | |
176 | unddel = addr1; | |
177 | } | |
178 | } | |
179 | ||
180 | /* | |
181 | * Crush out the undo save area, moving the open/visual | |
182 | * save area down in its place. | |
183 | */ | |
184 | squish() | |
185 | { | |
186 | register line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1; | |
187 | ||
887e3e0d MH |
188 | if(FIXUNDO) { |
189 | if (inopen == -1) | |
190 | return; | |
191 | if (a1 < a2 && a2 < a3) | |
192 | do | |
193 | *a1++ = *a2++; | |
194 | while (a2 < a3); | |
195 | truedol -= unddol - dol; | |
196 | unddol = dol; | |
197 | } | |
4beab9c4 MH |
198 | } |
199 | ||
200 | /* | |
201 | * Join lines. Special hacks put in spaces, two spaces if | |
202 | * preceding line ends with '.', or no spaces if next line starts with ). | |
203 | */ | |
204 | static int jcount, jnoop(); | |
205 | ||
206 | join(c) | |
207 | int c; | |
208 | { | |
209 | register line *a1; | |
210 | register char *cp, *cp1; | |
211 | ||
212 | cp = genbuf; | |
213 | *cp = 0; | |
214 | for (a1 = addr1; a1 <= addr2; a1++) { | |
215 | getline(*a1); | |
216 | cp1 = linebuf; | |
217 | if (a1 != addr1 && c == 0) { | |
218 | while (*cp1 == ' ' || *cp1 == '\t') | |
219 | cp1++; | |
220 | if (*cp1 && cp > genbuf && cp[-1] != ' ' && cp[-1] != '\t') { | |
221 | if (*cp1 != ')') { | |
222 | *cp++ = ' '; | |
223 | if (cp[-2] == '.') | |
224 | *cp++ = ' '; | |
225 | } | |
226 | } | |
227 | } | |
228 | while (*cp++ = *cp1++) | |
229 | if (cp > &genbuf[LBSIZE-2]) | |
230 | error("Line overflow|Result line of join would be too long"); | |
231 | cp--; | |
232 | } | |
233 | strcLIN(genbuf); | |
5a6c967e | 234 | ex_delete(0); |
4beab9c4 | 235 | jcount = 1; |
d266c416 MH |
236 | if (FIXUNDO) |
237 | undap1 = undap2 = addr1; | |
4beab9c4 | 238 | ignore(append(jnoop, --addr1)); |
d266c416 MH |
239 | if (FIXUNDO) |
240 | vundkind = VMANY; | |
4beab9c4 MH |
241 | } |
242 | ||
243 | static | |
244 | jnoop() | |
245 | { | |
246 | ||
247 | return(--jcount); | |
248 | } | |
249 | ||
250 | /* | |
251 | * Move and copy lines. Hard work is done by move1 which | |
252 | * is also called by undo. | |
253 | */ | |
254 | int getcopy(); | |
255 | ||
256 | move() | |
257 | { | |
258 | register line *adt; | |
259 | bool iscopy = 0; | |
260 | ||
261 | if (Command[0] == 'm') { | |
262 | setdot1(); | |
263 | markpr(addr2 == dot ? addr1 - 1 : addr2 + 1); | |
264 | } else { | |
265 | iscopy++; | |
266 | setdot(); | |
267 | } | |
268 | nonzero(); | |
299f2784 | 269 | adt = address((char*)0); |
4beab9c4 MH |
270 | if (adt == 0) |
271 | serror("%s where?|%s requires a trailing address", Command); | |
272 | newline(); | |
273 | move1(iscopy, adt); | |
274 | killed(); | |
275 | } | |
276 | ||
277 | move1(cflag, addrt) | |
278 | int cflag; | |
279 | line *addrt; | |
280 | { | |
281 | register line *adt, *ad1, *ad2; | |
282 | int lines; | |
283 | ||
284 | adt = addrt; | |
285 | lines = (addr2 - addr1) + 1; | |
286 | if (cflag) { | |
287 | tad1 = addr1; | |
288 | ad1 = dol; | |
289 | ignore(append(getcopy, ad1++)); | |
290 | ad2 = dol; | |
291 | } else { | |
292 | ad2 = addr2; | |
293 | for (ad1 = addr1; ad1 <= ad2;) | |
294 | *ad1++ &= ~01; | |
295 | ad1 = addr1; | |
296 | } | |
297 | ad2++; | |
298 | if (adt < ad1) { | |
299 | if (adt + 1 == ad1 && !cflag && !inglobal) | |
300 | error("That move would do nothing!"); | |
301 | dot = adt + (ad2 - ad1); | |
302 | if (++adt != ad1) { | |
303 | reverse(adt, ad1); | |
304 | reverse(ad1, ad2); | |
305 | reverse(adt, ad2); | |
306 | } | |
307 | } else if (adt >= ad2) { | |
308 | dot = adt++; | |
309 | reverse(ad1, ad2); | |
310 | reverse(ad2, adt); | |
311 | reverse(ad1, adt); | |
312 | } else | |
313 | error("Move to a moved line"); | |
314 | change(); | |
315 | if (!inglobal) | |
887e3e0d MH |
316 | if(FIXUNDO) { |
317 | if (cflag) { | |
318 | undap1 = addrt + 1; | |
319 | undap2 = undap1 + lines; | |
320 | deletenone(); | |
321 | } else { | |
322 | undkind = UNDMOVE; | |
323 | undap1 = addr1; | |
324 | undap2 = addr2; | |
325 | unddel = addrt; | |
326 | squish(); | |
327 | } | |
4beab9c4 MH |
328 | } |
329 | } | |
330 | ||
331 | getcopy() | |
332 | { | |
333 | ||
334 | if (tad1 > addr2) | |
335 | return (EOF); | |
336 | getline(*tad1++); | |
337 | return (0); | |
338 | } | |
339 | ||
340 | /* | |
341 | * Put lines in the buffer from the undo save area. | |
342 | */ | |
343 | getput() | |
344 | { | |
345 | ||
346 | if (tad1 > unddol) | |
347 | return (EOF); | |
348 | getline(*tad1++); | |
349 | tad1++; | |
350 | return (0); | |
351 | } | |
352 | ||
353 | put() | |
354 | { | |
355 | register int cnt; | |
356 | ||
887e3e0d MH |
357 | if (!FIXUNDO) |
358 | error("Cannot put inside global/macro"); | |
4beab9c4 MH |
359 | cnt = unddol - dol; |
360 | if (cnt && inopen && pkill[0] && pkill[1]) { | |
361 | pragged(1); | |
362 | return; | |
363 | } | |
364 | tad1 = dol + 1; | |
365 | ignore(append(getput, addr2)); | |
366 | undkind = UNDPUT; | |
367 | notecnt = cnt; | |
368 | netchange(cnt); | |
369 | } | |
370 | ||
371 | /* | |
372 | * A tricky put, of a group of lines in the middle | |
373 | * of an existing line. Only from open/visual. | |
374 | * Argument says pkills have meaning, e.g. called from | |
375 | * put; it is 0 on calls from putreg. | |
376 | */ | |
377 | pragged(kill) | |
378 | bool kill; | |
379 | { | |
380 | extern char *cursor; | |
381 | register char *gp = &genbuf[cursor - linebuf]; | |
382 | ||
383 | /* | |
384 | * This kind of stuff is TECO's forte. | |
385 | * We just grunge along, since it cuts | |
386 | * across our line-oriented model of the world | |
387 | * almost scrambling our addled brain. | |
388 | */ | |
389 | if (!kill) | |
390 | getDOT(); | |
391 | strcpy(genbuf, linebuf); | |
392 | getline(*unddol); | |
393 | if (kill) | |
394 | *pkill[1] = 0; | |
395 | strcat(linebuf, gp); | |
396 | putmark(unddol); | |
397 | getline(dol[1]); | |
398 | if (kill) | |
399 | strcLIN(pkill[0]); | |
400 | strcpy(gp, linebuf); | |
401 | strcLIN(genbuf); | |
402 | putmark(dol+1); | |
403 | undkind = UNDCHANGE; | |
404 | undap1 = dot; | |
405 | undap2 = dot + 1; | |
406 | unddel = dot - 1; | |
407 | undo(1); | |
408 | } | |
409 | ||
410 | /* | |
411 | * Shift lines, based on c. | |
412 | * If c is neither < nor >, then this is a lisp aligning =. | |
413 | */ | |
414 | shift(c, cnt) | |
415 | int c; | |
416 | int cnt; | |
417 | { | |
418 | register line *addr; | |
419 | register char *cp; | |
420 | char *dp; | |
421 | register int i; | |
422 | ||
887e3e0d | 423 | if(FIXUNDO) |
4beab9c4 MH |
424 | save12(), undkind = UNDCHANGE; |
425 | cnt *= value(SHIFTWIDTH); | |
426 | for (addr = addr1; addr <= addr2; addr++) { | |
427 | dot = addr; | |
428 | #ifdef LISPCODE | |
429 | if (c == '=' && addr == addr1 && addr != addr2) | |
430 | continue; | |
431 | #endif | |
432 | getDOT(); | |
433 | i = whitecnt(linebuf); | |
434 | switch (c) { | |
435 | ||
436 | case '>': | |
437 | if (linebuf[0] == 0) | |
438 | continue; | |
439 | cp = genindent(i + cnt); | |
440 | break; | |
441 | ||
442 | case '<': | |
443 | if (i == 0) | |
444 | continue; | |
445 | i -= cnt; | |
446 | cp = i > 0 ? genindent(i) : genbuf; | |
447 | break; | |
448 | ||
449 | #ifdef LISPCODE | |
450 | default: | |
451 | i = lindent(addr); | |
452 | getDOT(); | |
453 | cp = genindent(i); | |
454 | break; | |
455 | #endif | |
456 | } | |
457 | if (cp + strlen(dp = vpastwh(linebuf)) >= &genbuf[LBSIZE - 2]) | |
458 | error("Line too long|Result line after shift would be too long"); | |
459 | CP(cp, dp); | |
460 | strcLIN(genbuf); | |
461 | putmark(addr); | |
462 | } | |
463 | killed(); | |
464 | } | |
465 | ||
466 | /* | |
467 | * Find a tag in the tags file. | |
468 | * Most work here is in parsing the tags file itself. | |
469 | */ | |
470 | tagfind(quick) | |
471 | bool quick; | |
472 | { | |
473 | char cmdbuf[BUFSIZ]; | |
474 | char filebuf[FNSIZE]; | |
887e3e0d | 475 | char tagfbuf[128]; |
4beab9c4 MH |
476 | register int c, d; |
477 | bool samef = 1; | |
887e3e0d MH |
478 | int tfcount = 0; |
479 | int omagic; | |
480 | char *fn, *fne; | |
43d18593 | 481 | struct stat sbuf; |
6df584e5 JB |
482 | #ifdef FASTTAG |
483 | int iof; | |
484 | char iofbuf[MAXBSIZE]; | |
887e3e0d MH |
485 | long mid; /* assumed byte offset */ |
486 | long top, bot; /* length of tag file */ | |
887e3e0d | 487 | #endif |
4beab9c4 MH |
488 | |
489 | omagic = value(MAGIC); | |
4beab9c4 MH |
490 | if (!skipend()) { |
491 | register char *lp = lasttag; | |
492 | ||
493 | while (!iswhite(peekchar()) && !endcmd(peekchar())) | |
494 | if (lp < &lasttag[sizeof lasttag - 2]) | |
5a6c967e | 495 | *lp++ = ex_getchar(); |
4beab9c4 MH |
496 | else |
497 | ignchar(); | |
498 | *lp++ = 0; | |
499 | if (!endcmd(peekchar())) | |
500 | badtag: | |
501 | error("Bad tag|Give one tag per line"); | |
502 | } else if (lasttag[0] == 0) | |
503 | error("No previous tag"); | |
5a6c967e | 504 | c = ex_getchar(); |
4beab9c4 MH |
505 | if (!endcmd(c)) |
506 | goto badtag; | |
507 | if (c == EOF) | |
508 | ungetchar(c); | |
509 | clrstats(); | |
887e3e0d MH |
510 | |
511 | /* | |
512 | * Loop once for each file in tags "path". | |
513 | */ | |
514 | CP(tagfbuf, svalue(TAGS)); | |
515 | fne = tagfbuf - 1; | |
516 | while (fne) { | |
517 | fn = ++fne; | |
518 | while (*fne && *fne != ' ') | |
519 | fne++; | |
520 | if (*fne == 0) | |
521 | fne = 0; /* done, quit after this time */ | |
522 | else | |
523 | *fne = 0; /* null terminate filename */ | |
6df584e5 JB |
524 | #ifdef FASTTAG |
525 | iof = topen(fn, iofbuf); | |
526 | if (iof == -1) | |
887e3e0d MH |
527 | continue; |
528 | tfcount++; | |
6df584e5 | 529 | fstat(iof, &sbuf); |
887e3e0d | 530 | top = sbuf.st_size; |
6df584e5 | 531 | if (top == 0L ) |
887e3e0d MH |
532 | top = -1L; |
533 | bot = 0L; | |
534 | while (top >= bot) { | |
535 | #else | |
536 | /* | |
537 | * Avoid stdio and scan tag file linearly. | |
538 | */ | |
539 | io = open(fn, 0); | |
540 | if (io<0) | |
541 | continue; | |
d266c416 | 542 | tfcount++; |
43d18593 JB |
543 | if (fstat(io, &sbuf) < 0) |
544 | bsize = LBSIZE; | |
545 | else { | |
546 | bsize = sbuf.st_blksize; | |
547 | if (bsize <= 0) | |
548 | bsize = LBSIZE; | |
549 | } | |
4beab9c4 | 550 | while (getfile() == 0) { |
887e3e0d MH |
551 | #endif |
552 | /* loop for each tags file entry */ | |
4beab9c4 MH |
553 | register char *cp = linebuf; |
554 | register char *lp = lasttag; | |
555 | char *oglobp; | |
556 | ||
6df584e5 | 557 | #ifdef FASTTAG |
887e3e0d | 558 | mid = (top + bot) / 2; |
6df584e5 | 559 | tseek(iof, mid); |
887e3e0d | 560 | if (mid > 0) /* to get first tag in file to work */ |
04379bab | 561 | /* scan to next \n */ |
6df584e5 | 562 | if(tgets(linebuf, sizeof linebuf, iof)==NULL) |
04379bab MH |
563 | goto goleft; |
564 | /* get the line itself */ | |
6df584e5 | 565 | if(tgets(linebuf, sizeof linebuf, iof)==NULL) |
04379bab | 566 | goto goleft; |
6df584e5 | 567 | #ifdef TDEBUG |
5a6c967e | 568 | ex_printf("tag: %o %o %o %s\n", bot, mid, top, linebuf); |
6df584e5 | 569 | #endif |
887e3e0d | 570 | #endif |
4beab9c4 MH |
571 | while (*cp && *lp == *cp) |
572 | cp++, lp++; | |
6df584e5 JB |
573 | if ((*lp || !iswhite(*cp)) && (value(TAGLENGTH)==0 || |
574 | lp-lasttag < value(TAGLENGTH))) { | |
575 | #ifdef FASTTAG | |
887e3e0d MH |
576 | if (*lp > *cp) |
577 | bot = mid + 1; | |
578 | else | |
04379bab | 579 | goleft: |
887e3e0d MH |
580 | top = mid - 1; |
581 | #endif | |
582 | /* Not this tag. Try the next */ | |
4beab9c4 | 583 | continue; |
887e3e0d MH |
584 | } |
585 | ||
586 | /* | |
587 | * We found the tag. Decode the line in the file. | |
588 | */ | |
6df584e5 JB |
589 | #ifdef FASTTAG |
590 | tclose(iof); | |
887e3e0d | 591 | #else |
4beab9c4 | 592 | close(io); |
887e3e0d | 593 | #endif |
d266c416 MH |
594 | /* Rest of tag if abbreviated */ |
595 | while (!iswhite(*cp)) | |
596 | cp++; | |
597 | ||
887e3e0d | 598 | /* name of file */ |
4beab9c4 MH |
599 | while (*cp && iswhite(*cp)) |
600 | cp++; | |
601 | if (!*cp) | |
602 | badtags: | |
603 | serror("%s: Bad tags file entry", lasttag); | |
604 | lp = filebuf; | |
605 | while (*cp && *cp != ' ' && *cp != '\t') { | |
606 | if (lp < &filebuf[sizeof filebuf - 2]) | |
607 | *lp++ = *cp; | |
608 | cp++; | |
609 | } | |
610 | *lp++ = 0; | |
887e3e0d | 611 | |
4beab9c4 MH |
612 | if (*cp == 0) |
613 | goto badtags; | |
614 | if (dol != zero) { | |
615 | /* | |
616 | * Save current position in 't for ^^ in visual. | |
617 | */ | |
618 | names['t'-'a'] = *dot &~ 01; | |
619 | if (inopen) { | |
d266c416 | 620 | extern char *ncols['z'-'a'+2]; |
4beab9c4 MH |
621 | extern char *cursor; |
622 | ||
623 | ncols['t'-'a'] = cursor; | |
624 | } | |
625 | } | |
626 | strcpy(cmdbuf, cp); | |
627 | if (strcmp(filebuf, savedfile) || !edited) { | |
628 | char cmdbuf2[sizeof filebuf + 10]; | |
629 | ||
887e3e0d | 630 | /* Different file. Do autowrite & get it. */ |
4beab9c4 MH |
631 | if (!quick) { |
632 | ckaw(); | |
633 | if (chng && dol > zero) | |
634 | error("No write@since last change (:tag! overrides)"); | |
635 | } | |
636 | oglobp = globp; | |
637 | strcpy(cmdbuf2, "e! "); | |
638 | strcat(cmdbuf2, filebuf); | |
639 | globp = cmdbuf2; | |
640 | d = peekc; ungetchar(0); | |
641 | commands(1, 1); | |
642 | peekc = d; | |
643 | globp = oglobp; | |
44232d5b | 644 | value(MAGIC) = omagic; |
4beab9c4 MH |
645 | samef = 0; |
646 | } | |
887e3e0d MH |
647 | |
648 | /* | |
649 | * Look for pattern in the current file. | |
650 | */ | |
4beab9c4 MH |
651 | oglobp = globp; |
652 | globp = cmdbuf; | |
653 | d = peekc; ungetchar(0); | |
654 | if (samef) | |
655 | markpr(dot); | |
887e3e0d MH |
656 | /* |
657 | * BUG: if it isn't found (user edited header | |
658 | * line) we get left in nomagic mode. | |
659 | */ | |
44232d5b | 660 | value(MAGIC) = 0; |
4beab9c4 MH |
661 | commands(1, 1); |
662 | peekc = d; | |
663 | globp = oglobp; | |
664 | value(MAGIC) = omagic; | |
665 | return; | |
887e3e0d MH |
666 | } /* end of "for each tag in file" */ |
667 | ||
668 | /* | |
669 | * No such tag in this file. Close it and try the next. | |
670 | */ | |
6df584e5 JB |
671 | #ifdef FASTTAG |
672 | tclose(iof); | |
887e3e0d MH |
673 | #else |
674 | close(io); | |
675 | #endif | |
676 | } /* end of "for each file in path" */ | |
677 | if (tfcount <= 0) | |
4beab9c4 | 678 | error("No tags file"); |
887e3e0d MH |
679 | else |
680 | serror("%s: No such tag@in tags file", lasttag); | |
4beab9c4 MH |
681 | } |
682 | ||
683 | /* | |
684 | * Save lines from addr1 thru addr2 as though | |
685 | * they had been deleted. | |
686 | */ | |
687 | yank() | |
688 | { | |
689 | ||
887e3e0d MH |
690 | if (!FIXUNDO) |
691 | error("Can't yank inside global/macro"); | |
4beab9c4 MH |
692 | save12(); |
693 | undkind = UNDNONE; | |
694 | killcnt(addr2 - addr1 + 1); | |
695 | } | |
696 | ||
697 | /* | |
698 | * z command; print windows of text in the file. | |
699 | * | |
700 | * If this seems unreasonably arcane, the reasons | |
701 | * are historical. This is one of the first commands | |
702 | * added to the first ex (then called en) and the | |
703 | * number of facilities here were the major advantage | |
704 | * of en over ed since they allowed more use to be | |
705 | * made of fast terminals w/o typing .,.22p all the time. | |
706 | */ | |
707 | bool zhadpr; | |
708 | bool znoclear; | |
709 | short zweight; | |
710 | ||
711 | zop(hadpr) | |
712 | int hadpr; | |
713 | { | |
714 | register int c, lines, op; | |
715 | bool excl; | |
716 | ||
717 | zhadpr = hadpr; | |
718 | notempty(); | |
719 | znoclear = 0; | |
720 | zweight = 0; | |
721 | excl = exclam(); | |
5a6c967e | 722 | switch (c = op = ex_getchar()) { |
4beab9c4 MH |
723 | |
724 | case '^': | |
725 | zweight = 1; | |
726 | case '-': | |
727 | case '+': | |
728 | while (peekchar() == op) { | |
729 | ignchar(); | |
730 | zweight++; | |
731 | } | |
732 | case '=': | |
733 | case '.': | |
5a6c967e | 734 | c = ex_getchar(); |
4beab9c4 MH |
735 | break; |
736 | ||
737 | case EOF: | |
738 | znoclear++; | |
739 | break; | |
740 | ||
741 | default: | |
742 | op = 0; | |
743 | break; | |
744 | } | |
745 | if (isdigit(c)) { | |
746 | lines = c - '0'; | |
747 | for(;;) { | |
5a6c967e | 748 | c = ex_getchar(); |
4beab9c4 MH |
749 | if (!isdigit(c)) |
750 | break; | |
751 | lines *= 10; | |
752 | lines += c - '0'; | |
753 | } | |
754 | if (lines < LINES) | |
755 | znoclear++; | |
756 | value(WINDOW) = lines; | |
757 | if (op == '=') | |
758 | lines += 2; | |
759 | } else | |
760 | lines = op == EOF ? value(SCROLL) : excl ? LINES - 1 : 2*value(SCROLL); | |
761 | if (inopen || c != EOF) { | |
762 | ungetchar(c); | |
763 | newline(); | |
764 | } | |
765 | addr1 = addr2; | |
766 | if (addr2 == 0 && dot < dol && op == 0) | |
767 | addr1 = addr2 = dot+1; | |
768 | setdot(); | |
769 | zop2(lines, op); | |
770 | } | |
771 | ||
772 | zop2(lines, op) | |
773 | register int lines; | |
774 | register int op; | |
775 | { | |
776 | register line *split; | |
b61c5edc | 777 | static void splitit(); |
4beab9c4 MH |
778 | |
779 | split = NULL; | |
780 | switch (op) { | |
781 | ||
782 | case EOF: | |
783 | if (addr2 == dol) | |
784 | error("\nAt EOF"); | |
785 | case '+': | |
786 | if (addr2 == dol) | |
787 | error("At EOF"); | |
788 | addr2 += lines * zweight; | |
789 | if (addr2 > dol) | |
790 | error("Hit BOTTOM"); | |
791 | addr2++; | |
792 | default: | |
793 | addr1 = addr2; | |
794 | addr2 += lines-1; | |
795 | dot = addr2; | |
796 | break; | |
797 | ||
798 | case '=': | |
799 | case '.': | |
800 | znoclear = 0; | |
801 | lines--; | |
802 | lines >>= 1; | |
803 | if (op == '=') | |
804 | lines--; | |
805 | addr1 = addr2 - lines; | |
806 | if (op == '=') | |
807 | dot = split = addr2; | |
808 | addr2 += lines; | |
809 | if (op == '.') { | |
810 | markDOT(); | |
811 | dot = addr2; | |
812 | } | |
813 | break; | |
814 | ||
815 | case '^': | |
816 | case '-': | |
817 | addr2 -= lines * zweight; | |
818 | if (addr2 < one) | |
819 | error("Hit TOP"); | |
820 | lines--; | |
821 | addr1 = addr2 - lines; | |
822 | dot = addr2; | |
823 | break; | |
824 | } | |
825 | if (addr1 <= zero) | |
826 | addr1 = one; | |
827 | if (addr2 > dol) | |
828 | addr2 = dol; | |
829 | if (dot > dol) | |
830 | dot = dol; | |
831 | if (addr1 > addr2) | |
832 | return; | |
833 | if (op == EOF && zhadpr) { | |
834 | getline(*addr1); | |
5a6c967e | 835 | ex_putchar('\r' | QUOTE); |
4beab9c4 MH |
836 | shudclob = 1; |
837 | } else if (znoclear == 0 && CL != NOSTR && !inopen) { | |
838 | flush1(); | |
839 | vclear(); | |
840 | } | |
841 | if (addr2 - addr1 > 1) | |
842 | pstart(); | |
843 | if (split) { | |
844 | plines(addr1, split - 1, 0); | |
845 | splitit(); | |
846 | plines(split, split, 0); | |
847 | splitit(); | |
848 | addr1 = split + 1; | |
849 | } | |
850 | plines(addr1, addr2, 0); | |
851 | } | |
852 | ||
b61c5edc | 853 | static void |
4beab9c4 MH |
854 | splitit() |
855 | { | |
856 | register int l; | |
857 | ||
858 | for (l = COLUMNS > 80 ? 40 : COLUMNS / 2; l > 0; l--) | |
5a6c967e | 859 | ex_putchar('-'); |
4beab9c4 MH |
860 | putnl(); |
861 | } | |
862 | ||
863 | plines(adr1, adr2, movedot) | |
864 | line *adr1; | |
865 | register line *adr2; | |
866 | bool movedot; | |
867 | { | |
868 | register line *addr; | |
869 | ||
870 | pofix(); | |
871 | for (addr = adr1; addr <= adr2; addr++) { | |
872 | getline(*addr); | |
873 | pline(lineno(addr)); | |
874 | if (inopen) | |
5a6c967e | 875 | ex_putchar('\n' | QUOTE); |
4beab9c4 MH |
876 | if (movedot) |
877 | dot = addr; | |
878 | } | |
879 | } | |
880 | ||
881 | pofix() | |
882 | { | |
883 | ||
884 | if (inopen && Outchar != termchar) { | |
885 | vnfl(); | |
886 | setoutt(); | |
887 | } | |
888 | } | |
889 | ||
890 | /* | |
891 | * Dudley doright to the rescue. | |
892 | * Undo saves the day again. | |
893 | * A tip of the hatlo hat to Warren Teitleman | |
894 | * who made undo as useful as do. | |
895 | * | |
896 | * Command level undo works easily because | |
897 | * the editor has a unique temporary file | |
898 | * index for every line which ever existed. | |
899 | * We don't have to save large blocks of text, | |
900 | * only the indices which are small. We do this | |
901 | * by moving them to after the last line in the | |
902 | * line buffer array, and marking down info | |
903 | * about whence they came. | |
904 | * | |
905 | * Undo is its own inverse. | |
906 | */ | |
907 | undo(c) | |
908 | bool c; | |
909 | { | |
910 | register int i; | |
911 | register line *jp, *kp; | |
912 | line *dolp1, *newdol, *newadot; | |
913 | ||
887e3e0d MH |
914 | #ifdef TRACE |
915 | if (trace) | |
916 | vudump("before undo"); | |
917 | #endif | |
4beab9c4 MH |
918 | if (inglobal && inopen <= 0) |
919 | error("Can't undo in global@commands"); | |
920 | if (!c) | |
921 | somechange(); | |
922 | pkill[0] = pkill[1] = 0; | |
923 | change(); | |
924 | if (undkind == UNDMOVE) { | |
925 | /* | |
926 | * Command to be undone is a move command. | |
927 | * This is handled as a special case by noting that | |
928 | * a move "a,b m c" can be inverted by another move. | |
929 | */ | |
930 | if ((i = (jp = unddel) - undap2) > 0) { | |
931 | /* | |
932 | * when c > b inverse is a+(c-b),c m a-1 | |
933 | */ | |
934 | addr2 = jp; | |
935 | addr1 = (jp = undap1) + i; | |
936 | unddel = jp-1; | |
937 | } else { | |
938 | /* | |
939 | * when b > c inverse is c+1,c+1+(b-a) m b | |
940 | */ | |
941 | addr1 = ++jp; | |
942 | addr2 = jp + ((unddel = undap2) - undap1); | |
943 | } | |
944 | kp = undap1; | |
945 | move1(0, unddel); | |
946 | dot = kp; | |
947 | Command = "move"; | |
948 | killed(); | |
949 | } else { | |
950 | int cnt; | |
951 | ||
952 | newadot = dot; | |
953 | cnt = lineDOL(); | |
954 | newdol = dol; | |
955 | dolp1 = dol + 1; | |
956 | /* | |
957 | * Command to be undone is a non-move. | |
958 | * All such commands are treated as a combination of | |
959 | * a delete command and a append command. | |
960 | * We first move the lines appended by the last command | |
961 | * from undap1 to undap2-1 so that they are just before the | |
962 | * saved deleted lines. | |
963 | */ | |
964 | if ((i = (kp = undap2) - (jp = undap1)) > 0) { | |
965 | if (kp != dolp1) { | |
966 | reverse(jp, kp); | |
967 | reverse(kp, dolp1); | |
968 | reverse(jp, dolp1); | |
969 | } | |
970 | /* | |
971 | * Account for possible backward motion of target | |
972 | * for restoration of saved deleted lines. | |
973 | */ | |
974 | if (unddel >= jp) | |
975 | unddel -= i; | |
976 | newdol -= i; | |
977 | /* | |
978 | * For the case where no lines are restored, dot | |
979 | * is the line before the first line deleted. | |
980 | */ | |
981 | dot = jp-1; | |
982 | } | |
983 | /* | |
984 | * Now put the deleted lines, if any, back where they were. | |
985 | * Basic operation is: dol+1,unddol m unddel | |
986 | */ | |
987 | if (undkind == UNDPUT) { | |
988 | unddel = undap1 - 1; | |
989 | squish(); | |
990 | } | |
991 | jp = unddel + 1; | |
992 | if ((i = (kp = unddol) - dol) > 0) { | |
993 | if (jp != dolp1) { | |
994 | reverse(jp, dolp1); | |
995 | reverse(dolp1, ++kp); | |
996 | reverse(jp, kp); | |
997 | } | |
998 | /* | |
999 | * Account for possible forward motion of the target | |
1000 | * for restoration of the deleted lines. | |
1001 | */ | |
1002 | if (undap1 >= jp) | |
1003 | undap1 += i; | |
1004 | /* | |
1005 | * Dot is the first resurrected line. | |
1006 | */ | |
1007 | dot = jp; | |
1008 | newdol += i; | |
1009 | } | |
1010 | /* | |
1011 | * Clean up so we are invertible | |
1012 | */ | |
1013 | unddel = undap1 - 1; | |
1014 | undap1 = jp; | |
1015 | undap2 = jp + i; | |
1016 | dol = newdol; | |
1017 | netchHAD(cnt); | |
1018 | if (undkind == UNDALL) { | |
1019 | dot = undadot; | |
1020 | undadot = newadot; | |
887e3e0d MH |
1021 | } else |
1022 | undkind = UNDCHANGE; | |
4beab9c4 | 1023 | } |
d266c416 MH |
1024 | /* |
1025 | * Defensive programming - after a munged undadot. | |
1026 | * Also handle empty buffer case. | |
1027 | */ | |
1028 | if ((dot <= zero || dot > dol) && dot != dol) | |
4beab9c4 | 1029 | dot = one; |
887e3e0d MH |
1030 | #ifdef TRACE |
1031 | if (trace) | |
1032 | vudump("after undo"); | |
1033 | #endif | |
4beab9c4 MH |
1034 | } |
1035 | ||
1036 | /* | |
1037 | * Be (almost completely) sure there really | |
1038 | * was a change, before claiming to undo. | |
1039 | */ | |
1040 | somechange() | |
1041 | { | |
1042 | register line *ip, *jp; | |
1043 | ||
1044 | switch (undkind) { | |
1045 | ||
1046 | case UNDMOVE: | |
1047 | return; | |
1048 | ||
1049 | case UNDCHANGE: | |
1050 | if (undap1 == undap2 && dol == unddol) | |
1051 | break; | |
1052 | return; | |
1053 | ||
1054 | case UNDPUT: | |
1055 | if (undap1 != undap2) | |
1056 | return; | |
1057 | break; | |
1058 | ||
1059 | case UNDALL: | |
1060 | if (unddol - dol != lineDOL()) | |
1061 | return; | |
1062 | for (ip = one, jp = dol + 1; ip <= dol; ip++, jp++) | |
1063 | if ((*ip &~ 01) != (*jp &~ 01)) | |
1064 | return; | |
1065 | break; | |
1066 | ||
1067 | case UNDNONE: | |
1068 | error("Nothing to undo"); | |
1069 | } | |
1070 | error("Nothing changed|Last undoable command didn't change anything"); | |
1071 | } | |
1072 | ||
1073 | /* | |
1074 | * Map command: | |
1075 | * map src dest | |
1076 | */ | |
d266c416 | 1077 | mapcmd(un, ab) |
4beab9c4 | 1078 | int un; /* true if this is unmap command */ |
d266c416 | 1079 | int ab; /* true if this is abbr command */ |
4beab9c4 | 1080 | { |
d266c416 | 1081 | char lhs[100], rhs[100]; /* max sizes resp. */ |
4beab9c4 | 1082 | register char *p; |
299f2784 | 1083 | register int c; /* mjm: char --> int */ |
4beab9c4 | 1084 | char *dname; |
887e3e0d | 1085 | struct maps *mp; /* the map structure we are working on */ |
4beab9c4 | 1086 | |
d266c416 | 1087 | mp = ab ? abbrevs : exclam() ? immacs : arrows; |
4beab9c4 MH |
1088 | if (skipend()) { |
1089 | int i; | |
1090 | ||
1091 | /* print current mapping values */ | |
1092 | if (peekchar() != EOF) | |
1093 | ignchar(); | |
d266c416 MH |
1094 | if (un) |
1095 | error("Missing lhs"); | |
4beab9c4 MH |
1096 | if (inopen) |
1097 | pofix(); | |
887e3e0d MH |
1098 | for (i=0; mp[i].mapto; i++) |
1099 | if (mp[i].cap) { | |
1100 | lprintf("%s", mp[i].descr); | |
5a6c967e | 1101 | ex_putchar('\t'); |
887e3e0d | 1102 | lprintf("%s", mp[i].cap); |
5a6c967e | 1103 | ex_putchar('\t'); |
887e3e0d | 1104 | lprintf("%s", mp[i].mapto); |
4beab9c4 MH |
1105 | putNFL(); |
1106 | } | |
1107 | return; | |
1108 | } | |
1109 | ||
1110 | ignore(skipwh()); | |
1111 | for (p=lhs; ; ) { | |
5a6c967e | 1112 | c = ex_getchar(); |
65bacefd | 1113 | if (c == CTRL('v')) { |
5a6c967e | 1114 | c = ex_getchar(); |
d266c416 MH |
1115 | } else if (!un && any(c, " \t")) { |
1116 | /* End of lhs */ | |
1117 | break; | |
1118 | } else if (endcmd(c) && c!='"') { | |
4beab9c4 MH |
1119 | ungetchar(c); |
1120 | if (un) { | |
1121 | newline(); | |
d266c416 | 1122 | *p = 0; |
887e3e0d | 1123 | addmac(lhs, NOSTR, NOSTR, mp); |
4beab9c4 MH |
1124 | return; |
1125 | } else | |
1126 | error("Missing rhs"); | |
1127 | } | |
1128 | *p++ = c; | |
1129 | } | |
1130 | *p = 0; | |
1131 | ||
1132 | if (skipend()) | |
1133 | error("Missing rhs"); | |
1134 | for (p=rhs; ; ) { | |
5a6c967e | 1135 | c = ex_getchar(); |
65bacefd | 1136 | if (c == CTRL('v')) { |
5a6c967e | 1137 | c = ex_getchar(); |
d266c416 | 1138 | } else if (endcmd(c) && c!='"') { |
4beab9c4 MH |
1139 | ungetchar(c); |
1140 | break; | |
1141 | } | |
1142 | *p++ = c; | |
1143 | } | |
1144 | *p = 0; | |
1145 | newline(); | |
1146 | /* | |
1147 | * Special hack for function keys: #1 means key f1, etc. | |
1148 | * If the terminal doesn't have function keys, we just use #1. | |
1149 | */ | |
1150 | if (lhs[0] == '#') { | |
1151 | char *fnkey; | |
1152 | char *fkey(); | |
1153 | char funkey[3]; | |
1154 | ||
1155 | fnkey = fkey(lhs[1] - '0'); | |
1156 | funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0; | |
1157 | if (fnkey) | |
1158 | strcpy(lhs, fnkey); | |
1159 | dname = funkey; | |
1160 | } else { | |
1161 | dname = lhs; | |
1162 | } | |
887e3e0d | 1163 | addmac(lhs,rhs,dname,mp); |
4beab9c4 MH |
1164 | } |
1165 | ||
1166 | /* | |
1167 | * Add a macro definition to those that already exist. The sequence of | |
1168 | * chars "src" is mapped into "dest". If src is already mapped into something | |
1169 | * this overrides the mapping. There is no recursion. Unmap is done by | |
887e3e0d MH |
1170 | * using NOSTR for dest. Dname is what to show in listings. mp is |
1171 | * the structure to affect (arrows, etc). | |
4beab9c4 | 1172 | */ |
887e3e0d | 1173 | addmac(src,dest,dname,mp) |
4beab9c4 | 1174 | register char *src, *dest, *dname; |
887e3e0d | 1175 | register struct maps *mp; |
4beab9c4 MH |
1176 | { |
1177 | register int slot, zer; | |
1178 | ||
d266c416 MH |
1179 | #ifdef TRACE |
1180 | if (trace) | |
1181 | fprintf(trace, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src, dest, dname, mp); | |
1182 | #endif | |
887e3e0d | 1183 | if (dest && mp==arrows) { |
4beab9c4 MH |
1184 | /* Make sure user doesn't screw himself */ |
1185 | /* | |
44232d5b MH |
1186 | * Prevent tail recursion. We really should be |
1187 | * checking to see if src is a suffix of dest | |
887e3e0d MH |
1188 | * but this makes mapping involving escapes that |
1189 | * is reasonable mess up. | |
4beab9c4 | 1190 | */ |
44232d5b MH |
1191 | if (src[1] == 0 && src[0] == dest[strlen(dest)-1]) |
1192 | error("No tail recursion"); | |
4beab9c4 MH |
1193 | /* |
1194 | * We don't let the user rob himself of ":", and making | |
1195 | * multi char words is a bad idea so we don't allow it. | |
1196 | * Note that if user sets mapinput and maps all of return, | |
1197 | * linefeed, and escape, he can screw himself. This is | |
1198 | * so weird I don't bother to check for it. | |
1199 | */ | |
1200 | if (isalpha(src[0]) && src[1] || any(src[0],":")) | |
1201 | error("Too dangerous to map that"); | |
4beab9c4 | 1202 | } |
887e3e0d MH |
1203 | else if (dest) { |
1204 | /* check for tail recursion in input mode: fussier */ | |
1205 | if (eq(src, dest+strlen(dest)-strlen(src))) | |
1206 | error("No tail recursion"); | |
1207 | } | |
1208 | /* | |
1209 | * If the src were null it would cause the dest to | |
1210 | * be mapped always forever. This is not good. | |
1211 | */ | |
1212 | if (src == NOSTR || src[0] == 0) | |
1213 | error("Missing lhs"); | |
4beab9c4 MH |
1214 | |
1215 | /* see if we already have a def for src */ | |
1216 | zer = -1; | |
887e3e0d MH |
1217 | for (slot=0; mp[slot].mapto; slot++) { |
1218 | if (mp[slot].cap) { | |
d266c416 | 1219 | if (eq(src, mp[slot].cap) || eq(src, mp[slot].mapto)) |
4beab9c4 MH |
1220 | break; /* if so, reuse slot */ |
1221 | } else { | |
1222 | zer = slot; /* remember an empty slot */ | |
1223 | } | |
1224 | } | |
1225 | ||
1226 | if (dest == NOSTR) { | |
1227 | /* unmap */ | |
887e3e0d MH |
1228 | if (mp[slot].cap) { |
1229 | mp[slot].cap = NOSTR; | |
1230 | mp[slot].descr = NOSTR; | |
4beab9c4 MH |
1231 | } else { |
1232 | error("Not mapped|That macro wasn't mapped"); | |
1233 | } | |
1234 | return; | |
1235 | } | |
1236 | ||
1237 | /* reuse empty slot, if we found one and src isn't already defined */ | |
887e3e0d | 1238 | if (zer >= 0 && mp[slot].mapto == 0) |
4beab9c4 MH |
1239 | slot = zer; |
1240 | ||
1241 | /* if not, append to end */ | |
1242 | if (slot >= MAXNOMACS) | |
1243 | error("Too many macros"); | |
1244 | if (msnext == 0) /* first time */ | |
1245 | msnext = mapspace; | |
1246 | /* Check is a bit conservative, we charge for dname even if reusing src */ | |
1247 | if (msnext - mapspace + strlen(dest) + strlen(src) + strlen(dname) + 3 > MAXCHARMACS) | |
1248 | error("Too much macro text"); | |
1249 | CP(msnext, src); | |
887e3e0d | 1250 | mp[slot].cap = msnext; |
4beab9c4 MH |
1251 | msnext += strlen(src) + 1; /* plus 1 for null on the end */ |
1252 | CP(msnext, dest); | |
887e3e0d | 1253 | mp[slot].mapto = msnext; |
4beab9c4 MH |
1254 | msnext += strlen(dest) + 1; |
1255 | if (dname) { | |
1256 | CP(msnext, dname); | |
887e3e0d | 1257 | mp[slot].descr = msnext; |
4beab9c4 MH |
1258 | msnext += strlen(dname) + 1; |
1259 | } else { | |
1260 | /* default descr to string user enters */ | |
887e3e0d | 1261 | mp[slot].descr = src; |
4beab9c4 MH |
1262 | } |
1263 | } | |
1264 | ||
1265 | /* | |
1266 | * Implements macros from command mode. c is the buffer to | |
1267 | * get the macro from. | |
1268 | */ | |
1269 | cmdmac(c) | |
1270 | char c; | |
1271 | { | |
1272 | char macbuf[BUFSIZ]; | |
1273 | line *ad, *a1, *a2; | |
1274 | char *oglobp; | |
b8c3ed58 | 1275 | short pk; |
4beab9c4 MH |
1276 | bool oinglobal; |
1277 | ||
1278 | lastmac = c; | |
1279 | oglobp = globp; | |
1280 | oinglobal = inglobal; | |
1281 | pk = peekc; peekc = 0; | |
1282 | if (inglobal < 2) | |
1283 | inglobal = 1; | |
1284 | regbuf(c, macbuf, sizeof(macbuf)); | |
1285 | a1 = addr1; a2 = addr2; | |
1286 | for (ad=a1; ad<=a2; ad++) { | |
1287 | globp = macbuf; | |
1288 | dot = ad; | |
1289 | commands(1,1); | |
1290 | } | |
1291 | globp = oglobp; | |
1292 | inglobal = oinglobal; | |
1293 | peekc = pk; | |
1294 | } |