diff options
Diffstat (limited to '')
-rw-r--r-- | src/Xsystem.c | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/src/Xsystem.c b/src/Xsystem.c new file mode 100644 index 0000000..cc6cdd8 --- /dev/null +++ b/src/Xsystem.c @@ -0,0 +1,589 @@ +/* $LynxId: Xsystem.c,v 1.29 2018/02/17 14:58:15 tom Exp $ + * like system("cmd") but return with exit code of "cmd" + * for Turbo-C/MS-C/LSI-C + * This code is in the public domain. + * + * @Log: xsystem.c,v @ + * + * Revision 1.14 1997/10/17 (Fri) 16:28:24 senshu + * *** for Win32 version *** + * + * Revision 1.13 1992/02/24 06:59:13 serow + * *** empty log message *** + * + * Revision 1.12 1991/04/09 08:48:20 serow + * ignore new line at command line tail + * + * Revision 1.11 1991/03/12 07:12:50 serow + * CMDLINE + * + * Revision 1.10 91/02/24 05:10:14 serow + * 2>&1 + * + * Revision 1.9 91/02/22 07:01:17 serow + * NEAR for ms-c + * + */ +#include <LYUtils.h> +#include <LYStrings.h> +#include <LYGlobalDefs.h> + +#ifdef DOSPATH +#include <io.h> +#else +extern char *mktemp(char *); +#endif + +#ifndef USECMDLINE +#define USECMDLINE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define TABLESIZE(v) (sizeof(v)/sizeof(v[0])) + +#define STR_MAX 512 /* MAX command line */ + +#define isk1(c) ((0x81 <= UCH(c) && UCH(c) <= 0x9F) || (0xE0 <= UCH(c) && UCH(c) <= 0xFC)) +#define isq(c) ((c) == '"') +#define isspc(c) ((c) == ' ' || (c) == '\t') +#define issep(c) (isspc(c) || (c) == '"' || (c) == '\'' || (c) == '<' || (c) == '>' || (c) == 0) +#define issep2(c) (issep(c) || (c) == '.' || (c) == '\\' || (c) == '/') +#define isdeg(c) ('0' <= (c) && (c) <= '9') + +#ifndef NEAR +#define NEAR +#endif + +#define SAVE_FD 10 + +typedef struct _proc { + struct _proc *next; + char *line; + char *cmd; + char *arg; + char *inf; + int infmod; + char *outf; + int outfmod; + int ored[SAVE_FD]; + int sred[SAVE_FD]; +} PRO; + +static PRO *p1 = 0; + +static char *NEAR xmalloc(size_t n) +{ + char *bp; + + if ((bp = typecallocn(char, n)) == 0) { + write(2, "xsystem: Out of memory.!\n", 25); + exit_immediately(EXIT_FAILURE); + } + return bp; +} + +static char *NEAR xrealloc(void *p, size_t n) +{ + char *bp; + + if ((bp = realloc(p, n)) == (char *) 0) { + write(2, "xsystem: Out of memory!.\n", 25); + exit_immediately(EXIT_FAILURE); + } + return bp; +} + +static int NEAR is_builtin_command(char *s) +{ + static char *cmdtab[] = + { + "dir", "type", "rem", "ren", "rename", "erase", "del", + "copy", "pause", "date", "time", "ver", "vol", "label", + "cd", "chdir", "md", "mkdir", "rd", "rmdir", "break", + "verify", "set", "prompt", "path", "exit", "ctty", "echo", + "if", "for", "cls", "goto", "shift" + ,"start" /* start is NT only */ + }; + int i, l, lc, count; + + l = (int) strlen(s); + count = TABLESIZE(cmdtab); + count--; +#ifdef WIN_EX + if (system_is_NT) + count++; +#endif + for (i = 0; i < count; i++) { + if (strcasecomp(s, cmdtab[i]) == 0) + return 1; + lc = (int) strlen(cmdtab[i]); + if (lc < l && strncasecomp(s, cmdtab[i], lc) == 0 && issep2(s[lc])) + return 1; + } + return 0; +} + +static int NEAR getswchar(void) +{ + int result; + +#ifdef __WIN32__ + result = '/'; +#else + union REGS reg; + + reg.x.ax = 0x3700; + intdos(®, ®); + result = reg.h.dl; +#endif + return result; +} + +#define spawnl_rc(flag, rc) \ + ((flag == P_WAIT) \ + ? (int)(rc) \ + : ((rc) == 0 ? -2 : 0)) + +static int NEAR csystem(PRO * p, int flag) +{ + char *cmp; + char SW[3]; + intptr_t rc; + + if ((cmp = LYGetEnv("COMSPEC")) == 0) + return -2; + SW[0] = (char) getswchar(); + SW[1] = 'c'; + SW[2] = 0; + rc = spawnl(flag, cmp, cmp, SW, p->cmd, p->arg, (char *) 0); + return spawnl_rc(flag, rc); +} + +static PRO *NEAR pars1c(char *s) +{ + PRO *pp; + char *fnp; + int ms, mi; + int fs, fi, inpf; + int q; + + pp = (PRO *) xmalloc(sizeof(PRO)); + for (q = 0; q < (int) TABLESIZE(pp->ored); q++) + pp->ored[q] = q; + while (isspc(*s)) + s++; + pp->line = strdup(s); + pp->cmd = xmalloc(ms = 8); + mi = 0; + while (!issep(*s)) { + if (mi >= ms - 1) + pp->cmd = xrealloc(pp->cmd, ms += 8); + pp->cmd[mi++] = *s++; + } + pp->cmd[mi] = 0; + q = 0; + pp->arg = xmalloc(ms = 32); + if (isspc(*s)) + s++; + mi = 0; + while (*s) { + if (mi >= ms - 1) { + pp->arg = xrealloc(pp->arg, ms += 32); + } + if (q == 0) { + inpf = 0; + if ((mi == 0 || isspc(s[-1])) && + isdeg(s[0]) && s[1] == '>' && + s[2] == '&' && isdeg(s[3])) { + + pp->ored[s[0] & 15] = s[3] & 15; + s += 4; + continue; + } else if (s[0] == '<') { + if (pp->inf == 0) { + pp->infmod = O_RDONLY; + } + inpf = 1; + } else if (s[0] == '>' && s[1] == '>') { + if (pp->outf == 0) { + pp->outfmod = O_WRONLY | O_CREAT | O_APPEND; + } + s++; + } else if (s[0] == '>') { + if (pp->outf == 0) { + pp->outfmod = O_WRONLY | O_CREAT | O_TRUNC; + } + } else { + if (*s == '"') + q = !q; + pp->arg[mi++] = *s++; + continue; + } + fnp = xmalloc(fs = 16); + fi = 0; + s++; + while (isspc(*s)) + s++; + while (!issep(*s)) { + if (fi >= fs - 1) + fnp = xrealloc(fnp, fs += 16); + fnp[fi++] = *s++; + } + fnp[fi] = 0; + if (inpf) { + if (pp->inf == 0) + pp->inf = fnp; + } else { + if (pp->outf == 0) + pp->outf = fnp; + } + } else if (s[0] == '"') { + q = !q; + pp->arg[mi++] = *s++; + } else { + pp->arg[mi++] = *s++; + } + } + pp->arg[mi] = 0; + return pp; +} + +static PRO *NEAR pars(char *s) +{ + char *lb; + int li, ls, q; + int c; + PRO *pp = 0; + + lb = xmalloc(ls = STR_MAX); /* about */ + li = q = 0; + p1 = 0; + + for (;;) { + c = *s++; + if (li >= ls - 2) + lb = xrealloc(lb, ls += STR_MAX); + if (isk1(c) && *s) { + lb[li++] = (char) c; + lb[li++] = *s++; + } else if ((!q && c == '|') || c == 0 || (c == '\n' && *s == 0)) { + lb[li++] = 0; + if (p1 == 0) { + pp = p1 = pars1c(lb); + } else { + pp->next = pars1c(lb); + pp = pp->next; + } + li = 0; + if (c == 0 || (c == '\n' && *s == 0)) + break; + } else if (c == '"') { + q = !q; + lb[li++] = (char) c; + } else { + lb[li++] = (char) c; + } + } + free(lb); + return p1; +} + +static int NEAR try3(char *cnm, PRO * p, int flag) +{ + char cmdb[STR_MAX]; + int rc; + intptr_t rc2; + + sprintf(cmdb, "%.*s.com", (int) sizeof(cmdb) - 5, cnm); + if ((rc = open(cmdb, O_RDONLY)) >= 0) { + close(rc); + rc2 = spawnl(flag, cmdb, cmdb, p->arg, (char *) 0); + return spawnl_rc(flag, rc2); + } + sprintf(cmdb, "%.*s.exe", (int) sizeof(cmdb) - 5, cnm); + if ((rc = open(cmdb, O_RDONLY)) >= 0) { + close(rc); + rc2 = spawnl(flag, cmdb, cmdb, p->arg, (char *) 0); + return spawnl_rc(flag, rc2); + } + sprintf(cmdb, "%.*s.bat", (int) sizeof(cmdb) - 5, cnm); + if ((rc = open(cmdb, O_RDONLY)) >= 0) { + close(rc); + return csystem(p, flag); + } + return -1; +} + +static int NEAR prog_go(PRO * p, int flag) +{ + char *s; + char *extp = 0; + char cmdb[STR_MAX]; + char *ep; + int rc, lc = 0, cmd_len; + intptr_t rc2; + + cmd_len = (int) strlen(p->cmd); + + s = p->cmd + cmd_len - 1; + while (cmd_len && (*s != '\\') && (*s != '/') && (*s != ':')) { + if (*s == '.') + extp = s; + cmd_len--; + s--; + } + + if (is_builtin_command(p->cmd) || (extp && strcasecomp(extp, ".bat") == 0)) + return csystem(p, flag); + + if (s < p->cmd) { /* cmd has no PATH nor Drive */ + ep = LYGetEnv("PATH"); + LYStrNCpy(cmdb, p->cmd, sizeof(cmdb) - 1); + for (;;) { + if (extp) { /* has extension */ + if ((rc = open(cmdb, O_RDONLY)) >= 0) { + close(rc); + rc2 = spawnl(flag, cmdb, cmdb, p->arg, (char *) 0); + rc = spawnl_rc(flag, rc2); + } + } else { + rc = try3(cmdb, p, flag); + } + if (rc >= 0) + return rc; + + if (ep && *ep) { + int i; + + for (i = 0; *ep != ';' && *ep != '\0'; ep++, i++) + lc = cmdb[i] = *ep; + if (*ep == ';') + ep++; + if (i > 0 && lc != ':' && lc != '\\' && lc != '/') + cmdb[i++] = '\\'; + cmdb[i] = 0; + LYStrNCpy(cmdb + i, p->cmd, sizeof(cmdb) - 1 - i); + } else { + if (rc == -2) + return rc; + return -1; + } + } + } else { /* has PATH or Drive */ + if (extp) { /* has extension */ + if ((rc = open(p->cmd, O_RDONLY)) >= 0) { + close(rc); + rc2 = spawnl(flag, p->cmd, p->cmd, p->arg, (char *) 0); + return spawnl_rc(flag, rc2); + } + return -1; + } else { + return try3(p->cmd, p, flag); + } + } +} + +static char *NEAR tmpf(char *tp) +{ + char tplate[STR_MAX]; + char *ev; + int i; + + if ((ev = LYGetEnv("TMP")) != 0) { + LYStrNCpy(tplate, ev, sizeof(tplate) - 2 - strlen(tp)); + i = (int) strlen(ev); + if (i && ev[i - 1] != '\\' && ev[i - 1] != '/') + strcat(tplate, "\\"); + } else { + tplate[0] = 0; + } + strcat(tplate, tp); + return strdup(mktemp(tplate)); +} + +static int NEAR redopen(char *fn, int md, int sfd) +{ + int rc; + int fd; + + if ((fd = open(fn, md, 0666)) != -1) { + if (md & O_APPEND) + lseek(fd, 0L, SEEK_END); + rc = dup(sfd); + if (fd != sfd) { + dup2(fd, sfd); + close(fd); + } + return rc; + } + return -1; +} + +static int NEAR redclose(int fd, int sfd) +{ + if (fd != -1) { + dup2(fd, sfd); + close(fd); + } + return -1; +} + +static void NEAR redswitch(PRO * p) +{ + int d; + + for (d = 0; d < (int) TABLESIZE(p->ored); d++) { + if (d != p->ored[d]) { + p->sred[d] = dup(d); + dup2(p->ored[d], d); + } + } +} + +static void NEAR redunswitch(PRO * p) +{ + int d; + + for (d = 0; d < (int) TABLESIZE(p->ored); d++) { + if (d != p->ored[d]) { + dup2(p->sred[d], d); + close(p->sred[d]); + } + } +} + +int xsystem(char *cmd) +{ + PRO *p, *pn; + char *pof, *pif, *pxf; + int psstdin, psstdout; + int rdstdin, rdstdout; + int rc = 0; + +#if USECMDLINE + static char *cmdline = 0; +#endif + +#ifdef SH_EX /* 1997/11/01 (Sat) 10:04:03 add by JH7AYN */ + pif = cmd; + while (*pif++) { + if (*pif == '\r') { + *pif = '\0'; + break; + } else if (*pif == '\n') { + *pif = '\0'; + break; + } + } +#endif + + pof = pif = pxf = 0; + p = pars(cmd); + pof = tmpf("p1XXXXXX"); + pif = tmpf("p2XXXXXX"); + psstdin = psstdout = rdstdin = rdstdout = -1; + while (p) { +#if USECMDLINE + if (!LYGetEnv("NOCMDLINE")) { + cmdline = xmalloc(strlen(p->cmd) + strlen(p->arg) + 10); + sprintf(cmdline, "CMDLINE=%s %s", p->cmd, p->arg); + putenv(cmdline); + } +#endif + if (p->next) + psstdout = redopen(pof, O_WRONLY | O_CREAT | O_TRUNC, 1); + if (p->inf) + rdstdin = redopen(p->inf, p->infmod, 0); + if (p->outf) + rdstdout = redopen(p->outf, p->outfmod, 1); + redswitch(p); + rc = prog_go(p, P_WAIT); + redunswitch(p); + rdstdin = redclose(rdstdin, 0); + rdstdout = redclose(rdstdout, 1); + psstdout = redclose(psstdout, 1); + psstdin = redclose(psstdin, 0); + if ((p = p->next) != 0) { + pxf = pif; + pif = pof; + pof = pxf; + psstdin = redopen(pif, O_RDONLY, 0); + } + } + unlink(pif); + free(pif); + unlink(pof); + free(pof); + for (pn = p = p1; p; p = pn) { + pn = p->next; + if (p->line) + free(p->line); + if (p->cmd) + free(p->cmd); + if (p->arg) + free(p->arg); + if (p->inf) + free(p->inf); + if (p->outf) + free(p->outf); + free(p); + } + if (rc == -2) + return 127; + return rc < 0 ? 0xFF00 : rc; +} + +int exec_command(char *cmd, int wait_flag) +{ + int rc; + + PRO *p; + char *pif; + int cmd_str; + + pif = cmd; + while (*pif == ' ') + pif++; + + cmd = pif; + cmd_str = TRUE; + + while (*pif++) { + if (*pif == '\r') { + *pif = '\0'; + break; + } else if (*pif == '\n') { + *pif = '\0'; + break; + } else if (cmd_str) { + if (*pif == '/') + *pif = '\\'; + } else if (cmd_str) { + if (*pif == ' ') + cmd_str = FALSE; + } + } + p = pars(cmd); + + if (wait_flag) + rc = prog_go(p, P_WAIT); + else + rc = prog_go(p, P_NOWAIT); + + return rc; +} + +#ifdef TEST +void main() +{ + char line_buff[STR_MAX]; + + while (gets(line_buff)) { + printf("\nreturn %04X\n", xsystem(line_buff)); + } +} +#endif /* TEST */ |