| Index: experimental/LightSymbolsUtil/Callstacker/Callstacker/Callstacker.cpp
|
| diff --git a/experimental/LightSymbolsUtil/Callstacker/Callstacker/Callstacker.cpp b/experimental/LightSymbolsUtil/Callstacker/Callstacker/Callstacker.cpp
|
| deleted file mode 100644
|
| index 348e6572dc95088533a9e0034324935a2037ae44..0000000000000000000000000000000000000000
|
| --- a/experimental/LightSymbolsUtil/Callstacker/Callstacker/Callstacker.cpp
|
| +++ /dev/null
|
| @@ -1,673 +0,0 @@
|
| -// Callstacker.cpp : Defines the entry point for the console application.
|
| -//
|
| -
|
| -#include "stdafx.h"
|
| -
|
| -#include <string>
|
| -#include <map>
|
| -#include <vector>
|
| -
|
| -using namespace std;
|
| -
|
| -// can't delete, only add files repository!
|
| -class SkSourceDb {
|
| -public:
|
| - SkSourceDb(const char* szBaseSrcPath, const char* szLightSymbolsDbFile) {
|
| - this->baseSrcPath = szBaseSrcPath;
|
| - this->lightSymbolsDbFile = szLightSymbolsDbFile;
|
| - nextId = 1;
|
| - }
|
| -
|
| - const string& getBaseSrcPath() const {
|
| - return baseSrcPath;
|
| - }
|
| -
|
| - string GetStoredFilename(const string& filename) {
|
| - string base = filename.substr(0, baseSrcPath.length());
|
| - if (base != baseSrcPath) {
|
| - return "";
|
| - }
|
| -
|
| - string relative = filename.substr(baseSrcPath.length());
|
| - char tmp[10000];
|
| - strcpy(tmp, relative.c_str()); // insecure
|
| - char* sz = tmp;
|
| - while (*sz) {
|
| - if (*sz == '\\') *sz = '/';
|
| - sz++;
|
| - }
|
| - sz = tmp;
|
| - if (*sz == '/') sz++;
|
| -
|
| - return string(sz);
|
| - }
|
| -
|
| - int obtainFileId(const string& filename) {
|
| - string stored = GetStoredFilename(filename);
|
| - if (stored.empty()) {
|
| - return -1;
|
| - }
|
| -
|
| - if (filenames.find(stored) == filenames.end()) {
|
| - int id = nextId;
|
| - nextId++;
|
| - filenames[stored] = id;
|
| - return id;
|
| - } else {
|
| - return filenames[stored];
|
| - }
|
| - }
|
| -
|
| - static void Load(char* szFileName, SkSourceDb** ret, const char* whereToSave, const char* szBaseSrcPath) {
|
| - char szLine[10000];
|
| - FILE* file = fopen(szFileName, "rt");
|
| - if (file == NULL) {
|
| - *ret = NULL;
|
| - return;
|
| - }
|
| -
|
| - const char* trimed;
|
| - SkSourceDb* db = new SkSourceDb(szBaseSrcPath, whereToSave == NULL ? szFileName : whereToSave);
|
| -
|
| - map<int, string> ids;
|
| - int id;
|
| - while (true) {
|
| - id = -1;
|
| - if (fscanf(file, "%i", &id) == 0) break;
|
| - if (id == -1) break;
|
| - *szLine = '\0';
|
| - fgets(szLine, 10000, file);
|
| - trimed = trim(szLine);
|
| -
|
| - if (id < 0 || ids[id] != "") {
|
| - printf("fatal error: duplicate value for id = %i, existing = \"%s\", new = \"%s\"\n", id, ids[id].c_str(), trimed);
|
| - exit(-1);
|
| - }
|
| -
|
| - if (trimed == NULL || *trimed == '\0') {
|
| - printf("fatal error: no valuefor id = %i\n", id);
|
| - exit(-1);
|
| - }
|
| -
|
| - if (db->filenames.find(trimed) != db->filenames.end()) {
|
| - printf("fatal error: duplicate id for same file: file = %s, existing id = %i, new id = %i\n", trimed, db->filenames[trimed], id);
|
| -// exit(-1);
|
| - }
|
| -
|
| - string value = trimed;
|
| - ids[id] = value;
|
| - db->filenames[value] = id;
|
| - if (db->nextId <= id) {
|
| - db->nextId = id + 1;
|
| - }
|
| - }
|
| -
|
| - *ret = db;
|
| - }
|
| -
|
| - // dumb comit, smarter: use append
|
| - void commit() {
|
| - save(lightSymbolsDbFile.c_str());
|
| - }
|
| -
|
| -private:
|
| -
|
| - static const char* trim(char* sz) {
|
| - if (sz == NULL) return NULL;
|
| -
|
| - while (*sz == ' ' || *sz == '\t' || *sz == '\r' || *sz == '\n' || *sz == ',')
|
| - sz++;
|
| -
|
| - if (*sz == '\0') return sz;
|
| -
|
| - int len = strlen(sz);
|
| - char* start = sz;
|
| - sz = sz + (len - 1);
|
| -
|
| - while (sz >= start && (*sz == ' ' || *sz == '\t' || *sz == '\r' || *sz == '\n' || *sz == ',')) {
|
| - *sz = '\0';
|
| - sz--;
|
| - }
|
| -
|
| - return start;
|
| - }
|
| -
|
| - void save(const char* szFilename) {
|
| - char szLine[10000];
|
| - FILE* file = fopen(szFilename, "wt");
|
| -
|
| - map<string, int>::const_iterator itr;
|
| -
|
| - for(itr = filenames.begin(); itr != filenames.end(); ++itr){
|
| - fprintf(file, "%i, %s\n", (*itr).second, (*itr).first.c_str());
|
| - }
|
| - fclose(file);
|
| - }
|
| -
|
| - string baseSrcPath;
|
| - string lightSymbolsDbFile;
|
| - map<string, int> filenames;
|
| - int nextId;
|
| -};
|
| -
|
| -SkSourceDb* source_db = NULL;
|
| -
|
| -bool endsWith(const char* who, const char* what) {
|
| - int a = strlen(who);
|
| - int b = strlen(what);
|
| - return stricmp(who + a - b, what) == 0; // insecure
|
| -}
|
| -
|
| -bool sourceFile(const char* szFileName) {
|
| - return endsWith(szFileName, ".h") || endsWith(szFileName, ".c") || endsWith(szFileName, ".cpp") || endsWith(szFileName, ".cc");
|
| -}
|
| -
|
| -// "
|
| -// //
|
| -// /*
|
| -class CppState {
|
| -public:
|
| -
|
| - CppState() : line(1), inComment(false), inLineComment(false), inDoubleQuote(false), inSingleQuote(false), isEscaping(false), commentEnding(false), commentMightBeStarting(false) {
|
| - }
|
| -
|
| - void apply(int ch) {
|
| - if (ch == '\n') {
|
| - line++;
|
| - if (inLineComment) inLineComment = false;
|
| - }
|
| -
|
| - if (inLineComment) {
|
| - return;
|
| - }
|
| -
|
| - if (commentMightBeStarting) {
|
| - commentMightBeStarting = false;
|
| - if (ch == '*') {
|
| - inComment = true;
|
| - } else if (ch == '/') {
|
| - inLineComment = true;
|
| - } else {
|
| - add('/');//previously we has / but was not pushed on tokens
|
| - newToken();//
|
| - }
|
| - }
|
| -
|
| - if (inSingleQuote) {
|
| - if (isEscaping)
|
| - isEscaping = false;
|
| - else if (ch == '\\')
|
| - isEscaping = true;
|
| - else if (ch == '\'') {
|
| - inSingleQuote = false;
|
| - newToken();
|
| - pushToken("__SINGLE_QUOTE__");
|
| - newToken();
|
| - }
|
| -
|
| - return;
|
| - } else if (inDoubleQuote) {
|
| - if (isEscaping)
|
| - isEscaping = false;
|
| - else if (ch == '\\')
|
| - isEscaping = true;
|
| - else if (ch == '\"') {
|
| - inDoubleQuote = false;
|
| - newToken();
|
| - pushToken("__DOUBLE_QUOTE__");
|
| - newToken();
|
| - }
|
| -
|
| - return;
|
| - } else if (inComment) {
|
| - if (ch == '*') {
|
| - commentEnding = true;
|
| - } else if (ch == '/') {
|
| - inComment = false;
|
| - commentEnding = false;
|
| - } else {
|
| - commentEnding = false;
|
| - }
|
| -
|
| - return;
|
| - }
|
| -
|
| - switch (ch) {
|
| - case '\'':
|
| - newToken();
|
| - inSingleQuote = true;
|
| - return;
|
| -
|
| - case '\"':
|
| - newToken();
|
| - inDoubleQuote = true;
|
| - return;
|
| -
|
| - case '/':
|
| - newToken();
|
| - commentMightBeStarting = true;
|
| - return;
|
| - }
|
| -
|
| - if (isspace(ch)) {
|
| - newToken();
|
| - } else if (tokenDelimiter(ch)) {
|
| - newToken();
|
| - if (isSingleCharToken(ch)) {
|
| - add(ch);
|
| - newToken();
|
| - }
|
| - } else if (isTokenable(ch)) {
|
| - add(ch);
|
| - } else {
|
| - printf("undexpected ... %c", (char)ch);
|
| - }
|
| - }
|
| -
|
| - bool enteredFunction() {
|
| - if (inComment || inLineComment || inDoubleQuote || inSingleQuote || commentMightBeStarting) {
|
| - return false;
|
| - }
|
| -
|
| - if (tokens.size() == 0) {
|
| - return false;
|
| - }
|
| -
|
| - if (tokens[tokens.size() - 1] != "{") {
|
| - return false;
|
| - }
|
| -
|
| - int i = tokens.size() - 2;
|
| -
|
| - bool foundCloseBraket = false;
|
| - int innerBrakets = 0;
|
| - bool foundOpenBraket = false;
|
| - int iName = -1;
|
| -
|
| - while (i >= 0) {
|
| - string t_i = tokens[i]; // debugging sucks!
|
| -
|
| - if (!foundCloseBraket && (tokens[i] == "enum"
|
| - || tokens[i] == "struct"
|
| - || tokens[i] == "class"
|
| - || tokens[i] == "namespace"
|
| - || tokens[i] == "public"
|
| - || tokens[i] == "private"
|
| - || tokens[i] == "protected"
|
| - || tokens[i] == "__asm"
|
| - || tokens[i] == "catch"
|
| - || tokens[i] == "__except"
|
| - )) {
|
| - return false;
|
| - }
|
| -
|
| - if (tokens[i] == ")") {
|
| - if (foundCloseBraket)
|
| - innerBrakets++;
|
| - else if (i >= 3 && tokens[i - 1] == "." && tokens[i - 2] == "." && tokens[i - 3] == ".") {
|
| - i -= 3;
|
| - }
|
| - foundCloseBraket = true;
|
| - } else if (tokens[i] == "(" && innerBrakets > 0) {
|
| - innerBrakets--;
|
| - } else if (tokens[i] == "(" && innerBrakets == 0) {
|
| - foundOpenBraket = true;
|
| - i--; if ( i < 0) return false;
|
| - string name = tokens[i];
|
| - iName = i;
|
| -
|
| - if (name == "if" || name == "while" || name == "switch"|| name == "for") {
|
| - return false;
|
| - }
|
| -
|
| - if (!CouldBeFunctionName(name)) return false;
|
| - if (i >= 6 && tokens[i - 1] == ":" && tokens[i - 2] == ":" && CouldBeClassnName(tokens[i - 3]) && tokens[i - 4] == ":" && tokens[i - 5] == ":" && CouldBeClassnName(tokens[i - 6])) {
|
| - name = tokens[i - 6] + "::" + tokens[i - 3] + "::" + name;
|
| - iName = i - 6;
|
| - if (i >= 7 && (tokens[i - 7] == ":" || tokens[i-7] == ",")) {
|
| - i -= 7 + 1;
|
| - name = "";
|
| - foundCloseBraket = false;
|
| - foundOpenBraket = false;
|
| - innerBrakets = 0;
|
| - continue;
|
| - }
|
| - }
|
| - else if (i >= 3 && tokens[i - 1] == ":" && tokens[i - 2] == ":" && CouldBeClassnName(tokens[i - 3])) {
|
| - name = tokens[i - 3] + "::" + name;
|
| - iName = i - 3;
|
| - if (i >= 4 && (tokens[i - 4] == ":" || tokens[i-4] == ",")) {
|
| - i -= 4 + 1;
|
| - name = "";
|
| - foundCloseBraket = false;
|
| - foundOpenBraket = false;
|
| - innerBrakets = 0;
|
| - continue;
|
| - }
|
| - }
|
| - else if (i >= 1 && (tokens[i - 1] == ":" || tokens[i-1] == ",")) {
|
| - i -= 1 + 1;
|
| - name = "";
|
| - foundCloseBraket = false;
|
| - foundOpenBraket = false;
|
| - innerBrakets = 0;
|
| - continue;
|
| - }
|
| -
|
| - if (name == "") {
|
| - return false;
|
| - }
|
| -
|
| - if (iName >= 2 && tokens[iName - 2] == "#" && tokens[iName - 1] == "define") {
|
| - return false;
|
| - }
|
| -
|
| - if (iName >= 1 && (tokens[i - 1] == "enum"
|
| - || tokens[i - 1] == "struct"
|
| - || tokens[i - 1] == "class"
|
| - || tokens[i - 1] == "namespace"
|
| - || tokens[i - 1] == "public"
|
| - || tokens[i - 1] == "private"
|
| - || tokens[i - 1] == "protected"
|
| - || tokens[i - 1] == "__asm"
|
| - || tokens[i - 1] == "if"
|
| - || tokens[i - 1] == "while"
|
| - || tokens[i - 1] == "for"
|
| - || tokens[i - 1] == "switch"
|
| - || tokens[i - 1] == "!"
|
| - )) {
|
| - return false;
|
| - }
|
| -
|
| - int k = 10;
|
| - i = iName - 2;
|
| - bool isInline = false;// heuristic for inline functions
|
| - while (k > 0 && i >= 0) {
|
| - if (tokens[i] == "inline") {
|
| - isInline = true;
|
| - break;
|
| - }
|
| - if (tokens[i] == ";" || tokens[i] == "{" || tokens[i] == "}") {
|
| - break;
|
| - }
|
| - i--;
|
| - k--;
|
| - }
|
| -
|
| - if (isInline) return false; //do not trace inline functions
|
| -
|
| - lastFunctionName = name;
|
| - return true;
|
| - } else {
|
| - if (!foundCloseBraket) {
|
| - if (!IgnorableFunctionModifier(tokens[i])) {
|
| - return false;
|
| - }
|
| - } else {
|
| - if (!IgnorableFunctionParameter(tokens[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| -
|
| - i--;
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - const char* functionName() {
|
| - return lastFunctionName.c_str();
|
| - }
|
| -
|
| - int lineNumber() {
|
| - return line;
|
| - }
|
| -
|
| -private:
|
| -
|
| - bool CouldBeFunctionName(const string& str) {
|
| - if (str.empty()) return false;
|
| - if (!isalpha(str[0]) && str[0] != '_' && str[0] != '~' && str[0] != ':') return false;
|
| - for (int i = 1; i < str.length(); i++) {
|
| - if (!isalpha(str[i]) && !isdigit(str[i]) && str[i] != '_' && str[i] != ':') return false;
|
| - }
|
| -
|
| - return true;
|
| - }
|
| -
|
| - bool isNumber(const string& str) {
|
| - if (str.empty()) return false;
|
| - for (int i = 0; i < str.length(); i++) {
|
| - if (!isdigit(str[i]) && str[i] != '.' && str[i] != 'x' && str[i] != 'X' && str[i] != 'e' && str[i] != 'E') return false;
|
| - }
|
| -
|
| - return true;
|
| - }
|
| -
|
| -
|
| - bool isOperator(const string& str) {
|
| - if (str.empty()) return false;
|
| - for (int i = 1; i < str.length(); i++) {
|
| - switch (str[i]) {
|
| - case '<':
|
| - case '>':
|
| - case '=':
|
| - case '+':
|
| - case '-':
|
| - case '*':
|
| - case '/':
|
| - case '(':
|
| - case ')':
|
| - case '[':
|
| - case ']':
|
| - case '!':
|
| - case '|':
|
| - case '&':
|
| - case '^':
|
| - case '%':
|
| - break;
|
| - default:
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - return true;
|
| - }
|
| -
|
| - bool CouldBeClassnName(const string& str) {
|
| - return CouldBeFunctionName(str);
|
| - }
|
| -
|
| - bool IgnorableFunctionModifier(const string& str) {
|
| - return str.empty() || CouldBeFunctionName(str);
|
| - }
|
| -
|
| - bool IgnorableFunctionParameter(const string& str) {
|
| - if (str.empty()) return true;
|
| - if (CouldBeFunctionName(str)) return true;
|
| - if (str == ",") return true;
|
| - if (str == "*") return true;
|
| - if (str == "=") return true;
|
| - if (str == "&") return true;
|
| - if (str == "<") return true;
|
| - if (str == ">") return true;
|
| - if (str == ":") return true;
|
| - if (str == "=") return true;
|
| - if (isNumber(str)) return true;
|
| - if (str == "]") return true;
|
| - if (str == "[") return true;
|
| -
|
| - if (str == ";") return false;
|
| -
|
| - return false;
|
| - }
|
| -
|
| -
|
| - bool tokenDelimiter(int ch) {
|
| - if (isspace(ch)) return true;
|
| - if (isdigit(ch)) return false;
|
| - if (isalpha(ch)) return false;
|
| - if (ch == '_') return false;
|
| - return true;
|
| - }
|
| -
|
| - bool isTokenable(int ch) {
|
| - if (isdigit(ch)) return true;
|
| - if (isalpha(ch)) return true;
|
| - if (ch == '_') return true;
|
| - return false;
|
| - }
|
| -
|
| - bool isSingleCharToken(int ch) {
|
| - if (isspace(ch)) return false;
|
| - if (isdigit(ch)) return false;
|
| - if (isalpha(ch)) return false;
|
| - if (ch == '_') return false;
|
| - return true;
|
| - }
|
| -
|
| - void add(char ch) {
|
| - token += ch;
|
| - }
|
| -
|
| - void pushToken(const char* sz) {
|
| - newToken();
|
| - token = sz;
|
| - newToken();
|
| - }
|
| -
|
| - void newToken() {
|
| - if (token.empty()) return;
|
| -
|
| - if (tokens.size() > 0) {
|
| - string last = tokens[tokens.size() -1];
|
| - if (last == "operator") {
|
| - if (isOperator(op + token)) {
|
| - op += token;
|
| - token = "";
|
| - return;
|
| - } else if (op != "" && isOperator(op)) {
|
| - tokens[tokens.size() -1] = last + op;
|
| - op = "";
|
| - return;
|
| - } else if (isOperator(token)) {
|
| - op = token;
|
| - token = "";
|
| - return;
|
| - } else {
|
| - // compile error?
|
| - op = "";
|
| - }
|
| - } else if (last == "~") {
|
| - tokens[tokens.size() -1] = last + token;
|
| - token = "";
|
| - return;
|
| - }
|
| - }
|
| -
|
| - tokens.push_back(token);
|
| - token = "";
|
| - }
|
| -
|
| - int line;
|
| - vector<string> tokens;
|
| - string token;
|
| - string lastFunctionName;
|
| -
|
| - bool inComment;
|
| - bool inLineComment;
|
| - bool inDoubleQuote;
|
| - bool inSingleQuote;
|
| - bool isEscaping;
|
| - bool commentEnding;
|
| - bool commentMightBeStarting;
|
| -
|
| - string op;
|
| -};
|
| -
|
| -char output[100000000];
|
| -char* now;
|
| -
|
| -
|
| -void emit(char ch) {
|
| - *now = ch;
|
| - now++;
|
| -}
|
| -
|
| -void emit(const char* szCode, const char* szFunctionName, int fileId, int line) {
|
| - sprintf(now, szCode, szFunctionName, fileId, line);
|
| - while (*now) {
|
| - now++;
|
| - }
|
| -}
|
| -
|
| -void runFile(const char* szFileNameInput, const char* szFileNameOutput, const char* szInclude) {
|
| - printf("%s\n", szFileNameInput);
|
| -
|
| -
|
| - if (!sourceFile(szFileNameInput))
|
| - return;
|
| -
|
| - now = output;
|
| - int fileId = source_db->obtainFileId(szFileNameInput);
|
| - FILE* file = fopen(szFileNameInput, "rt");
|
| - int ch;
|
| - CppState state;
|
| - while (true) {
|
| - int ch = getc(file);
|
| - if (ch == -1)
|
| - break;
|
| - state.apply(ch);
|
| - emit(ch);
|
| - if (ch == '{' && state.enteredFunction()) { // {
|
| - emit("LS_TRACE(\"%s\", %i, %i);", state.functionName(), fileId, state.lineNumber()); // light symbol traces, create a macro to define it
|
| - }
|
| - }
|
| - fclose(file);
|
| -
|
| - file = fopen(szFileNameOutput, "wt");
|
| - // TODO: input parameter
|
| - fprintf(file, "#include \"%s\"\n", szInclude);
|
| - fwrite(output, 1, now - output, file);
|
| - fclose(file);
|
| - //source_db->commit();
|
| -}
|
| -
|
| -// to create the list file:
|
| -// dir *.cpp;*.h;*.cc /s /b
|
| -void runAll(char* szFileHolder, const char* szInclude) {
|
| - FILE* file = fopen(szFileHolder, "rt");
|
| - if (file == NULL) {
|
| - return;
|
| - }
|
| -
|
| - while (true) {
|
| - char szFileName[10000] = "";
|
| - fgets(szFileName, 10000, file);
|
| - char* end = szFileName + strlen(szFileName) - 1;
|
| - while (end > szFileName && (*end == '\n' || *end == '\r' || *end == ' ' || *end == '\t')) {
|
| - *end = 0;
|
| - end--;
|
| - }
|
| - if (strlen(szFileName) == 0)
|
| - break;
|
| -
|
| - runFile(szFileName, szFileName, szInclude);
|
| - }
|
| - fclose(file);
|
| - source_db->commit();
|
| -}
|
| -
|
| -int _tmain(int argc, char* argv[])
|
| -{
|
| - // base path, include, list.txt, lightSymbolFile, [lightSymbolsOut]
|
| - SkSourceDb::Load(argv[4], &source_db, argc == 5 ? argv[4] : argv[5], argv[1]);
|
| - if (source_db == NULL) {
|
| - source_db = new SkSourceDb(argv[1], argv[4]);
|
| - }
|
| -
|
| - runAll(argv[3], argv[2]); // e.g. foo\\src\\lightsymbols\\lightsymbols.h");
|
| -
|
| - return 0;
|
| -}
|
|
|