ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GBase.cpp
Revision: 310
Committed: Fri Mar 22 20:06:27 2013 UTC (6 years, 7 months ago) by gpertea
File size: 18737 byte(s)
Log Message:
sync with igm repo

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