home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / forut062.zip / ForUtil-0.62 / commons / lib_commons.c < prev    next >
C/C++ Source or Header  |  1996-08-28  |  16KB  |  664 lines

  1. #ifndef lint
  2. static char rcsId[]="$Header: /usr/local/rcs/ForUtil/Commons/RCS/lib_commons.c,v 1.9 1996/08/28 17:43:55 koen Exp koen $";
  3. #endif
  4. /*****
  5. * lib_commons.c : functions used by all commons programs
  6. *
  7. * This file Version    $Revision: 1.9 $
  8. *
  9. * Creation date:    Fri Mar 15 04:51:43 GMT+0100 1996
  10. * Last modification:     $Date: 1996/08/28 17:43:55 $
  11. * By:            $Author: koen $
  12. * Current State:    $State: Exp $
  13. *
  14. * Author:        koen
  15. * (C)Copyright 1995 Ripley Software Development
  16. * All Rights Reserved
  17. *****/
  18. /*****
  19. * ChangeLog 
  20. * $Log: lib_commons.c,v $
  21. * Revision 1.9  1996/08/28 17:43:55  koen
  22. * Changed uname define for __MSDOS__ only to #ifdef HAVE_UNAME;#else;#endif
  23. *
  24. * Revision 1.8  1996/08/27 19:11:46  koen
  25. * Added support for DOUBLE, COMPLEX. linecount added to check if less than 
  26. * 19 cont. lines
  27. *
  28. * Revision 1.7  1996/08/07 21:12:01  koen
  29. * Fixed a bug in remove_tokens for the PARAMETER case.
  30. *
  31. * Revision 1.6  1996/08/02 14:49:21  koen
  32. * moved all system dependencies to lib/sysdeps.h
  33. *
  34. * Revision 1.5  1996/07/30 01:56:01  koen
  35. * re-ordered include files.
  36. *
  37. * Revision 1.4  1996/07/16 00:36:20  koen
  38. * added warning and error values upon return from scan_block. Finally got
  39. * compress_common_block correct with respect to continuation characters.
  40. *
  41. * Revision 1.3  1996/05/06 00:32:19  koen
  42. * Adapted for MSDOS.
  43. *
  44. * Revision 1.2  1996/04/25 02:27:12  koen
  45. * Cleanup and comments added.
  46. *
  47. * Revision 1.1  1996/03/15 04:16:32  koen
  48. * Initial Revision
  49. *
  50. *****/ 
  51. /* needed to prevent multiple variable decls under MSDOS in lib/sysdeps.h */
  52. #define LIBRARY_OBJECT
  53.  
  54. /* include this before anything else */
  55. #ifdef HAVE_CONFIG_H
  56. #include "autoconf.h"
  57. #endif
  58.  
  59. #include <ctype.h>
  60. #include <time.h>
  61.  
  62. #ifdef HAVE_UNAME
  63. #include <sys/utsname.h>
  64. #else
  65. struct utsname{
  66.         char *nodename;
  67.         char *sysname;
  68.         char *machine;
  69. };
  70. #define uname(INFO) { (INFO)->nodename="<unknown nodename>"; \
  71.     (INFO)->sysname="<unknown sysname>"; \
  72.     (INFO)->machine="<unknown machine>";}
  73. #endif /* !HAVE_UNAME */
  74.  
  75. #include "lib_commons.h"
  76. #include "forutil.h"
  77. #include "memmacros.h"
  78.  
  79. #ifdef TEST
  80. #define VERBOSE
  81.  
  82. static char *text={"\n"
  83. "      COMMON /ISUBW/ IB0020 , \n"                                           
  84. "*     This is a comment containing a COMMON   IDTEST                     \n"
  85. "     +               NMSBW, NMSBU , LNDFDS ,                             \n"
  86. "     +               lnisbw(lmsbw), lnxsbw(lmsbw), lncsbw(lmsBW),        \n"
  87. "     X               KBISBW(LMSBW), KBXSBW(LMSBW), KBCSBW(LMSBW),        \n"
  88. "     x               LISDAS( LMSBW ) , IACTDS( LMSBW ) ,                 \n"
  89. "     x               Intdas( lmsbu ) , nhgint ,                          \n"
  90. "     +               IE0020                                              \n"
  91. "      COMMON /XSUBW/ XB0020,XE0020                                       \n"
  92. "  *    Intendent COMMON IDTES2 which should not show up in the output    \n"
  93. "      CHARACTER*60   NAMSBW                                              \n"
  94. "      CHARACTER*31   CSUBDF                                              \n"
  95. "      CHARACTER*8    CB0020 , CE0020                                     \n"
  96. "      CHARACTER*(LEN) CB0020 , CE0020                                    \n"
  97. "      PARAMETER (MAXVEC=128)                                             \n"
  98. "      PARAMETER ( LEN=128 )                                              \n"
  99. "      PARAMETER ( LEN12 = 12 )                                           \n"
  100. "      COMMON /CSUBW/ CB0020 , NAMSBW(LMSBW)  , CSUBDF(LMSBW) ,           \n"
  101. "     #               CE0020\n"}; 
  102.  
  103. static char *wrong_text={"\n"
  104. "*      This is a common block with some errors in it \n"
  105. "  *    This is a comment starting with an ident. \n"
  106. "*      This piece contains an unbalaced brace.   \n"
  107. "      COMMON         IDWRONG(UNCLOSED            \n"
  108. "\n"};
  109.  
  110. static int num_errors;
  111. #endif /* TEST */
  112.  
  113. /* structure for holding token definitions */
  114. typedef struct {
  115.     int id;        /* id of token */
  116.     char *token;    /* name of token */
  117.     int len;    /* length of token */
  118. }token;
  119.  
  120. #define COMMON        0
  121. #define CHARACTER    1
  122. #define LOGICAL        2
  123. #define PARAMETER    3
  124. #define REAL        4
  125. #define INTEGER        5
  126. #define DOUBLE        6
  127. #define COMPLEX        7
  128. #define NUM_TOKEN    8        /* number of tokens */
  129. #define NUM_DELIMITER    4        /* number of possible delimiters */
  130.  
  131. /* token lookup table */
  132. token token_words[NUM_TOKEN] = {
  133.     {COMMON, "COMMON", 6},
  134.     {CHARACTER, "CHARACTER*", 10},
  135.     {LOGICAL, "LOGICAL", 7},
  136.     {PARAMETER, "PARAMETER", 9},
  137.     {REAL, "REAL", 4},
  138.     {INTEGER, "INTEGER", 7},
  139.     {DOUBLE, "DOUBLE PRECISION", 16},
  140.     {COMPLEX, "COMPLEX", 7}};
  141.  
  142. static char delimit_table[NUM_DELIMITER] = {'/','/', '(', ')'};
  143. static int num_warnings;
  144.  
  145. /****
  146. * Find out what our database is called
  147. ****/
  148. char
  149. *get_database_location(char *db_env)
  150. {
  151.     static char *ptr;
  152.     ptr = getenv(db_env);
  153.     return(ptr);
  154. }
  155.  
  156. /****
  157. * get & print the header of the database given
  158. ****/
  159. void
  160. print_commondb_header(GDBM_FILE db_file)
  161. {
  162.     datum key, content;
  163.     char *chPtr;
  164.  
  165.     key.dptr = DBM_ID_TOKEN;
  166.     key.dsize = strlen(DBM_ID_TOKEN)+1;
  167.  
  168.     /* original database, contains platform, user, date & time */
  169.     content = gdbm_fetch(db_file, key);
  170.     if(content.dptr != NULL)
  171.     {
  172.         printf(content.dptr);
  173.         free(content.dptr);
  174.     }
  175.  
  176.     /* update info, contains platform, user, data & time */
  177.     key.dptr = DBM_UPDATE_TOKEN;
  178.     key.dsize = strlen(DBM_UPDATE_TOKEN)+1;
  179.  
  180.     content = gdbm_fetch(db_file, key);
  181.     if(content.dptr != NULL)
  182.     {
  183.         printf(content.dptr);
  184.         free(content.dptr);
  185.     }
  186.  
  187.     /* searched directories */
  188.     key.dptr = DBM_INFO_TOKEN;
  189.     key.dsize = strlen(DBM_INFO_TOKEN)+1;
  190.     content = gdbm_fetch(db_file, key);
  191.     if(content.dptr != NULL)
  192.     {
  193.         printf("Contains the following directories:\n");
  194.         for(chPtr = strtok(content.dptr, ","); chPtr != NULL; 
  195.             chPtr = strtok(NULL, ","))
  196.             printf("\t%s\n", chPtr);
  197.     }
  198. }
  199.  
  200. /***** 
  201. * Add a section identifying what paths are stored in this database. 
  202. *****/
  203. void
  204. write_commondb_dirinfo(GDBM_FILE db_file, char *dir)
  205. {
  206.     datum key, prev;
  207.  
  208.     key.dptr = DBM_INFO_TOKEN;
  209.     key.dsize = strlen(DBM_INFO_TOKEN)+1;
  210.  
  211.     if(gdbm_exists(db_file, key))
  212.     {
  213.         prev = gdbm_fetch(db_file, key);
  214.         /* 
  215.         * If the stringcompare matches the current dir, it's already 
  216.         * here so we don't want to update it again. 
  217.         */
  218.         if(strstr(prev.dptr, dir))
  219.             return;
  220.         /*
  221.         * Resize the returned item so it will contain the next also 
  222.         * but separated by a comma 
  223.         */
  224.         prev.dsize += strlen(dir) + 2;
  225.         checked_realloc(prev.dptr, prev.dsize, char);
  226.  
  227.         /* update data */
  228.         strcat(prev.dptr, ",");
  229.         strcat(prev.dptr, dir);
  230.  
  231.         gdbm_store(db_file, key, prev, GDBM_REPLACE);
  232.  
  233.         free(prev.dptr);
  234.     }
  235.     else
  236.     {
  237.         prev.dsize += strlen(dir) + 1;
  238.         prev.dptr = dir;
  239.         gdbm_store(db_file, key, prev, GDBM_INSERT);
  240.     }
  241. }
  242.  
  243.  
  244. /***** 
  245. * Add a section identifying how many entries are stored in this database. 
  246. *****/
  247. /*ARGSUSED*/
  248. void
  249. write_commondb_update_info(GDBM_FILE db_file, int entries)
  250. {
  251.     datum content, update_key;
  252.     struct utsname sysinfo;
  253.     time_t cr_time;
  254.     char *upd_time, fullname[256];
  255.  
  256.     uname(&sysinfo);
  257.     time(&cr_time);
  258.     upd_time = ctime(&cr_time);
  259.  
  260.     update_key.dptr = DBM_UPDATE_TOKEN;
  261.     update_key.dsize = strlen(DBM_UPDATE_TOKEN)+1;
  262. #if 0
  263.     if(gdbm_exists(db_file, update_key))
  264.     {
  265.         datum prev;
  266.         char *chPtr;
  267.         int num_entry, num_files;
  268.  
  269.         prev = gdbm_fetch(db_file, update_key);
  270.         chPtr = strstr(prev.dptr, "Contains ");
  271. fprintf(stderr,"write_commondb_update_info, chPtr is %s\n", chPtr);
  272.         sscanf(chPtr, "%i entries.", &num_entry);
  273. fprintf(stderr,"write_commondb_update_info, num_entry is %i\n", num_entry); 
  274.         entries +=num_entry;
  275.     }
  276.     sprintf(fullname, "Last updated by %s\nHost %s, platform %s (%s) "
  277.         "on %sContains %i entries.\n", get_user_login(), 
  278.         sysinfo.nodename, sysinfo.sysname, sysinfo.machine,
  279.         upd_time, entries);
  280. #endif
  281.  
  282.     sprintf(fullname, "Last updated by %s, host %s, platform %s (%s)\n"
  283.         "on %s", get_user_login(), 
  284.         sysinfo.nodename, sysinfo.sysname, sysinfo.machine,
  285.         upd_time);
  286.  
  287.     content.dptr = fullname;
  288.     content.dsize = strlen(fullname)+1;
  289.  
  290.     gdbm_store(db_file, update_key, content, GDBM_REPLACE);
  291.  
  292. }
  293.  
  294. /***** 
  295. * Add a header identifying the user, date, system and name of the 
  296. * database file 
  297. *****/
  298. void
  299. write_commondb_header(GDBM_FILE db_file, char *outfile)
  300. {
  301.     struct utsname sysinfo;
  302.     time_t cr_time;
  303.     char fullname[256];
  304.     datum key, content;
  305.     char *upd_time;
  306.  
  307.     uname(&sysinfo);        /* get system information */
  308.     time(&cr_time);            /* get the system time */
  309.     upd_time = ctime(&cr_time);    /* convert to ASCII string */
  310.     sprintf(fullname, "Database %s created by %s (%s).\n"
  311.         "Host %s, platform %s (%s) on %s", 
  312.         outfile, get_user_login(), get_user_name(), 
  313.         sysinfo.nodename, sysinfo.sysname, sysinfo.machine,
  314.         upd_time);
  315.  
  316.     content.dptr = fullname;
  317.     content.dsize = strlen(fullname)+1;
  318.     key.dptr = DBM_ID_TOKEN;
  319.     key.dsize = strlen(DBM_ID_TOKEN)+1;
  320.  
  321.     if(!gdbm_exists(db_file, key))
  322.         gdbm_store(db_file, key, content, GDBM_INSERT);
  323. }
  324.  
  325. /*****
  326. * Remove all unnecessary characters from the given string. Compresses white
  327. * space, replaces newlines with commas and does a little syntax checking on
  328. * intended commons and the no of continuation lines allowed by the f77 standard.
  329. *****/
  330. static inline void
  331. compress_common_block(char *string, int curr_line_num)
  332. {
  333.     register char *outPtr = string;
  334.     register int sp_count = 0;
  335.     int numline = 0;
  336.     while (1)
  337.     {
  338.         switch(*string)
  339.         {
  340.             case ' ':    /* a space, increment the space cnt. */
  341.                 string++;
  342.                 sp_count++;
  343.                 break;
  344.             case '\n':    /* special case, replace with a comma */
  345.                 sp_count = 0;    /* reset space counter */
  346.                 numline++;
  347.                 *outPtr++=',';
  348.                 string++;
  349.                 break;
  350.             /*
  351.             * C is a comment char if it's at the beginning of a 
  352.             * line (space count equals zero), so delete until we 
  353.             * reach end of line or \0. 
  354.             */
  355.             case 'C':
  356.             case '*':
  357.                 if(sp_count == 0)
  358.                 {
  359.                     while(*string != '\0' 
  360.                         && *string != '\n')
  361.                         string++;
  362.                     break;
  363.                 }
  364.                 else
  365.                     if(sp_count < 5)
  366.                     {
  367.                         num_warnings++;
  368.                         fprintf(stderr, "WARNING: "
  369.                             "intended comment "
  370.                             "found near line %i\n",
  371.                             curr_line_num);
  372.                         while(*string != '\0' 
  373.                             && *string != '\n')
  374.                             string++;
  375.                         break;
  376.                     } /* else fall through */
  377.             /* 
  378.             * any character but a space or a 0 appearing on the 
  379.             * sixth column is a continuation char 
  380.             */
  381.             default:
  382.                 if(sp_count == 5 && *string != '\0' 
  383.                     && *string != ' ' && *string != '0')
  384.                 {
  385.                     string++;
  386.                     sp_count++;
  387.                 }
  388.                 else
  389.                     *(outPtr++) = *(string++);
  390.         }
  391.         if (*string == 0)
  392.         {
  393.             /* 19 continuation lines allowed by f77 standard */
  394.             if(numline > 18)
  395.             {
  396.                 num_warnings++;
  397.                 fprintf(stderr, "WARNING: more than 19 "
  398.                     "continuation lines near line %i\n",
  399.                     curr_line_num);
  400.             }
  401.             *outPtr = '\0';
  402.             return;
  403.         }
  404.     }
  405. }
  406.  
  407. /****
  408. * Remove excess commas in the output put there by compress_common_block.
  409. ****/
  410. static inline void
  411. remove_excess_commas(char *string)
  412. {
  413.     register char *outPtr = string;
  414.  
  415.     /* what is this 'R' doing here ? */
  416.     if(*string == 'R' && *(string+1) == ',')
  417.         string++;
  418.     while(1)
  419.     {
  420.         /*
  421.         * Skip commas as long as the next character is a comma and we 
  422.         * haven't reached the end of the line
  423.         */
  424.         if(*string == ',')
  425.             while(*(string+1) != '\0' && *(string+1) == ',')
  426.                 string++;
  427.         if(*string == 0)
  428.         {
  429.             *outPtr = '\0';
  430.             return;
  431.         }
  432.         *(outPtr++) = *(string++);
  433.     }
  434. }
  435.  
  436. /*****
  437. * remove the tokens in the token table from the given string
  438. *****/
  439. static inline int
  440. remove_tokens(char *string)
  441. {
  442.     register char *outPtr = string;
  443.     register int tok_id;
  444.  
  445.     while(1)
  446.     {
  447.         /* scan for any tokens appearing in token_table */
  448.         for(tok_id = 0 ; tok_id < NUM_TOKEN && 
  449.             strncmp(string, token_words[tok_id].token, 
  450.                 token_words[tok_id].len); tok_id++); 
  451.         switch(tok_id)
  452.         {
  453.             /* This is again a special case. We only want to have
  454.             * the name of the param, not it's value 
  455.             */
  456.             case PARAMETER:
  457.                 string = string + token_words[tok_id].len;
  458.                 /* remove anything not a character */
  459.                 while(!isalnum(*string))
  460.                     string++;
  461.                 /* copy the word found */
  462.                 while(isalnum(*string))
  463.                     *(outPtr++) = *(string++);
  464.                 /* remove anything else until the end of line */
  465.                 while(*string != '\0' && *string != '\n')
  466.                     *string++; 
  467.                 break;
  468.             case COMMON:
  469.             case LOGICAL:
  470.                 /* skip past the token found */
  471.                 string = string + token_words[tok_id].len;
  472.                 break;
  473.             case REAL:
  474.             case INTEGER:
  475.             case DOUBLE:
  476.             case COMPLEX:
  477.                 /* skip past the token found */
  478.                 string = string + token_words[tok_id].len;
  479.                 /* numbers params must start with a letter */
  480.                 while(!isalpha(*string))
  481.                     string++;
  482.                 break;
  483.             case CHARACTER:
  484.                 /* 
  485.                 * skip past the token found and any numbers 
  486.                 * found in here 
  487.                 */
  488.                 string = string + token_words[tok_id].len;
  489.  
  490.                 /* 
  491.                 * can't use isdigit(*string++), CHARACTER can
  492.                 * given as CHARACTER*(LEN) also 
  493.                 */
  494.                 while(!isspace(*string))
  495.                     string++;
  496.                 break;
  497.             case NUM_TOKEN:
  498.                 /* no token found */
  499.                 *(outPtr++) = *(string++);
  500.                 break;
  501.             default:    
  502.                 /* should never happen */
  503.                 fprintf(stderr, "Internal Parse Error: invalid" 
  504.                     "token range!\n");
  505.                 exit(7);
  506.         }
  507.         /* terminate if at end of current block of text */
  508.         if (*string == 0)
  509.         {
  510.             *outPtr = '\0';
  511.             return(1);
  512.         }
  513.     }
  514. }
  515.  
  516. /*****
  517. * remove all text between the delimiters in the delimit_table
  518. *****/ 
  519. static inline int 
  520. remove_delimiter(char *string)
  521. {
  522.     register char *outPtr = string;
  523.     register int i;
  524.  
  525.     while(1)
  526.     {
  527.         for(i = 0 ; i < NUM_DELIMITER && *string != delimit_table[i]; 
  528.             i++);
  529.         switch(i)
  530.         {
  531.             case 0:    /* a / was found */
  532.             case 2:    /* a ( was found */
  533.                 string++; /* move past the delimiter */
  534.                 while(*string != '\0' && 
  535.                     *string != delimit_table[i+1])
  536.                     string++;
  537.                 if (*string == 0)
  538.                 {
  539.                     *outPtr = '\0';
  540.                     return(0);
  541.                 }
  542.                 else /* move past the delimiter */
  543.                     string++; 
  544.                 break;
  545.             default:
  546.                 *(outPtr++) = *(string++);
  547.                 break;
  548.         }
  549.         if (*string == 0)
  550.         {
  551.             *outPtr = '\0';
  552.             return(1);
  553.         }
  554.     }
  555. }
  556.  
  557. /**** 
  558. * scan a block for common names 
  559. * Returns 0 or the number of warnings outputted on success,
  560. * -1 on failure.
  561. ****/ 
  562. int 
  563. scan_block(char *text, int line_num)
  564. {
  565.     num_warnings = 0;
  566.     if(remove_tokens(text))
  567.     {
  568.         compress_common_block(text, line_num);
  569.         if(remove_delimiter(text))
  570.         {
  571.             remove_excess_commas(text);
  572.             return(num_warnings);
  573.         }
  574.         else
  575.         {
  576.             fprintf(stderr, "WARNING:"
  577.                 "unbalanced brace or delimiter near line %i.\n",
  578.                 line_num);
  579. #ifdef TEST
  580.             num_errors++;
  581. #endif 
  582.             return(-1);
  583.         }
  584.     }
  585.     else    /* should never happen */
  586.     {
  587.         fprintf(stderr, "Internal Parse Error: Failed to remove common"
  588.             "keywords!\n");
  589.         exit(8);
  590.     }
  591.     return(-1);
  592. }
  593.             
  594. #ifdef TEST
  595. int main()
  596. {
  597.     char *chPtr;
  598.     char path[256], file[256];
  599.     int i;
  600.     printf("Name of current user: %s\n", get_user_name());
  601.     printf("Login name of current user: %s\n", get_user_login());
  602.     fflush(stdout);
  603.     printf("Testing ParseFilename on lib_comm.h\n");
  604.     fflush(stdout);
  605.     ParseFilename("lib_comm.h", file, path);        
  606.     printf("lib_comm.h -> %s%s\n", path, file);
  607.     fflush(stdout);
  608.     printf("Test 1, you should get 1 warning.\n");
  609.     printf("Block to scan: \n%s\n", text);
  610.     if(scan_block(text))
  611.     {
  612.         printf("Commons found: \n");
  613.         for(i=0, chPtr = strtok(text, ","); 
  614.             chPtr != NULL; chPtr = strtok(NULL, ","), i++)
  615.             printf("%s ", chPtr);
  616.         printf("%i in total\n",i);
  617.     }
  618.     else
  619.         printf("scan failed...\n"); 
  620.     printf("\nTest 2, you should get 1 warning, 1 error and no output.\n");
  621.     printf("Block to scan: \n%s\n", wrong_text);
  622.     if((scan_block(wrong_text)) != -1)
  623.     {
  624.         printf("Oops, some errors should have been detected.\n");
  625.         printf("Commons found: \n");
  626.         for(i=0, chPtr = strtok(text, ","); 
  627.             chPtr != NULL; chPtr = strtok(NULL, ","), i++)
  628.             printf("%s\n", chPtr);
  629.         printf("%i in total\n",i);
  630.     }
  631.     else
  632.         printf("scan failed (as it should with this garbage)\n"); 
  633.     switch(num_warnings)
  634.     {
  635.         case 0 :
  636.             printf("Something was seriously wrong, no warnings "
  637.                 "found, should have found one\n");
  638.             break;
  639.         case 1:
  640.             printf("Found one warning, should have found one. "
  641.                 "Test passed\n");
  642.             break;
  643.         default:
  644.             printf("Serious trouble, found more than one warning: "
  645.                 "%i in total\n", num_warnings);
  646.     }
  647.     switch(num_errors)
  648.     {
  649.         case 0 :
  650.             printf("Something was wrong, no errors found, should "
  651.                 "have found 1\n");
  652.             break;
  653.         case 1:
  654.             printf("Found 1 error, should have found 1. "
  655.                 "Test passed\n");
  656.             break;
  657.         default:
  658.             printf("Internal scanner error: found more than 1 "
  659.                 "error: %i in total\n", num_errors);
  660.     }
  661.     return(0);
  662. }
  663. #endif
  664.