home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / ntcode / gnugrep / setargv.c < prev   
Encoding:
C/C++ Source or Header  |  1995-05-19  |  32.1 KB  |  1,331 lines

  1. /*
  2.  *    setargv.c - parse arguments
  3.  *
  4.  *    $Header: C:/SRC/RCS/setargv.c 1.11 1994/01/25 23:20:37 few Exp $
  5.  *
  6.  *    This code evolved out of a requirement for expansion of wildcard
  7.  *    arguments given on the command line.  None of the (currently)
  8.  *    available wildcard matchers did the job for me.  I want my "argv"
  9.  *    to arrive correctly expanded.  I also use several different compilers 
  10.  *    and operating systems.  This requires some intricate gyrations, as 
  11.  *    you can discover below.
  12.  *
  13.  *    This version can expand wildcard arguments either by globbing or 
  14.  *    by using system facilities.  Expanded filename arguments are usually 
  15.  *    converted to lower case, although this can be overridden.  Arguments 
  16.  *    that are quoted (with either " or ') are left alone, but the quote 
  17.  *    characters are stripped.
  18.  *    #ifdef UNIXBS
  19.  *     Any single character may be escaped with a backslash (\).
  20.  *    #else
  21.  *     Quote characters may be escaped with a backslash (\).
  22.  *    #endif
  23.  *
  24.  *    "@name" processing is also handled by this package.  In order to
  25.  *    overcome the 126 byte command line limitation of MS-DOS, several
  26.  *    tool makers have agreed to pass lengthy command lines either in
  27.  *    an environment variable or a temporary file.  This mechanism comes
  28.  *    to play only if the first non-blank character of a command line
  29.  *    is '@'.  First the environment is searched for a tag matching
  30.  *    "name", otherwise "name" is assumed to be the name of a temporary
  31.  *    file containing the command line.  This code extends the "@file"
  32.  *    mechanism by reading up to 'MAXLINE' bytes from a file, where
  33.  *    individual arguments may be separated by any whitespace character
  34.  *    (including newlines).
  35.  *
  36.  *    MKS-style extended arguments which are passed in the environment
  37.  *    are also interpreted.  If MKS-style arguments are selected, this
  38.  *    module also provides _setenvp() which ensures that these arguments
  39.  *    are stripped from the environment.  Several tools (make programs,
  40.  *    shells, etc.) pass lengthy arguments via the MKS method, but do
  41.  *    not perform wildcard expansion.  There is a problem in combining 
  42.  *    tools that expect MKS-style arguments to be already expanded with 
  43.  *    tools that don't expect expansion -- it's hard to tell what you 
  44.  *    really meant.  In this case, nested quoting ("'arg'") may be 
  45.  *    required to get wildcard arguments into your program.
  46.  *
  47.  *    Finally (I think), 4DOS stores command lines in the environment
  48.  *    variable CMDLINE.
  49.  *
  50.  *    Even though OS/2 allows lengthy command lines, the three methods
  51.  *    of passing long command lines are included in the OS/2 version,
  52.  *    for use in "compatibility mode" programs.
  53.  *
  54.  *    The Windows/NT version uses an undocumented external variable 
  55.  *    and may be incomplete.  It works for me.
  56.  *
  57.  *    In all cases the "correct" command line is retrieved before any
  58.  *    filename expansion is performed.  This allows all calling programs
  59.  *    (shells, make, etc.) to pass a simple version of the command line.
  60.  *
  61.  *    Seven flags select the compiler and operating system:
  62.  *        __TURBOC__    Turbo-C 2.0
  63.  *        __TURBOCCC__    Turbo-C++ 1.0
  64.  *        __BORLANDC__    Borland C++ 2.0/3.x
  65.  *        __MSC__        Microsoft C 5.10, 7.0 or 8.0 (not 6.00)
  66.  *        __MSDOS__    MS-DOS 3.x/4.x/5.x/6.x
  67.  *        __OS2__        OS/2 1.2/1.3/2.0
  68.  *        __NT__        Windows/NT
  69.  *    Note that when using Turbo C, Turbo C++, or Borland C++, the flags
  70.  *    __TURBOC__, __TURBOCCC__, __BORLANDC__, and __MSDOS__ are set
  71.  *    automatically.
  72.  *
  73.  *    Ten additional conditional-compilation flags are provided:
  74.  *        ATARGS:        Handle extended arguments passed by the
  75.  *                "@name" protocol.
  76.  *        CMDLINE:    Handle 4DOS-style arguments passed in the
  77.  *                "CMDLINE" environment variable.
  78.  *        FIXARG0:    Convert argv[0] to lower case and switch
  79.  *                all backslashes to slashes (cosmetic).
  80.  *        GLOB:        Use filename globbing instead of standard
  81.  *                system wildcard matching.
  82.  *        LCFAT:        Force FAT filenames to lowercase under 
  83.  *                Windows NT, when UPPERCASE is also defined.
  84.  *        MATCHCASE:    Only match globbed arguments when their
  85.  *                character case matches exactly.
  86.  *        MKSARGS:    Look for MKS-style extended arguments
  87.  *                passed in the environment.
  88.  *        SORTARGS:    Use qsort() to sort the expansions of
  89.  *                each argument.
  90.  *        UNIXBS        Treat backslashes in the Unix fashion (as
  91.  *                a single-character escape) rather than as
  92.  *                directory separator characters.
  93.  *        UPPERCASE:    Leave matched arguments as uppercase, instead
  94.  *                of converting to lowercase.
  95.  *
  96.  *    A test program is provided at the end of this file, and is built
  97.  *    if 'TEST' is defined.  A few possibilities:
  98.  *     tcc -DTEST -DFIXARG0 -DGLOB -DSORTARGS setargv.c
  99.  *     cl -D__MSC__ -D__MSDOS__ -DTEST -DMKSARGS setargv.c -link /NOE/ST:8192
  100.  *     cl -D__MSC__ -D__OS2__ -G2 -DTEST -DGLOB -DSORTARGS setargv.c \ 
  101.  *                                -link /NOE/ST:8192
  102.  *     cl -D__MSC__ -D__NT__ -DTEST -DFIXARG0 -DGLOB -DUPPERCASE -DLCFAT \
  103.  *                            -DSORTARGS setargv.c
  104.  *    or, since VC++ broke the '-link' option:
  105.  *     cl -D__MSDOS__ -D__MSC__ -DTEST -DATARGS -DFIXARG0 -DGLOB -DMKSARGS \ 
  106.  *                    -DSORTARGS -F 2000/NOE -c setargv.c
  107.  *
  108.  *    Note that this code requires just under 6K of stack space (along with
  109.  *    a substantial amount of allocated memory), which exceeds the default
  110.  *    of 4K built into most runtime code.
  111.  *
  112.  *    Notes on using Microsoft C 6.00:
  113.  *        In version 6.00 of Microsoft's C compiler, the memory
  114.  *        allocation initialization was changed to occur sometime
  115.  *        after _setargv() is called.  This causes a situation where
  116.  *        (sometimes) the first malloc() call made by this code
  117.  *        enters an infinite loop.  I have only seen this problem on
  118.  *        MS-DOS; OS/2 memory allocation initialization seems to be
  119.  *        handled differently.  The problem does not seem to occur
  120.  *        with MSC 7.0 or 8.0.
  121.  *
  122.  *    Notes on 4DOS-style 'CMDLINE=' arguments:
  123.  *        This code does not remove the 'CMDLINE=...' string from the
  124.  *        environment.  If a program using this module calls another
  125.  *        program that recognizes 'CMDLINE=', it is possible for the
  126.  *        child program to receive the original program's command line
  127.  *        (if the caller's environment is passed unchanged).  The
  128.  *        'CMDLINE=...' string can be removed by a
  129.  *            putenv("CMDLINE=");
  130.  *        statement in your program.
  131.  *
  132.  *    Further enhancements greatly appreciated.
  133.  *
  134.  *    This code placed in the public domain on 25-Jan-94 by the original 
  135.  *    author, Frank Whaley (few@autodesk.com).
  136.  *
  137.  *    The author would like to thank W. Metzenthen of Monash University
  138.  *    in Australia (apm233m@vaxc.cc.monash.edu.au) for his considerable
  139.  *    assistance in producing the Turbo-C++ 1.0 modifications.  I have
  140.  *    paraphrased his notes below.
  141.  *    ----------
  142.  *    Turbo C++ uses a different mechanism for its startup code.  Instead
  143.  *    of a built-in call to _setargv(), it links in much of its startup
  144.  *    code only if needed.  For example, if a program does not reference
  145.  *    _argv or _argc, and main() is declared with no formal parameters, then
  146.  *    the setargv code will not be linked in.
  147.  *
  148.  *    If a program does reference _argv or _argc, then the appropriate code
  149.  *    is linked automatically.
  150.  *
  151.  *    If main() is declared with formal parameters then the object code
  152.  *    produced by tcc (or tc) will include a reference to __setargv__.
  153.  *    In this case we need to rename _setargv() to _setargv__().
  154.  *
  155.  *    In addition, it is necessary to have a short block of data placed
  156.  *    in a data segment named INITDATA in the group INIT in order for the
  157.  *    startup code to function correctly.  This is handled by resorting to
  158.  *    in-line assembly code.
  159.  *
  160.  *    Similarly, if MKSARGS is used, _setenvp__() must be defined instead
  161.  *    of _setenvp().
  162.  */
  163.  
  164. #define CHUNK    128    /*  pointer allocation chunksize  */
  165. #define MAXLINE    4096    /*  max unexpanded command line length  */
  166.  
  167. #include <stdio.h>
  168. #include <stdlib.h>
  169. #include <string.h>
  170. #include <ctype.h>
  171. #include <io.h>
  172.  
  173. #ifdef __TURBOC__
  174.     /*  TC++, BC++  */
  175. /*  Normally the following test would be '#if __TURBOC__ >= 0x0200', however
  176.  *  I have applied an allegedly "official" Borland patch to TCC.EXE which
  177.  *  causes __TURBOC__ to be defined as 0x0200.  Now I can't think of a test
  178.  *  that will tell me if I'm using TC++.
  179.  */
  180. #if WORKING_TURBO_CPLUSPLUS_TEST || defined(__BORLANDC__)
  181. #pragma inline
  182. #define __TURBOCCC__
  183. #define _setargv        _setargv__
  184. #define _setenvp        _setenvp__
  185. #define ARGC            _C0argc
  186. #define ARGV            _C0argv
  187. #ifdef MKSARGS
  188. char **environ;
  189. #endif /*MKSARGS*/
  190. extern char **_C0environ;
  191. #else /*__TURBOCCC__*/
  192. #define ARGC            _argc
  193. #define ARGV            _argv
  194. #endif /*__TURBOCCC__*/
  195.  
  196. #include <alloc.h>
  197. #include <dir.h>
  198. #include <dos.h>
  199. #include <mem.h>
  200. typedef struct ffblk FIND_T;
  201. #define findclose(f)
  202. #define FAR            __far
  203. #endif /*__TURBOC__*/
  204.  
  205. #if defined(__MSC__) && defined(__MSDOS__)
  206. #include <dos.h>
  207. #include <malloc.h>
  208. #include <memory.h>
  209. #define ARGC            __argc
  210. #define ARGV            __argv
  211. #ifndef MK_FP
  212. #define MK_FP(seg,ofs)        ((void __far *)(((unsigned long)(seg)<<16)|\
  213.                             (unsigned)(ofs)))
  214. #endif
  215. typedef struct find_t FIND_T;
  216. #define findfirst(n,f,a)    _dos_findfirst(n,a,f)
  217. #define findnext(f)        _dos_findnext(f)
  218. #define findclose(f)
  219. #define ff_name            name
  220. #define ff_attrib        attrib
  221. #define FA_RDONLY        _A_RDONLY
  222. #define FA_HIDDEN        _A_HIDDEN
  223. #define FA_SYSTEM        _A_SYSTEM
  224. #define FA_DIREC        _A_SUBDIR
  225. #define FAR            __far
  226. #endif /*__MSC__&&__MSDOS__*/
  227.  
  228. #if defined(__MSC__) && defined(__OS2__)
  229. #define INCL_DOS
  230. #include <os2.h>
  231. #include <malloc.h>
  232. #include <memory.h>
  233. #define ARGC            __argc
  234. #define ARGV            __argv
  235. typedef struct
  236. {
  237.     HDIR ft_handle;
  238.     FILEFINDBUF ft_ffb;
  239.     int ft_count;
  240. } FIND_T;
  241. #define findfirst(n,f,a)    ((f)->ft_handle=0xFFFF,(f)->ft_count=1,\
  242.                     DosFindFirst(n,&(f)->ft_handle,a,\
  243.                     &(f)->ft_ffb,sizeof((f)->ft_ffb),\
  244.                     &(f)->ft_count,0L))
  245. #define findnext(f)        DosFindNext((f)->ft_handle,&(f)->ft_ffb,\
  246.                     sizeof((f)->ft_ffb),&(f)->ft_count)
  247. #define findclose(f)        DosFindClose((f)->ft_handle);
  248. #define ff_attrib        ft_ffb.attrFile
  249. #define ff_name            ft_ffb.achName
  250. #define FA_RDONLY        0x01
  251. #define FA_HIDDEN        0x02
  252. #define FA_SYSTEM        0x04
  253. #define FA_DIREC        0x10
  254. #define FAR            __far
  255. #endif /*__MSC__&&__OS2__*/
  256.  
  257.     /*  MSC and NT  */
  258. #if defined(__MSC__) && defined(__NT__)
  259. #include <windows.h>
  260. #include <direct.h>
  261. #include <io.h>
  262. #define ARGC            __argc
  263. #define ARGV            __argv
  264. extern char *_acmdln;
  265. typedef struct
  266. {
  267.     HANDLE ft_hdl;
  268.     WIN32_FIND_DATA ft_ffb;
  269. } FIND_T;
  270. #define findfirst(n,f,a)    (((f)->ft_hdl=FindFirstFile(n,&(f)->ft_ffb))\
  271.                     ==INVALID_HANDLE_VALUE)
  272. #define findnext(f)        !FindNextFile((f)->ft_hdl,&(f)->ft_ffb)
  273. #define findclose(f)        FindClose((f)->ft_hdl)
  274. #define ff_attrib        ft_ffb.dwFileAttributes
  275. #define ff_name            ft_ffb.cFileName
  276. #define FA_RDONLY        FILE_ATTRIBUTE_READONLY
  277. #define FA_HIDDEN        FILE_ATTRIBUTE_HIDDEN
  278. #define FA_SYSTEM        FILE_ATTRIBUTE_SYSTEM
  279. #define FA_DIREC        FILE_ATTRIBUTE_DIRECTORY
  280. #define strdup            _strdup
  281. #define strlwr            _strlwr
  282. #define write            _write
  283. #endif /*__MSC__&&__NT__*/
  284.  
  285.     /*  mask for all interesting files  */
  286. #define ALL        (FA_RDONLY+FA_HIDDEN+FA_SYSTEM+FA_DIREC)
  287.  
  288.     /*  let's do some things with macros...  */
  289. #ifdef MATCHCASE
  290. #define CHARMATCH(a,b)    ((a)==(b))
  291. #else /*MATCHCASE*/
  292. #define CHARMATCH(a,b)    (lowercase(a)==lowercase(b))
  293. #endif /*MATCHCASE*/
  294. #ifdef UPPERCASE
  295. #define CONCAT        strcat
  296. #else /*UPPERCASE*/
  297. #define CONCAT        lwrcat
  298. #endif /*UPPERCASE*/
  299. #define ISBLANK(c)    (((c)==' ')||((c)=='\t')||((c)=='\r')||((c)=='\n'))
  300. #define ISQUOTE(c)    (((c)=='"')||((c)=='\''))
  301. #ifdef GLOB
  302. #define ISWILD(c)    (((c)=='?')||((c)=='*')||((c)=='['))
  303. #else /*GLOB*/
  304. #define ISWILD(c)    (((c)=='?')||((c)=='*'))
  305. #endif /*GLOB*/
  306.  
  307. static char *cmdLine;        /*  -> local copy of command line  */
  308. static char dirSep[] = "/";    /*  current directory separator  */
  309. static int maxArgs;        /*  current max arg count  */
  310.  
  311.     /*  error messages  */
  312. static char memFail[] = "Memory shortage\n";
  313.  
  314. extern int ARGC;        /*  number of args  */
  315. extern char **ARGV;        /*  arg ptrs  */
  316.  
  317.     /*  forward declarations  */
  318. #if defined(ATARGS) || defined(CMDLINE)
  319. static char FAR *pickEnvVar(const char *name);
  320. #endif /*ATARGS||CMDLINE*/
  321. #ifdef FIXARG0
  322. static char lowercase(char c);
  323. #endif /*FIXARG0*/
  324. #ifdef GLOB
  325. static char **fileGlob(char *pattern);
  326. #endif /*GLOB*/
  327. static int hasWildcard(void);
  328. static void pickRegular(void);
  329. static void pickWild(void);
  330. static void *xMalloc(size_t size);
  331. static void *xRealloc(void *block, size_t size);
  332. static char *xStrdup(char *s);
  333.  
  334.  
  335. /*
  336. -*    _setargv - set argument vector
  337.  */
  338. #ifdef __TURBOCCC__
  339.     void FAR
  340. #else /*__TURBOCCC__*/
  341.     void
  342. #endif /*__TURBOCCC__*/
  343. _setargv(void)
  344. {
  345.     char buf[MAXLINE];    /*  working buffer  */
  346.     char FAR *farPtr;    /*  generic far ptr  */
  347.     int len;        /*  command line length  */
  348. #ifdef MKSARGS
  349.     char FAR *mksPtr;    /*  ptr to MKS-style arguments  */
  350. #endif /*MKSARGS*/
  351. #ifdef __OS2__
  352.     USHORT selEnviron;    /*  environment segment selector  */
  353.     USHORT usOffsetCmd;    /*  offset to command line  */
  354. #endif /*__OS2__*/
  355.  
  356.     /*  get working vector  */
  357.     ARGV = xMalloc(CHUNK * sizeof(char *));
  358.     maxArgs = CHUNK;
  359.  
  360.     /*  get program name  */    
  361. #ifdef __NT__
  362.     cmdLine = buf;
  363.     farPtr = _acmdln;
  364.     while ( *farPtr && !ISBLANK(*farPtr) )
  365.     {
  366. #ifdef FIXARG0
  367.         *cmdLine = lowercase(*farPtr++);
  368.         if ( *cmdLine == '\\' )
  369.             *cmdLine = '/';
  370.         cmdLine++;
  371. #else /*FIXARG0*/
  372.         *cmdLine++ = *farPtr++;
  373. #endif /*FIXARG0*/
  374.     }
  375. #else /*__NT__*/
  376.     /*  copy program name from environment  */
  377.     cmdLine = buf;
  378. #ifdef __OS2__
  379.     DosGetEnv(&selEnviron, &usOffsetCmd);
  380.     farPtr = MAKEP(selEnviron, usOffsetCmd);
  381. #endif /*__OS2__*/
  382. #ifdef __MSDOS__
  383.     farPtr = MK_FP(*(int FAR *)MK_FP(_psp, 0x2c), 0);
  384.     while ( *farPtr )
  385.         if ( !*++farPtr )
  386.             farPtr++;
  387.     farPtr += 3;
  388. #endif /*__MSDOS__*/
  389.  
  390.     while ( *farPtr )
  391.     {
  392. #ifdef FIXARG0
  393.         *cmdLine = lowercase(*farPtr++);
  394.         if ( *cmdLine == '\\' )
  395.             *cmdLine = '/';
  396.         cmdLine++;
  397. #else /*FIXARG0*/
  398.         *cmdLine++ = *farPtr++;
  399. #endif /*FIXARG0*/
  400.     }
  401. #endif /*__NT__*/
  402.     *cmdLine = '\0';
  403.     ARGV[0] = xStrdup(buf);
  404.  
  405. #ifdef MKSARGS
  406.     /*  get MKS-style arguments if there  */
  407. #ifdef __NT__
  408.     mksPtr = (char *)GetEnvironmentStrings();
  409. #endif /*__NT__*/
  410. #ifdef __OS2__
  411.     mksPtr = MAKEP(selEnviron, 0);
  412. #endif /*__OS2__*/
  413. #ifdef __MSDOS__
  414.     mksPtr = MK_FP(*(int FAR *)MK_FP(_psp, 0x2c), 0);
  415. #endif /*__MSDOS__*/
  416.  
  417.     if ( *mksPtr == '~' )
  418.     {
  419.         /*  skip over argv[0]  */
  420.         while ( *mksPtr++ )
  421.             ;
  422.         cmdLine = buf;
  423.         while ( *mksPtr == '~' )
  424.         {
  425.             mksPtr++;
  426.             while ( *mksPtr )
  427.                 *cmdLine++ = *mksPtr++;
  428.             if ( *++mksPtr == '~' )
  429.                 *cmdLine++ = ' ';
  430.         }
  431.         *cmdLine = '\0';
  432.     }
  433.     else
  434. #endif /*MKSARGS*/
  435.     {
  436.         /*  copy cmd line from PSP  */
  437.         cmdLine = buf;
  438. #if defined(__OS2__) || defined(__NT__)
  439.         farPtr++;
  440.         /*  remove leading blanks  */
  441.         while ( ISBLANK(*farPtr) )
  442.             farPtr++;
  443.         /*  copy  */
  444.         while ( *cmdLine++ = *farPtr++ )
  445.             ;
  446. #else /*__OS2__*/
  447.         farPtr = MK_FP(_psp, 0x80);
  448.         len = *farPtr++;
  449.         /*  remove leading blanks  */
  450.         while ( len && ISBLANK(*farPtr) )
  451.         {
  452.             farPtr++;
  453.             len--;
  454.         }
  455.         /*  copy  */
  456.         while ( len )
  457.         {
  458.             *cmdLine++ = *farPtr++;
  459.             len--;
  460.         }
  461.         *cmdLine = 0;
  462. #endif /*__OS2__*/
  463.  
  464. #ifdef ATARGS
  465.         /*  handle "@name"  */
  466.         if ( buf[0] == '@' )
  467.         {
  468.             FILE *fp;
  469.  
  470.             /*  try environment first  */
  471.             if ( (farPtr = pickEnvVar(buf + 1)) != NULL )
  472.             {
  473.                 for ( cmdLine = buf;
  474.                       (*cmdLine++ = *farPtr++) != '\0'; )
  475.                     ;
  476.             }
  477.             else
  478.             {
  479.                 /*  open '@' file  */
  480.                 if ( (fp = fopen(buf + 1, "rt")) != (FILE *)0 )
  481.                 {
  482.                     int length;
  483.                     /*  load the buffer  */
  484.                     length = fread(buf, sizeof(*buf),
  485.                             sizeof(buf) - 1, fp);
  486.                     buf[length] = '\0';
  487.                     /*  close up  */
  488.                     fclose(fp);
  489.                 }
  490.             }
  491.         }
  492. #endif /*ATARGS*/
  493.  
  494. #ifdef CMDLINE
  495.         if ( (farPtr = pickEnvVar("CMDLINE")) != NULL )
  496.         {
  497.             /*  skip over program name  */
  498.             while ( *farPtr && !ISBLANK(*farPtr) )
  499.                 farPtr++;
  500.             for ( cmdLine = buf;
  501.                   (*cmdLine++ = *farPtr++) != '\0'; )
  502.                 ;
  503.         }
  504. #endif /*CMDLINE*/
  505.     }
  506.  
  507.     /*  let's get down to some expansion  */
  508.     ARGC = 1;
  509.     cmdLine = buf;
  510.     while ( *cmdLine )
  511.     {
  512.         /*  deblank  */
  513.         while ( ISBLANK(*cmdLine) )
  514.             cmdLine++;
  515.  
  516.         /*  pick next argument  */
  517.         while ( *cmdLine )
  518.         {
  519.             if ( hasWildcard() )
  520.                 pickWild();
  521.             else
  522.                 pickRegular();
  523.  
  524.             /*  deblank  */
  525.             while ( ISBLANK(*cmdLine) )
  526.                 cmdLine++;
  527.         }
  528.     }
  529. /*
  530.  *  This final realloc() should be done to save a bit of memory (the
  531.  *  end of the last block allocated to ARGV.  However, both TC's and
  532.  *  MSC's realloc() functions sometimes break here.  So we waste a
  533.  *  few bytes...
  534.  */
  535. #if 0
  536.     /*  shrink vector -- this might be overkill  */
  537.     ARGV = (char **)xRealloc(ARGV, ARGC * sizeof(char *));
  538. #endif
  539. }
  540.  
  541. #ifdef __TURBOCCC__
  542. asm    _INIT_    Segment Word Public 'INITDATA'
  543. asm        DB    1
  544. asm        DB    16
  545. asm        DD    __setargv__
  546. asm    _INIT_    EndS
  547. #endif /*__TURBOCCC__*/
  548.  
  549. /*
  550.  *    does current argument contain a globbing char ??
  551.  */
  552.     static int
  553. hasWildcard(void)
  554. {
  555.     char *s = cmdLine;    /*  work ptr  */
  556.     char quote;    /*  current quote char  */
  557.  
  558.     while ( *s && !ISBLANK(*s) )
  559.     {
  560.         /*  skip over quoted sections  */
  561.         if ( ISQUOTE(*s) )
  562.         {
  563.             quote = *s++;
  564.             while ( *s && (*s != quote) )
  565.             {
  566. #ifdef UNIXBS
  567.                 if ( *s == '\\' )
  568.                     s++;
  569. #else /*UNIXBS*/
  570.                 if ( (*s == '\\') && (*(s + 1) == quote) )
  571.                     s++;
  572. #endif /*UNIXBS*/
  573.                 s++;
  574.             }
  575.         }
  576.         else if ( ISWILD(*s) )
  577.             return ( 1 );
  578. #ifdef UNIXBS
  579.         else if ( *s == '\\' )
  580.             s++;
  581. #else /*UNIXBS*/
  582.         else if ( (*s == '\\') && ISQUOTE(*(s + 1)) )
  583.             s++;
  584. #endif /*UNIXBS*/
  585.         s++;
  586.     }
  587.  
  588.     return ( 0 );
  589. }
  590.  
  591. /*
  592.  *    allocate memory with test
  593.  */
  594.     static void *
  595. xMalloc(size_t size)
  596. {
  597.     void *mem;
  598.  
  599.     if ( (mem = malloc(size)) == NULL )
  600.     {
  601.         write(2, memFail, sizeof(memFail));
  602.         abort();
  603.     }
  604.  
  605.     return ( mem );
  606. }
  607.  
  608. /*
  609.  *    re-allocate memory with test
  610.  */
  611.     static void *
  612. xRealloc(void *block, size_t size)
  613. {
  614.     void *mem;
  615.  
  616.     if ( (mem = realloc(block, size)) == NULL )
  617.     {
  618.         write(2, memFail, sizeof(memFail));
  619.         abort();
  620.     }
  621.  
  622.     return ( mem );
  623. }
  624.  
  625. /*
  626.  *    dup string with test
  627.  */
  628.     static char *
  629. xStrdup(char *s)
  630. {
  631.     char *t;
  632.  
  633.     if ( (t = strdup(s)) == NULL )
  634.     {
  635.         write(2, memFail, sizeof(memFail));
  636.         abort();
  637.     }
  638.  
  639.     return ( t );
  640. }
  641.  
  642. /*
  643.  *    pick a regular argument from command line
  644.  */
  645.     static void
  646. pickRegular(void)
  647. {
  648.     char buf[128];    /*  argument buffer  */
  649.     char *bp = buf;    /*  work ptr  */
  650.     char quote;    /*  current quote char  */
  651.  
  652.     /*  copy argument (minus quotes) into local buffer  */
  653.     while ( *cmdLine && !ISBLANK(*cmdLine) )
  654.     {
  655.         if ( ISQUOTE(*cmdLine) )
  656.         {
  657.             quote = *cmdLine++;
  658.             while ( *cmdLine && (*cmdLine != quote) )
  659.             {
  660. #ifdef UNIXBS
  661.                 if ( *cmdLine == '\\' )
  662.                     cmdLine++;
  663. #else /*UNIXBS*/
  664.                 if ( (*cmdLine == '\\') &&
  665.                      (*(cmdLine + 1) == quote) )
  666.                     cmdLine++;
  667. #endif /*UNIXBS*/
  668.                 *bp++ = *cmdLine++;
  669.             }
  670.             if ( *cmdLine )
  671.                 cmdLine++;
  672.         }
  673.         else
  674.         {
  675. #ifdef UNIXBS
  676.             if ( *cmdLine == '\\' )
  677.                 cmdLine++;
  678. #else /*UNIXBS*/
  679.             if ( (*cmdLine == '\\') && ISQUOTE(*(cmdLine + 1)) )
  680.                 cmdLine++;
  681. #endif /*UNIXBS*/
  682.             *bp++ = *cmdLine++;
  683.         }
  684.     }
  685.     *bp = '\0';
  686.  
  687.     /*  skip over terminator char  */
  688.     if ( *cmdLine )
  689.         cmdLine++;
  690.  
  691.     /*  store ptr to copy of string  */
  692.     ARGV[ARGC++] = xStrdup(buf);
  693.     /*  reallocate vector if necessary  */
  694.     if ( ARGC >= maxArgs )
  695.     {
  696.         maxArgs += CHUNK;
  697.         ARGV = xRealloc(ARGV, maxArgs * sizeof(char *));
  698.     }
  699. }
  700.  
  701. /*
  702.  *    safe 'tolower' function
  703.  */
  704.     static char
  705. lowercase(char c)
  706. {
  707.     return ( (char)tolower(c) );
  708. }
  709.  
  710. #if !defined(UPPERCASE) && !defined(GLOB)
  711. /*
  712.  *    concatenate strings, convert to lower case
  713.  */
  714.     static char *
  715. lwrcat(char *s, char *t)
  716. {
  717.     char *cp = s;
  718.  
  719.     while ( *cp )
  720.         cp++;
  721.     while ( (*cp++ = lowercase(*t++)) != '\0' )
  722.         ;
  723.  
  724.     return ( s );
  725. }
  726. #endif /*!UPPERCASE&&!GLOB*/
  727.  
  728. #if defined(ATARGS) || defined(CMDLINE)
  729. /*
  730.  *    check for environment variable
  731.  */
  732.     static int
  733. envMatch(char FAR *ptr, const char *name)
  734. {
  735.     int len = strlen(name);
  736.  
  737.     while ( len-- )
  738.         if ( *ptr++ != *name++ )
  739.             return ( 0 );
  740.  
  741.     return ( 1 );
  742. }
  743. /*
  744.  *    find 'real' environment variable
  745.  */
  746.     static char FAR *
  747. pickEnvVar(const char *name)
  748. {
  749. #ifdef __OS2__
  750.     USHORT selEnviron;    /*  environment segment selector  */
  751.     USHORT usOffsetCmd;    /*  (dummy) offset to command line  */
  752.     char FAR *ptr;        /*  ptr into environment  */
  753.  
  754.     DosGetEnv(&selEnviron, &usOffsetCmd);
  755.     ptr = MAKEP(selEnviron, 0);
  756. #else /*__OS2__*/
  757.     char FAR *ptr = MK_FP(*(int FAR *)MK_FP(_psp, 0x2c), 0);
  758. #endif /*__OS2__*/
  759.  
  760.     while ( *ptr )
  761.     {
  762.         if ( envMatch(ptr, name) )
  763.         {
  764.             ptr += strlen(name);
  765.             while ( *ptr == ' ')
  766.                 ptr++;
  767.             if ( *ptr++ == '=' )
  768.                 return ( ptr );
  769.         }
  770.         while ( *ptr++ )
  771.             ;
  772.     }
  773.  
  774.     return ( NULL );
  775. }
  776. #endif /*ATARGS||CMDLINE*/
  777.  
  778. /*
  779.  *    pick pathname from argument
  780.  */
  781.     static void
  782. pickPath(char *arg, char *path)
  783. {
  784.     char *t;
  785.     int n;
  786.  
  787.     /*  find beginning of basename  */
  788.     for ( t = arg + strlen(arg) - 1; t >= arg; t-- )
  789.         if ( (*t == '/') ||
  790. #ifndef UNIXBS
  791.              (*t == '\\') ||
  792. #endif /*!UNIXBS*/
  793.              (*t == ':') )
  794.             break;
  795.  
  796.     /*  pick off path  */
  797.     for ( n = (t - arg) + 1, t = arg; n--; )
  798.         *path++ = lowercase(*t++);
  799.     *path = '\0';
  800. }
  801.  
  802. #ifdef SORTARGS
  803. /*
  804.  *    comparison routine for qsort()
  805.  */
  806.     static int
  807. myCmp(const void *l, const void *r)
  808. {
  809.     return ( strcmp(*(char **)l, *(char **)r) );
  810. }
  811. #endif /*SORTARGS*/
  812.  
  813. /*
  814.  *    get wildcard argument from command line
  815.  */
  816.     static void
  817. pickWild(void)
  818. {
  819.     char path[256];
  820.     char srch[256];
  821.     char *s = srch;
  822. #ifdef SORTARGS
  823.     int first = ARGC;    /*  first element to sort  */
  824.     int nmatched = 0;    /*  number matched on this arg  */
  825. #endif /*SORTARGS*/
  826. #ifdef GLOB
  827.     char **array;
  828.     int i;
  829. #else /*GLOB*/
  830.     FIND_T f;
  831. #endif /*GLOB*/
  832.  
  833.     /*  pick search string  */
  834.     while ( *cmdLine && !ISBLANK(*cmdLine) )
  835.         *s++ = *cmdLine++;
  836.     *s = '\0';
  837.  
  838.     pickPath(srch, path);
  839.  
  840. #ifdef GLOB
  841.     /*  glob pattern  */
  842.     array = fileGlob(srch);
  843.     /*  copy new names to argv  */
  844.     for ( i = 0; array[i] != NULL; i++ )
  845.     {
  846.         ARGV[ARGC++] = array[i];
  847.         /*  reallocate vector if necessary  */
  848.         if ( ARGC >= maxArgs )
  849.         {
  850.             maxArgs += CHUNK;
  851.             ARGV = xRealloc(ARGV, maxArgs * sizeof(char *));
  852.         }
  853.     }
  854.     free(array);
  855.  
  856.     /*  get anything ??  */
  857.     if ( i == 0 )
  858.     {
  859.         /*  pass unexpanded argument  */
  860.         ARGV[ARGC++] = xStrdup(srch);
  861.         /*  reallocate vector if necessary  */
  862.         if ( ARGC >= maxArgs )
  863.         {
  864.             maxArgs += CHUNK;
  865.             ARGV = xRealloc(ARGV, maxArgs * sizeof(char *));
  866.         }
  867.         i = 1;
  868.     }
  869. #ifdef SORTARGS
  870.     nmatched = i;
  871. #endif /*SORTARGS*/
  872. #else /*GLOB*/
  873.     if ( findfirst(srch, &f, ALL) )
  874.     {
  875.         /*  no match, pass argument as is  */
  876.         ARGV[ARGC++] = xStrdup(srch);
  877.         /*  reallocate vector if necessary  */
  878.         if ( ARGC >= maxArgs )
  879.         {
  880.             maxArgs += CHUNK;
  881.             ARGV = xRealloc(ARGV, maxArgs * sizeof(char *));
  882.         }
  883.         return;
  884.     }
  885.  
  886.     do
  887.     {
  888.         /*  add name if not "." or ".."  */
  889.         if ( f.ff_name[0] != '.' )
  890.         {
  891.             strcpy(srch, path);
  892.             CONCAT(srch, f.ff_name);
  893.             ARGV[ARGC++] = xStrdup(srch);
  894.             /*  reallocate vector if necessary  */
  895.             if ( ARGC >= maxArgs )
  896.             {
  897.                 maxArgs += CHUNK;
  898.                 ARGV = xRealloc(ARGV,
  899.                         maxArgs * sizeof(char *));
  900.             }
  901. #ifdef SORTARGS
  902.             nmatched++;
  903. #endif /*SORTARGS*/
  904.         }
  905.     }
  906.     while ( !findnext(&f) );
  907.     findclose(&f);
  908. #endif /*GLOB*/
  909.  
  910. #ifdef SORTARGS
  911.     /*  sort these entries  */
  912.     qsort(&ARGV[first], nmatched, sizeof(char *), myCmp);
  913. #endif /*SORTARGS*/
  914. }
  915.  
  916. #ifdef GLOB
  917. /*
  918.  *    does pattern contain any globbing chars ??
  919.  */
  920.     static int
  921. hasGlobChar(char *pattern)
  922. {
  923.     while ( *pattern )
  924.     {
  925.         switch ( *pattern++ )
  926.         {
  927.         case '?':
  928.         case '[':
  929.         case '*':
  930.             return ( 1 );
  931.  
  932. #ifdef UNIXBS
  933.         case '\\':
  934.             if ( !*pattern++ )
  935.                 return ( 0 );
  936. #endif /*UNIXBS*/
  937.         }
  938.     }
  939.     return ( 0 );
  940. }
  941.  
  942. /*
  943.  *    is file a directory ??
  944.  */
  945.     static int
  946. isDir(char *file)
  947. {
  948.     FIND_T ff;
  949.  
  950.     /*  what does DOS think it is ??  */
  951.     if ( findfirst(file, &ff, ALL) )
  952.         return ( 0 );
  953.     findclose(&ff);
  954.     return ( ff.ff_attrib & FA_DIREC );
  955. }
  956.  
  957. /*
  958.  *    match pattern against text
  959.  */
  960.     static int
  961. patternMatch(char *pat, char *txt)
  962. {
  963.     int ret;
  964.  
  965.     for ( ; *pat; txt++, pat++ )
  966.     {
  967.         /*  shortcut if out of text  */
  968.         if ( (*txt == '\0') && (*pat != '*') )
  969.             return ( -1 );
  970.         switch ( *pat )
  971.         {
  972.         case '*':    /*  match zero or more chars  */
  973.             /*  trailing '*' matches everything  */
  974.             if ( *++pat == '\0' )
  975.                 return ( 1 );
  976.             /*  try matching balance of pattern  */
  977.             while ( (ret = patternMatch(pat, txt++)) == 0 )
  978.                 ;
  979.             return ( ret );
  980.  
  981.         case '[':    /*  match character class  */
  982.         {
  983.             int last;
  984.             int matched;
  985.             int invert;
  986.  
  987.             if ( (invert = (pat[1] == '!')) != 0 )
  988.                 pat++;
  989.             for ( last = 256, matched = 0;
  990.                   *++pat && (*pat != ']');
  991.                   last = *pat )
  992.                 if ( (*pat == '-') ?
  993. #ifdef MATCHCASE
  994.                      (*txt <= *++pat) && (*txt >= last) :
  995.                      (*txt == *pat) )
  996. #else /*MATCHCASE*/
  997.                      (lowercase(*txt) <= lowercase(*++pat)) &&
  998.                      (lowercase(*txt) >=
  999.                              lowercase((char)last)) :
  1000.                      CHARMATCH(*txt, *pat) )
  1001. #endif /*MATCHCASE*/
  1002.                     matched = 1;
  1003.             if ( matched == invert )
  1004.                 return ( 0 );
  1005.             break;
  1006.         }
  1007. #ifdef UNIXBS
  1008.         case '\\':    /*  literal match next char  */
  1009.             pat++;
  1010.             /*FALLTHRU*/
  1011. #endif /*UNIXBS*/
  1012.         default:    /*  match single char  */
  1013.             if ( !CHARMATCH(*txt, *pat) )
  1014.                 return ( 0 );
  1015.             /*FALLTHRU*/
  1016.         case '?':    /*  match any char  */
  1017.             break;
  1018.  
  1019.         }
  1020.     }
  1021.  
  1022.     /*  matched if end of pattern and text  */
  1023.     return ( *txt == '\0' );
  1024. }
  1025.  
  1026. /*
  1027.  *    return vector of names in given dir that match pattern
  1028.  */
  1029.     static char **
  1030. dirGlob(char *pat, char *dir)
  1031. {
  1032.     char **names;        /*  temporary vector of names  */
  1033.     char search[256];    /*  search string  */
  1034.     int count = 0;        /*  number of matched filenames  */
  1035.     int maxNames;        /*  available entries in 'names'  */
  1036.     int pathLen;        /*  length of path in 'search'  */
  1037.     FIND_T ff;        /*  findfile() buffer  */
  1038.  
  1039.     /*  get temporary vector  */
  1040.     names = xMalloc(CHUNK * sizeof(char *));
  1041.     maxNames = CHUNK;
  1042.     /*  build our search string  */
  1043.     strcpy(search, dir);
  1044.     /*  save path length for later  */
  1045.     pathLen = strlen(search);
  1046.     /*  ensure trailing dir separator  */
  1047.     if ( search[0] &&
  1048.          (search[pathLen - 1] != '/') &&
  1049. #ifndef UNIXBS
  1050.          (search[pathLen - 1] != '\\') &&
  1051. #endif /*!UNIXBS*/
  1052.          (search[pathLen - 1] != ':') )
  1053.     {
  1054.         strcat(search, dirSep);
  1055.         pathLen++;
  1056.     }
  1057.     /*  search for all files  */
  1058.     strcat(search, "*.*");
  1059.  
  1060.     /*  add names to vector  */
  1061.     if ( !findfirst(search, &ff, ALL) )
  1062.         do
  1063.         {
  1064. #if defined(LCFAT) && defined(__NT__) && defined(UPPERCASE)
  1065.             /*  convert to lowercase if FAT filesystem  */
  1066.             if ( (ff.ft_ffb.ftCreationTime.dwLowDateTime == 0) &&
  1067.                  (ff.ft_ffb.ftCreationTime.dwHighDateTime == 0) )
  1068.                 strlwr(ff.ff_name);
  1069. #endif /*LCFAT&&__NT__&&UPPERCASE*/
  1070. #ifndef UPPERCASE
  1071.             /*  cosmetic  */
  1072.             strlwr(ff.ff_name);
  1073. #endif /*!UPPERCASE*/
  1074.             /*  try to match pattern, skipping "." and ".."  */
  1075.             if ( (ff.ff_name[0] != '.') &&
  1076.                  (patternMatch(pat, ff.ff_name) == 1) )
  1077.             {
  1078.                 char file[256];
  1079.                 /*  build complete filename  */
  1080.                 strncpy(file, search, pathLen);
  1081.                 strcpy(file + pathLen, ff.ff_name);
  1082.                 /*  save a copy  */
  1083.                 names[count++] = xStrdup(file);
  1084.                 if ( count >= maxNames )
  1085.                     names = xRealloc(names,
  1086.                      (maxNames += CHUNK) * sizeof(char *));
  1087.             }
  1088.         }
  1089.         while ( !findnext(&ff) );
  1090.     findclose(&ff);
  1091.  
  1092.     /*  terminate  */
  1093.     names[count++] = NULL;
  1094.  
  1095.     /*  shrink vector and return  */
  1096.     return ( (char **)xRealloc(names, (count * sizeof(char *))) );
  1097. }
  1098.  
  1099. /*
  1100.  *    return vector of names that match pattern
  1101.  */
  1102.     static char **
  1103. fileGlob(char *pattern)
  1104. {
  1105.     char **vec;
  1106.     int vecSize;
  1107.     char dirName[256];
  1108.     int dirLen;
  1109.     char *fileName;
  1110.  
  1111.     /*  get initial vector  */
  1112.     vecSize = 1;
  1113.     vec = (char **)xMalloc(sizeof(char *));
  1114.     vec[0] = NULL;
  1115.  
  1116.     /*  pick the basename  */
  1117.     fileName = pattern + strlen(pattern) - 1;
  1118.     while ( fileName >= pattern )
  1119.     {
  1120.         if ( (*fileName == '/') ||
  1121. #ifndef UNIXBS
  1122.              (*fileName == '\\') ||
  1123. #endif /*!UNIXBS*/
  1124.              (*fileName == ':') )
  1125.             break;
  1126.         fileName--;
  1127.     }
  1128.     /*  save their chosen directory separator  */
  1129.     if ( (*fileName == '/') || (*fileName == '\\') )
  1130.         dirSep[0] = *fileName;
  1131.     /*  copy directory name  */
  1132.     dirLen = (fileName - pattern) + 1;
  1133.     memcpy(dirName, pattern, dirLen);
  1134.     dirName[dirLen] = '\0';
  1135.     fileName++;
  1136.  
  1137.     /*  if dir name contains globbing chars, expand previous levels  */
  1138.     if ( hasGlobChar(dirName) )
  1139.     {
  1140.         char **dirs;
  1141.         int i;
  1142.  
  1143. #ifdef UNIXBS
  1144.         if ( dirName[dirLen - 1] == '/' )
  1145. #else /*UNIXBS*/
  1146.         if ( (dirName[dirLen - 1] == '/') ||
  1147.              (dirName[dirLen - 1] == '\\') )
  1148. #endif /*UNIXBS*/
  1149.             dirName[dirLen - 1] = '\0';
  1150.  
  1151.         dirs = fileGlob(dirName);
  1152.  
  1153.         /*  now glob each directory  */
  1154.         for ( i = 0; dirs[i] != NULL; i++ )
  1155.         {
  1156.             char **array;
  1157.  
  1158.             if ( isDir(dirs[i]) )
  1159.             {
  1160.                 int j;
  1161.                 /*  glob this dir  */
  1162.                 array = dirGlob(fileName, dirs[i]);
  1163.                 /*  count number of entries  */
  1164.                 for ( j = 0; array[j] != NULL; j++ )
  1165.                     ;
  1166.                 /*  realloc vector  */
  1167.                 vec = (char **)xRealloc(vec,
  1168.                            (vecSize + j) * sizeof(char *));
  1169.                 /*  append to vector  */
  1170.                 for ( j = 0; array[j] != NULL; j++ )
  1171.                     vec[vecSize++ - 1] = array[j];
  1172.                 vec[vecSize - 1] = NULL;
  1173.                 free(array);
  1174.             }
  1175.         }
  1176.         /*  free the dirs  */
  1177.         for ( i = 0; dirs[i]; i++ )
  1178.             free(dirs[i]);
  1179.         free(dirs);
  1180.  
  1181.         return ( vec );
  1182.     }
  1183.  
  1184.     /* If there is only a directory name, return it. */
  1185.     if ( *fileName == '\0' )
  1186.     {
  1187.         vec = (char **)xRealloc(vec, 2 * sizeof(char *));
  1188.         vec[0] = xStrdup(dirName);
  1189.         vec[1] = NULL;
  1190.         return ( vec );
  1191.     }
  1192.  
  1193.     /*  we didn't need a vector  */
  1194.     free(vec);
  1195.     /*  just return what dirGlob() returns  */
  1196.     return ( dirGlob(fileName, dirName) );
  1197. }
  1198. #endif /*GLOB*/
  1199.  
  1200. #ifdef MKSARGS
  1201. /*
  1202. -*    _setenvp - build vector of environment strings
  1203.  */
  1204. #ifdef __TURBOCCC__
  1205.     void FAR
  1206. #else /*__TURBOCCC__*/
  1207.     void
  1208. #endif /*__TURBOCCC__*/
  1209. _setenvp()
  1210. {
  1211. #if defined(__TURBOC__) && !defined(__TURBOCCC__)
  1212.     extern int _envLng;    /*  size of actual environment  */
  1213.     extern int _envSize;    /*  size of ptrs to strings  */
  1214. #else /*__TURBOC__&&!__TURBOCCC__*/
  1215.     int _envLng;        /*  size of actual environment  */
  1216.     int _envSize;        /*  size of ptrs to strings  */
  1217. #endif /*__TURBOC__&&!__TURBOCCC__*/
  1218.     char FAR *farPtr;
  1219.     char FAR *wrkPtr;
  1220.     char *env;
  1221.     int i;
  1222. #ifdef __OS2__
  1223.     USHORT selEnviron;
  1224.     USHORT usOffsetCmd;
  1225. #endif /*__OS2__*/
  1226.  
  1227. #ifdef __NT__
  1228.     wrkPtr = farPtr = GetEnvironmentStrings();
  1229. #endif /*__NT__*/
  1230. #ifdef __OS2__
  1231.     DosGetEnv(&selEnviron, &usOffsetCmd);
  1232.     wrkPtr = farPtr = MAKEP(selEnviron, 0);
  1233. #endif /*__OS2__*/
  1234. #ifdef __MSDOS__
  1235.     wrkPtr = farPtr = MK_FP(*(int FAR *)MK_FP(_psp, 0x2c), 0);
  1236. #endif /*__MSDOS__*/
  1237.  
  1238.     /*  find size of environment without MKS args  */
  1239.     _envLng = _envSize = 0;
  1240.     while ( *wrkPtr )
  1241.     {
  1242.         if ( *wrkPtr != '~' )
  1243.         {
  1244.             while ( *wrkPtr++ )
  1245.                 _envLng++;
  1246.             _envLng++;
  1247.             _envSize += sizeof(char *);
  1248.         }
  1249.         else
  1250.             while ( *wrkPtr++ )
  1251.                 ;
  1252.     }
  1253.  
  1254.     /*  bump a little  */
  1255.     _envSize += (sizeof(char *) * 10);
  1256.  
  1257.     /*  allocate space  */
  1258.     environ = xMalloc(_envSize);
  1259.     i = 0;
  1260.  
  1261. #if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) || \
  1262.     defined(M_I86SM) || defined(M_I86MM)
  1263.     /*  copy and parse strings  */
  1264.     env = xMalloc(_envLng);
  1265.     while ( *farPtr )
  1266.     {
  1267.         if ( *farPtr != '~' )
  1268.         {
  1269.             environ[i++] = env;
  1270.             while ( (*env++ = *farPtr++) != '\0' )
  1271.                 ;
  1272.         }
  1273.         else
  1274.             while ( *farPtr++ )
  1275.                 ;
  1276.     }
  1277. #else /*__TINY__||__SMALL__||__MEDIUM__||M_I86SM||M_I86MM*/
  1278.     /*  parse strings  */
  1279.     while ( *farPtr )
  1280.     {
  1281.         if ( *farPtr != '~' )
  1282.             environ[i++] = farPtr;
  1283.         while ( *farPtr++ )
  1284.             ;
  1285.     }
  1286. #endif /*__TINY__||__SMALL__||__MEDIUM__||M_I86SM||M_I86MM*/
  1287.  
  1288.     environ[i] = NULL;
  1289.  
  1290. #ifdef __TURBOCCC__
  1291.     _C0environ = environ;
  1292. #endif /*__TURBOCCC__*/
  1293.  
  1294. }
  1295.  
  1296. #ifdef __TURBOCCC__
  1297. asm    _INIT_    Segment Word Public 'INITDATA'
  1298. asm        DB    1
  1299. asm        DB    2
  1300. asm        DD    __setenvp__
  1301. asm    _INIT_    EndS
  1302. #endif /*__TURBOCCC__*/
  1303.  
  1304. #endif /*MKSARGS*/
  1305.  
  1306. #ifdef TEST
  1307. #if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
  1308. unsigned _stklen = 8192;
  1309. #endif /*__COMPACT__||__LARGE__||__HUGE__*/
  1310. /*
  1311. -*    main - _setargv() and _setenvp() test, print arglist and environment
  1312.  */
  1313.     void
  1314. main(int argc, char *argv[], char *envp[])
  1315. {
  1316.     int i;
  1317.  
  1318.     printf("-----\n");
  1319.     for ( i = 0; i < argc; i++ )
  1320.         printf("argv[%04d]=[%s]\n", i, argv[i]);
  1321.     printf("-----\n");
  1322. #ifndef SKIPENV
  1323.     for ( i = 0; envp[i]; i++ )
  1324.         printf("envp[%04d]=[%s]\n", i, envp[i]);
  1325.     printf("-----\n");
  1326. #endif /*SKIPENV*/
  1327. }
  1328. #endif /*TEST*/
  1329.  
  1330. /*  END of setargv.c  */
  1331.