#ifndef _STRLIST_H_ #define _STRLIST_H_ #include "Platform.h" #include #include // for gcc #ifndef _WIN32 # include # include # include # include #endif class IGrowBuf { public: virtual int add(const void *data, int len)=0; virtual void resize(int newlen)=0; virtual int getlen()=0; virtual void *get()=0; }; class IMMap { public: virtual void resize(int newlen)=0; virtual int getsize()=0; virtual void *get(int offset, int size)=0; virtual void *get(int offset, int *size)=0; virtual void *getmore(int offset, int *size)=0; virtual void release()=0; virtual void release(void *view, int size)=0; virtual void clear()=0; virtual void setro(BOOL bRO)=0; virtual void flush(int num)=0; }; class GrowBuf : public IGrowBuf { public: GrowBuf() { m_alloc=m_used=m_zero=0; m_s=NULL; m_bs=32768; } virtual ~GrowBuf() { free(m_s); } void set_zeroing(int zero) { m_zero=zero; } int add(const void *data, int len) { if (len<=0) return 0; resize(m_used+len); memcpy((char*)m_s+m_used-len,data,len); return m_used-len; } void resize(int newlen) { int os=m_alloc; int ou=m_used; m_used=newlen; if (newlen > m_alloc) { void *n; m_alloc = newlen*2 + m_bs; n = realloc(m_s, m_alloc); if (!n) { extern FILE *g_output; extern int g_display_errors; if (g_display_errors) { fprintf(g_output,"\nack! realloc(%d) failed, trying malloc(%d)!\n",m_alloc,newlen); fflush(g_output); } m_alloc=newlen; // try to malloc the minimum needed n=malloc(m_alloc); if (!n) { extern void quit(); if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",m_alloc); fflush(g_output); } quit(); } memcpy(n,m_s,min(newlen,os)); free(m_s); } m_s=n; } if (m_zero && m_used > ou) memset((char*)m_s + ou, 0, m_used - ou); if (!m_used && m_alloc > 2*m_bs) // only free if you resize to 0 and we're > 64k { m_alloc=0; free(m_s); m_s=NULL; } } int getlen() { return m_used; } void *get() { return m_s; } private: void *m_s; int m_alloc; int m_used; int m_zero; protected: int m_bs; }; class TinyGrowBuf : public GrowBuf { public: TinyGrowBuf() : GrowBuf() { m_bs=1024; } }; class StringList { public: StringList() { } ~StringList() { } int add(const char *str, int case_sensitive) { int a=find(str,case_sensitive); if (a >= 0 && case_sensitive!=-1) return a; return gr.add(str,strlen(str)+1); } // use 2 for case sensitive end-of-string matches too int find(const char *str, int case_sensitive, int *idx=NULL) // returns -1 if not found { char *s=(char*)gr.get(); int ml=gr.getlen(); int offs=0; if (idx) *idx=0; while (offs < ml) { if ((case_sensitive && !strcmp(s+offs,str)) || (!case_sensitive && !stricmp(s+offs,str))) { return offs; } if (case_sensitive==2 && strlen(str) < strlen(s+offs) && // check for end of string !strcmp(s+offs+strlen(s+offs)-strlen(str),str)) { return offs+strlen(s+offs)-strlen(str); } offs+=strlen(s+offs)+1; if (idx) (*idx)++; } return -1; } void delbypos(int pos) { char *s=(char*)gr.get(); int len=strlen(s+pos)+1; if (pos+len < gr.getlen()) memcpy(s+pos,s+pos+len,gr.getlen()-(pos+len)); gr.resize(gr.getlen()-len); } int idx2pos(int idx) { char *s=(char*)gr.get(); int offs=0; int cnt=0; if (idx>=0) while (offs < gr.getlen()) { if (cnt++ == idx) return offs; offs+=strlen(s+offs)+1; } return -1; } int getnum() { char *s=(char*)gr.get(); int ml=gr.getlen(); int offs=0; int idx=0; while (offs < ml) { offs+=strlen(s+offs)+1; idx++; } return idx; } char *get() { return (char*)gr.get(); } int getlen() { return gr.getlen(); } private: GrowBuf gr; }; template class SortedStringList { public: SortedStringList() { } ~SortedStringList() { T *s=(T*)gr.get(); int num=gr.getlen()/sizeof(T); for (int i=0; i ll) { int res; if (case_sensitive) res=strcmp(str, data[nextpos].name); else res=stricmp(str, data[nextpos].name); if (res==0) return returnbestpos ? -1 : nextpos; if (res<0) ul=nextpos; else ll=nextpos+1; nextpos=(ul+ll)/2; } return returnbestpos ? nextpos : -1; } // returns 0 on success, 1 otherwise int del(const char *str, int case_sensitive=0) { int pos=find(str, case_sensitive); if (pos==-1) return 1; delbypos(pos); return 0; } void delbypos(int pos) { T *db=(T *)gr.get(); free(db[pos].name); memmove(db+pos,db+pos+1,gr.getlen()-(pos*sizeof(T))-sizeof(T)); gr.resize(gr.getlen()-sizeof(T)); } protected: TinyGrowBuf gr; }; #define mymin(x, y) ((x < y) ? x : y) template class SortedStringListND // no delete - can be placed in GrowBuf { public: SortedStringListND() { } ~SortedStringListND() { } // returns -1 when name already exists and pos if added int add(const char *name, int case_sensitive=0, int alwaysreturnpos=0) { int where; T newstruct={0,}; int pos=find(name,-1,case_sensitive,1,&where); if (pos==-1) return alwaysreturnpos ? where : -1; newstruct.name=strings.add(name,strlen(name)+1); gr.add(&newstruct,sizeof(T)); T *s=(T*)gr.get(); memmove(s+pos+1,s+pos,gr.getlen()-((pos+1)*sizeof(T))); memcpy(s+pos,&newstruct,sizeof(T)); return pos; } // returns -1 if not found, position if found // if returnbestpos=1 returns -1 if found, best pos to insert if not found // if n_chars equal to -1 all string is tested int find(const char *str, int n_chars=-1, int case_sensitive=0, int returnbestpos=0, int *where=0) { T *data=(T *)gr.get(); int ul=gr.getlen()/sizeof(T); int ll=0; int nextpos=(ul+ll)/2; while (ul > ll) { int res; const char *pCurr = (char*)strings.get() + data[nextpos].name; if (n_chars < 0) { if (case_sensitive) res = strcmp(str, pCurr); else res = stricmp(str, pCurr); } else { if (case_sensitive) res=strncmp(str, pCurr, mymin((unsigned int) n_chars, strlen(pCurr))); else res=strnicmp(str, pCurr, mymin((unsigned int) n_chars, strlen(pCurr))); if (res == 0 && n_chars != -1 && (unsigned int) n_chars != strlen(pCurr)) res = n_chars - strlen(pCurr); } if (res==0) { if (where) *where = nextpos; return returnbestpos ? (case_sensitive!=-1 ? -1 : nextpos) : nextpos; } if (res<0) ul=nextpos; else ll=nextpos+1; nextpos=(ul+ll)/2; } return returnbestpos ? nextpos : -1; } protected: TinyGrowBuf gr; GrowBuf strings; }; struct define { char *name; char *value; }; class DefineList : public SortedStringList { public: DefineList() { } ~DefineList() { struct define *s=(struct define*)gr.get(); int num=gr.getlen()/sizeof(struct define); for (int i=0; i::add(name); if (pos == -1) { return 1; } char **newvalue=&(((struct define*)gr.get())[pos].value); *newvalue=(char*)malloc(strlen(value)+1); if (!(*newvalue)) { extern FILE *g_output; extern int g_display_errors; extern void quit(); if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",strlen(value)+1); fflush(g_output); } quit(); } strcpy(*newvalue,value); return 0; } char *find(const char *name) { int v=SortedStringList::find(name); if (v==-1) { return NULL; } return ((struct define*)gr.get())[v].value; } // returns 0 on success, 1 otherwise int del(const char *str) { int pos=SortedStringList::find(str); if (pos==-1) return 1; struct define *db=(struct define *)gr.get(); free(db[pos].value); delbypos(pos); return 0; } int getnum() { return gr.getlen()/sizeof(define); } char *getname(int num) { if ((unsigned int)getnum() <= (unsigned int)num) return 0; return ((struct define*)gr.get())[num].name; } char *getvalue(int num) { if ((unsigned int)getnum() <= (unsigned int)num) return 0; return ((struct define*)gr.get())[num].value; } }; struct string_t { int name; }; class FastStringList : public SortedStringListND { public: FastStringList() { } ~FastStringList() { } int add(const char *name, int case_sensitive=0) { int pos = SortedStringListND::add(name, case_sensitive); if (pos == -1) return -1; return ((struct string_t*)gr.get())[pos].name; } char *get() { return (char*)strings.get(); } int getlen() { return strings.getlen(); } int getnum() { return gr.getlen()/sizeof(struct string_t); } }; class MMapFile : public IMMap { public: MMapFile() { #ifdef _WIN32 m_hFile = INVALID_HANDLE_VALUE; m_hFileMap = NULL; #else m_hFile = -1; #endif m_pView = NULL; m_iSize = 0; m_bReadOnly = FALSE; m_bTempHandle = FALSE; if (!m_iAllocationGranularity) { #ifdef _WIN32 SYSTEM_INFO si; GetSystemInfo(&si); m_iAllocationGranularity = (int) si.dwAllocationGranularity; #else m_iAllocationGranularity = getpagesize(); #endif } } virtual ~MMapFile() { clear(); } void clear() { release(); #ifdef _WIN32 if (m_hFileMap) CloseHandle(m_hFileMap); if (m_bTempHandle && m_hFile) CloseHandle(m_hFile); m_hFileMap = 0; #else if (m_bTempHandle && m_hFile) close(m_hFile); #endif } void setro(BOOL bRO) { m_bReadOnly = bRO; } #ifdef _WIN32 int setfile(HANDLE hFile, DWORD dwSize) #else int setfile(int hFile, DWORD dwSize) #endif { clear(); m_hFile = hFile; m_bTempHandle = FALSE; #ifdef _WIN32 if (m_hFile == INVALID_HANDLE_VALUE) #else if (m_hFile == -1) #endif return 0; m_iSize = (int) dwSize; if (m_iSize <= 0) return 0; #ifdef _WIN32 m_hFileMap = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, m_iSize, NULL); if (!m_hFileMap) return 0; #endif m_bReadOnly = TRUE; return 1; } void resize(int newsize) { release(); if (newsize > m_iSize) { #ifdef _WIN32 if (m_hFileMap) CloseHandle(m_hFileMap); m_hFileMap = 0; #endif m_iSize = newsize; #ifdef _WIN32 if (m_hFile == INVALID_HANDLE_VALUE) { char buf[MAX_PATH], buf2[MAX_PATH]; GetTempPath(MAX_PATH, buf); GetTempFileName(buf, "nsd", 0, buf2); m_hFile = CreateFile( buf2, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); m_bTempHandle = TRUE; } if (m_hFile != INVALID_HANDLE_VALUE) { m_hFileMap = CreateFileMapping( m_hFile, NULL, m_bReadOnly ? PAGE_READONLY : PAGE_READWRITE, 0, m_iSize, NULL ); } if (!m_hFileMap) { extern FILE *g_output; extern void quit(); extern int g_display_errors; if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: error creating mmap the size of %d.\n", m_iSize); fflush(g_output); } quit(); } #else if (m_hFile == -1) { char tmp[] = "/tmp/makensisXXXXXX"; m_hFile = mkstemp(tmp); m_bTempHandle = TRUE; } #endif } } int getsize() { return m_iSize; } void *get(int offset, int size) { return get(offset, &size); } void *get(int offset, int *sizep) { if (!sizep) return NULL; if (m_pView) release(); int size = *sizep; if (!m_iSize || offset + size > m_iSize) { extern FILE *g_output; extern void quit(); extern int g_display_errors; if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: error mmapping file (%d, %d) is out of range.\n", offset, size); fflush(g_output); } quit(); } // fix offset int alignedoffset = offset - (offset % m_iAllocationGranularity); size += offset - alignedoffset; #ifdef _WIN32 m_pView = MapViewOfFile(m_hFileMap, m_bReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE, 0, alignedoffset, size); #else m_pView = mmap(0, size, m_bReadOnly ? PROT_READ : PROT_READ | PROT_WRITE, MAP_SHARED, m_hFile, alignedoffset); m_iMappedSize = *sizep = size; #endif #ifdef _WIN32 if (!m_pView) #else if (m_pView == MAP_FAILED) #endif { extern FILE *g_output; extern void quit(); extern int g_display_errors; if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: error mmapping datablock to %d.\n", size); fflush(g_output); } quit(); } #ifdef _WIN32 return (void *)((char *)m_pView + offset - alignedoffset); #else return m_pView; #endif } void *getmore(int offset, int *size) { void *pView; void *pViewBackup = m_pView; #ifndef _WIN32 int iMappedSizeBackup = m_iMappedSize; #endif m_pView = 0; pView = get(offset, size); m_pView = pViewBackup; #ifndef _WIN32 m_iMappedSize = iMappedSizeBackup; #endif return pView; } void release() { if (!m_pView) return; #ifdef _WIN32 UnmapViewOfFile(m_pView); #else munmap(m_pView, m_iMappedSize); #endif m_pView = NULL; } void release(void *pView, int size) { if (!pView) return; #ifdef _WIN32 UnmapViewOfFile(pView); #else munmap(pView, size); #endif } void flush(int num) { if (m_pView) #ifdef _WIN32 FlushViewOfFile(m_pView, num); #else msync(m_pView, num, MS_SYNC); #endif } private: #ifdef _WIN32 HANDLE m_hFile, m_hFileMap; #else int m_hFile; int m_iMappedSize; #endif void *m_pView; int m_iSize; BOOL m_bReadOnly; BOOL m_bTempHandle; static int m_iAllocationGranularity; }; class MMapFake : public IMMap { public: MMapFake() { m_pMem = NULL; m_iSize = 0; } void set(const char *pMem, int iSize) { m_pMem = pMem; m_iSize = iSize; } int getsize() { return m_iSize; } void *get(int offset, int size) { return get(offset, &size); } void *get(int offset, int *size) { if (!size || (offset + *size > m_iSize)) return NULL; return (void *)(m_pMem + offset); } void *getmore(int offset, int *size) { return get(offset, size); } void resize(int n) {} void release() {} void release(void *p, int size) {} void clear() {} void setro(BOOL b) {} void flush(BOOL b) {} private: const char *m_pMem; int m_iSize; }; class MMapBuf : public IGrowBuf, public IMMap { public: MMapBuf() { m_gb_u=0; m_alloc=m_used=0; } virtual ~MMapBuf() { m_fm.release(); } int add(const void *data, int len) { if (len <= 0) return 0; resize(getlen() + len); memcpy((char*)get(getlen() - len, len), data, len); return getlen() - len; } void setro(BOOL bRO) { m_fm.setro(bRO); } void resize(int newlen) { if (!m_gb_u && newlen < (16 << 20)) // still in db mode { m_gb.resize(newlen); return; } // not in db mode m_gb_u = 1; m_used = newlen; if (newlen > m_alloc) { m_alloc = newlen + (16 << 20); // add 16mb to top of mapping m_fm.resize(m_alloc); if (m_gb.getlen()) { memcpy(m_fm.get(0, m_gb.getlen()), m_gb.get(), m_gb.getlen()); m_fm.flush(m_gb.getlen()); m_fm.release(); m_gb.resize(0); } } } int getsize() { if (m_gb_u) return m_fm.getsize(); return m_gb.getlen(); } int getlen() { if (m_gb_u) return m_used; return m_gb.getlen(); } void *get() { return get(0, m_alloc); } void *get(int offset, int *sizep) { if (!sizep) return NULL; int size = *sizep; return get(offset, size); } void *get(int offset, int size) { if (m_gb_u) return m_fm.get(offset, size); return (void *) ((char *) m_gb.get() + offset); } void *getmore(int offset, int *size) { if (m_gb_u) return m_fm.getmore(offset, size); return (void *) ((char *) m_gb.get() + offset); } void release() { if (m_gb_u) m_fm.release(); } void release(void *pView, int size) { if (m_gb_u) m_fm.release(pView, size); } void clear() { if (m_gb_u) m_fm.clear(); } void flush(int num) { if (m_gb_u) m_fm.flush(num); } private: GrowBuf m_gb; MMapFile m_fm; int m_gb_u; int m_alloc, m_used; }; #endif//_STRLIST_H_