# 2.11BSD#431 - /usr/src/ucb/ex/ex_vmain.c

##### Functions

    grabtag           X
    prepapp           X
    vmain             X
    vremote           X
    vsave             X
    vzop              X

##### Macros

    forbid            X

       1: /*
       2:  * Copyright (c) 1980 Regents of the University of California.
       3:  * All rights reserved.  The Berkeley software License Agreement
       4:  * specifies the terms and conditions for redistribution.
       5:  */
       6:
       7: #if !defined(lint) && defined(DOSCCS)
       8: static char *sccsid = "@(#)ex_vmain.c	7.7 (Berkeley) 6/7/85";
       9: #endif
      10:
      11: #include "ex.h"
      12: #include "ex_tty.h"
      13: #include "ex_vis.h"
      14:
      15: /*
      16:  * This is the main routine for visual.
      17:  * We here decode the count and possible named buffer specification
      18:  * preceding a command and interpret a few of the commands.
      19:  * Commands which involve a target (i.e. an operator) are decoded
      20:  * in the routine operate in ex_voperate.c.
      21:  */
      22:
      23: #define forbid(a)   { if (a) goto fonfon; }
      24:
      25: vmain()
      26: {
      27:     register int c, cnt, i;
      28:     char esave[TUBECOLS];
      29:     char *oglobp;
      30:     short d;
      31:     line *addr;
      32:     int ind, nlput;
      33:     int shouldpo = 0;
      34:     int onumber, olist, (*OPline)(), (*OPutchar)();
      35:
      36:     vch_mac = VC_NOTINMAC;
      37:
      38:     /*
      39: 	 * If we started as a vi command (on the command line)
      40: 	 * then go process initial commands (recover, next or tag).
      41: 	 */
      42:     if (initev) {
      43:         oglobp = globp;
      44:         globp = initev;
      45:         hadcnt = cnt = 0;
      46:         i = tchng;
      47:         addr = dot;
      48:         goto doinit;
      49:     }
      50:
      51:     /*
      52: 	 * NB:
      53: 	 *
      54: 	 * The current line is always in the line buffer linebuf,
      55: 	 * and the cursor at the position cursor.  You should do
      56: 	 * a vsave() before moving off the line to make sure the disk
      57: 	 * copy is updated if it has changed, and a getDOT() to get
      58: 	 * the line back if you mung linebuf.  The motion
      59: 	 * routines in ex_vwind.c handle most of this.
      60: 	 */
      61:     for (;;) {
      62:         /*
      63: 		 * Decode a visual command.
      64: 		 * First sync the temp file if there has been a reasonable
      65: 		 * amount of change.  Clear state for decoding of next
      66: 		 * command.
      67: 		 */
      68:         TSYNC();
      69:         vglobp = 0;
      70:         vreg = 0;
      71:         hold = 0;
      72:         seenprompt = 1;
      73:         wcursor = 0;
      74:         Xhadcnt = hadcnt = 0;
      75:         Xcnt = cnt = 1;
      76:         splitw = 0;
      77:         if (i = holdupd) {
      78:             if (state == VISUAL)
      79:                 ignore(peekkey());
      80:             holdupd = 0;
      81: /*
      82: 			if (LINE(0) < ZERO) {
      83: 				vclear();
      84: 				vcnt = 0;
      85: 				i = 3;
      86: 			}
      87: */
      88:             if (state != VISUAL) {
      89:                 vcnt = 0;
      90:                 vsave();
      91:                 vrepaint(cursor);
      92:             } else if (i == 3)
      93:                 vredraw(WTOP);
      94:             else
      95:                 vsync(WTOP);
      96:             vfixcurs();
      97:         }
      98:
      99:         /*
     100: 		 * Gobble up counts and named buffer specifications.
     101: 		 */
     102:         for (;;) {
     103: looptop:
     104: #ifdef MDEBUG
     105:             if (trace)
     106:                 fprintf(trace, "pc=%c",peekkey());
     107: #endif
     108:             if (isdigit(peekkey()) && peekkey() != '0') {
     109:                 hadcnt = 1;
     110:                 cnt = vgetcnt();
     111:                 forbid (cnt <= 0);
     112:             }
     113:             if (peekkey() != '"')
     114:                 break;
     115:             ignore(getkey()), c = getkey();
     116:             /*
     117: 			 * Buffer names be letters or digits.
     118: 			 * But not '0' as that is the source of
     119: 			 * an 'empty' named buffer spec in the routine
     120: 			 * kshift (see ex_temp.c).
     121: 			 */
     122:             forbid (c == '0' || !isalpha(c) && !isdigit(c));
     123:             vreg = c;
     124:         }
     125: reread:
     126:         /*
     127: 		 * Come to reread from below after some macro expansions.
     128: 		 * The call to map allows use of function key pads
     129: 		 * by performing a terminal dependent mapping of inputs.
     130: 		 */
     131: #ifdef MDEBUG
     132:         if (trace)
     133:             fprintf(trace,"pcb=%c,",peekkey());
     134: #endif
     135:         op = getkey();
     136:         maphopcnt = 0;
     137:         do {
     138:             /*
     139: 			 * Keep mapping the char as long as it changes.
     140: 			 * This allows for double mappings, e.g., q to #,
     141: 			 * #1 to something else.
     142: 			 */
     143:             c = op;
     144:             op = map(c,arrows);
     145: #ifdef MDEBUG
     146:             if (trace)
     147:                 fprintf(trace,"pca=%c,",c);
     148: #endif
     149:             /*
     150: 			 * Maybe the mapped to char is a count. If so, we have
     151: 			 * to go back to the "for" to interpret it. Likewise
     152: 			 * for a buffer name.
     153: 			 */
     154:             if ((isdigit(c) && c!='0') || c == '"') {
     155:                 ungetkey(c);
     156:                 goto looptop;
     157:             }
     158:             if (!value(REMAP)) {
     159:                 c = op;
     160:                 break;
     161:             }
     162:             if (++maphopcnt > 256)
     163:                 error("Infinite macro loop");
     164:         } while (c != op);
     165:
     166:         /*
     167: 		 * Begin to build an image of this command for possible
     168: 		 * later repeat in the buffer workcmd.  It will be copied
     169: 		 * to lastcmd by the routine setLAST
     170: 		 * if/when completely specified.
     171: 		 */
     172:         lastcp = workcmd;
     173:         if (!vglobp)
     174:             *lastcp++ = c;
     175:
     176:         /*
     177: 		 * First level command decode.
     178: 		 */
     179:         switch (c) {
     180:
     181:         /*
     182: 		 * ^L		Clear screen e.g. after transmission error.
     183: 		 */
     184:
     185:         /*
     186: 		 * ^R		Retype screen, getting rid of @ lines.
     187: 		 *		If in open, equivalent to ^L.
     188: 		 *		On terminals where the right arrow key sends
     189: 		 *		^L we make ^R act like ^L, since there is no
     190: 		 *		way to get ^L.  These terminals (adm31, tvi)
     191: 		 *		are intelligent so ^R is useless.  Soroc
     192: 		 *		will probably foul this up, but nobody has
     193: 		 *		one of them.
     194: 		 */
     195:         case CTRL(l):
     196:         case CTRL(r):
     197:             if (c == CTRL(l) || (KR && *KR==CTRL(l))) {
     198:                 vclear();
     199:                 vdirty(0, vcnt);
     200:             }
     201:             if (state != VISUAL) {
     202:                 /*
     203: 				 * Get a clean line, throw away the
     204: 				 * memory of what is displayed now,
     205: 				 * and move back onto the current line.
     206: 				 */
     207:                 vclean();
     208:                 vcnt = 0;
     209:                 vmoveto(dot, cursor, 0);
     210:                 continue;
     211:             }
     212:             vredraw(WTOP);
     213:             /*
     214: 			 * Weird glitch -- when we enter visual
     215: 			 * in a very small window we may end up with
     216: 			 * no lines on the screen because the line
     217: 			 * at the top is too long.  This forces the screen
     218: 			 * to be expanded to make room for it (after
     219: 			 * we have printed @'s ick showing we goofed).
     220: 			 */
     221:             if (vcnt == 0)
     222:                 vrepaint(cursor);
     223:             vfixcurs();
     224:             continue;
     225:
     226:         /*
     227: 		 * $		Escape just cancels the current command
     228: 		 *		with a little feedback.
     229: 		 */
     230:         case ESCAPE:
     231:             beep();
     232:             continue;
     233:
     234:         /*
     235: 		 * @   		Macros. Bring in the macro and put it
     236: 		 *		in vmacbuf, point vglobp there and punt.
     237: 		 */
     238:          case '@':
     239:             c = getesc();
     240:             if (c == 0)
     241:                 continue;
     242:             if (c == '@')
     243:                 c = lastmac;
     244:             if (isupper(c))
     245:                 c = tolower(c);
     246:             forbid(!islower(c));
     247:             lastmac = c;
     248:             vsave();
     249:             CATCH
     250:                 char tmpbuf[BUFSIZ];
     251:
     252:                 regbuf(c,tmpbuf,sizeof(vmacbuf));
     253:                 macpush(tmpbuf, 1);
     254:             ONERR
     255:                 lastmac = 0;
     256:                 splitw = 0;
     257:                 getDOT();
     258:                 vrepaint(cursor);
     259:                 continue;
     260:             ENDCATCH
     261:             vmacp = vmacbuf;
     262:             goto reread;
     263:
     264:         /*
     265: 		 * .		Repeat the last (modifying) open/visual command.
     266: 		 */
     267:         case '.':
     268:             /*
     269: 			 * Check that there was a last command, and
     270: 			 * take its count and named buffer unless they
     271: 			 * were given anew.  Special case if last command
     272: 			 * referenced a numeric named buffer -- increment
     273: 			 * the number and go to a named buffer again.
     274: 			 * This allows a sequence like "1pu.u.u...
     275: 			 * to successively look for stuff in the kill chain
     276: 			 * much as one does in EMACS with C-Y and M-Y.
     277: 			 */
     278:             forbid (lastcmd[0] == 0);
     279:             if (hadcnt)
     280:                 lastcnt = cnt;
     281:             if (vreg)
     282:                 lastreg = vreg;
     283:             else if (isdigit(lastreg) && lastreg < '9')
     284:                 lastreg++;
     285:             vreg = lastreg;
     286:             cnt = lastcnt;
     287:             hadcnt = lasthad;
     288:             vglobp = lastcmd;
     289:             goto reread;
     290:
     291:         /*
     292: 		 * ^U		Scroll up.  A count sticks around for
     293: 		 *		future scrolls as the scroll amount.
     294: 		 *		Attempt to hold the indentation from the
     295: 		 *		top of the screen (in logical lines).
     296: 		 *
     297: 		 * BUG:		A ^U near the bottom of the screen
     298: 		 *		on a dumb terminal (which can't roll back)
     299: 		 *		causes the screen to be cleared and then
     300: 		 *		redrawn almost as it was.  In this case
     301: 		 *		one should simply move the cursor.
     302: 		 */
     303:         case CTRL(u):
     304:             if (hadcnt)
     305:                 vSCROLL = cnt;
     306:             cnt = vSCROLL;
     307:             if (state == VISUAL)
     308:                 ind = vcline, cnt += ind;
     309:             else
     310:                 ind = 0;
     311:             vmoving = 0;
     312:             vup(cnt, ind, 1);
     313:             vnline(NOSTR);
     314:             continue;
     315:
     316:         /*
     317: 		 * ^D		Scroll down.  Like scroll up.
     318: 		 */
     319:         case CTRL(d):
     320: #ifdef TRACE
     321:         if (trace)
     322:             fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
     323: #endif
     324:             if (hadcnt)
     325:                 vSCROLL = cnt;
     326:             cnt = vSCROLL;
     327:             if (state == VISUAL)
     328:                 ind = vcnt - vcline - 1, cnt += ind;
     329:             else
     330:                 ind = 0;
     331:             vmoving = 0;
     332:             vdown(cnt, ind, 1);
     333: #ifdef TRACE
     334:         if (trace)
     335:             fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
     336: #endif
     337:             vnline(NOSTR);
     338: #ifdef TRACE
     339:         if (trace)
     340:             fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
     341: #endif
     342:             continue;
     343:
     344:         /*
     345: 		 * ^E		Glitch the screen down (one) line.
     346: 		 *		Cursor left on same line in file.
     347: 		 */
     348:         case CTRL(e):
     349:             if (state != VISUAL)
     350:                 continue;
     351:             if (!hadcnt)
     352:                 cnt = 1;
     353:             /* Bottom line of file already on screen */
     354:             forbid(lineDOL()-lineDOT() <= vcnt-1-vcline);
     355:             ind = vcnt - vcline - 1 + cnt;
     356:             vdown(ind, ind, 1);
     357:             vnline(cursor);
     358:             continue;
     359:
     360:         /*
     361: 		 * ^Y		Like ^E but up
     362: 		 */
     363:         case CTRL(y):
     364:             if (state != VISUAL)
     365:                 continue;
     366:             if (!hadcnt)
     367:                 cnt = 1;
     368:             forbid(lineDOT()-1<=vcline); /* line 1 already there */
     369:             ind = vcline + cnt;
     370:             vup(ind, ind, 1);
     371:             vnline(cursor);
     372:             continue;
     373:
     374:
     375:         /*
     376: 		 * m		Mark position in mark register given
     377: 		 *		by following letter.  Return is
     378: 		 *		accomplished via ' or `; former
     379: 		 *		to beginning of line where mark
     380: 		 *		was set, latter to column where marked.
     381: 		 */
     382:         case 'm':
     383:             /*
     384: 			 * Getesc is generally used when a character
     385: 			 * is read as a latter part of a command
     386: 			 * to allow one to hit rubout/escape to cancel
     387: 			 * what you have typed so far.  These characters
     388: 			 * are mapped to 0 by the subroutine.
     389: 			 */
     390:             c = getesc();
     391:             if (c == 0)
     392:                 continue;
     393:
     394:             /*
     395: 			 * Markreg checks that argument is a letter
     396: 			 * and also maps ' and ` to the end of the range
     397: 			 * to allow '' or `` to reference the previous
     398: 			 * context mark.
     399: 			 */
     400:             c = markreg(c);
     401:             forbid (c == 0);
     402:             vsave();
     403:             names[c - 'a'] = (*dot &~ 01);
     404:             ncols[c - 'a'] = cursor;
     405:             anymarks = 1;
     406:             continue;
     407:
     408:         /*
     409: 		 * ^F		Window forwards, with 2 lines of continuity.
     410: 		 *		Count repeats.
     411: 		 */
     412:         case CTRL(f):
     413:             vsave();
     414:             if (vcnt > 2) {
     415:                 addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES;
     416:                 forbid(addr > dol);
     417:                 dot = addr;
     418:                 vcnt = vcline = 0;
     419:             }
     420:             vzop(0, 0, '+');
     421:             continue;
     422:
     423:         /*
     424: 		 * ^B		Window backwards, with 2 lines of continuity.
     425: 		 *		Inverse of ^F.
     426: 		 */
     427:         case CTRL(b):
     428:             vsave();
     429:             if (one + vcline != dot && vcnt > 2) {
     430:                 addr = dot - vcline + 2 - (cnt-1)*basWLINES;
     431:                 forbid (addr <= zero);
     432:                 dot = addr;
     433:                 vcnt = vcline = 0;
     434:             }
     435:             vzop(0, 0, '^');
     436:             continue;
     437:
     438:         /*
     439: 		 * z		Screen adjustment, taking a following character:
     440: 		 *			z<CR>		current line to top
     441: 		 *			z<NL>		like z<CR>
     442: 		 *			z-		current line to bottom
     443: 		 *		also z+, z^ like ^F and ^B.
     444: 		 *		A preceding count is line to use rather
     445: 		 *		than current line.  A count between z and
     446: 		 *		specifier character changes the screen size
     447: 		 *		for the redraw.
     448: 		 *
     449: 		 */
     450:         case 'z':
     451:             if (state == VISUAL) {
     452:                 i = vgetcnt();
     453:                 if (i > 0)
     454:                     vsetsiz(i);
     455:                 c = getesc();
     456:                 if (c == 0)
     457:                     continue;
     458:             }
     459:             vsave();
     460:             vzop(hadcnt, cnt, c);
     461:             continue;
     462:
     463:         /*
     464: 		 * Y		Yank lines, abbreviation for y_ or yy.
     465: 		 *		Yanked lines can be put later if no
     466: 		 *		changes intervene, or can be put in named
     467: 		 *		buffers and put anytime in this session.
     468: 		 */
     469:         case 'Y':
     470:             ungetkey('_');
     471:             c = 'y';
     472:             break;
     473:
     474:         /*
     475: 		 * J		Join lines, 2 by default.  Count is number
     476: 		 *		of lines to join (no join operator sorry.)
     477: 		 */
     478:         case 'J':
     479:             forbid (dot == dol);
     480:             if (cnt == 1)
     481:                 cnt = 2;
     482:             if (cnt > (i = dol - dot + 1))
     483:                 cnt = i;
     484:             vsave();
     485:             vmacchng(1);
     486:             setLAST();
     487:             cursor = strend(linebuf);
     488:             vremote(cnt, join, 0);
     489:             notenam = "join";
     490:             vmoving = 0;
     491:             killU();
     492:             vreplace(vcline, cnt, 1);
     493:             if (!*cursor && cursor > linebuf)
     494:                 cursor--;
     495:             if (notecnt == 2)
     496:                 notecnt = 0;
     497:             vrepaint(cursor);
     498:             continue;
     499:
     500:         /*
     501: 		 * S		Substitute text for whole lines, abbrev for c_.
     502: 		 *		Count is number of lines to change.
     503: 		 */
     504:         case 'S':
     505:             ungetkey('_');
     506:             c = 'c';
     507:             break;
     508:
     509:         /*
     510: 		 * O		Create a new line above current and accept new
     511: 		 *		input text, to an escape, there.
     512: 		 *		A count specifies, for dumb terminals when
     513: 		 *		slowopen is not set, the number of physical
     514: 		 *		line space to open on the screen.
     515: 		 *
     516: 		 * o		Like O, but opens lines below.
     517: 		 */
     518:         case 'O':
     519:         case 'o':
     520:             vmacchng(1);
     521:             voOpen(c, cnt);
     522:             continue;
     523:
     524:         /*
     525: 		 * C		Change text to end of line, short for c$.
     526: 		 */
     527:         case 'C':
     528:             if (*cursor) {
     529:                 ungetkey('$'), c = 'c';
     530:                 break;
     531:             }
     532:             goto appnd;
     533:
     534:         /*
     535: 		 * ~	Switch case of letter under cursor
     536: 		 */
     537:         case '~':
     538:             {
     539:                 char mbuf[4];
     540:                 setLAST();
     541:                 mbuf[0] = 'r';
     542:                 mbuf[1] = *cursor;
     543:                 mbuf[2] = cursor[1]==0 ? 0 : ' ';
     544:                 mbuf[3] = 0;
     545:                 if (isalpha(mbuf[1]))
     546:                     mbuf[1] ^= ' '; /* toggle the case */
     547:                 macpush(mbuf, 1);
     548:             }
     549:             continue;
     550:
     551:
     552:         /*
     553: 		 * A		Append at end of line, short for $a.
     554: 		 */
     555:         case 'A':
     556:             operate('$', 1);
     557: appnd:
     558:             c = 'a';
     559:             /* fall into ... */
     560:
     561:         /*
     562: 		 * a		Appends text after cursor.  Text can continue
     563: 		 *		through arbitrary number of lines.
     564: 		 */
     565:         case 'a':
     566:             if (*cursor) {
     567:                 if (state == HARDOPEN)
     568:                     putchar(*cursor);
     569:                 cursor++;
     570:             }
     571:             goto insrt;
     572:
     573:         /*
     574: 		 * I		Insert at beginning of whitespace of line,
     575: 		 *		short for ^i.
     576: 		 */
     577:         case 'I':
     578:             operate('^', 1);
     579:             c = 'i';
     580:             /* fall into ... */
     581:
     582:         /*
     583: 		 * R		Replace characters, one for one, by input
     584: 		 *		(logically), like repeated r commands.
     585: 		 *
     586: 		 * BUG:		This is like the typeover mode of many other
     587: 		 *		editors, and is only rarely useful.  Its
     588: 		 *		implementation is a hack in a low level
     589: 		 *		routine and it doesn't work very well, e.g.
     590: 		 *		you can't move around within a R, etc.
     591: 		 */
     592:         case 'R':
     593:             /* fall into... */
     594:
     595:         /*
     596: 		 * i		Insert text to an escape in the buffer.
     597: 		 *		Text is arbitrary.  This command reminds of
     598: 		 *		the i command in bare teco.
     599: 		 */
     600:         case 'i':
     601: insrt:
     602:             /*
     603: 			 * Common code for all the insertion commands.
     604: 			 * Save for redo, position cursor, prepare for append
     605: 			 * at command and in visual undo.  Note that nothing
     606: 			 * is doomed, unless R when all is, and save the
     607: 			 * current line in a the undo temporary buffer.
     608: 			 */
     609:             vmacchng(1);
     610:             setLAST();
     611:             vcursat(cursor);
     612:             prepapp();
     613:             vnoapp();
     614:             doomed = c == 'R' ? 10000 : 0;
     615:             if(FIXUNDO)
     616:                 vundkind = VCHNG;
     617:             vmoving = 0;
     618:             CP(vutmp, linebuf);
     619:
     620:             /*
     621: 			 * If this is a repeated command, then suppress
     622: 			 * fake insert mode on dumb terminals which looks
     623: 			 * ridiculous and wastes lots of time even at 9600B.
     624: 			 */
     625:             if (vglobp)
     626:                 hold = HOLDQIK;
     627:             vappend(c, cnt, 0);
     628:             continue;
     629:
     630:         /*
     631: 		 * ^?		An attention, normally a ^?, just beeps.
     632: 		 *		If you are a vi command within ex, then
     633: 		 *		two ATTN's will drop you back to command mode.
     634: 		 */
     635:         case ATTN:
     636:             beep();
     637:             if (initev || peekkey() != ATTN)
     638:                 continue;
     639:             /* fall into... */
     640:
     641:         /*
     642: 		 * ^\		A quit always gets command mode.
     643: 		 */
     644:         case QUIT:
     645:             /*
     646: 			 * Have to be careful if we were called
     647: 			 *	g/xxx/vi
     648: 			 * since a return will just start up again.
     649: 			 * So we simulate an interrupt.
     650: 			 */
     651:             if (inglobal)
     652:                 onintr();
     653:             /* fall into... */
     654:
     655: #ifdef notdef
     656:         /*
     657: 		 * q		Quit back to command mode, unless called as
     658: 		 *		vi on command line in which case dont do it
     659: 		 */
     660:         case 'q':   /* quit */
     661:             if (initev) {
     662:                 vsave();
     663:                 CATCH
     664:                     error("Q gets ex command mode, :q leaves vi");
     665:                 ENDCATCH
     666:                 splitw = 0;
     667:                 getDOT();
     668:                 vrepaint(cursor);
     669:                 continue;
     670:             }
     671: #endif
     672:             /* fall into... */
     673:
     674:         /*
     675: 		 * Q		Is like q, but always gets to command mode
     676: 		 *		even if command line invocation was as vi.
     677: 		 */
     678:         case 'Q':
     679:             vsave();
     680:             /*
     681: 			 * If we are in the middle of a macro, throw away
     682: 			 * the rest and fix up undo.
     683: 			 * This code copied from getbr().
     684: 			 */
     685:             if (vmacp) {
     686:                 vmacp = 0;
     687:                 if (inopen == -1)   /* don't screw up undo for esc esc */
     688:                     vundkind = VMANY;
     689:                 inopen = 1; /* restore old setting now that macro done */
     690:             }
     691:             return;
     692:
     693:
     694:         /*
     695: 		 * ZZ		Like :x
     696: 		 */
     697:          case 'Z':
     698:             forbid(getkey() != 'Z');
     699:             oglobp = globp;
     700:             globp = "x";
     701:             vclrech(0);
     702:             goto gogo;
     703:
     704:         /*
     705: 		 * P		Put back text before cursor or before current
     706: 		 *		line.  If text was whole lines goes back
     707: 		 *		as whole lines.  If part of a single line
     708: 		 *		or parts of whole lines splits up current
     709: 		 *		line to form many new lines.
     710: 		 *		May specify a named buffer, or the delete
     711: 		 *		saving buffers 1-9.
     712: 		 *
     713: 		 * p		Like P but after rather than before.
     714: 		 */
     715:         case 'P':
     716:         case 'p':
     717:             vmoving = 0;
     718: #ifdef notdef
     719:             forbid (!vreg && value(UNDOMACRO) && inopen < 0);
     720: #endif
     721:             /*
     722: 			 * If previous delete was partial line, use an
     723: 			 * append or insert to put it back so as to
     724: 			 * use insert mode on intelligent terminals.
     725: 			 */
     726:             if (!vreg && DEL[0]) {
     727:                 forbid ((DEL[0] & (QUOTE|TRIM)) == OVERBUF);
     728:                 vglobp = DEL;
     729:                 ungetkey(c == 'p' ? 'a' : 'i');
     730:                 goto reread;
     731:             }
     732:
     733:             /*
     734: 			 * If a register wasn't specified, then make
     735: 			 * sure there is something to put back.
     736: 			 */
     737:             forbid (!vreg && unddol == dol);
     738:             /*
     739: 			 * If we just did a macro the whole buffer is in
     740: 			 * the undo save area.  We don't want to put THAT.
     741: 			 */
     742:             forbid (vundkind == VMANY && undkind==UNDALL);
     743:             vsave();
     744:             vmacchng(1);
     745:             setLAST();
     746:             i = 0;
     747:             if (vreg && partreg(vreg) || !vreg && pkill[0]) {
     748:                 /*
     749: 				 * Restoring multiple lines which were partial
     750: 				 * lines; will leave cursor in middle
     751: 				 * of line after shoving restored text in to
     752: 				 * split the current line.
     753: 				 */
     754:                 i++;
     755:                 if (c == 'p' && *cursor)
     756:                     cursor++;
     757:             } else {
     758:                 /*
     759: 				 * In whole line case, have to back up dot
     760: 				 * for P; also want to clear cursor so
     761: 				 * cursor will eventually be positioned
     762: 				 * at the beginning of the first put line.
     763: 				 */
     764:                 cursor = 0;
     765:                 if (c == 'P') {
     766:                     dot--, vcline--;
     767:                     c = 'p';
     768:                 }
     769:             }
     770:             killU();
     771:
     772:             /*
     773: 			 * The call to putreg can potentially
     774: 			 * bomb since there may be nothing in a named buffer.
     775: 			 * We thus put a catch in here.  If we didn't and
     776: 			 * there was an error we would end up in command mode.
     777: 			 */
     778:             addr = dol; /* old dol */
     779:             CATCH
     780:                 vremote(1, vreg ? putreg : put, vreg);
     781:             ONERR
     782:                 if (vreg == -1) {
     783:                     splitw = 0;
     784:                     if (op == 'P')
     785:                         dot++, vcline++;
     786:                     goto pfixup;
     787:                 }
     788:             ENDCATCH
     789:             splitw = 0;
     790:             nlput = dol - addr + 1;
     791:             if (!i) {
     792:                 /*
     793: 				 * Increment undap1, undap2 to make up
     794: 				 * for their incorrect initialization in the
     795: 				 * routine vremote before calling put/putreg.
     796: 				 */
     797:                 if (FIXUNDO)
     798:                     undap1++, undap2++;
     799:                 vcline++;
     800:                 nlput--;
     801:
     802:                 /*
     803: 				 * After a put want current line first line,
     804: 				 * and dot was made the last line put in code
     805: 				 * run so far.  This is why we increment vcline
     806: 				 * above and decrease dot here.
     807: 				 */
     808:                 dot -= nlput - 1;
     809:             }
     810: #ifdef TRACE
     811:             if (trace)
     812:                 fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot));
     813: #endif
     814:             vreplace(vcline, i, nlput);
     815:             if (state != VISUAL) {
     816:                 /*
     817: 				 * Special case in open mode.
     818: 				 * Force action on the screen when a single
     819: 				 * line is put even if it is identical to
     820: 				 * the current line, e.g. on YP; otherwise
     821: 				 * you can't tell anything happened.
     822: 				 */
     823:                 vjumpto(dot, cursor, '.');
     824:                 continue;
     825:             }
     826: pfixup:
     827:             vrepaint(cursor);
     828:             vfixcurs();
     829:             continue;
     830:
     831:         /*
     832: 		 * ^^		Return to previous file.
     833: 		 *		Like a :e #, and thus can be used after a
     834: 		 *		"No Write" diagnostic.
     835: 		 */
     836:         case CTRL(^):
     837:             forbid (hadcnt);
     838:             vsave();
     839:             ckaw();
     840:             oglobp = globp;
     841:             if (value(AUTOWRITE))
     842:                 globp = "e! #";
     843:             else
     844:                 globp = "e #";
     845:             goto gogo;
     846:
     847:         /*
     848: 		 * ^]		Takes word after cursor as tag, and then does
     849: 		 *		tag command.  Read ``go right to''.
     850: 		 */
     851:         case CTRL(]):
     852:             grabtag();
     853:             oglobp = globp;
     854:             globp = "tag";
     855:             goto gogo;
     856:
     857:         /*
     858: 		 * &		Like :&
     859: 		 */
     860:          case '&':
     861:             oglobp = globp;
     862:             globp = "&";
     863:             goto gogo;
     864:
     865:         /*
     866: 		 * ^G		Bring up a status line at the bottom of
     867: 		 *		the screen, like a :file command.
     868: 		 *
     869: 		 * BUG:		Was ^S but doesn't work in cbreak mode
     870: 		 */
     871:         case CTRL(g):
     872:             oglobp = globp;
     873:             globp = "file";
     874: gogo:
     875:             addr = dot;
     876:             vsave();
     877:             goto doinit;
     878:
     879: #ifdef SIGTSTP
     880:         /*
     881: 		 * ^Z:	suspend editor session and temporarily return
     882: 		 * 	to shell.  Only works with Berkeley/IIASA process
     883: 		 *	control in kernel.
     884: 		 */
     885:         case CTRL(z):
     886:             forbid(dosusp == 0 || !ldisc);
     887:             vsave();
     888:             oglobp = globp;
     889:             globp = "stop";
     890:             goto gogo;
     891: #endif
     892:
     893:         /*
     894: 		 * :		Read a command from the echo area and
     895: 		 *		execute it in command mode.
     896: 		 */
     897:         case ':':
     898:             forbid (hadcnt);
     899:             vsave();
     900:             i = tchng;
     901:             addr = dot;
     902:             if (readecho(c)) {
     903:                 esave[0] = 0;
     904:                 goto fixup;
     905:             }
     906:             getDOT();
     907:             /*
     908: 			 * Use the visual undo buffer to store the global
     909: 			 * string for command mode, since it is idle right now.
     910: 			 */
     911:             oglobp = globp; strcpy(vutmp, genbuf+1); globp = vutmp;
     912: doinit:
     913:             esave[0] = 0;
     914:             fixech();
     915:
     916:             /*
     917: 			 * Have to finagle around not to lose last
     918: 			 * character after this command (when run from ex
     919: 			 * command mode).  This is clumsy.
     920: 			 */
     921:             d = peekc; ungetchar(0);
     922:             if (shouldpo) {
     923:                 /*
     924: 				 * So after a "Hit return..." ":", we do
     925: 				 * another "Hit return..." the next time
     926: 				 */
     927:                 pofix();
     928:                 shouldpo = 0;
     929:             }
     930:             CATCH
     931:                 /*
     932: 				 * Save old values of options so we can
     933: 				 * notice when they change; switch into
     934: 				 * cooked mode so we are interruptible.
     935: 				 */
     936:                 onumber = value(NUMBER);
     937:                 olist = value(LIST);
     938:                 OPline = Pline;
     939:                 OPutchar = Putchar;
     940: #ifndef CBREAK
     941:                 vcook();
     942: #endif
     943:                 commands(1, 1);
     944:                 if (dot == zero && dol > zero)
     945:                     dot = one;
     946: #ifndef CBREAK
     947:                 vraw();
     948: #endif
     949:             ONERR
     950: #ifndef CBREAK
     951:                 vraw();
     952: #endif
     953:                 copy(esave, vtube[WECHO], TUBECOLS);
     954:             ENDCATCH
     955:             fixol();
     956:             Pline = OPline;
     957:             Putchar = OPutchar;
     958:             ungetchar(d);
     959:             globp = oglobp;
     960:
     961:             /*
     962: 			 * If we ended up with no lines in the buffer, make
     963: 			 * a line, and don't consider the buffer changed.
     964: 			 */
     965:             if (dot == zero) {
     966:                 fixzero();
     967:                 sync();
     968:             }
     969:             splitw = 0;
     970:
     971:             /*
     972: 			 * Special case: did list/number options change?
     973: 			 */
     974:             if (onumber != value(NUMBER))
     975:                 setnumb(value(NUMBER));
     976:             if (olist != value(LIST))
     977:                 setlist(value(LIST));
     978:
     979: fixup:
     980:             /*
     981: 			 * If a change occurred, other than
     982: 			 * a write which clears changes, then
     983: 			 * we should allow an undo even if .
     984: 			 * didn't move.
     985: 			 *
     986: 			 * BUG: You can make this wrong by
     987: 			 * tricking around with multiple commands
     988: 			 * on one line of : escape, and including
     989: 			 * a write command there, but its not
     990: 			 * worth worrying about.
     991: 			 */
     992:             if (FIXUNDO && tchng && tchng != i)
     993:                 vundkind = VMANY, cursor = 0;
     994:
     995:             /*
     996: 			 * If we are about to do another :, hold off
     997: 			 * updating of screen.
     998: 			 */
     999:             if (vcnt < 0 && Peekkey == ':') {
    1000:                 getDOT();
    1001:                 shouldpo = 1;
    1002:                 continue;
    1003:             }
    1004:             shouldpo = 0;
    1005:
    1006:             /*
    1007: 			 * In the case where the file being edited is
    1008: 			 * new; e.g. if the initial state hasn't been
    1009: 			 * saved yet, then do so now.
    1010: 			 */
    1011:             if (unddol == truedol) {
    1012:                 vundkind = VNONE;
    1013:                 Vlines = lineDOL();
    1014:                 if (!inglobal)
    1015:                     savevis();
    1016:                 addr = zero;
    1017:                 vcnt = 0;
    1018:                 if (esave[0] == 0)
    1019:                     copy(esave, vtube[WECHO], TUBECOLS);
    1020:             }
    1021:
    1022:             /*
    1023: 			 * If the current line moved reset the cursor position.
    1024: 			 */
    1025:             if (dot != addr) {
    1026:                 vmoving = 0;
    1027:                 cursor = 0;
    1028:             }
    1029:
    1030:             /*
    1031: 			 * If current line is not on screen or if we are
    1032: 			 * in open mode and . moved, then redraw.
    1033: 			 */
    1034:             i = vcline + (dot - addr);
    1035:             if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) {
    1036:                 if (state == CRTOPEN)
    1037:                     vup1();
    1038:                 if (vcnt > 0)
    1039:                     vcnt = 0;
    1040:                 vjumpto(dot, (char *) 0, '.');
    1041:             } else {
    1042:                 /*
    1043: 				 * Current line IS on screen.
    1044: 				 * If we did a [Hit return...] then
    1045: 				 * restore vcnt and clear screen if in visual
    1046: 				 */
    1047:                 vcline = i;
    1048:                 if (vcnt < 0) {
    1049:                     vcnt = -vcnt;
    1050:                     if (state == VISUAL)
    1051:                         vclear();
    1052:                     else if (state == CRTOPEN) {
    1053:                         vcnt = 0;
    1054:                     }
    1055:                 }
    1056:
    1057:                 /*
    1058: 				 * Limit max value of vcnt based on $
    1059: 				 */
    1060:                 i = vcline + lineDOL() - lineDOT() + 1;
    1061:                 if (i < vcnt)
    1062:                     vcnt = i;
    1063:
    1064:                 /*
    1065: 				 * Dirty and repaint.
    1066: 				 */
    1067:                 vdirty(0, LINES);
    1068:                 vrepaint(cursor);
    1069:             }
    1070:
    1071:             /*
    1072: 			 * If in visual, put back the echo area
    1073: 			 * if it was clobberred.
    1074: 			 */
    1075:             if (state == VISUAL) {
    1076:                 int sdc = destcol, sdl = destline;
    1077:
    1078:                 splitw++;
    1079:                 vigoto(WECHO, 0);
    1080:                 for (i = 0; i < TUBECOLS - 1; i++) {
    1081:                     if (esave[i] == 0)
    1082:                         break;
    1083:                     vputchar(esave[i]);
    1084:                 }
    1085:                 splitw = 0;
    1086:                 vgoto(sdl, sdc);
    1087:             }
    1088:             continue;
    1089:
    1090:         /*
    1091: 		 * u		undo the last changing command.
    1092: 		 */
    1093:         case 'u':
    1094:             vundo(1);
    1095:             continue;
    1096:
    1097:         /*
    1098: 		 * U		restore current line to initial state.
    1099: 		 */
    1100:         case 'U':
    1101:             vUndo();
    1102:             continue;
    1103:
    1104: fonfon:
    1105:             beep();
    1106:             vmacp = 0;
    1107:             inopen = 1; /* might have been -1 */
    1108:             continue;
    1109:         }
    1110:
    1111:         /*
    1112: 		 * Rest of commands are decoded by the operate
    1113: 		 * routine.
    1114: 		 */
    1115:         operate(c, cnt);
    1116:     }
    1117: }
    1118:
    1119: /*
    1120:  * Grab the word after the cursor so we can look for it as a tag.
    1121:  */
    1122: grabtag()
    1123: {
    1124:     register char *cp, *dp;
    1125:
    1126:     cp = vpastwh(cursor);
    1127:     if (*cp) {
    1128:         dp = lasttag;
    1129:         do {
    1130:             if (dp < &lasttag[sizeof lasttag - 2])
    1131:                 *dp++ = *cp;
    1132:             cp++;
    1133:         } while (isalpha(*cp) || isdigit(*cp) || *cp == '_'
    1134: #ifdef LISPCODE
    1135:             || (value(LISP) && *cp == '-')
    1136: #endif LISPCODE
    1137:             );
    1138:         *dp++ = 0;
    1139:     }
    1140: }
    1141:
    1142: /*
    1143:  * Before appending lines, set up addr1 and
    1144:  * the command mode undo information.
    1145:  */
    1146: prepapp()
    1147: {
    1148:
    1149:     addr1 = dot;
    1150:     deletenone();
    1151:     addr1++;
    1152:     appendnone();
    1153: }
    1154:
    1155: /*
    1156:  * Execute function f with the address bounds addr1
    1157:  * and addr2 surrounding cnt lines starting at dot.
    1158:  */
    1159: vremote(cnt, f, arg)
    1160:     int cnt, (*f)(), arg;
    1161: {
    1162:     register int oing = inglobal;
    1163:
    1164:     addr1 = dot;
    1165:     addr2 = dot + cnt - 1;
    1166:     inglobal = 0;
    1167:     if (FIXUNDO)
    1168:         undap1 = undap2 = dot;
    1169:     (*f)(arg);
    1170:     inglobal = oing;
    1171:     if (FIXUNDO)
    1172:         vundkind = VMANY;
    1173:     vmcurs = 0;
    1174: }
    1175:
    1176: /*
    1177:  * Save the current contents of linebuf, if it has changed.
    1178:  */
    1179: vsave()
    1180: {
    1181:     char temp[LBSIZE];
    1182:
    1183:     CP(temp, linebuf);
    1184:     if (FIXUNDO && vundkind == VCHNG || vundkind == VCAPU) {
    1185:         /*
    1186: 		 * If the undo state is saved in the temporary buffer
    1187: 		 * vutmp, then we sync this into the temp file so that
    1188: 		 * we will be able to undo even after we have moved off
    1189: 		 * the line.  It would be possible to associate a line
    1190: 		 * with vutmp but we assume that vutmp is only associated
    1191: 		 * with line dot (e.g. in case ':') above, so beware.
    1192: 		 */
    1193:         prepapp();
    1194:         strcLIN(vutmp);
    1195:         putmark(dot);
    1196:         vremote(1, yank, 0);
    1197:         vundkind = VMCHNG;
    1198:         notecnt = 0;
    1199:         undkind = UNDCHANGE;
    1200:     }
    1201:     /*
    1202: 	 * Get the line out of the temp file and do nothing if it hasn't
    1203: 	 * changed.  This may seem like a loss, but the line will
    1204: 	 * almost always be in a read buffer so this may well avoid disk i/o.
    1205: 	 */
    1206:     getDOT();
    1207:     if (strcmp(linebuf, temp) == 0)
    1208:         return;
    1209:     strcLIN(temp);
    1210:     putmark(dot);
    1211: }
    1212:
    1213: #undef  forbid
    1214: #define forbid(a)   if (a) { beep(); return; }
    1215:
    1216: /*
    1217:  * Do a z operation.
    1218:  * Code here is rather long, and very uninteresting.
    1219:  */
    1220: vzop(hadcnt, cnt, c)
    1221:     bool hadcnt;
    1222:     int cnt;
    1223:     register int c;
    1224: {
    1225:     register line *addr;
    1226:
    1227:     if (state != VISUAL) {
    1228:         /*
    1229: 		 * Z from open; always like a z=.
    1230: 		 * This code is a mess and should be cleaned up.
    1231: 		 */
    1232:         vmoveitup(1, 1);
    1233:         vgoto(outline, 0);
    1234:         ostop(normf);
    1235:         setoutt();
    1236:         addr2 = dot;
    1237:         vclear();
    1238:         destline = WECHO;
    1239:         zop2(Xhadcnt ? Xcnt : value(WINDOW) - 1, '=');
    1240:         if (state == CRTOPEN)
    1241:             putnl();
    1242:         putNFL();
    1243:         termreset();
    1244:         Outchar = vputchar;
    1245:         ignore(ostart());
    1246:         vcnt = 0;
    1247:         outline = destline = 0;
    1248:         vjumpto(dot, cursor, 0);
    1249:         return;
    1250:     }
    1251:     if (hadcnt) {
    1252:         addr = zero + cnt;
    1253:         if (addr < one)
    1254:             addr = one;
    1255:         if (addr > dol)
    1256:             addr = dol;
    1257:         markit(addr);
    1258:     } else
    1259:         switch (c) {
    1260:
    1261:         case '+':
    1262:             addr = dot + vcnt - vcline;
    1263:             break;
    1264:
    1265:         case '^':
    1266:             addr = dot - vcline - 1;
    1267:             forbid (addr < one);
    1268:             c = '-';
    1269:             break;
    1270:
    1271:         default:
    1272:             addr = dot;
    1273:             break;
    1274:         }
    1275:     switch (c) {
    1276:
    1277:     case '.':
    1278:     case '-':
    1279:         break;
    1280:
    1281:     case '^':
    1282:         forbid (addr <= one);
    1283:         break;
    1284:
    1285:     case '+':
    1286:         forbid (addr >= dol);
    1287:         /* fall into ... */
    1288:
    1289:     case CR:
    1290:     case NL:
    1291:         c = CR;
    1292:         break;
    1293:
    1294:     default:
    1295:         beep();
    1296:         return;
    1297:     }
    1298:     vmoving = 0;
    1299:     vjumpto(addr, NOSTR, c);
    1300: }

#### Defined functions

grabtag defined in line 1122; used 1 times

- in line 852

prepapp defined in line 1146; used 5 times

- in line 612, 1193
- in /usr/src/ucb/ex/ex_vops.c line 617, 659, 888

vmain defined in line 25; used 2 times

- in /usr/src/ucb/ex/ex_v.c line 133, 237

vremote defined in line 1159; used 11 times

- in line 488, 780, 1196
- in /usr/src/ucb/ex/ex_vops.c line 372, 492, 708, 752, 823, 840, 907
- in /usr/src/ucb/ex/ex_vops2.c line 349

vsave defined in line 1179; used 31 times

- in line 90, 248, 402, 413, 428, 459, 484, 662, 679, 743, 838, 876, 887, 899
- in /usr/src/ucb/ex/ex_v.c line 427
- in /usr/src/ucb/ex/ex_vget.c line 509
- in /usr/src/ucb/ex/ex_voper.c line 224, 261, 581, 613
- in /usr/src/ucb/ex/ex_vops.c line 83, 90, 142, 199, 642, 793
- in /usr/src/ucb/ex/ex_vops2.c line 320, 900
- in /usr/src/ucb/ex/ex_vwind.c line 34, 91, 140

vzop defined in line 1220; used 3 times

- in line 420, 435, 460

#### Defined variables

sccsid defined in line 8; never used

#### Defined macros

forbid defined in line 1214; used 22 times

- in line 111, 122, 246, 278, 354, 368, 401, 416, 431, 479, 698, 719, 727, 737-742(2), 837, 886, 898, 1213, 1267, 1282-1286(2)

Last modified: 1991-09-08 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2876 |