1 |
gpertea |
16 |
#include "GBase.h" |
2 |
gpertea |
2 |
#include <stdarg.h> |
3 |
|
|
#include <ctype.h> |
4 |
|
|
#include <sys/stat.h> |
5 |
|
|
|
6 |
gpertea |
41 |
#ifndef S_ISDIR
|
7 |
|
|
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
8 |
|
|
#endif
|
9 |
|
|
|
10 |
|
|
#ifndef S_ISREG
|
11 |
|
|
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
12 |
|
|
#endif |
13 |
|
|
|
14 |
gpertea |
2 |
static char msg[4069]; |
15 |
gpertea |
16 |
/* |
16 |
|
|
#ifdef _DEFINE_WIN32_FSEEKO |
17 |
|
|
int fseeko(FILE *stream, off_t offset, int whence) { |
18 |
|
|
|
19 |
|
|
} |
20 |
|
|
#endif |
21 |
|
|
|
22 |
|
|
#ifdef _DEFINE_WIN32_FTELLO |
23 |
|
|
off_t ftello(FILE *stream) { |
24 |
|
|
|
25 |
|
|
} |
26 |
|
|
#endif |
27 |
|
|
*/ |
28 |
|
|
|
29 |
|
|
|
30 |
|
|
int saprintf(char **retp, const char *fmt, ...) { |
31 |
|
|
va_list argp; |
32 |
|
|
int len; |
33 |
|
|
char *buf; |
34 |
|
|
|
35 |
|
|
va_start(argp, fmt); |
36 |
|
|
len = vsnprintf(NULL, 0, fmt, argp); |
37 |
|
|
va_end(argp); |
38 |
|
|
GMALLOC(buf, (len + 1)); |
39 |
|
|
if(buf == NULL) |
40 |
|
|
{ |
41 |
|
|
*retp = NULL; |
42 |
|
|
return -1; |
43 |
|
|
} |
44 |
|
|
|
45 |
|
|
va_start(argp, fmt); |
46 |
|
|
vsnprintf(buf, len+1, fmt, argp); |
47 |
|
|
va_end(argp); |
48 |
|
|
|
49 |
|
|
*retp = buf; |
50 |
|
|
return len; |
51 |
|
|
} |
52 |
|
|
|
53 |
gpertea |
2 |
//************************* Debug helpers ************************** |
54 |
|
|
// Assert failed routine |
55 |
|
|
void GAssert(const char* expression, const char* filename, unsigned int lineno){ |
56 |
|
|
sprintf(msg,"%s(%d): ASSERT(%s) failed.\n",filename,lineno,expression); |
57 |
|
|
fprintf(stderr,"%s",msg); |
58 |
|
|
//abort(); |
59 |
|
|
} |
60 |
|
|
// Error routine (prints error message and exits!) |
61 |
|
|
void GError(const char* format,...){ |
62 |
|
|
#ifdef __WIN32__ |
63 |
|
|
va_list arguments; |
64 |
|
|
va_start(arguments,format); |
65 |
|
|
vsprintf(msg,format,arguments); |
66 |
|
|
va_end(arguments); |
67 |
|
|
OutputDebugString(msg); |
68 |
|
|
fprintf(stderr,"%s",msg); // if a console is available |
69 |
|
|
MessageBox(NULL,msg,NULL,MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL); |
70 |
|
|
#else |
71 |
|
|
va_list arguments; |
72 |
|
|
va_start(arguments,format); |
73 |
|
|
vfprintf(stderr,format,arguments); |
74 |
|
|
va_end(arguments); |
75 |
|
|
#ifdef DEBUG |
76 |
|
|
// modify here if you want a core dump |
77 |
|
|
abort(); |
78 |
|
|
#endif |
79 |
|
|
#endif |
80 |
|
|
exit(1); |
81 |
|
|
} |
82 |
gpertea |
16 |
|
83 |
gpertea |
2 |
// Warning routine (just print message without exiting) |
84 |
|
|
void GMessage(const char* format,...){ |
85 |
|
|
va_list arguments; |
86 |
|
|
va_start(arguments,format); |
87 |
|
|
vsprintf(msg,format,arguments); |
88 |
|
|
va_end(arguments); |
89 |
|
|
#ifdef __WIN32__ |
90 |
|
|
OutputDebugString(msg); |
91 |
|
|
#endif |
92 |
|
|
fprintf(stderr,"%s",msg);fflush(stderr); |
93 |
|
|
} |
94 |
|
|
|
95 |
|
|
/*************** Memory management routines *****************/ |
96 |
|
|
// Allocate memory |
97 |
|
|
bool GMalloc(pointer* ptr,unsigned long size){ |
98 |
|
|
//GASSERT(ptr); |
99 |
|
|
if (size!=0) *ptr=malloc(size); |
100 |
|
|
return *ptr!=NULL; |
101 |
|
|
} |
102 |
|
|
|
103 |
|
|
// Allocate cleaned memory (0 filled) |
104 |
|
|
bool GCalloc(pointer* ptr,unsigned long size){ |
105 |
|
|
GASSERT(ptr); |
106 |
|
|
*ptr=calloc(size,1); |
107 |
|
|
return *ptr!=NULL; |
108 |
|
|
} |
109 |
|
|
|
110 |
|
|
// Resize memory |
111 |
|
|
bool GRealloc(pointer* ptr,unsigned long size){ |
112 |
|
|
//GASSERT(ptr); |
113 |
|
|
if (size==0) { |
114 |
|
|
GFree(ptr); |
115 |
|
|
return true; |
116 |
|
|
} |
117 |
|
|
if (*ptr==NULL) {//simple malloc |
118 |
|
|
void *p=malloc(size); |
119 |
|
|
if (p != NULL) { |
120 |
|
|
*ptr=p; |
121 |
|
|
return true; |
122 |
|
|
} |
123 |
|
|
else return false; |
124 |
|
|
}//malloc |
125 |
|
|
else {//realloc |
126 |
|
|
void *p=realloc(*ptr,size); |
127 |
|
|
if (p) { |
128 |
|
|
*ptr=p; |
129 |
|
|
return true; |
130 |
|
|
} |
131 |
|
|
return false; |
132 |
|
|
} |
133 |
|
|
} |
134 |
|
|
// Free memory, resets ptr to NULL afterward |
135 |
|
|
void GFree(pointer* ptr){ |
136 |
|
|
GASSERT(ptr); |
137 |
|
|
if (*ptr) free(*ptr); |
138 |
|
|
*ptr=NULL; |
139 |
|
|
} |
140 |
|
|
|
141 |
|
|
char* Gstrdup(const char* str) { |
142 |
|
|
if (str==NULL) return NULL; |
143 |
gpertea |
16 |
char *copy=NULL; |
144 |
gpertea |
2 |
GMALLOC(copy, strlen(str)+1); |
145 |
|
|
strcpy(copy,str); |
146 |
|
|
return copy; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
char* newEmptyStr() { |
150 |
gpertea |
16 |
char* zs=NULL; |
151 |
gpertea |
2 |
GMALLOC(zs,1); |
152 |
|
|
zs[0]=0; |
153 |
|
|
return zs; |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
char* Gstrdup(const char* sfrom, const char* sto) { |
157 |
|
|
if (sfrom==NULL || sto==NULL) return NULL; |
158 |
gpertea |
16 |
char *copy=NULL; |
159 |
gpertea |
2 |
if (sfrom[0]==0) return newEmptyStr(); |
160 |
|
|
GMALLOC(copy, sto-sfrom+2); |
161 |
|
|
strncpy(copy, sfrom, sto-sfrom+1); |
162 |
|
|
copy[sto-sfrom+1]=0; |
163 |
|
|
return copy; |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
int Gstrcmp(char* a, char* b) { |
167 |
|
|
if (a==NULL || b==NULL) { |
168 |
|
|
return a==NULL ? -1 : 1; |
169 |
|
|
} |
170 |
|
|
else return strcmp(a,b); |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
int Gstricmp(const char* a, const char* b) { |
174 |
|
|
if (a==NULL || b==NULL) return a==NULL ? -1 : 1; |
175 |
|
|
register int ua, ub; |
176 |
|
|
while ((*a!=0) && (*b!=0)) { |
177 |
|
|
ua=tolower((unsigned char)*a); |
178 |
|
|
ub=tolower((unsigned char)*b); |
179 |
|
|
a++;b++; |
180 |
|
|
if (ua!=ub) return ua < ub ? -1 : 1; |
181 |
|
|
} |
182 |
|
|
return (*a == 0) ? ( (*b == 0) ? 0 : -1 ) : 1 ; |
183 |
|
|
} |
184 |
|
|
|
185 |
|
|
int strsplit(char* str, char** fields, int maxfields, const char* delim) { |
186 |
|
|
//splits by placing 0 where delim chars are found, setting fields[] to the beginning |
187 |
|
|
//of each field (stopping after maxfields); returns number of fields parsed |
188 |
|
|
int tidx=0; |
189 |
|
|
bool afterdelim=true; |
190 |
|
|
int i=0; |
191 |
|
|
while (str[i]!=0 && tidx<maxfields) { |
192 |
|
|
if (afterdelim) { |
193 |
|
|
fields[tidx]=str+i; |
194 |
|
|
tidx++; |
195 |
|
|
} |
196 |
|
|
afterdelim=false; |
197 |
|
|
if (chrInStr(str[i],(char*)delim)) { |
198 |
|
|
str[i]=0; |
199 |
|
|
i++; |
200 |
|
|
while (str[i]!=0 && chrInStr(str[i], (char*)delim)) i++; |
201 |
|
|
afterdelim=true; |
202 |
|
|
continue; |
203 |
|
|
} |
204 |
|
|
i++; |
205 |
|
|
} |
206 |
|
|
return tidx; |
207 |
|
|
} |
208 |
|
|
|
209 |
|
|
int strsplit(char* str, char** fields, int maxfields, const char delim) { |
210 |
|
|
//splits by placing 0 where delim is found, setting fields[] to the beginning |
211 |
|
|
//of each field (stopping after maxfields); returns number of fields parsed |
212 |
|
|
int tidx=0; |
213 |
|
|
bool afterdelim=true; |
214 |
|
|
int i=0; |
215 |
|
|
while (str[i]!=0 && tidx<maxfields) { |
216 |
|
|
if (afterdelim) { |
217 |
|
|
fields[tidx]=str+i; |
218 |
|
|
tidx++; |
219 |
|
|
} |
220 |
|
|
afterdelim=false; |
221 |
|
|
if (str[i]==delim) { |
222 |
|
|
str[i]=0; |
223 |
|
|
i++; |
224 |
|
|
while (str[i]!=0 && str[i]==delim) i++; |
225 |
|
|
afterdelim=true; |
226 |
|
|
continue; |
227 |
|
|
} |
228 |
|
|
i++; |
229 |
|
|
} |
230 |
|
|
return tidx; |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
int strsplit(char* str, char** fields, int maxfields) { |
234 |
|
|
//splits by placing 0 where delim is found, setting fields[] to the beginning |
235 |
|
|
//of each field (stopping after maxfields); returns number of fields parsed |
236 |
|
|
int tidx=0; |
237 |
|
|
bool afterdelim=true; |
238 |
|
|
int i=0; |
239 |
|
|
while (str[i]!=0 && tidx<maxfields) { |
240 |
|
|
if (afterdelim) { |
241 |
|
|
fields[tidx]=str+i; |
242 |
|
|
tidx++; |
243 |
|
|
} |
244 |
|
|
afterdelim=false; |
245 |
|
|
if (str[i]==' ' || str[i]=='\t') { |
246 |
|
|
str[i]=0; |
247 |
|
|
i++; |
248 |
|
|
while (str[i]!=0 && (str[i]=='\t' || str[i]==' ')) i++; |
249 |
|
|
afterdelim=true; |
250 |
|
|
continue; |
251 |
|
|
} |
252 |
|
|
i++; |
253 |
|
|
} |
254 |
|
|
return tidx; |
255 |
|
|
} |
256 |
|
|
|
257 |
|
|
|
258 |
|
|
char* Gsubstr(const char* str, char* from, char* to) { |
259 |
|
|
//extract (and allocate) a substring, including boundaries (from/to) |
260 |
|
|
if (str==NULL || from==NULL) return NULL; |
261 |
|
|
if (from[0]==0 || str[0]==0) return newEmptyStr(); |
262 |
|
|
if (from<str) return NULL; |
263 |
|
|
if (to==NULL) { |
264 |
|
|
to=from; |
265 |
|
|
while (to[1]) to++; |
266 |
|
|
} |
267 |
|
|
if (to<from) return newEmptyStr(); |
268 |
|
|
int newlen=to-from+1; |
269 |
|
|
char* subs; |
270 |
|
|
GMALLOC(subs, newlen); |
271 |
|
|
memcpy(subs, str, newlen-1); |
272 |
|
|
subs[newlen]='\0'; |
273 |
|
|
return subs; |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
char* replaceStr(char* &str, char* newvalue) { |
277 |
|
|
if (str!=NULL) GFREE(str); |
278 |
|
|
if (newvalue==NULL) { return NULL; } |
279 |
|
|
GMALLOC(str, strlen(newvalue)+1); |
280 |
|
|
strcpy(str,newvalue); |
281 |
|
|
return str; |
282 |
|
|
} |
283 |
|
|
|
284 |
|
|
void* Gmemscan(void *mem, unsigned int len, |
285 |
|
|
void *part, unsigned int partlen) { |
286 |
|
|
char* p; |
287 |
|
|
unsigned int restlen=len-partlen+1; |
288 |
|
|
void* oldp=mem; |
289 |
|
|
while ( (p=(char*)memchr(oldp, ((char*)part)[0], restlen))!=NULL) { |
290 |
|
|
//located first char, try to match the rest: |
291 |
|
|
p++; |
292 |
|
|
if (memcmp(p, &((char*)part)[1], partlen-1)==0) return p-1; |
293 |
|
|
//no string match, prepare next iteration |
294 |
|
|
restlen-=(p-(char*)oldp); |
295 |
|
|
oldp=p; |
296 |
|
|
}//while |
297 |
|
|
return NULL; |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
//rindex function is missing on some platforms ? |
301 |
|
|
char* rstrchr(char* str, char ch) { /* returns a pointer to the rightmost |
302 |
|
|
occurence of ch in str */ |
303 |
|
|
char *p; |
304 |
|
|
if (str==NULL) return NULL; |
305 |
|
|
p=str+strlen(str)-1; |
306 |
|
|
while (p>=str) { |
307 |
|
|
if (*p==ch) return p; |
308 |
|
|
p--; |
309 |
|
|
} |
310 |
|
|
return NULL; |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
|
314 |
|
|
/* DOS/UNIX safer fgets : reads a text line from a (binary) file and |
315 |
|
|
update the file position accordingly and the buffer capacity accordingly. |
316 |
|
|
The given buf is resized to read the entire line in memory |
317 |
|
|
-- even when it's abnormally long |
318 |
|
|
*/ |
319 |
|
|
char* fgetline(char* & buf, int& buf_cap, FILE *stream, off_t* f_pos, int* linelen) { |
320 |
|
|
//reads a char at a time until \n and/or \r are encountered |
321 |
|
|
int i=0; |
322 |
|
|
int c=0; |
323 |
|
|
off_t fpos=(f_pos!=NULL) ? *f_pos : 0; |
324 |
|
|
while ((c=getc(stream))!=EOF) { |
325 |
|
|
if (i>=buf_cap-1) { |
326 |
|
|
buf_cap+=1024; |
327 |
|
|
GREALLOC(buf, buf_cap); |
328 |
|
|
} |
329 |
|
|
if (c=='\n' || c=='\r') { |
330 |
|
|
if (c=='\r') { |
331 |
|
|
if ((c=getc(stream))!='\n') ungetc(c,stream); |
332 |
|
|
else fpos++; |
333 |
|
|
} |
334 |
|
|
fpos++; |
335 |
|
|
break; |
336 |
|
|
} |
337 |
|
|
fpos++; |
338 |
|
|
buf[i]=(char)c; |
339 |
|
|
i++; |
340 |
|
|
} //while i<buf_cap-1 |
341 |
|
|
if (linelen!=NULL) *linelen=i; |
342 |
|
|
if (f_pos!=NULL) *f_pos=fpos; |
343 |
|
|
if (c==EOF && i==0) return NULL; |
344 |
|
|
buf[i]='\0'; |
345 |
|
|
return buf; |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
char* GLineReader::getLine(FILE* stream, off_t& f_pos) { |
349 |
|
|
if (pushed) { pushed=false; return buf; } |
350 |
|
|
//reads a char at a time until \n and/or \r are encountered |
351 |
|
|
len=0; |
352 |
|
|
int c=0; |
353 |
|
|
while ((c=getc(stream))!=EOF) { |
354 |
|
|
if (len>=allocated-1) { |
355 |
|
|
allocated+=1024; |
356 |
|
|
GREALLOC(buf, allocated); |
357 |
|
|
} |
358 |
|
|
if (c=='\n' || c=='\r') { |
359 |
|
|
buf[len]='\0'; |
360 |
|
|
if (c=='\r') { //DOS file -- special case |
361 |
|
|
if ((c=getc(stream))!='\n') ungetc(c,stream); |
362 |
|
|
else f_pos++; |
363 |
|
|
} |
364 |
|
|
f_pos++; |
365 |
|
|
lcount++; |
366 |
|
|
return buf; |
367 |
|
|
} |
368 |
|
|
f_pos++; |
369 |
|
|
buf[len]=(char)c; |
370 |
|
|
len++; |
371 |
|
|
} //while i<buf_cap-1 |
372 |
|
|
if (c==EOF) { |
373 |
|
|
isEOF=true; |
374 |
|
|
if (len==0) return NULL; |
375 |
|
|
} |
376 |
|
|
buf[len]='\0'; |
377 |
|
|
lcount++; |
378 |
|
|
return buf; |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
|
382 |
|
|
//strchr but with a set of chars instead of only one |
383 |
gpertea |
16 |
char* strchrs(const char* s, const char* chrs) { |
384 |
gpertea |
2 |
if (s==NULL || chrs==NULL || *chrs=='\0' || *s=='\0') |
385 |
|
|
return NULL; |
386 |
|
|
unsigned int l=strlen(s); |
387 |
|
|
unsigned int r=strcspn(s, chrs); |
388 |
|
|
if (r==l) return NULL; |
389 |
gpertea |
16 |
return ((char*)s+r); |
390 |
gpertea |
2 |
} |
391 |
|
|
|
392 |
|
|
char* upCase(const char* str) { |
393 |
|
|
if (str==NULL) return NULL; |
394 |
|
|
int len=strlen(str); |
395 |
|
|
char* upstr; |
396 |
|
|
GMALLOC(upstr, len+1); |
397 |
|
|
upstr[len]='\0'; |
398 |
|
|
for (int i=0;i<len;i++) upstr[i]=toupper(str[i]); |
399 |
|
|
return upstr; |
400 |
|
|
} |
401 |
|
|
|
402 |
|
|
char* loCase(const char* str) { |
403 |
|
|
if (str==NULL) return NULL; |
404 |
|
|
int len=strlen(str); |
405 |
|
|
char* lostr; |
406 |
|
|
GMALLOC(lostr, len+1); |
407 |
|
|
lostr[len]='\0'; |
408 |
|
|
for (int i=0;i<len;i++) lostr[i]=tolower(str[i]); |
409 |
|
|
return lostr; |
410 |
|
|
} |
411 |
|
|
|
412 |
|
|
char* strlower(char * str) {//changes string in place |
413 |
|
|
if (str==NULL) return NULL; |
414 |
|
|
int i=0; |
415 |
|
|
while (str[i]!=0) { str[i]=tolower(str[i]); i++; } |
416 |
|
|
return str; |
417 |
|
|
} |
418 |
|
|
|
419 |
|
|
char* strupper(char * str) {//changes string in place |
420 |
|
|
if (str==NULL) return NULL; |
421 |
|
|
int i=0; |
422 |
|
|
while (str[i]!=0) { str[i]=toupper(str[i]); i++; } |
423 |
|
|
return str; |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
|
427 |
|
|
|
428 |
|
|
//test if a char is in a given string (set) |
429 |
gpertea |
16 |
bool chrInStr(char c, const char* str) { |
430 |
gpertea |
2 |
if (str==NULL || *str=='\0') return false; |
431 |
gpertea |
16 |
for (const char* p=str; (*p)!='\0'; p++) { |
432 |
gpertea |
2 |
if ((*p)==c) return true; |
433 |
|
|
} |
434 |
|
|
return false; |
435 |
|
|
} |
436 |
|
|
|
437 |
|
|
|
438 |
|
|
|
439 |
gpertea |
16 |
char* rstrfind(const char* str, const char* substr) { |
440 |
gpertea |
2 |
/* like rindex() for a string */ |
441 |
|
|
int l,i; |
442 |
|
|
if (str==NULL || *str=='\0') return NULL; |
443 |
|
|
if (substr==NULL || *substr=='\0') return NULL; |
444 |
|
|
l=strlen(substr); |
445 |
gpertea |
16 |
char* p=(char*)str+strlen(str)-l; |
446 |
gpertea |
2 |
//rightmost position that could match |
447 |
|
|
|
448 |
|
|
while (p>=str) { |
449 |
gpertea |
16 |
for (i=0; i<l && *(p+i) == *(substr+i); i++) ; |
450 |
gpertea |
2 |
if (i==l) return p; //found! |
451 |
|
|
p--; |
452 |
|
|
} |
453 |
|
|
return NULL; |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
|
457 |
gpertea |
16 |
char* strifind(const char* str, const char* substr) { |
458 |
gpertea |
2 |
// the case insensitive version of strstr -- finding a string within a strin |
459 |
|
|
int l,i; |
460 |
|
|
if (str==NULL || *str==0) return NULL; |
461 |
|
|
if (substr==NULL || *substr==0) return NULL; |
462 |
|
|
l=strlen(substr); |
463 |
gpertea |
16 |
char* smax=(char*)str+strlen(str)-l; |
464 |
gpertea |
2 |
//rightmost position that could match |
465 |
gpertea |
16 |
char* p=(char*)str; |
466 |
gpertea |
2 |
while (p<=smax) { |
467 |
gpertea |
16 |
for (i=0; i<l && tolower(*(p+i))==tolower(*(substr+i)); i++) ; |
468 |
gpertea |
2 |
if (i==l) return p; //found! |
469 |
|
|
p++; |
470 |
|
|
} |
471 |
|
|
return NULL; |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
|
475 |
|
|
|
476 |
|
|
// tests if string s has the given prefix |
477 |
gpertea |
16 |
bool startsWith(const char* s, const char* prefix) { |
478 |
gpertea |
2 |
if (prefix==NULL || s==NULL) return false; |
479 |
|
|
int i=0; |
480 |
|
|
while (prefix[i]!='\0' && prefix[i]==s[i]) i++; |
481 |
|
|
return (prefix[i]=='\0'); |
482 |
|
|
} |
483 |
|
|
|
484 |
gpertea |
16 |
// tests if string s ends with given suffix |
485 |
|
|
bool endsWith(const char* s, const char* suffix) { |
486 |
|
|
if (suffix==NULL || s==NULL) return false; |
487 |
|
|
if (suffix[0]==0) return true; //special case: empty suffix |
488 |
|
|
int j=strlen(suffix)-1; |
489 |
|
|
int i=strlen(s)-1; |
490 |
|
|
if (i<j) return false; |
491 |
|
|
while (j>=0 && s[i]==suffix[j]) { i--; j--; } |
492 |
|
|
return (j==-1); |
493 |
|
|
} |
494 |
gpertea |
2 |
|
495 |
gpertea |
16 |
|
496 |
gpertea |
2 |
char* reverseChars(char* str, int slen) { |
497 |
|
|
if (slen==0) slen=strlen(str); |
498 |
|
|
int l=0; |
499 |
|
|
int r=slen-1; |
500 |
gpertea |
90 |
char c; |
501 |
gpertea |
2 |
while (l<r) { |
502 |
|
|
c=str[l];str[l]=str[r]; |
503 |
|
|
str[r]=c; |
504 |
|
|
l++;r--; |
505 |
|
|
} |
506 |
|
|
return str; |
507 |
|
|
} |
508 |
|
|
|
509 |
|
|
|
510 |
gpertea |
16 |
char* rstrstr(const char* rstart, const char *lend, const char* substr) { /*like strstr, but starts searching |
511 |
gpertea |
2 |
from right end, going up to lend and returns a pointer to the last (right) |
512 |
|
|
matching character in str */ |
513 |
|
|
char *p; |
514 |
|
|
int l,i; |
515 |
|
|
l=strlen(substr); |
516 |
gpertea |
16 |
p=(char*)rstart-l+1; |
517 |
gpertea |
2 |
while (p>=lend) { |
518 |
|
|
for (i=0;i<l;i++) if (*(p+i) != *(substr+i)) break; |
519 |
|
|
if (i==l) return p+l-1; |
520 |
|
|
p--; |
521 |
|
|
} |
522 |
|
|
return NULL; |
523 |
|
|
} |
524 |
|
|
|
525 |
|
|
|
526 |
|
|
//hash function used for strings in GHash |
527 |
|
|
int strhash(const char* str){ |
528 |
|
|
register int h=0; |
529 |
|
|
register int g; |
530 |
|
|
while (*str) { |
531 |
|
|
h=(h<<4)+*str++; |
532 |
|
|
g=h&0xF0000000; |
533 |
|
|
if(g) h^=g>>24; |
534 |
|
|
h&=0x0fffffff; |
535 |
|
|
} |
536 |
|
|
GASSERT(h<=0x0fffffff); |
537 |
|
|
return h; |
538 |
|
|
} |
539 |
|
|
|
540 |
gpertea |
16 |
// removes the last part (file or directory name) of a full path |
541 |
gpertea |
2 |
// this is a destructive operation for the given string!!! |
542 |
|
|
// the trailing '/' is guaranteed to be there |
543 |
|
|
void delFileName(char* filepath) { |
544 |
|
|
char *p, *sep; |
545 |
|
|
if (filepath==NULL) return; |
546 |
|
|
for (p=filepath, sep=filepath;*p!='\0';p++) |
547 |
gpertea |
16 |
if (*p=='/' || *p=='\\') sep=p+1; |
548 |
gpertea |
2 |
*sep='\0'; // truncate filepath |
549 |
|
|
} |
550 |
|
|
|
551 |
gpertea |
16 |
// returns a pointer to the last file or directory name in a full path |
552 |
|
|
const char* getFileName(const char* filepath) { |
553 |
|
|
const char *p, *sep; |
554 |
gpertea |
2 |
if (filepath==NULL) return NULL; |
555 |
|
|
for (p=filepath, sep=filepath;*p!='\0';p++) |
556 |
gpertea |
16 |
if (*p=='/' || *p=='\\') sep=p+1; |
557 |
gpertea |
2 |
return sep; |
558 |
|
|
} |
559 |
|
|
|
560 |
gpertea |
16 |
// returns a pointer to the file "extension" part in a filename |
561 |
|
|
const char* getFileExt(const char* filepath) { |
562 |
|
|
const char *p, *dp, *sep; |
563 |
|
|
if (filepath==NULL) return NULL; |
564 |
|
|
for (p=filepath, dp=filepath, sep=filepath;*p!='\0';p++) { |
565 |
|
|
if (*p=='.') dp=p+1; |
566 |
|
|
else if (*p=='/' || *p=='\\') |
567 |
|
|
sep=p+1; |
568 |
|
|
} |
569 |
|
|
return (dp>sep) ? dp : NULL ; |
570 |
|
|
} |
571 |
|
|
|
572 |
gpertea |
2 |
int fileExists(const char* fname) { |
573 |
|
|
struct stat stFileInfo; |
574 |
|
|
int r=0; |
575 |
|
|
// Attempt to get the file attributes |
576 |
|
|
int fs = stat(fname,&stFileInfo); |
577 |
|
|
if (fs == 0) { |
578 |
|
|
r=3; |
579 |
|
|
// We were able to get the file attributes |
580 |
|
|
// so the file obviously exists. |
581 |
|
|
if (S_ISREG (stFileInfo.st_mode)) { |
582 |
|
|
r=2; |
583 |
|
|
} |
584 |
|
|
if (S_ISDIR (stFileInfo.st_mode)) { |
585 |
|
|
r=1; |
586 |
|
|
} |
587 |
|
|
} |
588 |
|
|
return r; |
589 |
|
|
} |
590 |
|
|
|
591 |
|
|
/*bool fileExists(const char* filepath) { |
592 |
|
|
if (filepath==NULL) return false; |
593 |
|
|
FILE* ft=fopen(filepath, "rb"); |
594 |
|
|
if (ft==NULL) return false; |
595 |
|
|
fclose(ft); |
596 |
|
|
return true; |
597 |
|
|
} |
598 |
|
|
*/ |
599 |
gpertea |
16 |
int64 fileSize(const char* fpath) { |
600 |
gpertea |
2 |
struct stat results; |
601 |
|
|
if (stat(fpath, &results) == 0) |
602 |
|
|
// The size of the file in bytes is in |
603 |
gpertea |
16 |
return (int64)results.st_size; |
604 |
gpertea |
2 |
else |
605 |
|
|
// An error occurred |
606 |
gpertea |
16 |
//GMessage("Error at stat(%s)!\n", fpath); |
607 |
gpertea |
2 |
return 0; |
608 |
|
|
} |
609 |
|
|
|
610 |
|
|
bool parseNumber(char* &p, double& v) { |
611 |
|
|
//skip any spaces.. |
612 |
|
|
while (*p==' ' || *p=='\t') p++; |
613 |
|
|
char* start=p; |
614 |
|
|
/*if (*p=='-') p++; |
615 |
|
|
else if (*p=='+') { p++;start++; }*/ |
616 |
|
|
|
617 |
|
|
/* while ((*p>='1' && *p<='9') || *p=='0' || |
618 |
|
|
*p=='.' || *p=='-' || tolower(*p)=='e') p++; */ |
619 |
|
|
int numlen=strspn(start, "0123456789eE.-+"); |
620 |
|
|
p=start+numlen; |
621 |
|
|
//now p is on a non-digit; |
622 |
|
|
if (*start=='-' && p==start+1) return false; |
623 |
|
|
char saved=*p; |
624 |
|
|
*p='\0'; |
625 |
|
|
char* endptr=p; |
626 |
|
|
v=strtod(start,&endptr); |
627 |
|
|
*p=saved; |
628 |
|
|
if (endptr!=p) return false; |
629 |
|
|
return true; |
630 |
|
|
} |
631 |
|
|
|
632 |
|
|
|
633 |
|
|
bool parseDouble(char* &p, double& v) { |
634 |
|
|
return parseNumber(p,v); |
635 |
|
|
} |
636 |
|
|
|
637 |
|
|
bool parseInt(char* &p, int& i) { |
638 |
|
|
while (*p==' ' || *p=='\t') p++; |
639 |
|
|
char* start=p; |
640 |
|
|
if (*p=='-') p++; |
641 |
|
|
else if (*p=='+') { p++;start++; } |
642 |
|
|
while ((*p>='1' && *p<='9') || *p=='0') p++; |
643 |
|
|
//now p is on a non-digit; |
644 |
|
|
if (*start=='-' && p==start+1) return false; |
645 |
|
|
char saved=*p; |
646 |
|
|
*p='\0'; |
647 |
|
|
char* endptr=p; |
648 |
|
|
long l=strtol(start,&endptr,10); |
649 |
|
|
i=(int)l; |
650 |
|
|
*p=saved; |
651 |
|
|
if (endptr!=p || i!=l) return false; |
652 |
|
|
return true; |
653 |
|
|
} |
654 |
|
|
|
655 |
|
|
bool parseUInt(char* &p, uint& i) { |
656 |
|
|
while (*p==' ' || *p=='\t') p++; |
657 |
|
|
char* start=p; |
658 |
|
|
if (*p=='-') return false; |
659 |
|
|
else if (*p=='+') { p++;start++; } |
660 |
|
|
while ((*p>='1' && *p<='9') || *p=='0') p++; |
661 |
|
|
//now p is on a non-digit; |
662 |
|
|
if (*start=='-' && p==start+1) return false; |
663 |
|
|
char saved=*p; |
664 |
|
|
*p='\0'; |
665 |
|
|
char* endptr=p; |
666 |
|
|
unsigned long l=strtoul(start,&endptr,10); |
667 |
|
|
i=(uint) l; |
668 |
|
|
*p=saved; |
669 |
|
|
if (endptr!=p || i!=l) return false; |
670 |
|
|
return true; |
671 |
|
|
} |
672 |
|
|
|
673 |
|
|
bool parseHex(char* &p, uint& i) { |
674 |
|
|
//skip initial spaces/prefix |
675 |
|
|
while (*p==' ' || *p=='\t' || *p=='0' || *p=='x') p++; |
676 |
|
|
char* start=p; |
677 |
|
|
if (*p=='-') return false; |
678 |
|
|
else if (*p=='+') { p++;start++; } |
679 |
|
|
while (isxdigit(*p)) p++; |
680 |
|
|
//now p is on a non-hexdigit; |
681 |
|
|
if (p==start+1) return false; |
682 |
|
|
char saved=*p; |
683 |
|
|
*p='\0'; |
684 |
|
|
char* endptr=p; |
685 |
|
|
unsigned long l=strtoul(start,&endptr,16); |
686 |
|
|
i=(uint) l; |
687 |
|
|
*p=saved; |
688 |
|
|
if (endptr!=p || i!=l) return false; |
689 |
|
|
return true; |
690 |
|
|
} |
691 |
|
|
|
692 |
gpertea |
16 |
//write a formatted fasta record, fasta formatted |
693 |
|
|
void writeFasta(FILE *fw, const char* seqid, const char* descr, |
694 |
|
|
const char* seq, int linelen, int seqlen) { |
695 |
|
|
fflush(fw); |
696 |
|
|
// write header line only if given! |
697 |
|
|
if (seqid!=NULL) { |
698 |
|
|
if (descr==NULL || descr[0]==0) |
699 |
|
|
fprintf(fw,">%s\n",seqid); |
700 |
|
|
else fprintf(fw,">%s %s\n",seqid, descr); |
701 |
|
|
} |
702 |
|
|
fflush(fw); |
703 |
|
|
if (seq==NULL || *seq==0) return; //nothing to print |
704 |
|
|
if (linelen==0) { //unlimited line length: write the whole sequence on a line |
705 |
|
|
if (seqlen>0) |
706 |
|
|
fwrite((const void*)seq, 1, seqlen,fw); |
707 |
|
|
else fprintf(fw,"%s",seq); |
708 |
|
|
fprintf(fw,"\n"); |
709 |
|
|
fflush(fw); |
710 |
|
|
return; |
711 |
|
|
} |
712 |
|
|
int ilen=0; |
713 |
|
|
if (seqlen>0) { //seq length given, so we know when to stop |
714 |
|
|
for (int i=0; i < seqlen; i++, ilen++) { |
715 |
|
|
if (ilen == linelen) { |
716 |
|
|
fputc('\n', fw); |
717 |
|
|
ilen = 0; |
718 |
|
|
} |
719 |
|
|
fputc(seq[i], fw); |
720 |
|
|
} |
721 |
|
|
fputc('\n', fw); |
722 |
|
|
} |
723 |
|
|
else { //seq length not given, stop when 0 encountered |
724 |
|
|
for (int i=0; seq[i]!=0; i++, ilen++) { |
725 |
|
|
if (ilen == linelen) { |
726 |
|
|
fputc('\n', fw); |
727 |
|
|
ilen = 0; |
728 |
|
|
} |
729 |
|
|
fputc(seq[i], fw); |
730 |
|
|
} //for |
731 |
|
|
fputc('\n', fw); |
732 |
|
|
} |
733 |
|
|
fflush(fw); |
734 |
|
|
} |
735 |
|
|
|
736 |
|
|
char* commaprint(uint64 n) { |
737 |
|
|
static int comma = '\0'; |
738 |
|
|
static char retbuf[48]; |
739 |
|
|
char *p = &retbuf[sizeof(retbuf)-1]; |
740 |
|
|
int i = 0; |
741 |
|
|
if(comma == '\0') { |
742 |
|
|
/* struct lconv *lcp = localeconv(); |
743 |
|
|
if(lcp != NULL) { |
744 |
|
|
if(lcp->thousands_sep != NULL && |
745 |
|
|
*lcp->thousands_sep != '\0') |
746 |
|
|
comma = *lcp->thousands_sep; |
747 |
|
|
else */ |
748 |
|
|
comma = ','; |
749 |
|
|
// } |
750 |
|
|
} |
751 |
|
|
*p = '\0'; |
752 |
|
|
do { |
753 |
|
|
if(i%3 == 0 && i != 0) |
754 |
|
|
*--p = comma; |
755 |
|
|
*--p = '0' + n % 10; |
756 |
|
|
n /= 10; |
757 |
|
|
i++; |
758 |
|
|
} while(n != 0); |
759 |
|
|
return p; |
760 |
|
|
} |