struct temp * maketemp(Area *ap, Temp_type type, struct temp **tlist) { struct temp *tp; int len; int fd; char *path; const char *dir; dir = tmpdir ? tmpdir : "/tmp"; /* The 20 + 20 is a paranoid worst case for pid/inc */ len = strlen(dir) + 3 + 20 + 20 + 1; tp = alloc(sizeof(struct temp) + len, ap); tp->name = path = (char *) &tp[1]; tp->shf = NULL; tp->type = type; shf_snprintf(path, len, "%s/shXXXXXXXX", dir); fd = mkstemp(path); if (fd >= 0) tp->shf = shf_fdopen(fd, SHF_WR, NULL); tp->pid = procpid; tp->next = *tlist; *tlist = tp; return tp; }
/* format a single select menu item */ static void options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) { const struct options_info *oi = (const struct options_info *)arg; shf_snprintf(buf, buflen, "%-*s %s", oi->opt_width, OFN(oi->opts[i]), Flag(oi->opts[i]) ? "on" : "off"); }
/* format a single select menu item */ static void select_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) { const struct select_menu_info *smi = (const struct select_menu_info *)arg; shf_snprintf(buf, buflen, "%*u) %s", smi->num_width, i + 1, smi->args[i]); }
/* format a single select menu item */ static char * options_fmt_entry(void *arg, int i, char *buf, int buflen) { struct options_info *oi = (struct options_info *) arg; shf_snprintf(buf, buflen, "%-*s %s", oi->opt_width, oi->opts[i].name, Flag(oi->opts[i].flag) ? "on" : "off"); return buf; }
/* format a single select menu item */ static char * options_fmt_entry(char *buf, int buflen, int i, const void *arg) { const struct options_info *oi = (const struct options_info *)arg; shf_snprintf(buf, buflen, "%-*s %s", oi->opt_width, options[oi->opts[i]].name, Flag(oi->opts[i]) ? "on" : "off"); return (buf); }
/* * Print job status in either short, medium or long format. * * If jobs are compiled in then this routine expects sigchld to be blocked. */ static void j_print(Job *j, int how, struct shf *shf) { Proc *p; int state; int status; int coredumped; char jobchar = ' '; char buf[64]; const char *filler; int output = 0; if (how == JP_PGRP) { /* POSIX doesn't say what to do it there is no process * group leader (ie, !FMONITOR). We arbitrarily return * last pid (which is what $! returns). */ shf_fprintf(shf, "%d\n", j->pgrp ? j->pgrp : (j->last_proc ? j->last_proc->pid : 0)); return; } j->flags &= ~JF_CHANGED; filler = j->job > 10 ? "\n " : "\n "; if (j == job_list) jobchar = '+'; else if (j == job_list->next) jobchar = '-'; for (p = j->proc_list; p != (Proc *) 0;) { coredumped = 0; switch (p->state) { case PRUNNING: strlcpy(buf, "Running", sizeof buf); break; case PSTOPPED: strlcpy(buf, sigtraps[WSTOPSIG(p->status)].mess, sizeof buf); break; case PEXITED: if (how == JP_SHORT) buf[0] = '\0'; else if (WEXITSTATUS(p->status) == 0) strlcpy(buf, "Done", sizeof buf); else shf_snprintf(buf, sizeof(buf), "Done (%d)", WEXITSTATUS(p->status)); break; case PSIGNALLED: if (WCOREDUMP(p->status)) coredumped = 1; /* kludge for not reporting `normal termination signals' * (ie, SIGINT, SIGPIPE) */ if (how == JP_SHORT && !coredumped && (WTERMSIG(p->status) == SIGINT || WTERMSIG(p->status) == SIGPIPE)) { buf[0] = '\0'; } else strlcpy(buf, sigtraps[WTERMSIG(p->status)].mess, sizeof buf); break; } if (how != JP_SHORT) { if (p == j->proc_list) shf_fprintf(shf, "[%d] %c ", j->job, jobchar); else shf_fprintf(shf, "%s", filler); } if (how == JP_LONG) shf_fprintf(shf, "%5d ", p->pid); if (how == JP_SHORT) { if (buf[0]) { output = 1; shf_fprintf(shf, "%s%s ", buf, coredumped ? " (core dumped)" : null); } } else { output = 1; shf_fprintf(shf, "%-20s %s%s%s", buf, p->command, p->next ? "|" : null, coredumped ? " (core dumped)" : null); } state = p->state; status = p->status; p = p->next; while (p && p->state == state && p->status == status) { if (how == JP_LONG) shf_fprintf(shf, "%s%5d %-20s %s%s", filler, p->pid, space, p->command, p->next ? "|" : null); else if (how == JP_MEDIUM) shf_fprintf(shf, " %s%s", p->command, p->next ? "|" : null); p = p->next; } } if (output) shf_fprintf(shf, newline); }
static char * formatstr(struct tbl *vp, const char *s) { int olen, nlen; char *p, *q; size_t psiz; olen = (int)utf_mbswidth(s); if (vp->flag & (RJUST|LJUST)) { if (!vp->u2.field) /* default field width */ vp->u2.field = olen; nlen = vp->u2.field; } else nlen = olen; p = alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP); if (vp->flag & (RJUST|LJUST)) { int slen = olen, i = 0; if (vp->flag & RJUST) { const char *qq = s; int n = 0; while (i < slen) i += utf_widthadj(qq, &qq); /* strip trailing spaces (AT&T uses qq[-1] == ' ') */ while (qq > s && ksh_isspace(qq[-1])) { --qq; --slen; } if (vp->flag & ZEROFIL && vp->flag & INTEGER) { if (!s[0] || !s[1]) goto uhm_no; if (s[1] == '#') n = 2; else if (s[2] == '#') n = 3; uhm_no: if (vp->u2.field <= n) n = 0; } if (n) { memcpy(p, s, n); s += n; } while (slen > vp->u2.field) slen -= utf_widthadj(s, &s); if (vp->u2.field - slen) memset(p + n, (vp->flag & ZEROFIL) ? '0' : ' ', vp->u2.field - slen); slen -= n; shf_snprintf(p + vp->u2.field - slen, psiz - (vp->u2.field - slen), "%.*s", slen, s); } else { /* strip leading spaces/zeros */ while (ksh_isspace(*s)) s++; if (vp->flag & ZEROFIL) while (*s == '0') s++; shf_snprintf(p, nlen + 1, "%-*.*s", vp->u2.field, vp->u2.field, s); } } else memcpy(p, s, strlen(s) + 1); if (vp->flag & UCASEV_AL) { for (q = p; *q; q++) *q = ksh_toupper(*q); } else if (vp->flag & LCASEV) { for (q = p; *q; q++) *q = ksh_tolower(*q); } return (p); }
static void getspec(struct tbl *vp) { mksh_ari_u num; int st; struct timeval tv; switch ((st = special(vp->name))) { case V_COLUMNS: case V_LINES: /* * Do NOT export COLUMNS/LINES. Many applications * check COLUMNS/LINES before checking ws.ws_col/row, * so if the app is started with C/L in the environ * and the window is then resized, the app won't * see the change cause the environ doesn't change. */ if (got_winch) change_winsz(); break; } switch (st) { case V_BASHPID: num.u = (mksh_uari_t)procpid; break; case V_COLUMNS: num.i = x_cols; break; case V_HISTSIZE: num.i = histsize; break; case V_LINENO: num.u = (mksh_uari_t)current_lineno + user_lineno; break; case V_LINES: num.i = x_lins; break; case V_EPOCHREALTIME: { /* 10(%u) + 1(.) + 6 + NUL */ char buf[18]; vp->flag &= ~SPECIAL; mksh_TIME(tv); shf_snprintf(buf, sizeof(buf), "%u.%06u", (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); setstr(vp, buf, KSH_RETURN_ERROR | 0x4); vp->flag |= SPECIAL; return; } case V_OPTIND: num.i = user_opt.uoptind; break; case V_RANDOM: num.i = rndget(); break; case V_SECONDS: /* * On start up the value of SECONDS is used before * it has been set - don't do anything in this case * (see initcoms[] in main.c). */ if (vp->flag & ISSET) { mksh_TIME(tv); num.i = tv.tv_sec - seconds; } else return; break; default: /* do nothing, do not touch vp at all */ return; } vp->flag &= ~SPECIAL; setint_n(vp, num.i, 0); vp->flag |= SPECIAL; }
static int dopprompt(const char *sp, int ntruncate, const char **spp, int doprint) { char strbuf[1024], tmpbuf[1024], *p, *str, nbuf[32], delimiter = '\0'; int len, c, n, totlen = 0, indelimit = 0, counting = 1, delimitthis; const char *cp = sp; struct tm *tm; time_t t; if (*cp && cp[1] == '\r') { delimiter = *cp; cp += 2; } while (*cp != 0) { delimitthis = 0; if (indelimit && *cp != delimiter) ; else if (*cp == '\n' || *cp == '\r') { totlen = 0; sp = cp + 1; } else if (*cp == '\t') { if (counting) totlen = (totlen | 7) + 1; } else if (*cp == delimiter) { indelimit = !indelimit; delimitthis = 1; } if (*cp == '\\') { cp++; if (!*cp) break; if (Flag(FSH)) snprintf(strbuf, sizeof strbuf, "\\%c", *cp); else switch (*cp) { case 'a': /* '\' 'a' bell */ strbuf[0] = '\007'; strbuf[1] = '\0'; break; case 'd': /* '\' 'd' Dow Mon DD */ time(&t); tm = localtime(&t); strftime(strbuf, sizeof strbuf, "%a %b %d", tm); break; case 'D': /* '\' 'D' '{' strftime format '}' */ p = strchr(cp + 2, '}'); if (cp[1] != '{' || p == NULL) { snprintf(strbuf, sizeof strbuf, "\\%c", *cp); break; } strlcpy(tmpbuf, cp + 2, sizeof tmpbuf); p = strchr(tmpbuf, '}'); if (p) *p = '\0'; time(&t); tm = localtime(&t); strftime(strbuf, sizeof strbuf, tmpbuf, tm); cp = strchr(cp + 2, '}'); break; case 'e': /* '\' 'e' escape */ strbuf[0] = '\033'; strbuf[1] = '\0'; break; case 'h': /* '\' 'h' shortened hostname */ gethostname(strbuf, sizeof strbuf); p = strchr(strbuf, '.'); if (p) *p = '\0'; break; case 'H': /* '\' 'H' full hostname */ gethostname(strbuf, sizeof strbuf); break; case 'j': /* '\' 'j' number of jobs */ snprintf(strbuf, sizeof strbuf, "%d", j_njobs()); break; case 'l': /* '\' 'l' basename of tty */ p = ttyname(0); if (p) p = basename(p); if (p) strlcpy(strbuf, p, sizeof strbuf); break; case 'n': /* '\' 'n' newline */ strbuf[0] = '\n'; strbuf[1] = '\0'; totlen = 0; /* reset for prompt re-print */ sp = cp + 1; break; case 'r': /* '\' 'r' return */ strbuf[0] = '\r'; strbuf[1] = '\0'; totlen = 0; /* reset for prompt re-print */ sp = cp + 1; break; case 's': /* '\' 's' basename $0 */ strlcpy(strbuf, kshname, sizeof strbuf); break; case 't': /* '\' 't' 24 hour HH:MM:SS */ time(&t); tm = localtime(&t); strftime(strbuf, sizeof strbuf, "%T", tm); break; case 'T': /* '\' 'T' 12 hour HH:MM:SS */ time(&t); tm = localtime(&t); strftime(strbuf, sizeof strbuf, "%l:%M:%S", tm); break; case '@': /* '\' '@' 12 hour am/pm format */ time(&t); tm = localtime(&t); strftime(strbuf, sizeof strbuf, "%r", tm); break; case 'A': /* '\' 'A' 24 hour HH:MM */ time(&t); tm = localtime(&t); strftime(strbuf, sizeof strbuf, "%R", tm); break; case 'u': /* '\' 'u' username */ p = getlogin(); if (p) strlcpy(strbuf, p, sizeof strbuf); else strbuf[0] = '\0'; break; case 'v': /* '\' 'v' version (short) */ p = strchr(ksh_version, ' '); if (p) p = strchr(p + 1, ' '); if (p) { p++; strlcpy(strbuf, p, sizeof strbuf); p = strchr(strbuf, ' '); if (p) *p = '\0'; } break; case 'V': /* '\' 'V' version (long) */ strlcpy(strbuf, ksh_version, sizeof strbuf); break; case 'w': /* '\' 'w' cwd */ p = str_val(global("PWD")); n = strlen(str_val(global("HOME"))); if (strcmp(p, "/") == 0) { strlcpy(strbuf, p, sizeof strbuf); } else if (strcmp(p, str_val(global("HOME"))) == 0) { strbuf[0] = '~'; strbuf[1] = '\0'; } else if (strncmp(p, str_val(global("HOME")), n) == 0 && p[n] == '/') { snprintf(strbuf, sizeof strbuf, "~/%s", str_val(global("PWD")) + n + 1); } else strlcpy(strbuf, p, sizeof strbuf); break; case 'W': /* '\' 'W' basename(cwd) */ p = str_val(global("PWD")); strlcpy(strbuf, basename(p), sizeof strbuf); break; case '!': /* '\' '!' history line number XXX busted */ snprintf(strbuf, sizeof strbuf, "%d", source->line + 1); break; case '#': /* '\' '#' command line number XXX busted */ snprintf(strbuf, sizeof strbuf, "%d", source->line + 1); break; case '$': /* '\' '$' $ or # XXX busted */ strbuf[0] = ksheuid ? '$' : '#'; strbuf[1] = '\0'; break; case '0': /* '\' '#' '#' ' #' octal numeric handling */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': if ((cp[1] > '7' || cp[1] < '0') || (cp[2] > '7' || cp[2] < '0')) { snprintf(strbuf, sizeof strbuf, "\\%c", *cp); break; } n = cp[0] * 8 * 8 + cp[1] * 8 + cp[2]; snprintf(strbuf, sizeof strbuf, "%c", n); cp += 2; break; case '\\': /* '\' '\' */ strbuf[0] = '\\'; strbuf[1] = '\0'; break; case '[': /* '\' '[' .... stop counting */ strbuf[0] = '\0'; counting = 0; break; case ']': /* '\' ']' restart counting */ strbuf[0] = '\0'; counting = 1; break; default: snprintf(strbuf, sizeof strbuf, "\\%c", *cp); break; } cp++; str = strbuf; len = strlen(str); if (ntruncate) { if (ntruncate >= len) { ntruncate -= len; continue; } str += ntruncate; len -= ntruncate; ntruncate = 0; } if (doprint) shf_write(str, len, shl_out); if (counting && !indelimit && !delimitthis) totlen += len; continue; } else if (*cp != '!') c = *cp++; else if (*++cp == '!') c = *cp++; else { char *p; shf_snprintf(p = nbuf, sizeof(nbuf), "%d", source->line + 1); len = strlen(nbuf); if (ntruncate) { if (ntruncate >= len) { ntruncate -= len; continue; } p += ntruncate; len -= ntruncate; ntruncate = 0; } if (doprint) shf_write(p, len, shl_out); if (counting && !indelimit && !delimitthis) totlen += len; continue; } if (ntruncate) --ntruncate; else if (doprint) { shf_putc(c, shl_out); } if (counting && !indelimit && !delimitthis) totlen++; } if (doprint) shf_flush(shl_out); if (spp) *spp = sp; return (totlen); }
/* search for variable; if not found, return NULL or create globally */ struct tbl * isglobal(const char *n, bool docreate) { struct tbl *vp; union mksh_cchack vname; struct block *l = e->loc; int c; bool array; uint32_t h, val; /* * check to see if this is an array; * dereference namerefs; must come first */ vn = array_index_calc(n, &array, &val); h = hash(vn); c = (unsigned char)vn[0]; if (!ctype(c, C_ALPHX)) { if (array) errorf(Tbadsubst); vp = vtemp; vp->flag = DEFINED; vp->type = 0; vp->areap = ATEMP; if (ctype(c, C_DIGIT)) { if (getn(vn, &c)) { /* main.c:main_init() says 12 */ shf_snprintf(vp->name, 12, Tf_d, c); if (c <= l->argc) { /* setstr can't fail here */ setstr(vp, l->argv[c], KSH_RETURN_ERROR); } } else vp->name[0] = '\0'; vp->flag |= RDONLY; goto out; } vp->name[0] = c; vp->name[1] = '\0'; vp->flag |= RDONLY; if (vn[1] != '\0') goto out; vp->flag |= ISSET|INTEGER; switch (c) { case '$': vp->val.i = kshpid; break; case '!': /* if no job, expand to nothing */ if ((vp->val.i = j_async()) == 0) vp->flag &= ~(ISSET|INTEGER); break; case '?': vp->val.i = exstat & 0xFF; break; case '#': vp->val.i = l->argc; break; case '-': vp->flag &= ~INTEGER; vp->val.s = getoptions(); break; default: vp->flag &= ~(ISSET|INTEGER); } goto out; } l = varsearch(e->loc, &vp, vn, h); if (vp == NULL && docreate) vp = ktenter(&l->vars, vn, h); else docreate = false; if (vp != NULL) { if (array) vp = arraysearch(vp, val); if (docreate) { vp->flag |= DEFINED; if (special(vn)) vp->flag |= SPECIAL; } } out: last_lookup_was_array = array; if (vn != n) afree(vname.rw, ATEMP); return (vp); }