home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / doc / mir / sort2.c < prev    next >
Text File  |  1992-07-02  |  13KB  |  381 lines

  1. /*
  2.  * Usage -  sort2 [/r] [/+n] from_file to_file key[s]
  3.  *
  4.  * sort2    Sorts large ASCII files using the memory-bound DOS SORT
  5.  *      routine in multiple passes.  /r signifies reverse order.
  6.  *      /+n specifies a starting column, 1-999.  A key is 1 to 3
  7.  *      characters, used as a dividing point.  The program separates
  8.  *      the input file into a series of temporary files, depending on
  9.  *      the byte(s) at the starting column.  For n dividing points,
  10.  *      the program makes n+1 temporary files, and reports the size
  11.  *      of each.  If all are under 60k characters, they are sorted
  12.  *      and placed together in the output file.  If a run fails, add
  13.  *      another dividing point mid-way in the range that fails (that
  14.  *      is, the file that is too big), and try again.  NOTE:  The DOS
  15.  *      SORT starts column count at 1, converts all lower to upper case!
  16.  *
  17.  *  input:  Line oriented printable ASCII text.
  18.  *
  19.  *  output: Same file, sorted.
  20.  *
  21.  *  writeup: MIR TUTORIAL ONE, topic 5
  22.  *
  23.  *  Written:    Douglas Lowry   Mar 06 91
  24.  *  Modified:   Douglas Lowry   Feb 21 92
  25.  *              Copyright (C) 1992 Marpex Inc.
  26.  *
  27.  *    The MIR (Mass Indexing and Retrieval) Tutorials explain detailed
  28.  *    usage and co-ordination of the MIR family of programs to analyze,
  29.  *    prepare and index databases (small through gigabyte size), and
  30.  *    how to build integrated retrieval software around the MIR search
  31.  *    engine.  The fifth of the five MIR tutorial series explains how
  32.  *    to extend indexing capability into leading edge search-related
  33.  *    technologies.  For more information, GO IBMPRO on CompuServe;
  34.  *    MIR files are in the DBMS library.  The same files are on the
  35.  *    Canada Remote Systems BBS.  A diskette copy of the Introduction
  36.  *    is available by mail ($10 US... check, Visa or Mastercard);
  37.  *    diskettes with Introduction, Tutorial ONE software and the
  38.  *    shareware Tutorial ONE text cost $29.  Shareware registration
  39.  *    for a tutorial is also $29.
  40.  *
  41.  *    E-mail...
  42.  *                Compuserve  71431,1337
  43.  *                Internet    doug.lowry%canrem.com
  44.  *                UUCP        canrem!doug.lowry
  45.  *                Others:     doug.lowry@canrem.uucp
  46.  *
  47.  *    FAX...                  416 963-5677
  48.  *
  49.  *    "Snail mail"...         Douglas Lowry, Ph.D.
  50.  *                            Marpex Inc.
  51.  *                            5334 Yonge Street, #1102
  52.  *                            North York, Ontario
  53.  *                            Canada  M2N 6M2
  54.  *
  55.  *    Related database consultation and preparation services are
  56.  *    available through:
  57.  *              Innotech Inc., 2001 Sheppard Avenue E., Suite #118,
  58.  *              North York, Ontario  Canada   M2J 4Z7
  59.  *              Tel.  416 492-3838   FAX  416 492-3843
  60.  *
  61.  *  This program is free software; you may redistribute it and/or
  62.  *  modify it under the terms of the GNU General Public License as
  63.  *  published by the Free Software Foundation; either version 2 of
  64.  *  the License, or (at your option) any later version.
  65.  *
  66.  *  This program is distributed in the hope that it will be useful,
  67.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  68.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  69.  *  GNU General Public License for more details.
  70.  *
  71.  *  You should have received a copy of the GNU General Public License
  72.  *  (file 05LICENS) along with this program; if not, write to the
  73.  *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
  74.  *  USA.
  75.  */
  76.  
  77. #include <stdio.h>
  78. #include <stdlib.h>
  79. #include <dos.h>
  80. #include <ctype.h>
  81. #include <direct.h>
  82. #include <process.h>
  83. #include <errno.h>
  84.  
  85. #define     MAX_BYTES   1024
  86. #define     MAX_DIV 25
  87.  
  88. #define     repeat      for(;;)
  89.  
  90. typedef     enum        _bool
  91.             { FALSE = 0, TRUE = 1 }  Bool;
  92. /*
  93.  *  declarations
  94.  */
  95.  
  96.     void    Usage_(), process();
  97.     char    *Cmdname_() {   return( "sort2" );  }
  98.  
  99.     FILE        *fp_in;
  100.  
  101. /*
  102.  *  MAIN
  103.  */
  104.  
  105. main( argc, argv )
  106.     int argc;
  107.     char    **argv;
  108. {
  109.     unsigned char   dividers[ MAX_DIV ][ 4 ],
  110.                 uc[4] ;
  111.     Bool        reverse;    /*  perform reverse sort    */
  112.     int         used_args,  /*  arguments identified so far */
  113.                 div_ct,     /*  count of dividers       */
  114.                 start_col,  /*  start sorting at column */
  115.                 test,       /*  evaluate a comparison   */
  116.                 ar, i, j ;
  117.  
  118.     /* usage: sort2 [/r] [/+n] from_file to_file key[s]     */
  119.  
  120.     if( argv[1][0] == '-' || argc < 4 )
  121.         Usage_();
  122.  
  123.     start_col = 1 ;
  124.     used_args = div_ct = 0 ;
  125.     reverse = FALSE ;
  126.  
  127.     for( i = 1 ; i < 3 ; i++ )
  128.     {
  129.         if( argv[i][0] != '/' )
  130.             break ;
  131.         if( argv[i][1] == 'r' || argv[i][1] == 'R' )
  132.         {
  133.             used_args++ ;
  134.             reverse = TRUE ;
  135.         }
  136.         else if( argv[i][1] == '+' )
  137.         {
  138.             used_args++ ;
  139.             start_col = ( int ) atol( &argv[i][2] ) ;
  140.         }
  141.         else
  142.         {
  143.             fprintf( stderr, "\nUnrecognized argument with /\n\n" );
  144.             Usage_();
  145.         }
  146.     }
  147.  
  148.     if(( fp_in = fopen( argv[ used_args + 1 ], "rb" )) == NULL )
  149.     {
  150.         fprintf( stderr, "FATAL... Unable to open file %s\n",
  151.             argv[ used_args + 1 ] );
  152.         Usage_();
  153.     }
  154.  
  155.     unlink( argv[ used_args + 2 ] );    /*  output file name    */
  156.  
  157.     if( argc < used_args + 3 )
  158.         Usage_();
  159.  
  160.     for( ar = used_args + 3 ; ar < argc ; ar++ )
  161.     {
  162.         if( strlen( argv[ ar ] ) > 3 )
  163.             Usage_();
  164.         for( i = 0 ; argv[ ar ][ i ] ; i++ )
  165.         {
  166.             uc[i] = argv[ar][i] ;
  167.             if( islower( uc[i] ) )
  168.                 uc[i] = toupper( uc[i] );
  169.         }
  170.         uc[i] = 0 ;
  171.  
  172.         if( !div_ct )
  173.         {
  174.             strcpy( dividers[ 0 ], uc ) ;
  175.             div_ct = 1 ;
  176.         }
  177.         else
  178.         {
  179.             /*  insertion sort              */
  180.             for( i = 0 ; i < div_ct ; i++ )
  181.             {
  182.                 test = strcmp( uc, dividers[ i ] ) ;
  183.                 if( !test )
  184.                     break ;     /*  a repetition    */
  185.                 if( test < 0 )
  186.                 {
  187.                     for( j = div_ct ; j > i ; j-- )
  188.                         strcpy( dividers[ j - 1 ], dividers[ j ] );
  189.                     strcpy( dividers[ i ], uc ) ;
  190.                     div_ct++ ;
  191.                     break ;
  192.                 }
  193.             }
  194.             if( i == div_ct )   /* add to end       */
  195.                 strcpy( dividers[ div_ct++ ], uc ) ;
  196.             if( div_ct > MAX_DIV -1 )
  197.                 fprintf( stderr, "RECOMPILE... over %d dividers.\n",
  198.                     MAX_DIV - 1 );
  199.         }
  200.  
  201.     }
  202.  
  203.     process( reverse, dividers, div_ct, start_col, argv[ used_args +2] );
  204.  
  205.     fclose( fp_in );
  206.     exit( 0 );
  207. }
  208. /*
  209.  *  Usage
  210.  */
  211.     void
  212. Usage_()
  213. {
  214. fprintf( stderr,
  215.     "usage:  %s [/r] [/+n] from_file to_file key[s]\n\n\
  216.     Sorts large ASCII files using the memory-bound DOS SORT\n\
  217.     routine in multiple passes.  /r signifies reverse order.\n\
  218.     /+n specifies a starting column, 1-999.  A key is 1 to 3\n",
  219.         Cmdname_());
  220. fprintf( stderr,
  221. "    characters, used as a dividing point.  The program separates\n\
  222.     the input file into a series of temporary files, depending on\n\
  223.     the byte(s) at the starting column.  For n dividing points,\n\
  224.     the program makes n+1 temporary files, and reports the size\n" );
  225. fprintf( stderr,
  226. "    of each.  If all are under 60k characters, they are sorted\n\
  227.     and placed together in the output file.  If a run fails, add\n\
  228.     another dividing point mid-way in the range that fails (that\n\
  229.     is, the file that is too big), and try again.  NOTE:  The DOS\n" ) ;
  230. fprintf( stderr,
  231. "    SORT starts column count at 1, converts all lower to upper case!\n\n\
  232. input:  Line oriented printable ASCII text.\n\n\
  233. output: Same file, sorted.\n\n\
  234. writeup: MIR TUTORIAL ONE, topic 5\n\n" ) ;
  235.     exit( 1 ) ;
  236. }
  237. /*
  238.  * PROCESS
  239.  */
  240.     void
  241. process( reverse, dividers, div_ct, start_col, outnam )
  242.     unsigned char   dividers[ MAX_DIV ][ 4 ] ;
  243.     Bool            reverse;        /*  perform reverse sort    */
  244.     int             div_ct,     /*  count of dividers       */
  245.                     start_col;  /*  start sorting at column */
  246.     char            outnam[32]; /*  name of output file     */
  247. {
  248.     FILE            *fp_tmp, *fp_bat ;
  249.     char            fname[ 32 ];
  250.     unsigned char   buf[ MAX_BYTES ], uc[4],
  251.                     from[4], to[4] ;
  252.     Bool            too_big ;       /*  Won't be able to sort subset.*/
  253.     long int        tmp_size ;  /*  size of temporary file  */
  254.     int         pass,
  255.                 errno,
  256.                 test_lo, test_hi,
  257.                 len, i, pt ;
  258.  
  259.     unlink ("sort2tmp.bat" );
  260.     if(( fp_bat = fopen( "sort2tmp.bat", "w" )) == NULL )
  261.     {
  262.         fprintf( stderr, "FATAL... Unable to open sort2tmp.bat\n" );
  263.         Usage_();
  264.     }
  265.  
  266.     too_big = FALSE ;
  267.  
  268.     for( pass = 0 ; pass <= div_ct ; pass++ )
  269.     {
  270.         for( i = 0 ; i < 4 ; i++ )
  271.             from[i] = to[i] = uc[i] = 0 ;
  272.         if( pass )
  273.             rewind( fp_in );
  274.         if( reverse )
  275.         {
  276.             if( !pass )
  277.             {
  278.                 strcpy( from, dividers[ div_ct - 1 ] ) ;
  279.                 to[0] =   255 ; /*  max char value  */
  280.             }
  281.             else if( pass == div_ct )
  282.                 strcpy( to, dividers[0] ) ;
  283.             else
  284.             {
  285.                 strcpy( from, dividers[ div_ct - pass - 1 ] ) ;
  286.                 strcpy( to, dividers[ div_ct - pass ] ) ;
  287.             }
  288.         }
  289.         else                    /*  forward sort    */
  290.         {
  291.             if( pass )
  292.                 strcpy( from, dividers[ pass - 1 ] ) ;
  293.             if( pass < div_ct )
  294.                 strcpy( to, dividers[ pass ] ) ;
  295.             else
  296.                 to[0] = 255 ;
  297.         }
  298.  
  299.         sprintf( fname, "sort%02d.tmp", pass );
  300.         if(( fp_tmp = fopen( fname, "wb" )) == NULL )
  301.         {
  302.             fprintf( stderr,
  303.                   "FATAL... Unable to open %s\n", fname );
  304.             Usage_();
  305.         }
  306.  
  307.         tmp_size = 0 ;
  308.         while( fgets( buf, MAX_BYTES, fp_in ) != NULL )
  309.         {
  310.             len = strlen( buf ) ;
  311.             if( len < start_col )
  312.             {
  313.                 for( i = 0 ; i < 3 ; i++ )
  314.                     uc[i] = 0 ;
  315.             }
  316.             else
  317.             {
  318.                 for( i = 0 ; i < 3 ; i++ )
  319.                 {
  320.                     uc[i] = buf[ start_col - 1 + i ];
  321.                     if( islower( uc[i] ))
  322.                         uc[i] = toupper( uc[i] );
  323.                 }
  324.             }
  325.             test_lo = strcmp( uc, from ) ;
  326.             test_hi = strcmp( uc, to ) ;
  327.             if( test_lo < 0 || test_hi >= 0 )
  328.                 continue ;
  329.             fputs( buf, fp_tmp );
  330.             tmp_size += len ;
  331.         }
  332.  
  333.         if(( !reverse && pass < div_ct ) || (  reverse && pass ))
  334.             fprintf( stderr, "Setting up to %s, size %ld bytes.\n",
  335.                 to, tmp_size );
  336.         else
  337.             fprintf( stderr,"Setting beyond %s, size %ld bytes.\n",
  338.                 dividers[ div_ct - 1], tmp_size );
  339.  
  340.         if( tmp_size > 60000 )
  341.             too_big = TRUE ;
  342.         fclose( fp_tmp );
  343.  
  344.         /*  Build up the command line       */
  345.  
  346.         if( tmp_size )
  347.         {
  348.             strncpy( buf, "sort ", 5    );
  349.             pt = 5 ;
  350.             if( reverse )
  351.             {
  352.                 strncpy( &buf[ pt ], "/r ", 3 );
  353.                pt += 3 ;
  354.             }
  355.             if( start_col > 1 )
  356.             {
  357.                 sprintf( &buf[ pt ], "/+%d ", start_col );
  358.                 pt += 4 ;
  359.                 if( start_col > 9 )     /*  to 2 digits */
  360.                     pt++ ;
  361.                 if( start_col > 99 )    /*  to 3 digits */
  362.                     pt++ ;
  363.             }
  364.             buf[ pt ] = '\0' ;
  365.             fprintf( fp_bat, "%s < %s >> %s\n", buf, fname, outnam );
  366.         }
  367.         fprintf( fp_bat, "del %s\n", fname );
  368.     }
  369.  
  370.     fclose( fp_bat );
  371.     if( !too_big )
  372.     {
  373.         errno = spawnl( 0, "sort2tmp.bat", "sort2tmp.bat", NULL );
  374.         if( errno )
  375.             fprintf( stderr, "spawnl error # %d\n", errno );
  376.     }
  377.  
  378.     unlink( "sort2tmp.bat" );
  379.     return ;
  380. }
  381.