home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2282 / iidfun.c
Encoding:
C/C++ Source or Header  |  1990-12-28  |  16.2 KB  |  659 lines

  1. /* iidfun.c - This file holds the utility functions called from iid.y
  2.  */
  3.  
  4. #include "iiddef.h"
  5.  
  6. /* ArgListSize - count the size of an arg list so can alloca() enough
  7.  * space for the command.
  8.  */
  9. int
  10. ArgListSize(idlp)
  11.    id_list_type * idlp ;
  12. {
  13.    id_type *      idep ;
  14.    int            size = 0;
  15.    
  16.    idep = idlp->id_list ;
  17.    while (idep != NULL) {
  18.       size += 1 + strlen(idep->id);
  19.       idep = idep->next_id;
  20.    }
  21.    return size;
  22. }
  23.  
  24. /* SetListSize - count the size of a string build up from a set so we can
  25.  * alloca() enough space for args.
  26.  */
  27. int
  28. SetListSize(sp)
  29.    set_type * sp ;
  30. {
  31.    int            i ;
  32.    int            size = 0 ;
  33.    
  34.    for (i = 0; i < NextFileNum; ++i) {
  35.       if (FileList[i]->mask_word < sp->set_size) {
  36.          if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  37.             size += 1 + strlen(FileList[i]->name);
  38.          }
  39.       }
  40.    }
  41.    return size;
  42. }
  43.  
  44. /* FlushFiles - clear out the TheFiles array for the start of a new
  45.  * query.
  46.  */
  47. void
  48. FlushFiles()
  49. {
  50.    int             i ;
  51.    
  52.    if (TheFiles != NULL) {
  53.       for (i = 0; i <= MaxCurFile; ++i) {
  54.          TheFiles[i] = 0 ;
  55.       }
  56.    }
  57.    MaxCurFile = 0 ;
  58. }
  59.  
  60. /* fatal - sometimes the only thing to do is die...
  61.  */
  62. void
  63. fatal(s)
  64. {
  65.    fprintf(stderr,"Fatal error: %s\n",s) ;
  66.    exit(1) ;
  67. }
  68.  
  69. /* CountBits - count the number of bits in a bit set. Actually fairly
  70.  * tricky since it needs to deal with sets having infinite tails
  71.  * as a result of a NOT operation.
  72.  */
  73. int
  74. CountBits(sp)
  75.    set_type * sp ;
  76. {
  77.    unsigned long      bit_mask ;
  78.    int                count = 0 ;
  79.    int                i ;
  80.    
  81.    i = 0;
  82.    for ( ; ; ) {
  83.       for (bit_mask = high_bit; bit_mask != 0; bit_mask >>= 1) {
  84.          if (bit_mask == NextMaskBit && i == NextMaskWord) {
  85.             return(count) ;
  86.          }
  87.          if (i < sp->set_size) {
  88.             if (sp->set_data[i] & bit_mask) {
  89.                ++count ;
  90.             }
  91.          } else {
  92.             if (sp->set_tail == 0) return count;
  93.             if (sp->set_tail & bit_mask) {
  94.                ++count;
  95.             }
  96.          }
  97.       }
  98.       ++i;
  99.    }
  100. }
  101.  
  102. /* OneDescription - Print a description of a set. This includes
  103.  * the set number, the number of files in the set, and the
  104.  * set description string.
  105.  */
  106. void
  107. OneDescription(sp)
  108.    set_type * sp ;
  109. {
  110.    int        elt_count ;
  111.    char       setnum[20] ;
  112.    
  113.    sprintf(setnum,"S%d",sp->set_num) ;
  114.    elt_count = CountBits(sp) ;
  115.    printf("%5s %6d  %s\n",setnum,elt_count,sp->set_desc) ;
  116. }
  117.  
  118. /* DescribeSets - Print description of all the sets.
  119.  */
  120. void
  121. DescribeSets()
  122. {
  123.    int            i ;
  124.  
  125.    if (NextSetNum > 0) {
  126.       for (i = 0; i < NextSetNum; ++i) {
  127.          OneDescription(TheSets[i]) ;
  128.       }
  129.    } else {
  130.       printf("No sets defined yet.\n") ;
  131.    }
  132. }
  133.  
  134. /* SetList - Go through the bit set and add the file names in
  135.  * it to an identifier list.
  136.  */
  137. id_list_type *
  138. SetList(idlp, sp)
  139.    id_list_type *  idlp ;
  140.    set_type *      sp ;
  141. {
  142.    int        i ;
  143.    id_type *  idep ;
  144.    
  145.    for (i = 0; i < NextFileNum; ++i) {
  146.       if (FileList[i]->mask_word < sp->set_size) {
  147.          if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  148.             idep = (id_type *)malloc(sizeof(id_type) +
  149.                                      strlen(FileList[i]->name)) ;
  150.             if (idep == NULL) {
  151.                fatal("Out of memory in SetList") ;
  152.             }
  153.             idep->next_id = NULL ;
  154.             strcpy(idep->id, FileList[i]->name) ;
  155.             idlp = ExtendList(idlp, idep) ;
  156.          }
  157.       }
  158.    }
  159.    return(idlp) ;
  160. }
  161.  
  162. /* PrintSet - Go through the bit set and print the file names
  163.  * corresponding to all the set bits.
  164.  */
  165. void
  166. PrintSet(sp)
  167.    set_type * sp ;
  168. {
  169.    int        i ;
  170.    
  171.    for (i = 0; i < NextFileNum; ++i) {
  172.       if (FileList[i]->mask_word < sp->set_size) {
  173.          if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  174.             printf("%s\n",FileList[i]->name) ;
  175.          }
  176.       }
  177.    }
  178. }
  179.  
  180. /* Free up all space used by current set of sets and reset all
  181.  * set numbers.
  182.  */
  183. void
  184. FlushSets()
  185. {
  186.    int         i ;
  187.    
  188.    for (i = 0; i < NextSetNum; ++i) {
  189.       free(TheSets[i]->set_desc) ;
  190.       free(TheSets[i]) ;
  191.    }
  192.    NextSetNum = 0 ;
  193. }
  194.  
  195. /* InitList - create an empty identifier list.
  196.  */
  197. id_list_type *
  198. InitList()
  199. {
  200.    id_list_type *   idlp ;
  201.    
  202.    idlp = (id_list_type *)malloc(sizeof(id_list_type)) ;
  203.    if (idlp == NULL) {
  204.       fatal("Out of memory in InitList") ;
  205.    }
  206.    idlp->id_count = 0 ;
  207.    idlp->end_ptr_ptr = & (idlp->id_list) ;
  208.    idlp->id_list = NULL ;
  209.    return(idlp) ;
  210. }
  211.  
  212. /* ExtendList - add one identifier to an ID list.
  213.  */
  214. id_list_type *
  215. ExtendList(idlp, idp)
  216.    id_list_type * idlp ;
  217.    id_type *      idp ;
  218. {
  219.    *(idlp->end_ptr_ptr) = idp ;
  220.    idlp->end_ptr_ptr = &(idp->next_id) ;
  221.    return(idlp) ;
  222. }
  223.  
  224. /* InitIid - do all initial processing for iid.
  225.  *   1) Determine the size of a unsigned long for bit set stuff.
  226.  *   2) Find out the name of the pager program to use.
  227.  *   3) Create the HelpSet (pointing to the help file).
  228.  *   4) Setup the prompt.
  229.  */
  230. void
  231. InitIid()
  232. {
  233.    unsigned long      bit_mask = 1 ;   /* find number of bits in long */
  234.    int                i ;
  235.    char *             page ;           /* pager program */
  236.    
  237.    do {
  238.       high_bit = bit_mask ;
  239.       bit_mask <<= 1 ;
  240.    } while (bit_mask != 0) ;
  241.    
  242.    NextMaskBit = high_bit ;
  243.    
  244.    page = getenv("PAGER") ;
  245.    if (page == NULL) {
  246.       page = PAGER ;
  247.    }
  248.    strcpy(Pager, page) ;
  249.    
  250.    FlushFiles() ;
  251.    InstallFile(HELPFILE) ;
  252.    HelpSet = (set_type *)
  253.       malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
  254.    if (HelpSet == NULL) {
  255.       fatal("No memory for set in InitIid") ;
  256.    }
  257.    HelpSet->set_tail = 0 ;
  258.    HelpSet->set_desc = NULL ;
  259.    HelpSet->set_size = MaxCurFile + 1 ;
  260.    for (i = 0; i <= MaxCurFile; ++i) {
  261.       HelpSet->set_data[i] = TheFiles[i] ;
  262.    }
  263.    
  264.    page = getenv("PS1") ;
  265.    if (page == NULL) {
  266.       page = PROMPT ;
  267.    }
  268.    strcpy(Prompt, page) ;
  269. }
  270.  
  271. /* InstallFile - install a file name in the symtab. Return the
  272.  * symbol table pointer of the file.
  273.  */
  274. symtab_type *
  275. InstallFile(fp)
  276.    char *      fp ;
  277. {
  278.    char             c ;
  279.    unsigned long    hash_code ;
  280.    int              i ;
  281.    char *           sp ;
  282.    symtab_type *    symp ;
  283.    
  284.    hash_code = 0 ;
  285.    sp = fp ;
  286.    while ((c = *sp++) != '\0') {
  287.       hash_code <<= 1 ;
  288.       hash_code ^= (unsigned long)(c) ;
  289.       if (hash_code & high_bit) {
  290.          hash_code &= ~ high_bit ;
  291.          hash_code ^= 1 ;
  292.       }
  293.    }
  294.    hash_code %= HASH_SIZE ;
  295.    symp = HashTable[hash_code] ;
  296.    while (symp != NULL && strcmp(symp->name, fp)) {
  297.       symp = symp->hash_link ;
  298.    }
  299.    if (symp == NULL) {
  300.       symp = (symtab_type *)malloc(sizeof(symtab_type) + strlen(fp)) ;
  301.       if (symp == NULL) {
  302.          fatal("No memory for symbol table entry in InstallFile") ;
  303.       }
  304.       strcpy(symp->name, fp) ;
  305.       symp->hash_link = HashTable[hash_code] ;
  306.       HashTable[hash_code] = symp ;
  307.       if (NextMaskWord >= FileSpace) {
  308.          FileSpace += 1000 ;
  309.          if (TheFiles != NULL) {
  310.             TheFiles = (unsigned long *)
  311.                realloc(TheFiles, sizeof(unsigned long) * FileSpace) ;
  312.          } else {
  313.             TheFiles = (unsigned long *)
  314.                malloc(sizeof(unsigned long) * FileSpace) ;
  315.          }
  316.          if (TheFiles == NULL) {
  317.             fatal("No memory for TheFiles in InstallFile") ;
  318.          }
  319.          for (i = NextMaskWord; i < FileSpace; ++i) {
  320.             TheFiles[i] = 0 ;
  321.          }
  322.       }
  323.       symp->mask_word = NextMaskWord ;
  324.       symp->mask_bit = NextMaskBit ;
  325.       NextMaskBit >>= 1 ;
  326.       if (NextMaskBit == 0) {
  327.          NextMaskBit = high_bit ;
  328.          ++NextMaskWord ;
  329.       }
  330.       if (NextFileNum >= ListSpace) {
  331.          ListSpace += 1000 ;
  332.          if (FileList == NULL) {
  333.             FileList = (symtab_type **)
  334.                malloc(sizeof(symtab_type *) * ListSpace) ;
  335.          } else {
  336.             FileList = (symtab_type **)
  337.                realloc(FileList, ListSpace * sizeof(symtab_type *)) ;
  338.          }
  339.          if (FileList == NULL) {
  340.             fatal("No memory for FileList in InstallFile") ;
  341.          }
  342.       }
  343.       FileList[NextFileNum++] = symp ;
  344.       /* put code here to sort the file list by name someday */
  345.    }
  346.    TheFiles[symp->mask_word] |= symp->mask_bit ;
  347.    if (symp->mask_word > MaxCurFile) {
  348.       MaxCurFile = symp->mask_word ;
  349.    }
  350.    return(symp) ;
  351. }
  352.  
  353. /* RunPager - run the users pager program on the list of files
  354.  * in the set.
  355.  */
  356. void
  357. RunPager(pp, sp)
  358.    char *     pp ;
  359.    set_type * sp ;
  360. {
  361.    char *         cmd = (char *)alloca(SetListSize(sp) + strlen(pp) + 2);
  362.    int            i ;
  363.    id_type *      idep ;
  364.    
  365.    strcpy(cmd, pp) ;
  366.    for (i = 0; i < NextFileNum; ++i) {
  367.       if (FileList[i]->mask_word < sp->set_size) {
  368.          if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  369.             strcat(cmd, " ") ;
  370.             strcat(cmd, FileList[i]->name) ;
  371.          }
  372.       }
  373.    }
  374.    system(cmd) ;
  375. }
  376.  
  377. /* AddSet - add a new set to the universal list of sets. Assign
  378.  * it the next set number.
  379.  */
  380. void
  381. AddSet(sp)
  382.    set_type *   sp ;
  383. {
  384.    if (NextSetNum >= SetSpace) {
  385.       SetSpace += 1000 ;
  386.       if (TheSets != NULL) {
  387.          TheSets = (set_type **)
  388.             realloc(TheSets, sizeof(set_type *) * SetSpace) ;
  389.       } else {
  390.          TheSets = (set_type **)
  391.             malloc(sizeof(set_type *) * SetSpace) ;
  392.       }
  393.       if (TheSets == NULL) {
  394.          fatal("No memory for TheSets in AddSet") ;
  395.       }
  396.    }
  397.    sp->set_num = NextSetNum ;
  398.    TheSets[NextSetNum++] = sp ;
  399. }
  400.  
  401. /* RunProg - run a program with arguments from id_list and
  402.  * accept list of file names back from the program which
  403.  * are installed in the symbol table and used to construct
  404.  * a new set.
  405.  */
  406. set_type *
  407. RunProg(pp, idlp)
  408.    char *         pp ;
  409.    id_list_type * idlp ;
  410. {
  411.    int            c ;
  412.    char *         cmd = (char *)alloca(ArgListSize(idlp) + strlen(pp) + 2);
  413.    char *         dp ;
  414.    char           file [ MAXCMD ] ;
  415.    int            i ;
  416.    id_type *      idep ;
  417.    id_type *      next_id ;
  418.    FILE *         prog ;
  419.    set_type *     sp ;
  420.    
  421.    FlushFiles() ;
  422.    strcpy(cmd, pp) ;
  423.    idep = idlp->id_list ;
  424.    while (idep != NULL) {
  425.       strcat(cmd, " ") ;
  426.       strcat(cmd, idep->id) ;
  427.       next_id = idep->next_id ;
  428.       free(idep) ;
  429.       idep = next_id ;
  430.    }
  431.    free(idlp) ;
  432.    
  433.    /* run program with popen, reading the output. Assume each
  434.     * white space terminated string is a file name.
  435.     */
  436.    prog = popen(cmd, "r") ;
  437.    dp = file ;
  438.    while ((c = getc(prog)) != EOF) {
  439.       if (isspace(c)) {
  440.          if (dp != file) {
  441.             *dp++ = '\0' ;
  442.             InstallFile(file) ;
  443.             dp = file ;
  444.          }
  445.       } else {
  446.          *dp++ = c ;
  447.       }
  448.    }
  449.    if (dp != file) {
  450.       *dp++ = '\0' ;
  451.       InstallFile(file) ;
  452.    }
  453.    if (pclose(prog) != 0) {
  454.       /* if there was an error make an empty set, who knows what
  455.        * garbage the program printed.
  456.        */
  457.       FlushFiles() ;
  458.    }
  459.    
  460.    sp = (set_type *)
  461.       malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
  462.    if (sp == NULL) {
  463.       fatal("No memory for set in RunProg") ;
  464.    }
  465.    sp->set_tail = 0 ;
  466.    sp->set_desc = (char *)malloc(strlen(cmd) + 1) ;
  467.    if (sp->set_desc == NULL) {
  468.       fatal("No memory for set description in RunProg") ;
  469.    }
  470.    strcpy(sp->set_desc, cmd) ;
  471.    sp->set_size = MaxCurFile + 1 ;
  472.    for (i = 0; i <= MaxCurFile; ++i) {
  473.       sp->set_data[i] = TheFiles[i] ;
  474.    }
  475.    AddSet(sp) ;
  476.    return(sp) ;
  477. }
  478.  
  479. /* SetDirectory - change the working directory. This will
  480.  * determine which ID file is found by the subprograms.
  481.  */
  482. void
  483. SetDirectory(dir)
  484.    id_type *      dir ;
  485. {
  486.    if (chdir(dir->id) != 0) {
  487.       fprintf(stderr,"Directory %s not accessible.\n",dir) ;
  488.    }
  489.    free(dir) ;
  490. }
  491.  
  492. /* SetIntersect - construct a new set from the intersection
  493.  * of two others. Also construct a new description string.
  494.  */
  495. set_type *
  496. SetIntersect(sp1, sp2)
  497.    set_type * sp1 ;
  498.    set_type * sp2 ;
  499. {
  500.    char *     desc ;
  501.    int        i ;
  502.    int        len1 ;
  503.    int        len2 ;
  504.    set_type * new_set ;
  505.    int        new_size ;
  506.    
  507.    if (sp1->set_tail || sp2->set_tail) {
  508.       new_size = MAX(sp1->set_size, sp2->set_size) ;
  509.    } else {
  510.       new_size = MIN(sp1->set_size, sp2->set_size) ;
  511.    }
  512.    new_set = (set_type *)malloc(sizeof(set_type) +
  513.                                 (new_size - 1) * sizeof(unsigned long)) ;
  514.    if (new_set == NULL) {
  515.       fatal("No memory for set in SetIntersect") ;
  516.    }
  517.    len1 = strlen(sp1->set_desc) ;
  518.    len2 = strlen(sp2->set_desc) ;
  519.    desc = (char *)malloc(len1 + len2 + 10) ;
  520.    if (desc == NULL) {
  521.       fatal("No memory for set description in SetIntersect") ;
  522.    }
  523.    new_set->set_desc = desc ;
  524.    strcpy(desc,"(") ;
  525.    ++desc ;
  526.    strcpy(desc, sp1->set_desc) ;
  527.    desc += len1 ;
  528.    strcpy(desc, ") AND (") ;
  529.    desc += 7 ;
  530.    strcpy(desc, sp2->set_desc) ;
  531.    desc += len2 ;
  532.    strcpy(desc, ")") ;
  533.    AddSet(new_set) ;
  534.    new_set->set_size = new_size ;
  535.    for (i = 0; i < new_size; ++i) {
  536.       new_set->set_data[i] = 
  537.          ((i < sp1->set_size) ? sp1->set_data[i] : sp1->set_tail) & 
  538.          ((i < sp2->set_size) ? sp2->set_data[i] : sp2->set_tail) ;
  539.    }
  540.    new_set->set_tail = sp1->set_tail & sp2->set_tail ;
  541.    return(new_set) ;
  542. }
  543.  
  544. /* SetUnion - construct a new set from the union of two others.
  545.  * Also construct a new description string.
  546.  */
  547. set_type *
  548. SetUnion(sp1, sp2)
  549.    set_type * sp1 ;
  550.    set_type * sp2 ;
  551. {
  552.    char *     desc ;
  553.    int        i ;
  554.    int        len1 ;
  555.    int        len2 ;
  556.    set_type * new_set ;
  557.    int        new_size ;
  558.    
  559.    new_size = MAX(sp1->set_size, sp2->set_size) ;
  560.    new_set = (set_type *)malloc(sizeof(set_type) +
  561.                                 (new_size - 1) * sizeof(unsigned long)) ;
  562.    if (new_set == NULL) {
  563.       fatal("No memory for set in SetUnion") ;
  564.    }
  565.    len1 = strlen(sp1->set_desc) ;
  566.    len2 = strlen(sp2->set_desc) ;
  567.    desc = (char *)malloc(len1 + len2 + 9) ;
  568.    if (desc == NULL) {
  569.       fatal("No memory for set description in SetUnion") ;
  570.    }
  571.    new_set->set_desc = desc ;
  572.    strcpy(desc,"(") ;
  573.    ++desc ;
  574.    strcpy(desc, sp1->set_desc) ;
  575.    desc += len1 ;
  576.    strcpy(desc, ") OR (") ;
  577.    desc += 6 ;
  578.    strcpy(desc, sp2->set_desc) ;
  579.    desc += len2 ;
  580.    strcpy(desc, ")") ;
  581.    AddSet(new_set) ;
  582.    new_set->set_size = new_size ;
  583.    for (i = 0; i < new_size; ++i) {
  584.       new_set->set_data[i] =
  585.          ((i < sp1->set_size) ? (sp1->set_data[i]) : sp1->set_tail) |
  586.          ((i < sp2->set_size) ? (sp2->set_data[i]) : sp2->set_tail) ;
  587.    }
  588.    new_set->set_tail = sp1->set_tail | sp2->set_tail ;
  589.    return(new_set) ;
  590. }
  591.  
  592. /* SetInverse - construct a new set from the inverse of another.
  593.  * Also construct a new description string.
  594.  *
  595.  * This is kind of tricky. An inverse set in iid may grow during
  596.  * the course of a session. By NOTing the set_tail extension the
  597.  * inverse at any given time will be defined as the inverse against
  598.  * a universe that grows as additional queries are made and new files
  599.  * are added to the database.
  600.  *
  601.  * Several alternative definitions were possible (snapshot the
  602.  * universe at the time of the NOT, go read the ID file to
  603.  * determine the complete universe), but this one was the one
  604.  * I picked.
  605.  */
  606. set_type *
  607. SetInverse(sp)
  608.    set_type * sp ;
  609. {
  610.    char *     desc ;
  611.    int        i ;
  612.    set_type * new_set ;
  613.    
  614.    new_set = (set_type *)malloc(sizeof(set_type) +
  615.                                 (sp->set_size - 1) * sizeof(unsigned long)) ;
  616.    if (new_set == NULL) {
  617.       fatal("No memory for set in SetInverse") ;
  618.    }
  619.    desc = (char *)malloc(strlen(sp->set_desc) + 5) ;
  620.    if (desc == NULL) {
  621.       fatal("No memory for set description in SetInverse") ;
  622.    }
  623.    new_set->set_desc = desc ;
  624.    strcpy(desc,"NOT ") ;
  625.    desc += 4 ;
  626.    strcpy(desc, sp->set_desc) ;
  627.    AddSet(new_set) ;
  628.    new_set->set_size = sp->set_size ;
  629.    for (i = 0; i < sp->set_size; ++i) {
  630.       new_set->set_data[i] = ~ sp->set_data[i] ;
  631.    }
  632.    new_set->set_tail = ~ sp->set_tail ;
  633.    return(new_set) ;
  634. }
  635.  
  636. /* RunShell - run a program with arguments from id_list.
  637.  */
  638. void
  639. RunShell(pp, idlp)
  640.    char *         pp ;
  641.    id_list_type * idlp ;
  642. {
  643.    char *         cmd = (char *)alloca(ArgListSize(idlp) + strlen(pp) + 2);
  644.    id_type *      idep ;
  645.    id_type *      next_id ;
  646.    
  647.    strcpy(cmd, pp) ;
  648.    idep = idlp->id_list ;
  649.    while (idep != NULL) {
  650.       strcat(cmd, " ") ;
  651.       strcat(cmd, idep->id) ;
  652.       next_id = idep->next_id ;
  653.       free(idep) ;
  654.       idep = next_id ;
  655.    }
  656.    free(idlp) ;
  657.    system(cmd) ;
  658. }
  659.