lib/snofmake.c

Go to the documentation of this file.
00001 /* snofmake - Write out an index file. 
00002  *
00003  * This file is copyright 2002 Jim Kent, but license is hereby
00004  * granted for all use - public, private or commercial. */
00005 
00006 #include "common.h"
00007 #include "localmem.h"
00008 #include "snofmake.h"
00009 #include "errabort.h"
00010 
00011 static char const rcsid[] = "$Id: snofmake.c,v 1.5 2003/05/06 07:33:44 kate Exp $";
00012 
00013 static jmp_buf errRecover;
00014 
00015 static void ourErrAbort()
00016 /* Default error handler. Prints message and exits
00017  * program. */
00018 {
00019 longjmp(errRecover, -1);
00020 }
00021 
00022 static struct lm *lm;
00023 
00024 static void initMem()
00025 {
00026 lm = lmInit((1<<16));
00027 }
00028 
00029 static void cleanupMem()
00030 {
00031 lmCleanup(&lm);
00032 }
00033 
00034 static void *localNeedMem(int size)
00035 {
00036 return lmAlloc(lm, size);
00037 }
00038 
00039 struct offsetList
00040     {
00041     struct offsetList *next;
00042     char *name;
00043     unsigned offset;
00044     };
00045 
00046 static struct offsetList *newOffset(char *name, int nameLen)
00047 /* Return a fresh name list entry. */
00048 {
00049 struct offsetList *nl = localNeedMem(sizeof(*nl));
00050 nl->name = localNeedMem(nameLen+1);
00051 memcpy(nl->name, name, nameLen);
00052 nl->name[nameLen] = 0;
00053 return nl;
00054 }
00055 
00056 static int cmpOffsetPointers(const void *va, const void *vb)
00057 /* comparison function for qsort on an array of offset pointers*/
00058 {
00059 struct offsetList **pa, **pb;
00060 struct offsetList *a, *b;
00061 pa = (struct offsetList **)va;
00062 pb = (struct offsetList **)vb;
00063 a = *pa;
00064 b = *pb;
00065 return strcmp(a->name, b->name);
00066 }
00067 
00068 static int longestNameSize(struct offsetList *list)
00069 {
00070 struct offsetList *el;
00071 int size, longestSize = 0;
00072 
00073 for (el = list; el != NULL; el = el->next)
00074     {
00075     size = strlen(el->name);
00076     if (size > longestSize) 
00077         {
00078         longestSize = size;
00079         }
00080     }
00081 return longestSize;
00082 }
00083 
00084 static struct offsetList *makeOffsetList(FILE *inFile, 
00085     boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), void *data)
00086 /* Build up a list of records and their offsets into file. */
00087 {
00088 struct offsetList *list = NULL;
00089 struct offsetList *newEl;
00090 for (;;)
00091     {
00092     long offset = ftell(inFile);
00093     char *name;
00094     int nameLen;
00095     if (!nextRecord(inFile, data, &name, &nameLen))
00096         break;
00097     if (nameLen > 0)
00098         {
00099         newEl = newOffset(name, nameLen);
00100         newEl->offset = offset;
00101         newEl->next = list;
00102         list = newEl;
00103         }
00104     }
00105 slReverse(&list);
00106 return list;
00107 }
00108 
00109 boolean warnAboutDupes(struct offsetList **array, int size)
00110 /* Since list is sorted it's easy to warn about duplications. */
00111 {
00112 char *name, *prevName;
00113 int i;
00114 boolean ok = TRUE;
00115 
00116 if (size < 2)
00117     return FALSE;
00118 prevName = array[0]->name;
00119 for (i=1; i<size; ++i)
00120     {
00121     name = array[i]->name;
00122     if (!differentWord(name, prevName))
00123         {
00124         warn("Duplicate strings: %s %s", prevName, name);
00125         ok = FALSE;
00126         }
00127     prevName = name;
00128     }
00129 return ok;
00130 }
00131 
00132 static void makeIndex(FILE *in, FILE *out, 
00133     boolean (*nextRecord)(FILE *in, void *data, char **rName, int *rNameLen), void *data,
00134     boolean dupeOk)
00135 /* Make index.  Throw error if there's a problem. */
00136 {
00137 struct offsetList *list;
00138 int listSize;
00139 struct offsetList **array;
00140 int i;
00141 struct offsetList *el;
00142 int nameSize;
00143 char *nameBuf;
00144 char *indexSig;
00145 int indexSigSize;
00146 
00147 printf("Reading input\n");
00148 list = makeOffsetList(in, nextRecord, data);
00149 listSize = slCount(list);
00150 array = localNeedMem(listSize * sizeof(*array));
00151 nameSize = longestNameSize(list)+1;
00152 
00153 printf("Got %d offsets %d nameSize.  Sorting...\n", listSize, nameSize);
00154 nameBuf = localNeedMem(nameSize);
00155 
00156 /* Make an array of pointers, one for each element in list. */
00157 for (i=0, el = list; i<listSize; i+=1, el = el->next)
00158     array[i] = el;
00159 
00160 /* Sort alphabetically based on name. */
00161 qsort(array, listSize, sizeof(array[0]), cmpOffsetPointers);
00162 if (!dupeOk)
00163     warnAboutDupes(array, listSize);
00164 
00165 /* Write out file header */
00166 printf("Writing index file \n");
00167 snofSignature(&indexSig, &indexSigSize);
00168 mustWrite(out, indexSig, indexSigSize);
00169 mustWrite(out, &nameSize, sizeof(nameSize));
00170     
00171 /* Write out sorted output */
00172 for (i=0; i<listSize; ++i)
00173     {
00174     zeroBytes(nameBuf, nameSize);
00175     strcpy(nameBuf, array[i]->name);
00176     mustWrite(out, nameBuf, nameSize);
00177     mustWrite(out, &array[i]->offset, sizeof(array[i]->offset));
00178     }
00179 }
00180 
00181 boolean snofDupeOkIndex(FILE *inFile, char *outName, 
00182     boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
00183     void *data, boolean dupeOk)
00184 /* Make an index file, as in snofMakeIndex, but optionally allow duplicates
00185  * without complaining. */
00186 {
00187 FILE *outFile;
00188 int status;
00189 
00190 /* Initialize */
00191 if ((outFile = fopen(outName, "wb")) == NULL)
00192     {
00193     fprintf(stderr, "Couldn't create index file %s\n", outName);
00194     return FALSE;
00195     }
00196 initMem();
00197 
00198 /* Wrap error recovery around main routine. */
00199 status = setjmp(errRecover);
00200 if (status == 0)
00201     {
00202     pushAbortHandler(ourErrAbort);
00203     makeIndex(inFile, outFile, nextRecord, data, dupeOk);
00204     }
00205 popAbortHandler();
00206 
00207 /* Cleanup. */
00208 fclose(outFile);
00209 cleanupMem();
00210 return status == 0;
00211 }
00212 
00213 boolean snofMakeIndex(FILE *inFile, char *outName, 
00214     boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
00215     void *data)
00216 /* Make an index file - name/offset pairs that are sorted by name.
00217  * Inputs:
00218  *     inFile - open file that you're indexing with header read and verified.
00219  *     outName - name of index file to create
00220  *     nextRecord - function that reads next record in file you're indexing
00221  *                  and returns the name of that record.
00222  *     data - void pointer passed through to nextRecord.
00223  *
00224  * In this implementation this function just is an error recovery wrapper
00225  * around the local function makeIndex, which does the real work. */
00226 {
00227 return snofDupeOkIndex(inFile, outName, nextRecord, data, FALSE);
00228 }
00229 

Generated on Tue Dec 25 18:39:31 2007 for blat by  doxygen 1.5.2