home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1986 / 10 / holublst.oct < prev    next >
Text File  |  1986-10-31  |  28KB  |  777 lines

  1.                               Listing 1 -- more.c
  2.  ------------------------------------------------------------------------------
  3.   1 #include <stdio.h>
  4.   2 #include <ctype.h>
  5.   3 #include <fcntl.h>
  6.   4 #include <process.h>
  7.   5 
  8.   6 /*      MORE.C          Page input to stdout.
  9.   7  *
  10.   8  *      (C) 1986, Allen I. Holub. All rights reserved.
  11.   9  *
  12.  10  *      Usage:  more [-<offset>] file...
  13.  11  *
  14.  12  *      Exit status: 0 always
  15.  13  */
  16.  14 
  17.  15 /*-----------------------------------------------------------------*/
  18.  16 
  19.  17 extern int  b_getc  ();                 /* Direct console input function */
  20.  18                                         /* source in /src/tools/b_getc.c */
  21.  19 extern int  look    ();                 /* Char. lookahead function.     */
  22.  20                                         /* source in /src/tools/look.asm */
  23.  21 extern long   ftell      ( FILE *);     /* Standard library functions:   */
  24.  22 extern long   atol       ( char* );
  25.  23 extern FILE   *fopen     ( char*, char* );
  26.  24 extern int    fclose     ( FILE* );
  27.  25 extern int    spawnl     ( int, char*, char*, );
  28.  26 extern char   *getenv    ( char* );
  29.  27 extern char   *fgets     ( char*, int, FILE* );
  30.  28 extern long   filelength ( int );
  31.  29 
  32.  30 /*-----------------------------------------------------------------*/
  33.  31 
  34.  32 #define CAN     0x18    /* ^X   */
  35.  33 #define ESC     0x1b    /* ^[   */
  36.  34 
  37.  35 #define max(a,b) ((a) > (b) ? (a) : (b))
  38.  36 #define min(a,b) ((a) < (b) ? (a) : (b))
  39.  37 
  40.  38 #define BSIZE     256   /* Maximum length of a line in the file */
  41.  39 #define PAGESIZE  23    /* # of lines to output before stopping */
  42.  40 
  43.  41 #define E(x)            fprintf(stderr,"%s\n", x)
  44.  42 #define HAS_DOT(p)      strchr(p,'.')
  45.  43 
  46.  44 FILE    *Ifile          = stdin;      /* Current input file               */
  47.  45 char    *Ifile_name     = "/dev/con"; /* Name of file associated w/ Ifile */
  48.  46 int     Repeat_count    = 1;          /* Repeat count for most recent cmd */
  49.  47 long    Line            = 0;          /* # of output Lines printed so far */
  50.  48 long    Flen            = 0;          /* Length of input file in chars    */
  51.  49 long    Start_here      = 0;          /* Seek to here when prog starts    */
  52.  50 
  53.  51 /*-----------------------------------------------------------------
  54.  52  *  Stack used to keep track of start of lines. Maximum number
  55.  53  *  of lines is determined by STACKSIZE.
  56.  54  */
  57.  55 
  58.  56 typedef long            STACKTYPE;
  59.  57 #define STACKSIZE       (1024*6)        /* Must be divisible by 2 */
  60.  58 
  61.  59 STACKTYPE               Stack[ STACKSIZE ];
  62.  60 STACKTYPE               *Sp = Stack + STACKSIZE;
  63.  61 
  64.  62 #define STACKFULL       (Sp <= Stack)
  65.  63 #define STACKEMPTY      (Sp >= Stack + STACKSIZE )
  66.  64 #define CLEAR_STACK()   Sp = Stack + STACKSIZE ;
  67.  65 #define TOS             (STACKEMPTY ? 0 : *Sp)
  68.  66 #define BACK_SCRN       *( min( Sp+(PAGESIZE-1), Stack+(STACKSIZE-1)) )
  69.  67 
  70.  68 #define erase_line()    line( ' ', 0 )  /* Draw a line of spaces    */
  71.  69 
  72.  70 /*------------------------------------------------------------------*/
  73.  71 
  74.  72 help()
  75.  73 {
  76.  74     register int        i;
  77.  75 
  78.  76     /*   Print a help message with a box around it, special IBM graphics
  79.  77      *   characters are used for the box
  80.  78      */
  81.  79 
  82.  80     putc( 0xd6, stderr );
  83.  81     for( i = 56 ; --i >= 0; putc( 0xc4, stderr) )
  84.  82         ;
  85.  83     E("\267");
  86.  84     E("\272 b ............... go (B)ack a page                     \272");
  87.  85     E("\272 e ............... go to end of file                    \272");
  88.  86     E("\272 n ............... go to (N)ext file                    \272");
  89.  87     E("\272 o ............... print (O)ffset from start of file    \272");
  90.  88     E("\272 q ............... (Q)uit (return to DOS)               \272");
  91.  89     E("\272 s ............... (S)kip one line (w/o printing)       \272");
  92.  90     E("\272 r ............... (R)ewind file (go back to beginning) \272");
  93.  91     E("\272 ! ............... execute a program (type blank line   \272");
  94.  92     E("\272                   at prompt to execute last)           \272");
  95.  93     E("\272 / ............... search for regular expression        \272");
  96.  94     E("\272                   (type blank line at prompt for last) \272");
  97.  95     E("\272 ESC ............. Scroll until any key is hit          \272");
  98.  96     E("\272 CR .............. next line                            \272");
  99.  97     E("\272 SP .............. next screen                          \272");
  100.  98     E("\272 anything else ... print this list                      \272");
  101.  99     E("\272                                                        \272");
  102. 100     E("\272 All commands may be preceeded by a count.              \272");
  103. 101 
  104. 102     putc( 0xd3, stderr );
  105. 103     for( i = 56 ; --i >= 0; putc( 0xc4 ,stderr) )
  106. 104         ;
  107. 105 
  108. 106     E("\275");
  109. 107 }
  110. 108 
  111. 109 /*------------------------------------------------------------------*/
  112. 110 
  113. 111 usage()
  114. 112 {
  115. 113     E("more:  Copyright (C) 1986, Allen I. Holub. All rights reserved.");
  116. 114     E("\nUseage: more [+<num>] [file...] \n");
  117. 115     E("Print all files in list on the screen, pausing every 23 lines");
  118. 116     E("If + is specified, more will start printing at character <num>");
  119. 117     E("One of the following commands is executed after each page:");
  120. 118 
  121. 119     help();
  122. 120     exit(1);
  123. 121 }
  124. 122 
  125. 123 /*----------------------------------------------------------------------*/
  126. 124 
  127. 125 push( file_posn )
  128. 126 long    file_posn;              /* Push file_posn onto the stack     */
  129. 127 {
  130. 128         if( STACKFULL )         /* If the stack is full, compress it */
  131. 129                 comp_stk();
  132. 130 
  133. 131         *( --Sp ) = file_posn;
  134. 132 }
  135. 133 
  136. 134 /*------------------------------------------------------------------*/
  137. 135 
  138. 136 long    pop()
  139. 137 {
  140. 138         /*      Pop one entry off the stack and return the file
  141. 139          *      position.
  142. 140          */
  143. 141 
  144. 142         return STACKEMPTY ? 0 : *Sp++ ; 
  145. 143 }
  146. 144 
  147. 145 /*------------------------------------------------------------------*/
  148. 146 
  149. 147 comp_stk()
  150. 148 {
  151. 149         /*      Compress the stack by removing every other entry.
  152. 150          *      This routine is called when the stack is full (we've
  153. 151          *      read more lines than the stack can hold).
  154. 152          */
  155. 153 
  156. 154         register STACKTYPE      *dest, *src;
  157. 155 
  158. 156         fprintf(stderr,"\007Stack Full:  Compressing\n");
  159. 157 
  160. 158         src = dest = Stack + STACKSIZE;
  161. 159 
  162. 160         while( (src -= 2) >= Stack )
  163. 161                 *--dest = *src;
  164. 162 
  165. 163         Sp = dest;
  166. 164 }
  167. 165 
  168. 166 /*------------------------------------------------------------------*/
  169. 167 
  170. 168 getcon()
  171. 169 {
  172. 170         /*      Get one character from the console using a direct
  173. 171          *      bios call. Map \r into \n if one is encountered.
  174. 172          */
  175. 173 
  176. 174         register int    c;
  177. 175 
  178. 176         c = b_getc() & 0x7f;    /* Get a character from console */
  179. 177         putchar(c);             /* Echo character               */
  180. 178 
  181. 179         return ( c == '\r' ) ? '\n' : c ;
  182. 180 }
  183. 181 
  184. 182 /*----------------------------------------------------------------------*/
  185. 183 
  186. 184 clear_io()
  187. 185 {
  188. 186         /*      Clears the entire I/O queue, both at the bios and the
  189. 187          *      bdos level.
  190. 188          */
  191. 189 
  192. 190         while( look() )
  193. 191                 b_getc();
  194. 192 
  195. 193 #ifdef NEVER
  196. 194         while( kbhit() )
  197. 195                 getchar();
  198. 196 #endif
  199. 197 
  200. 198 }
  201. 199 
  202. 200 /*----------------------------------------------------------------------*/
  203. 201 
  204. 202 khit()                          /* Return true if a key has been hit on */
  205. 203 {                               /* the physical keyboard (as compared   */
  206. 204         if( look() )            /* with a character available on stdin) */
  207. 205         {
  208. 206                 clear_io();
  209. 207                 return 1;
  210. 208         }
  211. 209         return 0;
  212. 210 }
  213. 211 
  214. 212 /*----------------------------------------------------------------------*/
  215. 213 
  216. 214 char    *getbuf( p )
  217. 215 register char   *p;
  218. 216 {
  219. 217         /*      Get a line of input using direct console I/O and put it
  220. 218          *      into buf. Return a pointer to the first whitespace on the
  221. 219          *      line or to end of line if none. This routine is for
  222. 220          *      getting commands from the user, not for getting normal
  223. 221          *      input. ^H is supported as a destructive backspace but no
  224. 222          *      other editing is available.
  225. 223          */
  226. 224 
  227. 225         register int    c;
  228. 226         int             gottail = 0;
  229. 227         char            *start  = p;
  230. 228         char            *tail   = "" ;
  231. 229 
  232. 230         clear_io();
  233. 231 
  234. 232         while( (c=getcon()) != '\n' )
  235. 233         {
  236. 234                 if( c == '\b' )
  237. 235                 {
  238. 236                         if( p <= start )
  239. 237                                 fputs( " \007", stderr );
  240. 238                         else
  241. 239                         {
  242. 240                                 --p;
  243. 241                                 fputs( " \b", stderr );
  244. 242                         }
  245. 243                 }
  246. 244                 else 
  247. 245                 {
  248. 246                         if( isspace(c) && !gottail )
  249. 247                                 gottail = (int)( tail = p );
  250. 248                         *p++ = c;
  251. 249                 }
  252. 250         }
  253. 251 
  254. 252         *p = '\0';
  255. 253         return( p <= start ? NULL : tail );
  256. 254 }
  257. 255 
  258. 256 /*------------------------------------------------------------------*/
  259. 257 
  260. 258 percent(s)
  261. 259 char    *s;
  262. 260 {
  263. 261         /* Print the percentage of the file that we've seen so far  */
  264. 262 
  265. 263         printf("%4.1f%%%s", ((double)TOS / (double)Flen) * 100.00, s );
  266. 264 }
  267. 265 
  268. 266 /*------------------------------------------------------------------*/
  269. 267 
  270. 268 int     getcmd()
  271. 269 {
  272. 270         /*      Get a command from the keyboard, using direct
  273. 271          *      bios I/O. Commands take the form [num]<c>. Returns
  274. 272          *      the command. Repeat_count is initialized to hold [num]
  275. 273          *      or 1 if no num is entered.
  276. 274          */
  277. 275 
  278. 276         int     c;
  279. 277 
  280. 278         clear_io();
  281. 279         percent("");
  282. 280         printf(", line %ld (? for commands): ", Line );
  283. 281 
  284. 282         Repeat_count = 0;
  285. 283         while( '0' <= (c = getcon()) && c <= '9' )
  286. 284                 Repeat_count = (Repeat_count * 10) + (c - '0');
  287. 285 
  288. 286         if( Repeat_count == 0 )
  289. 287                 Repeat_count = 1;
  290. 288 
  291. 289         erase_line();
  292. 290 
  293. 291         if( c == 0x03 )                         /* ^C == abort  */
  294. 292                 exit( 1 );
  295. 293 
  296. 294         return( c );
  297. 295 }
  298. 296 
  299. 297 /*------------------------------------------------------------------*/
  300. 298 
  301. 299 char    *inputline( suppress )
  302. 300 {
  303. 301         /* Get a line from the file being processed and put it into
  304. 302          * buf. Push the start of line character onto the stack.
  305. 303          * return 0 on end of file, a pointer to the line (ie. to buf)
  306. 304          * otherwise.
  307. 305          */
  308. 306 
  309. 307         register int    rval;
  310. 308         register long   start_of_line ;
  311. 309         static   char   buf[BSIZE];
  312. 310 
  313. 311         start_of_line = ftell( Ifile );
  314. 312 
  315. 313         if( rval = (int) fgets(buf, BSIZE, Ifile) )
  316. 314         {
  317. 315                 Line++;
  318. 316                 push( start_of_line );
  319. 317                 if( !suppress )
  320. 318                         fputs( buf, stdout );
  321. 319         }
  322. 320 
  323. 321         return rval ? buf : NULL ;
  324. 322 }
  325. 323 
  326. 324 /*------------------------------------------------------------------*/
  327. 325 
  328. 326 printpage()
  329. 327 {
  330. 328         /* Print an entire page from the input file                 */
  331. 329 
  332. 330         register int    i;
  333. 331 
  334. 332         for( i = PAGESIZE-1; --i >= 0 && inputline(0); )
  335. 333                 ;
  336. 334 }
  337. 335 
  338. 336 /*-------------------------------------------------------------------*/
  339. 337 
  340. 338 search()
  341. 339 {
  342. 340         /*      Prompt for a pattern and then search for it in the
  343. 341          *      file. Stop searching if the pattern is found or if
  344. 342          *      any key is hit. The previous pattern is remembered
  345. 343          *      in a local array so, if CR is entered instead of a
  346. 344          *      pattern, the previous pattern is used.
  347. 345          */
  348. 346 
  349. 347         static   char   pat[128], opat[128] ;
  350. 348         char            *iline;
  351. 349         extern  int     *makepat();
  352. 350         int             *template;
  353. 351 
  354. 352         printf("/");
  355. 353 
  356. 354         if( !getbuf( pat ) )
  357. 355                 strcpy( pat, opat );
  358. 356 
  359. 357         if( !(template = makepat( pat, 0 )) )
  360. 358                 printf("Illegal regular expression: %s\n", pat );
  361. 359         else
  362. 360         {
  363. 361                 erase_line();
  364. 362                 printf("/%s\n", pat );
  365. 363 
  366. 364                 while( (iline = inputline(1))  &&  !khit() )
  367. 365                 {
  368. 366                         percent("\r");
  369. 367                         if( matchs( iline, template, 0) )
  370. 368                                 break;
  371. 369                 }
  372. 370 
  373. 371                 unmakepat( template );
  374. 372                 fseek( Ifile, pop(), 0 );  /* back up one line  */
  375. 373                 --Line;
  376. 374                 line ( 0xcd, 1);
  377. 375                 printpage();    
  378. 376         }
  379. 377 
  380. 378         strcpy( opat, pat );
  381. 379 }
  382. 380 
  383. 381 /*----------------------------------------------------------------------*/
  384. 382 
  385. 383 execute()
  386. 384 {
  387. 385         /*      Spawn off a child process. When the process terminates
  388. 386          *      print a message and redraw the current page. Note that
  389. 387          *      spawn() is used (rather than system()) so you can't
  390. 388          *      execute a batch file or a built-in command. This
  391. 389          *      subroutine will set the CMDLINE environment variable
  392. 390          *      to a null string for the sake of those routines that
  393. 391          *      are executing under the shell which will use it.
  394. 392          */
  395. 393 
  396. 394         static   char   buf[128];
  397. 395         char            *tail = " ";
  398. 396 
  399. 397         static   char   obuf[128], *otail = obuf;
  400. 398 
  401. 399         register char   *p;
  402. 400         register int    c;
  403. 401         int             got_tail = 0;
  404. 402 
  405. 403         printf("!");
  406. 404 
  407. 405         if( !(tail = getbuf(buf)) )             /* If no command entered, */
  408. 406         {                                       /* use the same one we    */
  409. 407                 tail = otail;                   /* used last time         */
  410. 408                 memcpy( buf, obuf, 128 );
  411. 409                 printf( "\n!%s %s\n", buf, tail );
  412. 410         }
  413. 411         else
  414. 412         {
  415. 413                 if( *tail )
  416. 414                         *tail++ = '\0';
  417. 415         }
  418. 416 
  419. 417         if( HAS_DOT(buf) )
  420. 418         {
  421. 419                 /* Spawnlp will actually try to execute any file that you
  422. 420                  * give it. If you say to execute an ASCII file, it will
  423. 421                  * load that file into memory, try to execute it, and die
  424. 422                  * a horrible death. We attempt to avoid this by checking
  425. 423                  * for a dot in the file name. You may want to put a
  426. 424                  * more rigorous test here.
  427. 425                  */
  428. 426 
  429. 427                 fprintf(stderr,"\007<%s> is not a command\n", buf);
  430. 428         }
  431. 429         else
  432. 430         {
  433. 431                 putenv("CMDLINE=");
  434. 432                 if( spawnlp(P_WAIT, buf, buf, tail, NULL) == -1)
  435. 433                       fprintf(stderr,"Can't execute <%s %s>\n", buf, tail );
  436. 434 
  437. 435         }
  438. 436 
  439. 437         printf("Hit any key to continue ....");
  440. 438         getcon();
  441. 439         erase_line();
  442. 440         putchar('\n');
  443. 441 
  444. 442         otail = tail;
  445. 443         memcpy( obuf, buf, 128 );
  446. 444 }
  447. 445 
  448. 446 /*----------------------------------------------------------------------*/
  449. 447 
  450. 448 line( c , newline )
  451. 449 {
  452. 450         /*      Print a line of characters to mark top of page. 0xcd
  453. 451          *      is the IBM graphics character for a horizontal double
  454. 452          *      line. The cursor is put at the beginning of next line
  455. 453          *      if "newline" is true, else it's put at beginning of
  456. 454          *      current line.
  457. 455          */
  458. 456 
  459. 457         register int    i;
  460. 458 
  461. 459         putchar('\r');
  462. 460 
  463. 461         for( i = 79; --i >= 0 ; putchar( c ) )
  464. 462                 ;
  465. 463 
  466. 464         putchar( newline ? '\n' : '\r' );
  467. 465 
  468. 466 }
  469. 467 
  470. 468 /*------------------------------------------------------------------*/
  471. 469 
  472. 470 backapage( count )
  473. 471 {
  474. 472         /*      Go back count pages and print the resulting page.
  475. 473         */
  476. 474 
  477. 475         register int    i;
  478. 476 
  479. 477         i = ((count+1) * PAGESIZE) -1;
  480. 478 
  481. 479         while( --i >= 0 )
  482. 480         {
  483. 481                 Line--;
  484. 482                 pop();
  485. 483         }
  486. 484 
  487. 485         line ( 0xcd, 1);
  488. 486         fseek( Ifile, pop(), 0 );
  489. 487         Line = max( Line - 1, 0 );
  490. 488         printpage();
  491. 489 }
  492. 490 
  493. 491 /*------------------------------------------------------------------*/
  494. 492 
  495. 493 docmd( cmd, ateof )
  496. 494 {
  497. 495         /*      Do a single command, return 1 if next file is requested.
  498. 496          *      Actually call exit on a "quit" command or ^C.
  499. 497          */
  500. 498 
  501. 499         register int    rval = 0;
  502. 500         register int    i;
  503. 501         long            posn;
  504. 502 
  505. 503         do {
  506. 504                 switch( cmd )
  507. 505                 {
  508. 506                 case CAN:       break;          /* NOP                  */
  509. 507                 case 'q':       exit(0);        /* abort                */
  510. 508 
  511. 509                 case '\n':                      /* FORWARD MOTION       */
  512. 510                         if( ateof )             /* one line             */
  513. 511                                 rval = 1;
  514. 512                         else
  515. 513                                 inputline(0);
  516. 514                         break;
  517. 515 
  518. 516                 case ' ':                       /* one page             */
  519. 517                         if( ateof )
  520. 518                                 rval = 1;
  521. 519 
  522. 520                         printpage();
  523. 521                         break;
  524. 522 
  525. 523                 case 'e':                       /* To end of file       */
  526. 524                         erase_line();
  527. 525                         while( inputline(1) && !khit() )
  528. 526                                 percent("\r");
  529. 527                         break;
  530. 528 
  531. 529                 case 's':                       /* one line w/o printing */
  532. 530                         if( ateof )
  533. 531                                 rval = 1;
  534. 532                         else
  535. 533                         {
  536. 534                                 erase_line();
  537. 535                                 inputline(1);
  538. 536                                 percent("\r");
  539. 537                         }
  540. 538                         break;
  541. 539 
  542. 540                 case ESC:                     /* scroll till key is hit */
  543. 541                         if( ateof )
  544. 542                                 rval = 1;
  545. 543                         else
  546. 544                                 while( inputline(0) && !khit() )
  547. 545                                         clear_io();
  548. 546 
  549. 547                         clear_io();
  550. 548                         Repeat_count = 0;       /* Ignore repeat count  */
  551. 549                         break;                  /* if it's set          */
  552. 550 
  553. 551                 case 'n':                       /* to next file         */
  554. 552                         rval = 1;
  555. 553                         break;
  556. 554 
  557. 555                 case '/':                       /* search for pattern   */
  558. 556                         search();
  559. 557                         break;
  560. 558 
  561. 559                 case 'r':                       /* to start of file     */
  562. 560                         line( 0xcd, 1 );
  563. 561                         CLEAR_STACK();
  564. 562                         Line = 0;
  565. 563                         fseek( Ifile, 0L, 0 );
  566. 564                         printpage();
  567. 565                         break;
  568. 566 
  569. 567                 case 'b':                       /* to previous page     */
  570. 568                         backapage( Repeat_count );
  571. 569                         Repeat_count = 0;
  572. 570                         break;
  573. 571 
  574. 572                 case 'o':                       /* print file position  */
  575. 573 
  576. 574                         printf("Top line = %ld, ",      BACK_SCRN );
  577. 575                         printf("Bottom line = %ld\n",   TOS       );
  578. 576                         break;
  579. 577 
  580. 578                 case '!':
  581. 579                         /* Close the file and spawn another shell.
  582. 580                          * when we come back, reopen the file
  583. 581                          * and position to the same place we
  584. 582                          * were before. This is necessary because of
  585. 583                          * a bug in Microsoft C ver. 3.0's spawn functions
  586. 584                          * (they trash the IOB). It will cause problems
  587. 585                          * if standard input is used as the input source
  588. 586                          * (as in a pipe) because we won't be able to
  589. 587                          * successfully reopen stdin.
  590. 588                          */
  591. 589 
  592. 590                         Repeat_count = 0;       /* Ignore repeat count */
  593. 591                         fclose( Ifile );
  594. 592                         execute();
  595. 593                         posn = pop();
  596. 594 
  597. 595                         if( Ifile = fopen(Ifile_name, "r") )
  598. 596                         {
  599. 597                                 fseek( Ifile, posn, 0 );
  600. 598                                 backapage( 0 );
  601. 599                         }
  602. 600                         else
  603. 601                         {
  604. 602                                 fprintf(stderr,"more: can't open %s\n",
  605. 603                                                                 Ifile_name);
  606. 604                                 rval = 1;
  607. 605                         }
  608. 606                         break;
  609. 607 
  610. 608                 default :                       /* Print the help msg.  */
  611. 609                         help();
  612. 610                         cmd = getcmd();         /* get a new command    */
  613. 611                         Repeat_count++;
  614. 612                         break;
  615. 613                 }
  616. 614 
  617. 615         } while( --Repeat_count > 0 );
  618. 616 
  619. 617         return( rval );
  620. 618 }
  621. 619 
  622. 620 /*----------------------------------------------------------------------*/
  623. 621 
  624. 622 dofile( fname )
  625. 623 char    *fname;
  626. 624 {
  627. 625         /*      Process lines from an input file having the indicated
  628. 626          *      name.
  629. 627          */
  630. 628 
  631. 629         if( (Ifile_name = fname)  &&  !(Ifile = fopen(fname, "r")) )
  632. 630                 fprintf(stderr, "more: can't open %s\n", fname );
  633. 631         else
  634. 632         {
  635. 633                 Flen = filelength( fileno(Ifile) );
  636. 634                 fseek( Ifile, Start_here, 0 );
  637. 635 
  638. 636                 CLEAR_STACK();
  639. 637                 docmd(' ', 0 );                 /* dump the first page */
  640. 638 
  641. 639                 for(;;)
  642. 640                 {
  643. 641                         for(;;)
  644. 642                         {
  645. 643                                 if( docmd( getcmd(), 0) )
  646. 644                                         return;
  647. 645 
  648. 646                                 if( feof(Ifile) )
  649. 647                                         break;
  650. 648                         }
  651. 649 
  652. 650                         E("\n\020\020\020 LAST LINE IN FILE \021\021\021");
  653. 651                         if( docmd( getcmd(), 1) )
  654. 652                                 break;
  655. 653                 }
  656. 654 
  657. 655                 fclose( Ifile );
  658. 656         }
  659. 657 }
  660. 658 
  661. 659 /*------------------------------------------------------------------*/
  662. 660 
  663. 661 main(argc, argv)
  664. 662 char    **argv;
  665. 663 {
  666. 664         ctlc();
  667. 665         reargv(&argc, &argv);
  668. 666 
  669. 667         if( argc > 1 )
  670. 668         {
  671. 669                 if( argv[1][0] == '-' )
  672. 670                         usage();
  673. 671 
  674. 672                 else if (argv [1][0] == '+' )
  675. 673                 {
  676. 674                         Start_here = atol( &argv[1][1] );
  677. 675                         printf("Starting at character %ld\n", Start_here );
  678. 676                         push  ( Start_here );
  679. 677                         ++argv;
  680. 678                         --argc;
  681. 679                 }
  682. 680         }
  683. 681 
  684. 682         if( argc <= 1 )
  685. 683                 dofile( NULL );
  686. 684         else
  687. 685                 for(; --argc > 0 ; dofile(*++argv) )
  688. 686                         ;
  689. 687 
  690. 688         exit(0);
  691. 689 }
  692.                              Listing 2 -- b_getc.c
  693.  ------------------------------------------------------------------------------
  694.   1 #include <stdio.h>
  695.   2 #include <dos.h>
  696.   3 
  697.   4 /*   B_GETC.C           Get a character with a direct video bios call.
  698.   5  *                      this routine can be used to complement stderr as
  699.   6  *   it can be used to get characters from the keyboard, even when input
  700.   7  *   redirected. The typed character is returned in the low byte of the
  701.   8  *   returned integer, the high byte holds the auxillary byte used to
  702.   9  *   mark ALT keys and such. See the Technical Ref for more info.
  703.  10  *
  704.  11  *   Copyright (C) 1985 Allen I. Holub. All rights reserved.
  705.  12  *
  706.  13  *----------------------------------------------------------------------
  707.  14  */
  708.  15 
  709.  16 extern int int86(int, union REGS *, union REGS *);
  710.  17 
  711.  18 /*----------------------------------------------------------------------*/
  712.  19 
  713.  20 #define KB_INT  0x16    /*      Keyboard BIOS interrupt                 */
  714.  21 #define GETC    0x00    /*      Getc is service 0                       */
  715.  22 
  716.  23 
  717.  24 int     b_getc()
  718.  25 {
  719.  26         union REGS      Regs;
  720.  27 
  721.  28         Regs.h.ah = GETC ;
  722.  29         int86( KB_INT, &Regs, &Regs );
  723.  30         return( (int)Regs.x.ax );
  724.  31 }
  725.                             Listing 3 -- look.asm
  726.  ------------------------------------------------------------------------------
  727.   1 ;       Static Name Aliases
  728.   2 ;
  729.   3         TITLE   foo
  730.   4 
  731.   5 _TEXT   SEGMENT  BYTE PUBLIC 'CODE'
  732.   6 _TEXT   ENDS
  733.   7 CONST   SEGMENT  WORD PUBLIC 'CONST'
  734.   8 CONST   ENDS
  735.   9 _BSS    SEGMENT  WORD PUBLIC 'BSS'
  736.  10 _BSS    ENDS
  737.  11 _DATA   SEGMENT  WORD PUBLIC 'DATA'
  738.  12 _DATA   ENDS
  739.  13 ;
  740.  14 DGROUP  GROUP   CONST,  _BSS,   _DATA
  741.  15         ASSUME  CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
  742.  16 ;
  743.  17 _DATA   SEGMENT
  744.  18 EXTRN   __chkstk:NEAR
  745.  19 _DATA   ENDS
  746.  20 ;
  747.  21 _TEXT      SEGMENT
  748.  22 ;
  749.  23 ; int   look();
  750.  24 ;
  751.  25 ;       Tests the bios to see if a key has been hit. If no key has been
  752.  26 ;       hit then 0 is returned, else an int is returned in which the
  753.  27 ;       high byte is the scan code and the low byte is the character
  754.  28 ;       code, if the low byte is 0 then a non-ascii key has been hit
  755.  29 ;
  756.  30         PUBLIC  _look
  757.  31 _look   PROC NEAR
  758.  32         push    bp
  759.  33         mov     bp,sp
  760.  34         mov     ax,2
  761.  35         call    __chkstk
  762.  36 
  763.  37         mov     ah,1            ; service 1, Report on character ready
  764.  38         int     016H            ; BIOS keyboard interrupt.
  765.  39         jnz     exit            ; jump if a key is available
  766.  40                                 ;       (return the character)
  767.  41         mov     ax,0            ; else  (return 0);
  768.  42 exit:
  769.  43         mov     sp,bp
  770.  44         pop     bp
  771.  45         ret
  772.  46 _look   ENDP
  773.  47 
  774.  48 _TEXT   ENDS
  775.  49 END
  776.  
  777.