#include #include #include #include #include #include #include #include #include #include static char *imp; static char *ver; static const char *args[8]; static char dummy[256]; static char buf[256]; static size_t len; static void die(const char *msg) { fprintf(stderr, "%s\n", msg); exit(1); } static void diesys(const char *msg) { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(1); } static char * fdrun(int output_fd) { int fds[2]; int ignore_fd; int status; pid_t child; ssize_t nr; if (pipe(fds) == -1) diesys("pipe"); if ((child = fork()) == (pid_t)-1) diesys("fork"); if (!child) { ignore_fd = (output_fd != 1) ? 1 : 2; close(fds[0]); dup2(fds[1], output_fd); close(ignore_fd); dup2(open("/dev/null", O_RDWR), 0); dup2(0, ignore_fd); execvp(args[0], (char **)args); diesys("exec"); } close(fds[1]); len = 0; while (len < sizeof(buf) - 1) { nr = read(fds[0], buf + len, sizeof(buf) - 1 - len); if (nr == (ssize_t)-1) { if (errno == EINTR) { continue; } diesys("read"); } len += (size_t)nr; if (!nr) { break; } } buf[len] = 0; for (;;) { nr = read(fds[0], dummy, sizeof(dummy)); if (nr == (ssize_t)-1) { if (errno == EINTR) { continue; } diesys("read"); } if (!nr) { break; } } if (waitpid(child, &status, 0) == -1) diesys("waitpid"); if (!WIFEXITED(status)) die("bad termination"); #if 0 if (WEXITSTATUS(status) != 0) die("exit status != 0"); #endif return buf; } static char * outrun0(const char *exe) { args[0] = exe; args[1] = 0; return fdrun(1); } static char * outrun1(const char *exe, const char *a) { args[0] = exe; args[1] = a; args[2] = 0; return fdrun(1); } static char * outrun2(const char *exe, const char *a, const char *b) { args[0] = exe; args[1] = a; args[2] = b; args[3] = 0; return fdrun(1); } static char * dotted_after(char *magic_string) { const char version_chars[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "._"; char *a; char *b; if ((a = strstr(buf, magic_string))) { a += strlen(magic_string); } else { a = strchr(buf, 0); } b = a; for (;;) { if (!*b) break; if (!strchr(version_chars, *b)) break; b++; } *b = 0; if (b == a) { die("no version found"); } return a; } static char * version_plain(const char *exe) { outrun1(exe, "--version"); return dotted_after(""); } static char * version_chicken(const char *exe) { outrun1(exe, "-version"); return dotted_after("Version "); } static char * version_clojure(const char *exe) { outrun2(exe, "-e", "(print (clojure-version))"); return dotted_after(""); } static void detect(const char *exe) { outrun1(exe, "--version"); if (strstr(buf, "SBCL") == buf) { imp = "sbcl"; ver = dotted_after("SBCL "); return; } if (strstr(buf, "GNU CLISP") == buf) { imp = "clisp"; ver = dotted_after("GNU CLISP "); return; } if (!!strstr(buf, "GNU Guile")) { imp = "guile"; ver = dotted_after(" (GNU Guile) "); return; } if (strstr(buf, "MIT/GNU Scheme") == buf) { imp = "mit-scheme"; ver = dotted_after(" Release "); return; } outrun1(exe, "--help"); if (strstr(buf, "Lumo") == buf) { imp = "lumo"; ver = version_plain(exe); return; } if (strstr(buf, "Planck") == buf) { imp = "planck"; ver = version_plain(exe); return; } if (!!strstr(buf, "is a driver program for the CHICKEN compiler")) { imp = "csc"; ver = version_chicken(exe); return; } if (!!strstr(buf, "is the CHICKEN interpreter")) { imp = "csi"; ver = version_chicken(exe); return; } if (!!strstr(buf, "The clojure script is a runner for Clojure. clj is")) { imp = "clojure"; ver = version_clojure(exe); return; } outrun0(exe); if (strstr(buf, "Chez Scheme") == buf) { imp = "chez"; ver = dotted_after(" Version "); return; } if (strstr(buf, "Clozure Common Lisp") == buf) { imp = "ccl"; ver = dotted_after(" Version "); return; } outrun1(exe, "-V"); if (strstr(buf, "chibi-scheme") == buf) { imp = "chibi"; ver = dotted_after("chibi-scheme "); return; } if (strstr(buf, "Gauche scheme shell") == buf) { imp = "gauche"; ver = dotted_after("Gauche scheme shell, version "); return; } outrun1(exe, "-h"); if (!!strstr(buf, "newLISP")) { imp = "newlisp"; ver = dotted_after("newLISP v."); return; } } int main(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { imp = ver = 0; detect(argv[i]); printf("%s\n", imp ? imp : "(none)"); printf("%s\n", ver ? ver : "(none)"); printf("\n"); } return 0; }