1: /*
   2:  * User-level command processor.
   3:  */
   4: 
   5: #include "less.h"
   6: #include "position.h"
   7: #include <setjmp.h>
   8: 
   9: extern jmp_buf main_loop;
  10: extern int erase_char, kill_char;
  11: extern int pr_type;
  12: extern int sigs;
  13: extern int ispipe;
  14: extern int quit_at_eof;
  15: extern int hit_eof;
  16: extern int sc_width, sc_height;
  17: extern char *first_cmd;
  18: extern char version[];
  19: extern char current_file[];
  20: extern char *editor;
  21: 
  22: static char cmdbuf[90];     /* Buffer for holding a multi-char command */
  23: static char *cp;        /* Pointer into cmdbuf */
  24: static int cmd_col;     /* Current column of the multi-char command */
  25: static char mcc;        /* The multi-char command letter (e.g. '/') */
  26: static char last_mcc;       /* The previous mcc */
  27: 
  28: /*
  29:  * Reset command buffer (to empty).
  30:  */
  31: cmd_reset()
  32: {
  33:     cp = cmdbuf;
  34: }
  35: 
  36: /*
  37:  * Backspace in command buffer.
  38:  */
  39:     static int
  40: cmd_erase()
  41: {
  42:     if (cp == cmdbuf)
  43:         /*
  44: 		 * Backspace past beginning of the string:
  45: 		 * this usually means abort the command.
  46: 		 */
  47:         return (1);
  48: 
  49:     if (control_char(*--cp))
  50:     {
  51:         /*
  52: 		 * Erase an extra character, for the carat.
  53: 		 */
  54:         backspace();
  55:         cmd_col--;
  56:     }
  57:     backspace();
  58:     cmd_col--;
  59:     return (0);
  60: }
  61: 
  62: /*
  63:  * Set up the display to start a new multi-character command.
  64:  */
  65: start_mcc()
  66: {
  67:     lower_left();
  68:     clear_eol();
  69:     putc(mcc);
  70:     cmd_col = 1;
  71: }
  72: 
  73: /*
  74:  * Process a single character of a multi-character command, such as
  75:  * a number, or the pattern of a search command.
  76:  */
  77:     static int
  78: cmd_char(c)
  79:     int c;
  80: {
  81:     if (c == erase_char)
  82:     {
  83:         if (cmd_erase())
  84:             return (1);
  85:     } else if (c == kill_char)
  86:     {
  87:         /* {{ Could do this faster, but who cares? }} */
  88:         while (cmd_erase() == 0)
  89:             ;
  90:     } else
  91:     {
  92:         /*
  93: 		 * Append the character to the string,
  94: 		 * if there is room in the buffer and on the screen.
  95: 		 */
  96:         if (cp < &cmdbuf[sizeof(cmdbuf)-1] && cmd_col < sc_width-3)
  97:         {
  98:             *cp++ = c;
  99:             if (control_char(c))
 100:             {
 101:                 putc('^');
 102:                 cmd_col++;
 103:                 c = carat_char(c);
 104:             }
 105:             putc(c);
 106:             cmd_col++;
 107:         } else
 108:             bell();
 109:     }
 110:     return (0);
 111: }
 112: 
 113: /*
 114:  * Return the number currently in the command buffer.
 115:  */
 116:     static int
 117: cmd_int()
 118: {
 119:     *cp = '\0';
 120:     cp = cmdbuf;
 121:     return (atoi(cmdbuf));
 122: }
 123: 
 124: /*
 125:  * Move the cursor to lower left before executing a command.
 126:  * This looks nicer if the command takes a long time before
 127:  * updating the screen.
 128:  */
 129:     static void
 130: cmd_exec()
 131: {
 132:     lower_left();
 133:     flush();
 134: }
 135: 
 136: /*
 137:  * Display the appropriate prompt.
 138:  */
 139:     static void
 140: prompt()
 141: {
 142:     register char *p;
 143: 
 144:     if (first_cmd != NULL && *first_cmd != '\0')
 145:         /*
 146: 		 * No prompt necessary if commands are from first_cmd
 147: 		 * rather than from the user.
 148: 		 */
 149:         return;
 150: 
 151:     /*
 152: 	 * Select the proper prompt and display it.
 153: 	 */
 154:     p = pr_string();
 155:     if (p == NULL)
 156:         putc(':');
 157:     else
 158:     {
 159:         so_enter();
 160:         puts(p);
 161:         so_exit();
 162:     }
 163: }
 164: 
 165: /*
 166:  * Get command character.
 167:  * The character normally comes from the keyboard,
 168:  * but may come from the "first_cmd" string.
 169:  */
 170:     static int
 171: getcc()
 172: {
 173:     if (first_cmd == NULL)
 174:         return (getc());
 175: 
 176:     if (*first_cmd == '\0')
 177:     {
 178:         /*
 179: 		 * Reached end of first_cmd input.
 180: 		 */
 181:         first_cmd = NULL;
 182:         if (cp > cmdbuf && position(TOP) == NULL_POSITION)
 183:         {
 184:             /*
 185: 			 * Command is incomplete, so try to complete it.
 186: 			 * There are only two cases:
 187: 			 * 1. We have "/string" but no newline.  Add the \n.
 188: 			 * 2. We have a number but no command.  Treat as #g.
 189: 			 * (This is all pretty hokey.)
 190: 			 */
 191:             if (mcc != ':')
 192:                 return ('\n');
 193:             else
 194:                 return ('g');
 195:         }
 196:         return (getc());
 197:     }
 198:     return (*first_cmd++);
 199: }
 200: 
 201: /*
 202:  * Main command processor.
 203:  * Accept and execute commands until a quit command, then return.
 204:  */
 205:     public void
 206: commands()
 207: {
 208:     register int c;
 209:     register int n;
 210:     register int scroll = 10;
 211: 
 212:     mcc = last_mcc = 0;
 213: 
 214:     setjmp(main_loop);
 215:     for (;;)
 216:     {
 217:         /*
 218: 		 * Display prompt and accept a character.
 219: 		 */
 220:         psignals(); /* See if any signals need processing */
 221: 
 222:         if (quit_at_eof && hit_eof > 1)
 223:             /*
 224: 			 * After hitting end-of-file for the second time,
 225: 			 * automatically advance to the next file.
 226: 			 * If there are no more files, quit.
 227: 			 */
 228:             next_file(1);
 229: 
 230:         cmd_reset();
 231:         lower_left();
 232:         clear_eol();
 233:         prompt();
 234:         c = getcc();
 235: 
 236:     again:
 237:         if (sigs)
 238:             continue;
 239: 
 240:         if (mcc)
 241:         {
 242:             /*
 243: 			 * We are in a multi-character command.
 244: 			 * All chars until newline go into the command buffer.
 245: 			 * (Note that mcc == ':' is a special case that
 246: 			 *  means a number is being entered.)
 247: 			 */
 248:             if (mcc != ':' && (c == '\n' || c == '\r'))
 249:             {
 250:                 /*
 251: 				 * Execute the command.
 252: 				 */
 253:                 *cp = '\0';
 254:                 cmd_exec();
 255:                 if (mcc == 'E')
 256:                 {
 257:                     char *p;
 258:                     /*
 259: 					 * Ignore leading spaces
 260: 					 * in the filename.
 261: 					 */
 262:                     for (p = cmdbuf;  *p == ' ';  p++) ;
 263:                     edit(p);
 264: #if SHELL_ESCAPE
 265:                 } else if (mcc == '!')
 266:                 {
 267:                     lsystem(cmdbuf);
 268:                     error("!done");
 269:                     first_cmd = "r";    /* Repaint */
 270: #endif
 271:                 } else
 272:                     search(mcc, cmdbuf, n);
 273:                 mcc = 0;
 274:             } else
 275:             {
 276:                 if (mcc == ':' && (c < '0' || c > '9') &&
 277:                     c != erase_char && c != kill_char)
 278:                 {
 279:                     /*
 280: 					 * This is not part of the number
 281: 					 * we were entering.  Process
 282: 					 * it as a regular character.
 283: 					 */
 284:                     mcc = 0;
 285:                     goto again;
 286:                 }
 287: 
 288:                 /*
 289: 				 * Append the char to the command buffer.
 290: 				 */
 291:                 if (cmd_char(c))
 292:                 {
 293:                     /* Abort the multi-char command. */
 294:                     mcc = 0;
 295:                     continue;
 296:                 }
 297:                 c = getcc();
 298:                 goto again;
 299:             }
 300:         } else switch (c)
 301:         {
 302:         case '0': case '1': case '2': case '3': case '4':
 303:         case '5': case '6': case '7': case '8': case '9':
 304:             /*
 305: 			 * First digit of a number.
 306: 			 */
 307:             mcc = ':';
 308:             start_mcc();
 309:             goto again;
 310: 
 311:         case 'f':
 312:         case ' ':
 313:         case CONTROL('F'):
 314:             /*
 315: 			 * Forward one screen.
 316: 			 */
 317:             n = cmd_int();
 318:             if (n <= 0)
 319:                 n = sc_height - 1;
 320:             forward(n, 1);
 321:             break;
 322: 
 323:         case 'b':
 324:         case CONTROL('B'):
 325:             /*
 326: 			 * Backward one screen.
 327: 			 */
 328:             n = cmd_int();
 329:             if (n <= 0)
 330:                 n = sc_height - 1;
 331:             backward(n, 1);
 332:             break;
 333: 
 334:         case 'e':
 335:         case 'j':
 336:         case '\r':
 337:         case '\n':
 338:         case CONTROL('E'):
 339:             /*
 340: 			 * Forward N (default 1) line.
 341: 			 */
 342:             n = cmd_int();
 343:             if (n <= 0)
 344:                 n = 1;
 345:             forward(n, 0);
 346:             break;
 347: 
 348:         case 'y':
 349:         case 'k':
 350:         case CONTROL('K'):
 351:         case CONTROL('Y'):
 352:             /*
 353: 			 * Backward N (default 1) line.
 354: 			 */
 355:             n = cmd_int();
 356:             if (n <= 0)
 357:                 n = 1;
 358:             backward(n, 0);
 359:             break;
 360: 
 361:         case 'd':
 362:         case CONTROL('D'):
 363:             /*
 364: 			 * Forward N lines
 365: 			 * (default same as last 'd' or 'u' command).
 366: 			 */
 367:             n = cmd_int();
 368:             if (n > 0)
 369:                 scroll = n;
 370:             forward(scroll, 0);
 371:             break;
 372: 
 373:         case 'u':
 374:         case CONTROL('U'):
 375:             /*
 376: 			 * Forward N lines
 377: 			 * (default same as last 'd' or 'u' command).
 378: 			 */
 379:             n = cmd_int();
 380:             if (n > 0)
 381:                 scroll = n;
 382:             backward(scroll, 0);
 383:             break;
 384: 
 385:         case 'R':
 386:             /*
 387: 			 * Flush buffers, then repaint screen.
 388: 			 */
 389:             ch_init(0);
 390:             /* Fall thru */
 391:         case 'r':
 392:         case CONTROL('R'):
 393:         case CONTROL('L'):
 394:             /*
 395: 			 * Repaint screen.
 396: 			 */
 397:             repaint();
 398:             break;
 399: 
 400:         case 'g':
 401:             /*
 402: 			 * Go to line N, default beginning of file.
 403: 			 */
 404:             n = cmd_int();
 405:             if (n <= 0)
 406:                 n = 1;
 407:             cmd_exec();
 408:             jump_back(n);
 409:             break;
 410: 
 411:         case 'p':
 412:         case '%':
 413:             /*
 414: 			 * Go to a specified percentage into the file.
 415: 			 */
 416:             n = cmd_int();
 417:             if (n < 0)
 418:                 n = 0;
 419:             if (n > 100)
 420:                 n = 100;
 421:             cmd_exec();
 422:             jump_percent(n);
 423:             break;
 424: 
 425:         case 'G':
 426:             /*
 427: 			 * Go to line N, default end of file.
 428: 			 */
 429:             n = cmd_int();
 430:             cmd_exec();
 431:             if (n <= 0)
 432:                 jump_forw();
 433:             else
 434:                 jump_back(n);
 435:             break;
 436: 
 437:         case '=':
 438:         case CONTROL('G'):
 439:             /*
 440: 			 * Print file name, etc.
 441: 			 */
 442:             error(eq_message());
 443:             break;
 444: 
 445:         case 'V':
 446:             /*
 447: 			 * Print version number, without the "@(#)".
 448: 			 */
 449:             error(version+4);
 450:             break;
 451: 
 452:         case 'q':
 453:             /*
 454: 			 * Exit.
 455: 			 */
 456:             return;
 457: 
 458:         case '/':
 459:         case '?':
 460:             /*
 461: 			 * Search for a pattern.
 462: 			 * Accept chars of the pattern until \n.
 463: 			 */
 464:             n = cmd_int();
 465:             if (n <= 0)
 466:                 n = 1;
 467:             mcc = last_mcc = c;
 468:             start_mcc();
 469:             c = getcc();
 470:             goto again;
 471: 
 472:         case 'n':
 473:             /*
 474: 			 * Repeat previous search.
 475: 			 */
 476:             n = cmd_int();
 477:             if (n <= 0)
 478:                 n = 1;
 479:             mcc = last_mcc;
 480:             start_mcc();
 481:             cmd_exec();
 482:             search(mcc, (char *)NULL, n);
 483:             mcc = 0;
 484:             break;
 485: 
 486:         case 'h':
 487:             /*
 488: 			 * Help.
 489: 			 */
 490:             help();
 491:             repaint();
 492:             break;
 493: 
 494:         case 'E':
 495:             /*
 496: 			 * Edit a new file.  Get the filename.
 497: 			 */
 498:             cmd_reset();
 499:             mcc = 'E';
 500:             start_mcc();
 501:             puts("dit: ");  /* This looks nicer */
 502:             cmd_col += 5;
 503:             c = getcc();
 504:             goto again;
 505: 
 506: #if SHELL_ESCAPE
 507:         case '!':
 508:             /*
 509: 			 * Shell escape.
 510: 			 */
 511:             cmd_reset();
 512:             mcc = '!';
 513:             start_mcc();
 514:             c = getcc();
 515:             goto again;
 516: #endif
 517: 
 518: #if EDITOR
 519:         case 'v':
 520:             if (ispipe)
 521:             {
 522:                 error("Cannot edit standard input");
 523:                 break;
 524:             }
 525:             sprintf(cmdbuf, "%s %s", editor, current_file);
 526:             lsystem(cmdbuf);
 527:             first_cmd = "R";
 528:             break;
 529: #endif
 530: 
 531:         case 'N':
 532:             /*
 533: 			 * Examine next file.
 534: 			 */
 535:             n = cmd_int();
 536:             if (n <= 0)
 537:                 n = 1;
 538:             next_file(n);
 539:             break;
 540: 
 541:         case 'P':
 542:             /*
 543: 			 * Examine previous file.
 544: 			 */
 545:             n = cmd_int();
 546:             if (n <= 0)
 547:                 n = 1;
 548:             prev_file(n);
 549:             break;
 550: 
 551:         case '-':
 552:             /*
 553: 			 * Toggle a flag setting.
 554: 			 */
 555:             mcc = '-';
 556:             start_mcc();
 557:             c = getcc();
 558:             mcc = 0;
 559:             if (c == erase_char || c == kill_char)
 560:                 break;
 561:             toggle_option(c);
 562:             break;
 563: 
 564:         case 'm':
 565:             /*
 566: 			 * Set a mark.
 567: 			 */
 568:             lower_left();
 569:             clear_eol();
 570:             puts("mark: ");
 571:             c = getcc();
 572:             if (c == erase_char || c == kill_char)
 573:                 break;
 574:             setmark(c);
 575:             break;
 576: 
 577:         case '\'':
 578:             /*
 579: 			 * Go to a mark.
 580: 			 */
 581:             lower_left();
 582:             clear_eol();
 583:             puts("goto mark: ");
 584:             c = getcc();
 585:             if (c == erase_char || c == kill_char)
 586:                 break;
 587:             gomark(c);
 588:             break;
 589: 
 590:         default:
 591:             bell();
 592:             break;
 593:         }
 594:     }
 595: }

Defined functions

cmd_char defined in line 77; used 1 times
cmd_erase defined in line 39; used 2 times
cmd_exec defined in line 129; used 5 times
cmd_int defined in line 116; used 13 times
cmd_reset defined in line 31; used 3 times
getcc defined in line 170; used 8 times
prompt defined in line 139; used 1 times
start_mcc defined in line 65; used 6 times

Defined variables

cmd_col defined in line 24; used 7 times
cmdbuf defined in line 22; used 12 times
cp defined in line 23; used 9 times
last_mcc defined in line 26; used 3 times
mcc defined in line 25; used 21 times
public defined in line 205; never used
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2328
Valid CSS Valid XHTML 1.0 Strict