Subversion Repositories DevTools

Rev

Rev 4806 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - Unix File I/O Emulation
3
 *
4
 * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited
5
 *
6
 * This code is subject to the following copyright restrictions:
7
 *
8
 * 1.  Redistribution and use in source and binary forms are permitted
9
 *     provided that the above copyright notice is duplicated in the
10
 *     source form and the copyright notice in file sh6.c is displayed
11
 *     on entry to the program.
12
 *
13
 * 2.  The sources (or parts thereof) or objects generated from the sources
14
 *     (or parts of sources) cannot be sold under any circumstances.
15
 *
16
 * The directory functions opendir, readdir, closedir are based on the public
17
 * domain implementation for MS-DOS written by Michael Rendell
18
 * ({uunet,utai}michael@garfield), August 1897
19
 *
20
 * startup () is based on EMX/GCC startup.c in emx/lib/src/startup.  Copyright
21
 * (c) 1990-1993 by Eberhard Mattes.
22
 *
23
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/Sh8.c,v 1.2 2004/05/10 09:30:07 ayoung Exp $
24
 *
25
 *    $Log: Sh8.c,v $
26
 *    Revision 1.2  2004/05/10 09:30:07  ayoung
27
 *    improved Path/PATH handling
28
 *    Quote CreateProcess arg0 if embedded spaces are  encountered
29
 *    Native NT exec dont need to check command line length
30
 *    Warning when '@' within redirect list
31
 *    DEBUG_EXEC option, split from PRINT_EXEC option and improved
32
 *
33
 *    Revision 1.1  2002/08/02 06:49:35  adamy
34
 *    imported (reference only)
35
 *
36
 *    Revision 1.2  2001/08/03 08:30:55  ayoung
37
 *    removed mutliple dot conversion under WIN32
38
 *
39
 *    Revision 1.1  2001/07/20 05:55:45  ayoung
40
 *    WIN32 support
41
 *
42
 *    Revision 1.2  2000/09/27 08:33:36  adamy
43
 *    Added EXTENDED_LINE cache and use __systeml_mode during DOS builds.
44
 *
45
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
46
 *    UTIL
47
 *
48
 *      Revision 2.16  1994/08/25  20:49:11  istewart
49
 *      MS Shell 2.3 Release
50
 *
51
 *      Revision 2.15  1994/02/23  09:23:38  istewart
52
 *      Beta 233 updates
53
 *
54
 *      Revision 2.14  1994/02/01  10:25:20  istewart
55
 *      Release 2.3 Beta 2, including first NT port
56
 *
57
 *      Revision 2.13  1994/01/20  14:51:43  istewart
58
 *      Release 2.3 Beta 1
59
 *
60
 *      Revision 2.12  1994/01/11  17:55:25  istewart
61
 *      Release 2.3 Beta 0 patches
62
 *
63
 *      Revision 2.11  1993/11/09  10:39:49  istewart
64
 *      Beta 226 checking
65
 *
66
 *      Revision 2.10  1993/08/25  16:03:57  istewart
67
 *      Beta 225 - see Notes file
68
 *
69
 *      Revision 2.9  1993/07/02  10:21:35  istewart
70
 *      224 Beta fixes
71
 *
72
 *      Revision 2.8  1993/06/14  11:00:12  istewart
73
 *      More changes for 223 beta
74
 *
75
 *      Revision 2.7  1993/06/02  09:52:35  istewart
76
 *      Beta 223 Updates - see Notes file
77
 *
78
 *      Revision 2.6  1993/02/16  16:03:15  istewart
79
 *      Beta 2.22 Release
80
 *
81
 *      Revision 2.5  1993/01/26  18:35:09  istewart
82
 *      Release 2.2 beta 0
83
 *
84
 *      Revision 2.4  1992/12/14  10:54:56  istewart
85
 *      BETA 215 Fixes and 2.1 Release
86
 *
87
 *      Revision 2.3  1992/11/06  10:03:44  istewart
88
 *      214 Beta test updates
89
 *
90
 *      Revision 2.2  1992/07/16  14:33:34  istewart
91
 *      Beta 212 Baseline
92
 *
93
 *      Revision 2.1  1992/07/10  10:52:48  istewart
94
 *      211 Beta updates
95
 *
96
 *      Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
97
 *      MS-Shell 2.0 Baseline release
98
 *
99
 */
100
#if defined (__EMX__)
101
#  include <sys/emx.h>
102
#endif
103
#include <sys/types.h>
104
#include <sys/stat.h>
105
#include <stdio.h>
106
#include <signal.h>
107
#include <errno.h>
108
#include <setjmp.h>
109
#include <stdlib.h>
110
#include <fcntl.h>
111
#include <string.h>
112
#include <unistd.h>
113
#include <limits.h>
114
#include <dirent.h>
115
#include <ctype.h>
116
#include <stdarg.h>
117
#if defined (__EMX__)
118
#  include <sys/ioctl.h>
119
#endif
120
 
121
 
122
/*
123
 * There appears to be no alloca in TurboC
124
 */
125
 
126
#if defined (__TURBOC__)
127
#  include <alloc.h>
128
#  include <dir.h>
129
#  define alloca(x)             malloc (x)
130
#  define alloca_free(x)        free (x)
131
#elif defined(_MSC_VER)
132
#  include <malloc.h>
133
#  define alloca(x)             calloc (x,1)
134
#  define alloca_free(x)        free (x)
135
#else
136
#  include <malloc.h>
137
#  define alloca_free(x)
138
#endif
139
 
140
#include "sh.h"
141
 
142
#define MAX_LINE        160             /* Max line length              */
143
 
144
#define F_START         4
145
#define NSTART          16              /* default number of words to   */
146
                                        /* allow for initially          */
147
#define IS_OCTAL(a)     (((a) >= '0') && ((a) <= '7'))
148
 
149
static char            *nopipe = "can't create pipe";
150
 
151
/* List of open files to allow us to simulate the Unix open and unlink
152
 * operation for temporary files
153
 */
154
 
155
typedef struct flist {
156
    struct flist        *fl_next;       /* Next link                    */
157
    char                *fl_name;       /* File name                    */
158
    bool                fl_close;       /* Delete on close flag         */
159
    int                 fl_size;        /* Size of fl_fd array          */
160
    int                 fl_count;       /* Number of entries in array   */
161
    int                 fl_mode;        /* File open mode               */
162
    int                 *fl_fd;         /* File ID array (for dup)      */
163
} s_flist;
164
 
165
static s_flist                  *list_start = (s_flist *)NULL;
166
static s_flist * F_LOCAL        find_entry (int);
167
static void F_LOCAL             SaveFileDescriptor (FILE *);
168
static char * F_LOCAL           _Ex_SkipWhiteSpace (char *);
169
#if (OS_TYPE != OS_UNIX)
170
static void F_LOCAL             _Ex_ExpandIndirectFile (char *, Word_B **);
171
static char * F_LOCAL           _Ex_GetSpace (int, char *);
172
static void F_LOCAL             _Ex_ExpandField (char *, Word_B **);
173
static char * F_LOCAL           _Ex_ConvertEnvVariables (char *);
174
static void F_LOCAL             _Ex_SaveArgvValue (char *, bool, Word_B **);
175
static void F_LOCAL             _Ex_CommandLine (char *, Word_B **);
176
static unsigned long F_LOCAL    QueryApplicationType1 (int);
177
#endif
178
 
179
#if (OS_TYPE == OS_OS2)
180
static void F_LOCAL             _Ex_ProcessEMXArguments (char *, Word_B **);
181
#endif
182
 
183
#if (OS_TYPE == OS_DOS) && (__WATCOMC__)
184
extern char                     *_LpCmdLine;
185
extern char                     *_LpPgmName;
186
static void F_LOCAL             OutputBIOSString (char *);
187
#endif
188
 
189
#ifdef __WATCOMC__
190
char                            *_getdcwd (int, char *, int);
191
#endif
192
 
193
#ifdef __EMX__
194
char                            *_getdcwd (int, char *, int);
195
#endif
196
 
197
/*
198
 * Command Line pointers
199
 */
200
 
201
#if defined (__TURBOC__)        /* Borland C                            */
202
#  define ARG_ARRAY     _argv
203
#  define ARG_COUNT     _argc
204
#  define ENTRY_POINT   _setargv
205
#elif defined (__WATCOMC__)     /* WatCom C                             */
206
#  define ARG_ARRAY     ___Argv
207
#  define ARG_COUNT     ___Argc
208
#  define ENTRY_POINT   __Init_Argv
209
#elif defined (__IBMC__)        /* IBM C Set/2                          */
210
#  define ARG_ARRAY     _argv
211
#  define ARG_COUNT     _argc
212
#  define ENTRY_POINT   _setuparg
213
#elif defined (__EMX__)         /* Gcc/EMX                              */
214
#  define ARG_ARRAY     _argv
215
#  define ARG_COUNT     _argc
216
#  define ENTRY_POINT   GetArgcV
217
#elif defined (_MSC_VER)
218
                                /* Microsoft C                          */
219
#  define ARG_ARRAY     __argv
220
#  define ARG_COUNT     __argc
221
#  define ENTRY_POINT   __cdecl _setargv
222
#endif
223
 
224
#if (OS_TYPE != OS_UNIX)
225
#  if defined (__EMX__)                 /* Gcc/EMX                      */
226
extern void     __startup (int argc, char **argv);
227
extern void     ENTRY_POINT (void);
228
static char     **ARG_ARRAY;            /* Current argument address     */
229
static int      ARG_COUNT;              /* Current argument count       */
230
#  else
231
extern void     ENTRY_POINT (void);
232
extern char     **ARG_ARRAY;            /* Current argument address     */
233
extern int      ARG_COUNT;              /* Current argument count       */
234
#  endif
235
 
236
/*
237
 * Some EMX startup statics
238
 */
239
 
240
#  if defined (__EMX__)
241
                                        /* The version of this libc.*/
242
static const char       _libc_version[] = " libc for emx 0.8h";
243
/* Display this warning if emx.dll or emx.exe is out of date. */
244
static const char       _version_warning[] = 
245
                                "WARNING: emx 0.8h or later required\r\n";
246
                                        /* The buffer for stdin. */
247
static char             ibuf[BUFSIZ];
248
#  endif
249
 
250
/*
251
 * General OS independent start of the command line and program name.
252
 */
253
 
254
char            *_ACmdLine;
255
char            *_APgmName;             /* Program name                 */
256
 
257
#  if defined (OS2)
258
extern ushort far _aenvseg;
259
extern ushort far _acmdln;
260
#  endif
261
 
262
/*
263
 * Directory functions internals structure.
264
 */
265
 
266
typedef struct _dircontents     DIRCONT;
267
static void                     FreeDirectoryListing (DIRCONT *);
268
#endif
269
 
270
/*
271
 * Open a file and add it to the Open file list.  Errors are the same as
272
 * for a normal open.
273
 */
274
 
275
int S_open (bool d_flag, const char *pName, int mode)
276
{
277
    int                 pmask;
278
    s_flist             *fp = (s_flist *)NULL;
279
    int                 *f_list = (int *)NULL;
280
    char                *f_name = (char *)NULL;
281
    void                (_SIGDECL *save_signal)(int);
282
#ifdef __IBMC__
283
    HFILE               shfFileHandle;
284
    ULONG               ActionTaken;
285
    ULONG               ulFileAttribute;
286
    ULONG               ulOpenFlag;
287
    ULONG               ulOpenMode;
288
    APIRET              rc;            /* Return code */
289
#endif
290
    char                name[ MAX_PATH ];
291
 
292
/* Check this is a valid file name */
293
 
294
    CheckDOSFileName (pName, name);
295
 
296
/* Grap some space.  If it fails, free space and return an error */
297
 
298
    if (((fp = (s_flist *) GetAllocatedSpace (sizeof (s_flist)))
299
                == (s_flist *)NULL) ||
300
        ((f_list = (int *) GetAllocatedSpace (sizeof (int) * F_START))
301
                == (int *)NULL) ||
302
        ((f_name = StringSave (name)) == null))
303
    {
304
        if (f_list == (int *)NULL)
305
            ReleaseMemoryCell ((void *)f_list);
306
 
307
        if (fp == (s_flist *)NULL)
308
            ReleaseMemoryCell ((void *)fp);
309
 
310
        return -1;
311
    }
312
 
313
/* Disable signals */
314
 
315
    save_signal = signal (SIGINT, SIG_IGN);
316
 
317
/* Set up the structure.  Change two Unix device names to the DOS
318
 * equivalents and disable create
319
 */
320
 
321
#if (OS_TYPE != OS_UNIX)
322
    if (strnicmp (name, DeviceNameHeader, LEN_DEVICE_NAME_HEADER) == 0)
323
    {
324
        if (stricmp (&name[5], "tty") == 0)
325
            strcpy (&name[5], "con");
326
 
327
        else if (stricmp (&name[5], "null") == 0)
328
            strcpy (&name[5], "nul");
329
 
330
        mode &= ~(O_CREAT | O_TRUNC);
331
    }
332
#endif
333
 
334
    fp->fl_name  = strcpy (f_name, name);
335
    fp->fl_close = d_flag;
336
    fp->fl_size  = F_START;
337
    fp->fl_count = 1;
338
    fp->fl_fd    = f_list;
339
    fp->fl_mode  = mode;
340
 
341
/*
342
 * The IBM C Set/2 OS/2 2.x library function, open, does not appear work
343
 * correctly.  So I've replaced it with a emulator here
344
 */
345
 
346
#ifdef __IBMC__
347
 
348
/* Set up open actions */
349
 
350
    if (mode & O_CREAT)
351
         ulOpenFlag = OPEN_ACTION_CREATE_IF_NEW |
352
                        ((mode & O_EXCL)
353
                            ? OPEN_ACTION_FAIL_IF_EXISTS
354
                                : ((mode & O_TRUNC)
355
                                    ? OPEN_ACTION_REPLACE_IF_EXISTS
356
                                    : OPEN_ACTION_OPEN_IF_EXISTS));
357
    else
358
         ulOpenFlag = OPEN_ACTION_FAIL_IF_NEW |
359
                        ((mode & O_TRUNC)
360
                            ? OPEN_ACTION_REPLACE_IF_EXISTS
361
                            : OPEN_ACTION_OPEN_IF_EXISTS);
362
 
363
/* Set up open mode */
364
 
365
    ulOpenMode = OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE;
366
 
367
    if (mode & O_NOINHERIT)
368
        ulOpenMode |= OPEN_FLAGS_NOINHERIT;
369
 
370
    if (mode & O_WRONLY)
371
        ulOpenMode |= OPEN_ACCESS_WRITEONLY;
372
 
373
    else if (mode & O_RDONLY)
374
        ulOpenMode |= OPEN_ACCESS_READONLY;
375
 
376
    else
377
        ulOpenMode |= OPEN_ACCESS_READWRITE;
378
 
379
    DISABLE_HARD_ERRORS;
380
    rc = DosOpen (name, &shfFileHandle, &ActionTaken, (ULONG)0, FILE_NORMAL,
381
                  ulOpenFlag, ulOpenMode, (PEAOP2)NULL);
382
    ENABLE_HARD_ERRORS;
383
 
384
    if (!rc)
385
    {
386
        if (mode & O_TEXT)
387
            setmode (shfFileHandle, O_TEXT);
388
 
389
        else if (mode & O_BINARY)
390
            setmode (shfFileHandle, O_BINARY);
391
 
392
        fp->fl_fd[0] = shfFileHandle;
393
    }
394
 
395
    else
396
        fp->fl_fd[0] = -1;
397
 
398
#else
399
    DISABLE_HARD_ERRORS;
400
    fp->fl_fd[0] = open (name, mode, S_IREAD | S_IWRITE);
401
    ENABLE_HARD_ERRORS;
402
#endif
403
 
404
/* Open the file */
405
 
406
    if (fp->fl_fd[0] < 0)
407
    {
408
        ReleaseMemoryCell ((void *)f_name);
409
        ReleaseMemoryCell ((void *)f_list);
410
        ReleaseMemoryCell ((void *)fp);
411
        pmask = -1;
412
    }
413
 
414
/* Make sure everything is in area 0 */
415
 
416
    else
417
    {
418
        SetMemoryAreaNumber ((void *)fp, 0);
419
        SetMemoryAreaNumber ((void *)f_list, 0);
420
 
421
/* List into the list */
422
 
423
        fp->fl_next   = list_start;
424
        list_start = fp;
425
 
426
/* Return the file descriptor */
427
 
428
        pmask = fp->fl_fd[0];
429
 
430
/* Mark in use */
431
 
432
        ChangeFileDescriptorStatus (pmask, TRUE);
433
    }
434
 
435
/* Restore signals */
436
 
437
    signal (SIGINT, save_signal);
438
 
439
    return pmask;
440
}
441
 
442
/*
443
 * Scan the File list for the appropriate entry for the specified ID
444
 */
445
 
446
static s_flist * F_LOCAL find_entry (int fid)
447
{
448
    s_flist     *fp = list_start;
449
    int         i;
450
 
451
    while (fp != (s_flist *)NULL)
452
    {
453
        for (i = 0; i < fp->fl_count; i++)
454
        {
455
            if (fp->fl_fd[i] == fid)
456
                return fp;
457
        }
458
 
459
        fp = fp->fl_next;
460
    }
461
 
462
    return (s_flist *)NULL;
463
}
464
 
465
/* Close the file
466
 *
467
 * We need a version of close that does everything but close for dup2 as
468
 * new file id is closed.  If c_flag is TRUE, close the file as well.
469
 */
470
 
471
int     S_close (int fid, bool c_flag)
472
{
473
    s_flist     *fp = find_entry (fid);
474
    s_flist     *last = (s_flist *)NULL;
475
    s_flist     *fp1 = list_start;
476
    int         i = 0;
477
    bool        release = TRUE;
478
    bool        delete = FALSE;
479
    char        *fname = 0;
480
    void        (_SIGDECL *save_signal)(int);
481
 
482
/* Disable signals */
483
 
484
    save_signal = signal (SIGINT, SIG_IGN);
485
 
486
/* Find the entry for this ID */
487
 
488
    if (fp != (s_flist *)NULL)
489
    {
490
        for (i = 0; i < fp->fl_count; i++)
491
        {
492
            if (fp->fl_fd[i] == fid)
493
                fp->fl_fd[i] = -1;
494
 
495
            if (fp->fl_fd[i] != -1)
496
                release = FALSE;
497
        }
498
 
499
/* Are all the Fids closed ? */
500
 
501
        if (release)
502
        {
503
            fname = fp->fl_name;
504
            delete = fp->fl_close;
505
            ReleaseMemoryCell ((void *)fp->fl_fd);
506
 
507
/* Scan the list and remove the entry */
508
 
509
            while (fp1 != (s_flist *)NULL)
510
            {
511
                if (fp1 != fp)
512
                {
513
                    last = fp1;
514
                    fp1 = fp1->fl_next;
515
                    continue;
516
                }
517
 
518
                if (last == (s_flist *)NULL)
519
                    list_start = fp->fl_next;
520
 
521
                else
522
                    last->fl_next = fp->fl_next;
523
 
524
                break;
525
            }
526
 
527
/* OK - delete the area */
528
 
529
            ReleaseMemoryCell ((void *)fp);
530
        }
531
    }
532
 
533
/* Flush these two in case they were re-directed */
534
 
535
    FlushStreams ();
536
 
537
/* Close the file anyway */
538
 
539
    if (c_flag)
540
    {
541
        i = close (fid);
542
        ChangeFileDescriptorStatus (fid, FALSE);
543
    }
544
 
545
/* Delete the file ? */
546
 
547
    if (delete)
548
    {
549
        unlink (fname);
550
        ReleaseMemoryCell ((void *)fname);
551
    }
552
 
553
/* Restore signals */
554
 
555
    signal (SIGINT, save_signal);
556
 
557
    return i;
558
}
559
 
560
/*
561
 * Version of fclose
562
 */
563
 
564
void    S_fclose (FILE *FP, bool d_flag)
565
{
566
    CloseFile (FP);
567
    S_close (fileno (FP), d_flag);
568
}
569
 
570
/*
571
 * Duplicate file handler.  Add the new handler to the ID array for this
572
 * file.
573
 */
574
 
575
int S_dup (int old_fid)
576
{
577
    int         new_fid;
578
 
579
    if ((new_fid = dup (old_fid)) >= 0)
580
        S_Remap (old_fid, new_fid);
581
 
582
    return new_fid;
583
}
584
 
585
/*
586
 * Add the ID to the ID array for this file
587
 */
588
 
589
int S_Remap (int old_fid, int new_fid)
590
{
591
    s_flist     *fp = find_entry (old_fid);
592
    int         *flist;
593
    int         i;
594
 
595
    ChangeFileDescriptorStatus (new_fid, TRUE);
596
 
597
    if (fp == (s_flist *)NULL)
598
        return new_fid;
599
 
600
/* Is there an empty slot ? */
601
 
602
    for (i = 0; i < fp->fl_count; i++)
603
    {
604
        if (fp->fl_fd[i] == -1)
605
            return (fp->fl_fd[i] = new_fid);
606
    }
607
 
608
/* Is there any room at the end ? No - grap somemore space and effect a
609
 * re-alloc.  What to do if the re-alloc fails - should really get here.
610
 * Safty check only??
611
 */
612
 
613
    if (fp->fl_count == fp->fl_size)
614
    {
615
        flist = (int *)ReAllocateSpace ((void *)fp->fl_fd,
616
                                        (fp->fl_size + F_START) * sizeof (int));
617
 
618
        if (flist == (int *)NULL)
619
            return new_fid;
620
 
621
        SetMemoryAreaNumber ((void *)flist, 0);
622
        fp->fl_fd   = flist;
623
        fp->fl_size += F_START;
624
    }
625
 
626
    return (fp->fl_fd[fp->fl_count++] = new_fid);
627
}
628
 
629
 
630
/*
631
 * Duplicate file handler onto specific handler
632
 */
633
 
634
int S_dup2 (int old_fid, int new_fid)
635
{
636
    int         res = -1;
637
    int         i;
638
    Save_IO     *sp;
639
 
640
/* If duping onto stdin, stdout or stderr, Search the Save IO stack for an
641
 * entry matching us
642
 */
643
 
644
    if ((new_fid >= STDIN_FILENO) && (new_fid <= STDERR_FILENO))
645
    {
646
        for (sp = SSave_IO, i = 0;
647
             (i < NSave_IO_E) && (SSave_IO[i].depth < Execute_stack_depth);
648
             i++, ++sp)
649
            continue;
650
 
651
/* If depth is greater the Execute_stack_depth - we should panic as this
652
 * should not happen.  However, for the moment, I'll ignore it
653
 */
654
 
655
/* If there an entry for this depth ? */
656
 
657
        if (i == NSave_IO_E)
658
        {
659
 
660
/* Do we need more space? */
661
 
662
            if (NSave_IO_E == MSave_IO_E)
663
            {
664
                sp = (Save_IO *)ReAllocateSpace ((MSave_IO_E != 0)
665
                                                    ? SSave_IO : (void *)NULL,
666
                                                 (MSave_IO_E + SSAVE_IO_SIZE) *
667
                                                    sizeof (Save_IO));
668
 
669
/* Check for error */
670
 
671
                if (sp == (Save_IO *)NULL)
672
                    return -1;
673
 
674
/* Save original data */
675
 
676
                SetMemoryAreaNumber ((void *)sp, 1);
677
                SSave_IO = sp;
678
                MSave_IO_E += SSAVE_IO_SIZE;
679
            }
680
 
681
/* Initialise the new entry */
682
 
683
            sp = &SSave_IO[NSave_IO_E++];
684
            sp->depth             = Execute_stack_depth;
685
            sp->fp[STDIN_FILENO]  = -1;
686
            sp->fp[STDOUT_FILENO] = -1;
687
            sp->fp[STDERR_FILENO] = -1;
688
        }
689
 
690
        if (sp->fp[new_fid] == -1)
691
            sp->fp[new_fid] = ReMapIOHandler (new_fid);
692
 
693
        FlushStreams ();
694
    }
695
 
696
/* OK - Dup the descriptor */
697
 
698
    if ((old_fid != -1) && ((res = dup2 (old_fid, new_fid)) >= 0))
699
    {
700
        S_close (new_fid, FALSE);
701
        res = S_Remap (old_fid, new_fid);
702
    }
703
 
704
    return res;
705
}
706
 
707
/*
708
 * Restore the Stdin, Stdout and Stderr to original values.  If change is
709
 * FALSE, just remove entries from stack.  A special case for exec.
710
 */
711
 
712
int RestoreStandardIO (int rv, bool change)
713
{
714
    int         j, i;
715
    Save_IO     *sp;
716
 
717
/* Start at the top and remove any entries above the current execute stack
718
 * depth
719
 */
720
 
721
    for (j = NSave_IO_E; j > 0; j--)
722
    {
723
       sp = &SSave_IO[j - 1];
724
 
725
       if (sp->depth < Execute_stack_depth)
726
           break;
727
 
728
/* Reduce number of entries */
729
 
730
        --NSave_IO_E;
731
 
732
/* If special case (changed at this level) - continue */
733
 
734
        if (!change && (sp->depth == Execute_stack_depth))
735
            continue;
736
 
737
/* Close and restore any files */
738
 
739
        for (i = STDIN_FILENO; i <= STDERR_FILENO; i++)
740
        {
741
            if (sp->fp[i] != -1)
742
            {
743
                S_close (i, TRUE);
744
                dup2 (sp->fp[i], i);
745
                S_close (sp->fp[i], TRUE);
746
            }
747
        }
748
    }
749
 
750
    return rv;
751
}
752
 
753
/*
754
 * Create a Pipe
755
 */
756
 
757
int OpenAPipe (void)
758
{
759
    int         i;
760
 
761
    if ((i = S_open (TRUE, GenerateTemporaryFileName (), O_PMASK)) < 0)
762
        PrintErrorMessage (nopipe);
763
 
764
    return i;
765
}
766
 
767
/*
768
 * Close a pipe
769
 */
770
 
771
void CloseThePipe (int pv)
772
{
773
    if (pv != -1)
774
        S_close (pv, TRUE);
775
}
776
 
777
/*
778
 * Check for restricted shell
779
 */
780
 
781
bool CheckForRestrictedShell (char *s)
782
{
783
    if (RestrictedShellFlag)
784
    {
785
        PrintErrorMessage (BasicErrorMessage, s, "restricted");
786
        return TRUE;
787
    }
788
 
789
    return FALSE;
790
}
791
 
792
/*
793
 * Check to see if a file is a shell script.  If it is, return the file
794
 * handler for the file
795
 */
796
static char *Extensions[] = { null, SHELLExtension, KSHELLExtension};
797
 
798
int OpenForExecution (char *path, char **params, int *nargs)
799
{
800
    int         RetVal = -1;
801
    int         j;
802
    int         EndP = strlen (path);
803
    char        *local_path;
804
 
805
/* Work on a copy of the path */
806
 
807
    if ((local_path = AllocateMemoryCell (EndP + 5)) == (char *)NULL)
808
        return -1;
809
 
810
    strcpy (local_path, path);
811
 
812
/* Try the file name and then with a .sh and then .ksh appended */
813
 
814
    for (j = 0; j < 3; j++)
815
    {
816
        strcpy (&local_path[EndP], Extensions[j]);
817
 
818
        if ((RetVal = CheckForScriptFile (local_path, params, nargs)) >= 0)
819
            break;
820
    }
821
 
822
    ReleaseMemoryCell ((void *)local_path);
823
    return RetVal;
824
}
825
 
826
/*
827
 * Check for shell script
828
 */
829
 
830
int CheckForScriptFile (char *path, char **params, int *nargs)
831
{
832
    char        buf[512];               /* Input buffer                 */
833
    int         fp;                     /* File handler                 */
834
    int         nbytes;                 /* Number of bytes read         */
835
    char        *bp;                    /* Pointers into buffers        */
836
    char        *ep;
837
 
838
    if ((fp = S_open (FALSE, path, O_RMASK)) < 0)
839
        return -1;
840
 
841
/* zero or less bytes - not a script */
842
 
843
    memset (buf, 0, 512);
844
    nbytes = read (fp, buf, 512);
845
    lseek (fp, 0L, SEEK_SET);
846
 
847
    for (ep = &buf[nbytes], bp = buf;
848
         (bp < ep) && ((unsigned char)*bp >= 0x08); ++bp)
849
        continue;
850
 
851
/* If non-ascii file or length is less than 1 - not a script */
852
 
853
    if ((bp != ep) || (nbytes < 1))
854
    {
855
        S_close (fp, TRUE);
856
        return -1;
857
    }
858
 
859
/* Ensure end of buffer detected */
860
 
861
    buf[511] = 0;
862
 
863
/* Initialise the return parameters, if specified */
864
 
865
    if (params != (char **)NULL)
866
        *params = null;
867
 
868
    if (nargs != (int *)NULL)
869
        *nargs = 0;
870
 
871
/* We don't care how many bytes were read now, so use it to count the
872
 * additional arguments
873
 */
874
 
875
    nbytes = 0;
876
 
877
/* Find the end of the first line */
878
 
879
    if ((bp = strchr (buf, CHAR_NEW_LINE)) != (char *)NULL)
880
        *bp = 0;
881
 
882
    bp = buf;
883
    ep = (char *)NULL;
884
 
885
/* Check for script */
886
 
887
    if ((*(bp++) != CHAR_COMMENT) || (*(bp++) != '!'))
888
        return fp;
889
 
890
    while (*bp)
891
    {
892
 
893
/* Save the start of the arguments */
894
 
895
        if (*(bp = _Ex_SkipWhiteSpace (bp)))
896
        {
897
            if (ep == (char *)NULL)
898
                ep = bp;
899
 
900
/* Count the arguments */
901
 
902
            ++nbytes;
903
        }
904
 
905
        bp = SkipToWhiteSpace (bp);
906
    }
907
 
908
/* Set up the return parameters, if appropriate */
909
 
910
    if ((params != (char **)NULL) && (strlen (ep) != 0))
911
    {
912
        if ((*params = AllocateMemoryCell (strlen (ep) + 1)) == (char *)NULL)
913
        {
914
            *params = null;
915
            S_close (fp, TRUE);
916
            return -1;
917
        }
918
 
919
        strcpy (*params, ep);
920
    }
921
 
922
    if (nargs != (int *)NULL)
923
        *nargs = nbytes;
924
 
925
    return fp;
926
}
927
 
928
/*
929
 * Get the file descriptor type.
930
 */
931
 
932
#if (OS_TYPE == OS_OS2)
933
int      GetDescriptorType (int fp)
934
{
935
    OSCALL_PARAM        fsType = HANDTYPE_FILE;
936
    OSCALL_PARAM        usDeviceAttr;
937
 
938
    if (DosQHandType (fp, &fsType, &usDeviceAttr))
939
        return DESCRIPTOR_UNKNOWN;
940
 
941
    if (LOBYTE (fsType) == HANDTYPE_PIPE)
942
        return DESCRIPTOR_PIPE;
943
 
944
    else if (LOBYTE (fsType) != HANDTYPE_DEVICE)
945
        return DESCRIPTOR_FILE;
946
 
947
/* The value 0x8083 seems to be the value returned by the console */
948
 
949
    else if (usDeviceAttr == 0x8083)
950
        return DESCRIPTOR_CONSOLE;
951
 
952
    else
953
        return DESCRIPTOR_DEVICE;
954
}
955
#endif
956
 
957
/* NT version */
958
 
959
#if (OS_TYPE == OS_NT)
960
int      GetDescriptorType (int fp)
961
{
962
    DWORD               fdwMode;
963
    HANDLE              osfp = (HANDLE)_get_osfhandle (fp);
964
 
965
    switch (GetFileType (osfp))
966
    {
967
        default:
968
            return DESCRIPTOR_UNKNOWN;
969
 
970
        case FILE_TYPE_DISK:
971
            return DESCRIPTOR_FILE;
972
 
973
        case FILE_TYPE_PIPE:
974
            return DESCRIPTOR_PIPE;
975
 
976
        case FILE_TYPE_CHAR:
977
        {
978
            if (!GetConsoleMode (osfp, &fdwMode))
979
                return DESCRIPTOR_DEVICE;
980
 
981
            else
982
                return DESCRIPTOR_CONSOLE;
983
        }
984
    }
985
}
986
#endif
987
 
988
/* DOS Version */
989
 
990
#if (OS_TYPE == OS_DOS)
991
int      GetDescriptorType (int fp)
992
{
993
    union REGS  r;
994
 
995
    r.x.REG_AX = 0x4400;
996
    r.x.REG_BX = fp;
997
    DosInterrupt (&r, &r);
998
 
999
    if (r.x.REG_CFLAGS)
1000
        return DESCRIPTOR_UNKNOWN;
1001
 
1002
    if ((r.x.REG_DX & 0x0080) == 0)
1003
        return DESCRIPTOR_FILE;
1004
 
1005
    if ((r.x.REG_DX & 0x0081) != 0x0081)
1006
        return DESCRIPTOR_DEVICE;
1007
 
1008
/*
1009
 * Check to see if the console is really the console or something else.
1010
 * Look at /dev/con and see if the console i/o bits are set
1011
 */
1012
 
1013
    r.x.REG_AX = 0x4400;
1014
    r.x.REG_BX = open ("con", 0);
1015
    DosInterrupt (&r, &r);
1016
    close (r.x.REG_BX);
1017
 
1018
    if ((r.x.REG_CFLAGS) || ((r.x.REG_DX & 0x0083) != 0x0083))
1019
        return DESCRIPTOR_DEVICE;
1020
 
1021
    return DESCRIPTOR_CONSOLE;
1022
}
1023
#endif
1024
 
1025
/* UNIX Version */
1026
 
1027
#if (OS_TYPE == OS_UNIX)
1028
int      GetDescriptorType (int fp)
1029
{
1030
    struct stat         s;
1031
 
1032
    if (fstat (fp, &s) != 0) 
1033
        return DESCRIPTOR_UNKNOWN;
1034
 
1035
    else if (S_ISREG (s.st_mode))
1036
        return DESCRIPTOR_FILE;
1037
 
1038
    else if (S_ISCHR (s.st_mode))
1039
        return DESCRIPTOR_CONSOLE;
1040
 
1041
    return DESCRIPTOR_UNKNOWN;
1042
}
1043
#endif
1044
 
1045
/*
1046
 * Get the current drive number
1047
 */
1048
 
1049
#if (OS_TYPE == OS_OS2)
1050
unsigned int GetCurrentDrive (void)
1051
{
1052
    OSCALL_PARAM        usDisk;
1053
    ULONG               ulDrives;
1054
 
1055
    DosQCurDisk (&usDisk, &ulDrives);        /* gets current drive        */
1056
 
1057
    return (unsigned int)usDisk;
1058
}
1059
#endif
1060
 
1061
/* NT Version */
1062
 
1063
#if (OS_TYPE == OS_NT)
1064
unsigned int GetCurrentDrive (void)
1065
{
1066
    char        szCurDir [MAX_PATH];
1067
 
1068
    GetCurrentDirectory (MAX_PATH, szCurDir);
1069
 
1070
    return szCurDir[0] - 'A' + 1;
1071
}
1072
#endif
1073
 
1074
/* DOS Version */
1075
 
1076
#if (OS_TYPE == OS_DOS)
1077
unsigned int GetCurrentDrive (void)
1078
{
1079
#  if defined (__TURBOC__)
1080
    return (unsigned int)getdisk () + 1;
1081
 
1082
#  elif defined (__EMX__)
1083
 
1084
    union REGS          r;
1085
 
1086
    r.h.ah = 0x19;
1087
    DosInterrupt (&r, &r);
1088
    return r.h.al + 1;
1089
 
1090
#  else
1091
 
1092
    unsigned int        CurrentDrive;
1093
 
1094
    _dos_getdrive (&CurrentDrive);
1095
 
1096
    return CurrentDrive;
1097
#  endif
1098
}
1099
#endif
1100
 
1101
/*
1102
 * Set the current drive number and return the number of drives.
1103
 */
1104
 
1105
#if (OS_TYPE == OS_OS2)
1106
int     SetCurrentDrive (unsigned int drive)
1107
{
1108
    OSCALL_RET          usError;
1109
    OSCALL_PARAM        usDisk;
1110
    FSALLOCATE          FsBlock;
1111
    ULONG               ulDrives;
1112
    int                 i;
1113
 
1114
/* Check the drive exists */
1115
 
1116
    DISABLE_HARD_ERRORS;
1117
    usError = DosQFSInfo (drive, FSIL_ALLOC, (PBYTE)&FsBlock,
1118
                          sizeof (FSALLOCATE));
1119
    ENABLE_HARD_ERRORS;
1120
 
1121
    if (usError || DosSelectDisk ((USHORT)drive))
1122
        return -1;
1123
 
1124
/* Get the current disk and check that to see the number of drives */
1125
 
1126
    DosQCurDisk (&usDisk, &ulDrives);        /* gets current drive        */
1127
 
1128
    for (i = 25; (!(ulDrives & (1L << i))) && i >= 0; --i)
1129
        continue;
1130
 
1131
    return i + 1;
1132
}
1133
#endif
1134
 
1135
/* NT Version */
1136
 
1137
#if (OS_TYPE == OS_NT)
1138
int     SetCurrentDrive (unsigned int drive)
1139
{
1140
    char                szNewDrive[3];
1141
    DWORD               dwLogicalDrives;
1142
    int                 i;
1143
 
1144
    szNewDrive[0] = drive + 'A' - 1;
1145
    szNewDrive[1] = CHAR_DRIVE;
1146
    szNewDrive[2] = 0;
1147
 
1148
    if (!SetCurrentDirectory (szNewDrive))
1149
        return -1;
1150
 
1151
    dwLogicalDrives = GetLogicalDrives();
1152
 
1153
    for (i = 25; (!(dwLogicalDrives & (1L << i))) && i >= 0; --i)
1154
        continue;
1155
 
1156
    return i + 1;
1157
}
1158
#endif
1159
 
1160
/* DOS Version */
1161
 
1162
#if (OS_TYPE == OS_DOS)
1163
int     SetCurrentDrive (unsigned int drive)
1164
{
1165
#  if defined (__TURBOC__)
1166
 
1167
   return setdisk (drive - 1);
1168
 
1169
#  elif defined (__EMX__)
1170
 
1171
    union REGS          r;
1172
 
1173
    r.h.ah = 0x0e;
1174
    r.h.dl = drive;
1175
    DosInterrupt (&r, &r);
1176
    return r.h.al;
1177
 
1178
#  else
1179
 
1180
    unsigned int        ndrives;
1181
 
1182
    _dos_setdrive (drive, &ndrives);
1183
 
1184
    return (int)ndrives;
1185
#  endif
1186
}
1187
#endif
1188
 
1189
/*
1190
 * Get and process configuration line:
1191
 *
1192
 * <field> = <field> <field> # comment
1193
 *
1194
 * return the number of fields found.
1195
 */
1196
 
1197
int     ExtractFieldsFromLine (LineFields *fd)
1198
{
1199
    char        *cp;
1200
    int         len;
1201
    Word_B      *wb;
1202
 
1203
    if (fgets (fd->Line, fd->LineLength - 1, fd->FP) == (char *)NULL)
1204
    {
1205
        CloseFile (fd->FP);
1206
        return -1;
1207
    }
1208
 
1209
/* Remove the EOL */
1210
 
1211
    if ((cp = strchr (fd->Line, CHAR_NEW_LINE)) != (char *)NULL)
1212
        *cp = 0;
1213
 
1214
/* Remove the comments at end */
1215
 
1216
    if ((cp = strchr (fd->Line, CHAR_COMMENT)) != (char *)NULL)
1217
        *cp = 0;
1218
 
1219
/* Extract the fields */
1220
 
1221
    if (fd->Fields != (Word_B *)NULL)
1222
        fd->Fields->w_nword = 0;
1223
 
1224
    fd->Fields = SplitString (fd->Line, fd->Fields);
1225
 
1226
    if (WordBlockSize (fd->Fields) < 2)
1227
        return 1;
1228
 
1229
/* Check for =.  At end of first field? */
1230
 
1231
    wb = fd->Fields;
1232
    len = strlen (wb->w_words[0]) - 1;
1233
 
1234
    if (wb->w_words[0][len] == CHAR_ASSIGN)
1235
        wb->w_words[0][len] = 0;
1236
 
1237
/* Check second field for just being equals */
1238
 
1239
    if (strcmp (wb->w_words[1], "=") == 0)
1240
    {
1241
        if ((--(wb->w_nword)) > 1)
1242
            memcpy (wb->w_words + 1, wb->w_words + 2,
1243
                    (wb->w_nword - 1) * sizeof (void *));
1244
    }
1245
 
1246
/* Check the second field for starting with an equals */
1247
 
1248
    else if (*(wb->w_words[1]) == CHAR_ASSIGN)
1249
        strcpy (wb->w_words[1], wb->w_words[1] + 1);
1250
 
1251
    return wb->w_nword;
1252
}
1253
 
1254
/*
1255
 * Split the string up into words
1256
 */
1257
 
1258
Word_B *SplitString (char *string, Word_B *wb)
1259
{
1260
    while (*string)
1261
    {
1262
        while (isspace (*string))
1263
            *(string++) = 0;
1264
 
1265
        if (*string)
1266
            wb = AddWordToBlock (string, wb);
1267
 
1268
        string = SkipToWhiteSpace (string);
1269
    }
1270
 
1271
    return wb;
1272
}
1273
 
1274
/*
1275
 * Test to see if a file is a directory
1276
 */
1277
 
1278
bool    IsDirectory (const char *Name)
1279
{
1280
    struct stat         s;
1281
 
1282
    return C2bool (S_stat (Name, &s) && S_ISDIR (s.st_mode & S_IFMT));
1283
}
1284
 
1285
/*
1286
 * Check that filename conforms to DOS format.  Convert additional .'s to ~.
1287
 */
1288
 
1289
#if (OS_TYPE != OS_UNIX)
1290
const char *CheckDOSFileName (const char *name, char *tmp)
1291
{
1292
    static char tname[ MAX_PATH ];
1293
    char        *s;
1294
    char        *s1;
1295
    int         count = 0;
1296
 
1297
    if (tmp == NULL)
1298
        tmp = tname;
1299
    (void) strncpy(tmp, name, MAX_PATH);
1300
    tmp[ MAX_PATH-1 ] = '\0';
1301
 
1302
#if !defined(WIN32)
1303
    if (!IsHPFSFileSystem (tmp))
1304
    {
1305
 
1306
/* Find start of file name */
1307
 
1308
        if ((s = FindLastPathCharacter (tmp)) == (char *)NULL)
1309
            s = tmp;
1310
 
1311
        else
1312
            ++s;
1313
 
1314
/* Skip over the directory entries */
1315
 
1316
        if ((strcmp (s, CurrentDirLiteral) == 0) ||
1317
            (strcmp (s, ParentDirLiteral) == 0))
1318
            /*SKIP*/;
1319
 
1320
/* Name starts with a dot? */
1321
 
1322
        else if (*s == CHAR_PERIOD)
1323
            count = 2;
1324
 
1325
/* Count the number of dots */
1326
 
1327
        else
1328
        {
1329
            s1 = s;
1330
 
1331
            while ((s1 = strchr (s1, CHAR_PERIOD)) != (char *)NULL)
1332
            {
1333
                count++;
1334
                s1++;
1335
            }
1336
        }
1337
 
1338
/* Check the dot count */
1339
 
1340
        if (count > 1)
1341
        {
1342
            if (!FL_TEST (FLAG_WARNING))
1343
                fprintf(stderr, "sh: File <%s> has too many dots, changed to ",
1344
                         tmp);
1345
 
1346
/* Transform the very first if necessary */
1347
 
1348
            if (*s == CHAR_PERIOD)
1349
                *s = CHAR_TILDE;
1350
 
1351
            s1 = s;
1352
            count = 0;
1353
 
1354
/* Convert all except the first */
1355
 
1356
            while ((s1 = strchr (s1, CHAR_PERIOD)) != (char *)NULL)
1357
            {
1358
                if (++count != 1)
1359
                    *s1 = CHAR_TILDE;
1360
 
1361
                s1++;
1362
            }
1363
 
1364
            if (!FL_TEST (FLAG_WARNING))
1365
                PrintWarningMessage ("<%s>", tmp);
1366
        }
1367
    }
1368
#endif  /*WIN32*/
1369
 
1370
/* Check for double slashes */
1371
 
1372
    s = tmp;
1373
 
1374
    while ((s = FindPathCharacter (s)) != (char *)NULL)
1375
    {
1376
        if (IsPathCharacter (*(++s)))
1377
            strcpy (s, s + 1);
1378
    }
1379
 
1380
    return tmp;
1381
}
1382
#endif
1383
 
1384
/*
1385
 * Get a valid numeric value
1386
 */
1387
 
1388
bool    ConvertNumericValue (char *string, long *value, int base)
1389
{
1390
    char        *ep;
1391
 
1392
    *value = strtol (string, &ep, base);
1393
 
1394
    return C2bool (!*ep);
1395
}
1396
 
1397
/*
1398
 * Character types - replaces is???? functions
1399
 */
1400
 
1401
void    SetCharacterTypes (char *String, int Type)
1402
{
1403
    int         i;
1404
 
1405
/*
1406
 * If we're changing C_IFS (interfield separators), clear them all
1407
 */
1408
 
1409
    if ((Type & C_IFS))
1410
    {
1411
        for (i = 0; i < UCHAR_MAX+1; i++)
1412
            CharTypes[i] &=~ C_IFS;
1413
 
1414
        CharTypes[0] |= C_IFS;                  /* include \0 as an C_IFS */
1415
    }
1416
 
1417
 /*
1418
  * Allow leading \0 in string
1419
  */
1420
 
1421
    CharTypes[(unsigned char) *(String++)] |= Type;
1422
 
1423
    while (*String != 0)
1424
        CharTypes[(unsigned char) *(String++)] |= Type;
1425
}
1426
 
1427
/*
1428
 * Initialise the Ctypes values
1429
 */
1430
 
1431
void    InitialiseCharacterTypes ()
1432
{
1433
    int         c;
1434
 
1435
    memset (CharTypes, 0, UCHAR_MAX);
1436
 
1437
    for (c = 'a'; c <= 'z'; c++)
1438
        CharTypes[c] = C_ALPHA;
1439
 
1440
    for (c = 'A'; c <= 'Z'; c++)
1441
        CharTypes[c] = C_ALPHA;
1442
 
1443
    CharTypes['_'] = C_ALPHA;
1444
    CharTypes[';'] = C_SEMICOLON;
1445
    SetCharacterTypes ("0123456789", C_DIGIT);
1446
    SetCharacterTypes ("\0 \t\n|&;<>()", C_LEX1);
1447
    SetCharacterTypes ("*@#!$-?", C_VAR1);
1448
    SetCharacterTypes ("=-+?#%", C_SUBOP);
1449
    SetCharacterTypes ("?*[", C_WILD);
1450
}
1451
 
1452
/*
1453
 * Word Block Functions
1454
 *
1455
 * Add a new word to a Word Block or list
1456
 */
1457
 
1458
Word_B *AddWordToBlock (char *wd, Word_B *wb)
1459
{
1460
 
1461
/* Do we require more space ? */
1462
 
1463
    if ((wb == (Word_B *)NULL) || (wb->w_nword >= wb->w_bsize))
1464
    {
1465
        int     NewCount = (wb == (Word_B *)NULL) ? NSTART : wb->w_nword * 2;
1466
 
1467
        if ((wb = ReAllocateSpace (wb, (NewCount * sizeof (char *)) +
1468
                                         sizeof (Word_B))) == (Word_B *)NULL)
1469
            return (Word_B *)NULL;
1470
 
1471
        wb->w_bsize = NewCount;
1472
    }
1473
 
1474
/* Add to the list */
1475
 
1476
    wb->w_words[wb->w_nword++] = (void *)wd;
1477
    return wb;
1478
}
1479
 
1480
/*
1481
 * Get the number of words in a block
1482
 */
1483
 
1484
int     WordBlockSize (Word_B *wb)
1485
{
1486
    return (wb == (Word_B *)NULL) ? 0 : wb->w_nword;
1487
}
1488
 
1489
/*
1490
 * Convert a word block structure into a array of strings
1491
 */
1492
 
1493
char    **GetWordList (Word_B *wb)
1494
{
1495
    char        **wd;
1496
    int         nb;
1497
 
1498
/* If the word block is empty or does not exist, return no list */
1499
 
1500
    if (wb == (Word_B *)NULL)
1501
        return NOWORDS;
1502
 
1503
/* Get some space for the array and set it up */
1504
 
1505
    if (((nb = sizeof (char *) * wb->w_nword) == 0) ||
1506
        ((wd = (char **)GetAllocatedSpace (nb)) == (char **)NULL))
1507
    {
1508
        ReleaseMemoryCell ((void *)wb);
1509
        return NOWORDS;
1510
    }
1511
 
1512
    memcpy (wd, wb->w_words, nb);
1513
    ReleaseMemoryCell ((void *)wb);     /* perhaps should done by caller */
1514
    return wd;
1515
}
1516
 
1517
 
1518
/*
1519
 * Build up the parameter variables
1520
 */
1521
 
1522
Word_B *AddParameter (char *value, Word_B *wb, char *function)
1523
{
1524
    char        **NewArray;
1525
    int         Count;
1526
    int         i;
1527
 
1528
/* Add to block */
1529
 
1530
    if ((wb = AddWordToBlock (value, wb)) == (Word_B *)NULL)
1531
    {
1532
        fprintf (stderr, BasicErrorMessage, function, Outofmemory1);
1533
        return (Word_B *)NULL;
1534
    }
1535
 
1536
/* If not end, return */
1537
 
1538
    if (value != NOWORD)
1539
        return wb;
1540
 
1541
/* Get number of entries */
1542
 
1543
    Count = wb->w_nword - 1;
1544
 
1545
/* Convert to array */
1546
 
1547
    if ((NewArray = GetWordList (wb)) == NOWORDS)
1548
    {
1549
        fprintf (stderr, BasicErrorMessage, function, Outofmemory1);
1550
        return (Word_B *)NULL;
1551
    }
1552
 
1553
/* Release old array.  Note: never release entry zero */
1554
 
1555
    if (ParameterArray != NOWORDS)
1556
    {
1557
        for (i = 1; i < ParameterCount; ++i)
1558
            ReleaseMemoryCell ((void *)ParameterArray [i]);
1559
 
1560
        ReleaseMemoryCell ((void *)ParameterArray);
1561
    }
1562
 
1563
/* Set new array to no-release */
1564
 
1565
    for (i = 0; i < Count; ++i)
1566
        SetMemoryAreaNumber ((void *)NewArray[i], 0);
1567
 
1568
    SetMemoryAreaNumber ((void *)NewArray, 0);
1569
 
1570
/* Reset globals and environment */
1571
 
1572
    ParameterCount = Count - 1;
1573
    ParameterArray = NewArray;
1574
    SetVariableFromNumeric (ParameterCountVariable, (long)ParameterCount);
1575
    return wb;
1576
}
1577
 
1578
/*
1579
 * Is this a valid variable name
1580
 */
1581
 
1582
char    IsValidVariableName (char *s)
1583
{
1584
    if (!IS_VariableFC ((int)*s))
1585
        return *s;
1586
 
1587
    while (*s && IS_VariableSC ((int)*s))
1588
        ++s;
1589
 
1590
    return *s;
1591
}
1592
 
1593
/*
1594
 * File Open Stream Save
1595
 */
1596
 
1597
FILE    *FOpenFile (const char *name, const char *mode)
1598
{
1599
    FILE        *fp;
1600
 
1601
    DISABLE_HARD_ERRORS;
1602
    fp = fopen (name, mode);
1603
    ENABLE_HARD_ERRORS;
1604
 
1605
    if (fp != (FILE *)NULL)
1606
    {
1607
        SaveFileDescriptor (fp);
1608
        setvbuf (fp, (char *)NULL, _IOFBF, BUFSIZ);
1609
        ChangeFileDescriptorStatus (fileno (fp), TRUE);
1610
    }
1611
 
1612
    return fp;
1613
}
1614
 
1615
/*
1616
 * File D Open Stream Save
1617
 */
1618
 
1619
FILE    *ReOpenFile (int fid, const char *mode)
1620
{
1621
    FILE        *fp = fdopen (fid, mode);
1622
 
1623
    if (fp != (FILE *)NULL)
1624
    {
1625
        SaveFileDescriptor (fp);
1626
        setvbuf (fp, (char *)NULL, _IOFBF, BUFSIZ);
1627
    }
1628
 
1629
    return fp;
1630
}
1631
 
1632
/*
1633
 * File Close Stream Save
1634
 */
1635
 
1636
int     CloseFile (FILE *fp)
1637
{
1638
    Word_B      *wb = e.OpenStreams;
1639
    int         NEntries = WordBlockSize (wb);
1640
    int         i;
1641
 
1642
    for (i = 0; i < NEntries; i++)
1643
    {
1644
        if (wb->w_words[i] == (char *)fp)
1645
            wb->w_words[i] = (char *)NULL;
1646
    }
1647
 
1648
    ChangeFileDescriptorStatus (fileno (fp), FALSE);
1649
    return fclose (fp);
1650
}
1651
 
1652
/*
1653
 * Flush output streams
1654
 */
1655
 
1656
void    FlushStreams (void)
1657
{
1658
    fflush (stdout);
1659
    fflush (stderr);
1660
}
1661
 
1662
/*
1663
 * Save Descriptor in Environment
1664
 */
1665
 
1666
static void F_LOCAL SaveFileDescriptor (FILE *fp)
1667
{
1668
    Word_B      *wb = e.OpenStreams;
1669
    int         NEntries = WordBlockSize (wb);
1670
    int         i;
1671
 
1672
    for (i = 0; i < NEntries; i++)
1673
    {
1674
        if (wb->w_words[i] == (char *)NULL)
1675
        {
1676
            wb->w_words[i] = (char *)fp;
1677
            return;
1678
        }
1679
    }
1680
 
1681
    e.OpenStreams = AddWordToBlock ((char *)fp, wb);
1682
    SetMemoryAreaNumber ((void *)e.OpenStreams, 0);
1683
}
1684
 
1685
/*
1686
 * Local Stat function to do some additional checks
1687
 */
1688
 
1689
bool    S_stat (const char *FileName, struct stat *Status)
1690
{
1691
#if (OS_TYPE != OS_UNIX)
1692
    char        tname[ MAX_PATH ];
1693
#endif
1694
    int         rc;
1695
 
1696
    FileName = CheckDOSFileName (FileName, tname);
1697
    DISABLE_HARD_ERRORS;
1698
    rc = stat (FileName, Status);
1699
    ENABLE_HARD_ERRORS;
1700
 
1701
/*
1702
 * Watcom has a problem stat'ing the root directory!
1703
 */
1704
 
1705
#if defined (__WATCOMC__)       /* WatCom C                             */
1706
    if (rc)
1707
    {
1708
        char    *fullpath;
1709
        char    *cp;
1710
 
1711
        if ((fullpath = AllocateMemoryCell (FFNAME_MAX)) != (char *)NULL)
1712
        {
1713
            if (((cp = FindLastPathCharacter (strcpy (fullpath, FileName)))
1714
                     != (char *)NULL) &&
1715
                ((strcmp (++cp, ParentDirLiteral) == 0) ||
1716
                 (strcmp (cp, CurrentDirLiteral) == 0)))
1717
                    strcat (cp, "/");
1718
 
1719
/* Generate the full path */
1720
 
1721
            GenerateFullExecutablePath (fullpath);
1722
 
1723
/* Root directory is a special case */
1724
 
1725
            if (strcmp (fullpath + 1, ":\\.") == 0)
1726
                fullpath[3] = 0;
1727
 
1728
            DISABLE_HARD_ERRORS;
1729
            rc = stat (fullpath, Status);
1730
            ENABLE_HARD_ERRORS;
1731
            ReleaseMemoryCell (fullpath);
1732
        }
1733
    }
1734
#endif
1735
 
1736
    return rc ? FALSE : TRUE;
1737
}
1738
 
1739
/*
1740
 * Local access function to do some additional checks
1741
 */
1742
 
1743
bool    S_access (const char *FileName, int mode)
1744
{
1745
#if (OS_TYPE != OS_UNIX)
1746
    char        tname[ MAX_PATH ];
1747
#endif
1748
    int         rc;
1749
 
1750
    FileName = CheckDOSFileName (FileName, tname);
1751
    DISABLE_HARD_ERRORS;
1752
    rc = access (FileName, mode);
1753
    ENABLE_HARD_ERRORS;
1754
 
1755
    return rc ? FALSE : TRUE;
1756
}
1757
 
1758
/*
1759
 * Local change directory function to do some additional checks
1760
 */
1761
 
1762
bool    S_chdir (const char *PathName)
1763
{
1764
#if (OS_TYPE != OS_UNIX)
1765
    char        tname[ MAX_PATH ];
1766
#endif
1767
    int         rc;
1768
 
1769
    PathName = CheckDOSFileName (PathName, tname);
1770
    DISABLE_HARD_ERRORS;
1771
    rc = chdir (PathName);
1772
    ENABLE_HARD_ERRORS;
1773
 
1774
    return rc ? FALSE : TRUE;
1775
}
1776
 
1777
/*
1778
 * Local get current directory function to do some additional checks
1779
 *
1780
 * Assumes that PathName is a string of length PATH_MAX + 6.
1781
 */
1782
 
1783
bool    S_getcwd (char *PathName, int drive)
1784
{
1785
    char                *res = (char *)NULL;
1786
#if (OS_TYPE == OS_NT)
1787
    unsigned int        cdrive;
1788
#endif
1789
 
1790
#if defined (__TURBOC__)
1791
    *(strcpy (PathName, RootDirectory)) = GetDriveLetter (drive);
1792
#endif
1793
 
1794
    DISABLE_HARD_ERRORS;
1795
 
1796
#if (OS_TYPE != OS_UNIX)
1797
    if (drive)
1798
    {
1799
#  if defined (__TURBOC__)
1800
        res = getcurdir (drive, PathName + 3) ? (char *)NULL : PathName;
1801
#  elif (OS_TYPE != OS_NT)
1802
        res = _getdcwd (drive, PathName, PATH_MAX + 4);
1803
#  else
1804
        cdrive = GetCurrentDrive ();
1805
 
1806
        if (SetCurrentDrive (drive) != -1)
1807
        {
1808
            res = !GetCurrentDirectory (PATH_MAX + 4, PathName) ? (char *)NULL
1809
                                                                : PathName;
1810
            SetCurrentDrive (cdrive);
1811
        }
1812
#  endif
1813
    }
1814
 
1815
    else
1816
#  if defined (__EMX__)
1817
        res = _getdcwd (GetCurrentDrive (), PathName, PATH_MAX + 4);
1818
#  else
1819
        res = getcwd (PathName, PATH_MAX + 4);
1820
#  endif
1821
#else
1822
    res = getcwd (PathName, PATH_MAX + 4);
1823
#endif
1824
 
1825
    ENABLE_HARD_ERRORS;
1826
    PathName[PATH_MAX + 5] = 0;
1827
 
1828
/* Convert to Unix format */
1829
 
1830
    PATH_TO_UNIX (PathName);
1831
    PATH_TO_LOWER_CASE (PathName);
1832
 
1833
/* Drive letter in lower case */
1834
 
1835
#if (OS_TYPE != OS_UNIX)
1836
    *PathName = (char)tolower (*PathName);
1837
#endif
1838
 
1839
    return (res == (char *)NULL) ? FALSE : TRUE;
1840
}
1841
 
1842
/*
1843
 * Open the directory stream
1844
 *
1845
 *
1846
 * OS/2 version
1847
 */
1848
 
1849
#if (OS_TYPE == OS_OS2)
1850
DIR * _CDECL    opendir (name)
1851
const char      *name;
1852
{
1853
    DIR                 *dirp;
1854
    char                *last;
1855
    DIRCONT             *dp;
1856
    char                *nbuf;
1857
    HDIR                d_handle = HDIR_SYSTEM;
1858
    bool                HPFS;
1859
    int                 len = strlen (name);
1860
    unsigned long       rc;
1861
 
1862
#  if (OS_SIZE == OS_32)
1863
    FILEFINDBUF3        dtabuf;
1864
#    define DTA_NAME    dtabuf.achName
1865
    ULONG               d_count = 1;
1866
#  else
1867
    FILEFINDBUF         dtabuf;
1868
#    define DTA_NAME    dtabuf.achName
1869
    USHORT              d_count = 1;
1870
#  endif
1871
 
1872
    if (!len)
1873
    {
1874
        errno = ENOTDIR;
1875
        return (DIR *)NULL;
1876
    }
1877
 
1878
    if ((nbuf = AllocateMemoryCell (len + 5)) == (char *)NULL)
1879
        return (DIR *) NULL;
1880
 
1881
    strcpy (nbuf, name);
1882
    last = &nbuf[len - 1];
1883
 
1884
/* Ok, DOS is very picky about its directory names.  The following are
1885
 * valid.
1886
 *
1887
 *  c:/
1888
 *  c:.
1889
 *  c:name/name1
1890
 *
1891
 *  c:name/ is not valid
1892
 */
1893
 
1894
    if (((*last == CHAR_DOS_PATH) || IsPathCharacter (*last)) &&
1895
        (len > 1) && (!((len == 3) && IsDriveCharacter (name[1]))))
1896
        *(last--) = 0;
1897
 
1898
/* Check its a directory and get some space */
1899
 
1900
    if ((!IsDirectory (nbuf)) ||
1901
        ((dirp = (DIR *) AllocateMemoryCell (sizeof (DIR))) == (DIR *) NULL))
1902
    {
1903
        ReleaseMemoryCell (nbuf);
1904
        return (DIR *)NULL;
1905
    }
1906
 
1907
/* Set up to find everything */
1908
 
1909
    if ((*last != CHAR_DOS_PATH) && !IsPathCharacter (*last))
1910
        strcat (last, DirectorySeparator);
1911
 
1912
    strcat (last, "*.*");
1913
 
1914
/* For OS/2, find the file system type */
1915
 
1916
    HPFS = IsHPFSFileSystem (nbuf);
1917
 
1918
    dirp->dd_loc      = 0;
1919
    dirp->dd_cp       = (DIRCONT *) NULL;
1920
    dirp->dd_contents = (DIRCONT *) NULL;
1921
 
1922
    DISABLE_HARD_ERRORS;
1923
 
1924
#  if (OS_SIZE == OS_32)
1925
    rc = DosFindFirst (nbuf, &d_handle, OS_FILE_ATTRIBUTES, &dtabuf,
1926
                       sizeof (FILEFINDBUF3), &d_count, FIL_STANDARD);
1927
#  else
1928
    rc = DosFindFirst (nbuf, &d_handle, OS_FILE_ATTRIBUTES, &dtabuf,
1929
                       sizeof (FILEFINDBUF), &d_count, (ULONG)0);
1930
#  endif
1931
 
1932
    ENABLE_HARD_ERRORS;
1933
 
1934
    if (rc)
1935
    {
1936
        ReleaseMemoryCell (nbuf);
1937
        ReleaseMemoryCell (dirp);
1938
        return (DIR *) NULL;
1939
    }
1940
 
1941
/* Wander through the directory! */
1942
 
1943
    do
1944
    {
1945
        if (((dp = (DIRCONT *) AllocateMemoryCell (sizeof (DIRCONT)))
1946
                 == (DIRCONT *)NULL) ||
1947
            ((dp->_d_entry = StringCopy (DTA_NAME)) == null))
1948
        {
1949
            if (dp->_d_entry != (char *)NULL)
1950
                ReleaseMemoryCell ((char *)dp);
1951
 
1952
            ReleaseMemoryCell (nbuf);
1953
            FreeDirectoryListing (dirp->dd_contents);
1954
 
1955
            DosFindClose (d_handle);
1956
            return (DIR *) NULL;
1957
        }
1958
 
1959
        if (!HPFS)
1960
            strlwr (dp->_d_entry);
1961
 
1962
        if (dirp->dd_contents != (DIRCONT *) NULL)
1963
            dirp->dd_cp = dirp->dd_cp->_d_next = dp;
1964
 
1965
        else
1966
            dirp->dd_contents = dirp->dd_cp = dp;
1967
 
1968
        dp->_d_next = (DIRCONT *) NULL;
1969
 
1970
        d_count = 1;
1971
    } while (DosFindNext (d_handle, &dtabuf, sizeof (FILEFINDBUF),
1972
                          &d_count) == 0);
1973
 
1974
    dirp->dd_cp = dirp->dd_contents;
1975
    ReleaseMemoryCell (nbuf);
1976
 
1977
    DosFindClose (d_handle);
1978
    return dirp;
1979
}
1980
#endif
1981
 
1982
/*
1983
 * NT version (removed)
1984
 */
1985
 
1986
#if (OS_TYPE == OS_NT) && (0)
1987
DIR * _CDECL    opendir (name)
1988
const char      *name;
1989
{
1990
    DIR                 *dirp;
1991
    char                *last;
1992
    DIRCONT             *dp;
1993
    char                *nbuf;
1994
    HANDLE              d_handle;
1995
    bool                HPFS;
1996
    int                 len = strlen (name);
1997
    WIN32_FIND_DATA     dtabuf;
1998
 
1999
    if (!len)
2000
    {
2001
        errno = ENOTDIR;
2002
        return (DIR *)NULL;
2003
    }
2004
 
2005
    if ((nbuf = AllocateMemoryCell (len + 5)) == (char *)NULL)
2006
        return (DIR *) NULL;
2007
 
2008
    strcpy (nbuf, name);
2009
    last = &nbuf[len - 1];
2010
 
2011
/* Ok, DOS is very picky about its directory names.  The following are
2012
 * valid.
2013
 *
2014
 *  c:/
2015
 *  c:.
2016
 *  c:name/name1
2017
 *
2018
 *  c:name/ is not valid
2019
 */
2020
 
2021
    if (((*last == CHAR_DOS_PATH) || IsPathCharacter (*last)) &&
2022
        (len > 1) && (!((len == 3) && IsDriveCharacter (name[1]))))
2023
        *(last--) = 0;
2024
 
2025
/* Check its a directory and get some space */
2026
 
2027
    if ((!IsDirectory (nbuf)) ||
2028
        ((dirp = (DIR *) AllocateMemoryCell (sizeof (DIR))) == (DIR *) NULL))
2029
    {
2030
        ReleaseMemoryCell (nbuf);
2031
        return (DIR *)NULL;
2032
    }
2033
 
2034
/* Set up to find everything */
2035
 
2036
    if ((*last != CHAR_DOS_PATH) && !IsPathCharacter (*last))
2037
        strcat (last, DirectorySeparator);
2038
 
2039
    strcat (last, "*.*");
2040
 
2041
/* For OS/2, find the file system type */
2042
 
2043
    HPFS = IsHPFSFileSystem (nbuf);
2044
 
2045
    dirp->dd_loc      = 0;
2046
    dirp->dd_cp       = (DIRCONT *) NULL;
2047
    dirp->dd_contents = (DIRCONT *) NULL;
2048
 
2049
    DISABLE_HARD_ERRORS;
2050
    d_handle = FindFirstFile (nbuf, &dtabuf);
2051
    ENABLE_HARD_ERRORS;
2052
 
2053
    if (d_handle == INVALID_HANDLE_VALUE)
2054
    {
2055
        ReleaseMemoryCell (nbuf);
2056
        ReleaseMemoryCell (dirp);
2057
        return (DIR *) NULL;
2058
    }
2059
 
2060
/* Wander through the directory! */
2061
 
2062
    do
2063
    {
2064
        if (((dp = (DIRCONT *) AllocateMemoryCell (sizeof (DIRCONT)))
2065
                 == (DIRCONT *)NULL) ||
2066
            ((dp->_d_entry = StringCopy (dtabuf.cFileName)) == null))
2067
        {
2068
            if (dp->_d_entry != (char *)NULL)
2069
                ReleaseMemoryCell ((char *)dp);
2070
 
2071
            ReleaseMemoryCell (nbuf);
2072
            FreeDirectoryListing (dirp->dd_contents);
2073
 
2074
            FindClose (d_handle);
2075
            return (DIR *) NULL;
2076
        }
2077
 
2078
        if (!HPFS)
2079
            strlwr (dp->_d_entry);
2080
 
2081
        if (dirp->dd_contents != (DIRCONT *) NULL)
2082
            dirp->dd_cp = dirp->dd_cp->_d_next = dp;
2083
 
2084
        else
2085
            dirp->dd_contents = dirp->dd_cp = dp;
2086
 
2087
        dp->_d_next = (DIRCONT *) NULL;
2088
 
2089
    } while (FindNextFile (d_handle, &dtabuf));
2090
 
2091
    dirp->dd_cp = dirp->dd_contents;
2092
    ReleaseMemoryCell (nbuf);
2093
 
2094
    FindClose (d_handle);
2095
    return dirp;
2096
}
2097
#endif
2098
 
2099
/*
2100
 * DOS Version
2101
 */
2102
#if (OS_TYPE == OS_DOS) && !defined(__WATCOMC__)
2103
DIR * _CDECL    opendir (name)
2104
const char      *name;
2105
{
2106
    DIR                 *dirp;
2107
    char                *last;
2108
    DIRCONT             *dp;
2109
    char                *nbuf;
2110
    int                 len = strlen (name);
2111
    unsigned long       rc;
2112
 
2113
#  if defined (__TURBOC__)
2114
    struct ffblk                        dtabuf;
2115
#    define DTA_NAME                    dtabuf.ff_name
2116
#    define DIR_FINDNEXT(a)             findnext (a)
2117
#    define DIR_FINDFIRST(F,A,B)        findfirst (F, B, A)
2118
#  elif defined (__EMX__)
2119
    struct _find                        dtabuf;
2120
#    define DTA_NAME                    dtabuf.name
2121
#    define DIR_FINDNEXT(a)             __findnext (a)
2122
#    define DIR_FINDFIRST(F,A,B)        __findfirst (F, A, B)
2123
#  else
2124
    struct find_t                       dtabuf;
2125
#    define DTA_NAME                    dtabuf.name
2126
#    define DIR_FINDNEXT(a)             _dos_findnext (a)
2127
#    define DIR_FINDFIRST(F,A,B)        _dos_findfirst (F, A, B)
2128
#  endif
2129
 
2130
    if (!len)
2131
    {
2132
        errno = ENOTDIR;
2133
        return (DIR *)NULL;
2134
    }
2135
 
2136
    if ((nbuf = AllocateMemoryCell (len + 5)) == (char *)NULL)
2137
        return (DIR *) NULL;
2138
 
2139
    strcpy (nbuf, name);
2140
    last = &nbuf[len - 1];
2141
 
2142
/* Ok, DOS is very picky about its directory names.  The following are
2143
 * valid.
2144
 *
2145
 *  c:/
2146
 *  c:.
2147
 *  c:name/name1
2148
 *
2149
 *  c:name/ is not valid
2150
 */
2151
 
2152
    if (((*last == CHAR_DOS_PATH) || IsPathCharacter (*last)) &&
2153
        (len > 1) && (!((len == 3) && IsDriveCharacter (name[1]))))
2154
        *(last--) = 0;
2155
 
2156
/* Check its a directory and get some space */
2157
 
2158
    if ((!IsDirectory (nbuf)) ||
2159
        ((dirp = (DIR *) AllocateMemoryCell (sizeof (DIR))) == (DIR *) NULL))
2160
    {
2161
        ReleaseMemoryCell (nbuf);
2162
        return (DIR *)NULL;
2163
    }
2164
 
2165
/* Set up to find everything */
2166
 
2167
    if ((*last != CHAR_DOS_PATH) && !IsPathCharacter (*last))
2168
        strcat (last, DirectorySeparator);
2169
 
2170
    strcat (last, "*.*");
2171
 
2172
    dirp->dd_loc      = 0;
2173
    dirp->dd_cp       = (DIRCONT *) NULL;
2174
    dirp->dd_contents = (DIRCONT *) NULL;
2175
 
2176
    DISABLE_HARD_ERRORS;
2177
 
2178
    rc = DIR_FINDFIRST (nbuf, OS_FILE_ATTRIBUTES, &dtabuf);
2179
 
2180
    ENABLE_HARD_ERRORS;
2181
 
2182
    if (rc)
2183
    {
2184
        ReleaseMemoryCell (nbuf);
2185
        ReleaseMemoryCell (dirp);
2186
        return (DIR *) NULL;
2187
    }
2188
 
2189
    do
2190
    {
2191
        if (((dp = (DIRCONT *) AllocateMemoryCell (sizeof (DIRCONT)))
2192
                 == (DIRCONT *)NULL) ||
2193
            ((dp->_d_entry = StringCopy (DTA_NAME)) == null))
2194
        {
2195
            if (dp->_d_entry != (char *)NULL)
2196
                ReleaseMemoryCell ((char *)dp);
2197
 
2198
            ReleaseMemoryCell (nbuf);
2199
            FreeDirectoryListing (dirp->dd_contents);
2200
            return (DIR *) NULL;
2201
        }
2202
 
2203
        strlwr (dp->_d_entry);
2204
 
2205
        if (dirp->dd_contents != (DIRCONT *) NULL)
2206
            dirp->dd_cp = dirp->dd_cp->_d_next = dp;
2207
 
2208
        else
2209
            dirp->dd_contents = dirp->dd_cp = dp;
2210
 
2211
        dp->_d_next = (DIRCONT *) NULL;
2212
 
2213
    } while (DIR_FINDNEXT (&dtabuf) == 0);
2214
 
2215
    dirp->dd_cp = dirp->dd_contents;
2216
    ReleaseMemoryCell (nbuf);
2217
    return dirp;
2218
}
2219
#endif
2220
 
2221
/*
2222
 * Close the directory stream
2223
 */
2224
#if (OS_TYPE != OS_UNIX) && \
2225
       ((OS_TYPE == OS_DOS && !defined(__WATCOMC__)) || \
2226
        (OS_TYPE == OS_NT  && (0)) )
2227
int _CDECL      closedir (dirp)
2228
DIR             *dirp;
2229
{
2230
    if (dirp != (DIR *)NULL)
2231
    {
2232
        FreeDirectoryListing (dirp->dd_contents);
2233
        ReleaseMemoryCell ((char *)dirp);
2234
    }
2235
 
2236
    return 0;
2237
}
2238
 
2239
/*
2240
 * Read the next record from the stream
2241
 */
2242
struct dirent * _CDECL readdir (dirp)
2243
DIR             *dirp;
2244
{
2245
    static struct dirent        dp;
2246
 
2247
    if ((dirp == (DIR *)NULL) || (dirp->dd_cp == (DIRCONT *) NULL))
2248
        return (struct dirent *) NULL;
2249
 
2250
    dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
2251
    dp.d_off    = dirp->dd_loc * 32;
2252
    dp.d_ino    = (ino_t)++dirp->dd_loc;
2253
    dirp->dd_cp = dirp->dd_cp->_d_next;
2254
 
2255
    return &dp;
2256
}
2257
 
2258
 
2259
/*
2260
 * Release the internal structure
2261
 */
2262
static void     FreeDirectoryListing (dp)
2263
DIRCONT         *dp;
2264
{
2265
    DIRCONT     *odp;
2266
 
2267
    while ((odp = dp) != (DIRCONT *)NULL)
2268
    {
2269
        if (dp->_d_entry != (char *)NULL)
2270
            ReleaseMemoryCell (dp->_d_entry);
2271
 
2272
        dp = dp->_d_next;
2273
        ReleaseMemoryCell ((char *)odp);
2274
    }
2275
}
2276
#endif
2277
 
2278
/*
2279
 * For OS/2 and NT, we need to know if we have to convert to lower case.  This
2280
 * only applies to non-HPFS (FAT, NETWARE etc) file systems.
2281
 */
2282
 
2283
#if (OS_TYPE == OS_OS2) 
2284
/*
2285
 * Define the know FAT systems
2286
 */
2287
 
2288
static char     *FATSystems[] = {"FAT", "NETWARE", (char *)NULL};
2289
 
2290
/*
2291
 * Check for Long filenames
2292
 */
2293
 
2294
bool            IsHPFSFileSystem (char *directory)
2295
{
2296
    BYTE                bData[128];
2297
    BYTE                bName[3];
2298
    int                 i;
2299
    char                *FName;
2300
    unsigned long       rc;
2301
    OSCALL_PARAM        cbData;
2302
    unsigned int        nDrive;
2303
#  if (OS_SIZE == OS_32)
2304
    PFSQBUFFER2         pFSQ = (PFSQBUFFER2)bData;
2305
#  endif
2306
 
2307
/*
2308
 * Mike tells me there are IFS calls to determine this, but he carn't
2309
 * remember which.  So we read the partition info and check for HPFS.
2310
 */
2311
 
2312
    if (isalpha (directory[0]) && IsDriveCharacter (directory[1]))
2313
        nDrive = toupper (directory[0]) - '@';
2314
 
2315
    else
2316
        nDrive = GetCurrentDrive ();
2317
 
2318
/* Set up the drive name */
2319
 
2320
    bName[0] = (char) (nDrive + '@');
2321
    bName[1] = CHAR_DRIVE;
2322
    bName[2] = 0;
2323
 
2324
    cbData = sizeof (bData);
2325
 
2326
/* Read the info, if we fail - assume non-HPFS */
2327
 
2328
    DISABLE_HARD_ERRORS;
2329
 
2330
#  if (OS_SIZE == OS_32)
2331
    rc = DosQFSAttach (bName, 0, FSAIL_QUERYNAME, pFSQ, &cbData);
2332
#  else
2333
    rc = DosQFSAttach (bName, 0, FSAIL_QUERYNAME, bData, &cbData, 0L);
2334
#  endif
2335
 
2336
    ENABLE_HARD_ERRORS;
2337
 
2338
    if (rc)
2339
        return FALSE;
2340
 
2341
#  if (OS_SIZE == OS_32)
2342
    FName = pFSQ->szName + pFSQ->cbName + 1;
2343
#  else
2344
    FName = bData + (*((USHORT *) (bData + 2)) + 7);
2345
#  endif
2346
 
2347
    for (i = 0; FATSystems[i] != (char *)NULL; i++)
2348
    {
2349
        if (stricmp (FName, FATSystems[i]) == 0)
2350
            return FALSE;
2351
    }
2352
 
2353
    return TRUE;
2354
}
2355
#endif
2356
 
2357
/*
2358
 * Windows NT version (removed, see dirent services)
2359
 */
2360
#if (OS_TYPE == OS_NT) && (0)
2361
bool IsHPFSFileSystem (char *directory)
2362
{
2363
    char                bName[4];
2364
    DWORD               flags;
2365
    DWORD               maxname;
2366
    BOOL                rc;
2367
    unsigned int        nDrive;
2368
 
2369
/*
2370
 * Mike tells me there are IFS calls to determine this, but he carn't
2371
 * remember which.  So we read the partition info and check for HPFS.
2372
 */
2373
 
2374
    if (isalpha (directory[0]) && IsDriveCharacter (directory[1]))
2375
        nDrive = toupper (directory[0]) - '@';
2376
 
2377
    else
2378
        nDrive = GetCurrentDrive ();
2379
 
2380
/* Set up the drive name */
2381
 
2382
    bName[0] = (char) (nDrive + '@');
2383
    bName[1] = CHAR_DRIVE;
2384
    bName[2] = CHAR_DOS_PATH;
2385
    bName[3] = 0;
2386
 
2387
/* Read the volume info, if we fail - assume non-HPFS */
2388
 
2389
    DISABLE_HARD_ERRORS;
2390
 
2391
    rc = GetVolumeInformation (bName, (LPTSTR)NULL, 0, (LPDWORD)NULL,
2392
                               &maxname, &flags, (LPTSTR)NULL, 0);
2393
    ENABLE_HARD_ERRORS;
2394
 
2395
    return C2bool ((rc) && (flags & FS_CASE_SENSITIVE));
2396
}
2397
#endif
2398
 
2399
 
2400
/*
2401
 * Get directory on drive x
2402
 */
2403
 
2404
#if defined (__WATCOMC__)
2405
char    *_getdcwd (int drive, char *PathName, int len)
2406
{
2407
    char                TPath [PATH_MAX + 3];
2408
#  if (OS_TYPE == OS_DOS)
2409
    union REGS          r;
2410
 
2411
/* This is really a bit of a cheat.  I'm not sure why it works, but is
2412
 * does.  The missing bit is that you really should set the DS register up
2413
 * but that causes a memory violation. SO!!
2414
 */
2415
 
2416
    r.x.REG_AX = 0x4700;
2417
    r.h.dl = drive;
2418
#ifdef __386__
2419
    r.x.esi = FP_OFF (TPath);
2420
#else
2421
    r.x.si = FP_OFF (TPath);
2422
#endif
2423
 
2424
    DosInterrupt (&r, &r);
2425
 
2426
    if (r.x.cflag & INTR_CF)
2427
        return (char *)NULL;
2428
 
2429
#  else
2430
    ULONG       cbBuf = PATH_MAX + 3;
2431
 
2432
    if (DosQueryCurrentDir (drive, TPath, &cbBuf))
2433
        return (char *)NULL;
2434
#  endif
2435
 
2436
/* Insert the drive and root directory */
2437
 
2438
    *(strcpy (PathName, RootDirectory)) = GetDriveLetter (drive);
2439
    return strcat (PathName, TPath);
2440
}
2441
#endif
2442
 
2443
#if defined (__EMX__) 
2444
char    *_getdcwd (int drive, char *PathName, int len)
2445
{
2446
    char                TPath [PATH_MAX + 3];
2447
 
2448
    if (_getcwd1 (TPath, drive + 'A' - 1) != 0)
2449
        return (char *)NULL;
2450
 
2451
/* Insert the drive and root directory */
2452
 
2453
    *(strcpy (PathName, RootDirectory)) = GetDriveLetter (drive);
2454
    return strcpy (PathName + 2, TPath);
2455
}
2456
#endif
2457
 
2458
/*
2459
 *  MODULE ABSTRACT: _setargv
2460
 *
2461
 *  UNIX like command line expansion
2462
 */
2463
 
2464
/*
2465
 * OS/2 2.x (32-bit) version
2466
 */
2467
 
2468
#if (OS_TYPE == OS_OS2)
2469
#  if (OS_SIZE == OS_32)
2470
void    ENTRY_POINT (void)
2471
{
2472
    APIRET      rc;
2473
    PTIB        ptib;
2474
    PPIB        ppib;
2475
    char        *MName;
2476
    Word_B      *Alist = (Word_B *)NULL;
2477
 
2478
/* Get the command line and program name */
2479
 
2480
    if ((rc = DosGetInfoBlocks (&ptib, &ppib)))
2481
        PrintErrorMessage ("DosGetInfoBlocks: Cannot find command line\n%s\n",
2482
                           GetOSSystemErrorMessage (rc));
2483
 
2484
    if ((MName = GetAllocatedSpace (FFNAME_MAX)) == (char *)NULL)
2485
        PrintErrorMessage (Outofmemory1);
2486
 
2487
    if ((rc = DosQueryModuleName (ppib->pib_hmte, FFNAME_MAX - 1, MName)))
2488
        PrintErrorMessage ("DosQueryModuleName: Cannot get program name\n%s\n",
2489
                           GetOSSystemErrorMessage (rc));
2490
 
2491
/* Save the program name and process the command line */
2492
 
2493
    _APgmName = MName;
2494
    _Ex_ProcessEMXArguments (ppib->pib_pchcmd, &Alist);
2495
 
2496
/* Terminate */
2497
 
2498
    _Ex_SaveArgvValue ((char *)NULL, FALSE, &Alist);
2499
}
2500
 
2501
#  else /* (OS_SIZE == OS_16) */
2502
 
2503
/*
2504
 * OS/2 1.x (16-bit) version
2505
 */
2506
 
2507
void    ENTRY_POINT (void)
2508
{
2509
    char far            *argvp = (char far *)((((long)_aenvseg) << 16));
2510
    ushort              off = _acmdln;
2511
    Word_B              *Alist = (Word_B *)NULL;
2512
 
2513
    while (--off)
2514
    {
2515
        if (argvp[off - 1] == 0)
2516
            break;
2517
    }
2518
 
2519
/* Add program name */
2520
 
2521
    _APgmName =  &argvp[off];
2522
 
2523
    if (argvp[_acmdln] == 0)
2524
        _Ex_SaveArgvValue (_APgmName, TRUE, &Alist);
2525
 
2526
    else
2527
    {
2528
        argvp += _acmdln;
2529
        _Ex_ProcessEMXArguments (argvp, &Alist);
2530
    }
2531
 
2532
/* Terminate */
2533
 
2534
    _Ex_SaveArgvValue ((char *)NULL, FALSE, &Alist);
2535
}
2536
#  endif
2537
 
2538
#elif (OS_TYPE == OS_DOS)
2539
/*
2540
 * MSDOS version
2541
 */
2542
void    ENTRY_POINT (void)
2543
{
2544
    Word_B              *Alist = (Word_B *)NULL;
5659 dpurdie 2545
    char                *s = 0;             /* Temporary string pointer     */
227 dpurdie 2546
 
2547
#  if defined (__WATCOMC__)
2548
    {
2549
        extern void __setenvp(void);    /* sets up environ              */
2550
        __setenvp();                    /* found by grovelling          */
2551
    }
2552
    _ACmdLine = _LpCmdLine;
2553
    s = _LpPgmName;
2554
 
2555
#  elif (OS_SIZE == OS_16)
2556
                                        /* Set up pointer to command line */
2557
    unsigned int        envs = *(int far *)((((long)_psp) << 16) + 0x02cL);
2558
    union REGS          r;
2559
    unsigned int        Length;
2560
 
2561
/* For reasons that escape me, MSC 6.0 does sets up _osmajor and _osminor
2562
 * in the command line parser!
2563
 */
2564
 
2565
    r.h.ah = 0x30;
2566
    DosInterrupt (&r, &r);
2567
    _osminor = r.h.ah;
2568
    _osmajor = r.h.al;
2569
 
2570
/* Check the length */
2571
 
2572
    _ACmdLine = (char *)((((long)_psp) << 16) + 0x080L);
2573
 
2574
    if ((Length = (unsigned int)*(_ACmdLine++)) > 127)
2575
        Length = 127;
2576
 
2577
    _ACmdLine[Length] = 0;
2578
 
2579
/* Command line can be null or 0x0d terminated - convert to null */
2580
 
2581
    if ((s = strchr (_ACmdLine, CHAR_RETURN)) != (char *)NULL)
2582
        *s = 0;
2583
 
2584
/* Get the program name */
2585
 
2586
    if ((_osmajor <= 2) || (envs == 0))
2587
        s = "unknown";
2588
 
2589
/* In the case of DOS 3+, we look in the environment space */
2590
 
2591
    else
2592
    {
2593
        s = (char far *)(((long)envs) << 16);
2594
 
2595
        while (*s)
2596
        {
2597
            while (*(s++) != 0)
2598
                continue;
2599
        }
2600
 
2601
        s += 3;
2602
    }
2603
# endif
2604
 
2605
/* Add the program name */
2606
 
2607
    _APgmName = s;
2608
    _Ex_SaveArgvValue (s, TRUE, &Alist);
2609
    _Ex_CommandLine (_ACmdLine, &Alist);
2610
    _Ex_SaveArgvValue ((char *)NULL, FALSE, &Alist);
2611
}
2612
 
2613
#elif (OS_TYPE == OS_NT)
2614
/*
2615
 *  NT version
2616
 */
2617
void ENTRY_POINT (void)
2618
{
2619
    char        *MName;
2620
    Word_B      *Alist = (Word_B *)NULL;
2621
 
2622
    _ACmdLine = GetCommandLine ();
2623
 
2624
/* Get the command line and program name */
2625
 
2626
    if ((MName = GetAllocatedSpace (MAX_PATH)) == (char *)NULL)
2627
        PrintErrorMessage (Outofmemory1);
2628
 
2629
    if (!GetModuleFileName (0, MName, MAX_PATH))
2630
        PrintErrorMessage ("GetModuleFileName: Cannot get program name\n%s\n",
2631
                GetOSSystemErrorMessage (GetLastError ()));
2632
 
2633
/* Save the program name and process the command line */
2634
 
2635
    _APgmName = MName;
2636
 
2637
    if (*_ACmdLine)
2638
        _Ex_CommandLine (_ACmdLine, &Alist);
2639
 
2640
    else
2641
        _Ex_SaveArgvValue (MName, TRUE, &Alist);
2642
 
2643
    _Ex_SaveArgvValue ((char *)NULL, FALSE, &Alist);
2644
}
2645
#endif
2646
 
2647
 
2648
/*
2649
 * A fix for EMX, so that startup gets the arguments, I hope.
2650
 *
2651
 * Initialize the C run-time library.  This function is called from crt0.s.
2652
 * We know argc and argv are on the stack, and crt0.s does not remove them
2653
 * from the start before calling main, so we just replace the values, I
2654
 * hope.
2655
 */
2656
 
2657
#if defined (__EMX__)
2658
void    _startup (int argc, char **argv)
2659
{
2660
    int         i, j;
2661
 
2662
/*
2663
 * Print a warning message on handle 2 (stderr) if emx.dll or
2664
 * emx.exe is out of date.
2665
 */
2666
 
2667
    if (_emx_vcmp < 0x302e3868)   /* 0.8h */
2668
        __write (2, _version_warning, strlen (_version_warning));
2669
/*
2670
 * Fix the stack
2671
 */
2672
 
2673
#  if defined (EMX_DOS)
2674
   for (i = 0; i < argc; i++)
2675
   {
2676
       __write (2, "arg = <", 7);
2677
       __write (2, argv[i], strlen (argv[i]));
2678
       __write (2, ">\n", 2);
2679
   }
2680
#  else
2681
    GetArgcV ();
2682
    argc = ARG_COUNT;
2683
    argv = ARG_ARRAY;
2684
#  endif
2685
 
2686
/* Initialize the file handles and the streams. */
2687
 
2688
    for (i = 0; i < _nfiles; ++i)
2689
    {
2690
        _files[i] = 0;
2691
        _lookahead[i] = -1;
2692
        _streamv[i].flags = 0;
2693
 
2694
/*
2695
 * Get the handle type.  If this fails, the handle is not open.
2696
 */
2697
 
2698
        if (ioctl (i, FGETHTYPE, &j) >= 0)
2699
        {
2700
            _files[i] |= O_TEXT;
2701
 
2702
            if (HT_ISDEV (j))
2703
                _files[i] |= F_DEV;
2704
 
2705
            if (j == HT_NPIPE)
2706
                _files[i] |= F_NPIPE;
2707
 
2708
            _streamv[i].flags |= _IOOPEN;
2709
            _streamv[i].ptr = NULL;
2710
            _streamv[i].buffer = NULL;
2711
            _streamv[i].rcount = 0;
2712
            _streamv[i].wcount = 0;
2713
            _streamv[i].handle = i;
2714
            _streamv[i].buf_size = 0;
2715
            _streamv[i].tmpidx = 0;
2716
            _streamv[i].pid = 0;
2717
            _streamv[i].flush = _flushstream;
2718
 
2719
            switch (i)
2720
            {
2721
 
2722
/*
2723
 * stdin is always buffered.
2724
 */
2725
 
2726
                case 0:
2727
                    _files[0] |= O_RDONLY;
2728
                    _streamv[0].flags |= _IOREAD | _IOFBF | _IOBUFUSER;
2729
                    _streamv[0].ptr = ibuf;
2730
                    _streamv[0].buffer = ibuf;
2731
                    _streamv[0].buf_size = BUFSIZ;
2732
                    break;
2733
 
2734
/*
2735
 * stdout is buffered unless it's connected to a device.
2736
 */
2737
                case 1:                 
2738
                    _files[i] |= O_WRONLY;
2739
                    _streamv[i].flags |= (_IOWRT | _IOBUFNONE |
2740
                                          (HT_ISDEV (j) ? _IONBF : _IOFBF));
2741
                    break;
2742
 
2743
/*
2744
 * stderr is always unbuffered.
2745
 */
2746
                case 2:
2747
                    _files[i] |= O_WRONLY;
2748
                    _streamv[i].flags |= _IOWRT | _IOBUFNONE | _IONBF;
2749
                    break;
2750
 
2751
/*
2752
 * All other handles can be read and written.  A handle is buffered
2753
 * unless it's connected to a device.
2754
 */
2755
 
2756
                default:
2757
                    _files[i] |= O_RDWR;
2758
                    _streamv[i].flags |= (_IORW | _IOBUFNONE |
2759
                                            (HT_ISDEV (j) ? _IONBF : _IOFBF));
2760
                    break;
2761
            }
2762
        }
2763
    }
2764
}
2765
#endif
2766
 
2767
/*
2768
 * Expand the DOS Command line
2769
 */
2770
 
2771
#if (OS_TYPE != OS_UNIX)
2772
static void F_LOCAL _Ex_CommandLine (char *argvp, Word_B **Alist)
2773
{
2774
    char        *spos;                  /* End of string pointer        */
2775
    char        *cpos;                  /* Start of string pointer      */
2776
    char        *tpos;
2777
    char        *fn;                    /* Extracted file name string   */
2778
 
2779
/* Search for next separator */
2780
 
2781
    spos = argvp;
2782
 
2783
    while (*(cpos = _Ex_SkipWhiteSpace (spos)))
2784
    {
2785
 
2786
/* Extract string argument */
2787
 
2788
        if ((*cpos == CHAR_DOUBLE_QUOTE) || (*cpos == CHAR_SINGLE_QUOTE))
2789
        {
2790
            spos = cpos + 1;
2791
 
2792
            do
2793
            {
2794
                if ((spos = strchr (spos, *cpos)) != NULL)
2795
                {
2796
                    spos++;
2797
                    if (spos[-2] != CHAR_META)
2798
                        break;
2799
                }
2800
 
2801
                else
2802
                    spos = &spos[strlen (cpos)];
2803
 
2804
            } while (*spos);
2805
 
2806
            fn  = _Ex_GetSpace (spos - cpos - 2, cpos + 1);
2807
 
2808
/* Remove escaped characters */
2809
 
2810
           tpos = fn;
2811
 
2812
           while ((tpos = strchr (tpos, *cpos)) != (char *)NULL)
2813
               strcpy (tpos - 1, tpos);
2814
        }
2815
 
2816
/* Extract normal argument */
2817
 
2818
        else
2819
        {
2820
            spos = SkipToWhiteSpace (cpos);
2821
            fn = _Ex_GetSpace (spos - cpos, cpos);
2822
        }
2823
 
2824
/* Process argument */
2825
 
2826
        if (*cpos != CHAR_SINGLE_QUOTE)
2827
            fn = _Ex_ConvertEnvVariables (fn);
2828
 
2829
        switch (*cpos)
2830
        {
2831
            case CHAR_INDIRECT:         /* Expand file                  */
2832
                _Ex_ExpandIndirectFile (fn, Alist);
2833
                break;
2834
 
2835
            case CHAR_DOUBLE_QUOTE:     /* Expand string                */
2836
            case CHAR_SINGLE_QUOTE:
2837
                _Ex_SaveArgvValue (fn, FALSE, Alist);
2838
                break;
2839
 
2840
            default:            /* Expand field                         */
2841
                _Ex_ExpandField (fn, Alist);
2842
        }
2843
 
2844
        ReleaseMemoryCell (fn);
2845
    }
2846
}
2847
#endif
2848
 
2849
/*
2850
 * Expand an indirect file Argument
2851
 */
2852
 
2853
#if (OS_TYPE != OS_UNIX)
2854
static void F_LOCAL _Ex_ExpandIndirectFile (char *file, Word_B **Alist)
2855
{
2856
    FILE        *fp;            /* File descriptor                      */
2857
    char        *EoLFound;      /* Pointer                              */
2858
    int         c_maxlen = MAX_LINE;
2859
    char        *line;          /* Line buffer                          */
2860
    char        *eolp;
2861
 
2862
/* If file open fails, expand as a field */
2863
 
2864
    if ((fp = fopen (file + 1, sOpenReadMode)) == (FILE *)NULL)
2865
        PrintErrorMessage ("Cannot open re-direct file - %s (%s)\n",
2866
                           file + 1, strerror (errno));
2867
 
2868
/* Grab some memory for the line */
2869
 
2870
    line = (char *)GetAllocatedSpace (c_maxlen);
2871
 
2872
/* For each line in the file, remove EOF characters and add argument */
2873
 
2874
    while (fgets (line, c_maxlen, fp) != (char *)NULL)
2875
    {
2876
        EoLFound = strchr (line, CHAR_NEW_LINE);
2877
        eolp = line;
2878
 
2879
/* Handle continuation characters */
2880
 
2881
        while (TRUE)
2882
        {
2883
 
2884
/* Check for a continuation character */
2885
 
2886
            if (((EoLFound = strchr (eolp, CHAR_NEW_LINE)) != (char *)NULL) &&
2887
                (*(EoLFound - 1) == CHAR_META))
2888
            {
2889
                *(EoLFound - 1) = CHAR_NEW_LINE;
2890
                *EoLFound = 0;
2891
                EoLFound = (char *)NULL;
2892
            }
2893
 
2894
            else if (EoLFound == (char *)NULL)
2895
                EoLFound = strchr (line, 0x1a);
2896
 
2897
            if (EoLFound != (char *)NULL)
2898
                break;
2899
 
2900
/* Find the end of the line */
2901
 
2902
            c_maxlen = strlen (line);
2903
 
2904
/* Get some more space */
2905
 
2906
            line = (char *)ReAllocateSpace (line, c_maxlen + MAX_LINE);
2907
            eolp = &line[c_maxlen];
2908
 
2909
            if (fgets (eolp, MAX_LINE, fp) == (char *)NULL)
2910
                break;
2911
        }
2912
 
2913
/* Terminate the line and add it to the argument list */
2914
 
2915
        if (EoLFound != (char *)NULL)
2916
            *EoLFound = 0;
2917
 
2918
        _Ex_SaveArgvValue (line, FALSE, Alist);
2919
    }
2920
 
2921
    if (ferror(fp))
2922
        PrintErrorMessage ("%s (%s)", file + 1, strerror (errno));
2923
 
2924
    ReleaseMemoryCell (line);
2925
    fclose (fp);
2926
 
2927
/* Delete tempoary files */
2928
 
2929
    if (((line = strrchr (file + 1, CHAR_PERIOD)) != (char *)NULL) &&
2930
        (stricmp (line, ".tmp") == 0))
2931
        unlink (file + 1);                      /* Delete it            */
2932
}
2933
#endif
2934
 
2935
/*
2936
 * Get space for an argument name
2937
 */
2938
 
2939
#if (OS_TYPE != OS_UNIX)
2940
static char * F_LOCAL _Ex_GetSpace (int length, char *in_s)
2941
{
2942
    char        *out_s;                 /* Malloced space address       */
2943
 
2944
/* Copy string for specified length */
2945
 
2946
    out_s = strncpy ((char *)GetAllocatedSpace (length + 1), in_s, length);
2947
    out_s[length] = 0;
2948
    return (out_s);
2949
}
2950
#endif
2951
 
2952
/*
2953
 * Skip over spaces
2954
 */
2955
 
2956
static char * F_LOCAL _Ex_SkipWhiteSpace (char *a)
2957
{
2958
    while (isspace (*a))
2959
        a++;
2960
 
2961
    return a;
2962
}
2963
 
2964
/*
2965
 * Skip over spaces
2966
 */
2967
 
2968
char    *SkipToWhiteSpace (char *a)
2969
{
2970
    while (*a && !isspace (*a))
2971
        a++;
2972
 
2973
    return a;
2974
}
2975
 
2976
/* Find the location of meta-characters.  If no meta, add the argument and
2977
 * return NULL.  If meta characters, return position of end of directory
2978
 * name.  If not multiple directories, return -1
2979
 */
2980
 
2981
#if (OS_TYPE != OS_UNIX)
2982
static void F_LOCAL _Ex_ExpandField (char *file, Word_B **Alist)
2983
{
2984
    int         i;
2985
    int         j;
2986
    char        *vecp[2];
2987
    char        **FileList;
2988
 
2989
    if (strpbrk (file, "?*[]\\") == (char *)NULL)
2990
    {
2991
        _Ex_SaveArgvValue (file, FALSE, Alist);
2992
        return;
2993
    }
2994
 
2995
    vecp[0] = file;
2996
    vecp[1] = (char *)NULL;
2997
 
2998
    FileList = ExpandWordList (vecp, EXPAND_GLOBBING | EXPAND_TILDE,
2999
                               (ExeMode *)NULL);
3000
 
3001
    j = CountNumberArguments (FileList);
3002
 
3003
    for (i = 0; i < j; )
3004
        _Ex_SaveArgvValue (FileList[i++], FALSE, Alist);
3005
 
3006
    ReleaseAList (FileList);
3007
}
3008
#endif
3009
 
3010
/*
3011
 * Process Environment - note that field is a malloc'ed field
3012
 */
3013
 
3014
#if (OS_TYPE != OS_UNIX)
3015
static char * F_LOCAL _Ex_ConvertEnvVariables (char *field)
3016
{
3017
    char        *sp, *cp, *np, *ep;
3018
    char        save;
3019
    int         b_flag;
3020
 
3021
    sp = field;
3022
 
3023
/* Replace any $ strings */
3024
 
3025
    while ((sp = strchr (sp, CHAR_VARIABLE)) != (char *)NULL)
3026
    {
3027
 
3028
/* If ${...}, find the terminating } */
3029
 
3030
        if (*(cp = ++sp) == CHAR_OPEN_BRACES)
3031
        {
3032
            b_flag = 1;
3033
            ++cp;
3034
 
3035
            while (*cp && (*cp != CHAR_CLOSE_BRACES))
3036
                cp++;
3037
        }
3038
 
3039
/* Else must be $..., find the terminating non-alphanumeric */
3040
 
3041
        else
3042
        {
3043
            b_flag = 0;
3044
 
3045
            while (isalnum (*cp))
3046
                cp++;
3047
        }
3048
 
3049
/* Grab the environment variable */
3050
 
3051
        if (cp == sp)
3052
            continue;
3053
 
3054
/* Get its value */
3055
 
3056
        save = *cp;
3057
        *cp = 0;
3058
        ep = getenv (sp + b_flag);
3059
        *cp = save;
3060
 
3061
        if (ep != (char *)NULL)
3062
        {
3063
            np = _Ex_GetSpace (strlen(field) - (cp - sp) + strlen (ep) - 1,
3064
                               field);
3065
            strcpy (&np[sp - field - 1], ep);
3066
            ReleaseMemoryCell (field);
3067
            strcpy ((sp = &np[strlen(np)]), cp + b_flag);
3068
            field = np;
3069
        }
3070
    }
3071
 
3072
    return field;
3073
}
3074
#endif
3075
 
3076
/*
3077
 * Handle EMX style arguments
3078
 */
3079
 
3080
#if (OS_TYPE == OS_OS2)
3081
static void F_LOCAL  _Ex_ProcessEMXArguments (char *argvp, Word_B **Alist)
3082
{
3083
    char        *cp;
3084
    char        *s = argvp;
3085
 
3086
    _Ex_SaveArgvValue (argvp, TRUE, Alist);
3087
 
3088
    argvp += strlen (argvp) + 1;
3089
    _ACmdLine = argvp;
3090
 
3091
/*
3092
 * Add support in OS2 version for Eberhard Mattes EMX interface to commands.
3093
 */
3094
 
3095
    if ((*argvp) && (*(cp = argvp + strlen (argvp) + 1) == CHAR_TILDE) &&
3096
        (strcmp (s, PATH_TO_UNIX (cp + 1)) == 0))
3097
    {
3098
 
3099
/* Skip over the program name at string 2 to the start of the first
3100
 * argument at string 3
3101
 */
3102
 
3103
        EMXStyleParameters = TRUE;
3104
        argvp += strlen (argvp) + 1;
3105
        argvp += strlen (argvp) + 1;
3106
 
3107
        while (*argvp)
3108
        {
3109
            cp = (*argvp == CHAR_TILDE) ? argvp + 1 : argvp;
3110
 
3111
            if (*cp == CHAR_INDIRECT)
3112
                _Ex_ExpandIndirectFile (cp, Alist);
3113
 
3114
            else
3115
                _Ex_SaveArgvValue (cp, FALSE, Alist);
3116
 
3117
            argvp += strlen (argvp) + 1;
3118
        }
3119
    }
3120
 
3121
    else
3122
        _Ex_CommandLine (argvp, Alist);
3123
}
3124
#endif
3125
 
3126
/*
3127
 * Save the next argument in the word block
3128
 */
3129
 
3130
#if (OS_TYPE != OS_UNIX)
3131
static void F_LOCAL _Ex_SaveArgvValue (char *value, bool Convert,
3132
                                       Word_B **Alist)
3133
{
3134
    if (Convert)
3135
        PATH_TO_UNIX (value);
3136
 
3137
    *Alist = AddWordToBlock (value == (char *)NULL ? value : StringSave (value),
3138
                             *Alist);
3139
 
3140
    if (value == (char *)NULL)
3141
    {
3142
        ARG_ARRAY = GetWordList (*Alist);
3143
        ARG_COUNT = CountNumberArguments (ARG_ARRAY);
3144
    }
3145
}
3146
#endif
3147
 
3148
 
3149
#if (OS_TYPE == OS_DOS) && (OS_SIZE == OS_32) && !defined (__EMX__)
3150
/*
3151
 * INTERRUPT 24 - ERROR HANDLER - Output message
3152
 *
3153
 * doserror     - Error code
3154
 * devhdr       - Device header address.
3155
 * deverror     -
3156
 *
3157
 *   Bits     Meaning
3158
 *
3159
 *   15         Disk error if false (0).
3160
 *              Other device error if true (1).
3161
 *   14         Not used.
3162
 *   13         "Ignore" response not allowed if false.
3163
 *   12         "Retry" response not allowed if false.
3164
 *   11         "Fail" response not allowed if false. (Note that DOS changes
3165
 *              "fail" to "abort".)
3166
 *   9-10       Location (for disk error)
3167
 *
3168
 *              0 - DOS
3169
 *              1 - File Allocation Table (FAT)
3170
 *              2 - Directory
3171
 *              3 - Data area
3172
 *
3173
 *       8      Read error if false; write error if true
3174
 *       0 - 7  Device Number
3175
 */
3176
 
3177
 
3178
char    *I24_Errors [] = {
3179
    "Write-protect error",
3180
    "Unknown unit",
3181
    "Drive not ready",
3182
    "Unknown command",
3183
    "CRC error",
3184
    "Bad request structure length",
3185
    "Seek error",
3186
    "Unknown media type",
3187
    "Sector not found",
3188
    "Out of paper",
3189
    "Write fault",
3190
    "Read fault",
3191
    "General failure",
3192
    "Sharing violation",
3193
    "Lock violation",
3194
    "Invalid disk change",
3195
    "FCB unavailable",
3196
    "Sharing buffer overflow",
3197
    "Unknown error"
3198
};
3199
 
3200
#define I24_ERROR_LAST          (ARRAY_SIZE (I24_Errors) - 1)
3201
#define I24_ERROR_DEFAULT       I24_ERROR_LAST
3202
 
3203
/* 
3204
 * Error locus
3205
 */
3206
 
3207
char    *I24_Locus [] = {
3208
    "Unknown",
3209
    "Unknown",
3210
    "Block",
3211
    "Network",
3212
    "Serial",
3213
    "Memory",
3214
};
3215
 
3216
#define I24_LOCUS_LAST          (ARRAY_SIZE (I24_Locus) - 1)
3217
#define I24_LOCUS_DEFAULT       0
3218
 
3219
/*
3220
 * Action
3221
 */
3222
 
3223
char    *I24_Action [] = {
3224
    "None recommended",
3225
    "Retry, then abort or ignore",
3226
    "Retry with delay, then abort or ignore",
3227
    "Correct information supplied",
3228
    "Abort with cleanup",
3229
    "Abort without cleanup",
3230
    "Ignore",
3231
    "Retry after correcting",
3232
};
3233
 
3234
#define I24_ACTION_LAST         (ARRAY_SIZE (I24_Action) - 1)
3235
#define I24_ACTION_DEFAULT      0
3236
 
3237
/*
3238
 * Class
3239
 */
3240
 
3241
char    *I24_Class [] = {
3242
    "Unknown error",
3243
    "Out of resource",
3244
    "Temporary failure",
3245
    "Authorisation error",
3246
    "MSDOS Internal error",
3247
    "Hardware error",
3248
    "System error",
3249
    "Application error",
3250
    "Item missing",
3251
    "Item invalid",
3252
    "Item interlocked",
3253
    "Media problem"
3254
};
3255
 
3256
#define I24_CLASS_LAST          (ARRAY_SIZE (I24_Class) - 1)
3257
#define I24_CLASS_DEFAULT       0
3258
 
3259
static char     *I24_Space = "\n\r          ";
3260
 
3261
int __far       HardErrorHandler (unsigned int deverror,
3262
                                  unsigned int doserror,
3263
                                  unsigned int *devhdr)
3264
{
3265
    char                DeviceName[10];
3266
    static char         MessageBuffer[300];
3267
    char                *mp;
3268
    int                 ch;
3269
    struct DOSERROR     Ecodes;
3270
 
3271
/* If Ignore set, ignore */
3272
 
3273
    if (IgnoreHardErrors)
3274
        _hardresume (_HARDERR_FAIL);
3275
 
3276
/* Initialise device name */
3277
 
3278
    memset (DeviceName, 0, 10);
3279
 
3280
/* Get extended error codes */
3281
 
3282
    dosexterr (&Ecodes);
3283
 
3284
/* Output on message */
3285
 
3286
    if (deverror & 0x8000)
3287
    {
3288
        memcpy (DeviceName, (((char *)devhdr) + 10), 8);
3289
 
3290
        if ((mp = strchr (DeviceName, CHAR_SPACE)) == (char *)NULL)
3291
           mp = DeviceName + 8;
3292
 
3293
        strcpy (mp, ":");
3294
    }
3295
 
3296
    else
3297
        sprintf (DeviceName, "%c:", (deverror & 0x0ff) + 'A');
3298
 
3299
    sprintf (MessageBuffer, "\n\r%s when %s %s %s\n\r",
3300
             (doserror > I24_ERROR_LAST) ? I24_Errors[I24_ERROR_DEFAULT]
3301
                                         : I24_Errors [doserror],
3302
             (deverror & 0x0100) ? "writing" : "reading",
3303
             (deverror & 0x8000) ? "device " : "disk",
3304
             DeviceName);
3305
 
3306
    OutputBIOSString (MessageBuffer);
3307
 
3308
    sprintf (MessageBuffer, "[Extended Code  : 0x%.4x%sClass : %s%sAction: %s%sLocus : %s device]\n\r",
3309
             Ecodes.exterror, I24_Space,
3310
             (Ecodes.class > I24_CLASS_LAST) ? I24_Class[I24_CLASS_DEFAULT]
3311
                                             : I24_Class[Ecodes.class],
3312
             I24_Space,
3313
             (Ecodes.action > I24_ACTION_LAST) ? I24_Action[I24_ACTION_DEFAULT]
3314
                                               : I24_Action[Ecodes.action],
3315
             I24_Space,
3316
             (Ecodes.locus > I24_LOCUS_LAST) ? I24_Locus[I24_LOCUS_DEFAULT]
3317
                                             : I24_Locus[Ecodes.locus]);
3318
 
3319
    OutputBIOSString (MessageBuffer);
3320
 
3321
/* Allowed actions */
3322
 
3323
    strcpy (MessageBuffer, "Abort");
3324
    if (deverror & 0x2000)
3325
        strcat (MessageBuffer, ", Ignore");
3326
 
3327
    if (deverror & 0x1000)
3328
        strcat (MessageBuffer, ", Retry");
3329
 
3330
    if (deverror & 0x0800)
3331
        strcat (MessageBuffer, ", Fail");
3332
 
3333
    OutputBIOSString (strcat (MessageBuffer, "? "));
3334
 
3335
/* Use BIOS to get a key. */
3336
 
3337
    while (TRUE)
3338
    {
3339
        ch = _bios_keybrd (_KEYBRD_READ) & 0x00ff;
3340
 
3341
        if ((ch = tolower (ch)) == 'a') 
3342
        {
3343
            OutputBIOSString ("A\n\r");
3344
            _hardresume (_HARDERR_ABORT);
3345
        }
3346
 
3347
        else if ((ch == 'i') && (deverror & 0x2000))
3348
        {
3349
            OutputBIOSString ("I\n\r");
3350
            _hardresume (_HARDERR_IGNORE);
3351
        }
3352
 
3353
        else if ((ch == 'r') && (deverror & 0x1000))
3354
        {
3355
            OutputBIOSString ("R\n\r");
3356
            _hardresume (_HARDERR_RETRY);
3357
        }
3358
 
3359
        else if ((ch == 'f') && (deverror & 0x0800))
3360
        {
3361
            OutputBIOSString ("F\n\r");
3362
#  if defined (__WATCOMC__)
3363
            _hardresume (_HARDERR_FAIL);
3364
#  else
3365
            _hardretn (doserror);
3366
#  endif
3367
        }
3368
 
3369
        OutputBIOSString ("\007");
3370
    }
3371
 
3372
#  if defined (__WATCOMC__)
3373
    return _HARDERR_FAIL;
3374
#  endif
3375
}
3376
 
3377
/*
3378
 * Display a string using BIOS interrupt 0x0e (Write TTY).
3379
 */
3380
 
3381
static void F_LOCAL OutputBIOSString (char *p)
3382
{
3383
    union REGS          r;
3384
 
3385
    while (*p)
3386
    {
3387
        r.h.ah = 0x0e;
3388
        r.h.al = *(p++);
3389
        SystemInterrupt (0x10, &r, &r);
3390
    }
3391
}
3392
#endif
3393
 
3394
/*
3395
 * Output to Stderr
3396
 */
3397
 
3398
int     feputc (int c)
3399
{
3400
    return putc (c, stderr);
3401
}
3402
 
3403
int     feputs (const char *s)
3404
{
3405
    return fputs (s, stderr);
3406
}
3407
 
3408
int     foputs (const char *s)
3409
{
3410
    return fputs (s, stdout);
3411
}
3412
 
3413
/*
3414
 * Convert drives
3415
 */
3416
 
3417
#if (OS_TYPE != OS_UNIX)
3418
unsigned int    GetDriveNumber (char letter)
3419
{
3420
    return tolower (letter) - 'a' + 1;
3421
}
3422
 
3423
char            GetDriveLetter (unsigned int drive)
3424
{
3425
    return (char)(drive + 'a' - 1);
3426
}
3427
#endif
3428
 
3429
/*
3430
 * IO Map functions - Set or clear the inuse bit in the environment.
3431
 */
3432
 
3433
void    ChangeFileDescriptorStatus (int fd, bool InUse)
3434
{
3435
    if (fd < FDBASE)
3436
        return;
3437
 
3438
    else if (InUse)
3439
        e.IOMap |= 1L << (fd - FDBASE);
3440
 
3441
    else
3442
        e.IOMap &= ~(1L << (fd - FDBASE));
3443
}
3444
 
3445
/*
3446
 * Convert a string to a number
3447
 */
3448
 
3449
int      GetNumericValue (char *as)
3450
{
3451
    long        value;
3452
 
3453
    return ConvertNumericValue (as, &value, 10) ? (int) value : -1;
3454
}
3455
 
3456
 
3457
/*
3458
 * ProcessOutputMetaCharacters - Convert an escaped character to a binary value.
3459
 *
3460
 * Returns the binary value and updates the string pointer.
3461
 */
3462
 
3463
static struct {
3464
    char        Escaped;
3465
    int         NewValue;
3466
} ConvertMetaCharacters [] =
3467
{
3468
    { 'b',  0x08}, { 'f',  0x0c}, { 'v',        0x0b},      { 'n',  0x0a},
3469
    { 'r',  0x0d}, { 't',  0x09}, { CHAR_META,  CHAR_META}, { 'c',  -1},
3470
    { 0, 0}
3471
};
3472
 
3473
int ProcessOutputMetaCharacters (char **cp)
3474
{
3475
    int         c_val = **cp;                   /* Current character    */
3476
    int         j = 0;
3477
 
3478
    if (c_val)
3479
        (*cp)++;
3480
 
3481
/* Process escaped characters */
3482
 
3483
    while (ConvertMetaCharacters[j].Escaped != 0)
3484
    {
3485
        if (ConvertMetaCharacters[j].Escaped == (char)c_val)
3486
            return ConvertMetaCharacters[j].NewValue;
3487
 
3488
        ++j;
3489
    }
3490
 
3491
/* Check for an octal string */
3492
 
3493
    if (IS_OCTAL (c_val) && IS_OCTAL (**cp) && IS_OCTAL (*((*cp) + 1)))
3494
    {
3495
        c_val = ((c_val & 0x07) << 6) |
3496
                ((**cp & 0x07) << 3)  |
3497
                ((*((*cp) + 1) & 0x07));
3498
 
3499
        (*cp) += 2;
3500
        return c_val;
3501
    }
3502
 
3503
    return c_val;
3504
}
3505
 
3506
 
3507
/*
3508
 * Extract the next path from a string and build a new path from the
3509
 * extracted path and a file name
3510
 */
3511
 
3512
char *BuildNextFullPathName (char *path_s,      /* Path string          */
3513
                             char *file_s,      /* File name string     */
3514
                             char *output_s)    /* Output path          */
3515
{
3516
    char        *s = output_s;
3517
    int         fsize = 0;
3518
 
3519
    while (*path_s && (*path_s != CHAR_PATH_SEPARATOR) && (fsize++ < FFNAME_MAX))
3520
        *s++ = *path_s++;
3521
 
3522
#if (OS_TYPE == OS_NT)                          /* handle quoted paths */
3523
    if (fsize > 2 && output_s[0] == '"' && s[-1] == '"')
3524
    {
3525
        fsize -= 2;                             /* stripe */
3526
        memmove( output_s, output_s+1, fsize );
3527
        s = output_s + fsize;
3528
    } 
3529
#endif
3530
 
3531
    if ((output_s != s) && !IsPathCharacter (*(s - 1)) && (fsize++ < FFNAME_MAX))
3532
        *s++ = CHAR_UNIX_DIRECTORY;
3533
 
3534
    *s = 0;
3535
 
3536
    if (file_s != (char *)NULL)
3537
        strncpy (s, file_s, FFNAME_MAX - fsize);
3538
 
3539
    output_s[FFNAME_MAX - 1] = 0;
3540
 
3541
    return (*path_s ? ++path_s : (char *)NULL);
3542
}
3543
 
3544
/*
3545
 * Go To the specified directory
3546
 */
3547
 
3548
bool    GotoDirectory (char *CNDirectory, unsigned int cdrive)
3549
{
3550
    if (IsDriveCharacter (*(CNDirectory + 1)))
3551
    {
3552
        if (SetCurrentDrive (GetDriveNumber (*CNDirectory)) == -1)
3553
            return FALSE;
3554
 
3555
        CNDirectory += 2;
3556
    }
3557
 
3558
/* Was the change successful? */
3559
 
3560
    if ((!*CNDirectory) || (S_chdir (CNDirectory)))
3561
        return TRUE;
3562
 
3563
    SetCurrentDrive (cdrive);
3564
    return FALSE;
3565
}
3566
 
3567
/*
3568
 * Find out the application type
3569
 */
3570
 
3571
unsigned long   QueryApplicationType (const char *pathname)
3572
{
3573
#if (OS_TYPE == OS_UNIX)
3574
    return EXETYPE_UNIX_NATIVE;
3575
#else
3576
    int                 fd;
3577
    unsigned long       res;
3578
    size_t              len;
3579
    if (pathname == NULL)
3580
        res = EXETYPE_BAD_FILE;
3581
 
3582
/* Open the file */
3583
 
3584
    else if ((fd = open (pathname, O_RDONLY | O_BINARY)) == -1)
3585
        res = EXETYPE_BAD_FILE;
3586
 
3587
    else
3588
    {
3589
        res = QueryApplicationType1 (fd);
3590
        close (fd);
3591
 
3592
/* Check for .com file */
3593
 
3594
        if ((res == EXETYPE_UNKNOWN) && ((len = strlen (pathname)) > 5) &&
3595
               (stricmp (&pathname[len - 4], ".com") == 0))
3596
          res = EXETYPE_DOS_CUI;
3597
    }     
3598
    return res;
3599
#endif
3600
}
3601
 
3602
 
3603
/*
3604
 * Do the actual work!  Under UNIX, we don't care
3605
 */
3606
 
3607
#if (OS_TYPE != OS_UNIX)
3608
static unsigned long F_LOCAL QueryApplicationType1 (int fd)
3609
{
3610
    union {
3611
        struct ExecOS2_16Header OS2aHead;
3612
        struct ExecOS2_32header OS2bHead;
3613
        struct ExecNTHeader     NTHead;
3614
        struct ExecDosHeader    DosHead;
3615
    }                           OS_Headers;
3616
    struct stat                 fstatus;
3617
 
3618
    if ((read (fd, &OS_Headers, sizeof (struct ExecDosHeader)) !=
3619
                sizeof (struct ExecDosHeader)) ||
3620
        (OS_Headers.DosHead.e_magic != SIG_DOS))
4806 dpurdie 3621
    {
227 dpurdie 3622
        return EXETYPE_UNKNOWN;
4806 dpurdie 3623
    }
227 dpurdie 3624
 
3625
/*
3626
 * If the header size in the header is not a new header or the relocation
3627
 * section starts before the end of the new header, it must be a DOS program
3628
 */
3629
 
3630
    if ((OS_Headers.DosHead.e_cparhdr * 16 < sizeof (struct ExecDosHeader)) ||
3631
        (OS_Headers.DosHead.e_lfarlc < sizeof (struct ExecDosHeader)))
4806 dpurdie 3632
    {
227 dpurdie 3633
        return EXETYPE_DOS_CUI;
4806 dpurdie 3634
    }
227 dpurdie 3635
 
3636
    if ((fstat (fd, &fstatus) == -1) ||
3637
        (fstatus.st_size < (off_t) OS_Headers.DosHead.e_lfanew))
4806 dpurdie 3638
    {
227 dpurdie 3639
        return EXETYPE_DOS_CUI;
4806 dpurdie 3640
    }
227 dpurdie 3641
 
3642
    if ((lseek (fd, (off_t) OS_Headers.DosHead.e_lfanew, SEEK_SET) ==
3643
                (off_t) -1) ||
3644
        (read (fd, &OS_Headers, sizeof (OS_Headers)) != sizeof (OS_Headers)))
4806 dpurdie 3645
    {
227 dpurdie 3646
        return EXETYPE_BAD_IMAGE;
4806 dpurdie 3647
    }
227 dpurdie 3648
 
3649
/* NT */
3650
    if (OS_Headers.NTHead.Signature == SIG_NT)
3651
    {
4806 dpurdie 3652
        // Note: X64 OptionalHeaderSize is longer
3653
        if (OS_Headers.NTHead.FileHeader.SizeOfOptionalHeader < NT_OPTIONAL_HEADER)
227 dpurdie 3654
            return EXETYPE_UNKNOWN;
3655
 
3656
        switch (OS_Headers.NTHead.OptionalHeader.Subsystem)
3657
        {
3658
            default:
3659
                return EXETYPE_UNKNOWN;
3660
 
3661
            case NT_SS_NATIVE:
3662
                return EXETYPE_NT_NATIVE;
3663
 
3664
            case NT_SS_WINDOWS_GUI:
3665
                return EXETYPE_NT_WINDOWS_GUI;
3666
 
3667
            case NT_SS_WINDOWS_CUI:
3668
                return EXETYPE_NT_WINDOWS_CUI;
3669
 
3670
            case NT_SS_OS2_CUI:
3671
                return EXETYPE_NT_OS2;
3672
 
3673
            case NT_SS_POSIX_CUI:
3674
                return EXETYPE_NT_POSIX;
3675
        }
3676
    }
3677
 
3678
/* OS2 1.x */
3679
 
3680
    else if ((OS_Headers.OS2aHead.ne_magic == SIG_OS2_16) ||
3681
             (OS_Headers.OS2aHead.ne_magic == SIG_OS2_16LE))
3682
    {
3683
#ifdef APPDEBUG
3684
        if (FL_TEST(FLAG_DEBUG_EXECUTE)) {
3685
            fprintf(stderr, "ne_flags       = %.4x  ne_flagsothers = %.4x\n",
3686
               OS_Headers.OS2aHead.ne_flags,
3687
               OS_Headers.OS2aHead.ne_flagsothers);
3688
            printf("ne_exetyp      = %.4x (R %.2x V %.2x)\n",
3689
               OS_Headers.OS2aHead.ne_exetyp,
3690
               OS_Headers.OS2aHead.ne_ver,
3691
               OS_Headers.OS2aHead.ne_rev);
3692
        } 
3693
#endif
3694
 
3695
        if (OS_Headers.OS2aHead.ne_flags & (OS2_16_NOTP | OS2_16_IERR))
3696
            return EXETYPE_BAD_IMAGE;
3697
 
3698
        if (OS_Headers.OS2aHead.ne_exetyp == OS2_16_WINDOWS)
3699
            return EXETYPE_DOS_GUI;
3700
 
3701
/* This appears to be what Watcom generates */
3702
 
3703
        else if ((OS_Headers.OS2aHead.ne_exetyp == OS2_16_UNKNOWN) &&
3704
                 (OS_Headers.OS2aHead.ne_flags == 0))
3705
            return EXETYPE_DOS_32;
3706
 
3707
/* Under OS/2, A bound app is an OS/2 app otherwise its a DOS app */
3708
 
3709
#if (OS_TYPE != OS_OS2)
3710
        else if (OS_Headers.OS2aHead.ne_exetyp == OS2_16_UNKNOWN)
3711
            return EXETYPE_DOS_CUI;
3712
 
3713
        else if (OS_Headers.OS2aHead.ne_flags & OS2_16_BOUND)
3714
            return EXETYPE_DOS_BOUND;
3715
#else
3716
        else if (OS_Headers.OS2aHead.ne_exetyp == OS2_16_UNKNOWN)
3717
            return EXETYPE_OS2_CUI;
3718
#endif
3719
 
3720
/* Real OS/2 app */
3721
 
3722
        else if (OS_Headers.OS2aHead.ne_exetyp == OS2_16_OS2)
3723
        {
3724
            switch (OS_Headers.OS2aHead.ne_flags & OS2_16_APPTYP)
3725
            {
3726
                case OS2_16_NOTWINCOMPAT:
3727
                    return EXETYPE_OS2_CUI;
3728
 
3729
                case OS2_16_WINCOMPAT:
3730
                    return EXETYPE_OS2_CGUI;
3731
 
3732
                case OS2_16_WINAPI:
3733
                    return EXETYPE_OS2_GUI;
3734
 
3735
                case 0:
3736
#if (OS_TYPE == OS_OS2)
3737
                    return EXETYPE_OS2_CUI;
3738
#else
3739
                    return EXETYPE_DOS_BOUND;
3740
#endif
3741
            }
3742
        }
3743
    }
3744
 
3745
/* OS2 2.x */
3746
 
3747
    else if (OS_Headers.OS2bHead.e32_magic == SIG_OS2_32)
3748
    {
3749
#ifdef APPDEBUG
3750
        if (FL_TEST(FLAG_DEBUG_EXECUTE))
3751
            fprintf(stderr, "Mflags = %.8lx\n", OS_Headers.OS2bHead.e32_mflags);
3752
#endif
3753
 
3754
        if ((OS_Headers.OS2bHead.e32_mflags & (OS2_NOTP | OS2_NOLOAD)) ||
3755
            (OS_Headers.OS2bHead.e32_mflags & OS2_MODMASK))
3756
            return EXETYPE_NOT_EXE;
3757
 
3758
        if ((OS_Headers.OS2bHead.e32_mflags & OS2_APPMASK) == OS2_NOPMW)
3759
                return EXETYPE_OS2_CUI | EXETYPE_OS2_32;
3760
 
3761
        else if ((OS_Headers.OS2bHead.e32_mflags & OS2_APPMASK) == OS2_PMW)
3762
                return EXETYPE_OS2_CGUI | EXETYPE_OS2_32;
3763
 
3764
        else if ((OS_Headers.OS2bHead.e32_mflags & OS2_APPMASK) == OS2_PMAPI)
3765
                return EXETYPE_OS2_GUI | EXETYPE_OS2_32;
3766
    }
3767
 
3768
/* Give UP! */
3769
 
3770
    return EXETYPE_UNKNOWN;
3771
}
3772
#endif
3773
 
3774
/*
3775
 * Need case change for UNIX
3776
 */
3777
 
3778
#if (OS_TYPE == OS_UNIX)
3779
 
3780
/* Convert a string to lower case */
3781
 
3782
char *strlwr (char *s)
3783
{
3784
    char        *original = s;
3785
 
3786
    if (s != (char *)NULL)
3787
    {
3788
        while (*s)
3789
        {
3790
            *s = tolower (*s);
3791
            s++;
3792
        }
3793
    }
3794
 
3795
    return (original);
3796
}
3797
 
3798
/*
3799
 * Convert a string to upper case
3800
 */
3801
 
3802
char *strupr (char *s)
3803
{
3804
    char        *original = s;
3805
 
3806
    if (s != (char *)NULL)
3807
    {
3808
        while (*s)
3809
        {
3810
            *s = toupper (*s);
3811
            s++;
3812
        }
3813
    }
3814
 
3815
    return (original);
3816
}
3817
 
3818
/*
3819
 * String compare - ignore case
3820
 */
3821
 
3822
int stricmp (char *a, char *b)
3823
{
3824
    int         diff;
3825
 
3826
    while ((!(diff = tolower(*a) - toupper (*b))) && *a)
3827
    {
3828
        a++;
3829
        b++;
3830
    }
3831
 
3832
    return diff;
3833
}
3834
#endif
3835
 
3836
/*
3837
 * Convert long to based number string
3838
 */
3839
 
3840
#if (OS_TYPE == OS_UNIX) || defined (__EMX__)
3841
char *ltoa (long n, char *ibuffer, int base)
3842
{
3843
    char                flag = 0;
3844
    int                 r;
3845
    char                lbuffer[32 + 2];
3846
    char                *c_pos = lbuffer + 32 + 2;
3847
 
3848
    if ((base < 2) || (base > 36))
3849
    {
3850
        errno = ERANGE;
3851
        return (char *)NULL;
3852
    }
3853
 
3854
    *(--c_pos) = 0;
3855
 
3856
    if (n < 0)
3857
    {
3858
        flag++;
3859
        n = -n;
3860
    }
3861
 
3862
    if (n == 0)
3863
        *(--c_pos) = '0';
3864
 
3865
    else
3866
    {
3867
        while (n > 0)
3868
        {
3869
            r = (int)(n % (long)base);
3870
 
3871
            *(--c_pos) = r + ((r > 9) ? 'a' - 10 : '0');
3872
 
3873
            n /= (long)base;
3874
        }
3875
    }
3876
 
3877
    if (flag)
3878
        *(--c_pos) = (char)'-';
3879
 
3880
    return strcpy (ibuffer, c_pos);
3881
}
3882
#endif
3883
 
3884
/*
3885
 * EMX does not have a cwait function
3886
 */
3887
 
3888
#if defined (__EMX__) && (OS_TYPE == OS_OS2)
3889
int cwait (int *TermCode, int pid, int action)
3890
{
3891
    ULONG               rc;
3892
    RESULTCODES         res;
3893
    PID                 rpid;
3894
    PID                 apid = pid;
3895
 
3896
    if ((rc = DosWaitChild (action == WAIT_GRANDCHILD ? DCWA_PROCESSTREE
3897
                                                      : DCWA_PROCESS,
3898
                            DCWW_WAIT, &res, &rpid, apid)))
3899
    {
3900
        if (rc == ERROR_INVALID_PROCID)
3901
            errno = EINVAL;
3902
 
3903
        else
3904
             errno = ECHILD;
3905
 
3906
        return (-1);
3907
    }
3908
 
3909
    *TermCode = res.codeResult;
3910
    return rpid;
3911
}
3912
#endif
3913
 
3914
/*
3915
 * DEBUG code
3916
 */
3917
 
3918
#ifdef DEBUG_ON
3919
void db_printf (char *fmt, ...)
3920
{
3921
    va_list     ap;
3922
 
3923
    va_start (ap, fmt);
3924
    vfprintf (stderr, fmt, ap);
3925
    fputc (CHAR_NEW_LINE, stderr);
3926
    fflush (stderr);
3927
    va_end (ap);
3928
}
3929
#endif
3930
 
3931
/*
3932
 * Get file attributes - EMX version
3933
 */
3934
 
3935
#if (OS_TYPE == OS_DOS) && defined (__EMX__)
3936
unsigned _dos_getfileattr(
3937
    char *file, unsigned int *attr)
3938
{
3939
    struct _find        dtabuf;
3940
    int                 rc;
3941
 
3942
    DISABLE_HARD_ERRORS;
3943
 
3944
    rc = __findfirst (file, OS_FILE_ATTRIBUTES, &dtabuf);
3945
 
3946
    ENABLE_HARD_ERRORS;
3947
 
3948
    *attr = (char)dtabuf.attr;
3949
 
3950
    return (unsigned int)rc;
3951
}
3952
#endif
3953