home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / c / bigsort.arc / BIGSORT.C next >
Text File  |  1986-04-21  |  8KB  |  373 lines

  1. /* Reverse Engineered UNIX (tm) inspired sort                       */
  2. /* Copyright (c) Jim Gast, Naperville, IL    April, 1986        */
  3. /* NOT copyright, I hereby put this here thing in the PUBLIC DOMAIN */
  4.  
  5. /* SYNTAX:   bigsort [ -tx ] [+dd.dd[n][r]] [-dd.dd] . . .          */
  6. /*            [infile] . . . -o [outfile]            */
  7. /* "-tx" specifies a new tab (delimeter) character (default is tab) */
  8. /* "+5.6 -6.0" means that a key starts at the 5th delimeter plus    */
  9. /*    six more characters, and ends at the sixth delimeter        */
  10. /* "n" appended to any key specifier makes it a numeric comparison  */
  11. /* "r" appended to any key specifier makes it a reverse comparison  */
  12.  
  13. /* Assuming a file that contained:
  14.  *    accountname;name;address;balance;phone number
  15.  *
  16.  * Example record:
  17.  *    0023Flint;Flintstone, Fred;43 Quarry Lane;120.00;355-9881
  18.  *
  19.  * SAMPLE sorts:
  20.  *    bigsort people -o namesort
  21.  *        bigsorts by name and puts the output in file "namesort".
  22.  *    bigsort -t; +3n -4 +0 people
  23.  *        sorts by balance (numerically), and accountname if the
  24.  *        balance is the same. outputs to stdout.
  25.  *        The "-t;" changes the tab (field delimeter) to semicolon.
  26.  *        Note that +3n skips to the field after the 3rd delimeter,
  27.  *        you might think of it as the 4th field.
  28.  *    bigsort +0.4 people
  29.  *        sorts by characters starting with the 5th (skips 4).
  30.  */
  31.  
  32. /*  This program is SHAREWARE, an $8.00 donation puts you on my mailing
  33.  *  list to receive the next version of this and my screen utilities.
  34.  *
  35.  *        Jim Gast
  36.  *        16 N. Columbia
  37.  *        Naperville, IL 60540
  38.  */
  39.  
  40. /* Compiled under CI-86, and depends on the CI-86 routine qsort()   */
  41. /* To sort any decent size file, compile with BIG model            */
  42.  
  43. /* up to MAXKEYS keys can be specified  */
  44. #define MAXKEYS          20
  45.  
  46. /* up to MAXRECS records can be sorted  */
  47. #define MAXRECS        5000
  48.  
  49. /* each record can be up to LINELEN long */
  50. #define LINELEN         512
  51.  
  52. /* there can be up to MAXFILES input files */
  53. #define MAXFILES     50
  54.  
  55. /* CI-86 is does not understand <stdio.h> */
  56. #include "\lib\stdio.h"
  57.  
  58. #define STRING        1
  59. #define NUMERIC        2
  60.  
  61. #define FORWARD        1
  62. #define REVERSE        2
  63.  
  64. #define INFINITY    LINELEN
  65.  
  66. #define TAB        '\011'
  67.  
  68. struct key_struct {
  69.     int k_lo_field;
  70.     int k_lo_char;
  71.     int k_hi_field;
  72.     int k_hi_char;
  73.     int k_comparison;
  74.     int k_direction;
  75.     } key_table[MAXKEYS], *lastkey;
  76.  
  77. int keypointers;
  78. char tab;
  79. char *rec[MAXRECS];
  80. int numrecs;
  81.  
  82. char *passdigits();
  83. char *keyptr();
  84. FILE *fopen();
  85. char *fgets();
  86. char *alloc();
  87. long atoi();
  88.  
  89. main (argc, argv)
  90.  int argc;
  91.  char *argv[];
  92.  {
  93.   int a;
  94.   int hi;
  95.   register char *arg;
  96.   register struct key_struct *k;
  97.   char *pdata;
  98.   int r;
  99.   char *p;
  100.   char *infile_name[MAXFILES];
  101.   char outfile[80];
  102.   int infiles;
  103.   int fi;
  104.   FILE *sort_out;
  105.   int comp();
  106.  
  107.   infiles = 0;
  108.   numrecs = 0;
  109.   *outfile = 0;
  110.   tab = TAB;
  111.   k = &key_table[-1];
  112.   for (a = 1;a < argc; a++)
  113.     {
  114.      arg = argv[a];
  115.      if (*arg != '-' && *arg != '+')
  116.         {
  117.          /* This must be an input file name */
  118.          infile_name[infiles] = alloc(strlen(arg) + 1);
  119.          strcpy(infile_name[infiles], arg);
  120.          infiles++;
  121.          continue;
  122.         }
  123.      if (*arg == '-' && arg[1] == 'o')
  124.         {
  125.          if (arg[2] == 0) arg = argv[++a];
  126.          strcpy(outfile,arg);
  127.          continue;
  128.         }
  129.      if (*arg == '-' && arg[1] == 't')
  130.         {
  131.          tab = arg[2];
  132.          continue;
  133.         }
  134.      if (*arg == '+' || k < &key_table[0])
  135.         {
  136.          k++;
  137.          k->k_lo_field = 0;
  138.          k->k_lo_char  = 0;
  139.          k->k_hi_field = INFINITY;
  140.          k->k_hi_char  = 0;
  141.          k->k_comparison = STRING;
  142.          k->k_direction  = FORWARD;
  143.         }
  144.  
  145.      hi = (*arg++ == '-');
  146.  
  147.      if (hi) k->k_hi_field = atoi(arg);
  148.         else k->k_lo_field = atoi(arg);
  149.      arg = passdigits(arg);
  150.  
  151.      if (*arg == '.')
  152.         {
  153.          arg++;
  154.          if (hi) k->k_hi_char = atoi(arg);
  155.             else k->k_lo_char = atoi(arg);
  156.          arg = passdigits(arg);
  157.         }
  158.  
  159.      /* handle letters appended after field specifiers */
  160.      while (*arg)
  161.         {
  162.          switch (*arg)
  163.             {
  164.             case 'n':  k->k_comparison = NUMERIC;
  165.                    break;
  166.  
  167.             case 'r':  k->k_direction = REVERSE;
  168.                    break;
  169.  
  170.             default:   fprintf(stderr,"bad specifier: %s\n",argv[a]);
  171.                     fprintf(stderr,"bad letter:    %c\n",*arg);
  172.                    break;
  173.             }
  174.          arg++;
  175.         }
  176.     }
  177.  
  178.  /* if no keys were specified */
  179.  if (k == &key_table[-1])
  180.     {
  181.      k++;
  182.      k->k_lo_field = 0;
  183.      k->k_lo_char  = 0;
  184.      k->k_hi_field = INFINITY;
  185.      k->k_hi_char  = 0;
  186.      k->k_comparison = STRING;
  187.      k->k_direction = FORWARD;
  188.     }
  189.  
  190.  lastkey = k;
  191.  
  192.  keypointers = sizeof (char *) * 2 * (lastkey - &key_table[-1]);
  193.  
  194.  if (*outfile != 0)
  195.     {
  196.      sort_out = fopen(outfile,"w");
  197.      if (sort_out == NULL)
  198.         {
  199.          fprintf(stderr, "bigsort: unable to open out file %s\n",outfile);
  200.          exit(1);
  201.         }
  202.     }
  203.      else
  204.     {
  205.      sort_out = stdout; 
  206.     }
  207.  
  208.  if (infiles == 0)
  209.     {
  210.      infiles = 1;
  211.      infile_name[0] = "";
  212.     }
  213.  
  214.  for (fi = 0; fi < infiles; fi++) get_data(infile_name[fi]);
  215.  
  216.  qsort(rec, numrecs, sizeof (char *), comp);
  217.  
  218.  for (r = 0; r < numrecs; r++)
  219.     {
  220.      pdata = rec[r] + keypointers;
  221.      fprintf(sort_out,"%s",pdata);
  222.     }
  223.   fclose(sort_out);
  224.  }
  225.  
  226. char *passdigits(p)
  227.  char *p;
  228.   {
  229.    while (*p >= '0' && *p <= '9') p++;
  230.    return(p);
  231.   }
  232.  
  233. int show_args()
  234.   {
  235.    register struct key_struct *k;
  236.  
  237.    printf("Tab is octal %4o\n",tab);
  238.  
  239.    for (k = &key_table[0]; k <= lastkey; k++)
  240.     {
  241.      printf("\n");
  242.      printf("lo = %4d . %4d\n",k->k_lo_field, k->k_lo_char);
  243.      printf("hi = %4d . %4d\n",k->k_hi_field, k->k_hi_char);
  244.      printf("compare   = %s\n",
  245.         (k->k_comparison == NUMERIC? "numeric" : "string"));
  246.      printf("direction = %s\n",
  247.         (k->k_direction == FORWARD? "forward" : "reverse"));
  248.     }
  249.   }
  250.  
  251. char *keyptr(data, fld, chr)
  252.  char *data;
  253.  int fld;
  254.  int chr;
  255.   {
  256.    int f, c;
  257.  
  258.    for (f = 0; f < fld; )
  259.     {
  260.      if (*data == tab) f++;
  261.      if (*data == 0) break;
  262.      data++;
  263.     }
  264.  
  265.    for (c = 0; c < chr; c++)
  266.     {
  267.      if (*data == tab) break;
  268.      if (*data == 0) break;
  269.      data++;
  270.     }
  271.    return(data);
  272.   }
  273.  
  274. int comp(a,b)
  275.  char **a, **b;
  276.   {
  277.    register char *p, *q;
  278.    register struct key_struct *k;
  279.    char *p_end, *q_end;
  280.    char **pp, **qq;
  281.    int high, low;
  282.    long pval, qval;
  283.  
  284.    pp = (char **) *a;
  285.    qq = (char **) *b;
  286.  
  287.    for (k = &key_table[0]; k <= lastkey; k++)
  288.     {
  289.      p = *pp++;
  290.      p_end = *pp++;
  291.      q = *qq++;
  292.      q_end = *qq++;
  293.  
  294.      if (k->k_direction == FORWARD)
  295.         {
  296.          high = 1;
  297.          low = -1;
  298.         }
  299.      else
  300.         {
  301.          high = -1;
  302.          low = 1;
  303.         }
  304.  
  305.      if (k->k_comparison == NUMERIC)
  306.         {
  307.          pval = atoi(p);
  308.          qval = atoi(q);
  309.          if (pval > qval) return(high);
  310.          if (pval < qval) return(low);
  311.         }
  312.  
  313.      /* all other comparisons are string comparisons */
  314.      else while (1)
  315.         {
  316.          if (p >= p_end)
  317.             {
  318.              if (q >= q_end) break;
  319.                 else return(low);
  320.             }
  321.          if (q >= q_end) return(high);
  322.          if (*p < *q) return(low);
  323.          if (*p > *q) return(high);
  324.          p++; q++;
  325.         }
  326.     }
  327.    return(0);
  328.   }
  329.  
  330. /* get_data reads records in from a data file. If the file name is */
  331. /* NULL (""), it reads from standard in */
  332.  
  333. int get_data(filename)
  334.  char *filename;
  335.  {
  336.   register char *p;
  337.   register int r;
  338.   char buffer[LINELEN];
  339.   char **pp;
  340.   char *pdata;
  341.   FILE *sort_in;
  342.   struct key_struct *k;
  343.  
  344.   if (filename[0] != 0)
  345.     {
  346.      sort_in = fopen(filename, "r");
  347.      if (sort_in == NULL)
  348.         {
  349.          fprintf(stderr, "bigsort: unable to open %s\n",filename);
  350.          exit(1);
  351.         }
  352.     }
  353.     else sort_in = stdin;
  354.  
  355.   for (r = numrecs; r < MAXRECS; r++)
  356.     {
  357.      p = fgets(buffer,LINELEN,sort_in);
  358.      if (p == NULL) break;
  359.      rec[r] = alloc(strlen(buffer) + keypointers + 1);
  360.      pdata = rec[r] + keypointers;
  361.      strcpy(pdata, buffer);
  362.      pp = (char **) rec[r];
  363.      for (k = &key_table[0]; k <= lastkey; k++)
  364.         {
  365.          *pp++ = keyptr(pdata,k->k_lo_field,k->k_lo_char);
  366.          *pp++ = keyptr(pdata,k->k_hi_field,k->k_hi_char);
  367.         }
  368.     }
  369.   numrecs = r;
  370.  
  371.   if (filename[0] != 0) fclose(sort_in);
  372.  }
  373.