ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GBase.cpp
Revision: 16
Committed: Mon Jul 18 20:56:02 2011 UTC (7 years, 10 months ago) by gpertea
File size: 18165 byte(s)
Log Message:
sync with local source

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