/*************************************************************************** gb_table_temp.h (c) 2000-2013 BenoƮt Minisini 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 2, 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #define __TABLE_C #include #include #include #include #include "gb_common.h" #include "gb_error.h" #include "gb_alloc.h" #include "gb_limit.h" #include "gb_table.h" #define SYM(table, ind) (TABLE_get_symbol(table, ind)) #define SSYM(_symbol, _pos, _size) ((SYMBOL *)((char *)(_symbol) + (_pos) * (_size))) static char _buffer[MAX_SYMBOL_LEN + 1]; #if TABLE_USE_KEY static inline uint make_key(const char *sym, int len) { static void *jump[] = { &&__LEN_0, &&__LEN_1, &&__LEN_2, &&__LEN_3 }; const uchar *p = (uchar *)sym; if (len >= 4) return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; goto *jump[len]; __LEN_0: return 0; __LEN_1: return (p[0] << 24); __LEN_2: return (p[0] << 24) + (p[1] << 16); __LEN_3: return (p[0] << 24) + (p[1] << 16) + (p[2] << 8); } static inline uint make_key_ignore_case(const char *sym, int len) { static void *jump[] = { &&__LEN_0, &&__LEN_1, &&__LEN_2, &&__LEN_3 }; const uchar *p = (uchar *)sym; if (len >= 4) return (tolower(p[0]) << 24) + (tolower(p[1]) << 16) + (tolower(p[2]) << 8) + tolower(p[3]); goto *jump[len]; __LEN_0: return 0; __LEN_1: return (tolower(p[0]) << 24); __LEN_2: return (tolower(p[0]) << 24) + (tolower(p[1]) << 16); __LEN_3: return (tolower(p[0]) << 24) + (tolower(p[1]) << 16) + (tolower(p[2]) << 8); } #endif char TABLE_compare(const char *s1, int len1, const char *s2, int len2) { int i; int len = (len1 < len2) ? len1 : len2; register char c1; register char c2; for (i = 0; i < len; i++) { c1 = s1[i]; c2 = s2[i]; if (LIKELY(c1 > c2)) return 1; if (LIKELY(c1 < c2)) return -1; } if (LIKELY(len1 < len2)) return -1; else if (LIKELY(len1 > len2)) return 1; else return 0; } char TABLE_compare_ignore_case(const char *s1, int len1, const char *s2, int len2) { unsigned int len = (len1 < len2) ? len1 : len2; unsigned int i; int result; for (i = 0; len > 0; i++) { result = toupper(s1[i]) - toupper(s2[i]); if (LIKELY(result)) return result; // < 0 ? -1 : 1; len--; } if (LIKELY(len1 < len2)) return -1; else if (LIKELY(len1 > len2)) return 1; else return 0; } char TABLE_compare_ignore_case_len(const char *s1, int len1, const char *s2, int len2) { int result; if (LIKELY(len1 < len2)) return -1; else if (LIKELY(len1 > len2)) return 1; while (len1) { result = tolower(*s1++) - tolower(*s2++); if (LIKELY(result)) return result; // < 0 ? -1 : 1; --len1; } return 0; } static inline bool search(void *symbol, ushort *sort, int n_symbol, size_t size, const char *name, int len, int *index) { int pos, deb, fin; SYMBOL *sym; int l; int result; // must be an integer (or a short) because uchar - uchar may not fit in a char! const uchar *s1; const uchar *s2; #if TABLE_USE_KEY uint key = make_key(name, len); #endif pos = 0; deb = 0; fin = n_symbol; //ARRAY_count(table->symbol); for(;;) { if (UNLIKELY(deb >= fin)) { *index = deb; return FALSE; } pos = (deb + fin) >> 1; sym = SSYM(symbol, sort[pos], size); if (LIKELY(len < sym->len)) goto __B_LOWER; else if (LIKELY(len > sym->len)) goto __B_GREATER; #if TABLE_USE_KEY if (key < sym->key) goto __B_LOWER; if (key > sym->key) goto __B_GREATER; l = len - 4; if (l > 0) { s1 = (uchar *)name + 4; s2 = (uchar *)sym->name + 4; #else { l = len; s1 = (uchar *)name; s2 = (uchar *)sym->name; #endif for(;;) { result = *s1 - *s2; if (LIKELY(result < 0)) goto __B_LOWER; else if (LIKELY(result > 0)) goto __B_GREATER; if (UNLIKELY(--l == 0)) break; s1++; s2++; } } *index = pos; return TRUE; __B_LOWER: fin = pos; continue; __B_GREATER: deb = pos + 1; continue; } } static inline bool search_ignore_case(void *symbol, ushort *sort, int n_symbol, size_t size, const char *name, int len, int *index) { int pos, deb, fin; SYMBOL *sym; int l; int result; // must be an integer (or a short) because uchar - uchar may not fit in a char! const uchar *s1; const uchar *s2; #if TABLE_USE_KEY uint key = make_key_ignore_case(name, len); #endif pos = 0; deb = 0; fin = n_symbol; for(;;) { if (UNLIKELY(deb >= fin)) { *index = deb; return FALSE; } pos = (deb + fin) >> 1; sym = SSYM(symbol, sort[pos], size); if (LIKELY(len < sym->len)) goto __T_LOWER; else if (LIKELY(len > sym->len)) goto __T_GREATER; #if TABLE_USE_KEY if (key < sym->key) goto __T_LOWER; if (key > sym->key) goto __T_GREATER; l = len - 4; if (l > 0) { s1 = (uchar *)name + 4; s2 = (uchar *)sym->name + 4; #else { l = len; s1 = (uchar *)name; s2 = (uchar *)sym->name; #endif for(;;) { result = tolower(*s1) - tolower(*s2); if (LIKELY(result < 0)) goto __T_LOWER; else if (LIKELY(result > 0)) goto __T_GREATER; if (UNLIKELY(--l == 0)) break; s1++; s2++; } } *index = pos; return TRUE; __T_LOWER: fin = pos; continue; __T_GREATER: deb = pos + 1; continue; } } const char *TABLE_get_symbol_name(TABLE *table, int index) { if (UNLIKELY((index < 0) || (index >= ARRAY_count(table->symbol)))) strcpy(_buffer, "?"); else SYMBOL_get_name(SYM(table, index)); return _buffer; } const char *TABLE_get_symbol_name_suffix(TABLE *table, int index, const char* suffix) { SYMBOL *sym; if (UNLIKELY((index < 0) || (index >= ARRAY_count(table->symbol)))) return "?"; sym = SYM(table, index); if ((sym->len + strlen(suffix)) > MAX_SYMBOL_LEN) return "?"; SYMBOL_get_name(sym); strcat(_buffer, suffix); return _buffer; } void TABLE_create_static(TABLE *table, size_t size, TABLE_FLAG flag) { ARRAY_create_with_size(&table->symbol, Max(size, sizeof(SYMBOL)), 64); ARRAY_create_with_size(&table->sort, sizeof(ushort), 64); table->flag = flag; } void TABLE_create(TABLE **result, size_t size, TABLE_FLAG flag) { TABLE *table; ALLOC(&table, sizeof(TABLE)); TABLE_create_static(table, size, flag); *result = table; } void TABLE_create_from(TABLE **result, size_t size, const char *sym_list[], TABLE_FLAG flag) { TABLE *table; int index; TABLE_create(&table, size, flag); while (*sym_list) { TABLE_add_symbol(table, *sym_list, strlen(*sym_list), &index); sym_list++; } *result = table; } void TABLE_delete_static(TABLE *table) { ARRAY_delete(&table->symbol); ARRAY_delete(&table->sort); } void TABLE_delete(TABLE **p_table) { if (*p_table) { TABLE_delete_static(*p_table); FREE(p_table); } } bool TABLE_find_symbol(TABLE *table, const char *name, int len, int *index) { int ind; bool result; SYMBOL *tsym; int count; size_t size; tsym = table->symbol; count = ARRAY_count(tsym); size = ARRAY_size(tsym); if (table->flag) result = search_ignore_case(tsym, table->sort, count, size, name, len, &ind); else result = search(tsym, table->sort, count, size, name, len, &ind); if (result) *index = table->sort[ind]; return result; } #if 0 void TABLE_add_new_symbol_without_sort(TABLE *table, const char *name, int len, int sort, SYMBOL **symbol, int *index) { SYMBOL *sym; int count; len = Min(len, MAX_SYMBOL_LEN); count = ARRAY_count(table->symbol); sym = (SYMBOL *)ARRAY_add_void_size(&table->symbol); sym->name = (char *)name; sym->len = len; *((ushort *)ARRAY_add(&table->sort)) = sort; if (symbol) *symbol = sym; /*&table->symbol[ind];*/ if (index) *index = count; } #endif bool TABLE_add_symbol(TABLE *table, const char *name, int len, int *index) { int ind; bool result; SYMBOL *sym; int count; size_t size; /*len = Min(len, MAX_SYMBOL_LEN);*/ //len = Min(len, 65535); count = ARRAY_count(table->symbol); size = ARRAY_size(table->symbol); if (table->flag) result = search_ignore_case(table->symbol, table->sort, count, size, name, len, &ind); else result = search(table->symbol, table->sort, count, size, name, len, &ind); if (!result) { sym = (SYMBOL *)ARRAY_add_void_size(&table->symbol); sym->name = (char *)name; sym->len = len; #if TABLE_USE_KEY sym->key = table->flag ? make_key_ignore_case(name, len) : make_key(name, len); #endif /* printf("TABLE_add_symbol: %.*s %d %d\n", len, name, ((CLASS_SYMBOL *)sym)->global.type, ((CLASS_SYMBOL *)sym)->local.type); */ //s1 = (SYMBOL *)((char *)table->symbol + count * size); ARRAY_add(&table->sort); if (count > ind) memmove(&table->sort[ind + 1], &table->sort[ind], sizeof(ushort) * (count - ind)); table->sort[ind] = (ushort)count; ind = count; } else ind = table->sort[ind]; //SYM(table, ind)->sort; /*table->symbol[ind].sort;*/ *index = ind; return result; } void TABLE_print(TABLE *table, bool sort) { int i; SYMBOL *sym; fprintf(stderr, "capacity %i\n", ARRAY_count(table->symbol)); /* for (i = 0; i < ARRAY_count(table->symbol); i++) { sym = SYM(table, i); printf("%*s (%li) ", (int)sym->len, sym->name, sym->sort); } printf("\n"); */ for (i = 0; i < ARRAY_count(table->symbol); i++) { if (sort) { sym = SYM(table, table->sort[i]); fprintf(stderr, "%.*s ", (int)sym->len, sym->name); } else { sym = SYM(table, i); fprintf(stderr, "%d %.*s ", (int)table->sort[i], (int)sym->len, sym->name); } //if ((i > 0) && (!(i & 0xF))) // fprintf(stderr, "\n"); } fprintf(stderr, "\n\n"); } void TABLE_copy_symbol_with_prefix(TABLE *table, int ind_src, char prefix, int *index) { SYMBOL *sym; char *ptr; sym = TABLE_get_symbol(table, ind_src); ptr = (char *)sym->name - 1; if (UNLIKELY(!isspace((unsigned char)*ptr))) ERROR_panic("Cannot add prefix to symbol"); *ptr = prefix; TABLE_add_symbol(table, ptr, sym->len + 1, index); } SYMBOL *TABLE_get_symbol_sort(TABLE *table, int index) { return TABLE_get_symbol(table, table->sort[index]); } // Symbol tables with no TABLE structure int SYMBOL_find(void *symbol, ushort *sort, int n_symbol, size_t s_symbol, int flag, const char *name, int len, const char *prefix) { int index; int len_prefix; if (UNLIKELY(prefix != NULL)) { len_prefix = strlen(prefix); if (UNLIKELY((len + len_prefix) > MAX_SYMBOL_LEN)) ERROR_panic("SYMBOL_find: prefixed symbol too long"); strcpy(_buffer, prefix); strcpy(&_buffer[len_prefix], name); len += len_prefix; name = _buffer; } if (flag) { if (search_ignore_case(symbol, sort, n_symbol, s_symbol, name, len, &index)) return sort[index]; } else { if (search(symbol, sort, n_symbol, s_symbol, name, len, &index)) return sort[index]; } return NO_SYMBOL; } const char *SYMBOL_get_name(SYMBOL *sym) { int len; len = Min(MAX_SYMBOL_LEN, sym->len); memcpy(_buffer, sym->name, len); _buffer[len] = 0; return _buffer; } #if TABLE_USE_KEY void SYMBOL_compute_keys(void *symbol, int n_symbol, size_t s_symbol, int flag) { int i; SYMBOL *sym; if (flag) { for (i = 0; i < n_symbol; i++) { sym = SSYM(symbol, i, s_symbol); sym->key = make_key_ignore_case(sym->name, sym->len); } } else { for (i = 0; i < n_symbol; i++) { sym = SSYM(symbol, i, s_symbol); sym->key = make_key(sym->name, sym->len); } } } #endif