home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / os2 / os2misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  13.4 KB  |  514 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * os2misc.c
  21.  *
  22.  */
  23. #include "primpl.h"
  24.  
  25. PR_IMPLEMENT(char *)
  26. _PR_MD_GET_ENV(const char *name)
  27. {
  28.     return getenv(name);
  29. }
  30.  
  31. PR_IMPLEMENT(PRIntn)
  32. _PR_MD_PUT_ENV(const char *name)
  33. {
  34.     return putenv(name);
  35. }
  36.  
  37.  
  38. /*
  39.  **************************************************************************
  40.  **************************************************************************
  41.  **
  42.  **     Date and time routines
  43.  **
  44.  **************************************************************************
  45.  **************************************************************************
  46.  */
  47.  
  48. #include <sys/timeb.h>
  49. /*
  50.  *-----------------------------------------------------------------------
  51.  *
  52.  * PR_Now --
  53.  *
  54.  *     Returns the current time in microseconds since the epoch.
  55.  *     The epoch is midnight January 1, 1970 GMT.
  56.  *     The implementation is machine dependent.  This is the
  57.  *     implementation for OS/2.
  58.  *     Cf. time_t time(time_t *tp)
  59.  *
  60.  *-----------------------------------------------------------------------
  61.  */
  62.  
  63. PR_IMPLEMENT(PRTime)
  64. PR_Now(void)
  65. {
  66.     PRInt64 s, ms, ms2us, s2us;
  67.     struct timeb b;
  68.  
  69.     ftime(&b);
  70.     LL_I2L(ms2us, PR_USEC_PER_MSEC);
  71.     LL_I2L(s2us, PR_USEC_PER_SEC);
  72.     LL_I2L(s, b.time);
  73.     LL_I2L(ms, b.millitm);
  74.     LL_MUL(ms, ms, ms2us);
  75.     LL_MUL(s, s, s2us);
  76.     LL_ADD(s, s, ms);
  77.     return s;       
  78. }
  79.  
  80.  
  81. /*
  82.  ***********************************************************************
  83.  ***********************************************************************
  84.  *
  85.  * Process creation routines
  86.  *
  87.  ***********************************************************************
  88.  ***********************************************************************
  89.  */
  90.  
  91. /*
  92.  * Assemble the command line by concatenating the argv array.
  93.  * On success, this function returns 0 and the resulting command
  94.  * line is returned in *cmdLine.  On failure, it returns -1.
  95.  */
  96. static int assembleCmdLine(char *const *argv, char **cmdLine)
  97. {
  98.     char *const *arg;
  99.     char *p, *q;
  100.     int cmdLineSize;
  101.     int numBackslashes;
  102.     int i;
  103.     int argNeedQuotes;
  104.  
  105.     /*
  106.      * Find out how large the command line buffer should be.
  107.      */
  108.     cmdLineSize = 0;
  109.     for (arg = argv; *arg; arg++) {
  110.         /*
  111.          * \ and " need to be escaped by a \.  In the worst case,
  112.          * every character is a \ or ", so the string of length
  113.          * may double.  If we quote an argument, that needs two ".
  114.          * Finally, we need a space between arguments, a null between
  115.          * the EXE name and the arguments, and 2 nulls at the end 
  116.          * of command line.
  117.          */
  118.         cmdLineSize += 2 * strlen(*arg)  /* \ and " need to be escaped */
  119.                 + 2                      /* we quote every argument */
  120.                 + 4;                     /* space in between, or final nulls */
  121.     }
  122.     p = *cmdLine = PR_MALLOC(cmdLineSize);
  123.     if (p == NULL) {
  124.         return -1;
  125.     }
  126.  
  127.     for (arg = argv; *arg; arg++) {
  128.         /* Add a space to separates the arguments */
  129.         if (arg > argv + 1) {
  130.             *p++ = ' '; 
  131.         }
  132.         q = *arg;
  133.         numBackslashes = 0;
  134.         argNeedQuotes = 0;
  135.  
  136.         /* If the argument contains white space, it needs to be quoted. */
  137.         if (strpbrk(*arg, " \f\n\r\t\v")) {
  138.             argNeedQuotes = 1;
  139.         }
  140.  
  141.         if (argNeedQuotes) {
  142.             *p++ = '"';
  143.         }
  144.         while (*q) {
  145.             if (*q == '\\') {
  146.                 numBackslashes++;
  147.                 q++;
  148.             } else if (*q == '"') {
  149.                 if (numBackslashes) {
  150.                     /*
  151.                      * Double the backslashes since they are followed
  152.                      * by a quote
  153.                      */
  154.                     for (i = 0; i < 2 * numBackslashes; i++) {
  155.                         *p++ = '\\';
  156.                     }
  157.                     numBackslashes = 0;
  158.                 }
  159.                 /* To escape the quote */
  160.                 *p++ = '\\';
  161.                 *p++ = *q++;
  162.             } else {
  163.                 if (numBackslashes) {
  164.                     /*
  165.                      * Backslashes are not followed by a quote, so
  166.                      * don't need to double the backslashes.
  167.                      */
  168.                     for (i = 0; i < numBackslashes; i++) {
  169.                         *p++ = '\\';
  170.                     }
  171.                     numBackslashes = 0;
  172.                 }
  173.                 *p++ = *q++;
  174.             }
  175.         }
  176.  
  177.         /* Now we are at the end of this argument */
  178.         if (numBackslashes) {
  179.             /*
  180.              * Double the backslashes if we have a quote string
  181.              * delimiter at the end.
  182.              */
  183.             if (argNeedQuotes) {
  184.                 numBackslashes *= 2;
  185.             }
  186.             for (i = 0; i < numBackslashes; i++) {
  187.                 *p++ = '\\';
  188.             }
  189.         }
  190.         if (argNeedQuotes) {
  191.             *p++ = '"';
  192.         }
  193.         if(arg == argv)
  194.            *p++ = '\0';
  195.     } 
  196.  
  197.     /* Add 2 nulls at the end */
  198.     *p++ = '\0';
  199.     *p = '\0';
  200.     return 0;
  201. }
  202.  
  203. /*
  204.  * Assemble the environment block by concatenating the envp array
  205.  * (preserving the terminating null byte in each array element)
  206.  * and adding a null byte at the end.
  207.  *
  208.  * Returns 0 on success.  The resulting environment block is returned
  209.  * in *envBlock.  Note that if envp is NULL, a NULL pointer is returned
  210.  * in *envBlock.  Returns -1 on failure.
  211.  */
  212. static int assembleEnvBlock(char **envp, char **envBlock)
  213. {
  214.     char *p;
  215.     char *q;
  216.     char **env;
  217.     char *curEnv;
  218.     char *cwdStart, *cwdEnd;
  219.     int envBlockSize;
  220.  
  221.     PPIB ppib = NULL;
  222.     PTIB ptib = NULL;
  223.  
  224.     if (envp == NULL) {
  225.         *envBlock = NULL;
  226.         return 0;
  227.     }
  228.  
  229.     if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR)
  230.        return -1;
  231.  
  232.     curEnv = ppib->pib_pchenv;
  233.  
  234.     cwdStart = curEnv;
  235.     while (*cwdStart) {
  236.         if (cwdStart[0] == '=' && cwdStart[1] != '\0'
  237.                 && cwdStart[2] == ':' && cwdStart[3] == '=') {
  238.             break;
  239.         }
  240.         cwdStart += strlen(cwdStart) + 1;
  241.     }
  242.     cwdEnd = cwdStart;
  243.     if (*cwdEnd) {
  244.         cwdEnd += strlen(cwdEnd) + 1;
  245.         while (*cwdEnd) {
  246.             if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
  247.                     || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
  248.                 break;
  249.             }
  250.             cwdEnd += strlen(cwdEnd) + 1;
  251.         }
  252.     }
  253.     envBlockSize = cwdEnd - cwdStart;
  254.  
  255.     for (env = envp; *env; env++) {
  256.         envBlockSize += strlen(*env) + 1;
  257.     }
  258.     envBlockSize++;
  259.  
  260.     p = *envBlock = PR_MALLOC(envBlockSize);
  261.     if (p == NULL) {
  262.         return -1;
  263.     }
  264.  
  265.     q = cwdStart;
  266.     while (q < cwdEnd) {
  267.         *p++ = *q++;
  268.     }
  269.  
  270.     for (env = envp; *env; env++) {
  271.         q = *env;
  272.         while (*q) {
  273.             *p++ = *q++;
  274.         }
  275.         *p++ = '\0';
  276.     }
  277.     *p = '\0';
  278.     return 0;
  279. }
  280.  
  281. /*
  282.  * For qsort.  We sort (case-insensitive) the environment strings
  283.  * before generating the environment block.
  284.  */
  285. static int compare(const void *arg1, const void *arg2)
  286. {
  287.     return stricmp(* (char**)arg1, * (char**)arg2);
  288. }
  289. PRProcess * _PR_CreateOS2Process(
  290.     const char *path,
  291.     char *const *argv,
  292.     char *const *envp,
  293.     const PRProcessAttr *attr)
  294. {
  295.    char szFailed[CCHMAXPATH];
  296.    RESULTCODES procInfo;
  297.    APIRET retVal;
  298.    char *cmdLine = NULL;
  299.    char *envBlock = NULL;
  300.    char **newEnvp;
  301.    PRProcess *proc = NULL;
  302.    HFILE hStdIn  = 0,
  303.            hStdOut = 0, 
  304.            hStdErr = 0;
  305.  
  306.  
  307.    proc = PR_NEW(PRProcess);
  308.    if (!proc) {
  309.        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  310.        goto errorExit;
  311.    }
  312.  
  313.    if (assembleCmdLine(argv, &cmdLine) == -1) {
  314.        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  315.        goto errorExit;
  316.    }
  317.  
  318.    if (envp == NULL) {
  319.        newEnvp = NULL;
  320.    } else {
  321.        int i;
  322.        int numEnv = 0;
  323.        while (envp[numEnv]) {
  324.            numEnv++;
  325.        }
  326.        newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *));
  327.        for (i = 0; i <= numEnv; i++) {
  328.            newEnvp[i] = envp[i];
  329.        }
  330.        qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare);
  331.    }
  332.    if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
  333.        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  334.        goto errorExit;
  335.    }
  336.  
  337.    if (attr) {
  338.        PRBool redirected = PR_FALSE;
  339.  
  340.       /* On OS/2, there is really no way to pass file handles for stdin, stdout, 
  341.        * and stderr to a new process.  Instead, we can make it a child process       
  342.        * and make the given file handles a copy of our stdin, stdout, and stderr.
  343.        * The child process then inherits ours, and we set ours back.  Twisted
  344.        * and gross I know. If you know a better way, please use it.
  345.        */
  346.        if (attr->stdinFd) {
  347.             hStdIn = (HFILE) attr->stdinFd->secret->md.osfd;
  348.             DosDupHandle(0, &hStdIn);
  349.         }
  350.         if (attr->stdoutFd) {
  351.             hStdOut = (HFILE) attr->stdoutFd->secret->md.osfd;
  352.             DosDupHandle(1, &hStdOut);
  353.         }
  354.         if (attr->stderrFd) {
  355.             hStdErr = (HFILE) attr->stderrFd->secret->md.osfd;
  356.             DosDupHandle(2, &hStdErr);
  357.         }
  358.    }
  359.  
  360.    retVal = DosExecPgm(szFailed, 
  361.                        CCHMAXPATH, 
  362.                        EXEC_ASYNCRESULT, 
  363.                        cmdLine, 
  364.                        envBlock, 
  365.                        &procInfo,
  366.                        argv[0]);
  367.  
  368.    /* Restore our old values.  Hope this works */
  369.    if(hStdIn){
  370.       hStdIn = 0;
  371.       DosDupHandle(0, &hStdIn);      
  372.    }
  373.    if(hStdOut){
  374.       hStdOut = 1;
  375.       DosDupHandle(1, &hStdOut);      
  376.    }
  377.    if(hStdErr){
  378.       hStdErr = 1;
  379.       DosDupHandle(0, &hStdErr);      
  380.    }
  381.  
  382.    if (retVal != NO_ERROR) {
  383.        /* XXX what error code? */
  384.        PR_SetError(PR_UNKNOWN_ERROR, retVal);
  385.        goto errorExit;
  386.    }
  387.  
  388.    proc->md.pid = procInfo.codeTerminate;
  389.  
  390.    PR_DELETE(cmdLine);
  391.    if (envBlock) {
  392.        PR_DELETE(envBlock);
  393.    }
  394.    return proc;
  395.  
  396. errorExit:
  397.    if (cmdLine) {
  398.        PR_DELETE(cmdLine);
  399.    }
  400.    if (envBlock) {
  401.        PR_DELETE(envBlock);
  402.    }
  403.    if (proc) {
  404.        PR_DELETE(proc);
  405.    }
  406.    return NULL;
  407.     
  408. }  /* _PR_CreateWindowsProcess */
  409.  
  410. PRStatus _PR_DetachOS2Process(PRProcess *process)
  411. {
  412.     /* This is basically what they did on Windows (CloseHandle)
  413.      * but I don't think it will do much on OS/2. A process is
  414.      * either created as a child or not.  You can't 'detach' it
  415.      * later on.
  416.      */
  417.     DosClose(process->md.pid);
  418.     PR_DELETE(process);
  419.     return PR_SUCCESS;
  420. }
  421.  
  422. /*
  423.  * XXX: This will currently only work on a child process.
  424.  */
  425. PRStatus _PR_WaitOS2Process(PRProcess *process,
  426.     PRInt32 *exitCode)
  427. {
  428.     ULONG ulRetVal;
  429.     RESULTCODES results;
  430.     PID pidEnded = 0;
  431.  
  432.     ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, 
  433.                             &results,
  434.                             &pidEnded, process->md.pid);
  435.  
  436.     if (ulRetVal != NO_ERROR) {
  437.        printf("\nDosWaitChild rc = %i\n", ulRetVal);
  438.         PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
  439.         return PR_FAILURE;
  440.     }
  441.     PR_DELETE(process);
  442.     return PR_SUCCESS;
  443. }
  444.  
  445. PRStatus _PR_KillOS2Process(PRProcess *process)
  446. {
  447.    ULONG ulRetVal;
  448.     if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) {
  449.     return PR_SUCCESS;
  450.     }
  451.     PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
  452.     return PR_FAILURE;
  453. }
  454.  
  455. PR_IMPLEMENT(PRStatus) _MD_OS2GetHostName(char *name, PRUint32 namelen)
  456. {
  457.     PRIntn rv;
  458.     PRInt32 syserror;
  459.  
  460.     rv = gethostname(name, (PRInt32) namelen);
  461.     if (0 == rv) {
  462.         return PR_SUCCESS;
  463.     }
  464.     _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno());
  465.     return PR_FAILURE;
  466. }
  467.  
  468. PR_IMPLEMENT(void)
  469. _PR_MD_WAKEUP_CPUS( void )
  470. {
  471.     return;
  472. }    
  473.  
  474.  
  475. /*
  476.  **********************************************************************
  477.  *
  478.  * Memory-mapped files are not supported on OS/2 (or Win16).
  479.  *
  480.  **********************************************************************
  481.  */
  482.  
  483. PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
  484. {
  485.     PR_ASSERT(!"Not implemented");
  486.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  487.     return PR_FAILURE;
  488. }
  489.  
  490. void * _MD_MemMap(
  491.     PRFileMap *fmap,
  492.     PRInt64 offset,
  493.     PRUint32 len)
  494. {
  495.     PR_ASSERT(!"Not implemented");
  496.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  497.     return NULL;
  498. }
  499.  
  500. PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
  501. {
  502.     PR_ASSERT(!"Not implemented");
  503.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  504.     return PR_FAILURE;
  505. }
  506.  
  507. PRStatus _MD_CloseFileMap(PRFileMap *fmap)
  508. {
  509.     PR_ASSERT(!"Not implemented");
  510.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  511.     return PR_FAILURE;
  512. }
  513.  
  514.