wine/tools/winedump/symbol.c
2008-01-18 12:52:09 +01:00

309 lines
7.1 KiB
C

/*
* Symbol functions
*
* Copyright 2000 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include "winedump.h"
/* Items that are swapped in arguments after the symbol structure
* has been populated
*/
static const char * const swap_after[] =
{
"\r", " ", /* Remove whitespace, normalise pointers and brackets */
"\t", " ",
" ", " ",
" * ", " *",
"* *", "**",
"* ", "*",
" ,", ",",
"( ", "(",
" )", ")",
"wchar_t", "WCHAR", /* Help with Unicode compiles */
"wctype_t", "WCHAR",
"wint_t", "WCHAR",
NULL, NULL
};
/* Items containing these substrings are assumed to be wide character
* strings, unless they contain more that one '*'. A preceding 'LP'
* counts as a '*', so 'LPWCSTR *' is a pointer, not a string
*/
static const char * const wide_strings[] =
{
"WSTR", "WCSTR", NULL
};
/* Items containing these substrings are assumed to be wide characters,
* unless they contain one '*'. A preceding 'LP' counts as a '*',
* so 'WCHAR *' is string, while 'LPWCHAR *' is a pointer
*/
static const char * const wide_chars[] =
{
"WCHAR", NULL
};
/* Items containing these substrings are assumed to be ASCII character
* strings, as above
*/
static const char * const ascii_strings[] =
{
"STR", "CSTR", NULL
};
/* Items containing these substrings are assumed to be ASCII characters,
* as above
*/
static const char * const 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 * const known_longs[] =
{
"char", "CHAR", "float", "int", "INT", "short", "SHORT", "long", "LONG",
"WCHAR", "BOOL", "bool", "INT16", "WORD", "DWORD", NULL
};
int symbol_init(parsed_symbol* sym, const char* name)
{
memset(sym, 0, sizeof(parsed_symbol));
sym->symbol = strdup(name);
return 0;
}
/*******************************************************************
* 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);
free (sym->return_text);
free (sym->function_name);
for (i = sym->argc - 1; i >= 0; i--)
{
free (sym->arg_text [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_get_call_convention
*
* Return the calling convention of a symbol
*/
const char *symbol_get_call_convention(const parsed_symbol *sym)
{
int call = sym->flags ? sym->flags : CALLING_CONVENTION;
assert (sym);
assert (sym->symbol);
if (call & SYM_CDECL)
return "cdecl";
return "stdcall";
}
/*******************************************************************
* symbol_get_spec_type
*
* Get the .spec file text for a symbol's 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 * const *tab;
int ptrs = 0;
while (*iter && isspace(*iter))
iter++;
if (*iter == 'P' || *iter == 'H')
ptrs++; /* Win32 type pointer */
iter = string;
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 < 2) 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 < 2) 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, "float") || strstr (string, "FLOAT"))
return ARG_FLOAT;
if (strstr (string, "void") || 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 * const *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 */
}