home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Tools / nShell™ 1.0.3 / MoreSource / wc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-29  |  11.7 KB  |  522 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     wc.c
  4.     
  5.     Copyright (c) 1993,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. #ifdef __MWERKS__            // CodeWarrior requires an A4 setup
  16. #include <A4Stuff.h>
  17. #endif
  18.  
  19. #define    FILE_BUF_SIZE        2048
  20.  
  21. #define    CONSOLE_BUF_SIZE    200
  22.  
  23. #include "nshc.h"
  24. #include "arg_utl.proto.h"
  25. #include "fss_utl.proto.h"
  26. #include "str_utl.proto.h"
  27. #include "nshc_utl.proto.h"
  28.  
  29. /* ======================================== */
  30.  
  31. // our data record, NewHandled and attached to nshc_parms->data
  32.  
  33. typedef struct {
  34.  
  35.     int        by_file;        // 1 if files are listed, 0 if stdin
  36.     
  37.     int        got_fss;        // 0 if FSSpec calls are not available
  38.     int        arg;            // position in arg list (if by file)
  39.     short    fref;            // file ref. number, 0 if no file open
  40.     int        fcount;            // number of files processed
  41.     int        inword;            // 1 if we are in the middle of a word
  42.     
  43.     int        got_options;    // 1 if any option was given
  44.     int        line_option;    // show-line option was given
  45.     int        word_option;    // show-word option was given
  46.     int        bytes_option;    // show-bytes option was given
  47.  
  48.     long    lines;            // number of carridge returns (seen a carridge lately?)
  49.     long    lines_total;    // total number of carridge returns for all files
  50.  
  51.     long    words;            // number of "words" (actually things between whitespace)
  52.     long    words_total;    // total number of words for all files
  53.  
  54.     long    bytes;            // number of bytes
  55.     long    bytes_total;    // total number of bytes for all files
  56.     
  57. } t_wc_data;
  58.  
  59. typedef t_wc_data **t_wc_handle;
  60.  
  61. /* ======================================== */
  62.  
  63. // prototypes - utility
  64.  
  65. void wc_bad( t_nshc_parms *nshc_parms, int code );
  66. void wc_bad_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg );
  67. int  wc_by_file( t_nshc_parms *nshc_parms );
  68. void wc_good( t_nshc_parms *nshc_parms );
  69. int     wc_whitespace( char c );
  70.  
  71. // prototypes - print routines
  72.  
  73. void wc_print_one( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData, int arg );
  74. void wc_print_total( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  75.  
  76. // prototypes - file access routines
  77.  
  78. void wc_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  79. void wc_process_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  80.  
  81. // console access routines
  82.  
  83. void wc_process_console( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  84.  
  85. // prototypes - state machine
  86.  
  87. void wc_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  88. void wc_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  89. void wc_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  90.  
  91. /* ======================================== */
  92.  
  93. // utility
  94.  
  95. int    wc_by_file( t_nshc_parms *nshc_parms )
  96. {
  97.  
  98.     // if we have any operands, then we count by file
  99.     
  100.     int    arg;
  101.     
  102.     arg = 1;
  103.     
  104.     while ( arg < nshc_parms->argc ) {
  105.         if ( nshc_is_operand( nshc_parms, arg ) )
  106.             return( 1 );
  107.         arg++;
  108.         }
  109.         
  110.     return( 0 );
  111. }
  112.  
  113. void wc_bad(  t_nshc_parms *nshc_parms, int code )
  114. {
  115.     nshc_parms->action = nsh_stop;
  116.     nshc_parms->result = code;
  117. }
  118.  
  119. void wc_bad_file(  t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg )
  120. {
  121.     nshc_calls->NSH_putStr_err("\pwc: File access error (");
  122.     nshc_calls->NSH_putStr_err(msg);
  123.     nshc_calls->NSH_putStr_err("\p)\r");
  124.  
  125.     nshc_parms->action = nsh_stop;
  126.     nshc_parms->result = NSHC_ERR_GENERAL;
  127. }
  128.  
  129. void wc_good(  t_nshc_parms *nshc_parms )
  130. {
  131.     nshc_parms->action = nsh_stop;
  132.     nshc_parms->result = 0;
  133. }
  134.  
  135. int    wc_whitespace( char c )
  136. {
  137.     switch (c) {
  138.         case ' ':
  139.         case '\t':
  140.         case '\r':
  141.             return(1);
  142.         default:
  143.             return(0);
  144.         }
  145. }
  146.  
  147. /* ======================================== */
  148.  
  149. // print routines
  150.  
  151. /* ======================================== */
  152.  
  153. void wc_print_one( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData, int arg )
  154. {
  155.     int    all;
  156.     
  157.     all = !(**ourData).got_options;
  158.     
  159.     if (all || (**ourData).line_option )
  160.         nshc_calls->NSH_printf( "%7ld ", (**ourData).lines );
  161.     
  162.     if (all || (**ourData).word_option )
  163.         nshc_calls->NSH_printf( "%7ld ", (**ourData).words );
  164.     
  165.     if (all || (**ourData).bytes_option )
  166.         nshc_calls->NSH_printf( "%7ld ", (**ourData).bytes );
  167.  
  168.     if (arg)
  169.         nshc_calls->NSH_puts( &nshc_parms->arg_buf[nshc_parms->argv[arg]] );
  170.         
  171.     nshc_calls->NSH_putchar('\r');
  172. }
  173.  
  174. void wc_print_total( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  175. {
  176.     int    all;
  177.     
  178.     all = !(**ourData).got_options;
  179.  
  180.     if (all || (**ourData).line_option )
  181.         nshc_calls->NSH_printf( "%7ld ", (**ourData).lines_total );
  182.     
  183.     if (all || (**ourData).word_option )
  184.         nshc_calls->NSH_printf( "%7ld ", (**ourData).words_total );
  185.     
  186.     if (all || (**ourData).bytes_option )
  187.         nshc_calls->NSH_printf( "%7ld ", (**ourData).bytes_total );
  188.         
  189.     nshc_calls->NSH_putStr("\ptotal\r");
  190. }
  191.  
  192. /* ======================================== */
  193.  
  194. // file access routines
  195.  
  196. /* ======================================== */
  197.  
  198. void wc_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  199. {
  200.     int        result;
  201.     long    dirID;
  202.     Boolean    isDir;
  203.     FSSpec    fss;
  204.     
  205.     (**ourData).fref = 0;
  206.  
  207.     // a good time to initialize counts, etc.
  208.         
  209.     (**ourData).lines = 0;
  210.     (**ourData).words = 0;
  211.     (**ourData).bytes = 0;
  212.     (**ourData).inword = 0;
  213.  
  214.     // =====> convert path to fsspec
  215.     
  216.     if ( nshc_is_operand( nshc_parms, (**ourData).arg ) ) {
  217.         result = arg_to_fss( nshc_parms, nshc_calls, (**ourData).arg, &fss );
  218.         (**ourData).arg++;
  219.         }
  220.     else {
  221.         (**ourData).arg++;
  222.         return;
  223.         }
  224.     
  225.     if (result) {
  226.         wc_bad( nshc_parms, result );
  227.         return;
  228.         }
  229.     
  230.     result = fss_to_DirID( &fss, &dirID, &isDir );
  231.         
  232.     if (( result == noErr) && isDir) {
  233.         nshc_calls->NSH_putStr_err("\pwc: Skiping directory = ");
  234.         nshc_calls->NSH_putStr_err((StringPtr)fss.name);
  235.         nshc_calls->NSH_putchar('\r');
  236.         return;
  237.         }
  238.             
  239.     if ( result == fnfErr ) {
  240.         nshc_calls->NSH_putStr_err("\pwc: File not found = ");
  241.         nshc_calls->NSH_putStr_err((StringPtr)fss.name);
  242.         nshc_calls->NSH_putchar('\r');
  243.         return;
  244.         }
  245.             
  246.     if (!result)
  247.         result = fss_OpenDF((**ourData).got_fss, &fss, fsRdPerm, &(**ourData).fref);
  248.     
  249.     if ( result ) {
  250.         wc_bad_file( nshc_parms, nshc_calls, (StringPtr)fss.name );
  251.         return;
  252.         }
  253. }
  254.  
  255. /* ======================================== */
  256.  
  257. void wc_process_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  258. {
  259.     int        close;
  260.     int        temp;
  261.     int        result;
  262.     long    bcount;
  263.     char    buf[FILE_BUF_SIZE];
  264.     char    c;
  265.     int        i;
  266.     
  267.     result = close = 0;
  268.     
  269.     // =====> copy the data fork
  270.         
  271.     bcount = FILE_BUF_SIZE;
  272.     result = FSRead( (**ourData).fref, &bcount, &buf );
  273.     
  274.     if (( result == noErr ) || ( result == eofErr )) {
  275.     
  276.         if (result == eofErr) {
  277.             close = 1;
  278.             result = 0;
  279.             }
  280.         
  281.         if (bcount && !result) {
  282.         
  283.             (**ourData).bytes += bcount;
  284.  
  285.             for (i=0 ; i<bcount; i++ ) {
  286.                 c = buf[i];
  287.                 if ( c == '\r' ) (**ourData).lines++;
  288.                 temp = wc_whitespace( c );
  289.                 if ( temp && (**ourData).inword )
  290.                     (**ourData).words++;
  291.                 (**ourData).inword = !temp;        
  292.                 }
  293.                 
  294.             }
  295.         
  296.         }
  297.     else
  298.         wc_bad_file( nshc_parms, nshc_calls, "\pread resource" );
  299.     
  300.     // =====> close the input file
  301.     
  302.     if (close) {
  303.     
  304.         // close
  305.  
  306.         if ( (**ourData).fref ) {
  307.             if ( temp = FSClose( (**ourData).fref ) )
  308.                 result = temp;
  309.             (**ourData).fref = 0;
  310.             }
  311.             
  312.         // if an error occured, bail.  otherwise compute & print
  313.  
  314.         if (result)
  315.             wc_bad_file( nshc_parms, nshc_calls, "\pclose file" );
  316.         else {
  317.         
  318.             if ( (**ourData).inword )    // if we finish in a word, it's still a word
  319.                 (**ourData).words++;
  320.                 
  321.             (**ourData).fcount++;
  322.             
  323.             (**ourData).lines_total += (**ourData).lines;
  324.             (**ourData).words_total += (**ourData).words;
  325.             (**ourData).bytes_total += (**ourData).bytes;
  326.             
  327.             wc_print_one( nshc_parms, nshc_calls, ourData, (**ourData).arg - 1 );
  328.         
  329.             }
  330.         
  331.         }
  332. }
  333.  
  334. /* ======================================== */
  335.  
  336. // console access routines
  337.  
  338. /* ======================================== */
  339.  
  340. void wc_process_console( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  341. {
  342.     long    bcount;
  343.     char    buf[CONSOLE_BUF_SIZE];
  344.     char    c;
  345.     int        i;
  346.     int        temp;
  347.     
  348.     bcount = nshc_calls->NSH_gets( buf, CONSOLE_BUF_SIZE );
  349.     
  350.     if (!bcount) return;    // wait for characters
  351.     
  352.     i = 0;
  353.     
  354.     while ( c = buf[i++] ) {
  355.     
  356.         (**ourData).bytes++;
  357.  
  358.         if ( c == '\r' ) (**ourData).lines++;
  359.         
  360.         temp = wc_whitespace( c );
  361.         if ( temp && (**ourData).inword )
  362.             (**ourData).words++;
  363.         (**ourData).inword = !temp;        
  364.             
  365.         }
  366.  
  367.     if ( bcount == -1 ) {    // end of input, display and exit
  368.     
  369.         if ( (**ourData).inword )    // if we finish in a word, it's still a word
  370.             (**ourData).words++;
  371.         
  372.         wc_print_one( nshc_parms, nshc_calls, ourData, 0 );
  373.         wc_good( nshc_parms );
  374.  
  375.         }
  376. }
  377.  
  378. /* ======================================== */
  379.  
  380. // state machine - core routines
  381.  
  382. /* ======================================== */
  383.  
  384. void wc_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  385. {
  386.     t_wc_handle    ourData;
  387.  
  388.     nshc_parms->action = nsh_idle;
  389.     nshc_parms->result = NSHC_NO_ERR;
  390.     
  391.     ourData = (t_wc_handle)NewHandleClear( sizeof(t_wc_data) );
  392.  
  393.     if (ourData) {
  394.  
  395.         // setup for by_file (or by stdin)
  396.     
  397.         (**ourData).by_file = wc_by_file( nshc_parms );
  398.         
  399.         (**ourData).arg = 1;
  400.  
  401.         // test if we can use FSSpec calls
  402.                 
  403.         (**ourData).got_fss = fss_test();
  404.         
  405.         // record user options
  406.         
  407.         (**ourData).line_option = nshc_got_option( nshc_parms, 'l' );
  408.         (**ourData).word_option = nshc_got_option( nshc_parms, 'w' );
  409.         (**ourData).bytes_option = nshc_got_option( nshc_parms, 'c' );
  410.         
  411.         (**ourData).got_options = (**ourData).line_option ||
  412.                                   (**ourData).word_option ||
  413.                                   (**ourData).bytes_option;
  414.                                  
  415.         nshc_parms->data = (Handle)ourData;
  416.         nshc_parms->action = nsh_continue;
  417.         }
  418.     else {
  419.         nshc_calls->NSH_puts("wc: Could not allocate storage.\r");
  420.         nshc_parms->result = NSHC_ERR_MEMORY;
  421.         }
  422. }
  423.  
  424. /* ======================================== */
  425.  
  426. void wc_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  427. {
  428.     t_wc_handle    ourData;
  429.     
  430.     if (ourData = (t_wc_handle)nshc_parms->data) {
  431.  
  432.         if ( (**ourData).by_file ) {
  433.             
  434.             // if we are not in the middle of a file, open one
  435.  
  436.             if ( !(**ourData).fref )
  437.                 wc_open( nshc_parms, nshc_calls, ourData );
  438.             
  439.             // read and proccess some of the open file
  440.  
  441.             if ( (**ourData).fref )
  442.                 wc_process_file( nshc_parms, nshc_calls, ourData );
  443.             
  444.             // and see if we are done
  445.  
  446.             if ( !(**ourData).fref && ( (**ourData).arg >= nshc_parms->argc ) ) {
  447.                 wc_good( nshc_parms );
  448.                 return;
  449.                 }
  450.  
  451.             }
  452.         else
  453.             wc_process_console( nshc_parms, nshc_calls, ourData );
  454.  
  455.         }
  456. }
  457.  
  458. /* ======================================== */
  459.  
  460. void wc_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  461. {        
  462.     short        fRef;
  463.     t_wc_handle    ourData;
  464.     int            temp;
  465.     int            result;
  466.     
  467.     result = 0;
  468.     
  469.     if (ourData = (t_wc_handle)nshc_parms->data) {
  470.  
  471.         // these are unsuccessfull closes only - so no file totals are printed
  472.     
  473.         if ( (**ourData).fref ) {
  474.             if ( temp = FSClose( (**ourData).fref ) )
  475.                 result = temp;
  476.             (**ourData).fref = 0;
  477.             }
  478.             
  479.         if (result)
  480.             wc_bad_file( nshc_parms, nshc_calls, "\pclosing files" );
  481.             
  482.         // if there have been no errors, print the grand total
  483.         
  484.         if ( !nshc_parms->result && ( (**ourData).fcount > 1 ) )
  485.             wc_print_total( nshc_parms, nshc_calls, ourData );
  486.             
  487.         DisposeHandle(nshc_parms->data);
  488.         }
  489.         
  490.         
  491.     nshc_parms->action = nsh_idle;
  492. }
  493.  
  494. /* ======================================== */
  495.  
  496. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  497. {
  498. #ifdef __MWERKS__
  499.     long oldA4  = SetCurrentA4();
  500. #endif
  501.     
  502.     if ( !nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION ) ) {
  503.         
  504.         switch (nshc_parms->action) {
  505.             case nsh_start:
  506.                 wc_start(nshc_parms,nshc_calls);
  507.                 break;
  508.             case nsh_continue:
  509.                 wc_continue(nshc_parms,nshc_calls);
  510.                 break;
  511.             default:
  512.                 wc_stop(nshc_parms,nshc_calls);
  513.                 break;
  514.             }
  515.             
  516.         }
  517.     
  518. #ifdef __MWERKS__
  519.     SetA4(oldA4);
  520. #endif
  521. }
  522.