libutils.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006  SRI International
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00017  *
00018  * SRI International: 333 Ravenswood Ave, Menlo Park, CA 94025
00019  */
00020 
00021 #include <stdio.h>
00022 #include <string.h>
00023 //#include <malloc.h>
00024 
00025 #ifndef _WINDOWS
00026 #include <pwd.h>        /* used by expandFileName */
00027 #endif
00028 
00029 #include <stdarg.h>   /* Variable length argument lists */
00030 #include <stdlib.h>
00031 
00032 #include "libutils.h"
00033 #include "filetermreader.h"
00034 
00035 /****************************************************************************
00036  * Global variables and forward declarations
00037  ****************************************************************************/
00038 
00039 #define EXPORT_BORLAND
00040 
00041 #ifdef IS_DLL
00042 #define EXPORT_MSCPP __declspec(dllexport)
00043 #else
00044 #define EXPORT_MSCPP
00045 #endif
00046 
00047 /* Exported by liboaa */
00048 extern int oaa_argc;
00049 extern char** oaa_argv;
00050 #define SETUP_FILE_NAME "setup.pl"
00051 /* Each line in a setup file should be less than this length: */
00052 #define SETUP_FILE_BUFSIZ 1024
00053 
00054 char *expand_filename(char* nm, char* startDir);
00055 
00056 /****************************************************************************
00057  * name:    oaa_ResolveVariable
00058  * purpose:
00059  * remarks:
00060  * returns:
00061  ****************************************************************************/
00062 EXPORT_MSCPP
00063 int EXPORT_BORLAND
00064 oaa_ResolveVariable(char* inVarName, ICLTerm **resolvedVar){
00065   int i = 1;
00066   int found = FALSE;
00067 
00068   ICLTerm* varNameAsIclStruct;
00069   ICLTerm* varNameAsIclStr;
00070   ICLTerm* resultOfUnification = NULL;
00071   ICLTerm* var;
00072 
00073   var = icl_NewVar("_");
00074   varNameAsIclStruct = icl_NewStruct(inVarName, 1, var);
00075   if(varNameAsIclStruct == NULL) {
00076     icl_Free(var);
00077   }
00078   CHECK_LEAKS();
00079   varNameAsIclStr = icl_NewStr(inVarName);
00080   CHECK_LEAKS();
00081 
00082   /* First looks at the command line */
00083   while ((i<oaa_argc) && !found) {
00084     ICLTerm* currentParamAsTerm = icl_NewStr(oaa_argv[i]);
00085     CHECK_LEAKS();
00086 
00087     /* Looks at the term as a struct */
00088     if (currentParamAsTerm && icl_IsStruct(currentParamAsTerm)) {
00089       CHECK_LEAKS();
00090       if (icl_Unify(currentParamAsTerm, varNameAsIclStruct, &resultOfUnification)) {
00091         CHECK_LEAKS();
00092         if (resolvedVar) {
00093           *resolvedVar = icl_CopyTerm(icl_NthTerm(resultOfUnification, 1));
00094           CHECK_LEAKS();          
00095         }
00096         found = TRUE;
00097       }
00098       icl_Free(resultOfUnification);
00099       CHECK_LEAKS();
00100     }
00101 
00102     /* Looks at the term as an icl str */
00103     if (currentParamAsTerm && icl_IsStr(currentParamAsTerm)) {
00104       if (icl_Unify(currentParamAsTerm, varNameAsIclStr, &resultOfUnification)) {
00105         /* The -oaa parameter does not take any parameters */
00106         if (strcmp(oaa_argv[i],"-oaa")==0) {
00107           if (resolvedVar)
00108             *resolvedVar = icl_CopyTerm(icl_NthTerm(resultOfUnification, 1));
00109         }
00110         else{
00111           if (resolvedVar)
00112             *resolvedVar = icl_NewTermFromString(oaa_argv[++i]);
00113         }
00114         found = TRUE;
00115       }
00116       icl_Free(resultOfUnification);
00117     }
00118 
00119     icl_Free(currentParamAsTerm);
00120     i++;
00121   }
00122 
00123   /*
00124      If not found within the arguments, looks in the setup.pl file.
00125      First in the current directory, then in the user's root directory
00126      on UNIX (LINUX) systems, or in c:\ on Windows based machines.
00127   */
00128 
00129   if (!found) {
00130     FILE *setup_file;
00131     char buf[SETUP_FILE_BUFSIZ];
00132 #ifndef _WINDOWS /* --------------------------------------------------------- */
00133     char *filename;
00134     strcpy(buf, "./");
00135     strcat(buf, SETUP_FILE_NAME);
00136 #else /* ----------------------------------------------------------------- */
00137     strcpy(buf, SETUP_FILE_NAME);
00138 #endif  /* ---------------------------------------------------------------- */
00139     if ((setup_file = fopen(buf, "r")) == NULL) {
00140 #ifdef _WINDOWS  /* ----------------------------------------------------- */
00141       strcpy(buf,"C:\\");
00142       strcat(buf, SETUP_FILE_NAME);
00143 #else  /* ---------------------------------------------------------------- */
00144       strcpy(buf, "~/");
00145       strcat(buf, SETUP_FILE_NAME);
00146       filename = expand_filename(buf, NULL);
00147       strncpy(buf, filename, 512);
00148       icl_stFree(filename);
00149 #endif  /* ---------------------------------------------------------------- */
00150       setup_file = fopen(buf, "r");
00151     }
00152 
00153     
00154 
00155     // One remaining issue with this is that comments aren't handled correctly;
00156     // don't use percent characters except for comments.
00157     if (setup_file != NULL) {
00158       TermReader* tr = termReader_create();
00159       void* filterState = filterPercent_createState();
00160       ICLTerm* currentTerm;
00161       (void)fileTermReader_createWithFilter(tr, setup_file, filterPercent_filter, filterState);
00162       for(currentTerm = termReader_getNextTerm(tr, 0); currentTerm != NULL; currentTerm = termReader_getNextTerm(tr, 0)) {
00163         if(icl_Unify(currentTerm, varNameAsIclStruct, &resultOfUnification)) {
00164           *resolvedVar = icl_CopyTerm(icl_NthTerm(resultOfUnification, 1));
00165           icl_Free(resultOfUnification);
00166           icl_Free(currentTerm);
00167           break;
00168         }
00169         icl_Free(currentTerm);
00170       }
00171       
00172       free(filterState);
00173       termReader_free(tr);
00174       fclose(setup_file);
00175     }
00176     else {
00177       printf("no setup.pl file\n");
00178     }
00179   }
00180 
00181   CHECK_LEAKS();
00182   icl_Free(varNameAsIclStruct);
00183   CHECK_LEAKS();
00184   icl_Free(varNameAsIclStr);
00185   CHECK_LEAKS();
00186 
00187   return found;
00188 }
00189 
00190 /****************************************************************************
00191  * name:    filename_as_directory
00192  * purpose: concatenate a slash onto a filename if necessary
00193  * inputs:
00194  *    - char  *in: file to work on
00195  *    - char *out: result
00196  * remarks:
00197  *    Internal static command
00198  ****************************************************************************/
00199 static char *
00200 filename_as_directory (out, in)
00201      char *out, *in;
00202 {
00203   int size = strlen (in) - 1;
00204 
00205   strcpy (out, in);
00206 
00207   /* For Unix syntax, Append a slash if necessary */
00208   if (out[size] != '/')
00209     strcat (out, "/");
00210   return out;
00211 }
00212 
00223 char *
00224 expand_filename(char* nm, char* startDir) {
00225 
00226   register char *newdir, *p, *o;
00227   int tlen;
00228   char *target;
00229   int lose;
00230 
00231 #ifndef _WINDOWS
00232   struct passwd *pw;
00233 #endif
00234 
00235   /* If nm is absolute, flush ...// and detect /./ and /../.
00236      If no /./ or /../ we can return right away. */
00237   if (nm[0] == '/') {
00238     p = nm;
00239     lose = 0;
00240     while (*p){
00241       if (p[0] == '/' && p[1] == '/')
00242   nm = p + 1;
00243       if (p[0] == '/' && p[1] == '~')
00244   nm = p + 1, lose = 1;
00245       if (p[0] == '/' && p[1] == '.'
00246     && (p[2] == '/' || p[2] == 0
00247         || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
00248   lose = 1;
00249       p++;
00250     }
00251     if (!lose) {
00252       printf("expand_filename !lose\n");
00253       return strdup (nm);
00254     }
00255   }
00256 
00257   /* Now determine directory to start with and put it in NEWDIR.  */
00258 
00259   newdir = 0;
00260 
00261 #ifndef _WINDOWS
00262   if (nm[0] == '~'){
00263     if (nm[1] == '/' || nm[1] == 0){
00264       /* Handle ~ on its own.  */
00265       newdir = getenv ("HOME");
00266     }
00267     else {
00268       /* Handle ~ followed by user name.  */
00269       char *user = nm + 1;
00270 
00271       /* Find end of name.  */
00272       char *ptr = strchr (user, '/');
00273       int len = ptr ? (int) (ptr - user) : (int) strlen (user);
00274 
00275       /* Copy the user name into temp storage.  */
00276       o = strdup(user);
00277       o[len] = 0;
00278 
00279       /* Look up the user name.  */
00280       pw = (struct passwd *) getpwnam (o);
00281       if (!pw) {
00282   printf("User \"%s\" is not known", o);
00283       }
00284 
00285       newdir = pw->pw_dir;
00286 
00287       /* Discard the user name from NM.  */
00288       nm += len;
00289     }
00290 
00291     /* Discard the ~ from NM.  */
00292     nm++;
00293 
00294     if (newdir == 0) {
00295       newdir = "";
00296     }
00297   }
00298 #endif
00299 
00300   if (nm[0] != '/' && !newdir){
00301     if (startDir[0] == 0)
00302       newdir = getenv("PWD");
00303     else
00304       newdir = startDir;
00305   }
00306 
00307   if (newdir != 0){
00308     /* Get rid of any slash at the end of newdir.  */
00309     int length = strlen (newdir);
00310     if (length > 1 && newdir[length - 1] == '/'){
00311       char *temp = strdup(newdir);
00312       temp[length - 1] = 0;
00313       newdir = temp;
00314     }
00315     tlen = length + 1;
00316   }
00317   else {
00318     tlen = 0;
00319   }
00320 
00321   /* Now concatenate the directory and name to new space in the stack frame */
00322 
00323   tlen += strlen (nm) + 1;
00324   target = (char *) malloc (tlen);
00325   *target = 0;
00326 
00327   if (newdir){
00328     if (nm[0] == 0 || nm[0] == '/') {
00329       strcpy (target, newdir);
00330     }
00331     else {
00332       filename_as_directory (target, newdir);
00333     }
00334   }
00335 
00336   strcat (target, nm);
00337 
00338   /* Now canonicalize by removing /. and /foo/.. if they appear */
00339   /* This could be done by using realpath(), but realpath only  */
00340   /* works if the file actually exists.        */
00341 
00342   p = target;
00343   o = target;
00344 
00345   while (*p){
00346     if (*p != '/'){
00347       *o++ = *p++;
00348     }
00349     else
00350       if (!strncmp (p, "//", 2)){
00351         o = target;
00352         p++;
00353       }
00354       else
00355         if (p[0] == '/' && p[1] == '.' &&
00356             (p[2] == '/' || p[2] == 0)){
00357           if (o == target && p[2] == '\0') {
00358             *o++ = *p;
00359           }
00360           p += 2;
00361         }
00362         else if (!strncmp (p, "/..", 3)
00363                  && o != target
00364                  && (p[3] == '/' || p[3] == 0)){
00365           while (o != target && *--o != '/');
00366           if (o == target && *o == '/') {
00367             ++o;
00368           }
00369           p += 3;
00370         }
00371         else {
00372           *o++ = *p++;
00373         }
00374   }
00375   target[o-target] = 0;
00376   return (char *)target;
00377 }
00378 
00382 EXTERN void printDebug(int level, char *str, ...) {
00383   if (level < DEBUG_LEVEL) {
00384     char buf[512];
00385     va_list ptr;
00386     va_start(ptr,str);
00387     vsprintf(buf,str,ptr);
00388     printf("DEBUG : %s\n",  buf);
00389     va_end(ptr);
00390   }
00391 }
00392 
00396 EXTERN void printWarning(int level, char *str, ...) {
00397   if (level < DEBUG_LEVEL) {
00398     char buf[512];
00399     va_list ptr;
00400     va_start(ptr,str);
00401     vsprintf(buf,str,ptr);
00402     printf("WARNING : %s\n",  buf);
00403     va_end(ptr);
00404   }
00405 }
00406 
00410 void print_dictionary(DICTIONARY *d) {
00411   int i, n;
00412 
00413   printf("Print dictionary of size %d\n", d->size);
00414   for(i=0, n=d->size; i<n; i++)
00415     printf("Key %s Value : %s\n",
00416            icl_NewStringFromTerm((ICLTerm*)d->key[i]),
00417            icl_NewStringFromTerm((ICLTerm*)d->value[i]));
00418 }
00419 
00426 hthash_table *htconstruct_table(hthash_table *table, size_t size)
00427 {
00428   size_t i;
00429   htbucket **temp;
00430 
00431   table -> size  = size;
00432   table -> table = (htbucket * *)malloc(sizeof(htbucket *) * size);
00433   temp = table -> table;
00434 
00435   if ( temp == NULL )
00436   {
00437     table -> size = 0;
00438     return table;
00439   }
00440 
00441   for (i=0;i<size;i++)
00442     temp[i] = NULL;
00443   return table;
00444 }
00445 
00446 
00447 /*
00448  * Hashes a string to produce an unsigned short, which should be
00449  * sufficient for most purposes.
00450  */
00451 static unsigned hthash(char *string)
00452 {
00453   unsigned ret_val = 0;
00454   int i;
00455 
00456   while (*string)
00457   {
00458     i = (int)(*string);
00459     ret_val ^= i;
00460     ret_val <<= 1;
00461     string ++;
00462   }
00463   return ret_val;
00464 }
00465 
00471 void *htinsert(char *key, void *data, hthash_table *table)
00472 {
00473   unsigned val = hthash(key) % table->size;
00474   htbucket *ptr;
00475 
00476   /*
00477    * NULL means this bucket hasn't been used yet.  We'll simply
00478    * allocate space for our new bucket and put our data there, with
00479    * the table pointing at it.
00480    */
00481 
00482   if (NULL == (table->table)[val])
00483   {
00484     (table->table)[val] = (htbucket *)malloc(sizeof(htbucket));
00485     if (NULL==(table->table)[val])
00486       return NULL;
00487 
00488     (table->table)[val] -> key = strdup(key);
00489     (table->table)[val] -> next = NULL;
00490     (table->table)[val] -> data = data;
00491     return (table->table)[val] -> data;
00492   }
00493 
00494   /*
00495    * This spot in the table is already in use.  See if the current string
00496    * has already been inserted, and if so, increment its count.
00497    */
00498 
00499   for (ptr = (table->table)[val];NULL != ptr; ptr = ptr -> next)
00500     if (0 == strcmp(key, ptr->key))
00501     {
00502       void *old_data;
00503 
00504       old_data = ptr->data;
00505       ptr -> data = data;
00506       return old_data;
00507     }
00508 
00509   /*
00510    * This key must not be in the table yet.  We'll add it to the head of
00511    * the list at this spot in the hash table.  Speed would be
00512    * slightly improved if the list was kept sorted instead.  In this case,
00513    * this code would be moved into the loop above, and the insertion would
00514    * take place as soon as it was determined that the present key in the
00515    * list was larger than this one.
00516    */
00517 
00518   ptr = (htbucket *)malloc(sizeof(htbucket));
00519   if (NULL==ptr)
00520     return 0;
00521   ptr -> key = strdup(key);
00522   ptr -> data = data;
00523   ptr -> next = (table->table)[val];
00524   (table->table)[val] = ptr;
00525   return data;
00526 }
00527 
00528 
00533 void *htlookup(char *key, hthash_table *table)
00534 {
00535   unsigned val = hthash(key) % table->size;
00536   htbucket *ptr;
00537 
00538   if (NULL == (table->table)[val])
00539     return NULL;
00540 
00541   for ( ptr = (table->table)[val];NULL != ptr; ptr = ptr->next )
00542   {
00543     if (0 == strcmp(key, ptr -> key ) ) {
00544       return ptr->data;
00545     }
00546   }
00547   return NULL;
00548 }
00549 
00554 void *htdel(char *key, hthash_table *table)
00555 {
00556   unsigned val = hthash(key) % table->size;
00557   void *data;
00558   htbucket *ptr, *last = NULL;
00559 
00560   if (NULL == (table->table)[val])
00561     return NULL;
00562 
00563   /*
00564    * Traverse the list, keeping track of the previous node in the list.
00565    * When we find the node to delete, we set the previous node's next
00566    * pointer to point to the node after ourself instead.  We then delete
00567    * the key from the present node, and return a pointer to the data it
00568    * contains.
00569    */
00570 
00571   for (last = NULL, ptr = (table->table)[val];
00572        NULL != ptr;
00573        last = ptr, ptr = ptr->next)
00574   {
00575     if (0 == strcmp(key, ptr -> key))
00576     {
00577       if (last != NULL )
00578       {
00579   data = ptr -> data;
00580   last -> next = ptr -> next;
00581   free(ptr->key);
00582   free(ptr);
00583   return data;
00584       }
00585 
00586       /*
00587        * If 'last' still equals NULL, it means that we need to
00588        * delete the first node in the list. This simply consists
00589        * of putting our own 'next' pointer in the array holding
00590        * the head of the list.  We then dispose of the current
00591        * node as above.
00592        */
00593 
00594       else
00595       {
00596   data = ptr->data;
00597   (table->table)[val] = ptr->next;
00598   free(ptr->key);
00599   free(ptr);
00600   return data;
00601       }
00602     }
00603   }
00604 
00605   /*
00606    * If we get here, it means we didn't find the item in the table.
00607    * Signal this by returning NULL.
00608    */
00609 
00610   return NULL;
00611 }
00612 
00620 void htfree_node(char *key, void *data, void *otherData)
00621 {
00622   htfreeNodeData *oData;
00623   (void)data;
00624   oData = (htfreeNodeData *)otherData;
00625 
00626   if (oData->function) {
00627     void *toFree = htdel(key,oData->the_table);
00628     oData->function(toFree);
00629   }
00630   else {
00631     htdel(key,oData->the_table);
00632   }
00633 }
00634 
00642 void htfree_table(hthash_table *table, void (*func)(void *))
00643 {
00644   htfreeNodeData freeData;
00645   freeData.function = func;
00646   freeData.the_table = table;
00647   htenumerate( table, htfree_node, &freeData);
00648   free(table->table);
00649   table->table = NULL;
00650   table->size = 0;
00651 }
00652 
00657 void htenumerate( hthash_table *table, void (*func)(char *, void *, void *), void *otherData)
00658 {
00659   unsigned i;
00660   htbucket *temp;
00661 
00662   htbucket *nextPtr;
00663   for (i=0;i<table->size; i++)
00664   {
00665     if ((table->table)[i] != NULL)
00666     {
00667       nextPtr = (table->table)[i]->next;
00668       for (temp = (table->table)[i];
00669      NULL != temp;
00670      temp = nextPtr)
00671       {
00672   nextPtr = temp->next;
00673   func(temp -> key, temp->data, otherData);
00674       }
00675     }
00676   }
00677 }
00678 
00679 void printer(char *key, void *data, void *otherData)
00680 {
00681   (void)otherData;
00682   printf("Key = [%s], data = %s\n", key, (char *)data);
00683 }
00684 
00685 void htprint(hthash_table *table)
00686 {
00687   printf("Printing table\n");
00688   htenumerate(table, printer, NULL);
00689 }
00690 
00691 char* get64BitFormatWrapped(char* pre, char* post)
00692 {
00693   long int i = 0;
00694   char* middle = "";
00695   char* result;
00696   int len;
00697   if(!pre) {
00698     pre = "";
00699   }
00700   if(!post) {
00701     post = "";
00702   }
00703   if(sizeof(i) == 4) {
00704     middle = "%lld";
00705   }
00706   else if(sizeof(i) == 8) {
00707     middle = "%ld";
00708   }
00709   else if(sizeof(i) == 16) {
00710     middle = "%hd";
00711   }
00712 
00713 #ifdef _WINDOWS
00714   len = _snprintf(NULL, 0, "%s%s%s", pre, middle, post);
00715 #else
00716   len = snprintf(NULL, 0, "%s%s%s", pre, middle, post);
00717 #endif
00718   if(len < 0) {
00719     len = strlen(pre) + strlen(post) + strlen(middle);
00720   }
00721   result = (char*)malloc((len + 1) * sizeof(char));
00722 #ifdef _WINDOWS
00723   _snprintf(result, len, "%s%s%s", pre, middle, post);
00724 #else
00725   snprintf(result, len, "%s%s%s", pre, middle, post);
00726 #endif
00727 
00728   return result;
00729 }
00730 
00731 char* get64BitFormat()
00732 {
00733   long int i = 0;
00734   if(sizeof(i) == 4) {
00735     return "%lld";
00736   }
00737   else if(sizeof(i) == 8) {
00738     return "%d";
00739   }
00740   else if(sizeof(i) == 16) {
00741     return "%hd";
00742   }
00743 }
00744 

Generated on Wed May 23 17:20:12 2007 using doxygen 1.5.2