home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1993 #2 / Image.iso / os2 / edmi3.zip / DPIPELN.ZIP / DPIPELN.C < prev    next >
Text File  |  1993-04-27  |  23KB  |  811 lines

  1. /* dpipeln.c
  2.  * Copyright (C) 1993 Charles R. Oldham
  3.  * DPipeLn is distributed without any warranty.
  4.  * I am reasonably sure that it is without major bugs, but I assume no
  5.  * responsibility for anything it may do to your machine.  You use this
  6.  * tool at your own risk.
  7.  *
  8.  * Allows a user to start a DOS VDM from an OS/2 prompt
  9.  * and pipe stdout back to the OS/2 session.
  10.  *
  11.  * $Log: dpipeln.c,v $
  12.  * Revision 1.11  1993/04/12  18:17:06  cro
  13.  * Cosmetic changes and code cleanup.
  14.  *
  15.  * Revision 1.10  1993/03/17  15:12:33  cro
  16.  * Modified the program so it doesn't start the DosSession as a related
  17.  * session now, but instead starts it as an unrelated session.  This is
  18.  * because WF/2 spawns nmake as a child process, then nmake spawns
  19.  * dpipeln as a child process.  If you have started any other process
  20.  * as a child process from within WF then subsequent DosStartSession
  21.  * calls will fail with "ERROR_SMG_NOT_PARENT" (or something like that).
  22.  * The downside is that if a session is not started as a related session
  23.  * a termination queue (that would contain the session's return code) is
  24.  * not created.  So dpipeln now creates a batch file that is executed instead
  25.  * of the Dos program.  The batch file pipes the program output to the
  26.  * original npipe, and the result code to a second npipe.
  27.  *
  28.  * Revision 1.9  1993/03/15  20:21:17  cro
  29.  * Changed BUFSIZE to 80 so messages would appear more frequently during
  30.  * makes.
  31.  *
  32.  * Revision 1.8  1993/03/09  17:16:43  cro
  33.  * Restructured some of the code to eliminate unnecessary global variables
  34.  * and move major functions out of main.  Added more comments.
  35.  *
  36.  * Revision 1.7  1993/03/08  15:32:13  cro
  37.  * Re-enabled title-bar display (for testing had it forced to "DPipeLn").
  38.  *
  39.  * Revision 1.6  1993/03/05  21:17:06  cro
  40.  * Removed code that set the StartData.PgmName parameter.  It was not
  41.  * necessary--DosStartSession invokes the appropriate shell if
  42.  * the parameter is 0 or NULL.
  43.  *
  44.  * Revision 1.5  1993/03/04  20:56:07  cro
  45.  * Added support for multiple instances of dpipeln by making the
  46.  * named pipe name out of dpipeln's PID.  Also laid foundation
  47.  * for implementation of the termination queue so we can
  48.  * tell what the return code of the Dos command was.
  49.  *
  50.  * Revision 1.4  1993/03/04  19:20:47  cro
  51.  * Added code to process arguments without quotes.  This changes
  52.  * the syntax of the command subtly--before you could place the Dos command
  53.  * anywhere on the command line.  Now you must place it at the *end* of the
  54.  * command line.
  55.  * Before: dpipeln -v "mem /c"
  56.  * After:  dpipeln -v mem /c
  57.  *
  58.  * Revision 1.3  1993/03/03  17:00:42  cro
  59.  * Added mucho comments, replaced some numeric constants with #defined
  60.  * constants.
  61.  *
  62.  * Revision 1.2  1993/03/03  16:05:03  cro
  63.  * Changed mode of stdout to binary to prevent translation of
  64.  * LF to CR/LF.  Added debug code, but commented out in this version.
  65.  *
  66.  * Revision 1.1  1993/03/02  21:12:09  cro
  67.  * Initial revision
  68.  *
  69.  *
  70.  */
  71.  
  72. #define INCL_DOSSESMGR        /* Session Manager values */
  73. #define INCL_DOS            /* DOS Calls (not MS-DOS) */
  74. #define INCL_DOSNMPIPES        /* Named Pipe Support */
  75. #define INCL_DOSPROCESS        /* Process IDs */
  76. #define INCL_DOSQUEUES        /* Queue support */
  77.  
  78. #define BUFSIZE 80            /* Pipe buffer size */
  79. #define SETSIZE 4096        /* Dos settings maximum size */
  80.  
  81. /* String macros to make life a little easier */
  82. #define new_string(x) ((char *)malloc((x) + 1))
  83. #define freemem(x) if ((x) != NULL) free((x))
  84.  
  85. #include <os2.h>
  86. #include <stdio.h>
  87. #include <string.h>
  88. #include <ctype.h>
  89. #include <stdlib.h>
  90.  
  91. PBYTE    get_dos_settings(char *file);
  92. char    *get_basename();
  93. char    *make_npipename(char *PQbasename);
  94. char    *make_batname(char *base, char *tempdir);
  95. int        build_batchfile(char *Batname, char *Errpname, char *Command);
  96. void    process_cmdline(int argc, char *argv[]);
  97. void    usage();
  98. void    cleanup();
  99. char    *get_exename(char *arg);
  100. void    setup_startdata();
  101. void    transfer_data(HPIPE *piphand);
  102. void    read_errpipe();
  103. char    *make_rcdname(char *base);
  104. char    *get_tempdir();
  105.  
  106.  
  107. PSZ            PgmTitle = NULL;            /* Title of window in which Dos program will execute */
  108. PSZ            PgmCmdLine = NULL;            /* Command line for Dos program */
  109. PSZ            PgmSettingsFile = NULL;    /* File containing DOS settings */
  110. PSZ            Exename = NULL;            /* DPipeLn Executable name */
  111. UCHAR        ObjBuf[100];                /* Object buffer.  Used by DosStartSession */
  112. PSZ            Command;                    /* The actual DOS command to be executed */
  113. PSZ            Errpname;                    /* Name of the pipe that contains the return code */
  114. HPIPE        Piphand, Rcdpipe;            /* Named Pipe handles */
  115.  
  116. int            Opt_visible;                /* Run DOS session invisibly */
  117. int            Opt_settings;                /* DOS session has a settings file */
  118. int            Opt_foreground;            /* Run session in foreground */
  119. char        *PQbasename;                /* Unique name for the named pipe */
  120. char        *Pname;                    /* Fully qualified path for named pipe */
  121. char        *Batname;                    /* Unique name of the batch file */
  122. ULONG        OwningPID;                    /* PID of dpipeln.exe */
  123. char        RCstring[BUFSIZE];            /* String to temporarily hold ret code from */
  124.                                         /*  DOS program */
  125. char        *Tempdir = NULL;            /* temporary directory in which to put batch file */
  126.  
  127. /*------------------------------------------------------------------------*/
  128. /* begin main                                                             */
  129. /*------------------------------------------------------------------------*/
  130.  
  131. USHORT main(int argc, char *argv[]) {
  132.  
  133.     STARTDATA    sd;                        /* Start session data structure */
  134.     ULONG        sess_id;                    /* Session ID (returned) */
  135.     PID        s_pid;                        /* Process ID (returned) */
  136.     ULONG        outbuffer = 1,                /* Size of out buffer */
  137.                 inbuffer = BUFSIZE - 1,    /* Size of in buffer */
  138.                 timeout = 10000;            /* Timeout before giving up */
  139.     APIRET        rc = 0;                    /* Return code */
  140.     int        dosreturn = -1;            /* return code from the Dos program */
  141.     TID        threadid;
  142.     ULONG        targ;
  143.     ULONG        tstack;
  144.     ULONG        tflags;
  145.     RESULTCODES wp_results;
  146.     PID        the_pid;
  147.  
  148.     /* Get the name by which dpipeln was called out of the command line */
  149.     Exename = get_exename(argv[0]);
  150.  
  151.     /* Force stdout into binary mode */
  152.     if (_fsetmode(stdout, "b") == -1) {
  153.         fprintf(stderr, "Could not set stdout to binary mode.\n");
  154.         exit(-1);
  155.     }
  156.  
  157.     PQbasename = get_basename();    /* Get the unique name to be used for the Named */
  158.                                     /* Pipe and the termination queue */
  159.  
  160.     Pname = make_npipename(PQbasename);
  161.     Errpname = make_rcdname(PQbasename);
  162.  
  163.     /* Process the command line */
  164.     process_cmdline(argc, argv);
  165.  
  166.     if (Tempdir == NULL)  Tempdir = get_tempdir();
  167.     Batname = make_batname(PQbasename, Tempdir);
  168.  
  169.  
  170.     /* Create the named pipe */
  171.     rc = DosCreateNPipe(Pname,                /* Pipe name */
  172.                         &Piphand,                        /* returned pipe handle */
  173.                         NP_ACCESS_DUPLEX,                /* Open mode */
  174.                         NP_WAIT || NP_TYPE_BYTE || NP_READMODE_BYTE ||
  175.                         NP_UNLIMITED_INSTANCES,        /* Pipe modes */
  176.                         outbuffer,                        /* Size of out buffer */
  177.                         inbuffer,                        /* Size of in buffer */
  178.                         timeout);                        /* Timeout time */
  179.  
  180.     /* Die if create pipe failed */
  181.     if (rc != 0) {
  182.         fprintf(stderr, "%s: DosCreateNPipe '%s' failed (%ld).\n", Exename, Pname, rc);
  183.         exit(-1);
  184.     }
  185.  
  186.     rc = DosCreateNPipe(Errpname,                        /* Pipe name */
  187.                         &Rcdpipe,                        /* returned pipe handle */
  188.                         NP_ACCESS_DUPLEX,                /* Open mode */
  189.                         NP_WAIT || NP_TYPE_BYTE || NP_READMODE_BYTE ||
  190.                         NP_UNLIMITED_INSTANCES,        /* Pipe modes */
  191.                         outbuffer,                        /* Size of out buffer */
  192.                         inbuffer,                        /* Size of in buffer */
  193.                         timeout);                        /* Timeout time */
  194.  
  195.     /* Die if create pipe failed */
  196.     if (rc != 0) {
  197.         fprintf(stderr, "%s: DosCreateNPipe '%s' failed (%ld).\n", Exename, Pname, rc);
  198.         exit(-1);
  199.     }
  200.  
  201.  
  202.     /* Set the StartData parameters */
  203.     setup_startdata(&sd);
  204.  
  205.     /* Create the batch file */
  206.     rc = build_batchfile(Batname, Errpname, Command);
  207.     if (rc != 0) {
  208.         fprintf(stderr, "%s: Batch file build failed (%ld).\n", Exename, rc);
  209.         exit(-1);
  210.     }
  211.     
  212.     /* Start the Dos session */
  213.     rc = DosStartSession(&sd, &sess_id, &s_pid);
  214.                           /* On successful return, the variable  */
  215.                           /*   sess_id contains the session ID   */
  216.                           /*   of the new session, and the       */
  217.                           /*   variable s_pid contains the process */
  218.                           /*   ID of the new process             */
  219.  
  220.     if (rc != 0) {
  221.         fprintf(stderr, "%s: DosStartSession failed (%ld)\n", Exename, rc);
  222.         exit(-1);
  223.     }
  224.  
  225.     RCstring[0] = 0;
  226.     targ = 0;
  227.     tflags = 0;    /* Start thread immediately */
  228.     tstack = 4096;    /* Stack size for thread */
  229.  
  230. #ifdef DEBUG_EMX
  231.     threadid = _beginthread(read_errpipe, NULL, (unsigned)tstack, &targ);
  232.     if (threadid == -1)  fprintf(stderr, "_beginthread returned %ld.\n", threadid);
  233. #else
  234.     rc = DosCreateThread(&threadid, read_errpipe, targ, tflags, tstack);
  235.     if (rc != 0) {
  236.            fprintf(stderr, "%s: DosCreateThread failed (%ld).", Exename, rc);
  237.         exit(-1);
  238.     }
  239. #endif
  240.  
  241.     /* Receive data from the pipes */
  242.     rc = DosConnectNPipe(Piphand);
  243.     if (rc != 0) {
  244.         fprintf(stderr, "%s: DosConnectNPipe failed (%ld)\n", Exename, rc);
  245.         exit(-1);
  246.     }
  247.  
  248.  
  249.     transfer_data(&Piphand);
  250.  
  251.  
  252.     rc = DosWaitThread(&threadid, DCWW_WAIT);
  253.  
  254.     sscanf(RCstring, "%d", &dosreturn);
  255.  
  256. /*    fprintf(stderr, "String: %s, Return: %d", RCstring, dosreturn);*/
  257.  
  258.     /* Wait for the DOS process to finish */
  259.     DosWaitChild(DCWA_PROCESS,
  260.                 DCWW_WAIT,
  261.                 &wp_results,
  262.                 &the_pid,
  263.                 s_pid);
  264.  
  265.     cleanup();
  266.  
  267. #ifdef DEBUG
  268.     fprintf(stderr, "wp_results.codeTerminate=%ld, wp_results.codeResult=%ld\n",
  269.                 wp_results.codeTerminate, wp_results.codeResult);
  270. #endif
  271.  
  272.     return (USHORT)dosreturn;
  273.  
  274. } /* end of main */
  275.  
  276. /*------------------------------------------------------------------------*/
  277. /* end main                                                               */
  278. /*------------------------------------------------------------------------*/
  279.  
  280. /*
  281.  * cleanup
  282.  * Free memory and disconnect the pipe
  283.  *
  284.  */
  285. void cleanup() {
  286.  
  287.     APIRET    rc;
  288.     int    tries = 0;
  289.  
  290.     /* Close the pipes */
  291.     DosDisConnectNPipe(Piphand);
  292.     DosDisConnectNPipe(Rcdpipe);
  293.  
  294.     /* Erase the batch file */
  295.     if (Batname != NULL) {            /* Batname may not have been created when */
  296.         do {                        /* usage() is called */
  297.             rc = DosDelete(Batname);
  298.             tries++;
  299.         } while (rc == 32 && tries < 10000);
  300.  
  301.         if (rc != 0) fprintf(stderr, "%s: DosDelete on '%s' failed (%ld).\n",
  302.                             Exename, Batname, rc);
  303.     }
  304.  
  305.     /* Free memory */
  306.     freemem(PgmTitle);
  307.     freemem(PgmCmdLine);
  308.     freemem(PgmSettingsFile);
  309.     freemem(Exename);
  310.     freemem(PQbasename);
  311.     freemem(Pname);
  312.     freemem(Batname);
  313.     freemem(Command);
  314.     freemem(Tempdir);
  315. } /* End of cleanup */
  316.  
  317. /*
  318.  * get_dos_settings
  319.  *
  320.  * Read the environment from the Dos Settings File
  321.  */
  322. PBYTE get_dos_settings(char *file) {
  323.  
  324.     FILE *setfile;
  325.     PBYTE env = (PBYTE)malloc(SETSIZE);
  326.     PBYTE p = env;
  327.  
  328.     setfile = fopen(file, "r");
  329.     if (setfile == NULL) {
  330.         fprintf(stderr, "%s: Error opening DOS Settings file %s.\n", Exename, PgmSettingsFile);
  331.         exit(-1);
  332.     }
  333.  
  334.     while (fgets(p, 80, setfile)) {
  335.         p += strlen(p);
  336.         *(p-1)='\0';
  337.         if (p > env + 4096) {
  338.             fprintf(stderr, "%s: Too many settings.\n", Exename);
  339.             fflush(stderr);
  340.             exit(-1);
  341.         }
  342.  
  343.     }
  344.  
  345.     realloc(env, p-env);
  346.  
  347.     fclose(setfile);
  348.  
  349.     return(env);
  350.  
  351. } /* end of get_dos_settings */
  352.  
  353. /* 
  354.  * process_cmdline
  355.  *
  356.  * Takes the command line arguments and iterates through them, setting various
  357.  * global variables
  358.  */
  359. void process_cmdline(int argc, char *argv[]) {
  360.  
  361.     int    cmdcount = 0, argscount = 0, argsize = 0;
  362.     char    *doscommand;
  363.  
  364.     Opt_visible = 0;
  365.     Opt_settings = 0;
  366.     Opt_foreground = 0;
  367.  
  368.     if (argc < 2) {
  369.         usage();
  370.     }
  371.  
  372.     for (cmdcount = 1; cmdcount < argc && argv[cmdcount][0] == '-'; cmdcount++) {
  373.  
  374.         switch (argv[cmdcount][1]) {
  375.             case 'v':    Opt_visible = 1;
  376.                         break;
  377.  
  378.             case 's':    PgmSettingsFile = strdup(&argv[cmdcount][2]);
  379.                         if (access(PgmSettingsFile, 0) != 0) {
  380.                             fprintf(stderr, "%s: Cannot access %s.\n", Exename, PgmSettingsFile);
  381.                             exit(-1);
  382.                         }
  383.                         Opt_settings = 1;
  384.                         break;
  385.             case 'f':    Opt_foreground = 1;
  386.                         break;
  387.             case 't':    if (argv[cmdcount][strlen(argv[cmdcount]) - 1] != '\\') {
  388.                             /* For the extra \ at the end of the string */
  389.                             Tempdir = new_string(strlen(&argv[cmdcount][2]) + 1);
  390.                             strcpy(Tempdir, &argv[cmdcount][2]);
  391.                             strcat(Tempdir, "\\");
  392.                         } else {
  393.                             Tempdir = new_string(strlen(&argv[cmdcount][2]));
  394.                             strcpy(Tempdir, &argv[cmdcount][2]);
  395.                         }
  396.                         break;
  397.             default:    break;
  398.         }
  399.     }
  400.     argsize = 0;
  401.     for (argscount = cmdcount; argscount < argc; argscount++) {
  402.         argsize += strlen(argv[argscount]) + 1;
  403.     }
  404.     if (argsize == 0) usage();
  405.  
  406.     doscommand = new_string(argsize);
  407.     doscommand[0] = 0;
  408.     for (argscount = cmdcount; argscount < argc; argscount++) {
  409.         strcat(doscommand, argv[argscount]);
  410.         strcat(doscommand, " ");
  411.     }
  412.  
  413.     if (PgmTitle == NULL) {
  414.  
  415.         PgmTitle = new_string(strlen(&doscommand[1]) > 50 ? 55 : strlen(&doscommand[1]));
  416.         PgmTitle[0] = 0;
  417.         strncpy(PgmTitle, doscommand, 50);
  418.         if (strlen(doscommand) > 50) {
  419.             PgmTitle[54] = 0;    /* 54, not 55 because PgmTitle is 0 based */
  420.             strcat(PgmTitle, "...");
  421.         }
  422.  
  423.         Command = strdup(doscommand);
  424.  
  425.     } else {
  426.         freemem(doscommand);
  427.         usage();
  428.     }
  429.  
  430.     if (Command == NULL) {
  431.         freemem(doscommand);
  432.         usage();
  433.     }
  434.  
  435.     freemem(doscommand);
  436.  
  437. } /* end of process_cmdline */
  438.  
  439. /*
  440.  * usage
  441.  *
  442.  * Print usage message, cleanup, then terminate with exit code -1
  443.  *
  444.  */
  445. void usage() {
  446.  
  447.  
  448.     fprintf(stderr, "Usage: %s [-v] [-f] [-sdos_settings_filename] [-ttemp_dir_name] dos_command\n", Exename);
  449.  
  450.     cleanup();
  451.  
  452.     exit(-1);
  453.  
  454. } /* End of usage */
  455.  
  456. /*
  457.  * get_tempdir
  458.  *
  459.  * Return a string to the temporary directory where the batch file will be
  460.  * created.  This function is called only if -t"dir_name" is not specified
  461.  * on the command line.  The environment is scanned for this information, searching 
  462.  * first for DPIPELN_TEMP, then for TEMP, then for just TMP.  If none are 
  463.  * found then the current directory will be used.
  464.  *
  465.  */
  466. char *get_tempdir() {
  467.  
  468.     APIRET    rc;
  469.     PSZ    envptr;
  470.     PSZ    temp;
  471.  
  472.     if (DosScanEnv("DPIPELN_TEMP", &envptr) != 0)
  473.         if (DosScanEnv("TEMP", &envptr) != 0)
  474.             if (DosScanEnv("TMP", &envptr) != 0)  return NULL;
  475.  
  476.     if (envptr[strlen(envptr) - 1] != '\\') {
  477.         temp = new_string(strlen(envptr) + 1);
  478.         strcpy(temp, envptr);
  479.         strcat(temp, "\\");
  480.     } else {
  481.         temp = strdup(envptr);
  482.     }
  483.  
  484.     return temp;
  485.  
  486. }
  487.  
  488.  
  489.  
  490. /*
  491.  * get_basename
  492.  *
  493.  * Create a base name for the named pipe and the termination queue out of
  494.  * the process id and a character.
  495.  */
  496. char *get_basename() {
  497.  
  498.     char    tmpname[256];    /* 255 characters ought to be enough */
  499.  
  500. /* DosGetInfoBlocks returns the address of the Thread Information Block (TIB)
  501.    of the current thread. This function also returns the address
  502.    of the Process Information Block (PIB) of the current process. */
  503.  
  504.     PTIB            pptib;    /* Address of a pointer to a TIB */
  505.     PPIB            pppib;    /* Address of a pointer to a PIB */
  506.     
  507.     APIRET            rc;        /* Return code */
  508.  
  509.     rc = DosGetInfoBlocks(&pptib, &pppib);
  510.  
  511.     if (rc != 0) fprintf(stderr, "%s: DosGetInfoBlocks failed (%ld)\n", Exename, rc);
  512.  
  513.     OwningPID = pppib->pib_ulpid;
  514.  
  515.     sprintf(tmpname, "n%u", pppib->pib_ulpid);
  516.  
  517.  
  518.     return(strdup(tmpname));
  519.  
  520. } /* end of get_basename */
  521.  
  522.  
  523. /*
  524.  * make_npipename
  525.  *
  526.  * Add the word \\PIPE\\ onto the base name for the pipe and return
  527.  * a new string.
  528.  */
  529. char *make_npipename(char *base) {
  530.  
  531.     char    *npipe;
  532.     char    prefix[] = "\\PIPE\\";
  533.  
  534.     npipe = new_string(strlen(prefix) + strlen(base));
  535.     npipe[0] = 0;
  536.  
  537.     strcpy(npipe, prefix);
  538.     strcat(npipe, base);
  539.     
  540.  
  541.     return npipe;
  542.  
  543. } /* end of make_npipename */
  544.  
  545.  
  546. /*
  547.  * make_batname
  548.  *
  549.  * Make the name of the batch file that will be executed by the DOS
  550.  * command processor.
  551.  * 
  552.  */
  553. char *make_batname(char *base, char *tempdir) {
  554.  
  555.     char    *bat;
  556.  
  557.     bat = new_string(strlen(tempdir) + strlen(base) + strlen(".bat"));
  558.     bat[0] = 0;
  559.  
  560.     strcpy(bat, tempdir);
  561.     strcat(bat, base);
  562.     strcat(bat, ".bat");
  563.  
  564.     return bat;
  565.  
  566. } /* end of make_batname */
  567.  
  568.  
  569. /*
  570.  * make_rcdname
  571.  *
  572.  * Make the name of the file that will contain the return code from the
  573.  * DOS program.
  574.  *
  575.  */
  576. char *make_rcdname(char *base) {
  577.  
  578.     char    *rcd;
  579.     char    prefix[] = "\\PIPE\\";
  580.  
  581.     rcd = new_string(strlen(prefix) + strlen(base) + 1);
  582.     rcd[0] = 0;
  583.  
  584.     strcpy(rcd, prefix);
  585.     strcat(rcd, "e");
  586.     strcat(rcd, base);
  587.     return rcd;
  588.  
  589. } /* end of make_rcdname */
  590.  
  591.  
  592. /*
  593.  * get_exename
  594.  * Retrieve the name of the executable. i.e. d:\src\stuff\dpipeln.exe will
  595.  * become dpipeln.exe, and return a new string containing such
  596.  */
  597. char *get_exename(char *arg) {
  598.  
  599.     int cmdcount;
  600.  
  601.     for (cmdcount = strlen(arg); cmdcount > 0 && (arg[cmdcount] != '/' &&
  602.                                                         arg[cmdcount] != '\\' &&
  603.                                                         arg[cmdcount] != ':');
  604.             cmdcount-- && (arg[cmdcount] = tolower(arg[cmdcount])));
  605.  
  606.     /* Copy the executable name into Exename */
  607.     return (strdup(&(arg[cmdcount == 0 ? cmdcount : ++cmdcount])));
  608.  
  609. } /* end of get_exename */
  610.  
  611.  
  612. /*
  613.  * setup_startdata
  614.  *
  615.  * The startdata structure provides almost all the necessary information
  616.  * to DosStartSession about the type of session to be started.
  617.  * This function initializes that data.
  618.  *
  619.  */
  620. void setup_startdata(STARTDATA *SD) {
  621.  
  622.     SD->Length = sizeof(STARTDATA);            /* Length of STARTDATA structure */
  623.  
  624.     SD->Related = SSF_RELATED_INDEPENDENT;        /* Independent session */
  625.  
  626.     SD->FgBg = Opt_foreground ? SSF_FGBG_FORE : SSF_FGBG_BACK;
  627.                                             /* Start session in fore/background */
  628.  
  629.  
  630.     SD->TraceOpt = SSF_TRACEOPT_NONE;        /* Don't trace session */
  631.  
  632.     SD->PgmTitle = PgmTitle;                /* Session Title string */
  633.  
  634.     /* This session will not need a termination queue. */
  635.     SD->TermQ = 0;
  636.  
  637.     SD->InheritOpt = SSF_INHERTOPT_PARENT;
  638.                            /* Inherit environment and open */
  639.                            /*   file handles from parent    */
  640.  
  641.     SD->SessionType = SSF_TYPE_WINDOWEDVDM;
  642.                             /* Session type is a windowed VDM */
  643.  
  644.     SD->IconFile = 0;
  645.                            /* Assume no specific icon file */
  646.                            /*   is provided                */
  647.  
  648.     SD->PgmHandle = 0;
  649.                            /* Do not use the installation file */
  650.  
  651.     
  652.     SD->PgmControl = Opt_visible ? SSF_CONTROL_VISIBLE : SSF_CONTROL_INVISIBLE;
  653.                            /* Start the program as visible, or invisible */
  654.                            /* depending on the command line argument     */
  655.  
  656.     SD->InitXPos = 30;
  657.     SD->InitYPos = 40;
  658.     SD->InitXSize = 200;    /* Initial window coordinates */
  659.     SD->InitYSize = 140;    /*   and size                 */
  660.  
  661.     SD->Reserved = 0;
  662.                            /* Reserved, must be zero */
  663.  
  664.     SD->ObjectBuffer = ObjBuf;
  665.                            /* Object buffer to hold DosExecPgm */
  666.                            /*   failure causes                 */
  667.  
  668.     SD->ObjectBuffLen = 100;
  669.                            /* Size of object buffer */
  670.  
  671.     /* Get the DOS settings or just 0 if no settings file requested */
  672.     SD->Environment = Opt_settings ? get_dos_settings(PgmSettingsFile) : 0;
  673.  
  674.     SD->PgmName = 0;                /* If this is 0 (or NULL) the Session */
  675.                                     /* will invoke the proper shell--either */
  676.                                     /* the one specified in CONFIG.SYS */
  677.                                     /* or the one in the settings file */
  678.  
  679.     PgmCmdLine = new_string(strlen(Batname) + strlen("/c "));
  680.     strcpy(PgmCmdLine, "/c ");
  681.     strcat(PgmCmdLine, Batname);
  682.  
  683.     SD->PgmInputs = PgmCmdLine;    /* Command line arguments to command processor */
  684.  
  685. } /* end of setup_startdata */
  686.  
  687. /*
  688.  * transfer_data
  689.  * Get passed text from the Dos session and write it to stdout.
  690.  *
  691.  */
  692. void transfer_data(HPIPE *piphand) {
  693.  
  694.     char    prep_string[BUFSIZE];
  695.     APIRET    rc = 0;
  696.  
  697.     ULONG    BytesRead;
  698.  
  699.     /* "Prep" the string and the return code. */
  700.     prep_string[0] = 0;
  701.  
  702.     do {
  703.  
  704.         rc = DosRead(*piphand,                /* Read from the pipe */
  705.                     prep_string,            /* Into prep_string   */
  706.                     BUFSIZE - 1,            /* A maximum of BUFSIZE - 1 bytes */
  707.                     &BytesRead);            /* Total bytes read goes here */
  708.  
  709.         if (rc !=0) fprintf(stderr, "%s: DosRead failed (%ld)\n", Exename, rc);
  710.  
  711.         /* DosRead is supposed to return 0 in BytesRead when it reaches EOF */
  712.         if (BytesRead > 0L) {
  713.             prep_string[(int)BytesRead] = 0;    /* Stick a null at the end of the string */
  714.             fputs(prep_string, stdout);        /* Write the string to stdout */
  715.  
  716. /* Debugging code */
  717. #ifdef DEBUG
  718.             for (i = 0; i < strlen(prep_string); i++) {
  719.                    fprintf(stderr, "%c (%3d)", prep_string[i], prep_string[i]);
  720.                 if (i % 8 == 0) fprintf(stderr, "\n");
  721.             }
  722. #endif
  723.  
  724.         }
  725.  
  726.     } while (rc == 0 && BytesRead > 0L);
  727.  
  728. } /* end of transfer_data */
  729.  
  730. /*
  731.  * build_batchfile
  732.  *
  733.  * Build the batch file that the Dos session will execute
  734.  *
  735.  */
  736. int build_batchfile(char *fname, char *errpname, char *cmd) {
  737.  
  738.     int    count;
  739.     FILE    *bfile;
  740.  
  741.     if (NULL == (bfile = fopen(fname, "w")))
  742.         return -1;
  743.  
  744.     fprintf(bfile, "@echo off\n");
  745.  
  746. #ifdef USING_4DOS
  747.     fprintf(bfile, "%s >& %s\n", cmd, Pname);
  748.     fprintf(bfile, "echo %%? > %s\n", errpname);
  749. #else
  750.     fprintf(bfile, "%s > %s\n", cmd, Pname);
  751.     fprintf(bfile, "echo 0 > %s\n", errpname);
  752. #endif
  753.  
  754.     fclose(bfile);
  755.  
  756.     return 0;
  757. }
  758.     
  759.  
  760. /*
  761.  * read_errpipe
  762.  *
  763.  * Read the pipe that should contain the return code from the spawned program.
  764.  *
  765.  */
  766. void read_errpipe(ULONG targ) {
  767.  
  768.     APIRET    rc = 0;
  769.     ULONG    bytesread;
  770.     int    i;
  771.  
  772.     rc = DosConnectNPipe(Rcdpipe);
  773.  
  774. #ifdef DEBUG_EMX
  775.     if (rc != 0) {
  776.         fprintf(stderr, "%s: DosConnectNPipe for Rcdpipe failed (%ld)\n", Exename, rc);
  777.         exit(-1);
  778.     }
  779. #endif
  780.     /* "Prep" the string and the return code. */
  781.     RCstring[0] = 0;
  782.  
  783.     do {
  784.  
  785.         rc = DosRead(Rcdpipe,                /* Read from the pipe */
  786.                     RCstring,                /* Into prep_string   */
  787.                     BUFSIZE - 1,            /* A maximum of BUFSIZE - 1 bytes */
  788.                     &bytesread);            /* Total bytes read goes here */
  789.  
  790. /*        if (rc !=0) fprintf(stderr, "%s: Return code pipe DosRead failed (%ld)\n", Exename, rc);*/
  791.  
  792.         /* DosRead is supposed to return 0 in BytesRead when it reaches EOF */
  793.         if (bytesread > 0L) {
  794.             RCstring[(int)bytesread] = 0;            /* Stick a null at the end of the string */
  795.         }
  796. /* Debugging code
  797.             for (i = 0; i < strlen(RCstring); i++) {
  798.                    fprintf(stderr, "%c (%3d)", RCstring[i], RCstring[i]);
  799.                 if (i % 8 == 0) fprintf(stderr, "\n");
  800.             }
  801. */
  802.     } while (rc == 0 && bytesread > 0L);
  803.  
  804. #ifdef DEBUG_EMX
  805.     _endthread();
  806. #else
  807.     DosExit(0, 0); /* Exit this thread */
  808. #endif
  809.  
  810. } /* end of read_errpipe */
  811.