home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / EXEC33B.ZIP / EXEC.C < prev    next >
C/C++ Source or Header  |  1993-06-22  |  14KB  |  576 lines

  1. /*
  2.    --- Version 3.4 93-06-22 13:40 ---
  3.  
  4.    EXEC.C: EXEC function with memory swap - Prepare parameters.
  5.  
  6.    Public domain software by
  7.  
  8.         Thomas Wagner
  9.         Ferrari electronic GmbH
  10.         Beusselstrasse 27
  11.         D-1000 Berlin 21
  12.         Germany
  13. */
  14.  
  15. #include "compat.h"
  16. #include "exec.h"
  17. #include "checkpat.h"
  18. #include <bios.h>
  19.  
  20. /*>e
  21.    Set REDIRECT to 1 to support redirection, else to 0.
  22.    CAUTION: The definition in 'spawn.asm' must match this definition!!
  23. <*/
  24. /*>d
  25.    Setzen Sie REDIRECT auf 1 um Dateiumleitung zu untertützen, sonst auf 0.
  26.    ACHTUNG: Die Definition in 'spawn.asm' muß mit dieser Definition 
  27.    übereinstimmen!!
  28. <*/
  29.  
  30.  
  31. #define REDIRECT  1
  32.  
  33. #define SWAP_FILENAME "$$AAAAAA.AAA" 
  34.  
  35. /*e internal flags for prep_swap */
  36. /*d interne Flags für prep_swap */
  37.  
  38. #define CREAT_TEMP      0x0080
  39. #define DONT_SWAP_ENV   0x4000
  40.  
  41. #define ERR_COMSPEC     -7
  42. #define ERR_NOMEM       -8
  43.  
  44.  
  45. spawn_check_proc *spawn_check = NULL;
  46.  
  47. /*e local variables */
  48. /*d Lokale Variablen */
  49.  
  50. static char drive [MAXDRIVE], dir [MAXDIR];
  51. static char name [MAXFILE], ext [MAXEXT];
  52. static char cmdpath [MAXPATH] = "";
  53. static char cmdpars [80] = "";
  54.  
  55.  
  56. #ifdef __cplusplus
  57. extern "C" int
  58. #else
  59. extern int _cdecl
  60. #endif
  61. do_spawn (int swapping,     /*e swap if non-0 */
  62.                             /*d Auslagern wenn nicht 0 */
  63.           char *xeqfn,      /*e file to execute */
  64.                             /*d auszuführende Datei */
  65.           char *cmdtail,    /*e command tail string */
  66.                             /*d Kommandozeile */
  67.           unsigned envlen,  /*e environment length */
  68.                             /*d Länge Umgebungsvariablen */
  69.           char *envp        /*e environment pointer */
  70.                             /*d Zeiger auf Umgebungsvariablen */
  71. #if (REDIRECT)
  72.           ,char *rstdin,    /*e redirection file names */
  73.                             /*d Umleitungs-Dateinamen */
  74.           char *rstdout,
  75.           char *rstderr
  76. #endif
  77.           );
  78.  
  79. #ifdef __cplusplus
  80. extern "C" int
  81. #else
  82. extern int _cdecl
  83. #endif
  84. prep_swap (int method,      /*e swap method */
  85.                             /*d Auslagerungsmethode */
  86.            char *swapfn);   /*e swap file name and/or path */
  87.                             /*d Auslagerungsdateiname und/oder Pfad */
  88.  
  89. #ifdef __cplusplus
  90. extern "C" int
  91. #else
  92. extern int _cdecl
  93. #endif
  94. exists (char *fname);
  95.  
  96. #define isslash(ch)  (ch == '\\' || ch == '/')
  97.  
  98. /* --------------------------------------------------------------------- */
  99.  
  100. /*>e Try '.COM', '.EXE', and '.BAT' on current filename, modify 
  101.    filename if found. <*/
  102. /*>d '.COM', '.EXE' und '.BAT' mit dem aktuellen Dateinamen versuchen,
  103.    Dateinamen modifizieren wenn gefunden. <*/
  104.  
  105. static int tryext (char *fn)
  106. {
  107.    char *ext;
  108.  
  109.    ext = strchr (fn, '\0');
  110.    strcpy (ext, ".COM");
  111.    if (exists (fn))
  112.       return 1;
  113.    strcpy (ext, ".EXE");
  114.    if (exists (fn))
  115.       return 1;
  116.    strcpy (ext, ".BAT");
  117.    if (exists (fn))
  118.       return 2;
  119.    *ext = 0;
  120.    return 0;
  121. }
  122.  
  123. /*>e Try to find the file 'fn' in the current path. Modifies the filename
  124.    accordingly. <*/
  125. /*>d Versuchen die Datei 'fn' im aktuellen Pfad zu finden. Der Dateiname
  126.    wird entsprechend modifiziert. <*/
  127.  
  128. static int findfile (char *fn)
  129. {
  130.    char *path, *penv;
  131.    char *prfx;
  132.    int found, check, hasext;
  133.  
  134.    if (!*fn)
  135.       return (cmdpath [0]) ? 3 : ERR_COMSPEC;
  136.  
  137.    if (isslash (fn [0]) && isslash (fn [1]))
  138.       {
  139.       }
  140.    check = checkpath (fn, INF_NODIR, drive, dir, name, ext, fn);
  141.    if (check < 0)
  142.       return check;
  143.  
  144.    if ((check & HAS_WILD) || !(check & HAS_FNAME))
  145.       return ERR_FNAME;
  146.  
  147.    hasext = (check & HAS_EXT) ? ((!stricmp (ext, ".bat")) ? 2 : 1) : 0;
  148.  
  149.    if (hasext)
  150.       {
  151.       if (check & FILE_EXISTS)
  152.          found = hasext;
  153.       else
  154.          found = 0;
  155.       }
  156.    else
  157.       found = tryext (fn);
  158.  
  159.    if (found || (check & (HAS_PATH | HAS_DRIVE)))
  160.       return found;
  161.  
  162.    penv = getenv ("PATH");
  163.    if (!penv)
  164.       return 0;
  165.    path = (char *)malloc (strlen (penv) + 1);
  166.    if (path == NULL)
  167.       return ERR_NOMEM;
  168.  
  169.    strcpy (path, penv);
  170.    prfx = strtok (path, ";");
  171.  
  172.    while (!found && prfx != NULL)
  173.       {
  174.       while (isspace (*prfx))
  175.          prfx++;
  176.       if (*prfx)
  177.          {
  178.          strcpy (fn, prfx);
  179.          prfx = strchr (fn, '\0');
  180.          prfx--;
  181.          if (*prfx != '\\' && *prfx != '/' && *prfx != ':')
  182.             {
  183.             *++prfx = '\\';
  184.             }
  185.          prfx++;
  186.          strcpy (prfx, name);
  187.          strcat (prfx, ext);
  188.          check = checkpath (fn, INF_NODIR, drive, dir, name, ext, fn);
  189.          if (check > 0 && (check & HAS_FNAME))
  190.             {
  191.             if (hasext)
  192.                {
  193.                if (check & FILE_EXISTS)
  194.                   found = hasext;
  195.                }
  196.             else
  197.                found = tryext (fn);
  198.             }
  199.          }
  200.       prfx = strtok (NULL, ";");
  201.       }
  202.    free (path);
  203.    return found;
  204. }
  205.  
  206.  
  207. /*>e 
  208.    Get name and path of the command processor via the COMSPEC 
  209.    environmnt variable. Any parameters after the program name
  210.    are copied and inserted into the command line.
  211. <*/
  212. /*>d
  213.    Namen und Pfad des Kommandoprozessors über die COMSPEC-Umgebungs-
  214.    Variable bestimmen. Parameter nach dem Programmnamen werden kopiert
  215.    und in die Kommandozeile eingefügt.
  216. <*/
  217.  
  218. static void getcmdpath (void)
  219. {
  220.    char *pcmd;
  221.    int found = 0;
  222.  
  223.    if (cmdpath [0])
  224.       return;
  225.    pcmd = getenv ("COMSPEC");
  226.    if (pcmd)
  227.       {
  228.       strcpy (cmdpath, pcmd);
  229.       pcmd = cmdpath;
  230.       while (isspace (*pcmd))
  231.          pcmd++;
  232.       if (NULL != (pcmd = strpbrk (pcmd, ";,=+/\"[]|<> \t")))
  233.          {
  234.          while (isspace (*pcmd))
  235.             *pcmd++ = 0;
  236.          if (strlen (pcmd) >= 79)
  237.             pcmd [79] = 0;
  238.          strcpy (cmdpars, pcmd);
  239.          strcat (cmdpars, " ");
  240.          }
  241.       found = findfile (cmdpath);
  242.       }
  243.    if (!found)
  244.       {
  245.       cmdpars [0] = 0;
  246.       strcpy (cmdpath, "COMMAND.COM");
  247.       found = findfile (cmdpath);
  248.       if (!found)
  249.          cmdpath [0] = 0;
  250.       }
  251. }
  252.  
  253.  
  254. /*>e
  255.    tempdir: Set temporary file path.
  256.             Read "TMP/TEMP" environment. If empty or invalid, clear path.
  257.             If TEMP is drive or drive+backslash only, return TEMP.
  258.             Otherwise check if given path is a valid directory.
  259.             If so, add a backslash, else clear path.
  260. <*/
  261. /*>d
  262.    tempdir: Pfad für temporäre Datei setzen.
  263.             Die Umgebungsvariable "TMP" oder "TEMP" wird gelesen. Ist
  264.             keine der beiden vorhanden, oder sind sie ungültig, wird
  265.             der Pfad gelöscht.
  266.             Besteht TMP/TEMP nur aus Laufwerksbuchstaben, oder aus
  267.             Laufwerk und Backslash, liefern TEMP.
  268.             Sonst prüfen ob der Pfad gültig ist, und einen Backslash
  269.             anfügen.
  270. <*/
  271.  
  272. static int tempdir (char *outfn)
  273. {
  274.    int i, res;
  275.    char *stmp [4];
  276.  
  277.    stmp [0] = getenv ("TMP");
  278.    stmp [1] = getenv ("TEMP");
  279.    stmp [2] = ".\\";
  280.    stmp [3] = "\\";
  281.  
  282.    for (i = 0; i < 4; i++)
  283.       if (stmp [i])
  284.          {
  285.          strcpy (outfn, stmp [i]);
  286.          res = checkpath (outfn, 0, drive, dir, name, ext, outfn);
  287.          if (res > 0 && (res & IS_DIR) && !(res & IS_READ_ONLY))
  288.             return 1;
  289.          }
  290.    return 0;
  291. }
  292.  
  293.  
  294. #if (REDIRECT)
  295.  
  296. static int redirect (char *par, char **rstdin, char **rstdout, char **rstderr)
  297. {
  298.    char ch, sav;
  299.    char *fn, *fnp, *beg;
  300.    int app;
  301.  
  302.    do
  303.       {
  304.       app = 0;
  305.       beg = par;
  306.       ch = *par++;
  307.       if (ch != '<')
  308.          {
  309.          if (*par == '&')
  310.             {
  311.             ch = '&';
  312.             par++;
  313.             }
  314.          if (*par == '>')
  315.             {
  316.             app = 1;
  317.             par++;
  318.             }
  319.          }
  320.  
  321.       while (isspace (*par))
  322.          par++;
  323.       fn = par;
  324.       if ((fnp = strpbrk (par, ";,=+/\"[]|<> \t")) != NULL)
  325.          par = fnp;
  326.       else
  327.          par = strchr (par, '\0');
  328.       sav = *par;
  329.       *par = 0;
  330.  
  331.       if (!strlen (fn))
  332.          return 0;
  333.       fnp = (char *)malloc (strlen (fn) + app + 1);
  334.       if (fnp == NULL)
  335.          return 0;
  336.       if (app)
  337.          {
  338.          strcpy (fnp, ">");
  339.          strcat (fnp, fn);
  340.          }
  341.       else
  342.          strcpy (fnp, fn);
  343.  
  344.       switch (ch)
  345.          {
  346.          case '<':   if (*rstdin != NULL)
  347.                         return 0;
  348.                      *rstdin = fnp;
  349.                      break;
  350.          case '>':   if (*rstdout != NULL)
  351.                         return 0;
  352.                      *rstdout = fnp;
  353.                      break;
  354.          case '&':   if (*rstderr != NULL)
  355.                         return 0;
  356.                      *rstderr = fnp;
  357.                      break;
  358.          }
  359.  
  360.       *par = sav;
  361.       strcpy (beg, par);
  362.       par = strpbrk (beg, "<>");
  363.       }
  364.    while (par);
  365.  
  366.    return 1;
  367. }
  368.  
  369. #endif
  370.  
  371.  
  372. int do_exec (char *exfn, char *epars, int spwn, unsigned needed, char **envp)
  373. {
  374.    static char swapfn [MAXPATH];
  375.    static char execfn [MAXPATH];
  376.    unsigned avail;
  377.    union REGS regs;
  378.    unsigned envlen;
  379.    int rc, ffrc;
  380.    int idx;
  381.    char **env;
  382.    char *ep, *envptr, *envbuf;
  383.    char *progpars;
  384.    int swapping;
  385. #if (REDIRECT)
  386.    char *rstdin = NULL, *rstdout = NULL, *rstderr = NULL;
  387. #endif
  388.  
  389.    envlen = 0;
  390.    envptr = NULL;
  391.    envbuf = NULL;
  392.  
  393.    if (epars == NULL)
  394.       epars = "";
  395.    if (exfn == NULL)
  396.       execfn [0] = 0;
  397.    else
  398.       strcpy (execfn, exfn);
  399.  
  400.    getcmdpath ();
  401.  
  402.    /*e First, check if the file to execute exists. */
  403.    /*d Zunächst prüfen ob die auszuführende Datei existiert. */
  404.  
  405.    if ((ffrc = findfile (execfn)) <= 0)
  406.       return RC_NOFILE | -ffrc;
  407.  
  408.    if (ffrc > 1)   /* COMMAND.COM or Batch file */
  409.       {
  410.       if (!cmdpath [0])
  411.          return RC_NOFILE | -ERR_COMSPEC;
  412.  
  413.       idx = (ffrc == 2) ? strlen (execfn) + 5 : 1;
  414.       progpars = (char *)malloc (strlen (epars) + strlen (cmdpars) + idx);
  415.       if (progpars == NULL)
  416.          return RC_NOFILE | -ERR_NOMEM;
  417.       strcpy (progpars, cmdpars);
  418.       if (ffrc == 2)
  419.          {
  420.          strcat (progpars, "/c ");
  421.          strcat (progpars, execfn);
  422.          strcat (progpars, " ");
  423.          }
  424.       strcat (progpars, epars);
  425.       strcpy (execfn, cmdpath);
  426.       }
  427.    else
  428.       {
  429.       progpars = (char *)malloc (strlen (epars) + 1);
  430.       if (progpars == NULL)
  431.          return RC_NOFILE | -ERR_NOMEM;
  432.       strcpy (progpars, epars);
  433.       }
  434.  
  435. #if (REDIRECT)
  436.    if ((ep = strpbrk (progpars, "<>")) != NULL)
  437.       if (!redirect (ep, &rstdin, &rstdout, &rstderr))
  438.          {
  439.          rc = RC_REDIRERR;
  440.          goto exit;
  441.          }
  442. #endif
  443.  
  444.    /*e Now create a copy of the environment if the user wants it. */
  445.    /*d Nun eine Kopie der Umgebungsvariablen anlegen wenn angefordert. */
  446.  
  447.    if (envp != NULL)
  448.       for (env = envp; *env != NULL; env++)
  449.          envlen += strlen (*env) + 1;
  450.  
  451.    if (envlen)
  452.       {
  453.       /*e round up to paragraph, and alloc another paragraph leeway */
  454.       /*d Auf Paragraphengrenze runden, plus einen Paragraphen zur Sicherheit */
  455.       envlen = (envlen + 32) & 0xfff0;
  456.       envbuf = (char *)malloc (envlen);
  457.       if (envbuf == NULL)
  458.          {
  459.          rc = RC_ENVERR;
  460.          goto exit;
  461.          }
  462.  
  463.       /*e align to paragraph */
  464.       /*d Auf Paragraphengrenze adjustieren */
  465.       envptr = envbuf;
  466.       if (FP_OFF (envptr) & 0x0f)
  467.          envptr += 16 - (FP_OFF (envptr) & 0x0f);
  468.       ep = envptr;
  469.  
  470.       for (env = envp; *env != NULL; env++)
  471.          {
  472.          ep = stpcpy (ep, *env) + 1;
  473.          }
  474.       *ep = 0;
  475.       }
  476.  
  477.    if (!spwn)
  478.       swapping = -1;
  479.    else
  480.       {
  481.       /*e Determine amount of free memory */
  482.       /*d Freien Speicherbereich feststellen */
  483.  
  484.       regs.x.ax = 0x4800;
  485.       regs.x.bx = 0xffff;
  486.       intdos (®s, ®s);
  487.       avail = regs.x.bx;
  488.  
  489.       /*e No swapping if available memory > needed */
  490.       /*d Keine Auslagerung wenn freier Speicher > benötigter */
  491.  
  492.       if (needed < avail)
  493.          swapping = 0;
  494.       else
  495.          {
  496.          /*>e Swapping necessary, use 'TMP' or 'TEMP' environment variable
  497.            to determine swap file path if defined. <*/
  498.          /*>d Auslagerung notwendig, 'TMP' oder 'TEMP' Umgebungsvariable
  499.             verwenden um Auslagerungsdateipfad festzulegen. <*/
  500.  
  501.          swapping = spwn;
  502.          if (spwn & USE_FILE)
  503.             {
  504.             if (!tempdir (swapfn))
  505.                {
  506.                spwn &= ~USE_FILE;
  507.                swapping = spwn;
  508.                }
  509.             else if (OS_MAJOR >= 3)
  510.                swapping |= CREAT_TEMP;
  511.             else
  512.                {
  513.                strcat (swapfn, SWAP_FILENAME);
  514.                idx = strlen (swapfn) - 1;
  515.                while (exists (swapfn))
  516.                   {
  517.                   if (swapfn [idx] == 'Z')
  518.                      idx--;
  519.                   if (swapfn [idx] == '.')
  520.                      idx--;
  521.                   swapfn [idx]++;
  522.                   }
  523.                }
  524.             }
  525.          }
  526.       }
  527.  
  528.    /*e All set up, ready to go. */
  529.    /*d Alles vorbereitet, jetzt kann's losgehen. */
  530.  
  531.    if (swapping > 0)
  532.       {
  533.       if (!envlen)
  534.          swapping |= DONT_SWAP_ENV;
  535.  
  536.       rc = prep_swap (swapping, swapfn);
  537.       if (rc < 0)
  538.          rc = RC_PREPERR | -rc;
  539.       else
  540.          rc = 0;
  541.       }
  542.    else
  543.       rc = 0;
  544.  
  545.    if (!rc)
  546.       {
  547.       if (spawn_check != NULL)
  548.          rc = spawn_check (ffrc, swapping, execfn, progpars);
  549.       if (!rc)
  550. #if (REDIRECT)
  551.          rc = do_spawn (swapping, execfn, progpars, envlen, envptr, rstdin, rstdout, rstderr);
  552. #else
  553.          rc = do_spawn (swapping, execfn, progpars, envlen, envptr);
  554. #endif
  555.       }
  556.  
  557.    /*e Free the environment buffer if it was allocated. */
  558.    /*d Den Umgebungsvariablenblock freigeben falls er alloziert wurde. */
  559.  
  560. exit:
  561.    free (progpars);
  562. #if (REDIRECT)
  563.    if (rstdin)
  564.       free (rstdin);
  565.    if (rstdout)
  566.       free (rstdout);
  567.    if (rstderr)
  568.       free (rstderr);
  569. #endif
  570.    if (envlen)
  571.       free (envbuf);
  572.  
  573.    return rc;
  574. }
  575.  
  576.