[alt.sources] mkid 09/11

tom@ssd.csd.harris.com (Tom Horsley) (12/12/90)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 9 (of 11)."
# Contents:  iidfun.c
# Wrapped by tom@hcx2 on Wed Dec 12 07:21:58 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'iidfun.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'iidfun.c'\"
else
echo shar: Extracting \"'iidfun.c'\" \(16553 characters\)
sed "s/^X//" >'iidfun.c' <<'END_OF_FILE'
X/* iidfun.c - This file holds the utility functions called from iid.y
X */
X
X#include "iiddef.h"
X
X/* ArgListSize - count the size of an arg list so can alloca() enough
X * space for the command.
X */
Xint
XArgListSize(idlp)
X   id_list_type * idlp ;
X{
X   id_type *      idep ;
X   int            size = 0;
X   
X   idep = idlp->id_list ;
X   while (idep != NULL) {
X      size += 1 + strlen(idep->id);
X      idep = idep->next_id;
X   }
X   return size;
X}
X
X/* SetListSize - count the size of a string build up from a set so we can
X * alloca() enough space for args.
X */
Xint
XSetListSize(sp)
X   set_type * sp ;
X{
X   int            i ;
X   int            size = 0 ;
X   
X   for (i = 0; i < NextFileNum; ++i) {
X      if (FileList[i]->mask_word < sp->set_size) {
X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
X            size += 1 + strlen(FileList[i]->name);
X         }
X      }
X   }
X   return size;
X}
X
X/* FlushFiles - clear out the TheFiles array for the start of a new
X * query.
X */
Xvoid
XFlushFiles()
X{
X   int             i ;
X   
X   if (TheFiles != NULL) {
X      for (i = 0; i <= MaxCurFile; ++i) {
X         TheFiles[i] = 0 ;
X      }
X   }
X   MaxCurFile = 0 ;
X}
X
X/* fatal - sometimes the only thing to do is die...
X */
Xvoid
Xfatal(s)
X{
X   fprintf(stderr,"Fatal error: %s\n",s) ;
X   exit(1) ;
X}
X
X/* CountBits - count the number of bits in a bit set. Actually fairly
X * tricky since it needs to deal with sets having infinite tails
X * as a result of a NOT operation.
X */
Xint
XCountBits(sp)
X   set_type * sp ;
X{
X   unsigned long      bit_mask ;
X   int                count = 0 ;
X   int                i ;
X   
X   i = 0;
X   for ( ; ; ) {
X      for (bit_mask = high_bit; bit_mask != 0; bit_mask >>= 1) {
X         if (bit_mask == NextMaskBit && i == NextMaskWord) {
X            return(count) ;
X         }
X         if (i < sp->set_size) {
X            if (sp->set_data[i] & bit_mask) {
X               ++count ;
X            }
X         } else {
X            if (sp->set_tail == 0) return count;
X            if (sp->set_tail & bit_mask) {
X               ++count;
X            }
X         }
X      }
X      ++i;
X   }
X}
X
X/* OneDescription - Print a description of a set. This includes
X * the set number, the number of files in the set, and the
X * set description string.
X */
Xvoid
XOneDescription(sp)
X   set_type * sp ;
X{
X   int        elt_count ;
X   char       setnum[20] ;
X   
X   sprintf(setnum,"S%d",sp->set_num) ;
X   elt_count = CountBits(sp) ;
X   printf("%5s %6d  %s\n",setnum,elt_count,sp->set_desc) ;
X}
X
X/* DescribeSets - Print description of all the sets.
X */
Xvoid
XDescribeSets()
X{
X   int            i ;
X
X   if (NextSetNum > 0) {
X      for (i = 0; i < NextSetNum; ++i) {
X         OneDescription(TheSets[i]) ;
X      }
X   } else {
X      printf("No sets defined yet.\n") ;
X   }
X}
X
X/* SetList - Go through the bit set and add the file names in
X * it to an identifier list.
X */
Xid_list_type *
XSetList(idlp, sp)
X   id_list_type *  idlp ;
X   set_type *      sp ;
X{
X   int        i ;
X   id_type *  idep ;
X   
X   for (i = 0; i < NextFileNum; ++i) {
X      if (FileList[i]->mask_word < sp->set_size) {
X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
X            idep = (id_type *)malloc(sizeof(id_type) +
X                                     strlen(FileList[i]->name)) ;
X            if (idep == NULL) {
X               fatal("Out of memory in SetList") ;
X            }
X            idep->next_id = NULL ;
X            strcpy(idep->id, FileList[i]->name) ;
X            idlp = ExtendList(idlp, idep) ;
X         }
X      }
X   }
X   return(idlp) ;
X}
X
X/* PrintSet - Go through the bit set and print the file names
X * corresponding to all the set bits.
X */
Xvoid
XPrintSet(sp)
X   set_type * sp ;
X{
X   int        i ;
X   
X   for (i = 0; i < NextFileNum; ++i) {
X      if (FileList[i]->mask_word < sp->set_size) {
X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
X            printf("%s\n",FileList[i]->name) ;
X         }
X      }
X   }
X}
X
X/* Free up all space used by current set of sets and reset all
X * set numbers.
X */
Xvoid
XFlushSets()
X{
X   int         i ;
X   
X   for (i = 0; i < NextSetNum; ++i) {
X      free(TheSets[i]->set_desc) ;
X      free(TheSets[i]) ;
X   }
X   NextSetNum = 0 ;
X}
X
X/* InitList - create an empty identifier list.
X */
Xid_list_type *
XInitList()
X{
X   id_list_type *   idlp ;
X   
X   idlp = (id_list_type *)malloc(sizeof(id_list_type)) ;
X   if (idlp == NULL) {
X      fatal("Out of memory in InitList") ;
X   }
X   idlp->id_count = 0 ;
X   idlp->end_ptr_ptr = & (idlp->id_list) ;
X   idlp->id_list = NULL ;
X   return(idlp) ;
X}
X
X/* ExtendList - add one identifier to an ID list.
X */
Xid_list_type *
XExtendList(idlp, idp)
X   id_list_type * idlp ;
X   id_type *      idp ;
X{
X   *(idlp->end_ptr_ptr) = idp ;
X   idlp->end_ptr_ptr = &(idp->next_id) ;
X   return(idlp) ;
X}
X
X/* InitIid - do all initial processing for iid.
X *   1) Determine the size of a unsigned long for bit set stuff.
X *   2) Find out the name of the pager program to use.
X *   3) Create the HelpSet (pointing to the help file).
X *   4) Setup the prompt.
X */
Xvoid
XInitIid()
X{
X   unsigned long      bit_mask = 1 ;   /* find number of bits in long */
X   int                i ;
X   char *             page ;           /* pager program */
X   
X   do {
X      high_bit = bit_mask ;
X      bit_mask <<= 1 ;
X   } while (bit_mask != 0) ;
X   
X   NextMaskBit = high_bit ;
X   
X   page = getenv("PAGER") ;
X   if (page == NULL) {
X      page = PAGER ;
X   }
X   strcpy(Pager, page) ;
X   
X   FlushFiles() ;
X   InstallFile(HELPFILE) ;
X   HelpSet = (set_type *)
X      malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
X   if (HelpSet == NULL) {
X      fatal("No memory for set in InitIid") ;
X   }
X   HelpSet->set_tail = 0 ;
X   HelpSet->set_desc = NULL ;
X   HelpSet->set_size = MaxCurFile + 1 ;
X   for (i = 0; i <= MaxCurFile; ++i) {
X      HelpSet->set_data[i] = TheFiles[i] ;
X   }
X   
X   page = getenv("PS1") ;
X   if (page == NULL) {
X      page = PROMPT ;
X   }
X   strcpy(Prompt, page) ;
X}
X
X/* InstallFile - install a file name in the symtab. Return the
X * symbol table pointer of the file.
X */
Xsymtab_type *
XInstallFile(fp)
X   char *      fp ;
X{
X   char             c ;
X   unsigned long    hash_code ;
X   int              i ;
X   char *           sp ;
X   symtab_type *    symp ;
X   
X   hash_code = 0 ;
X   sp = fp ;
X   while ((c = *sp++) != '\0') {
X      hash_code <<= 1 ;
X      hash_code ^= (unsigned long)(c) ;
X      if (hash_code & high_bit) {
X         hash_code &= ~ high_bit ;
X         hash_code ^= 1 ;
X      }
X   }
X   hash_code %= HASH_SIZE ;
X   symp = HashTable[hash_code] ;
X   while (symp != NULL && strcmp(symp->name, fp)) {
X      symp = symp->hash_link ;
X   }
X   if (symp == NULL) {
X      symp = (symtab_type *)malloc(sizeof(symtab_type) + strlen(fp)) ;
X      if (symp == NULL) {
X         fatal("No memory for symbol table entry in InstallFile") ;
X      }
X      strcpy(symp->name, fp) ;
X      symp->hash_link = HashTable[hash_code] ;
X      HashTable[hash_code] = symp ;
X      if (NextMaskWord >= FileSpace) {
X         FileSpace += 1000 ;
X         if (TheFiles != NULL) {
X            TheFiles = (unsigned long *)
X               realloc(TheFiles, sizeof(unsigned long) * FileSpace) ;
X         } else {
X            TheFiles = (unsigned long *)
X               malloc(sizeof(unsigned long) * FileSpace) ;
X         }
X         if (TheFiles == NULL) {
X            fatal("No memory for TheFiles in InstallFile") ;
X         }
X         for (i = NextMaskWord; i < FileSpace; ++i) {
X            TheFiles[i] = 0 ;
X         }
X      }
X      symp->mask_word = NextMaskWord ;
X      symp->mask_bit = NextMaskBit ;
X      NextMaskBit >>= 1 ;
X      if (NextMaskBit == 0) {
X         NextMaskBit = high_bit ;
X         ++NextMaskWord ;
X      }
X      if (NextFileNum >= ListSpace) {
X         ListSpace += 1000 ;
X         if (FileList == NULL) {
X            FileList = (symtab_type **)
X               malloc(sizeof(symtab_type *) * ListSpace) ;
X         } else {
X            FileList = (symtab_type **)
X               realloc(FileList, ListSpace * sizeof(symtab_type *)) ;
X         }
X         if (FileList == NULL) {
X            fatal("No memory for FileList in InstallFile") ;
X         }
X      }
X      FileList[NextFileNum++] = symp ;
X      /* put code here to sort the file list by name someday */
X   }
X   TheFiles[symp->mask_word] |= symp->mask_bit ;
X   if (symp->mask_word > MaxCurFile) {
X      MaxCurFile = symp->mask_word ;
X   }
X   return(symp) ;
X}
X
X/* RunPager - run the users pager program on the list of files
X * in the set.
X */
Xvoid
XRunPager(pp, sp)
X   char *     pp ;
X   set_type * sp ;
X{
X   char *         cmd = (char *)alloca(SetListSize(sp) + strlen(pp) + 2);
X   int            i ;
X   id_type *      idep ;
X   
X   strcpy(cmd, pp) ;
X   for (i = 0; i < NextFileNum; ++i) {
X      if (FileList[i]->mask_word < sp->set_size) {
X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
X            strcat(cmd, " ") ;
X            strcat(cmd, FileList[i]->name) ;
X         }
X      }
X   }
X   system(cmd) ;
X}
X
X/* AddSet - add a new set to the universal list of sets. Assign
X * it the next set number.
X */
Xvoid
XAddSet(sp)
X   set_type *   sp ;
X{
X   if (NextSetNum >= SetSpace) {
X      SetSpace += 1000 ;
X      if (TheSets != NULL) {
X         TheSets = (set_type **)
X            realloc(TheSets, sizeof(set_type *) * SetSpace) ;
X      } else {
X         TheSets = (set_type **)
X            malloc(sizeof(set_type *) * SetSpace) ;
X      }
X      if (TheSets == NULL) {
X         fatal("No memory for TheSets in AddSet") ;
X      }
X   }
X   sp->set_num = NextSetNum ;
X   TheSets[NextSetNum++] = sp ;
X}
X
X/* RunProg - run a program with arguments from id_list and
X * accept list of file names back from the program which
X * are installed in the symbol table and used to construct
X * a new set.
X */
Xset_type *
XRunProg(pp, idlp)
X   char *         pp ;
X   id_list_type * idlp ;
X{
X   int            c ;
X   char *         cmd = (char *)alloca(ArgListSize(idlp) + strlen(pp) + 2);
X   char *         dp ;
X   char           file [ MAXCMD ] ;
X   int            i ;
X   id_type *      idep ;
X   id_type *      next_id ;
X   FILE *         prog ;
X   set_type *     sp ;
X   
X   FlushFiles() ;
X   strcpy(cmd, pp) ;
X   idep = idlp->id_list ;
X   while (idep != NULL) {
X      strcat(cmd, " ") ;
X      strcat(cmd, idep->id) ;
X      next_id = idep->next_id ;
X      free(idep) ;
X      idep = next_id ;
X   }
X   free(idlp) ;
X   
X   /* run program with popen, reading the output. Assume each
X    * white space terminated string is a file name.
X    */
X   prog = popen(cmd, "r") ;
X   dp = file ;
X   while ((c = getc(prog)) != EOF) {
X      if (isspace(c)) {
X         if (dp != file) {
X            *dp++ = '\0' ;
X            InstallFile(file) ;
X            dp = file ;
X         }
X      } else {
X         *dp++ = c ;
X      }
X   }
X   if (dp != file) {
X      *dp++ = '\0' ;
X      InstallFile(file) ;
X   }
X   if (pclose(prog) != 0) {
X      /* if there was an error make an empty set, who knows what
X       * garbage the program printed.
X       */
X      FlushFiles() ;
X   }
X   
X   sp = (set_type *)
X      malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
X   if (sp == NULL) {
X      fatal("No memory for set in RunProg") ;
X   }
X   sp->set_tail = 0 ;
X   sp->set_desc = (char *)malloc(strlen(cmd) + 1) ;
X   if (sp->set_desc == NULL) {
X      fatal("No memory for set description in RunProg") ;
X   }
X   strcpy(sp->set_desc, cmd) ;
X   sp->set_size = MaxCurFile + 1 ;
X   for (i = 0; i <= MaxCurFile; ++i) {
X      sp->set_data[i] = TheFiles[i] ;
X   }
X   AddSet(sp) ;
X   return(sp) ;
X}
X
X/* SetDirectory - change the working directory. This will
X * determine which ID file is found by the subprograms.
X */
Xvoid
XSetDirectory(dir)
X   id_type *      dir ;
X{
X   if (chdir(dir->id) != 0) {
X      fprintf(stderr,"Directory %s not accessible.\n",dir) ;
X   }
X   free(dir) ;
X}
X
X/* SetIntersect - construct a new set from the intersection
X * of two others. Also construct a new description string.
X */
Xset_type *
XSetIntersect(sp1, sp2)
X   set_type * sp1 ;
X   set_type * sp2 ;
X{
X   char *     desc ;
X   int        i ;
X   int        len1 ;
X   int        len2 ;
X   set_type * new_set ;
X   int        new_size ;
X   
X   if (sp1->set_tail || sp2->set_tail) {
X      new_size = MAX(sp1->set_size, sp2->set_size) ;
X   } else {
X      new_size = MIN(sp1->set_size, sp2->set_size) ;
X   }
X   new_set = (set_type *)malloc(sizeof(set_type) +
X                                (new_size - 1) * sizeof(unsigned long)) ;
X   if (new_set == NULL) {
X      fatal("No memory for set in SetIntersect") ;
X   }
X   len1 = strlen(sp1->set_desc) ;
X   len2 = strlen(sp2->set_desc) ;
X   desc = (char *)malloc(len1 + len2 + 10) ;
X   if (desc == NULL) {
X      fatal("No memory for set description in SetIntersect") ;
X   }
X   new_set->set_desc = desc ;
X   strcpy(desc,"(") ;
X   ++desc ;
X   strcpy(desc, sp1->set_desc) ;
X   desc += len1 ;
X   strcpy(desc, ") AND (") ;
X   desc += 7 ;
X   strcpy(desc, sp2->set_desc) ;
X   desc += len2 ;
X   strcpy(desc, ")") ;
X   AddSet(new_set) ;
X   new_set->set_size = new_size ;
X   for (i = 0; i < new_size; ++i) {
X      new_set->set_data[i] = 
X         ((i < sp1->set_size) ? sp1->set_data[i] : sp1->set_tail) & 
X         ((i < sp2->set_size) ? sp2->set_data[i] : sp2->set_tail) ;
X   }
X   new_set->set_tail = sp1->set_tail & sp2->set_tail ;
X   return(new_set) ;
X}
X
X/* SetUnion - construct a new set from the union of two others.
X * Also construct a new description string.
X */
Xset_type *
XSetUnion(sp1, sp2)
X   set_type * sp1 ;
X   set_type * sp2 ;
X{
X   char *     desc ;
X   int        i ;
X   int        len1 ;
X   int        len2 ;
X   set_type * new_set ;
X   int        new_size ;
X   
X   new_size = MAX(sp1->set_size, sp2->set_size) ;
X   new_set = (set_type *)malloc(sizeof(set_type) +
X                                (new_size - 1) * sizeof(unsigned long)) ;
X   if (new_set == NULL) {
X      fatal("No memory for set in SetUnion") ;
X   }
X   len1 = strlen(sp1->set_desc) ;
X   len2 = strlen(sp2->set_desc) ;
X   desc = (char *)malloc(len1 + len2 + 9) ;
X   if (desc == NULL) {
X      fatal("No memory for set description in SetUnion") ;
X   }
X   new_set->set_desc = desc ;
X   strcpy(desc,"(") ;
X   ++desc ;
X   strcpy(desc, sp1->set_desc) ;
X   desc += len1 ;
X   strcpy(desc, ") OR (") ;
X   desc += 6 ;
X   strcpy(desc, sp2->set_desc) ;
X   desc += len2 ;
X   strcpy(desc, ")") ;
X   AddSet(new_set) ;
X   new_set->set_size = new_size ;
X   for (i = 0; i < new_size; ++i) {
X      new_set->set_data[i] =
X         ((i < sp1->set_size) ? (sp1->set_data[i]) : sp1->set_tail) |
X         ((i < sp2->set_size) ? (sp2->set_data[i]) : sp2->set_tail) ;
X   }
X   new_set->set_tail = sp1->set_tail | sp2->set_tail ;
X   return(new_set) ;
X}
X
X/* SetInverse - construct a new set from the inverse of another.
X * Also construct a new description string.
X *
X * This is kind of tricky. An inverse set in iid may grow during
X * the course of a session. By NOTing the set_tail extension the
X * inverse at any given time will be defined as the inverse against
X * a universe that grows as additional queries are made and new files
X * are added to the database.
X *
X * Several alternative definitions were possible (snapshot the
X * universe at the time of the NOT, go read the ID file to
X * determine the complete universe), but this one was the one
X * I picked.
X */
Xset_type *
XSetInverse(sp)
X   set_type * sp ;
X{
X   char *     desc ;
X   int        i ;
X   set_type * new_set ;
X   
X   new_set = (set_type *)malloc(sizeof(set_type) +
X                                (sp->set_size - 1) * sizeof(unsigned long)) ;
X   if (new_set == NULL) {
X      fatal("No memory for set in SetInverse") ;
X   }
X   desc = (char *)malloc(strlen(sp->set_desc) + 5) ;
X   if (desc == NULL) {
X      fatal("No memory for set description in SetInverse") ;
X   }
X   new_set->set_desc = desc ;
X   strcpy(desc,"NOT ") ;
X   desc += 4 ;
X   strcpy(desc, sp->set_desc) ;
X   AddSet(new_set) ;
X   new_set->set_size = sp->set_size ;
X   for (i = 0; i < sp->set_size; ++i) {
X      new_set->set_data[i] = ~ sp->set_data[i] ;
X   }
X   new_set->set_tail = ~ sp->set_tail ;
X   return(new_set) ;
X}
X
X/* RunShell - run a program with arguments from id_list.
X */
Xvoid
XRunShell(pp, idlp)
X   char *         pp ;
X   id_list_type * idlp ;
X{
X   char *         cmd = (char *)alloca(ArgListSize(idlp) + strlen(pp) + 2);
X   id_type *      idep ;
X   id_type *      next_id ;
X   
X   strcpy(cmd, pp) ;
X   idep = idlp->id_list ;
X   while (idep != NULL) {
X      strcat(cmd, " ") ;
X      strcat(cmd, idep->id) ;
X      next_id = idep->next_id ;
X      free(idep) ;
X      idep = next_id ;
X   }
X   free(idlp) ;
X   system(cmd) ;
X}
END_OF_FILE
if test 16553 -ne `wc -c <'iidfun.c'`; then
    echo shar: \"'iidfun.c'\" unpacked with wrong size!
fi
# end of 'iidfun.c'
fi
echo shar: End of archive 9 \(of 11\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 11 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
--
======================================================================
domain: tahorsley@csd.harris.com       USMail: Tom Horsley
  uucp: ...!uunet!hcx1!tahorsley               511 Kingbird Circle
                                               Delray Beach, FL  33444
+==== Censorship is the only form of Obscenity ======================+
|     (Wait, I forgot government tobacco subsidies...)               |
+====================================================================+