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