ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GBase.cpp
Revision: 258
Committed: Tue Jun 26 22:29:50 2012 UTC (7 years, 3 months ago) by gpertea
File size: 18718 byte(s)
Log Message:
commented out saprintf(), not used

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