|  | /* | 
|  | genidl - Generate interface defintion language listing from a | 
|  | Portable Executable. | 
|  | Copyright (C) 2009-2016  mingw-w64 project | 
|  |  | 
|  | This program is free software: you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation, either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|  | */ | 
|  |  | 
|  | #include "genidl_cfg.h" | 
|  |  | 
|  | #define TOK_NAME  256 | 
|  | #define TOK_DIGIT 257 | 
|  | #define TOK_STRING 258 | 
|  |  | 
|  | static sCfgLib *gen_cfglib (const char *); | 
|  | static sCfgLib *has_cfglib (const char *, int); | 
|  | static sCfgAlias *gen_cfglib_alias (sCfgLib *, const char *); | 
|  | static sCfgAlias *has_cfglib_alias (sCfgLib *, const char *); | 
|  | static sCfgItem *has_cfglib_item (sCfgLib *, const char *); | 
|  | static sCfgItem *gen_cfglib_item (sCfgLib *, const char *, const char *); | 
|  |  | 
|  | static int rCh (void); | 
|  | static void bCh (int r); | 
|  | static int pCh (void); | 
|  | static int addCh (int r); | 
|  | #if 0 | 
|  | static void delCh (void); | 
|  | #endif | 
|  | static void clrCh (void); | 
|  | static void printError (const char *fmt, ...); | 
|  | static int lex (void); | 
|  |  | 
|  | static FILE *conf_fp = NULL; | 
|  | static int last_ch = -1; | 
|  | static int line_no = 1; | 
|  | static int seen_eof = 0; | 
|  | static char *l_buffer = NULL; | 
|  | static size_t l_max, l_cur; | 
|  |  | 
|  | static sCfgLib *cfg_head = NULL; | 
|  | static int is_modified = 0; | 
|  |  | 
|  | static sCfgItem * | 
|  | has_cfglib_item (sCfgLib *c, const char *name) | 
|  | { | 
|  | sCfgItem *h; | 
|  | if (!c || c->item == NULL) | 
|  | return NULL; | 
|  | h = c->item; | 
|  | do { | 
|  | if (!strcmp (h->name, name)) | 
|  | return h; | 
|  | h = h->next; | 
|  | } while (h != NULL); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static sCfgItem * | 
|  | gen_cfglib_item (sCfgLib *c, const char *name, const char *type) | 
|  | { | 
|  | sCfgItem *a, *p = NULL, *e = c->item; | 
|  | int is_new = 0; | 
|  | a = has_cfglib_item (c, name); | 
|  | if (!a) | 
|  | { | 
|  | a = (sCfgItem *) malloc (sizeof (sCfgItem) + strlen (name) + 1); | 
|  | memset (a, 0, sizeof (sCfgItem)); | 
|  | strcpy (a->name, name); | 
|  | is_new = 1; | 
|  | } | 
|  | is_modified = 1; | 
|  | if (a->type != NULL) | 
|  | free (a->type); | 
|  | a->type = strdup (type); | 
|  | if (!is_new) | 
|  | return a; | 
|  | while (e != NULL) | 
|  | { | 
|  | p = e; | 
|  | e = e->next; | 
|  | } | 
|  | if (!p) | 
|  | c->item = a; | 
|  | else | 
|  | p->next = a; | 
|  | return a; | 
|  | } | 
|  |  | 
|  | static sCfgAlias * | 
|  | gen_cfglib_alias (sCfgLib *c, const char *name) | 
|  | { | 
|  | sCfgAlias *p, *e; | 
|  | sCfgAlias *a = has_cfglib_alias (c, name); | 
|  | if (a) | 
|  | return a; | 
|  | a = (sCfgAlias *) malloc (sizeof (sCfgAlias) + strlen (name) + 1); | 
|  | memset (a, 0, sizeof (sCfgAlias)); | 
|  | strcpy (a->name, name); | 
|  | p = NULL; e = c->alias; | 
|  | while (e != NULL) | 
|  | { | 
|  | p = e; | 
|  | e = e->next; | 
|  | } | 
|  | if (!p) | 
|  | c->alias = a; | 
|  | else | 
|  | p->next = a; | 
|  | is_modified = 1; | 
|  | return a; | 
|  | } | 
|  |  | 
|  | static sCfgAlias * | 
|  | has_cfglib_alias (sCfgLib *c, const char *name) | 
|  | { | 
|  | sCfgAlias *a = (c ? c->alias : NULL); | 
|  | while (a != NULL) | 
|  | { | 
|  | if (!strcmp (a->name, name)) | 
|  | return a; | 
|  | a = a->next; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static sCfgLib * | 
|  | has_cfglib (const char *name, int withAlias) | 
|  | { | 
|  | sCfgLib *r = cfg_head; | 
|  | while (r != NULL) | 
|  | { | 
|  | if (!strcmp (r->name, name)) | 
|  | return r; | 
|  | if (withAlias && has_cfglib_alias (r, name) != NULL) | 
|  | return r; | 
|  | r = r->next; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static sCfgLib * | 
|  | gen_cfglib (const char *name) | 
|  | { | 
|  | sCfgLib *r, *p, *e; | 
|  | if ((r = has_cfglib (name, 0)) != NULL) | 
|  | return r; | 
|  | r = (sCfgLib *) malloc (sizeof (sCfgLib) + strlen (name) + 1); | 
|  | memset (r, 0, sizeof (sCfgLib)); | 
|  | strcpy (r->name, name); | 
|  | p = NULL; e = cfg_head; | 
|  | while (e != NULL) | 
|  | { | 
|  | p = e; e = e->next; | 
|  | } | 
|  | if (!p) cfg_head = r; | 
|  | else p->next = r; | 
|  | is_modified = 1; | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static void | 
|  | printError (const char *fmt, ...) | 
|  | { | 
|  | va_list argp; | 
|  | va_start (argp, fmt); | 
|  | fprintf (stderr, "configfile at "); | 
|  | if (l_buffer[0] == 0 && seen_eof) | 
|  | fprintf (stderr, "end of file"); | 
|  | else if (l_buffer[0] == 0) | 
|  | fprintf (stderr, "start of file"); | 
|  | else | 
|  | fprintf (stderr, "line %d near ,%s'", line_no, l_buffer); | 
|  | fprintf (stderr, ": "); | 
|  | vfprintf (stderr, fmt, argp); | 
|  | va_end (argp); | 
|  | } | 
|  |  | 
|  | static int | 
|  | lex (void) | 
|  | { | 
|  | int r; | 
|  |  | 
|  | rescan: | 
|  | clrCh (); | 
|  | do { | 
|  | r = rCh (); | 
|  | } while (r >= 0 && r <= 0x20); | 
|  |  | 
|  | if (r == -1) | 
|  | return -1; | 
|  | if (r == '/' && pCh () == '*') | 
|  | { | 
|  | rCh (); | 
|  | while ((r=rCh ()) != -1) | 
|  | { | 
|  | if (r == '*' && pCh () == '/') | 
|  | { | 
|  | rCh (); | 
|  | break; | 
|  | } | 
|  | } | 
|  | goto rescan; | 
|  | } | 
|  | else if (r == '/' && pCh () == '/') | 
|  | { | 
|  | while ((r=rCh ()) != -1) | 
|  | { | 
|  | if (r == '\n') | 
|  | break; | 
|  | } | 
|  | goto rescan; | 
|  | } | 
|  | if (r == '_' || (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')) | 
|  | { | 
|  | bCh (r); | 
|  | do { | 
|  | addCh (rCh ()); | 
|  | r = pCh (); | 
|  | } while (r == '_' || (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') | 
|  | || (r >= '0' && r <= '9') || r == '$' || r == '.'); | 
|  | return TOK_NAME; | 
|  | } | 
|  | if (r >= '0' && r <= '9') | 
|  | { | 
|  | addCh (r); | 
|  | if (r == '0') | 
|  | { | 
|  | switch (pCh ()) { | 
|  | case 'x': case 'X': addCh (rCh ()); break; | 
|  | case 'o': case 'O': addCh (rCh ()); break; | 
|  | case 'b': case 'B': addCh (rCh ()); break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | return TOK_DIGIT; | 
|  | } | 
|  | if (r == '"') | 
|  | { | 
|  | while ((r = pCh ()) != -1 && r != '"' && r != '\n') | 
|  | addCh (rCh ()); | 
|  | if (r != '"') | 
|  | printError ("Missing '\"' at end of string.\n"); | 
|  | else | 
|  | rCh (); | 
|  | return TOK_STRING; | 
|  | } | 
|  | addCh (r); | 
|  | switch (r) | 
|  | { | 
|  | case '=': case '{': case '}': case ',': | 
|  | case ';': | 
|  | return r; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | printError ("Illegal character found.\n"); | 
|  | goto rescan; | 
|  | } | 
|  |  | 
|  | static void | 
|  | clrCh (void) | 
|  | { | 
|  | l_cur = 0; | 
|  | l_buffer[0] = 0; | 
|  | } | 
|  |  | 
|  | #if 0 | 
|  | static void | 
|  | delCh (void) | 
|  | { | 
|  | if (l_cur == 0) | 
|  | return; | 
|  | --l_cur; | 
|  | l_buffer[l_cur] = 0; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static int | 
|  | addCh (int r) | 
|  | { | 
|  | if (r == -1) | 
|  | return r; | 
|  | if (l_cur == l_max) | 
|  | { | 
|  | char *h = (char *) realloc (l_buffer, l_max + 129); | 
|  | if (!h) | 
|  | abort (); | 
|  | l_max += 128; | 
|  | } | 
|  | l_buffer[l_cur++] = (char) r; | 
|  | l_buffer[l_cur] = 0; | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static int | 
|  | pCh (void) | 
|  | { | 
|  | int r = last_ch; | 
|  | if (r != -1) | 
|  | return r; | 
|  | r = rCh (); | 
|  | if (r != -1) | 
|  | bCh (r); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static void | 
|  | bCh (int r) | 
|  | { | 
|  | if (r == '\n') | 
|  | line_no--; | 
|  | last_ch = r; | 
|  | } | 
|  |  | 
|  | static int | 
|  | rCh (void) | 
|  | { | 
|  | int r; | 
|  | if ((r = last_ch) == -1) | 
|  | { | 
|  | char ch; | 
|  | if (seen_eof || feof (conf_fp)) | 
|  | return -1; | 
|  | if (fread (&ch, 1, 1, conf_fp) != 1) | 
|  | return -1; | 
|  | r = ((int) ch) & 0xff; | 
|  | } | 
|  | else | 
|  | last_ch = -1; | 
|  | if (r == '\r') | 
|  | r = rCh (); | 
|  | if (r == '\n') | 
|  | line_no++; | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static char ** | 
|  | parse_export (sCfgLib *cfg, int *re, const char *tname) | 
|  | { | 
|  | char **ret = NULL; | 
|  | int r = lex (); | 
|  | if (r == '=') | 
|  | r = lex (); | 
|  | if (r != '{') | 
|  | { | 
|  | printError ("Missing '{' for alias in ,%s'\n", tname); | 
|  | *re = r; | 
|  | return ret; | 
|  | } | 
|  | while ((r = lex ()) != -1) | 
|  | { | 
|  | if (r == '}') | 
|  | break; | 
|  | if (r == ',' || r == ';') | 
|  | continue; | 
|  | if (r == TOK_NAME || r == TOK_STRING) | 
|  | { | 
|  | char *left = strdup (l_buffer); | 
|  |  | 
|  | r = lex (); | 
|  | if (r == ',' || r == '=') | 
|  | r = lex (); | 
|  | if (r != TOK_NAME && r != TOK_STRING) | 
|  | { | 
|  | printError ("Expected in export second string.\n"); | 
|  | } | 
|  | else | 
|  | { | 
|  | gen_cfglib_item (cfg, left, l_buffer); | 
|  | } | 
|  | free (left); | 
|  | } | 
|  | else | 
|  | printError ("Ignore token in alias of ,%s'.\n", tname); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static char ** | 
|  | parse_alias (sCfgLib *cfg, int *re, const char *tname) | 
|  | { | 
|  | char **ret = NULL; | 
|  | int r = lex (); | 
|  | if (r == '=') | 
|  | r = lex (); | 
|  | if (r != '{') | 
|  | { | 
|  | printError ("Missing '{' for alias in ,%s'\n", tname); | 
|  | *re = r; | 
|  | return ret; | 
|  | } | 
|  | while ((r = lex ()) != -1) | 
|  | { | 
|  | if (r == '}') | 
|  | break; | 
|  | if (r == ',' || r == ';') | 
|  | continue; | 
|  | if (r == TOK_NAME || r == TOK_STRING) | 
|  | { | 
|  | gen_cfglib_alias (cfg, l_buffer); | 
|  | } | 
|  | else | 
|  | printError ("Ignore token in alias of ,%s'.\n", tname); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int | 
|  | parseTableSub (const char *tname) | 
|  | { | 
|  | char **alias = NULL; | 
|  | char **exps; | 
|  | int r = lex (); | 
|  | sCfgLib *cfg = gen_cfglib (tname); | 
|  | while (r != '}') | 
|  | { | 
|  | if (r == ';') | 
|  | { | 
|  | r = lex (); | 
|  | continue; | 
|  | } | 
|  | if (r != TOK_NAME) | 
|  | { | 
|  | printError ("Unknown content in ,%s'\n", tname); | 
|  | break; | 
|  | } | 
|  | if (strcmp (l_buffer, "alias")  == 0) | 
|  | { | 
|  | alias = parse_alias (cfg, &r, tname); | 
|  | if (r == -1) | 
|  | break; | 
|  | } | 
|  | else if (strcmp (l_buffer, "export") == 0) | 
|  | { | 
|  | exps = parse_export (cfg, &r, tname); | 
|  | if (r == -1) | 
|  | break; | 
|  | } | 
|  | else | 
|  | { | 
|  | printError ("Unknown command %s in ,%s'\n", l_buffer, tname); | 
|  | while ((r = lex ()) != -1 && r != ';'); | 
|  | } | 
|  | r = lex (); | 
|  | } | 
|  | if (r != '}') | 
|  | { | 
|  | } | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static int | 
|  | parseTable (void) | 
|  | { | 
|  | char *table_name; | 
|  | int r = lex (); | 
|  |  | 
|  | if (r == ';') | 
|  | return 0; | 
|  |  | 
|  | switch (r) | 
|  | { | 
|  | case TOK_NAME: | 
|  | case TOK_STRING: | 
|  | table_name = strdup (l_buffer); | 
|  | break; | 
|  | case -1: | 
|  | return -1; | 
|  | default: | 
|  | printError ("Unexpected token.\n"); | 
|  | return 0; | 
|  | } | 
|  | r = lex (); | 
|  | if (r == '=') | 
|  | r = lex (); | 
|  | if (r != '{') | 
|  | { | 
|  | printError ("Missing '{' after ,%s'\n", table_name); | 
|  | free (table_name); | 
|  | return 0; | 
|  | } | 
|  | r = parseTableSub (table_name); | 
|  | if (r != '}') | 
|  | printError ("Missing '}' at end of ,%s'\n", table_name); | 
|  | free (table_name); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void | 
|  | parseStmt (void) | 
|  | { | 
|  | int r; | 
|  |  | 
|  | while ((r = parseTable ()) != -1) | 
|  | { | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | int | 
|  | genidl_read_config (const char *fname) | 
|  | { | 
|  | if (!fname) | 
|  | return -1; | 
|  | conf_fp = fopen (fname, "rb"); | 
|  | if (!conf_fp) | 
|  | return -1; | 
|  | l_buffer = (char *) malloc (129); | 
|  | if (!l_buffer) | 
|  | { | 
|  | fclose (conf_fp); | 
|  | return -1; | 
|  | } | 
|  | l_max = 128; | 
|  | l_cur = 0; | 
|  | l_buffer[0] = 0; | 
|  | line_no = 1; | 
|  | seen_eof = 0; | 
|  | parseStmt (); | 
|  | is_modified = 0; | 
|  | free (l_buffer); | 
|  | fclose (conf_fp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | genidl_save_config (const char *file) | 
|  | { | 
|  | FILE *fp; | 
|  | int ret; | 
|  |  | 
|  | if (!genidl_ismodified_config ()) | 
|  | return 1; | 
|  | if (!file) | 
|  | return 0; | 
|  | fp = fopen (file, "wb"); | 
|  | ret = !genidl_save_config_fp (fp); | 
|  | if (fp) | 
|  | fclose (fp); | 
|  | is_modified = 0; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int | 
|  | genidl_save_config_fp (FILE *fp) | 
|  | { | 
|  | sCfgLib *h = cfg_head; | 
|  | sCfgAlias *alias; | 
|  | sCfgItem *item; | 
|  |  | 
|  | if (!fp) | 
|  | return 1; | 
|  | fprintf (fp, "/* Configuration of genidl tool.  */\n"); | 
|  | if (!h) | 
|  | return 0; | 
|  | do { | 
|  | alias = h->alias; | 
|  | item = h->item; | 
|  | fprintf (fp, "\"%s\" = {\n", h->name); | 
|  | if (alias) | 
|  | { | 
|  | fprintf (fp,"  alias = {\n"); | 
|  | do { | 
|  | fprintf (fp, "    \"%s\"%s\n", alias->name, (alias->next != NULL ? "," : "")); | 
|  | alias = alias->next; | 
|  | } while (alias); | 
|  | fprintf (fp, "  };\n"); | 
|  | } | 
|  | if (item) | 
|  | { | 
|  | fprintf (fp, "  export = {\n"); | 
|  | do { | 
|  | fprintf (fp, "    \"%s\" = \"%s\";\n", item->name, item->type); | 
|  | item = item->next; | 
|  | } while (item); | 
|  | fprintf (fp, "  };\n"); | 
|  | } | 
|  | fprintf (fp, "};\n\n"); | 
|  | h = h->next; | 
|  | } while (h != NULL); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | genidl_ismodified_config (void) | 
|  | { | 
|  | return is_modified; | 
|  | } | 
|  |  | 
|  | int | 
|  | genidl_add_lib (const char *lib) | 
|  | { | 
|  | if (!lib || *lib == 0) | 
|  | return 0; | 
|  | if (gen_cfglib (lib)) | 
|  | return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | genidl_add_lib_alias (const char *lib, const char *alias) | 
|  | { | 
|  | sCfgLib *l; | 
|  | if (!lib || *lib == 0 || !alias || *alias == 0) | 
|  | return 0; | 
|  | l = gen_cfglib (lib); | 
|  | if (!l) | 
|  | return 0; | 
|  | if (gen_cfglib_alias (l, alias)) | 
|  | return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | genidl_add_lib_item (const char *lib, const char *name, const char *typ) | 
|  | { | 
|  | sCfgLib *l; | 
|  | if (!lib || *lib == 0 || !name || *name == 0 || !typ || *typ == 0) | 
|  | return 0; | 
|  | l = gen_cfglib (lib); | 
|  | if (!l) | 
|  | return 0; | 
|  | if (gen_cfglib_item (l, name, typ)) | 
|  | return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | const char * | 
|  | genidl_find_type (const char *lib, const char *name) | 
|  | { | 
|  | sCfgLib *l; | 
|  | sCfgItem *h; | 
|  | char *is_tlb; | 
|  |  | 
|  | if (!lib || *lib == 0) | 
|  | return NULL; | 
|  | is_tlb = strstr (lib, ".tlb"); | 
|  | if (is_tlb) | 
|  | { | 
|  | sCfgLib *r = cfg_head; | 
|  | while (r != NULL) | 
|  | { | 
|  | if (!strcmp (r->name, lib)) | 
|  | { | 
|  | sCfgAlias *a = r->alias; | 
|  | while (a != NULL) | 
|  | { | 
|  | const char *rs = genidl_find_type (a->name, name); | 
|  | if (rs != NULL) | 
|  | return rs; | 
|  | a = a->next; | 
|  | } | 
|  | } | 
|  | r = r->next; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  | l = has_cfglib (lib, 1); | 
|  | if (!l) | 
|  | return NULL; | 
|  | h = has_cfglib_item (l, name); | 
|  | if (!h) | 
|  | return NULL; | 
|  | return h->type; | 
|  | } | 
|  |  | 
|  | int | 
|  | genidl_del_lib_item (const char *lib) | 
|  | { | 
|  | sCfgLib *l; | 
|  | sCfgItem *h; | 
|  | if (!lib || *lib == 0) | 
|  | return 0; | 
|  | l = gen_cfglib (lib); | 
|  | if (!l) | 
|  | return 1; | 
|  | if (l->item == NULL) | 
|  | return 1; | 
|  | while ((h = l->item) != NULL) | 
|  | { | 
|  | l->item = h->next; | 
|  | if (h->type) | 
|  | free (h->type); | 
|  | free (h); | 
|  | } | 
|  | return 1; | 
|  | } |