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

Defined functions

cmd_char defined in line 82; used 1 times
cmd_erase defined in line 42; used 2 times
cmd_exec defined in line 134; used 6 times
cmd_int defined in line 121; used 13 times
cmd_reset defined in line 34; used 4 times
commands defined in line 223; used 2 times
getcc defined in line 186; used 9 times
prompt defined in line 144; used 1 times
start_mcc defined in line 68; used 7 times

Defined variables

cmd_col defined in line 26; used 7 times
cmdbuf defined in line 24; used 13 times
cp defined in line 25; used 9 times
last_mcc defined in line 28; used 3 times
mcc defined in line 27; used 15 times
public defined in line 223; never used
screen_trashed defined in line 29; used 5 times
Last modified: 1990-07-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3461
Valid CSS Valid XHTML 1.0 Strict