home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 347_01 / sortx.c < prev    next >
C/C++ Source or Header  |  1991-10-20  |  6KB  |  218 lines

  1. /*:file:version:date: "%n    V.%v;  %f"
  2.  * "SORTX.C    V.7;  20-Oct-91,14:57:32"
  3.  *
  4.  *  Program: Sort
  5.  *  Purpose: Text line sorter: sorts standard input and writes to
  6.  *           standard output. Similar to MS-DOS sort, but collating
  7.  *           sequence is not quite the same.  This sort is much, much
  8.  *           faster than MS-DOS Sort on medium to large files.
  9.  *
  10.  *  Usage:   SORTX [/R] [/+n]         (or SORTX [-R] [-+n], UNIX)
  11.  *
  12.  *              Where /R  means sort descending.
  13.  *                    /+n sort key begins in n'th column of text line.
  14.  *              Command line options must be separated by white space.
  15.  *
  16.  *           MS-DOS examples:
  17.  *           C>dir | SORTX /R /+10
  18.  *           ...writes directory sorted by extension in descending order
  19.  *           C>SORTX < Afile.txt > Sorted.txt
  20.  *           ...writes sorted Afile.txt to Sorted.txt
  21.  *
  22.  *           DOS users should compile in a LARGE data model, SMALL code;
  23.  *           (COMPACT, for Turbo C users).
  24.  *
  25.  *      Copyright (c) 1991  Bert C. Hughes
  26.  *                          200 N.Saratoga
  27.  *                          St.Paul, MN 55104
  28.  *                          Compuserve 71211,577
  29.  */
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include "tavltree.h"
  35.  
  36. #define BUFSIZE 4608               /*arbitrary but make it large*/
  37. char IObuffer[BUFSIZE];            /*buffer for "stdin" & "stdout" */
  38.  
  39. #define MAX_STR 500
  40.  
  41. typedef struct {
  42.             int line_no;
  43.             char text[MAX_STR];
  44.         } LineRec, *PLineRec;
  45.  
  46. #define LR_SIZE(x)  (sizeof(int)+sizeof(char)+sizeof(char)*strlen(((PLineRec)(x))->text))
  47.  
  48. char default_name[] = "SORTX";     /* For error messages */
  49. char *program_name = default_name;
  50.  
  51. unsigned CmpOfs;                   /* Offset into text lines */
  52.  
  53. void error(const char *message, int code);
  54.  
  55. #if defined __MSDOS__
  56. #define DEFAULT_SWT '/'       /* default for MS-DOS */
  57. #else
  58. #define DEFAULT_SWT '-'       /* UNIX ? */
  59. #endif
  60.  
  61. char swt = DEFAULT_SWT;       /* command line switch character */
  62.  
  63. /*
  64.  * Get options from the command line:
  65.  *     If your system does not have "getopt", you will have to write one -
  66.  *     but it only needs to handle the "R" option and "+n" option.
  67.  *     A dummy routine may simply return 0 -then you can sort with no options
  68.  *     TurboC v2.0 includes "getopt.c" in sample routines; apparently it is
  69.  *     a part of UNIX system V (?)
  70.  *
  71.  * AMENDMENT: the "dummy" provided below works for this program - to add
  72.  *            options you will need the real "getopt".
  73.  */
  74.  
  75. #if defined USE_GETOPT
  76.  
  77. extern int  getopt(int argc, char *argv[], char *optionS);
  78. extern char *optarg;
  79.  
  80. #else
  81.  
  82. char default_optarg[1] = "";
  83. char *optarg;
  84.  
  85. int  getopt(int argc, char *argv[], char *optionS)
  86. {
  87.  /*
  88.     NOT a general purpose "getopt"; in fact, this one will ignore "optionS".
  89.     It looks for options interesting to this program only.
  90.   */
  91.  
  92.     char *p;
  93.     static int optind;
  94.     static char Reverse_Swt[3] = {DEFAULT_SWT, 'R','\0'};
  95.     static char Column_Swt[3]  = {DEFAULT_SWT, '+','\0'};
  96.  
  97.     optarg = default_optarg;
  98.  
  99.     while (++optind < argc) {
  100.         if (strstr(argv[optind],Reverse_Swt))      /* option /R  */
  101.             return('R');
  102.  
  103.         if (p = strstr(argv[optind],Column_Swt)) { /* option /+n */
  104.             optarg = p+2;
  105.             return('+');
  106.         }
  107.     } /* end while */
  108.  
  109.     return(EOF);  /* no more argv's */
  110. }
  111. #endif
  112.  
  113.  
  114. void error(const char *message, int code)
  115. {
  116.     fprintf(stderr,"\n%s: ",program_name);
  117.     if (errno)
  118.         perror(message);
  119.     else
  120.         fprintf(stderr,"%s\n",message);
  121.     exit(code);
  122. }
  123.  
  124. int cmp(PLineRec key1, PLineRec key2)
  125. {
  126.     int cmpval;
  127.     static char nullstr[] = "";
  128.     char *p1 = ((strlen(key1->text) < CmpOfs) ? nullstr : &key1->text[CmpOfs]);
  129.     char *p2 = ((strlen(key2->text) < CmpOfs) ? nullstr : &key2->text[CmpOfs]);
  130.  
  131.     if (!(cmpval = strcmp(p1,p2)))
  132.         return(key1->line_no - key2->line_no);
  133.     else
  134.         return(cmpval);
  135. }
  136.  
  137. int reverse_cmp(PLineRec key1, PLineRec key2)
  138. {
  139.     return(-cmp(key1,key2));
  140. }
  141.  
  142. void *ident(void *p)
  143. {
  144.     return(p);
  145. }
  146.  
  147. void *create(const void *p)
  148. {
  149.     register unsigned size = LR_SIZE(p);
  150.     PLineRec q = malloc(size);
  151.     if (q) memcpy(q,p,size);
  152.     return(q);
  153. }
  154.  
  155. void *copy(void *dest, const void *src)
  156. {
  157.     return(memcpy(dest,src,LR_SIZE(src)));
  158. }
  159.  
  160.  
  161. main(int argc, char **argv)
  162. {
  163.     int (*compare)() = cmp;
  164.     LineRec item;
  165.     TAVL_treeptr List;
  166.     TAVL_nodeptr p;
  167.     int options;
  168.     long Uval;
  169.     char emsg[64];
  170.  
  171.    /* get options: ?reverse sort?  ?compare beginning at column N? */
  172.  
  173.     do {
  174.         options = getopt(argc, argv, "R+:");
  175.         switch (options) {
  176.             case 'R':   compare = reverse_cmp;
  177.                         break;
  178.  
  179.             case '+':   Uval = strtol(optarg,NULL,10);
  180.                         if ((Uval > 0) && (Uval < MAX_STR-1))
  181.                             CmpOfs = Uval - 1;
  182.                         else {
  183.                             sprintf(emsg,"%c+n  :invalid \"n\": requires  0 < n < %d",swt,MAX_STR-1);
  184.                             error(emsg,1);
  185.                         }
  186.                         break;
  187.  
  188.             case '?':   fprintf(stderr,"\nUsage: %s [%cR] [%c+n]\n",program_name,swt,swt);
  189.                         fprintf(stderr,"INPUT is from \"standard input\", ");
  190.                         fprintf(stderr,"OUTPUT is to \"standard output\".\n");
  191.                         exit(1);
  192.         }
  193.     } while (options != EOF);
  194.  
  195.     if (!(List = tavl_init(compare,ident,create,free,copy,malloc,free)))
  196.         error("At tavl_init",1);
  197.  
  198.  /* read file into tree */
  199.  
  200.     setbuf(stdin,IObuffer);
  201.  
  202.     while (fgets(item.text,MAX_STR-2,stdin)) {
  203.         if (!tavl_insert(List,&item,0))
  204.             error("At tavl_insert",1);
  205.         item.line_no++;                 /* Use line #'s to distinguish */
  206.     }                                   /* identical lines - otherwise */
  207.                                         /* duplicates will be eliminated! */
  208.  /* write file from tree in order */
  209.  
  210.     setbuf(stdout,IObuffer);
  211.  
  212.     p = tavl_reset(List);
  213.     while (p = tavl_succ(p)) {
  214.         tavl_getdata(List,p,&item);
  215.         fputs(item.text,stdout);
  216.     }
  217. }
  218.