mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
698 lines
15 KiB
C++
698 lines
15 KiB
C++
// Copyright (C) 2003 Mirek Fidler, Tomas Rylek. 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 (see COPYING) along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
#include "coff.h"
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
#include <winver.h>
|
|
#include <imagehlp.h>
|
|
#endif
|
|
|
|
NAMESPACE_UPP
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
|
|
#define DLLFILENAME "imagehlp.dll"
|
|
#define DLIHEADER <coff/imagehlp.dli>
|
|
#define DLIMODULE ImageHlp
|
|
#include <Core/dli.h>
|
|
|
|
Vector<String> EnumWinRegSubkeys(const char *path, HKEY base_key) {
|
|
HKEY key = 0;
|
|
Vector<String> keys;
|
|
if(RegOpenKeyEx(base_key, path, 0, KEY_READ, &key) != ERROR_SUCCESS)
|
|
return keys;
|
|
for(DWORD index = 0;; index++) {
|
|
char name[1000];
|
|
dword length = sizeof(name);
|
|
FILETIME time;
|
|
if(RegEnumKeyEx(key, index, name, &length, 0, NULL, NULL, &time) != ERROR_SUCCESS)
|
|
break;
|
|
keys.Add(String(name, length));
|
|
}
|
|
RegCloseKey(key);
|
|
return keys;
|
|
}
|
|
|
|
String TranslateCygWinPath(const char *path)
|
|
{
|
|
static String base_key = "SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2";
|
|
static String cygdrive = GetWinRegString("cygdrive prefix", base_key, HKEY_LOCAL_MACHINE);
|
|
static Vector<String> root = EnumWinRegSubkeys(base_key, HKEY_LOCAL_MACHINE);
|
|
static Vector<String> mount;
|
|
if(mount.IsEmpty()) {
|
|
mount.SetCount(root.GetCount());
|
|
for(int i = 0; i < root.GetCount(); i++)
|
|
mount[i] = GetWinRegString("native", base_key + "\\" + root[i], HKEY_LOCAL_MACHINE);
|
|
}
|
|
if(!memcmp(path, cygdrive, cygdrive.GetLength()) && path[cygdrive.GetLength()] == '/') {
|
|
const char *drv = path + cygdrive.GetLength() + 1;
|
|
if(IsAlpha(*drv) && drv[1] == '/')
|
|
return AppendFileName(String(*drv, 1) + ":\\", drv + 2);
|
|
}
|
|
String bestroot, bestmount, bestrel;
|
|
for(int i = 0; i < root.GetCount(); i++) {
|
|
int l = root[i].GetLength();
|
|
if(!memcmp(path, root[i], l) && (*root[i].Last() == '/' || path[l] == 0 || path[l] == '/')) {
|
|
if(l > bestroot.GetLength()) {
|
|
bestroot = root[i];
|
|
bestmount = mount[i];
|
|
const char *p = path + l;
|
|
if(*p == '/')
|
|
p++;
|
|
bestrel = p;
|
|
}
|
|
}
|
|
}
|
|
if(!IsNull(bestroot))
|
|
return AppendFileName(bestmount, bestrel);
|
|
|
|
return Null;
|
|
}
|
|
#endif
|
|
|
|
const char *EatPrefix(const char *string, const char *prefix)
|
|
{
|
|
int len = (int)strlen(prefix);
|
|
return (!MemICmp(string, prefix, len) ? string + len : NULL);
|
|
}
|
|
|
|
Vector<String> SplitCmdArgs(const char *cmd)
|
|
{
|
|
Vector<String> out;
|
|
while(*cmd)
|
|
if((byte)*cmd <= ' ')
|
|
cmd++;
|
|
else
|
|
{
|
|
String arg;
|
|
while(*cmd > ' ')
|
|
if(*cmd == '\"')
|
|
{
|
|
cmd++;
|
|
while(*cmd && (*cmd != '\"' || *++cmd == '\"'))
|
|
arg.Cat(*cmd++);
|
|
}
|
|
else
|
|
arg.Cat(*cmd++);
|
|
out.Add(arg);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
const char *FetchCmdArg(const Vector<String>& cmdlist, int& cmdi)
|
|
{
|
|
if(cmdi + 1 >= cmdlist.GetCount())
|
|
throw Exc(NFormat("Argument missing for option '%s'.", cmdlist[cmdi]));
|
|
return cmdlist[++cmdi];
|
|
}
|
|
|
|
const char *FetchCmdArg(const Vector<String>& cmdlist, int& cmdi, const char *ptr)
|
|
{
|
|
return (ptr && *ptr ? ptr : FetchCmdArg(cmdlist, cmdi));
|
|
}
|
|
|
|
int ScanCInt(const char *line)
|
|
{
|
|
while(*line && (byte)*line <= ' ')
|
|
line++;
|
|
bool sign = (*line == '-');
|
|
if(sign || *line == '+')
|
|
line++;
|
|
if(!IsDigit(*line))
|
|
return Null;
|
|
int out = 0;
|
|
if(*line == '0')
|
|
{
|
|
if(line[1] == 'x')
|
|
{ // hexadecimal
|
|
line += 2;
|
|
if(!IsXDigit(*line))
|
|
return Null;
|
|
for(; IsXDigit(*line); line++)
|
|
out = 16 * out + (*line <= '9' ? *line - '0' : (*line & ~0x20) - 'A' + 10);
|
|
}
|
|
else
|
|
{ // octal
|
|
while(unsigned(*++line - '0') < 8)
|
|
out = 8 * out + *line - '0';
|
|
}
|
|
}
|
|
else
|
|
{ // decimal
|
|
do
|
|
out = 10 * out + *line++ - '0';
|
|
while(IsDigit(*line));
|
|
}
|
|
return sign ? -out : out;
|
|
}
|
|
|
|
static inline bool IsDirSep(char c) { return c == '/' || c == '\\'; }
|
|
|
|
String NormalizeRelPath(const char *path)
|
|
{
|
|
String out;
|
|
while(*path)
|
|
{
|
|
while(IsDirSep(*path))
|
|
{
|
|
out.Cat('\\');
|
|
path++;
|
|
}
|
|
const char *b = path;
|
|
while(*path && !IsDirSep(*path))
|
|
path++;
|
|
if(path - b == 1 && *b == '.')
|
|
{
|
|
if(!out.IsEmpty() && !IsDirSep(*out.Last()))
|
|
out.Cat('\\');
|
|
while(IsDirSep(*path))
|
|
path++;
|
|
continue;
|
|
}
|
|
if(path - b == 2 && *b == '.' && b[1] == '.')
|
|
{
|
|
const char *o = out.Begin(), *e = out.End();
|
|
if(e - o >= 2 && IsDirSep(e[-1]) && !IsDirSep(e[-2]))
|
|
{
|
|
e -= 2;
|
|
while(e > o && !IsDirSep(e[-1]))
|
|
e--;
|
|
out.Trim(int(e - o));
|
|
while(IsDirSep(*path))
|
|
path++;
|
|
continue;
|
|
}
|
|
}
|
|
out.Cat(b, int(path - b));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
int CatN0(Vector<byte>& out, int length)
|
|
{
|
|
int l = out.GetCount();
|
|
out.AddN(length);
|
|
memset(&out[l], 0, length);
|
|
return l;
|
|
}
|
|
|
|
int CatN(Vector<byte>& out, int length, const void *in)
|
|
{
|
|
int l = out.GetCount();
|
|
if(length > 0)
|
|
{
|
|
out.AddN(length);
|
|
if(in)
|
|
memcpy(&out[l], in, length);
|
|
}
|
|
return l;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
static String WipeClass(const char *p)
|
|
{
|
|
String out;
|
|
while(*p)
|
|
if(IsAlpha(*p) || *p == '_')
|
|
{
|
|
const char *b = p++;
|
|
while(IsAlNum(*p) || *p == '_')
|
|
p++;
|
|
if(p - b == 5 && !memcmp(b, "class", 5))
|
|
{
|
|
while(*p == ' ')
|
|
p++;
|
|
}
|
|
else
|
|
out.Cat(b, int(p - b));
|
|
}
|
|
else
|
|
out.Cat(*p++);
|
|
return out;
|
|
}
|
|
#endif
|
|
|
|
static inline bool IsIdent(char c) { return IsAlNum(c) || c == '_'; }
|
|
|
|
static inline const char *ReadIdent(const char *p, int len)
|
|
{
|
|
const char *b = p;
|
|
while(IsIdent(*p) && ++p - b < len)
|
|
;
|
|
return p;
|
|
}
|
|
|
|
static const char *DemangleGccDeclarator(String& base, String& prefix, const char *p,
|
|
Vector<String>& templmap, Vector<String>& argmap, bool is_template);
|
|
|
|
static const char *DemangleGccDeclarator(String& out, const char *p,
|
|
Vector<String>& templmap, Vector<String>& argmap, bool is_template)
|
|
{
|
|
String base, prefix;
|
|
p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template);
|
|
out << base;
|
|
if(!IsNull(prefix))
|
|
out << ' ' << prefix;
|
|
return p;
|
|
}
|
|
|
|
static const char *DemangleGccDeclarator(String& out, String& prefix, const char *p,
|
|
Vector<String>& templmap, Vector<String>& argmap, bool is_template)
|
|
{
|
|
String base;
|
|
switch(*p++)
|
|
{
|
|
case 'b':
|
|
base << "bool";
|
|
break;
|
|
|
|
case 'c':
|
|
base << "char";
|
|
break;
|
|
|
|
case 'd':
|
|
base << "double";
|
|
break;
|
|
|
|
case 'F':
|
|
p = DemangleGccDeclarator(base, p, templmap, argmap, false);
|
|
prefix = "(" + prefix + ")(";
|
|
while(p && *p && *p != 'E')
|
|
{
|
|
if(*prefix.Last() != '(')
|
|
prefix << ", ";
|
|
p = DemangleGccDeclarator(prefix, p, templmap, argmap, false);
|
|
}
|
|
if(p && *p == 'E')
|
|
p++;
|
|
prefix.Cat(')');
|
|
break;
|
|
|
|
case 'h':
|
|
base << "byte";
|
|
break;
|
|
|
|
case 'E': // single argument
|
|
p = DemangleGccDeclarator(base, p + 1, templmap, argmap, is_template);
|
|
break;
|
|
|
|
case 'I':
|
|
{ // multiple arguments
|
|
String tmpargs;
|
|
// Vector<String> auxmap;
|
|
while(p && *p && *p != 'E')
|
|
{
|
|
if(!tmpargs.IsEmpty())
|
|
tmpargs.Cat(", ");
|
|
String arg;
|
|
p = DemangleGccDeclarator(arg, p, templmap, argmap, is_template);
|
|
tmpargs.Cat(arg);
|
|
}
|
|
if(tmpargs[0] == '<' || !tmpargs.IsEmpty() && *tmpargs.Last() == '>')
|
|
base << "< " << tmpargs << " >";
|
|
else
|
|
base << '<' << tmpargs << '>';
|
|
if(p && *p == 'E')
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case 'i':
|
|
base << "int";
|
|
break;
|
|
|
|
case 'j':
|
|
base << "unsigned";
|
|
break;
|
|
|
|
case 'K':
|
|
if(!IsNull(prefix))
|
|
prefix = "const " + prefix;
|
|
else
|
|
base << "const ";
|
|
p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template);
|
|
break;
|
|
|
|
case 'L':
|
|
if(*p == 'i')
|
|
{
|
|
int num = ScanInt(p + 1, &p);
|
|
if(!IsNull(num))
|
|
{
|
|
base << num;
|
|
break;
|
|
}
|
|
}
|
|
goto UNKNOWN;
|
|
|
|
case 'm':
|
|
base << "dword";
|
|
break;
|
|
|
|
case 'P':
|
|
prefix = "*" + prefix;
|
|
p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template);
|
|
break;
|
|
|
|
case 'R':
|
|
prefix = "&" + prefix;
|
|
p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template);
|
|
break;
|
|
|
|
case 'S':
|
|
{
|
|
int equiv = 0;
|
|
if(IsDigit(*p))
|
|
{
|
|
equiv = ScanInt(p, &p);
|
|
if(equiv < 0)
|
|
{
|
|
base << "error(S)";
|
|
return NULL;
|
|
}
|
|
}
|
|
if(*p++ != '_')
|
|
{
|
|
base << "error(S_)";
|
|
return NULL;
|
|
}
|
|
if(!argmap.IsEmpty() && equiv == argmap.GetCount()) // ??
|
|
base.Cat(argmap.Top());
|
|
else if(equiv >= argmap.GetCount())
|
|
{
|
|
base << "error(S" << equiv << "_)";
|
|
return NULL;
|
|
}
|
|
else
|
|
base.Cat(argmap[equiv]);
|
|
}
|
|
break;
|
|
|
|
case 'T':
|
|
{
|
|
int equiv = 0;
|
|
if(IsDigit(*p))
|
|
{
|
|
equiv = ScanInt(p, &p);
|
|
if(equiv < 0)
|
|
{
|
|
base << "error(T)";
|
|
return NULL;
|
|
}
|
|
}
|
|
if(*p++ != '_')
|
|
{
|
|
base << "error(T_)";
|
|
return NULL;
|
|
}
|
|
if(!templmap.IsEmpty() && equiv == templmap.GetCount()) // ??
|
|
base.Cat(templmap.Top());
|
|
else if(equiv >= templmap.GetCount())
|
|
{
|
|
base << "error(T" << equiv << "_)";
|
|
return NULL;
|
|
}
|
|
else
|
|
base.Cat(templmap[equiv]);
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
base << "word";
|
|
break;
|
|
|
|
case 'v': // void
|
|
base << "void";
|
|
break;
|
|
|
|
case 'z':
|
|
base << "...";
|
|
break;
|
|
|
|
case 'N':
|
|
{
|
|
bool first = true;
|
|
while(p && *p != 'E')
|
|
{
|
|
if(!IsDigit(*p))
|
|
break;
|
|
int ident = ScanInt(p, &p);
|
|
if(ident <= 0)
|
|
break;
|
|
const char *b = p;
|
|
p = ReadIdent(p, ident);
|
|
if(p - b < ident)
|
|
break;
|
|
if(!first)
|
|
base.Cat("::");
|
|
base.Cat(b, int(p - b));
|
|
if(*p == 'I')
|
|
p = DemangleGccDeclarator(base, p, templmap, argmap, true);
|
|
first = false;
|
|
}
|
|
if(!p)
|
|
base << "(error)";
|
|
else if(*p == 'E')
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if(IsDigit(*--p))
|
|
{
|
|
int ident = ScanInt(p, &p);
|
|
if(ident <= 0)
|
|
break;
|
|
const char *b = p;
|
|
p = ReadIdent(p, ident);
|
|
if(p - b < ident)
|
|
break;
|
|
base.Cat(b, int(p - b));
|
|
if(*p == 'I')
|
|
p = DemangleGccDeclarator(base, p, templmap, argmap, true);
|
|
break;
|
|
}
|
|
|
|
UNKNOWN:
|
|
base << "unknown " << *p;
|
|
return NULL;
|
|
}
|
|
if(is_template)
|
|
templmap.Add(base);
|
|
argmap.Add(base);
|
|
out.Cat(base);
|
|
return p;
|
|
}
|
|
|
|
const char *DemangleOperator(char a, char b)
|
|
{
|
|
const char *functor = NULL;
|
|
/**/ if(a == 'e' && b == 'q') functor = "==";
|
|
else if(a == 'n' && b == 'e') functor = "!=";
|
|
else if(a == 'l' && b == 't') functor = "<";
|
|
else if(a == 'l' && b == 'e') functor = "<=";
|
|
else if(a == 'g' && b == 't') functor = ">";
|
|
else if(a == 'g' && b == 'e') functor = ">=";
|
|
else if(a == 'i' && b == 'x') functor = "[]";
|
|
else if(a == 'r' && b == 'm') functor = "%";
|
|
else if(a == 'p' && b == 'L') functor = "+=";
|
|
else if(a == 'a' && b == 'S') functor = "=";
|
|
else if(a == 'p' && b == 'l') functor = "+";
|
|
else if(a == 'l' && b == 's') functor = "<<";
|
|
else if(a == 'l' && b == 'S') functor = "<<=";
|
|
return functor;
|
|
}
|
|
|
|
String DemangleGccName(const char *name)
|
|
{
|
|
const char *p = name;
|
|
if(*p++ != '_' || *p++ != '_' || *p++ != 'Z')
|
|
return name;
|
|
String out;
|
|
bool method = (*p == 'N');
|
|
if(method)
|
|
p++;
|
|
bool methconst = (*p == 'K');
|
|
if(methconst)
|
|
p++;
|
|
if(IsDigit(*p))
|
|
{
|
|
if(!IsDigit(*p))
|
|
return name;
|
|
int ident = ScanInt(p, &p);
|
|
if(ident <= 0)
|
|
return name;
|
|
const char *b = p;
|
|
p = ReadIdent(p, ident);
|
|
if(p - b < ident)
|
|
return name;
|
|
out.Cat(b, ident);
|
|
}
|
|
else
|
|
{
|
|
const char *functor = (*p ? DemangleOperator(p[0], p[1]) : NULL);
|
|
if(!functor)
|
|
return name;
|
|
p += 2;
|
|
out << "operator " << functor << ' ';
|
|
}
|
|
Vector<String> templmap, argmap;
|
|
bool retval = false;
|
|
if(*p == 'I')
|
|
{
|
|
String arg;
|
|
p = DemangleGccDeclarator(arg, p, templmap, argmap, true);
|
|
out.Cat(arg);
|
|
retval = (!method);
|
|
}
|
|
if(!p)
|
|
{
|
|
out << "; " << name;
|
|
return out;
|
|
}
|
|
String root = out;
|
|
if(method)
|
|
argmap.Add(out);
|
|
if(method)
|
|
{
|
|
while(p && *p && *p != 'E' && *p != 'I')
|
|
{
|
|
int notempl = root.Find('<');
|
|
if(notempl < 0)
|
|
notempl = root.GetLength();
|
|
if(*p == 'C')
|
|
{
|
|
retval = false;
|
|
out.Cat("::");
|
|
out.Cat(root, notempl);
|
|
p++;
|
|
if(*p != '1' && *p != '2')
|
|
return name;
|
|
p++;
|
|
break;
|
|
}
|
|
if(*p == 'D')
|
|
{
|
|
retval = false;
|
|
out.Cat("::~");
|
|
out.Cat(root, notempl);
|
|
p++;
|
|
if(*p != '0' && *p != '1' && *p != '2')
|
|
return name;
|
|
p++;
|
|
break;
|
|
}
|
|
String subname, functor;
|
|
if(*p == 'c' && p[1] == 'v')
|
|
{
|
|
retval = false;
|
|
p += 2;
|
|
subname << "operator ";
|
|
p = DemangleGccDeclarator(subname, p, templmap, argmap, false);
|
|
}
|
|
else if(*p && !IsNull(functor = DemangleOperator(p[0], p[1])))
|
|
p += 2;
|
|
else if(!IsDigit(*p))
|
|
return name;
|
|
else
|
|
{
|
|
int ident = ScanInt(p, &p);
|
|
if(ident <= 0)
|
|
return name;
|
|
const char *b = p;
|
|
p = ReadIdent(p, ident);
|
|
if(p - b < ident)
|
|
return name;
|
|
subname = String(b, ident);
|
|
}
|
|
if(!IsNull(functor))
|
|
subname << "operator " << functor << ' ';
|
|
out.Cat("::");
|
|
out.Cat(subname);
|
|
root = subname;
|
|
// if(*p == 'I' || *p == 'E')
|
|
// p = DemangleGccDeclarator(subname, p, templmap, argmap, false);
|
|
}
|
|
if(!p || *p != 'E')
|
|
return name;
|
|
p++;
|
|
}
|
|
if(retval)
|
|
{
|
|
String rvl;
|
|
p = DemangleGccDeclarator(rvl, p, templmap, argmap, false);
|
|
if(!rvl.IsEmpty() && IsIdent(*rvl.Last()))
|
|
rvl.Cat(' ');
|
|
rvl.Cat(out);
|
|
out = rvl;
|
|
}
|
|
out.Cat('(');
|
|
while(p && *p)
|
|
{
|
|
if(*out.Last() != '(')
|
|
out.Cat(", ");
|
|
String arg;
|
|
p = DemangleGccDeclarator(arg, p, templmap, argmap, false);
|
|
out.Cat(arg);
|
|
argmap.Add(arg);
|
|
}
|
|
out.Cat(')');
|
|
if(methconst)
|
|
out.Cat(" const");
|
|
// if(!p)
|
|
out << "; " << name;
|
|
return out;
|
|
}
|
|
|
|
String DemangleName(String name, int mangling_style)
|
|
{
|
|
String out = name;
|
|
#ifdef PLATFORM_WIN32
|
|
if(mangling_style == MANGLING_MSC && ImageHlp())
|
|
{
|
|
char buffer[1024];
|
|
ImageHlp().UnDecorateSymbolName(name, buffer, sizeof(buffer),
|
|
UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_MS_KEYWORDS);
|
|
out = WipeClass(buffer);
|
|
}
|
|
else
|
|
#endif
|
|
if(mangling_style == MANGLING_GCC)
|
|
out = DemangleGccName(name);
|
|
return out;
|
|
}
|
|
|
|
|
|
String NormalizePathCase(String file)
|
|
{
|
|
#if PATH_HAS_CASE
|
|
return file;
|
|
#else
|
|
return ToLower(file);
|
|
#endif
|
|
}
|
|
|
|
bool EqualsPathCase(String f1, String f2)
|
|
{
|
|
#if PATH_HAS_CASE
|
|
return f1 == f2;
|
|
#else
|
|
return !CompareNoCase(f1, f2);
|
|
#endif
|
|
}
|
|
|
|
void PutStdOut(const char *text)
|
|
{
|
|
puts(text);
|
|
fflush(stdout);
|
|
}
|
|
|
|
String MaxLenString(const byte *b, int maxlen)
|
|
{
|
|
const byte *e = b + maxlen;
|
|
while(e > b && e[-1] == 0)
|
|
e--;
|
|
return String(b, int(e - b));
|
|
}
|
|
|
|
END_UPP_NAMESPACE
|