home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 9 / amigaformatcd09.iso / coverdisks / subsdisk / subs.dms / subs.adf / cookie.LZX / cookietool / src / cookietool.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-19  |  10.3 KB  |  368 lines

  1. /*************************************************************************\
  2.          cookietool: remove duplicate entries from a cookie file
  3. Various options for sorting the output.  The expected file format is 
  4. plain text with a "%%" line ending each cookie.
  5. Usage:
  6.     cookietool [options] <database> [logfile]
  7. options:      meaning:
  8.     -s        sort output
  9.     -sl        " , looking at the last line only
  10.     -sw        " , looking at the last word only
  11.     -s<sep>    " , starting after the last occurence of <sep>, e.g. '--'
  12.     -p        passive, don't delete anything
  13.     -c        case-sensitive comparisons (for both sorting and deleting)
  14.     -d[0-3]   how fussy about word delimiters? (default: 2)
  15.     -a        delete cookies that are "abbreviations" of another, too
  16.     -o        overwrite the input file directly (no tempfile)
  17. Note:  Option -o is risky and should only be used if no disk space for a
  18.    tempfile is available.
  19. \*************************************************************************/
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include "strstuff.h"
  26.  
  27. char version[] = "$VER: cookietool 2.1 (19.11.96)";
  28.  
  29. struct cookie {
  30.   UBYTE *text;
  31.   UBYTE *sorthook;
  32.   long number;
  33. };
  34.  
  35. struct cookie *clist;
  36.  
  37. long listsize = 1000;    /* will be adjusted dynamically */
  38. long listed = 0;
  39.  
  40. #define FBUFSIZE 16384   /* we'll use larger file buffers */
  41. #define CBUFSIZE 20000
  42. #define LBUFSIZE 2000
  43. UBYTE cbuf[CBUFSIZE];    /* large enough to hold one complete cookie */
  44. UBYTE line[LBUFSIZE];    /* large enough to hold the longest line */
  45.  
  46.  
  47. void help(UBYTE *s)
  48. /* print a help text and nag about illegal parameter <s> */
  49. {
  50.   if (s) printf("illegal option '%s'\n", s);
  51.   printf("usage:  cookietool [options] <database> \n");
  52.   printf("where options are:\n");
  53.   printf(" -p      passive, don't delete anything\n");
  54.   printf(" -a      treat 'abbreviations' as doubles (i.e. delete them, too)\n");
  55.   printf(" -s      sort cookies\n");
  56.   printf(" -sl      \" , looking at the last line only\n");
  57.   printf(" -sw      \" , looking at the last word only\n");
  58.   printf(" -s<sep>  \" , starting after the last <sep>, e.g. '-s--'\n");
  59.   printf(" -d[0-3] how fussy about word delimiters? (default: 2)\n");
  60.   printf(" -c      case sensitive comparisons\n");
  61.   printf(" -o      overwrite directly, no tempfile (caution!)\n");
  62. }
  63.  
  64.  
  65. int cookie_cmp(struct cookie *a, struct cookie *b)
  66. /* compares cookies by string and, if these are identical, by number */
  67. {
  68.   int c;
  69.   if (c = str_cmp(a->sorthook, b->sorthook))
  70.     return c;
  71.   else
  72.     return (a->number) - (b->number);
  73. }
  74.  
  75. void sift(struct cookie v[], long i, long m, int mode)
  76. /* centre routine to heapsort() */
  77. /* mode==0: sort by number, mode==±1: sort by name (ascending/descending) */
  78. {                                          
  79.   long j;
  80.   struct cookie temp;
  81.  
  82.   if (mode != 0) {  /* by name */
  83.     while ((j = 2*(i+1)-1) <= m) {
  84.       if (j < m  && mode*cookie_cmp(&v[j], &v[j+1]) < 0)
  85.         j++;
  86.       if (mode*cookie_cmp(&v[i], &v[j]) < 0) {
  87.         temp = v[i]; v[i] = v[j]; v[j] = temp;
  88.         i = j;
  89.       } else
  90.         i = m;  /* done */
  91.     }
  92.   } else {  /* by number */
  93.     while ((j = 2*(i+1)-1) <= m) {
  94.       if (j < m  && (v[j].number < v[j+1].number) )
  95.         j++;
  96.       if (v[i].number < v[j].number) {
  97.         temp = v[i]; v[i] = v[j]; v[j] = temp;
  98.         i = j;
  99.       } else
  100.         i = m;  /* done */
  101.     }
  102.   }
  103. }
  104.  
  105.  
  106. void my_heapsort(struct cookie v[], long n, int mode)
  107. /* mode==0: sort by number, mode==±1: sort by name (ascending/descending) */
  108. {
  109.   long i;
  110.   struct cookie temp;
  111.  
  112.   if (n<2)          /* no sorting necessary */
  113.     return;
  114.   for (i = n/2-1; i >= 0; i--)
  115.     sift(v, i, n-1, mode);
  116.   for (i = n-1; i >= 1; i--) {
  117.     temp = v[0]; v[0] = v[i]; v[i] = temp;
  118.     sift(v, 0, i-1, mode);
  119.   }
  120. }
  121.  
  122.  
  123. UBYTE hooktarget[16];
  124.  
  125. void set_hooks(int mode)
  126. /* adjust sorthooks for the final sort, according to the desired mode */
  127. {
  128.   long l;
  129.   int hot;
  130.   UBYTE *s;
  131.   
  132.   printf("adjusting sort hooks"); fflush(stdout);
  133.   for (l=0; l<listed; l++) {
  134.     s = clist[l].text;
  135.     switch (mode) {
  136.       case 2:   /* start of last line */
  137.         hot = 1;
  138.         while (*s) {
  139.           if (*s == '\n')  
  140.             hot = 1;
  141.           else if (hot) {
  142.             clist[l].sorthook = s; hot = 0;
  143.           }
  144.           s++;
  145.         } break;
  146.       case 3:   /* start of last word */
  147.         hot = 1;
  148.         while (*s) {
  149.           if (isspace(*s))
  150.             hot = 1;
  151.           else if (hot) {
  152.             clist[l].sorthook = s; hot = 0;
  153.           }
  154.           s++;
  155.         } break;
  156.       case 4:   /* at last occurence of <hooktarget> */
  157.         while (s) {
  158.           clist[l].sorthook = s++;
  159.           s = strstr(s, hooktarget);
  160.         } break;
  161.       default:
  162.     }
  163.   }
  164.   printf(", done.\n");
  165. }
  166.  
  167.  
  168. void one_cookie(int doubles, int abbrevs, int sortmode, FILE *fp)
  169. /* delete cookies and log them to a file */
  170. {
  171.   long i, j, dbl = 0, abr = 0;
  172.   int c;
  173.  
  174.   if (doubles) {
  175.     printf("removing double entries"); 
  176.     if (abbrevs) printf(" + 'abbreviations'");
  177.     fflush(stdout);
  178.     my_heapsort(clist, listed, -1);   /* sort descending by string */
  179.     for (i = listed-1; i > 0; i = j) {
  180.       for (j = i-1; j >= 0 && ( (c=str_cmp(clist[j].text,clist[i].text)) == 0
  181.       || (abbrevs && c == STR_SHORTER) ); j--) {
  182.         if (fp)
  183.           if (fprintf(fp, "%s\n%%%%\n", clist[j].text) <= 0) {
  184.             printf("\nfile error, aborted !!!\n");
  185.             exit(20);                          
  186.           }
  187.         free(clist[j].text);
  188.         clist[j] = clist[--listed];
  189.         if (c == 0) dbl++;  else  abr++;
  190.       }
  191.     }
  192.     printf(", done. (%ld + %ld found)\n",dbl,abr);
  193.   }
  194.   if (sortmode>0) {
  195.     if (sortmode>1) set_hooks(sortmode);
  196.     printf("sorting"); fflush(stdout);
  197.     my_heapsort(clist, listed, 1);   /* sort ascending by string */
  198.   } else {
  199.     printf("restoring order"); fflush(stdout);
  200.     my_heapsort(clist, listed, 0);   /* sort by number */
  201.   }
  202.   printf(", done.\n");
  203. }
  204.  
  205.  
  206. void read_cookies(FILE *fp)
  207. {
  208.   long cbuflen, ignored=0;
  209.   int lines;
  210.   UBYTE *s;
  211.  
  212.   printf("reading cookies"); fflush(stdout);
  213.   strcpy(cbuf,""); lines=0; cbuflen=0;
  214.   while (fgets(line,LBUFSIZE,fp)) {
  215.     if (strncmp(line,"%%",2)==0) {   /* "end of cookie"-marker */
  216.       if (lines>0) {       /* store the cookie */
  217.         /* but drop the last LF, to avoid trouble in recognizing abbrev's: */
  218.         cbuflen = strlen(cbuf);
  219.         if (cbuf[cbuflen-1] == '\n')
  220.           cbuf[--cbuflen] = '\0';
  221.         if (clist[listed].text = malloc(cbuflen+1)) {  /* mind the '\0'! */
  222.           clist[listed].number = listed+ignored;
  223.           strcpy(clist[listed].text, cbuf);
  224.           s = clist[listed].sorthook = clist[listed].text;
  225.         } else {
  226.           printf("\nout of memory\n");
  227.           exit(20);
  228.         }
  229.         if (++listed == listsize) {
  230.           listsize = 3 * listsize / 2;
  231.           clist = realloc(clist, listsize * sizeof(struct cookie));
  232.           if (!clist) {
  233.             printf("\nlist reallocation failed\n");
  234.             exit(20);
  235.           }
  236.         }
  237.       } else {
  238.         ignored++;   /* or ignore it */
  239.       }
  240.       /* start a new one */
  241.       strcpy(cbuf,""); lines=0; cbuflen=0;
  242.     } else {
  243.       if ((cbuflen += strlen(line)) >= CBUFSIZE) {
  244.         printf("\ncookie too big (>%ld chars)\n", CBUFSIZE);
  245.         exit(20);
  246.       }
  247.       strcat(cbuf,line); lines++;
  248.     }
  249.   }
  250.   printf(", done. (%ld read, %ld empty)\n", listed, ignored);
  251. }
  252.  
  253.  
  254. write_cookies(FILE *fp)
  255. /* also frees the allocated memory! */
  256. {
  257.   long l;
  258.   
  259.   printf("writing cookies"); fflush(stdout);
  260.   for (l=0; l<listed; l++) {
  261.     if (fprintf(fp, "%s\n%%%%\n", clist[l].text) <= 0) {
  262.       printf("\nfile error, aborted !!!\n");
  263.       exit(20);
  264.     }
  265.     free(clist[l].text);
  266.   }
  267.   printf(", done. (%ld written)\n", listed);
  268. }
  269.  
  270.  
  271. int main(int argc, char *argv[])
  272. {
  273.   UBYTE *s;
  274.   int dirty = 0, passive = 0, abbrevs = 0, finalsort = 0;
  275.   int case_sense = 0, bordermode = 2;
  276.   UBYTE name1[100], name2[100], name3[100];
  277.   FILE *infile, *outfile, *logfile;
  278.  
  279.   name1[0] = name2[0] = name3[0] = '\0';
  280.   if (argc<2) {
  281.     help(NULL);
  282.     return 5;
  283.   }
  284.   while (--argc) {
  285.     s = *++argv;
  286.     if (*s != '-') {
  287.       if (name1[0] == '\0')
  288.         strcpy(name1, s);
  289.       else
  290.         strcpy(name3, s);
  291.     } else {
  292.       switch (*++s) {
  293.         case 's': 
  294.           switch (*++s) {
  295.             case '\0': finalsort = 1; break;
  296.             case 'l': finalsort = 2; break;
  297.             case 'w': finalsort = 3; break;
  298.             default: if ispunct(*s) {
  299.                 finalsort = 4; strncpy(hooktarget,s,15);
  300.               } else {
  301.                 help(argv[0]); return 5;
  302.               }
  303.           } break;
  304.         case 'd': if isdigit(*++s)
  305.             bordermode = atoi(s);
  306.           else {
  307.             help(argv[0]); return 5;
  308.           } break;
  309.         case 'c': case_sense = 1; break;
  310.         case 'a': abbrevs = 1; break;
  311.         case 'p': passive = 1; break;
  312.         case 'o': dirty = 1; break;
  313.         default:
  314.           help(argv[0]); return 5;
  315.       }
  316.     }
  317.   }
  318.   /* important, before calling anything from strstuff: */
  319.   str_setup(bordermode, case_sense);  
  320.   if (name1[0] == '\0') {
  321.     help(NULL);
  322.     return 5;
  323.   }
  324.   if (dirty) {
  325.     strcpy(name2, name1);
  326.     printf("Warning!  You have enabled direct writeback mode!\n");
  327.     printf("\e[2mDon't break (or crash) cookietool now, ");
  328.     printf("or you will inevitably lose data!\e[0m\n");
  329.   } else
  330.     strcpy(name2, "ct_temp_crunchfile");
  331.   printf("cookietool "); print_strstat();
  332.   clist = malloc(listsize * sizeof(struct cookie));
  333.   if (!clist) {
  334.     printf("list allocation failed\n");
  335.     return 20;
  336.   }
  337.   if (!(infile = fopen(name1,"r"))) {
  338.     printf("Can't open %s for input!\n", name1);
  339.     return 10;
  340.   }
  341.   setvbuf(infile, NULL, _IOFBF, FBUFSIZE);
  342.   if (name3[0] != '\0') {
  343.     if (!(logfile = fopen(name3,"w"))) {
  344.       printf("Can't open %s for output!\n", name3);
  345.       return 10;
  346.     }
  347.   } else
  348.     logfile = NULL;
  349.   read_cookies(infile); fclose(infile);
  350.   one_cookie(!passive, abbrevs, finalsort, logfile); 
  351.   if (logfile) fclose(logfile);
  352.   if (!(outfile = fopen(name2,"w"))) {
  353.     printf("Can't open %s for output!\n", name2);
  354.     return 10;
  355.   }
  356.   setvbuf(outfile, NULL, _IOFBF, FBUFSIZE);
  357.   write_cookies(outfile); fclose(outfile);
  358.   free(clist);
  359.   if (!dirty) {      /* replace the input file */
  360.     if (remove(name1) != 0 || rename(name2, name1) != 0) {
  361.       printf("Couldn't overwrite the input file!  Your cookies are in '%s'.\n", name2);
  362.       return 5;
  363.     }
  364.   }
  365.   return 0;
  366. }
  367.  
  368.