home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 December / simtel1292_SIMTEL_1292_Walnut_Creek.iso / msdos / filedocs / fildif.arc / FILDIF.C next >
Text File  |  1988-06-03  |  20KB  |  813 lines

  1. #define VERSION "1.0"
  2.  
  3. /*        FILDIF - SOURCE FILE DIFFERENCES LISTING        */
  4.  
  5. /*
  6.     Author:          Dennis B. Ruggles
  7.  
  8.                 Orion Data Resources
  9.                 PO box 3110
  10.             Manchester, NH 03105
  11.               (603) 622-2865
  12.     
  13.     Original SRCDIF modified by B.Eiben DEC Marlboro
  14.     to compare two FILES.IDX [single line per file directories]
  15.     of the SIMTEL archives and generate the 'rough' command-files
  16.     to 'delete' superceded and 'get' new files.
  17.     Compilation via Turbo-C.
  18. */
  19.  
  20. /*
  21.      The following includes and defines are specifi-
  22.      cally for Microsoft's C compiler and library
  23. */
  24.  
  25. #include "stdio.h"
  26. #include "stdlib.h"
  27. #include "dos.h"
  28.  
  29. #define index        strchr
  30. #define alloc        malloc
  31. /*    #define coreleft    _memavl */
  32. #define movcmdln( to )     { struct SREGS sregs;\
  33.               segread( &sregs );\
  34.               movedata( _psp, 0x80, sregs.ds, to, 128 );\
  35.             }
  36.  
  37. #define blockmv( dest, src, count )    (memcpy( dest, src, count ))
  38.  
  39. /* -------------------- END Microsoft specifics -------------------- */
  40.  
  41. #define TRUE     1
  42. #define FALSE    0
  43.  
  44. char *USAGE[]     ={
  45. "\n        Simtel File-Compare (Version ", VERSION, ")\n"
  46. ,"\n\
  47. Usage: FILDIF FILES.IDX(old) FILES.NEW(new FILES.IDX)\n"
  48. ,"\n\
  49. Creates files DELFILES.CMD [Files to be first DELETED]\n\
  50.           GETFILES.CMD [Files to be 'gotten']\n"
  51. ,"\n\
  52. Both .CMD files have to be edited for system specific commands!!\n"
  53. ,NULL
  54. };
  55. char CUR_DEFAULT[] = "\n    Current defaults are /D%d /C%d /B%d /W -%s";
  56.  
  57. char ON[]    = "on";
  58. char OFF[]    = "off";
  59.  
  60. #define NUM_CMP  1    /* no. of equal lines ending a difference area     */
  61. #define MIN_DISP 0    /* no. of lines to display prior to differences     */
  62. #define MIN_BUF  64    /* min size of internal buffer in 128 byte units */
  63.  
  64. int num_disp        = MIN_DISP;
  65. int num_cmp        = NUM_CMP;
  66. unsigned int num_buf    = MIN_BUF;
  67. int white_space        = FALSE;
  68.  
  69. #define FORWARD   1    /* direction for stepping LINE pointers        */
  70. #define BACKWARD -1
  71.  
  72.  
  73.     /* error messages                */
  74.  
  75. char CANT_OPEN[] = " CANNOT BE OPENED";
  76.  
  77.     /* address of command buffer for parsing switches        */
  78.  
  79. char CMD_BUF[ 128 ];
  80.  
  81.     /* structure of a line in the line buffers    */
  82.  
  83. typedef struct{
  84.   int num_prev;        /* no. of chars in previous line        */
  85.   int num_this;        /* no. of chars in this line             */
  86.   unsigned line_num;    /* line counter                    */
  87.   char line[1];        /* first char of variable length line        */
  88. }   LINE;
  89.  
  90.     /* typed functions                */
  91.  
  92. FILE *fopen();
  93. char *fgets();
  94. char *alloc();
  95. long int ftell();
  96. LINE *step_inx();
  97. char *p_non_white();
  98. unsigned int chrpos();
  99. unsigned int coreleft();
  100.  
  101.     /* LINE pointers                */
  102.  
  103. LINE *lines[2];        /* pointers to the two line arrays        */
  104. LINE *l_end[2];        /* pointers to the ends of the two arrays    */
  105. LINE *l_inx[2];        /* pointers to current last lines in the arrays    */
  106. LINE *c_inx[2];        /* pointers to the two lines being compared    */
  107. LINE *e_dif[2];        /* pointers to end of current difference area    */
  108.  
  109.     /* flags and counters                    */
  110.  
  111. char eof[2]= { FALSE, FALSE };    /* end of file flags for the two files    */
  112.  
  113. char differences = 0;    /* count of number of difference areas found    */
  114.  
  115.     /* command line arguments                */
  116.  
  117. int argc;
  118. char **argv;
  119.  
  120.     /* for readability of this program:            */
  121.  
  122. #define file1 0
  123. #define file2 1
  124.  
  125.     /* file pointers returned by C-library "fopen"            */
  126.  
  127. FILE *file[4];
  128.  
  129. /*        MAIN PROGRAM                        */
  130.  
  131. /*-----------------------------------------*/
  132.   main( c, v) int c; char *v[];
  133. /*-----------------------------------------*/
  134. {
  135.   argc = c;        /* move arguments to global definitions        */
  136.   argv = v;
  137.   movcmdln( CMD_BUF );
  138.  
  139.   get_switches();    /* parse switches (if any)            */
  140.  
  141.   open_files();
  142.  
  143.     /* Title line and statment of current option settings        */
  144.  
  145.   printf( "\nFILDIF creating DELFILES.CMD and GETFILES.CMD from %s and %s\n"
  146.     , argv[1]
  147.     , argv[2]
  148.     );
  149.  
  150. /*  printf( "     (Option settings: /D%d /C%d /B%d /W -%s)\n"
  151.  *    , num_disp
  152.  *    , num_cmp
  153.  *    , num_buf
  154.  *    , (white_space ? ON : OFF)
  155.  *    );
  156.  */
  157.   printf( "             Version %s\n\n", VERSION );
  158.  
  159.   assign_buffers();        /* grab memory for buffers    */
  160.   compare_files();        /* do the file comparisons    */
  161.  
  162.     /* output a summary report    */
  163.  
  164.   if( differences )
  165.     printf(   "\n%d DIFFERENCES FOUND BETWEEN %s AND %s\n"
  166.       , differences
  167.       , argv[ 1 ]
  168.       , argv[ 2 ]
  169.       );
  170.   else
  171.     printf(   "\nFILES %s AND %s ARE THE SAME.\n"
  172.       , argv[ 1 ]
  173.       , argv[ 2 ]
  174.       );
  175.  
  176.     if( white_space )
  177.       printf( "(MULTIPLE SPACES, TABS, FORM-FEEDS, BLANK LINES IGNORED)\n" );
  178.  
  179.       exit(0);
  180. }
  181.  
  182. /*        COMPARE_FILES                        */
  183.  
  184. /*---------------------*/
  185.   compare_files()
  186. /*---------------------*/
  187. {
  188.     /* keep going until we run completely out of text    */
  189.  
  190.   while(    more_lines( file1 )    /* fill buffer with file1 data    */
  191.       | more_lines( file2 )    /* fill buffer with file2 data    */
  192.        ){
  193.  
  194.     do{      /* compare the buffers line-by-line            */
  195.  
  196.       check_abort();    /* Operator had enough of this ? */
  197.  
  198.       if( ! cmp_line( &c_inx[ file1 ]->line, &c_inx[ file2 ]->line ) ){
  199.  
  200.       /* if a line doesn't compare            */
  201.  
  202.     find_differences();        /* find the difference area    */
  203.     display_differences();        /* and display it.        */
  204.     differences += 1;        /* count the difference areas    */
  205.       }
  206.       else{
  207.  
  208.       /* bump comparison index for each equal line        */
  209.  
  210.     c_inx[ file1 ] = step_inx( c_inx[ file1 ], FORWARD );
  211.     c_inx[ file2 ] = step_inx( c_inx[ file2 ], FORWARD );
  212.       }
  213.  
  214.     /* until the end of one of the buffers comes up        */
  215.  
  216.     }while(    (c_inx[ file1 ] != l_inx[ file1 ])
  217.         && (c_inx[ file2 ] != l_inx[ file2 ])
  218.       );
  219.   }
  220. }
  221.  
  222. /*        STEP_INX, MORE_LINES, COMPRESS                */
  223.  
  224. /*-------------------------------------------------------*/
  225.   LINE *step_inx( l, direc ) register LINE *l; int direc;
  226. /*-------------------------------------------------------*/
  227. { static int add_amount;
  228.  
  229.   switch( direc ){
  230.  
  231.     case FORWARD:        /* step a LINE pointer forward        */
  232.  
  233.       add_amount =  (l->num_this);
  234.       add_amount += (add_amount ?        /* don't step if NULL    */
  235.                   (sizeof( LINE ) - 1)
  236.                 : 0
  237.             );
  238.       break;
  239.  
  240.     case BACKWARD:        /* step a LINE pointer backward        */
  241.  
  242.       add_amount = -(l->num_prev);
  243.       add_amount -= (add_amount ?        /* don't step if NULL    */
  244.                   (sizeof( LINE ) - 1)
  245.                 : 0
  246.             );
  247.       break;
  248.   }
  249.   (char *)l = (char *)(l) + add_amount;
  250.   return( l );                /* return new pointer    */
  251. }
  252.  
  253. /*--------------------------------*/
  254.   more_lines( f ) register int f;
  255. /*--------------------------------*/
  256. { static int got_more;
  257.  
  258.   got_more = compress( f );        /* make room for more data    */
  259.   return (got_more | read_lines( f ));    /* and read it in.        */
  260. }
  261. /*------------------------------*/
  262.   compress( f ) register int f;
  263. /*------------------------------*/
  264. { static LINE *mark;
  265.   static int num_chars, move_distance;
  266.   static int i;
  267.  
  268.     /* move data in buffer down to make room            */
  269.  
  270.   mark = c_inx[ f ];    /* everything prior to c_inx is equal    */
  271.  
  272.     /* also preserve the requested number of equal lines to display    */
  273.  
  274.   for( i=0; i < num_disp; ++i )
  275.     mark = step_inx ( mark, BACKWARD );
  276.  
  277.     /* now move the data down                    */
  278.  
  279.   num_chars = ( (char *)(l_inx[ f ]) - (char *)(mark) ) + sizeof( LINE );
  280.   move_distance = ( (char *)(mark) - (char *)(lines[ f ]) );
  281.   blockmv( lines[ f ], mark, num_chars );
  282.  
  283.     /* reset our pointers to our moved data                */
  284.  
  285.   (char *)l_inx[ f ] = (char *)(l_inx[ f ]) - move_distance;
  286.   (char *) c_inx[ f ] = (char *)(c_inx[ f ]) - move_distance;
  287.  
  288.   lines[ f ]->num_prev = 0;        /* first line has no previous    */
  289.   return move_distance;
  290. }
  291.  
  292. /*        READ_LINES                        */
  293.  
  294. /*--------------------------------*/
  295.   read_lines( f ) register int f;
  296. /*--------------------------------*/
  297. { static LINE *next_line;    static long file_pos;    static int size_left;
  298.   static int line_size;     static int got_some;    static int i;
  299.                   static unsigned line_num;
  300.  
  301.   line_num = l_inx[ f ]->line_num;
  302.   got_some = FALSE;
  303.  
  304.     /*
  305.     keep reading as long as there is input data and enough
  306.     room left for a LINE structure containing two characters
  307.     (e.g. "\n\0") followed by a LINE structure consisting
  308.     of one null character (for l_inx)
  309.     */
  310.  
  311.   while(     (! eof[ f ])
  312.       && ( (size_left =   (char *)(l_end[ f ])
  313.                 - (char *)(&l_inx[ f ]->line)
  314.                 - sizeof( LINE )
  315.            ) > 1
  316.          ) 
  317.        ){
  318.  
  319.     check_abort();
  320.  
  321.       /* remember where we are in case next line goes beyond end    */
  322.  
  323.     file_pos = ftell( file[ f ] );
  324.  
  325.       /* get next line                        */
  326.  
  327.     if( eof[ f ] = ( (fgets( &l_inx[ f ]->line, size_left, file[ f ] )
  328.              ) == NULL
  329.            )
  330.       )
  331.       break;        /* unless none                */
  332.  
  333.       /* calculate the number of characters in the line        */
  334.  
  335.     l_inx[ f ]->num_this
  336.     = line_size
  337.     = chrpos( &l_inx[ f ]->line, '\0' );
  338.  
  339.       /* make sure the line fit in the size_left            */
  340.  
  341.     if( l_inx[ f ]->line[ --line_size ] != '\n' ){
  342.       fseek( file[ f ], file_pos, 0 );        /* it didn't so reset    */
  343.       break;                    /* the file pointers    */
  344.     }                        /* to re-read it later    */
  345.  
  346.     l_inx[ f ]->line[ line_size ] = '\0';    /* delete the '\n' at end */
  347.     ++line_num;                    /* count the lines      */
  348.  
  349.       /* If in the "ignore white space" mode - skip blank lines    */
  350.  
  351.     if( ! (    (white_space)
  352.         && (*p_non_white( &l_inx[ f ]->line ) == '\0')
  353.       )
  354.       ){
  355.  
  356.     /* We have a new source line                */
  357.  
  358.       got_some = TRUE;    /* set return flag to say we got data    */
  359.  
  360.     /* construct partial new LINE structure marking the end    */
  361.  
  362.       l_inx[ f ] = step_inx( l_inx[ f ], FORWARD );
  363.       l_inx[ f ]->num_prev = line_size;
  364.     }
  365.     l_inx[ f ]->line_num = line_num;    /* Update line number, if changed */
  366.   }
  367.     /* clean up final l_inx  LINE structure and leave        */
  368.  
  369.   l_inx[ f ]->num_this = 0;
  370.   l_inx[ f ]->line[0]  = '\0';
  371.  
  372.   return got_some;
  373. }
  374.  
  375. /*        FIND_DIFFERENCES                    */
  376.  
  377. /*----------------------*/
  378.   find_differences()    /* determine boundaries of difference area    */
  379. /*----------------------*/
  380. { static int i, k, swc_0_1;
  381.   static int match;
  382.   static LINE *c_inx1_init, *c_inx2_init;
  383.   register LINE *inx1, *inx2;
  384.  
  385.   more_lines( file1 );    /* get as much data as possible for use    */
  386.   more_lines( file2 );    /* in determining the difference area    */
  387.  
  388.     /*
  389.     set a maximal difference area in case the cross compare loop is
  390.     never entered (which happens repeatedly at the end of processing
  391.     when one file is very much longer than the other)
  392.     */
  393.  
  394.   e_dif[ file1 ] = l_inx[ file1 ];
  395.   e_dif[ file2 ] = l_inx[ file2 ];
  396.  
  397.     /* initialize things                        */
  398.  
  399.   k = 1;
  400.   c_inx1_init = c_inx[ file1 ];
  401.   c_inx2_init = c_inx[ file2 ];
  402.   match = FALSE;
  403.   swc_0_1 = 0;
  404.  
  405.     /*
  406.     The following loop performs a "cross-compare" on an ever-
  407.     increasing number of lines between the two files. It does
  408.     this until it gets "num_cmp" successive equal lines or
  409.     runs out of data to compare.
  410.     */
  411.  
  412.   while(    ! match                /* not got num_cmp equal  */
  413.      && (c_inx[ file1 ] != l_inx[ file1 ])    /* and more lines to com- */
  414.      && (c_inx[ file2 ] != l_inx[ file2 ])    /* pare in both buffers   */
  415.        ){
  416.  
  417.       /*
  418.       Step both c_inx's to widen the potential difference area. Also, 
  419.       now that we got into the loop, set a better maximal difference
  420.       area in case we never find num_cmp equal ("match" never set TRUE)
  421.       */
  422.  
  423.     e_dif[ file1 ]
  424.     = c_inx[ file1 ]
  425.     = step_inx( c_inx[ file1 ], FORWARD );
  426.  
  427.     e_dif[ file2 ]
  428.     = c_inx[ file2 ]
  429.     = step_inx( c_inx[ file2 ], FORWARD );
  430.  
  431.  
  432.       /* The "cross-compare":                        */
  433.  
  434.     do{ /* twice, once with "swc_0_1" = 0, and again with it = 1    */ 
  435.  
  436.       switch( swc_0_1 ){
  437.  
  438.     case 0:
  439.  
  440.         /*
  441.         set things up to compare all lines from original
  442.         c_inx[ file1 ] down to, but not including the new
  443.         c_inx[ file1 ] with the new line at c_inx[ file2]
  444.         */
  445.  
  446.       i = k;    /* leaving old "k" causes the exclusion        */
  447.       inx1 = c_inx1_init;
  448.       inx2 = c_inx[ file2 ];
  449.       break;
  450.  
  451.     case 1:
  452.  
  453.         /*
  454.         set things up to compare all lines from original
  455.         c_inx[ file2 ] down to, and this time including the
  456.         new c_inx[ file2 ] with the new line at c_inx[ file1 ]
  457.         */
  458.  
  459.       i = ++k;    /* increasing "k" causes the inclusion        */
  460.       inx1 = c_inx[ file1 ];
  461.       inx2 = c_inx2_init;
  462.       break;
  463.       }/* end switch( swc_0_1 ){ . . .                */
  464.  
  465.     /* if any single line compares, try to get a "num_cmp" match    */
  466.  
  467.       while( i-- ){
  468.  
  469.     if(    (cmp_line( &inx1->line, &inx2->line ))
  470.         && (match = try_num_cmp( inx1, inx2 ))
  471.       )
  472.       break;    /* the difference area is finally defined    */
  473.       /*
  474.           after each failure on a "num_cmp" match,
  475.           step the appropriate index to the next line
  476.       */
  477.  
  478.     switch( swc_0_1 ){
  479.  
  480.       case 0:
  481.         inx1 = step_inx( inx1, FORWARD );
  482.         break;
  483.  
  484.       case 1:
  485.         inx2 = step_inx( inx2, FORWARD );
  486.         break;
  487.  
  488.     }/* end switch( swc_0_1 ){ . . .                */
  489.       }/* end while( i-- ){ . . .                    */
  490.     /*
  491.         flip "swc_0_1" from 0 to 1 unless we got a
  492.         "num_cmp" match or "swc_0_1" was already a 1
  493.     */
  494.     }/* end do{ . . .*/ while( ! match && (swc_0_1 ^= 1) );
  495.  
  496.   }/* end of while( ! match    ){ . . .                */
  497.  
  498.     /* see how we got out of the above loop                */
  499.  
  500.   if( ! match ){     /* then we ran out of things to compare        */
  501.     c_inx[ file1 ] = e_dif[ file1 ];
  502.     c_inx[ file2 ] = e_dif[ file2 ];
  503.   }
  504. }
  505.  
  506. /*        TRY_NUM_CMP                        */
  507.  
  508. /*---------------------------------------------------------*/
  509.   try_num_cmp( x_file1, x_file2 ) LINE *x_file1, *x_file2;
  510. /*---------------------------------------------------------*/
  511. { static int i; register LINE *inx1, *inx2;
  512.  
  513.   inx1 = x_file1;    inx2 = x_file2;
  514.  
  515.     /*
  516.     since we got here by making one comparison, the following
  517.     loop actually performs "num_cmp - 1" compares.
  518.     */
  519.   for( i = num_cmp; --i;){
  520.     inx1 = step_inx( inx1, FORWARD );
  521.     inx2 = step_inx( inx2, FORWARD );
  522.     if( ! cmp_line( &inx1->line, &inx2->line ) )
  523.       return FALSE;
  524.   }
  525.   c_inx[ file1 ] = step_inx( inx1, FORWARD );
  526.   c_inx[ file2 ] = step_inx( inx2, FORWARD );
  527.  
  528.   e_dif[ file1 ] = x_file1;
  529.   e_dif[ file2 ] = x_file2;
  530.  
  531.   return TRUE;
  532. }
  533.  
  534. /*        DISPLAY_DIFFERENCES                    */
  535.  
  536. /*----------------------*/    
  537.   display_differences()    /* display a difference area             */
  538. /*----------------------*/
  539. { register LINE *inx;
  540.   register unsigned int this_line;
  541.   static int i;
  542.  
  543.     /* for "file1" (0) and "file2" (1) :    */
  544.  
  545.   for( i = 0; i < 2; ++i){
  546.  
  547.     inx = lines[ i ];
  548.     this_line = inx->line_num;    /* Set counter to restore blank lines    */
  549.  
  550.       /* output a title    */
  551.  
  552. /*
  553.  *   printf( ":----------- line %u of %s -----------:\n"
  554.  *      , this_line
  555.  *      , argv[ i+1 ]
  556.  *      );
  557.  */
  558.       /* then the difference area    */
  559.  
  560.     for( ;   inx != e_dif[ i ];   inx = step_inx( inx, FORWARD ) ){
  561.       while( this_line++ != inx->line_num )    /* Restore any blank lines */
  562.     printf( "\n" );
  563.       check_abort();
  564.       fprintf(file[i+3],"%s\n", &inx->line );
  565.     }
  566.   }
  567.     /* mark the end of the difference area    */
  568. /*
  569.  * printf(">>****************************************<<\n\n");
  570.  */
  571. }
  572.  
  573. /*        GET_SWITCHES                        */
  574.  
  575. /*------------------------*/
  576.   get_switches()
  577. /*------------------------*/
  578. { register char *swc;    register int *val; char *index();
  579.  
  580.   swc = CMD_BUF;
  581.  
  582.     /* scan command line for slashes, and determine the switch    */
  583.  
  584.   while( swc = index( swc, '/' ) ){
  585.  
  586.     switch( toupper(*++swc) ){
  587.  
  588.       case 'B':            /* set internal buffer size     */
  589.                       /* for reading the files     */
  590.     val = &num_buf;
  591.     break;
  592.  
  593.       case 'C':            /* set number of comparisons      */
  594.                       /* defining a difference area     */
  595.     val = &num_cmp;
  596.     break;
  597.  
  598.       case 'D':            /* set number of lines to dis-     */
  599.                       /* play prior to difference area */
  600.     val = &num_disp;
  601.     break;
  602.  
  603.       case 'W':
  604.  
  605.     white_space = TRUE;    /* Ignore multiple white spaces    */
  606.     break;
  607.  
  608.       case 'H':
  609.     help();
  610.     break;
  611.  
  612.       default:
  613.     err_exit("\nUnknown switch specified");
  614.     }
  615.       /* get value for the switch, and check minimums        */
  616.  
  617.     if( val != NULL )
  618.       sscanf( ++swc, "%d", val );
  619.  
  620.     if( num_buf < MIN_BUF )
  621.       num_buf = MIN_BUF;
  622.     if( num_cmp < NUM_CMP )
  623.       num_cmp = NUM_CMP;
  624.     if( num_disp < MIN_DISP  )
  625.       num_disp = MIN_DISP;
  626.   }
  627. }
  628.  
  629. /*        OPEN_FILES, ASSIGN_BUFFERS                */
  630.  
  631. /*---------------*/
  632.   open_files()
  633. /*---------------*/
  634. { register int i;
  635.  
  636.   if( argc < 3 )            /* if no files, show help message */
  637.     help();
  638.  
  639.     /* open the files        */
  640.  
  641.   for( i = 0; i < 2; ++i ){
  642.     if( ! (file[ i ] = fopen( argv[i+1], "r" )) ){
  643.       printf( "\n%s", argv[i+1] );
  644.       err_exit( CANT_OPEN );    /* oh, s-s-sigh!!        */
  645.     }
  646.   }
  647.   if( ! (file[ 3 ] = fopen("DELFILES.CMD", "w" )) ){
  648.     printf( "\n%s", "DELFILES.CMD");
  649.     err_exit( CANT_OPEN );
  650.   }
  651.   if( ! (file[ 4 ] = fopen("GETFILES.CMD", "w" )) ){
  652.     printf( "\n%s", "GETFILES.CMD");
  653.     err_exit( CANT_OPEN );
  654.   }
  655. }
  656.     
  657. /*------------------------*/
  658.   assign_buffers()
  659. /*------------------------*/
  660. { unsigned int i;
  661.  
  662.     /*
  663.     divide available memory between "file1"
  664.     and "file2" in 128 byte chunks
  665.     */
  666.  
  667.   i = (coreleft() - 1000) / 2;
  668.  
  669.   if( i > (num_buf <<= 7) )
  670.     i = num_buf;
  671.  
  672.   
  673.   (char *) lines[ 0 ] = alloc( i );
  674.   (char *) lines[ 1 ] = alloc( i );
  675.  
  676.   if(    (lines[ 0 ] == NULL)
  677.       || (lines[ 1 ] == NULL)
  678.       || (i < ( MIN_BUF << 7 ))
  679.     ){
  680.     err_exit( "\nNot enough memory" );
  681.   }
  682.     
  683.     /* initialize LINE pointers        */
  684.  
  685.   (char *) l_end[ 0 ] = (char *)(lines[ 0 ]) + i;
  686.   (char *) l_end[ 1 ] = (char *)(lines[ 1 ]) + i;
  687.  
  688.   for( i = 0; i < 2; ++i ){
  689.  
  690.     lines[i]->num_this
  691.     = lines[i]->num_prev
  692.     = 0;
  693.  
  694.     lines[i]->line_num = 1;
  695.  
  696.     c_inx[i]
  697.     = l_inx[i]
  698.     = lines[ i ];
  699.  
  700.     l_inx[i]->line[0] = '\0';
  701.  
  702.   }
  703. }
  704.  
  705. /*        ERR_EXIT, CHRPOS                    */
  706.  
  707. /*-----------------------------*/
  708.   err_exit( msg ) char *msg;
  709. /*-----------------------------*/
  710. {
  711.   printf( msg );    /* tell 'm off    */
  712.   exit(0);        /* and give up    */
  713. }
  714.  
  715. /*-------------------------------------------------*/
  716.     unsigned int chrpos(str, c) char *str; char c;
  717. /*-------------------------------------------------*/
  718. /* give position of char 'c' in string "str"       */
  719. /* return -1 if not found. Note: length of       */
  720. /* "str" is returned if 'c' is '\0'.           */
  721. {
  722.   register unsigned int i = 0;
  723.  
  724.   do{
  725.     if( str[i] == c )
  726.       return(i);
  727.   }while( str[ i++ ] != '\0' ); 
  728.  
  729.   return(-1);
  730. }
  731. /*---------------------*/
  732.   check_abort()
  733. /*---------------------*/
  734. {
  735.   if( (bdos( 6, 0xFF ) & 0xFF) == ('C' & 0x1F ) )
  736.     exit( 0 );
  737. }
  738. /*----------------------------------------------*/
  739.   cmp_line( s1, s2 ) register char *s1, *s2;    /* Compare two lines    */
  740. /*----------------------------------------------*/
  741. { static int s1_char, s2_char;
  742.  
  743.   if( strcmp( s1, s2 ) == 0 )
  744.     return TRUE;
  745.  
  746.   if( ! white_space )
  747.     return FALSE;
  748.  
  749.   s1 = p_non_white( s1 );
  750.   s2 = p_non_white( s2 );
  751.  
  752.   while(   ((s1_char = *s1) != '\0')
  753.     && ((s2_char = *s2) != '\0')
  754.        ){
  755.     if(    (is_white( s1_char ))
  756.     && (is_white( s2_char ))
  757.       ){
  758.       s1 = p_non_white( s1 );
  759.       s2 = p_non_white( s2 );
  760.     }
  761.     else{
  762.       if( s1_char != s2_char )
  763.     return FALSE;
  764.       ++s1;
  765.       ++s2;
  766.     }
  767.   }
  768.   if( *p_non_white( s1 ) == *p_non_white( s2 ))
  769.     return TRUE;
  770.  
  771.   return FALSE;
  772. }
  773. /*------------------------------*/
  774.   is_white( c ) char c;
  775. /*------------------------------*/
  776. {
  777.   switch( c ){
  778.  
  779.     case ' ':
  780.     case '\t':
  781.     case '\f':
  782.  
  783.       return TRUE;
  784.   }
  785.   return FALSE;
  786. }
  787. /*------------------------------------*/
  788. char *p_non_white( cp ) register char *cp;
  789. /*------------------------------------*/
  790. {
  791.   while( is_white( *cp ) )
  792.     ++cp;
  793.   return cp;
  794. }
  795. /*------------------------*/
  796.   help()
  797. /*------------------------*/
  798. { register char **usage = USAGE;
  799.  
  800.   while( *usage != NULL )
  801.     printf( "%s", *usage++ );
  802.  
  803. /*  printf( CUR_DEFAULT
  804.  *     , num_disp
  805.  *    , num_cmp
  806.  *    , num_buf
  807.  *    , (white_space ? ON : OFF)
  808.  *    );
  809.  */
  810.   exit(0);
  811. }
  812.     
  813.