/* Read a buffer from shf. Returns the number of bytes read into buf, * if no bytes were read, returns 0 if end of file was seen, EOF if * a read error occurred. */ int shf_read(char *buf, int bsize, struct shf *shf) { int orig_bsize = bsize; int ncopy; if (!(shf->flags & SHF_RD)) internal_errorf(1, "shf_read: flags %x", shf->flags); if (bsize <= 0) internal_errorf(1, "shf_read: bsize %d", bsize); while (bsize > 0) { if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) break; ncopy = shf->rnleft; if (ncopy > bsize) ncopy = bsize; memcpy(buf, shf->rp, ncopy); buf += ncopy; bsize -= ncopy; shf->rp += ncopy; shf->rnleft -= ncopy; } /* Note: fread(3S) returns 0 for errors - this doesn't */ return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) : orig_bsize - bsize; }
/* Make j the last async process * * If jobs are compiled in then this routine expects sigchld to be blocked. */ static void j_set_async(Job *j) { Job *jl, *oldest; if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE) remove_job(async_job, "async"); if (!(j->flags & JF_STARTED)) { internal_errorf(0, "j_async: job not started"); return; } async_job = j; async_pid = j->last_proc->pid; while (nzombie > child_max) { oldest = (Job *) 0; for (jl = job_list; jl; jl = jl->next) if (jl != async_job && (jl->flags & JF_ZOMBIE) && (!oldest || jl->age < oldest->age)) oldest = jl; if (!oldest) { /* XXX debugging */ if (!(async_job->flags & JF_ZOMBIE) || nzombie != 1) { internal_errorf(0, "j_async: bad nzombie (%d)", nzombie); nzombie = 0; } break; } remove_job(oldest, "zombie"); } }
/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ int shf_write(const char *buf, int nbytes, struct shf *shf) { int orig_nbytes = nbytes; int n; int ncopy; if (!(shf->flags & SHF_WR)) internal_errorf(1, "shf_write: flags %x", shf->flags); if (nbytes < 0) internal_errorf(1, "shf_write: nbytes %d", nbytes); /* Don't buffer if buffer is empty and we're writting a large amount. */ if ((ncopy = shf->wnleft) && (shf->wp != shf->buf || nbytes < shf->wnleft)) { if (ncopy > nbytes) ncopy = nbytes; memcpy(shf->wp, buf, ncopy); nbytes -= ncopy; buf += ncopy; shf->wp += ncopy; shf->wnleft -= ncopy; } if (nbytes > 0) { /* Flush deals with strings and sticky errors */ if (shf_emptybuf(shf, EB_GROW) == EOF) return EOF; if (nbytes > shf->wbsize) { ncopy = nbytes; if (shf->wbsize) ncopy -= nbytes % shf->wbsize; nbytes -= ncopy; while (ncopy > 0) { n = write(shf->fd, buf, ncopy); if (n < 0) { if (errno == EINTR && !(shf->flags & SHF_INTERRUPT)) continue; shf->flags |= SHF_ERROR; shf->errno_ = errno; shf->wnleft = 0; /* Note: fwrite(3S) returns 0 for * errors - this doesn't */ return EOF; } buf += n; ncopy -= n; } } if (nbytes > 0) { memcpy(shf->wp, buf, nbytes); shf->wp += nbytes; shf->wnleft -= nbytes; } } return orig_nbytes; }
/* Put a character back in the input stream. Returns the character if * successful, EOF if there is no room. */ int shf_ungetc(int c, struct shf *shf) { if (!(shf->flags & SHF_RD)) internal_errorf(1, "shf_ungetc: flags %x", shf->flags); if ((shf->flags & SHF_ERROR) || c == EOF || (shf->rp == shf->buf && shf->rnleft)) return EOF; if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) return EOF; if (shf->rp == shf->buf) shf->rp = shf->buf + shf->rbsize; if (shf->flags & SHF_STRING) { /* Can unget what was read, but not something different - we * don't want to modify a string. */ if (shf->rp[-1] != c) return EOF; shf->flags &= ~SHF_EOF; shf->rp--; shf->rnleft++; return c; } shf->flags &= ~SHF_EOF; *--(shf->rp) = c; shf->rnleft++; return c; }
/* * Process here documents by providing the content, either as * result (globally allocated) string or in a temp file; if * unquoted, the string is expanded first. */ static int hereinval(const char *content, int sub, char **resbuf, struct shf *shf) { const char * volatile ccp = content; struct source *s, *osource; osource = source; newenv(E_ERRH); if (kshsetjmp(e->jbuf)) { source = osource; quitenv(shf); /* special to iosetup(): don't print error */ return (-2); } if (sub) { /* do substitutions on the content of heredoc */ s = pushs(SSTRING, ATEMP); s->start = s->str = ccp; source = s; if (yylex(sub) != LWORD) internal_errorf("%s: %s", "herein", "yylex"); source = osource; ccp = evalstr(yylval.cp, 0); } if (resbuf == NULL) shf_puts(ccp, shf); else strdupx(*resbuf, ccp, APERM); quitenv(NULL); return (0); }
/* Un-read what has been read but not examined, or write what has been * buffered. Returns 0 for success, EOF for (write) error. */ int shf_flush(struct shf *shf) { if (shf->flags & SHF_STRING) return (shf->flags & SHF_WR) ? EOF : 0; if (shf->fd < 0) internal_errorf(1, "shf_flush: no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } if (shf->flags & SHF_READING) { shf->flags &= ~(SHF_EOF | SHF_READING); if (shf->rnleft > 0) { lseek(shf->fd, (off_t) -shf->rnleft, SEEK_CUR); shf->rnleft = 0; shf->rp = shf->buf; } return 0; } else if (shf->flags & SHF_WRITING) return shf_emptybuf(shf, 0); return 0; }
/* Open a string for reading or writing. If reading, bsize is the number * of bytes that can be read. If writing, bsize is the maximum number of * bytes that can be written. If shf is not null, it is filled in and * returned, if it is null, shf is allocated. If writing and buf is null * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is * used for the initial size). Doesn't fail. * When writing, a byte is reserved for a trailing null - see shf_sclose(). */ struct shf * shf_sopen(char *buf, int bsize, int sflags, struct shf *shf) { /* can't have a read+write string */ if (!(sflags & (SHF_RD | SHF_WR)) || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR)) internal_errorf(1, "shf_sopen: flags 0x%x", sflags); if (!shf) { shf = alloc(sizeof(struct shf), ATEMP); sflags |= SHF_ALLOCS; } shf->areap = ATEMP; if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { if (bsize <= 0) bsize = 64; sflags |= SHF_ALLOCB; buf = alloc(bsize, shf->areap); } shf->fd = -1; shf->buf = shf->rp = shf->wp = (unsigned char *) buf; shf->rnleft = bsize; shf->rbsize = bsize; shf->wnleft = bsize - 1; /* space for a '\0' */ shf->wbsize = bsize; shf->flags = sflags | SHF_STRING; shf->errno_ = 0; shf->bsize = bsize; return shf; }
int waitlast(void) { int rv; Job *j; sigset_t omask; sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); j = last_job; if (!j || !(j->flags & JF_STARTED)) { if (!j) { // warningf(true, "waitlast: no last job"); } else internal_errorf(0, "waitlast: not started"); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); // work arround for no job control // place the result of the last command // subshell or whatever in lastresult // and return it here. return lastresult; //return 125; /* not so arbitrary, non-zero value */ } rv = j_waitj(j, JW_NONE, "jw:waitlast"); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); return rv; }
/* wait for last job: only used for `command` jobs */ int waitlast(void) { int rv; Job *j; sigset_t omask; sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); j = last_job; if (!j || !(j->flags & JF_STARTED)) { if (!j) warningf(true, "waitlast: no last job"); else internal_errorf(0, "waitlast: not started"); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); return 125; /* not so arbitrary, non-zero value */ } rv = j_waitj(j, JW_NONE, "jw:waitlast"); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); return rv; }
void afree(void *ptr, Area *ap) { struct link *l, *l2; if (!ptr) return; l = P2L(ptr); for (l2 = ap->freelist; l2 != NULL; l2 = l2->next) { if (l == l2) break; } if (l2 == NULL) internal_errorf(1, "afree: %p not present in area %p", ptr, ap); if (l->prev) l->prev->next = l->next; else ap->freelist = l->next; if (l->next) l->next->prev = l->prev; free(l); }
/* * Do file globbing: * - appends * to (copy of) str if no globbing chars found * - does expansion, checks for no match, etc. * - sets *wordsp to array of matching strings * - returns number of matching strings */ static int x_file_glob(int flags, const char *str, int slen, char ***wordsp) { char *toglob; char **words; int nwords; XPtrV w; struct source *s, *sold; if (slen < 0) return 0; toglob = add_glob(str, slen); /* * Convert "foo*" (toglob) to an array of strings (words) */ sold = source; s = pushs(SWSTR, ATEMP); s->start = s->str = toglob; source = s; if (yylex(ONEWORD|UNESCAPE) != LWORD) { source = sold; internal_errorf(0, "fileglob: substitute error"); return 0; } source = sold; XPinit(w, 32); expand(yylval.cp, &w, DOGLOB|DOTILDE|DOMARKDIRS); XPput(w, NULL); words = (char **) XPclose(w); for (nwords = 0; words[nwords]; nwords++) ; if (nwords == 1) { struct stat statb; /* Check if file exists, also, check for empty * result - happens if we tried to glob something * which evaluated to an empty string (e.g., * "$FOO" when there is no FOO, etc). */ if ((lstat(words[0], &statb) < 0) || words[0][0] == '\0') { x_free_words(nwords, words); words = NULL; nwords = 0; } } afree(toglob, ATEMP); if (nwords) { *wordsp = words; } else if (words) { x_free_words(nwords, words); *wordsp = NULL; } return nwords; }
void * aresize(void *ptr, size_t numb, Area *ap) { ALLOC_ITEM *lp = NULL; /* resizing (true) or newly allocating? */ if (ptr != NULL) { ALLOC_ITEM *pp; pp = findptr(&lp, ptr, ap); pp->next = lp->next; } if ((numb >= SIZE_MAX - ALLOC_SIZE) || (lp = remalloc(lp, numb + ALLOC_SIZE)) == NULL #ifndef MKSH_SMALL || ALLOC_ISUNALIGNED(lp) #endif ) internal_errorf("cannot allocate %lu data bytes", (unsigned long)numb); /* this only works because Area is an ALLOC_ITEM */ lp->next = ap->next; ap->next = lp; /* return user item address */ return ((char *)lp + ALLOC_SIZE); }
/* set variable to string value */ int setstr(struct tbl *vq, const char *s, int error_ok) { const char *fs = NULL; int no_ro_check = error_ok & 0x4; error_ok &= ~0x4; if ((vq->flag & RDONLY) && !no_ro_check) { warningf(true, "%s: is read only", vq->name); if (!error_ok) errorf(null); return 0; } if (!(vq->flag&INTEGER)) { /* string dest */ if ((vq->flag&ALLOC)) { /* debugging */ if (s >= vq->val.s && s <= vq->val.s + strlen(vq->val.s)) internal_errorf(true, "setstr: %s=%s: assigning to self", vq->name, s); afree((void*)vq->val.s, vq->areap); } vq->flag &= ~(ISSET|ALLOC); vq->type = 0; if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) fs = s = formatstr(vq, s); if ((vq->flag&EXPORT)) export(vq, s); else { vq->val.s = str_save(s, vq->areap); vq->flag |= ALLOC; } } else { /* integer dest */
static ALLOC_ITEM * findptr(ALLOC_ITEM **lpp, char *ptr, Area *ap) { void *lp; #ifndef MKSH_SMALL if (ALLOC_ISUNALIGNED(ptr)) goto fail; #endif /* get address of ALLOC_ITEM from user item */ /* * note: the alignment of "ptr" to ALLOC_SIZE is checked * above; the "void *" gets us rid of a gcc 2.95 warning */ *lpp = (lp = ptr - ALLOC_SIZE); /* search for allocation item in group list */ while (ap->next != lp) if ((ap = ap->next) == NULL) { #ifndef MKSH_SMALL fail: #endif internal_errorf("rogue pointer %p", ptr); } return (ap); }
/* Take job out of job_list and put old structures into free list. * Keeps nzombies, last_job and async_job up to date. * * If jobs are compiled in then this routine expects sigchld to be blocked. */ static void remove_job(Job *j, const char *where) { Proc *p, *tmp; Job **prev, *curr; prev = &job_list; curr = *prev; for (; curr != (Job *) 0 && curr != j; prev = &curr->next, curr = *prev) ; if (curr != j) { internal_errorf(0, "remove_job: job not found (%s)", where); return; } *prev = curr->next; /* free up proc structures */ for (p = j->proc_list; p != (Proc *) 0; ) { tmp = p; p = p->next; tmp->next = free_procs; free_procs = tmp; } if ((j->flags & JF_ZOMBIE) && j->ppid == procpid) --nzombie; j->next = free_jobs; free_jobs = j; if (j == last_job) last_job = (Job *) 0; if (j == async_job) async_job = (Job *) 0; }
/* Set up an existing shf (and buffer) to use the given fd */ struct shf * shf_reopen(int fd, int sflags, struct shf *shf) { int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; /* use fcntl() to figure out correct read/write flags */ if (sflags & SHF_GETFL) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) /* will get an error on first read/write */ sflags |= SHF_RDWR; else { switch (flags & O_ACCMODE) { case O_RDONLY: sflags |= SHF_RD; break; case O_WRONLY: sflags |= SHF_WR; break; case O_RDWR: sflags |= SHF_RDWR; break; } } } if (!(sflags & (SHF_RD | SHF_WR))) internal_errorf(1, "shf_reopen: missing read/write"); if (!shf || !shf->buf || shf->bsize < bsize) internal_errorf(1, "shf_reopen: bad shf/buf/bsize"); /* assumes shf->buf and shf->bsize already set up */ shf->fd = fd; shf->rp = shf->wp = shf->buf; shf->rnleft = 0; shf->rbsize = bsize; shf->wnleft = 0; /* force call to shf_emptybuf() */ shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; shf->errno_ = 0; if (sflags & SHF_CLEXEC) fcntl(fd, F_SETFD, FD_CLOEXEC); return shf; }
/* Set up the shf structure for a file descriptor. Doesn't fail. */ struct shf * shf_fdopen(int fd, int sflags, struct shf *shf) { int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; /* use fcntl() to figure out correct read/write flags */ if (sflags & SHF_GETFL) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) /* will get an error on first read/write */ sflags |= SHF_RDWR; else { switch (flags & O_ACCMODE) { case O_RDONLY: sflags |= SHF_RD; break; case O_WRONLY: sflags |= SHF_WR; break; case O_RDWR: sflags |= SHF_RDWR; break; } } } if (!(sflags & (SHF_RD | SHF_WR))) internal_errorf(1, "shf_fdopen: missing read/write"); if (shf) { if (bsize) { shf->buf = alloc(bsize, ATEMP); sflags |= SHF_ALLOCB; } else shf->buf = NULL; } else { shf = alloc(sizeof(struct shf) + bsize, ATEMP); shf->buf = (unsigned char *) &shf[1]; sflags |= SHF_ALLOCS; } shf->areap = ATEMP; shf->fd = fd; shf->rp = shf->wp = shf->buf; shf->rnleft = 0; shf->rbsize = bsize; shf->wnleft = 0; /* force call to shf_emptybuf() */ shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; shf->flags = sflags; shf->errno_ = 0; shf->bsize = bsize; if (sflags & SHF_CLEXEC) fcntl(fd, F_SETFD, FD_CLOEXEC); return shf; }
/* Returns the char read. Returns EOF for error and end of file. */ int shf_getchar(struct shf *shf) { if (!(shf->flags & SHF_RD)) internal_errorf(1, "shf_getchar: flags %x", shf->flags); if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) return EOF; --shf->rnleft; return *shf->rp++; }
/* printf to shl_stdout (stdout) */ void shprintf(const char *fmt, ...) { va_list va; if (!shl_stdout_ok) internal_errorf(1, "shl_stdout not valid"); va_start(va, fmt); shf_vfprintf(shl_stdout, fmt, va); va_end(va); }
/* Write a character. Returns the character if successful, EOF if * the char could not be written. */ int shf_putchar(int c, struct shf *shf) { if (!(shf->flags & SHF_WR)) internal_errorf(1, "shf_putchar: flags %x", shf->flags); if (c == EOF) return EOF; if (shf->flags & SHF_UNBUF) { char cc = c; int n; if (shf->fd < 0) internal_errorf(1, "shf_putchar: no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } while ((n = write(shf->fd, &cc, 1)) != 1) if (n < 0) { if (errno == EINTR && !(shf->flags & SHF_INTERRUPT)) continue; shf->flags |= SHF_ERROR; shf->errno_ = errno; return EOF; } } else { /* Flush deals with strings and sticky errors */ if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) return EOF; shf->wnleft--; *shf->wp++ = c; } return c; }
/* set variable to string value */ int setstr(struct tbl *vq, const char *s, int error_ok) { char *salloc = NULL; bool no_ro_check = tobool(error_ok & 0x4); error_ok &= ~0x4; if ((vq->flag & RDONLY) && !no_ro_check) { warningf(true, "read-only: %s", vq->name); if (!error_ok) errorfxz(2); return (0); } if (!(vq->flag&INTEGER)) { /* string dest */ if ((vq->flag&ALLOC)) { #ifndef MKSH_SMALL /* debugging */ if (s >= vq->val.s && s <= vq->val.s + strlen(vq->val.s)) { internal_errorf( "setstr: %s=%s: assigning to self", vq->name, s); } #endif afree(vq->val.s, vq->areap); } vq->flag &= ~(ISSET|ALLOC); vq->type = 0; if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) s = salloc = formatstr(vq, s); if ((vq->flag&EXPORT)) exportprep(vq, s); else { strdupx(vq->val.s, s, vq->areap); vq->flag |= ALLOC; } } else { /* integer dest */ if (!v_evaluate(vq, s, error_ok, true)) return (0); } vq->flag |= ISSET; if ((vq->flag&SPECIAL)) setspec(vq); afree(salloc, ATEMP); return (1); }
void * alloc(size_t size, Area *ap) { struct link *l; l = malloc(sizeof(struct link) + size); if (l == NULL) internal_errorf(1, "unable to allocate memory"); l->next = ap->freelist; l->prev = NULL; if (ap->freelist) ap->freelist->prev = l; ap->freelist = l; return L2P(l); }
int shf_snprintf(char *buf, int bsize, const char *fmt, ...) { struct shf shf; va_list args; int n; if (!buf || bsize <= 0) internal_errorf(1, "shf_snprintf: buf %lx, bsize %d", (long) buf, bsize); shf_sopen(buf, bsize, SHF_WR, &shf); va_start(args, fmt); n = shf_vfprintf(&shf, fmt, args); va_end(args); shf_sclose(&shf); /* null terminates */ return n; }
static void tgrow(struct table *tp) { size_t i, j, osize, mask, perturb; struct tbl *tblp, **pp; struct tbl **ntblp, **otblp = tp->tbls; if (tp->tshift > 29) internal_errorf("hash table size limit reached"); /* calculate old size, new shift and new size */ osize = (size_t)1 << (tp->tshift++); i = osize << 1; ntblp = alloc2(i, sizeof(struct tbl *), tp->areap); /* multiplication cannot overflow: alloc2 checked that */ memset(ntblp, 0, i * sizeof(struct tbl *)); /* table can get very full when reaching its size limit */ tp->nfree = (tp->tshift == 30) ? 0x3FFF0000UL : /* but otherwise, only 75% */ ((i * 3) / 4); tp->tbls = ntblp; if (otblp == NULL) return; mask = i - 1; for (i = 0; i < osize; i++) if ((tblp = otblp[i]) != NULL) { if ((tblp->flag & DEFINED)) { /* search for free hash table slot */ j = perturb = tblp->ua.hval; goto find_first_empty_slot; find_next_empty_slot: j = (j << 2) + j + perturb + 1; perturb >>= PERTURB_SHIFT; find_first_empty_slot: pp = &ntblp[j & mask]; if (*pp != NULL) goto find_next_empty_slot; /* found an empty hash table slot */ *pp = tblp; tp->nfree--; } else if (!(tblp->flag & FINUSE)) {
static int call_builtin(struct tbl *tp, const char **wp, const char *where) { int rv; if (!tp) internal_errorf("%s: %s", where, wp[0]); builtin_argv0 = wp[0]; builtin_flag = tp->flag; shf_reopen(1, SHF_WR, shl_stdout); shl_stdout_ok = true; ksh_getopt_reset(&builtin_opt, GF_ERROR); rv = (*tp->val.f)(wp); shf_flush(shl_stdout); shl_stdout_ok = false; builtin_flag = 0; builtin_argv0 = NULL; return (rv); }
/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ static int shf_fillbuf(struct shf *shf) { if (shf->flags & SHF_STRING) return 0; if (shf->fd < 0) internal_errorf(1, "shf_fillbuf: no fd"); if (shf->flags & (SHF_EOF | SHF_ERROR)) { if (shf->flags & SHF_ERROR) errno = shf->errno_; return EOF; } if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) return EOF; shf->flags |= SHF_READING; shf->rp = shf->buf; while (1) { shf->rnleft = blocking_read(shf->fd, (char *) shf->buf, shf->rbsize); if (shf->rnleft < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT)) continue; break; } if (shf->rnleft <= 0) { if (shf->rnleft < 0) { shf->flags |= SHF_ERROR; shf->errno_ = errno; shf->rnleft = 0; shf->rp = shf->buf; return EOF; } shf->flags |= SHF_EOF; } return 0; }
/* hash(n) */ struct tbl * ktenter(struct table *tp, const char *n, unsigned int h) { struct tbl **pp, *p; int len; if (tp->size == 0) texpand(tp, INIT_TBLS); Search: /* search for name in hashed table */ for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) { if (*p->name == *n && strcmp(p->name, n) == 0) return p; /* found */ if (pp == tp->tbls) /* wrap */ pp += tp->size; } if (tp->nfree <= 0) { /* too full */ if (tp->size <= INT_MAX/2) texpand(tp, 2*tp->size); else internal_errorf(1, "too many vars"); goto Search; } /* create new tbl entry */ len = strlen(n) + 1; p = alloc(offsetof(struct tbl, name[0]) + len, tp->areap); p->flag = 0; p->type = 0; p->areap = tp->areap; p->u2.field = 0; p->u.array = NULL; memcpy(p->name, n, len); /* enter in tp->tbls */ tp->nfree--; *pp = p; return p; }
static int call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec) { int rv; if (!tp) internal_errorf("%s: %s", where, wp[0]); builtin_argv0 = wp[0]; builtin_spec = tobool(!resetspec && /*XXX odd use of KEEPASN */ ((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN)))); shf_reopen(1, SHF_WR, shl_stdout); shl_stdout_ok = true; ksh_getopt_reset(&builtin_opt, GF_ERROR); rv = (*tp->val.f)(wp); shf_flush(shl_stdout); shl_stdout_ok = false; builtin_argv0 = NULL; builtin_spec = false; return (rv); }
/* Read up to a newline or EOF. The newline is put in buf; buf is always * null terminated. Returns NULL on read error or if nothing was read before * end of file, returns a pointer to the null byte in buf otherwise. */ char * shf_getse(char *buf, int bsize, struct shf *shf) { unsigned char *end; int ncopy; char *orig_buf = buf; if (!(shf->flags & SHF_RD)) internal_errorf(1, "shf_getse: flags %x", shf->flags); if (bsize <= 0) return NULL; --bsize; /* save room for null */ do { if (shf->rnleft == 0) { if (shf_fillbuf(shf) == EOF) return NULL; if (shf->rnleft == 0) { *buf = '\0'; return buf == orig_buf ? NULL : buf; } } end = (unsigned char *) memchr((char *) shf->rp, '\n', shf->rnleft); ncopy = end ? end - shf->rp + 1 : shf->rnleft; if (ncopy > bsize) ncopy = bsize; memcpy(buf, (char *) shf->rp, ncopy); shf->rp += ncopy; shf->rnleft -= ncopy; buf += ncopy; bsize -= ncopy; } while (!end && bsize); *buf = '\0'; return buf; }
/* control what signal is set to before an exec() */ void setexecsig(Trap *p, int restore) { /* XXX debugging */ if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) internal_errorf(1, "setexecsig: unset signal %d(%s)", p->signal, p->name); /* restore original value for exec'd kids */ p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); switch (restore & SS_RESTORE_MASK) { case SS_RESTORE_CURR: /* leave things as they currently are */ break; case SS_RESTORE_ORIG: p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL; break; case SS_RESTORE_DFL: p->flags |= TF_EXEC_DFL; break; case SS_RESTORE_IGN: p->flags |= TF_EXEC_IGN; break; } }