| /* |
| * Symbol functions |
| * |
| * Copyright 2000 Jon Griffiths |
| */ |
| #include "specmaker.h" |
| |
| |
| /* Items that are swapped in arguments after the symbol structure |
| * has been populated |
| */ |
| static const char *swap_after[] = |
| { |
| "\r", " ", /* Remove whitespace, normalise pointers and brackets */ |
| "\t", " ", |
| " ", " ", |
| " * ", " *", |
| "* *", "**", |
| "* ", "*", |
| " ,", ",", |
| "( ", "(", |
| " )", ")", |
| "wchar_t", "WCHAR", /* Help with Unicode compliles */ |
| "wctype_t", "WCHAR", |
| "wint_t", "WCHAR", |
| "unsigned __int64", "__uint64", /* Wine doesn't cope with unsigned i64's */ |
| NULL, NULL |
| }; |
| |
| |
| /* Items containing these substrings are assumed to be wide character |
| * strings, unless they contain more that one '*'. A preceeding 'LP' |
| * counts as a '*', so 'LPWCSTR *' is a pointer, not a string |
| */ |
| static const char *wide_strings[] = |
| { |
| "WSTR", "WCSTR", NULL |
| }; |
| |
| /* Items containing these substrings are assumed to be wide characters, |
| * unless they contain one '*'. A preceeding 'LP' counts as a '*', |
| * so 'WCHAR *' is string, while 'LPWCHAR *' is a pointer |
| */ |
| static const char *wide_chars[] = |
| { |
| "WCHAR", NULL |
| }; |
| |
| /* Items containing these substrings are assumed to be ASCII character |
| * strings, as above |
| */ |
| static const char *ascii_strings[] = |
| { |
| "STR", "CSTR", NULL |
| }; |
| |
| |
| /* Items containing these substrings are assumed to be ASCII characters, |
| * as above |
| */ |
| static const char *ascii_chars[] = |
| { |
| "CHAR", "char", NULL |
| }; |
| |
| /* Any type other than the following will produce a FIXME warning with -v |
| * when mapped to a long, to allow fixups |
| */ |
| static const char *known_longs[] = |
| { |
| "char", "CHAR", "float", "int", "INT", "short", "SHORT", "long", "LONG", |
| "WCHAR", "BOOL", "bool", "INT16", NULL |
| }; |
| |
| |
| /******************************************************************* |
| * symbol_clear |
| * |
| * Free the memory used by a symbol and initialise it |
| */ |
| void symbol_clear(parsed_symbol *sym) |
| { |
| int i; |
| |
| assert (sym); |
| assert (sym->symbol); |
| |
| free (sym->symbol); |
| |
| if (sym->return_text) |
| free (sym->return_text); |
| |
| if (sym->calling_convention) |
| free (sym->calling_convention); |
| |
| if (sym->function_name) |
| free (sym->function_name); |
| |
| for (i = sym->argc - 1; i >= 0; i--) |
| { |
| if (sym->arg_text [i]) |
| free (sym->arg_text [i]); |
| if (sym->arg_name [i]) |
| free (sym->arg_name [i]); |
| } |
| memset (sym, 0, sizeof (parsed_symbol)); |
| } |
| |
| |
| /******************************************************************* |
| * symbol_is_valid_c |
| * |
| * Check if a symbol is a valid C identifier |
| */ |
| int symbol_is_valid_c(const parsed_symbol *sym) |
| { |
| char *name; |
| |
| assert (sym); |
| assert (sym->symbol); |
| |
| name = sym->symbol; |
| |
| while (*name) |
| { |
| if (!isalnum (*name) && *name != '_') |
| return 0; |
| name++; |
| } |
| return 1; |
| } |
| |
| |
| /******************************************************************* |
| * symbol_is_cdecl |
| * |
| * Check if a symbol is cdecl |
| */ |
| int symbol_is_cdecl(const parsed_symbol *sym) |
| { |
| assert (sym); |
| assert (sym->symbol); |
| |
| if (sym->calling_convention && (strstr (sym->calling_convention, "cdecl") |
| || strstr (sym->calling_convention, "CDECL"))) |
| return 1; |
| else if (!sym->calling_convention) |
| return globals.do_cdecl; |
| return 0; |
| } |
| |
| |
| /******************************************************************* |
| * symbol_get_spec_type |
| * |
| * Get the .spec file text for a symbols argument |
| */ |
| const char *symbol_get_spec_type (const parsed_symbol *sym, size_t arg) |
| { |
| assert (arg < sym->argc); |
| switch (sym->arg_type [arg]) |
| { |
| case ARG_STRING: return "str"; |
| case ARG_WIDE_STRING: return "wstr"; |
| case ARG_POINTER: return "ptr"; |
| case ARG_DOUBLE: return "double"; |
| case ARG_STRUCT: |
| case ARG_FLOAT: |
| case ARG_LONG: return "long"; |
| } |
| assert (0); |
| return NULL; |
| } |
| |
| |
| /******************************************************************* |
| * symbol_get_type |
| * |
| * Get the ARG_ constant for a type string |
| */ |
| int symbol_get_type (const char *string) |
| { |
| const char *iter = string; |
| const char **tab; |
| int ptrs = 0; |
| |
| while (*iter) |
| { |
| if (*iter == '*' || (*iter == 'L' && iter[1] == 'P') |
| || (*iter == '[' && iter[1] == ']')) |
| ptrs++; |
| if (ptrs > 1) |
| return ARG_POINTER; |
| iter++; |
| } |
| |
| /* 0 or 1 pointer */ |
| tab = wide_strings; |
| while (*tab++) |
| if (strstr (string, tab[-1])) |
| { |
| if (!ptrs) return ARG_WIDE_STRING; |
| else return ARG_POINTER; |
| } |
| tab = wide_chars; |
| while (*tab++) |
| if (strstr (string, tab[-1])) |
| { |
| if (!ptrs) return ARG_LONG; |
| else return ARG_WIDE_STRING; |
| } |
| tab = ascii_strings; |
| while (*tab++) |
| if (strstr (string, tab[-1])) |
| { |
| if (!ptrs) return ARG_STRING; |
| else return ARG_POINTER; |
| } |
| tab = ascii_chars; |
| while (*tab++) |
| if (strstr (string, tab[-1])) |
| { |
| if (!ptrs) return ARG_LONG; |
| else { |
| if (!strstr (string, "unsigned")) /* unsigned char * => ptr */ |
| return ARG_STRING; |
| } |
| } |
| |
| if (ptrs) |
| return ARG_POINTER; /* Pointer to some other type */ |
| |
| /* No pointers */ |
| if (strstr (string, "double")) |
| return ARG_DOUBLE; |
| |
| if (strstr (string, "void")) |
| return ARG_VOID; |
| |
| if (strstr (string, "struct") || strstr (string, "union")) |
| return ARG_STRUCT; /* Struct by value, ugh */ |
| |
| if (VERBOSE) |
| { |
| int known = 0; |
| |
| tab = known_longs; |
| while (*tab++) |
| if (strstr (string, tab[-1])) |
| { |
| known = 1; |
| break; |
| } |
| /* Unknown types passed by value can be 'grep'ed out for fixup later */ |
| if (!known) |
| printf ("/* FIXME: By value type: Assumed 'int' */ typedef int %s;\n", |
| string); |
| } |
| return ARG_LONG; |
| } |
| |
| |
| /******************************************************************* |
| * symbol_clean_string |
| * |
| * Make a type string more Wine-friendly. Logically const :-) |
| */ |
| void symbol_clean_string (const char *string) |
| { |
| const char **tab = swap_after; |
| char *str = (char *)string; |
| |
| #define SWAP(i, p, x, y) do { i = p; while ((i = str_replace (i, x, y))); } while(0) |
| |
| while (tab [0]) |
| { |
| char *p; |
| SWAP (p, str, tab [0], tab [1]); |
| tab += 2; |
| } |
| if (str [strlen (str) - 1] == ' ') |
| str [strlen (str) - 1] = '\0'; /* no trailing space */ |
| |
| if (*str == ' ') |
| memmove (str, str + 1, strlen (str)); /* No leading spaces */ |
| } |