10Sstevel@tonic-gate /* 2356Smuffin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 70Sstevel@tonic-gate /* All Rights Reserved */ 80Sstevel@tonic-gate 90Sstevel@tonic-gate /* 100Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 110Sstevel@tonic-gate * All rights reserved. The Berkeley Software License Agreement 120Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 130Sstevel@tonic-gate */ 140Sstevel@tonic-gate 150Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 160Sstevel@tonic-gate 170Sstevel@tonic-gate #include "sh.h" 180Sstevel@tonic-gate #include "sh.tconst.h" 190Sstevel@tonic-gate #include <fcntl.h> 200Sstevel@tonic-gate #include <unistd.h> 210Sstevel@tonic-gate 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * C Shell 240Sstevel@tonic-gate */ 25356Smuffin tchar **blkcat(tchar **, tchar **); 26356Smuffin tchar **blkend(tchar **); 270Sstevel@tonic-gate 28356Smuffin int 29356Smuffin any(int c, tchar *s) 300Sstevel@tonic-gate { 310Sstevel@tonic-gate 320Sstevel@tonic-gate while (s && *s) 330Sstevel@tonic-gate if (*s++ == c) 340Sstevel@tonic-gate return (1); 350Sstevel@tonic-gate return (0); 360Sstevel@tonic-gate } 370Sstevel@tonic-gate 38356Smuffin int 39356Smuffin onlyread(tchar *cp) 400Sstevel@tonic-gate { 410Sstevel@tonic-gate extern char end[]; 420Sstevel@tonic-gate 430Sstevel@tonic-gate return ((char *)cp < end); 440Sstevel@tonic-gate } 450Sstevel@tonic-gate 460Sstevel@tonic-gate tchar * 47356Smuffin savestr(tchar *s) 480Sstevel@tonic-gate { 490Sstevel@tonic-gate tchar *n; 50356Smuffin tchar *p; 510Sstevel@tonic-gate 520Sstevel@tonic-gate if (s == 0) 530Sstevel@tonic-gate s = S_ /* "" */; 540Sstevel@tonic-gate #ifndef m32 550Sstevel@tonic-gate for (p = s; *p++; ) 560Sstevel@tonic-gate ; 57*559Snakanon n = p = (tchar *)xalloc((unsigned)(p - s)*sizeof (tchar)); 580Sstevel@tonic-gate while (*p++ = *s++) 590Sstevel@tonic-gate ; 600Sstevel@tonic-gate return (n); 610Sstevel@tonic-gate #else 620Sstevel@tonic-gate p = (tchar *) xalloc((strlen_(s) + 1)*sizeof (tchar)); 630Sstevel@tonic-gate strcpy_(p, s); 640Sstevel@tonic-gate return (p); 650Sstevel@tonic-gate #endif 660Sstevel@tonic-gate } 670Sstevel@tonic-gate 68*559Snakanon static void * 69*559Snakanon nomem(size_t i) 700Sstevel@tonic-gate { 710Sstevel@tonic-gate #ifdef debug 720Sstevel@tonic-gate static tchar *av[2] = {0, 0}; 730Sstevel@tonic-gate #endif 740Sstevel@tonic-gate 750Sstevel@tonic-gate child++; 760Sstevel@tonic-gate #ifndef debug 770Sstevel@tonic-gate error("Out of memory"); 780Sstevel@tonic-gate #ifdef lint 790Sstevel@tonic-gate i = i; 800Sstevel@tonic-gate #endif 810Sstevel@tonic-gate #else 820Sstevel@tonic-gate showall(av); 830Sstevel@tonic-gate printf("i=%d: Out of memory\n", i); 840Sstevel@tonic-gate chdir("/usr/bill/cshcore"); 850Sstevel@tonic-gate abort(); 860Sstevel@tonic-gate #endif 870Sstevel@tonic-gate return (0); /* fool lint */ 880Sstevel@tonic-gate } 890Sstevel@tonic-gate 900Sstevel@tonic-gate tchar ** 91356Smuffin blkend(tchar **up) 920Sstevel@tonic-gate { 930Sstevel@tonic-gate 940Sstevel@tonic-gate while (*up) 950Sstevel@tonic-gate up++; 960Sstevel@tonic-gate return (up); 970Sstevel@tonic-gate } 980Sstevel@tonic-gate 99356Smuffin void 100356Smuffin blkpr(tchar **av) 1010Sstevel@tonic-gate { 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate for (; *av; av++) { 1040Sstevel@tonic-gate printf("%t", *av); 1050Sstevel@tonic-gate if (av[1]) 1060Sstevel@tonic-gate printf(" "); 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 110356Smuffin int 111356Smuffin blklen(tchar **av) 1120Sstevel@tonic-gate { 113356Smuffin int i = 0; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate while (*av++) 1160Sstevel@tonic-gate i++; 1170Sstevel@tonic-gate return (i); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate tchar ** 121356Smuffin blkcpy(tchar **oav, tchar **bv) 1220Sstevel@tonic-gate { 123356Smuffin tchar **av = oav; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate while (*av++ = *bv++) 1260Sstevel@tonic-gate continue; 1270Sstevel@tonic-gate return (oav); 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate tchar ** 131356Smuffin blkcat(tchar **up, tchar **vp) 1320Sstevel@tonic-gate { 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate (void) blkcpy(blkend(up), vp); 1350Sstevel@tonic-gate return (up); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 138356Smuffin void 139356Smuffin blkfree(tchar **av0) 1400Sstevel@tonic-gate { 141356Smuffin tchar **av = av0; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate for (; *av; av++) 144*559Snakanon xfree(*av); 145*559Snakanon xfree(av0); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate tchar ** 149356Smuffin saveblk(tchar **v) 1500Sstevel@tonic-gate { 151356Smuffin tchar **newv = 152*559Snakanon (tchar **)xcalloc((unsigned)(blklen(v) + 1), 1530Sstevel@tonic-gate sizeof (tchar **)); 1540Sstevel@tonic-gate tchar **onewv = newv; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate while (*v) 1570Sstevel@tonic-gate *newv++ = savestr(*v++); 1580Sstevel@tonic-gate return (onewv); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate tchar * 162356Smuffin strspl(tchar *cp, tchar *dp) 1630Sstevel@tonic-gate { 1640Sstevel@tonic-gate tchar *ep; 165356Smuffin tchar *p, *q; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate #ifndef m32 1680Sstevel@tonic-gate for (p = cp; *p++; ) 1690Sstevel@tonic-gate ; 1700Sstevel@tonic-gate for (q = dp; *q++; ) 1710Sstevel@tonic-gate ; 172*559Snakanon ep = (tchar *) xalloc((unsigned)(((p - cp) + 1730Sstevel@tonic-gate (q - dp) - 1))*sizeof (tchar)); 1740Sstevel@tonic-gate for (p = ep, q = cp; *p++ = *q++; ) 1750Sstevel@tonic-gate ; 1760Sstevel@tonic-gate for (p--, q = dp; *p++ = *q++; ) 1770Sstevel@tonic-gate ; 1780Sstevel@tonic-gate #else 1790Sstevel@tonic-gate int len1 = strlen_(cp); 1800Sstevel@tonic-gate int len2 = strlen_(dp); 1810Sstevel@tonic-gate 182*559Snakanon ep = (tchar *)xalloc((unsigned)(len1 + len2 + 1)*sizeof (tchar)); 1830Sstevel@tonic-gate strcpy_(ep, cp); 1840Sstevel@tonic-gate strcat_(ep, dp); 1850Sstevel@tonic-gate #endif 1860Sstevel@tonic-gate return (ep); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate tchar ** 190356Smuffin blkspl(tchar **up, tchar **vp) 1910Sstevel@tonic-gate { 192356Smuffin tchar **wp = 193*559Snakanon (tchar **)xcalloc((unsigned)(blklen(up) + blklen(vp) + 1), 1940Sstevel@tonic-gate sizeof (tchar **)); 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate (void) blkcpy(wp, up); 1970Sstevel@tonic-gate return (blkcat(wp, vp)); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 200356Smuffin int 201356Smuffin lastchr(tchar *cp) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (!*cp) 2050Sstevel@tonic-gate return (0); 2060Sstevel@tonic-gate while (cp[1]) 2070Sstevel@tonic-gate cp++; 2080Sstevel@tonic-gate return (*cp); 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate 211356Smuffin void 212356Smuffin donefds(void) 2130Sstevel@tonic-gate { 2140Sstevel@tonic-gate (void) close(0); 2150Sstevel@tonic-gate (void) close(1); 2160Sstevel@tonic-gate (void) close(2); 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * To avoid NIS+ functions to get hold of 0/1/2, 2200Sstevel@tonic-gate * use descriptor 0, and dup it to 1 and 2. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate open("/dev/null", 0); 2230Sstevel@tonic-gate dup(0); dup(0); 2240Sstevel@tonic-gate didfds = 0; 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* 2280Sstevel@tonic-gate * Move descriptor i to j. 2290Sstevel@tonic-gate * If j is -1 then we just want to get i to a safe place, 2300Sstevel@tonic-gate * i.e. to a unit > 2. This also happens in dcopy. 2310Sstevel@tonic-gate */ 232356Smuffin int 233356Smuffin dmove(int i, int j) 2340Sstevel@tonic-gate { 2350Sstevel@tonic-gate int fd; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate if (i == j || i < 0) 2380Sstevel@tonic-gate return (i); 2390Sstevel@tonic-gate if (j >= 0) { 2400Sstevel@tonic-gate fd = dup2(i, j); 2410Sstevel@tonic-gate if (fd != -1) 2420Sstevel@tonic-gate setfd(fd); 2430Sstevel@tonic-gate } else 2440Sstevel@tonic-gate j = dcopy(i, j); 2450Sstevel@tonic-gate if (j != i) { 2460Sstevel@tonic-gate (void) close(i); 2470Sstevel@tonic-gate unsetfd(i); 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate return (j); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 252356Smuffin int 253356Smuffin dcopy(int i, int j) 2540Sstevel@tonic-gate { 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate int fd; 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate if (i == j || i < 0 || j < 0 && i > 2) 2590Sstevel@tonic-gate return (i); 2600Sstevel@tonic-gate if (j >= 0) { 2610Sstevel@tonic-gate fd = dup2(i, j); 2620Sstevel@tonic-gate if (fd != -1) 2630Sstevel@tonic-gate setfd(fd); 2640Sstevel@tonic-gate return (j); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate (void) close(j); 2670Sstevel@tonic-gate unsetfd(j); 2680Sstevel@tonic-gate return (renum(i, j)); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 271356Smuffin int 272356Smuffin renum(int i, int j) 2730Sstevel@tonic-gate { 274356Smuffin int k = dup(i); 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate if (k < 0) 2770Sstevel@tonic-gate return (-1); 2780Sstevel@tonic-gate if (j == -1 && k > 2) { 2790Sstevel@tonic-gate setfd(k); 2800Sstevel@tonic-gate return (k); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate if (k != j) { 2830Sstevel@tonic-gate j = renum(k, j); 2840Sstevel@tonic-gate (void) close(k); /* no need ofr unsetfd() */ 2850Sstevel@tonic-gate return (j); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate return (k); 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate #ifndef copy 291356Smuffin void 292356Smuffin copy(tchar *to, tchar *from, int size) 2930Sstevel@tonic-gate { 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate if (size) 2960Sstevel@tonic-gate do 2970Sstevel@tonic-gate *to++ = *from++; 2980Sstevel@tonic-gate while (--size != 0); 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate #endif 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate /* 3030Sstevel@tonic-gate * Left shift a command argument list, discarding 3040Sstevel@tonic-gate * the first c arguments. Used in "shift" commands 3050Sstevel@tonic-gate * as well as by commands like "repeat". 3060Sstevel@tonic-gate */ 307356Smuffin void 308356Smuffin lshift(tchar **v, int c) 3090Sstevel@tonic-gate { 310356Smuffin tchar **u = v; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate while (*u && --c >= 0) 313356Smuffin xfree((char *)*u++); 3140Sstevel@tonic-gate (void) blkcpy(v, u); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 317356Smuffin int 318356Smuffin number(tchar *cp) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate if (*cp == '-') { 3220Sstevel@tonic-gate cp++; 3230Sstevel@tonic-gate if (!digit(*cp++)) 3240Sstevel@tonic-gate return (0); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate while (*cp && digit(*cp)) 3270Sstevel@tonic-gate cp++; 3280Sstevel@tonic-gate return (*cp == 0); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate tchar ** 332356Smuffin copyblk(tchar **v) 3330Sstevel@tonic-gate { 334356Smuffin tchar **nv = 335*559Snakanon (tchar **)xcalloc((unsigned)(blklen(v) + 1), 3360Sstevel@tonic-gate sizeof (tchar **)); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate return (blkcpy(nv, v)); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate tchar * 342356Smuffin strend(tchar *cp) 3430Sstevel@tonic-gate { 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate while (*cp) 3460Sstevel@tonic-gate cp++; 3470Sstevel@tonic-gate return (cp); 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate tchar * 351356Smuffin strip(tchar *cp) 3520Sstevel@tonic-gate { 353356Smuffin tchar *dp = cp; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate while (*dp++ &= TRIM) 3560Sstevel@tonic-gate continue; 3570Sstevel@tonic-gate return (cp); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 360356Smuffin void 361356Smuffin udvar(tchar *name) 3620Sstevel@tonic-gate { 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate setname(name); 3650Sstevel@tonic-gate bferr("Undefined variable"); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 368356Smuffin int 369356Smuffin prefix(tchar *sub, tchar *str) 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate for (;;) { 3730Sstevel@tonic-gate if (*sub == 0) 3740Sstevel@tonic-gate return (1); 3750Sstevel@tonic-gate if (*str == 0) 3760Sstevel@tonic-gate return (0); 3770Sstevel@tonic-gate if (*sub++ != *str++) 3780Sstevel@tonic-gate return (0); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * blk*_ routines 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate char ** 387356Smuffin blkend_(char **up) 3880Sstevel@tonic-gate { 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate while (*up) 3910Sstevel@tonic-gate up++; 3920Sstevel@tonic-gate return (up); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 395356Smuffin int 396356Smuffin blklen_(char **av) 3970Sstevel@tonic-gate { 398356Smuffin int i = 0; 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate while (*av++) 4010Sstevel@tonic-gate i++; 4020Sstevel@tonic-gate return (i); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate char ** 406356Smuffin blkcpy_(char **oav, char **bv) 4070Sstevel@tonic-gate { 408356Smuffin char **av = oav; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate while (*av++ = *bv++) 4110Sstevel@tonic-gate continue; 4120Sstevel@tonic-gate return (oav); 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate char ** 416356Smuffin blkcat_(char **up, char **vp) 4170Sstevel@tonic-gate { 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate (void) blkcpy_(blkend_(up), vp); 4200Sstevel@tonic-gate return (up); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate char ** 424356Smuffin blkspl_(char **up, char **vp) 4250Sstevel@tonic-gate { 426356Smuffin char **wp = 427*559Snakanon (char **)xcalloc((unsigned)(blklen_(up) + blklen_(vp) + 1), 4280Sstevel@tonic-gate sizeof (char **)); 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate (void) blkcpy_(wp, up); 4310Sstevel@tonic-gate return (blkcat_(wp, vp)); 4320Sstevel@tonic-gate } 433*559Snakanon 434*559Snakanon /* 435*559Snakanon * If stack address was passed to free(), we have no good way to see if 436*559Snakanon * they are really in the stack. Therefore, we record the bottom of heap, 437*559Snakanon * and filter out the address not within heap's top(end) and bottom 438*559Snakanon * (xalloc_bottom). 439*559Snakanon */ 440*559Snakanon extern char end[]; 441*559Snakanon static char *xalloc_bottom; 442*559Snakanon 443*559Snakanon void * 444*559Snakanon xalloc(size_t size) 445*559Snakanon { 446*559Snakanon char *rptr, *bp; 447*559Snakanon 448*559Snakanon if ((rptr = malloc(size)) == NULL) 449*559Snakanon return (nomem(size)); 450*559Snakanon bp = rptr + size; 451*559Snakanon if (bp > xalloc_bottom) 452*559Snakanon xalloc_bottom = bp; 453*559Snakanon return (rptr); 454*559Snakanon } 455*559Snakanon 456*559Snakanon void * 457*559Snakanon xrealloc(void *ptr, size_t size) 458*559Snakanon { 459*559Snakanon char *rptr = ptr, *bp; 460*559Snakanon 461*559Snakanon if (ptr == NULL) 462*559Snakanon return (xalloc(size)); 463*559Snakanon if (rptr < end) { 464*559Snakanon /* data area, but not in heap area. don't touch it */ 465*559Snakanon oob: 466*559Snakanon if (size == 0) 467*559Snakanon return (NULL); 468*559Snakanon rptr = xalloc(size); 469*559Snakanon /* copy max size */ 470*559Snakanon (void) memcpy(rptr, ptr, size); 471*559Snakanon return (rptr); 472*559Snakanon } 473*559Snakanon if (rptr < xalloc_bottom) { 474*559Snakanon /* address in the heap */ 475*559Snakanon inb: 476*559Snakanon if (size == 0) { 477*559Snakanon free(ptr); 478*559Snakanon return (NULL); 479*559Snakanon } 480*559Snakanon if ((rptr = realloc(ptr, size)) == NULL) 481*559Snakanon return (nomem(size)); 482*559Snakanon bp = rptr + size; 483*559Snakanon if (bp > xalloc_bottom) 484*559Snakanon xalloc_bottom = bp; 485*559Snakanon return (rptr); 486*559Snakanon } 487*559Snakanon #if defined(__sparc) 488*559Snakanon if (rptr > (char *)&rptr) { 489*559Snakanon /* in the stack frame */ 490*559Snakanon goto oob; 491*559Snakanon } 492*559Snakanon #endif 493*559Snakanon /* 494*559Snakanon * can be a memory block returned indirectly from 495*559Snakanon * library functions. update bottom, and check it again. 496*559Snakanon */ 497*559Snakanon xalloc_bottom = sbrk(0); 498*559Snakanon if (rptr <= xalloc_bottom) 499*559Snakanon goto inb; 500*559Snakanon else 501*559Snakanon goto oob; 502*559Snakanon /*NOTREACHED*/ 503*559Snakanon } 504*559Snakanon 505*559Snakanon void 506*559Snakanon xfree(void *ptr) 507*559Snakanon { 508*559Snakanon char *rptr = ptr; 509*559Snakanon 510*559Snakanon if (rptr < end) { 511*559Snakanon return; 512*559Snakanon } 513*559Snakanon if (rptr < xalloc_bottom) { 514*559Snakanon free(ptr); 515*559Snakanon return; 516*559Snakanon } 517*559Snakanon #if defined(__sparc) 518*559Snakanon if (rptr > (char *)&rptr) { 519*559Snakanon /* in the stack frame */ 520*559Snakanon return; 521*559Snakanon } 522*559Snakanon #endif 523*559Snakanon xalloc_bottom = sbrk(0); 524*559Snakanon if (rptr <= xalloc_bottom) { 525*559Snakanon free(ptr); 526*559Snakanon } 527*559Snakanon } 528*559Snakanon 529*559Snakanon void * 530*559Snakanon xcalloc(size_t i, size_t j) 531*559Snakanon { 532*559Snakanon char *cp; 533*559Snakanon 534*559Snakanon i *= j; 535*559Snakanon cp = xalloc(i); 536*559Snakanon (void) memset(cp, '\0', i); 537*559Snakanon return (cp); 538*559Snakanon } 539