home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 4 / AACD04.ISO / AACD / Programming / envsof20 / source / syntax / keyword.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-01  |  6.8 KB  |  249 lines

  1. /*
  2.  * keyword.c -- Handling of reserved word lists.
  3.  *
  4.  * Copyright 1999 Thomas Aglassinger and others, see file "forum.txt"
  5.  */
  6.  
  7. #include "defs.h"
  8. #include "debug.h"
  9. #include "keyword.h"
  10.  
  11. #include <intuition/intuition.h>
  12. #include <clib/intuition_protos.h>
  13.  
  14. #define MAXIMUM_KEYWORD_COUNT  100
  15. #define MAXIMUM_KEYWORD_LENGTH 100
  16.  
  17. Prototype VOID create_keyword_list(VOID);
  18. Prototype VOID dispose_keyword_info(struct keyword_info *info);
  19. Prototype struct keyword_info *create_keyword_info(STRPTR name);
  20. Prototype VOID dispose_keyword_list(VOID);
  21. Prototype BOOL read_keyword_info(struct keyword_info *info, ULONG *line);
  22. Prototype struct keyword_info *keywords_of(char *filename);
  23.  
  24.  
  25.  
  26. // Master list of holding all keyword info's (protected with a semaphore)
  27. static struct keyword_list_s keyword_list;
  28.  
  29. /* Clone string contents using AllocVec() */
  30. static char *clone_string(char *original)
  31. {
  32.    char *clone = AllocVec((ULONG) strlen(original)+1, MEMF_ANY);
  33.    if (clone != NULL) {
  34.       strcpy(clone, original);
  35.    } else {
  36.       SetIoErr(ERROR_NO_FREE_STORE);
  37.    }
  38.    return clone;
  39. }
  40.  
  41. /* Initialize the one and only master list */
  42. VOID create_keyword_list(VOID)
  43. {
  44.    InitSemaphore(&(keyword_list.semaphore));
  45.    NewList(&keyword_list.list);
  46. }
  47.  
  48. /* Dispose a keyword_info. Perform the following steps:
  49.  * - decrese usage counter; if last user gone, also:
  50.  * - unlink info from master list
  51.  * - release all memory allocated by info
  52.  */
  53. VOID dispose_keyword_info(struct keyword_info *info)
  54. {
  55.    ObtainSemaphore(&keyword_list.semaphore);
  56.  
  57.    info->usage_count -= 1;
  58.    if (info->usage_count == 0) {
  59.  
  60.       ULONG index = 0;
  61.  
  62.       D(bug("remove "));
  63.       D(bug(info->node.ln_Name));
  64.       D(bug("\n"));
  65.  
  66.       Remove((struct Node *) info);
  67.  
  68.       while (index < info->word_count) {
  69.          FreeVec(info->word[index]);
  70.          index += 1;
  71.       }
  72.  
  73.       if (info->node.ln_Name != NULL) {
  74.          FreeVec(info->node.ln_Name);
  75.       }
  76.       if (info->word != NULL) {
  77.          FreeVec(info->word);
  78.       }
  79.       FreeVec(info);
  80.    }
  81.    ReleaseSemaphore(&keyword_list.semaphore);
  82. }
  83.  
  84. /* Create a new info that know nothing but its name.
  85.  * All other fields are set to default */
  86. struct keyword_info *create_keyword_info(STRPTR name)
  87. {
  88.    struct keyword_info *info = AllocVec(sizeof(struct keyword_info), MEMF_CLEAR);
  89.  
  90.    if (info != NULL) {
  91.       info->node.ln_Name = clone_string(name);
  92.       if (info->node.ln_Name == NULL) {
  93.          dispose_keyword_info(info);
  94.          info = NULL;
  95.       } else {
  96.          AddTail(&keyword_list.list, (struct Node*) info);
  97.       }
  98.  
  99.    }
  100.    return (info);
  101. }
  102.  
  103. /* dispose all information about all keywords;
  104.  * this is never called by the scanner because there is no global
  105.  * cleanup. However, this does not cause any memory leaks or the
  106.  * like because all information is released if usage_count goes
  107.  * to 0 in dispose_keyword_info. */
  108. VOID dispose_keyword_list(VOID)
  109. {
  110.    struct Node *node = keyword_list.list.lh_Head;
  111.    struct Node *next_node;
  112.  
  113.    while (node->ln_Succ) {
  114.       next_node = node->ln_Succ;
  115.       dispose_keyword_info((struct keyword_info *) node);
  116.       node = next_node;
  117.    }
  118. }
  119.  
  120. /* Read keywords from a file named like info. The info has to empty,
  121.  * which is only the case if it was created by create_keyword_info(). */
  122. BOOL read_keyword_info(struct keyword_info *info, ULONG *line)
  123. {
  124.    static UBYTE buffer[MAXIMUM_KEYWORD_LENGTH];
  125.    BOOL ok = FALSE;
  126.    STRPTR previous_word = NULL; /* to ensure sort order */
  127.  
  128.    *line = 0;
  129.  
  130.    // TODO: don't use maximum size info
  131.    info->word_count = 0;
  132.    info->word = AllocVec(MAXIMUM_KEYWORD_COUNT * sizeof(char *), MEMF_ANY);
  133.    if (info->word != NULL) {
  134.       BPTR file = Open(info->node.ln_Name, MODE_OLDFILE);
  135.       if (file != NULL) {
  136.          ok = TRUE;
  137.          ;
  138.          while (ok && (FGets(file, buffer, MAXIMUM_KEYWORD_LENGTH) != NULL)) {
  139.             ULONG buffer_length = strlen(buffer);
  140.             *line = *line + 1;
  141.             if ((buffer_length > 1) && (buffer[0] != '-')) {
  142.                // Add new keyword to list
  143.                STRPTR last_ch = &(buffer[buffer_length - 1]);
  144.                // Strip trailing linefeed
  145.                if (*last_ch == '\n') {
  146.                   *last_ch = '\0';
  147.                }
  148.                if (info->word_count < MAXIMUM_KEYWORD_COUNT) {
  149.                   info->word[info->word_count] = clone_string(buffer);
  150.                   ok = (info->word[info->word_count] != NULL);
  151.                   if (ok) {
  152.                      // ensure that input is sorted
  153.                      if ((previous_word == NULL)
  154.                          || (strcmp(previous_word, buffer) <= 0)
  155.                         ) {
  156.                         previous_word = info->word[info->word_count];
  157.                      } else {
  158.                         SetIoErr(ERROR_INVALID_COMPONENT_NAME);
  159.                         ok = FALSE;
  160.                      }
  161.                      info->word_count += 1;
  162.  
  163. #if 0
  164.                      D(kint((int) *line));
  165.                      D(bug("."));
  166.                      D(kint((int) info->word_count));
  167.                      D(bug(" = "));
  168.                      D(bug(info->word[info->word_count]));
  169.                      D(bug("\n"));
  170. #endif
  171.                   }
  172.                } else {
  173.                   SetIoErr(ERROR_OBJECT_TOO_LARGE);
  174.                   ok = FALSE;
  175.                }
  176.             }
  177.          }
  178.          Close(file);
  179.       }
  180.    } else {
  181.       SetIoErr(ERROR_NO_FREE_STORE);
  182.    }
  183.  
  184.    return ok;
  185. }
  186.  
  187. /* Return pointer to keyword info stored in `filename'. If it is
  188.  * not in the master list allready, read it automatically. */
  189. struct keyword_info *keywords_of(char *filename)
  190. {
  191. #define MAXIMUM_FAULT_LENGTH 300
  192.  
  193.    static char fault_buffer[MAXIMUM_FAULT_LENGTH];
  194.    ULONG error_line;
  195.  
  196.    struct keyword_info *words = NULL;
  197.    struct Node *node;
  198.    BOOL ok = FALSE;
  199.  
  200.    ObtainSemaphore(&keyword_list.semaphore);
  201.  
  202.    node = FindName(&keyword_list.list, filename);
  203.    if (node != NULL) {
  204.       words = (struct keyword_info *) node;
  205.       ok = TRUE;
  206.    } else {
  207.       // Read keywords from disk
  208.       words = create_keyword_info(filename);
  209.       if (words != NULL) {
  210.          ok = read_keyword_info(words, &error_line);
  211.          if (!ok) {
  212.             dispose_keyword_info(words);
  213.          }
  214.       }
  215.    }
  216.  
  217.    if (!ok) {
  218.       /* View error message in requester */
  219.       struct EasyStruct error_requester = {
  220.          sizeof(struct EasyStruct),
  221.          0,
  222.          "Syntax Parser Problem",
  223.          "Cannot read keywords for syntax parser.\n\n"
  224.          "file: \"%s\"\nline: %ld%s",
  225.          "Continue"
  226.       };
  227.       ULONG argument[3];
  228.  
  229.       if (IoErr() != 0) {
  230.          Fault(IoErr(), "\ncause", fault_buffer, MAXIMUM_FAULT_LENGTH);
  231.       } else {
  232.          fault_buffer[0] = '\0';
  233.       }
  234.  
  235.       argument[0] = (ULONG) filename;
  236.       argument[1] = error_line;
  237.       argument[2] = (ULONG) fault_buffer;
  238.  
  239.       EasyRequestArgs(NULL, &error_requester, NULL, argument);
  240.  
  241.       words = NULL;
  242.    }
  243.  
  244.    ReleaseSemaphore(&keyword_list.semaphore);
  245.  
  246.    return words;
  247. }
  248.  
  249.