Mercurial > mm7
diff lib/swig/swigwin-2.0.11/CCache/unify.c @ 1899:b3009adc0e2f
Adding swig, gitignore, hgignore
author | Nomad |
---|---|
date | Mon, 21 Oct 2013 10:42:27 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/swig/swigwin-2.0.11/CCache/unify.c Mon Oct 21 10:42:27 2013 +0200 @@ -0,0 +1,307 @@ +/* + Copyright (C) Andrew Tridgell 2002 + + 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 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + C/C++ unifier + + the idea is that changes that don't affect the resulting C code + should not change the hash. This is achieved by folding white-space + and other non-semantic fluff in the input into a single unified format. + + This unifier was design to match the output of the unifier in + compilercache, which is flex based. The major difference is that + this unifier is much faster (about 2x) and more forgiving of + syntactic errors. Continuing on syntactic errors is important to + cope with C/C++ extensions in the local compiler (for example, + inline assembly systems). +*/ + +#include "ccache.h" + +static char *s_tokens[] = { + "...", ">>=", "<<=", "+=", "-=", "*=", "/=", "%=", "&=", "^=", + "|=", ">>", "<<", "++", "--", "->", "&&", "||", "<=", ">=", + "==", "!=", ";", "{", "<%", "}", "%>", ",", ":", "=", + "(", ")", "[", "<:", "]", ":>", ".", "&", "!", "~", + "-", "+", "*", "/", "%", "<", ">", "^", "|", "?", + 0 +}; + +#define C_ALPHA 1 +#define C_SPACE 2 +#define C_TOKEN 4 +#define C_QUOTE 8 +#define C_DIGIT 16 +#define C_HEX 32 +#define C_FLOAT 64 +#define C_SIGN 128 + +static struct { + unsigned char type; + unsigned char num_toks; + char *toks[7]; +} tokens[256]; + +/* build up the table used by the unifier */ +static void build_table(void) +{ + unsigned char c; + int i; + static int done; + + if (done) return; + done = 1; + + memset(tokens, 0, sizeof(tokens)); + for (c=0;c<128;c++) { + if (isalpha(c) || c == '_') tokens[c].type |= C_ALPHA; + if (isdigit(c)) tokens[c].type |= C_DIGIT; + if (isspace(c)) tokens[c].type |= C_SPACE; + if (isxdigit(c)) tokens[c].type |= C_HEX; + } + tokens['\''].type |= C_QUOTE; + tokens['"'].type |= C_QUOTE; + tokens['l'].type |= C_FLOAT; + tokens['L'].type |= C_FLOAT; + tokens['f'].type |= C_FLOAT; + tokens['F'].type |= C_FLOAT; + tokens['U'].type |= C_FLOAT; + tokens['u'].type |= C_FLOAT; + + tokens['-'].type |= C_SIGN; + tokens['+'].type |= C_SIGN; + + for (i=0;s_tokens[i];i++) { + c = s_tokens[i][0]; + tokens[c].type |= C_TOKEN; + tokens[c].toks[tokens[c].num_toks] = s_tokens[i]; + tokens[c].num_toks++; + } +} + +/* buffer up characters before hashing them */ +static void pushchar(unsigned char c) +{ + static unsigned char buf[64]; + static int len; + + if (c == 0) { + if (len > 0) { + hash_buffer((char *)buf, len); + len = 0; + } + hash_buffer(NULL, 0); + return; + } + + buf[len++] = c; + if (len == 64) { + hash_buffer((char *)buf, len); + len = 0; + } +} + +/* hash some C/C++ code after unifying */ +static void unify(unsigned char *p, size_t size) +{ + size_t ofs; + unsigned char q; + int i; + + build_table(); + + for (ofs=0; ofs<size;) { + if (p[ofs] == '#') { + if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) { + do { + ofs++; + } while (ofs < size && p[ofs] != '\n'); + ofs++; + } else { + do { + pushchar(p[ofs]); + ofs++; + } while (ofs < size && p[ofs] != '\n'); + pushchar('\n'); + ofs++; + } + continue; + } + + if (tokens[p[ofs]].type & C_ALPHA) { + do { + pushchar(p[ofs]); + ofs++; + } while (ofs < size && + (tokens[p[ofs]].type & (C_ALPHA|C_DIGIT))); + pushchar('\n'); + continue; + } + + if (tokens[p[ofs]].type & C_DIGIT) { + do { + pushchar(p[ofs]); + ofs++; + } while (ofs < size && + ((tokens[p[ofs]].type & C_DIGIT) || p[ofs] == '.')); + if (ofs < size && (p[ofs] == 'x' || p[ofs] == 'X')) { + do { + pushchar(p[ofs]); + ofs++; + } while (ofs < size && (tokens[p[ofs]].type & C_HEX)); + } + if (ofs < size && (p[ofs] == 'E' || p[ofs] == 'e')) { + pushchar(p[ofs]); + ofs++; + while (ofs < size && + (tokens[p[ofs]].type & (C_DIGIT|C_SIGN))) { + pushchar(p[ofs]); + ofs++; + } + } + while (ofs < size && (tokens[p[ofs]].type & C_FLOAT)) { + pushchar(p[ofs]); + ofs++; + } + pushchar('\n'); + continue; + } + + if (tokens[p[ofs]].type & C_SPACE) { + do { + ofs++; + } while (ofs < size && (tokens[p[ofs]].type & C_SPACE)); + continue; + } + + if (tokens[p[ofs]].type & C_QUOTE) { + q = p[ofs]; + pushchar(p[ofs]); + do { + ofs++; + while (ofs < size-1 && p[ofs] == '\\') { + pushchar(p[ofs]); + pushchar(p[ofs+1]); + ofs+=2; + } + pushchar(p[ofs]); + } while (ofs < size && p[ofs] != q); + pushchar('\n'); + ofs++; + continue; + } + + if (tokens[p[ofs]].type & C_TOKEN) { + q = p[ofs]; + for (i=0;i<tokens[q].num_toks;i++) { + unsigned char *s = (unsigned char *)tokens[q].toks[i]; + int len = strlen((char *)s); + if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) { + int j; + for (j=0;s[j];j++) { + pushchar(s[j]); + ofs++; + } + pushchar('\n'); + break; + } + } + if (i < tokens[q].num_toks) { + continue; + } + } + + pushchar(p[ofs]); + pushchar('\n'); + ofs++; + } + pushchar(0); +} + + +/* hash a file that consists of preprocessor output, but remove any line + number information from the hash +*/ +int unify_hash(const char *fname) +{ +#ifdef _WIN32 + HANDLE file; + HANDLE section; + DWORD filesize_low; + char *map; + int ret = -1; + + file = CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); + if (file != INVALID_HANDLE_VALUE) { + filesize_low = GetFileSize(file, NULL); + if (!(filesize_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)) { + section = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL); + CloseHandle(file); + if (section != NULL) { + map = MapViewOfFile(section, FILE_MAP_READ, 0, 0, 0); + CloseHandle(section); + if (map != NULL) + ret = 0; + } + } + } + + if (ret == -1) { + cc_log("Failed to open preprocessor output %s\n", fname); + stats_update(STATS_PREPROCESSOR); + return -1; + } + + /* pass it through the unifier */ + unify((unsigned char *)map, filesize_low); + + UnmapViewOfFile(map); + + return 0; +#else + int fd; + struct stat st; + char *map; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd == -1 || fstat(fd, &st) != 0) { + cc_log("Failed to open preprocessor output %s\n", fname); + stats_update(STATS_PREPROCESSOR); + return -1; + } + + /* we use mmap() to make it easy to handle arbitrarily long + lines in preprocessor output. I have seen lines of over + 100k in length, so this is well worth it */ + map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (map == (char *)-1) { + cc_log("Failed to mmap %s\n", fname); + stats_update(STATS_PREPROCESSOR); + return -1; + } + close(fd); + + /* pass it through the unifier */ + unify((unsigned char *)map, st.st_size); + + munmap(map, st.st_size); + + return 0; +#endif +} +