home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / nshellmegasource1.50 / mega src / commands / head.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-01  |  8.8 KB  |  407 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     head.c
  4.     
  5.     Copyright (c) 1994 Newport Software Development
  6.     
  7.     You may distribute unmodified copies of this file for
  8.     noncommercial purposes.  You may use this file as a
  9.     reference when writing your own nShell(tm) commands.
  10.     
  11.     All other rights are reserved.
  12.     
  13.    ========== the commmand file: ========== */
  14.  
  15. #define    HEAD_BUF_SIZE    2048
  16.  
  17. #ifdef __MWERKS__            // CodeWarrior requires an A4 setup
  18. #include <A4Stuff.h>
  19. #endif
  20.  
  21. #include "nshc.h"
  22.  
  23. #include "arg_utl.proto.h"
  24. #include "fss_utl.proto.h"
  25. #include "nshc_utl.proto.h"
  26. #include "str_utl.proto.h"
  27.  
  28. // data definition - this struct is the root of all data
  29.  
  30. typedef struct {
  31.  
  32.     short    got_fss;        // 0 if FSSpec calls are not available
  33.     short    arg;            // position in arg list
  34.     short    n_arg;            // non-zero if an -n option was used
  35.     short    by_file;        // 1 if files are listed, 0 if stdin
  36.     short    fref;            // file ref. number, 0 if no file open
  37.     long    lines;            // the line count for the current file
  38.     long    lines_max;        // the line limit
  39.  
  40. } t_head_data;
  41.  
  42. typedef    t_head_data    **HeadHndl;
  43.  
  44. /* ======================================== */
  45.  
  46. // prototypes - utility
  47.  
  48. void head_bad( t_nshc_parms *nshc_parms, int code );
  49. void head_bad_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg );
  50. void head_good( t_nshc_parms *nshc_parms );
  51.  
  52. // prototypes - file copy routines
  53.  
  54. void head_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_head_data **hData );
  55. void head_read_write( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_head_data **hData );
  56.  
  57. // prototypes - console copy routines
  58.  
  59. void head_console( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_head_data **hData );
  60.  
  61. // prototypes - state machine
  62.  
  63. void head_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  );
  64. void head_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  65. void head_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  66.  
  67. /* ======================================== */
  68.  
  69. // utility routines
  70.  
  71. /* ======================================== */
  72.  
  73. void head_bad(  t_nshc_parms *nshc_parms, int code )
  74. {
  75.     nshc_parms->action = nsh_stop;
  76.     nshc_parms->result = code;
  77. }
  78.  
  79. void head_bad_file(  t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg )
  80. {
  81.     nshc_calls->NSH_putStr_err("\phead: File access error (");
  82.     nshc_calls->NSH_putStr_err(msg);
  83.     nshc_calls->NSH_putStr_err("\p)\r");
  84.  
  85.     nshc_parms->action = nsh_stop;
  86.     nshc_parms->result = NSHC_ERR_FILE;
  87. }
  88.  
  89. void head_good(  t_nshc_parms *nshc_parms )
  90. {
  91.     nshc_parms->action = nsh_stop;
  92.     nshc_parms->result = 0;
  93. }
  94.  
  95. /* ======================================== */
  96.  
  97. // file access routines
  98.  
  99. /* ======================================== */
  100.  
  101. void head_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_head_data **hData )
  102. {
  103.     int        result;
  104.     long    dirID;
  105.     Boolean    isDir;
  106.     FSSpec    fss;
  107.     
  108.     // by definition, there is no open file, and it has no lines
  109.     
  110.     (**hData).fref = 0;
  111.     (**hData).lines = 0;
  112.  
  113.     // skip the -n option
  114.     
  115.     if ( (**hData).arg == (**hData).n_arg )
  116.         (**hData).arg += 2;
  117.         
  118.     if ( (**hData).arg >= nshc_parms->argc ) {
  119.         head_good( nshc_parms );
  120.         return;
  121.         }
  122.     
  123.     // =====> convert path to fsspec
  124.     
  125.     result = arg_to_fss( nshc_parms, nshc_calls, (**hData).arg, &fss );
  126.  
  127.     (**hData).arg++;
  128.     
  129.     if (result) {
  130.         head_bad( nshc_parms, result );
  131.         return;
  132.         }
  133.     
  134.     result = fss_to_DirID( &fss, &dirID, &isDir );
  135.         
  136.     if (( result == noErr) && isDir)
  137.         return;
  138.             
  139.     if ( result == fnfErr ) {
  140.         nshc_calls->NSH_putStr_err("\phead: File not found = ");
  141.         nshc_calls->NSH_putStr_err((StringPtr)fss.name);
  142.         nshc_calls->NSH_putchar('\r');
  143.         return;
  144.         }
  145.             
  146.     if (!result)
  147.         result = fss_OpenDF((**hData).got_fss, &fss, fsRdPerm, &(**hData).fref);
  148.     
  149.     if ( result ) {
  150.         head_bad_file( nshc_parms, nshc_calls, (StringPtr)fss.name );
  151.         return;
  152.         }
  153. }
  154.  
  155. /* ======================================== */
  156.  
  157. void head_read_write( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_head_data **hData )
  158. {
  159.     int        close;
  160.     int        temp;
  161.     int        result;
  162.     long    bcount;
  163.     char    buf[HEAD_BUF_SIZE+1];
  164.     char    c;
  165.     char    *p;
  166.     
  167.     result = close = 0;
  168.     
  169.     // =====> copy the data fork
  170.     
  171.     bcount = HEAD_BUF_SIZE;
  172.     result = FSRead( (**hData).fref, &bcount, &buf );
  173.     
  174.     if (( result == noErr ) || ( result == eofErr )) {
  175.     
  176.         if (result == eofErr) {
  177.             close = 1;
  178.             result = 0;
  179.             }
  180.         
  181.         if (bcount) {
  182.         
  183.             buf[bcount] = '\0';                    // make sure there is termination
  184.             
  185.             p = buf;
  186.                     
  187.             while ( c = *p++ ) {                // adjust line count and limit string
  188.                 if ( c == '\r' )
  189.                     (**hData).lines++;
  190.                 if ( (**hData).lines >= (**hData).lines_max ) {
  191.                     *p = 0;
  192.                     close = 1;
  193.                     break;
  194.                     }
  195.                 }
  196.                 
  197.             nshc_calls->NSH_puts( buf );    // display the line
  198.                 
  199.             }
  200.         
  201.         }
  202.     else
  203.         head_bad_file( nshc_parms, nshc_calls, "\pread data" );
  204.     
  205.     // =====> close the input file
  206.     
  207.     if (close) {
  208.  
  209.         if ( (**hData).fref ) {
  210.             if ( temp = FSClose( (**hData).fref ) )
  211.                 result = temp;
  212.             (**hData).fref = 0;
  213.             }
  214.             
  215.         if (result)
  216.             head_bad_file( nshc_parms, nshc_calls, "\pclose file" );
  217.                 
  218.         }
  219. }
  220.  
  221. /* ======================================== */
  222.  
  223. // console access routines
  224.  
  225. /* ======================================== */
  226.  
  227. #define    LINES_PER_PASS    10
  228.  
  229. void head_console( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_head_data **hData )
  230. {
  231.     long    bcount;
  232.     char    buf[LINE_MAX];
  233.     char    c;
  234.     char    *p;
  235.     int        pass;
  236.     
  237.     // if characters are waiting, pick up a few lines
  238.         
  239.     pass = 1;
  240.     
  241.     while ( pass++ < LINES_PER_PASS ) {
  242.     
  243.         bcount = nshc_calls->NSH_gets( buf, LINE_MAX );
  244.         
  245.         if (!bcount) return;                // go get more characters
  246.                 
  247.         if ( (**hData).lines < (**hData).lines_max ) {
  248.  
  249.             p = buf;
  250.                 
  251.             while ( c = *p++ )                // adjust line count
  252.                 if ( c == '\r' )
  253.                     (**hData).lines++;
  254.             
  255.             nshc_calls->NSH_puts( buf );    // display the line
  256.             
  257.             }
  258.                     
  259.         if ( bcount == -1 )     {                // end of input, set-up for exit
  260.             head_good( nshc_parms );
  261.             return;
  262.             }
  263.             
  264.         }
  265. }
  266.  
  267. /* ======================================== */
  268.  
  269. // state machine - core routines
  270.  
  271. /* ======================================== */
  272.  
  273. void head_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  )
  274. {
  275.     HeadHndl    hData;    // handle to hold our data
  276.     int            usage;  // if 1, usage error
  277.     
  278.     nshc_parms->action = nsh_continue;
  279.  
  280.     hData = (HeadHndl)NewHandleClear(sizeof(t_head_data));
  281.     
  282.     if (hData) {
  283.     
  284.         (**hData).arg = 1;                            // start at the arg = 1 position
  285.         (**hData).got_fss = fss_test();                // test if we can use FSSpec calls
  286.         (**hData).lines_max = 10;                    // do ten lines as default
  287.         
  288.         usage = 0;
  289.         
  290.         if ( (**hData).n_arg = nshc_got_option( nshc_parms, 'n' ) ) {
  291.         
  292.             usage = 1;
  293.         
  294.             if ( nshc_is_numeric_operand( nshc_parms, (**hData).n_arg + 1 ) ) {
  295.                 (**hData).lines_max = arg_to_num( nshc_parms, (**hData).n_arg + 1 );
  296.                 (**hData).by_file = nshc_parms->argc > 3;    // if we have other args, do file i/o
  297.                 usage = 0;
  298.                 }
  299.                 
  300.             }
  301.         else
  302.             (**hData).by_file = nshc_parms->argc > 1;    // if we have other args, do file i/o
  303.         
  304.         if ( usage ) {
  305.             nshc_calls->NSH_putStr_err( "\pUsage: head [-n lines] [files...]\r" );
  306.             head_bad( nshc_parms, NSHC_ERR_MEMORY );
  307.             }
  308.         
  309.         nshc_parms->data = (Handle)hData;
  310.         }
  311.     else {
  312.         nshc_calls->NSH_putStr_err( "\phead: Could not allocate storage.\r" );
  313.         head_bad( nshc_parms, NSHC_ERR_MEMORY );
  314.         }
  315. }
  316.  
  317. /* ======================================== */
  318.  
  319. void head_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  320. {
  321.     HeadHndl    hData;
  322.  
  323.     if (hData = (HeadHndl)nshc_parms->data) {
  324.  
  325.         if ( (**hData).by_file ) {
  326.         
  327.             // if we are not in the middle of a file, open one
  328.  
  329.             if ( !(**hData).fref )
  330.                 head_open( nshc_parms, nshc_calls, hData );
  331.  
  332.             // read and write some of the open file
  333.  
  334.             if ( (**hData).fref )
  335.                 head_read_write( nshc_parms, nshc_calls, hData );
  336.  
  337.             // and see if we are done
  338.  
  339.             if ( !(**hData).fref && ( (**hData).arg >= nshc_parms->argc ) )
  340.                 head_good( nshc_parms );
  341.                 
  342.             }
  343.         else
  344.             head_console( nshc_parms, nshc_calls, hData );
  345.  
  346.         }
  347. }
  348.  
  349. /* ======================================== */
  350.  
  351. void head_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  352. {
  353.     short        fRef;
  354.     HeadHndl    hData;
  355.     int            temp;
  356.     int            result;
  357.     
  358.     result = 0;
  359.     
  360.     if (hData = (HeadHndl)nshc_parms->data) {
  361.     
  362.         if ( (**hData).fref ) {
  363.             if ( temp = FSClose( (**hData).fref ) )
  364.                 result = temp;
  365.             (**hData).fref = 0;
  366.             }
  367.             
  368.         DisposeHandle(nshc_parms->data);
  369.         }
  370.         
  371.     if (result)
  372.         head_bad_file( nshc_parms, nshc_calls, "\pclosing files" );
  373.         
  374.     nshc_parms->action = nsh_idle;
  375. }
  376.  
  377. /* ======================================== */
  378.  
  379. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  380. {
  381. #ifdef __MWERKS__
  382.     long oldA4  = SetCurrentA4();
  383. #endif
  384.     
  385.     if ( !nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION ) ) {
  386.     
  387.         switch (nshc_parms->action) {
  388.             case nsh_start:
  389.                 head_start(nshc_parms, nshc_calls);
  390.                 break;
  391.             case nsh_continue:
  392.                 head_continue(nshc_parms, nshc_calls);
  393.                 break;
  394.             case nsh_stop:
  395.                 head_stop(nshc_parms, nshc_calls);
  396.                 break;
  397.             }
  398.         
  399.         }
  400.  
  401. #ifdef __MWERKS__
  402.     SetA4(oldA4);
  403. #endif
  404. }
  405.  
  406. /* ======================================== */
  407.