tran.c revision 146299
185587Sobrien/**************************************************************** 285587SobrienCopyright (C) Lucent Technologies 1997 385587SobrienAll Rights Reserved 485587Sobrien 585587SobrienPermission to use, copy, modify, and distribute this software and 685587Sobrienits documentation for any purpose and without fee is hereby 785587Sobriengranted, provided that the above copyright notice appear in all 885587Sobriencopies and that both that the copyright notice and this 985587Sobrienpermission notice and warranty disclaimer appear in supporting 1085587Sobriendocumentation, and that the name Lucent Technologies or any of 1185587Sobrienits entities not be used in advertising or publicity pertaining 1285587Sobriento distribution of the software without specific, written prior 1385587Sobrienpermission. 1485587Sobrien 1585587SobrienLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1685587SobrienINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 1785587SobrienIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 1885587SobrienSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1985587SobrienWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 2085587SobrienIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2185587SobrienARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 2285587SobrienTHIS SOFTWARE. 2385587Sobrien****************************************************************/ 2485587Sobrien 2585587Sobrien#define DEBUG 2685587Sobrien#include <stdio.h> 2785587Sobrien#include <math.h> 2885587Sobrien#include <ctype.h> 2985587Sobrien#include <string.h> 3085587Sobrien#include <stdlib.h> 3185587Sobrien#include "awk.h" 3285587Sobrien#include "ytab.h" 3385587Sobrien 3485587Sobrien#define FULLTAB 2 /* rehash when table gets this x full */ 3585587Sobrien#define GROWTAB 4 /* grow table by this factor */ 3685587Sobrien 3785587SobrienArray *symtab; /* main symbol table */ 3885587Sobrien 3985587Sobrienchar **FS; /* initial field sep */ 4085587Sobrienchar **RS; /* initial record sep */ 4185587Sobrienchar **OFS; /* output field sep */ 4285587Sobrienchar **ORS; /* output record sep */ 4385587Sobrienchar **OFMT; /* output format for numbers */ 4485587Sobrienchar **CONVFMT; /* format for conversions in getsval */ 4585587SobrienAwkfloat *NF; /* number of fields in current record */ 4685587SobrienAwkfloat *NR; /* number of current record */ 4785587SobrienAwkfloat *FNR; /* number of current record in current file */ 4885587Sobrienchar **FILENAME; /* current filename argument */ 4985587SobrienAwkfloat *ARGC; /* number of arguments from command line */ 5085587Sobrienchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 5185587SobrienAwkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 5285587SobrienAwkfloat *RLENGTH; /* length of same */ 5385587Sobrien 54146299SruCell *fsloc; /* FS */ 5585587SobrienCell *nrloc; /* NR */ 5685587SobrienCell *nfloc; /* NF */ 5785587SobrienCell *fnrloc; /* FNR */ 5885587SobrienArray *ARGVtab; /* symbol table containing ARGV[...] */ 5985587SobrienArray *ENVtab; /* symbol table containing ENVIRON[...] */ 6085587SobrienCell *rstartloc; /* RSTART */ 6185587SobrienCell *rlengthloc; /* RLENGTH */ 6285587SobrienCell *symtabloc; /* SYMTAB */ 6385587Sobrien 6485587SobrienCell *nullloc; /* a guaranteed empty cell */ 6585587SobrienNode *nullnode; /* zero&null, converted into a node for comparisons */ 6685587SobrienCell *literal0; 6785587Sobrien 6885587Sobrienextern Cell **fldtab; 6985587Sobrien 7085587Sobrienvoid syminit(void) /* initialize symbol table with builtin vars */ 7185587Sobrien{ 7285587Sobrien literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 7385587Sobrien /* this is used for if(x)... tests: */ 7485587Sobrien nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 7585587Sobrien nullnode = celltonode(nullloc, CCON); 7685587Sobrien 77146299Sru fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 78146299Sru FS = &fsloc->sval; 7985587Sobrien RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 8085587Sobrien OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; 8185587Sobrien ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 8285587Sobrien OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 8385587Sobrien CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 8485587Sobrien FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 8585587Sobrien nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 8685587Sobrien NF = &nfloc->fval; 8785587Sobrien nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 8885587Sobrien NR = &nrloc->fval; 8985587Sobrien fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 9085587Sobrien FNR = &fnrloc->fval; 9185587Sobrien SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; 9285587Sobrien rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 9385587Sobrien RSTART = &rstartloc->fval; 9485587Sobrien rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 9585587Sobrien RLENGTH = &rlengthloc->fval; 9685587Sobrien symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 9785587Sobrien symtabloc->sval = (char *) symtab; 9885587Sobrien} 9985587Sobrien 10085587Sobrienvoid arginit(int ac, char **av) /* set up ARGV and ARGC */ 10185587Sobrien{ 10285587Sobrien Cell *cp; 10385587Sobrien int i; 10485587Sobrien char temp[50]; 10585587Sobrien 10685587Sobrien ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 10785587Sobrien cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 10885587Sobrien ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 10985587Sobrien cp->sval = (char *) ARGVtab; 11085587Sobrien for (i = 0; i < ac; i++) { 11185587Sobrien sprintf(temp, "%d", i); 11285587Sobrien if (is_number(*av)) 11385587Sobrien setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 11485587Sobrien else 11585587Sobrien setsymtab(temp, *av, 0.0, STR, ARGVtab); 11685587Sobrien av++; 11785587Sobrien } 11885587Sobrien} 11985587Sobrien 12085587Sobrienvoid envinit(char **envp) /* set up ENVIRON variable */ 12185587Sobrien{ 12285587Sobrien Cell *cp; 12385587Sobrien char *p; 12485587Sobrien 12585587Sobrien cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 12685587Sobrien ENVtab = makesymtab(NSYMTAB); 12785587Sobrien cp->sval = (char *) ENVtab; 12885587Sobrien for ( ; *envp; envp++) { 12985587Sobrien if ((p = strchr(*envp, '=')) == NULL) 13085587Sobrien continue; 13185587Sobrien if( p == *envp ) /* no left hand side name in env string */ 13285587Sobrien continue; 13385587Sobrien *p++ = 0; /* split into two strings at = */ 13485587Sobrien if (is_number(p)) 13585587Sobrien setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 13685587Sobrien else 13785587Sobrien setsymtab(*envp, p, 0.0, STR, ENVtab); 13885587Sobrien p[-1] = '='; /* restore in case env is passed down to a shell */ 13985587Sobrien } 14085587Sobrien} 14185587Sobrien 14285587SobrienArray *makesymtab(int n) /* make a new symbol table */ 14385587Sobrien{ 14485587Sobrien Array *ap; 14585587Sobrien Cell **tp; 14685587Sobrien 14785587Sobrien ap = (Array *) malloc(sizeof(Array)); 14885587Sobrien tp = (Cell **) calloc(n, sizeof(Cell *)); 14985587Sobrien if (ap == NULL || tp == NULL) 15085587Sobrien FATAL("out of space in makesymtab"); 15185587Sobrien ap->nelem = 0; 15285587Sobrien ap->size = n; 15385587Sobrien ap->tab = tp; 15485587Sobrien return(ap); 15585587Sobrien} 15685587Sobrien 15785587Sobrienvoid freesymtab(Cell *ap) /* free a symbol table */ 15885587Sobrien{ 15985587Sobrien Cell *cp, *temp; 16085587Sobrien Array *tp; 16185587Sobrien int i; 16285587Sobrien 16385587Sobrien if (!isarr(ap)) 16485587Sobrien return; 16585587Sobrien tp = (Array *) ap->sval; 16685587Sobrien if (tp == NULL) 16785587Sobrien return; 16885587Sobrien for (i = 0; i < tp->size; i++) { 16985587Sobrien for (cp = tp->tab[i]; cp != NULL; cp = temp) { 17085587Sobrien xfree(cp->nval); 17185587Sobrien if (freeable(cp)) 17285587Sobrien xfree(cp->sval); 17385587Sobrien temp = cp->cnext; /* avoids freeing then using */ 17485587Sobrien free(cp); 17590902Sdes tp->nelem--; 17685587Sobrien } 17785587Sobrien tp->tab[i] = 0; 17885587Sobrien } 17990902Sdes if (tp->nelem != 0) 18090902Sdes WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 18185587Sobrien free(tp->tab); 18285587Sobrien free(tp); 18385587Sobrien} 18485587Sobrien 185107806Sobrienvoid freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 18685587Sobrien{ 18785587Sobrien Array *tp; 18885587Sobrien Cell *p, *prev = NULL; 18985587Sobrien int h; 19085587Sobrien 19185587Sobrien tp = (Array *) ap->sval; 19285587Sobrien h = hash(s, tp->size); 19385587Sobrien for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 19485587Sobrien if (strcmp(s, p->nval) == 0) { 19585587Sobrien if (prev == NULL) /* 1st one */ 19685587Sobrien tp->tab[h] = p->cnext; 19785587Sobrien else /* middle somewhere */ 19885587Sobrien prev->cnext = p->cnext; 19985587Sobrien if (freeable(p)) 20085587Sobrien xfree(p->sval); 20185587Sobrien free(p->nval); 20285587Sobrien free(p); 20385587Sobrien tp->nelem--; 20485587Sobrien return; 20585587Sobrien } 20685587Sobrien} 20785587Sobrien 208107806SobrienCell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 20985587Sobrien{ 21085587Sobrien int h; 21185587Sobrien Cell *p; 21285587Sobrien 21385587Sobrien if (n != NULL && (p = lookup(n, tp)) != NULL) { 21485587Sobrien dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 215107806Sobrien p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 21685587Sobrien return(p); 21785587Sobrien } 21885587Sobrien p = (Cell *) malloc(sizeof(Cell)); 21985587Sobrien if (p == NULL) 22085587Sobrien FATAL("out of space for symbol table at %s", n); 22185587Sobrien p->nval = tostring(n); 22285587Sobrien p->sval = s ? tostring(s) : tostring(""); 22385587Sobrien p->fval = f; 22485587Sobrien p->tval = t; 22585587Sobrien p->csub = CUNK; 22685587Sobrien p->ctype = OCELL; 22785587Sobrien tp->nelem++; 22885587Sobrien if (tp->nelem > FULLTAB * tp->size) 22985587Sobrien rehash(tp); 23085587Sobrien h = hash(n, tp->size); 23185587Sobrien p->cnext = tp->tab[h]; 23285587Sobrien tp->tab[h] = p; 23385587Sobrien dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 23485587Sobrien p, p->nval, p->sval, p->fval, p->tval) ); 23585587Sobrien return(p); 23685587Sobrien} 23785587Sobrien 238107806Sobrienint hash(const char *s, int n) /* form hash value for string s */ 23985587Sobrien{ 24085587Sobrien unsigned hashval; 24185587Sobrien 24285587Sobrien for (hashval = 0; *s != '\0'; s++) 24385587Sobrien hashval = (*s + 31 * hashval); 24485587Sobrien return hashval % n; 24585587Sobrien} 24685587Sobrien 24785587Sobrienvoid rehash(Array *tp) /* rehash items in small table into big one */ 24885587Sobrien{ 24985587Sobrien int i, nh, nsz; 25085587Sobrien Cell *cp, *op, **np; 25185587Sobrien 25285587Sobrien nsz = GROWTAB * tp->size; 25385587Sobrien np = (Cell **) calloc(nsz, sizeof(Cell *)); 25485587Sobrien if (np == NULL) /* can't do it, but can keep running. */ 25585587Sobrien return; /* someone else will run out later. */ 25685587Sobrien for (i = 0; i < tp->size; i++) { 25785587Sobrien for (cp = tp->tab[i]; cp; cp = op) { 25885587Sobrien op = cp->cnext; 25985587Sobrien nh = hash(cp->nval, nsz); 26085587Sobrien cp->cnext = np[nh]; 26185587Sobrien np[nh] = cp; 26285587Sobrien } 26385587Sobrien } 26485587Sobrien free(tp->tab); 26585587Sobrien tp->tab = np; 26685587Sobrien tp->size = nsz; 26785587Sobrien} 26885587Sobrien 269107806SobrienCell *lookup(const char *s, Array *tp) /* look for s in tp */ 27085587Sobrien{ 27185587Sobrien Cell *p; 27285587Sobrien int h; 27385587Sobrien 27485587Sobrien h = hash(s, tp->size); 27585587Sobrien for (p = tp->tab[h]; p != NULL; p = p->cnext) 27685587Sobrien if (strcmp(s, p->nval) == 0) 27785587Sobrien return(p); /* found it */ 27885587Sobrien return(NULL); /* not found */ 27985587Sobrien} 28085587Sobrien 28185587SobrienAwkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 28285587Sobrien{ 28385587Sobrien int fldno; 28485587Sobrien 28585587Sobrien if ((vp->tval & (NUM | STR)) == 0) 28685587Sobrien funnyvar(vp, "assign to"); 28785587Sobrien if (isfld(vp)) { 28885587Sobrien donerec = 0; /* mark $0 invalid */ 28985587Sobrien fldno = atoi(vp->nval); 29085587Sobrien if (fldno > *NF) 29185587Sobrien newfld(fldno); 29285587Sobrien dprintf( ("setting field %d to %g\n", fldno, f) ); 29385587Sobrien } else if (isrec(vp)) { 29485587Sobrien donefld = 0; /* mark $1... invalid */ 29585587Sobrien donerec = 1; 29685587Sobrien } 29785587Sobrien if (freeable(vp)) 29885587Sobrien xfree(vp->sval); /* free any previous string */ 29985587Sobrien vp->tval &= ~STR; /* mark string invalid */ 30085587Sobrien vp->tval |= NUM; /* mark number ok */ 301107806Sobrien dprintf( ("setfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), f, vp->tval) ); 30285587Sobrien return vp->fval = f; 30385587Sobrien} 30485587Sobrien 305107806Sobrienvoid funnyvar(Cell *vp, const char *rw) 30685587Sobrien{ 30785587Sobrien if (isarr(vp)) 30885587Sobrien FATAL("can't %s %s; it's an array name.", rw, vp->nval); 30985587Sobrien if (vp->tval & FCN) 31085587Sobrien FATAL("can't %s %s; it's a function.", rw, vp->nval); 31185587Sobrien WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 31285587Sobrien vp, vp->nval, vp->sval, vp->fval, vp->tval); 31385587Sobrien} 31485587Sobrien 315107806Sobrienchar *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 31685587Sobrien{ 31785587Sobrien char *t; 31885587Sobrien int fldno; 31985587Sobrien 320146299Sru dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 321146299Sru vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 32285587Sobrien if ((vp->tval & (NUM | STR)) == 0) 32385587Sobrien funnyvar(vp, "assign to"); 32485587Sobrien if (isfld(vp)) { 32585587Sobrien donerec = 0; /* mark $0 invalid */ 32685587Sobrien fldno = atoi(vp->nval); 32785587Sobrien if (fldno > *NF) 32885587Sobrien newfld(fldno); 32985587Sobrien dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 33085587Sobrien } else if (isrec(vp)) { 33185587Sobrien donefld = 0; /* mark $1... invalid */ 33285587Sobrien donerec = 1; 33385587Sobrien } 33485587Sobrien t = tostring(s); /* in case it's self-assign */ 33585587Sobrien vp->tval &= ~NUM; 33685587Sobrien vp->tval |= STR; 33785587Sobrien if (freeable(vp)) 33885587Sobrien xfree(vp->sval); 33985587Sobrien vp->tval &= ~DONTFREE; 340146299Sru dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 341146299Sru vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) ); 34285587Sobrien return(vp->sval = t); 34385587Sobrien} 34485587Sobrien 34585587SobrienAwkfloat getfval(Cell *vp) /* get float val of a Cell */ 34685587Sobrien{ 34785587Sobrien if ((vp->tval & (NUM | STR)) == 0) 34885587Sobrien funnyvar(vp, "read value of"); 34985587Sobrien if (isfld(vp) && donefld == 0) 35085587Sobrien fldbld(); 35185587Sobrien else if (isrec(vp) && donerec == 0) 35285587Sobrien recbld(); 35385587Sobrien if (!isnum(vp)) { /* not a number */ 35485587Sobrien vp->fval = atof(vp->sval); /* best guess */ 35585587Sobrien if (is_number(vp->sval) && !(vp->tval&CON)) 35685587Sobrien vp->tval |= NUM; /* make NUM only sparingly */ 35785587Sobrien } 358107806Sobrien dprintf( ("getfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), vp->fval, vp->tval) ); 35985587Sobrien return(vp->fval); 36085587Sobrien} 36185587Sobrien 362146299Srustatic char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 36385587Sobrien{ 36485587Sobrien char s[100]; /* BUG: unchecked */ 36585587Sobrien double dtemp; 36685587Sobrien 36785587Sobrien if ((vp->tval & (NUM | STR)) == 0) 36885587Sobrien funnyvar(vp, "read value of"); 36985587Sobrien if (isfld(vp) && donefld == 0) 37085587Sobrien fldbld(); 37185587Sobrien else if (isrec(vp) && donerec == 0) 37285587Sobrien recbld(); 37385587Sobrien if (isstr(vp) == 0) { 37485587Sobrien if (freeable(vp)) 37585587Sobrien xfree(vp->sval); 37685587Sobrien if (modf(vp->fval, &dtemp) == 0) /* it's integral */ 37785587Sobrien sprintf(s, "%.30g", vp->fval); 37885587Sobrien else 379107806Sobrien sprintf(s, *fmt, vp->fval); 38085587Sobrien vp->sval = tostring(s); 38185587Sobrien vp->tval &= ~DONTFREE; 38285587Sobrien vp->tval |= STR; 38385587Sobrien } 384107806Sobrien dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); 38585587Sobrien return(vp->sval); 38685587Sobrien} 38785587Sobrien 388107806Sobrienchar *getsval(Cell *vp) /* get string val of a Cell */ 38985587Sobrien{ 390107806Sobrien return get_str_val(vp, CONVFMT); 391107806Sobrien} 392107806Sobrien 393107806Sobrienchar *getpssval(Cell *vp) /* get string val of a Cell for print */ 394107806Sobrien{ 395107806Sobrien return get_str_val(vp, OFMT); 396107806Sobrien} 397107806Sobrien 398107806Sobrien 399107806Sobrienchar *tostring(const char *s) /* make a copy of string s */ 400107806Sobrien{ 40185587Sobrien char *p; 40285587Sobrien 40385587Sobrien p = (char *) malloc(strlen(s)+1); 40485587Sobrien if (p == NULL) 40585587Sobrien FATAL("out of space in tostring on %s", s); 40685587Sobrien strcpy(p, s); 40785587Sobrien return(p); 40885587Sobrien} 40985587Sobrien 410107806Sobrienchar *qstring(const char *is, int delim) /* collect string up to next delim */ 41185587Sobrien{ 412107806Sobrien const char *os = is; 41385587Sobrien int c, n; 41485587Sobrien uschar *s = (uschar *) is; 41585587Sobrien uschar *buf, *bp; 41685587Sobrien 41790902Sdes if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL) 41885587Sobrien FATAL( "out of space in qstring(%s)", s); 41985587Sobrien for (bp = buf; (c = *s) != delim; s++) { 42085587Sobrien if (c == '\n') 42185587Sobrien SYNTAX( "newline in string %.20s...", os ); 42285587Sobrien else if (c != '\\') 42385587Sobrien *bp++ = c; 42485587Sobrien else { /* \something */ 42585587Sobrien c = *++s; 42685587Sobrien if (c == 0) { /* \ at end */ 42785587Sobrien *bp++ = '\\'; 42885587Sobrien break; /* for loop */ 42985587Sobrien } 43085587Sobrien switch (c) { 43185587Sobrien case '\\': *bp++ = '\\'; break; 43285587Sobrien case 'n': *bp++ = '\n'; break; 43385587Sobrien case 't': *bp++ = '\t'; break; 43485587Sobrien case 'b': *bp++ = '\b'; break; 43585587Sobrien case 'f': *bp++ = '\f'; break; 43685587Sobrien case 'r': *bp++ = '\r'; break; 43785587Sobrien default: 43885587Sobrien if (!isdigit(c)) { 43985587Sobrien *bp++ = c; 44085587Sobrien break; 44185587Sobrien } 44285587Sobrien n = c - '0'; 44385587Sobrien if (isdigit(s[1])) { 44485587Sobrien n = 8 * n + *++s - '0'; 44585587Sobrien if (isdigit(s[1])) 44685587Sobrien n = 8 * n + *++s - '0'; 44785587Sobrien } 44885587Sobrien *bp++ = n; 44985587Sobrien break; 45085587Sobrien } 45185587Sobrien } 45285587Sobrien } 45385587Sobrien *bp++ = 0; 45485587Sobrien return (char *) buf; 45585587Sobrien} 456