#include #include #include #include #include #include template inline void NEVER(T s){ if(s){ fprintf(stderr,"ERROR: Something that should never happened has happened...\n"); exit(1); } }; template class Vector{ int size,alloc; T* p; public: Vector():size(0), alloc(0), p(0) {Resize(2);} ~Vector() {Resize(0);} inline int GetCount()const {return size;} inline T& operator[](int n) {return p[n];} inline const T& operator[](int n) const {return p[n];} T& Add(){ if(size>=alloc) Resize(2*alloc); return *(new(p+size++) T); } T& Add(const T& x) { return Add()=x; } T& AddUnique(const T& v){ int pos=Find(v); if(pos>=0) return p[pos]; return Add(v); } int Find(const T& v) const{ for(int i=0;ilen){ for(int i=len;i~T(); size=len; } p = (T*)realloc(p,len*sizeof(T)); alloc=len; } private: Vector& operator=(const Vector& v){} }; class String { char* p; public: String() : p(strdup("")) {} String(const String& s) : p(strdup(s.p)){} String(const char* s) : p(strdup(s)) {} ~String() {free(p);} char& operator[](const int n) const {return p[n];} bool IsEmpty() const {return *p == 0 || strlen(p) == 0;} const char* operator~() const {return p;} operator const char*() const {return p;} String& operator=(const String& s) {return operator=(s.p);} bool operator==(const char* s) const {return !strcmp(p, s);} bool operator==(const String& s) const {return !strcmp(p, s.p);} void Clear() {free(p); p = strdup("");} int GetCount() const {return strlen(p);} String& operator+=(const String& s){ const int lenp = strlen(p); const int lens = strlen(s.p) + 1; p = static_cast(realloc(p, lenp + lens)); NEVER(!p); memmove(p+lenp, s.p, lens); return *this; } String& operator+=(char s){ const int lenp = strlen(p); p = static_cast(realloc(p, lenp + 2)); NEVER(!p); p[lenp] = s; p[lenp+1] = 0; return *this; } String& operator=(const char* s){ if (p != s) { char *copy = strdup(s); free(p); p = copy; } return *this; } int Compare(const char* s, int len=-1) const { return len?strncmp(p,s,len):strcmp(p,s); } int FindLast(const char c) const { for(int i=strlen(p)-1;i>=0;i--) if(p[i]==c) return i; return -1; } int Find(const char* s) const { int lens=strlen(s); int lenp=strlen(p); for(int i=0;ilength && length>0) len = length; String s; free(s.p); s.p = static_cast(malloc(len+1)); NEVER(!s.p); memcpy(s.p, p + start, len); s.p[len] = '\0'; return s; } friend String operator+(const String& lhs, const String& rhs); friend int operator<(const String& lhs, const String& rhs); }; inline String operator+(const String& lhs, const String& rhs){ return String(lhs) += rhs; } inline int operator<(const String& lhs, const String& rhs){ return lhs.Compare(~rhs); } String ReadValue(String& s,char delim1 = ',',char delim2 = ','){ if(s=="") return ""; String r; int skip=0; while((s[skip]==delim1 || s[skip] == delim2 || s[skip]<=32) && s[skip]!=0) skip++; s = s.Mid(skip); bool q=false; if(s[0]=='\"'){ s = s.Mid(1); q = true; } const char* c = s; for(; *c; c++){ if(*c==delim1 || *c==delim2 || ((q && *c=='\"') && c[-1] != '\\')) break; if(*c<=(q?0:32)) continue; r += *c; } if(q) c++; s = c; return r; }; bool Consume(String& s,const char* section){ int len=strlen(section); if(s.Compare(section,len)==0){ s = s.Mid(len); return true; } return false; }; enum Opt{NONE, SPEED, SIZE}; enum OptState { UNKNOWN, NO, YES }; struct File{ Opt opt; String name, lang; File():opt(NONE){}; }; bool IsSource(File& f){ int pos=f.name.FindLast('.'); if(!pos) return false; String ext = f.name.Mid(pos+1); for(int i=0;i& v) { if(Consume(s,key)) { if(s[0]==' ') s = s.Mid(1); String when; if(s[0]=='('){ when=s; int len = 0; int lvl = 0; for(const char* c=when; *c; c++) { len++; if(*c == '(') lvl++; else if(*c == ')'){ lvl--; if(lvl == 0) break; } } when = s.Mid(0,len); s = s.Mid(len); } do { OptItem& m=v.Add(); m.when = when; m.item = ReadValue(s,','); Slashes(m.item); }while(s[0] == ','); return true; } return false; }; String BaseName(const String& s){ int pos=s.FindLast('/'); if(!pos) return s; return s.Mid(pos+1); }; String DirName(const String& s){ int pos=s.FindLast('/'); if(!pos) return ""; return s.Mid(0,pos); }; inline String LoadFile(const String& fn){ String r; char b[1000]; FILE* f=fopen(~fn,"r"); if(!f) return ""; int n=0; while(!feof(f)){ n+=fread(b,1,1000,f); r+=b; //this is a hack, correct implementation would not need it r=r.Mid(0,n); } return r; } inline String GetEnv(const char* n,const char* s=""){ String p("UPP_"); p+=n; const char* r=getenv(p); return r?r:s; }; struct Upp{ String name,description,dir; Opt opt; Vector option, link, library, addflags, target, uses, include, custom; Vector accepts, cfgk, cfgv, flags; Vector files; Upp() : opt(NONE){}; Upp(const String& package) : name(package), opt(NONE){}; Upp(const String& package,const Vector& nests) : opt(NONE) {Load(package,nests);} bool operator==(const Upp& u)const {return name==u.name;} Upp& operator=(const Upp& u){NEVER(true); return *this;} String GetClause(FILE* f){ String r; int l=0; bool q=false; while(1){ int c = fgetc(f); if(c==EOF || (!q && c==';')) break; if(c<=32){ if(!r.IsEmpty() && r[r.GetCount()-1]!=' ') r += ' '; continue; } else if (c == '\"' && l != '\\') { q=!q; } l = c; r += c; } return r; }; Upp& Load(const String& package,const Vector& nests){ name=package; char temp[FILENAME_MAX]; String cwd = getcwd(temp, FILENAME_MAX); cwd += "/"; String fn; FILE* f(NULL); for(int i=0; i& v){ while(s.GetCount()){ String val = ReadValue(s,' '); if(val.GetCount()) v.AddUnique(val); } } String FlagDir(const Vector& v){ Vector r; //simple insertion sort r.Resize(v.GetCount()); for(int i=0;i=0 && r[i].Compare(c)>0) { r[i+1]=r[i]; i--; } r[i+1]=c; } String s=r[0]; for(int i=1;i pkgs; String main; public: Vector nests, flags, dflags, libs, linkopts; static inline bool IsId(int c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9'); } bool sMatchFlag(String& s,int pkg){ if(Consume(s,"!")) return !sMatchFlag(s,pkg); if(Consume(s,"(")) { bool b = sMatchOr(s,pkg); Consume(s,")"); return b; } if(s.IsEmpty()) return true; int len=0; while(IsId(s[len])) len++; String id = s.Mid(0,len); s = s.Mid(len); if(flags.Find(id)>=0) return true; for(int j=0;j=0) && dflags.Find(id)>=0) return true; return (pkg==0&&id=="MAIN"); } bool sMatchAnd(String& s,int pkg){ bool b = sMatchFlag(s,pkg); while( IsId(s[0]) || s[0]=='!' || s[0]=='(' || Consume(s,"&&") || Consume(s,"&")) b = sMatchFlag(s,pkg) && b; return b; } bool sMatchOr(String& s,int pkg){ bool b = sMatchAnd(s,pkg); while(Consume(s,"||") || Consume(s,"|")) b = sMatchFlag(s,pkg) || b; return b; } bool EvalOpt(const OptItem& opt,int pkg){ if(opt.state!=UNKNOWN) return opt.state==YES; String s; for(const char* c = opt.when; *c; c++) if(*c > ' ') s += *c; if(s=="()"){ opt.state=YES; return true; } bool b = sMatchOr(s,pkg); if(!s.IsEmpty()){ fprintf(stderr, "Error: Invalid WHEN string: %s\n",~opt.when); exit(1); } opt.state=b?YES:NO; return b; } void GetDeps(const String& pkg){ if(pkgs.Find(Upp(pkg))>=0) return; Upp& added = pkgs.Add().Load(pkg, nests); Vector u; for(int i=0;i& v,int pkg,const String& prefix){ String r; for(int i=0;i= 0 && n < pkgs[0].cfgk.GetCount()) p = pkgs[0].cfgv[n]; if(p) Split(p,flags); p="Using flags"; for(int i=0; i=0) pkgs[i].flags.Add(dflags[j]); for(int j=0;j remflags; for(int j=0;j=0) continue; pkgs[i].flags.Add(flags[j]); } } } void EvalOpts(){ String optimize=GetEnv("OPT"); for(int i=0;i