summaryrefslogtreecommitdiffstats
path: root/src/Xsystem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Xsystem.c')
-rw-r--r--src/Xsystem.c589
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(&reg, &reg);
+ 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 */