Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - Main program, memory and variable management
3
 *
4
 * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited and Charles Forsyth
5
 *
6
 * This code is based on (in part) the shell program written by Charles
7
 * Forsyth and is subject to the following copyright restrictions:
8
 *
9
 * 1.  Redistribution and use in source and binary forms are permitted
10
 *     provided that the above copyright notice is duplicated in the
11
 *     source form and the copyright notice in file sh6.c is displayed
12
 *     on entry to the program.
13
 *
14
 * 2.  The sources (or parts thereof) or objects generated from the sources
15
 *     (or parts of sources) cannot be sold under any circumstances.
16
 *
17
 * When parts of the original 2.1 shell were replaced by the Lexical
18
 * Analsyer written by Simon J. Gerraty (for his Public Domain Korn Shell,
19
 * which is also based on Charles Forsyth original idea), a number of changes
20
 * were made to reflect the changes Simon made to the Parse output tree.  Some
21
 * parts of this code in this module are based on the algorithms/ideas that
22
 * he incorporated into his shell, in particular interfaces to the new Lexical
23
 * Scanner.
24
 *
25
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/Sh1.c,v 1.3 2004/11/04 02:47:59 ayoung Exp $
26
 *
27
 *    $Log: Sh1.c,v $
28
 *    Revision 1.3  2004/11/04 02:47:59  ayoung
29
 *    handle upto 8 PATH definitions
30
 *
31
 *    Revision 1.2  2004/05/10 09:30:06  ayoung
32
 *    improved Path/PATH handling
33
 *    Quote CreateProcess arg0 if embedded spaces are  encountered
34
 *    Native NT exec dont need to check command line length
35
 *    Warning when '@' within redirect list
36
 *    DEBUG_EXEC option, split from PRINT_EXEC option and improved
37
 *
38
 *    Revision 1.1  2002/08/02 06:49:33  adamy
39
 *    imported (reference only)
40
 *
41
 *    Revision 1.1  2001/07/20 05:55:43  ayoung
42
 *    WIN32 support
43
 *
44
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
45
 *    UTIL
46
 *
5659 dpurdie 47
 *      Revision 2.19  1994/08/25  20:49:11  istewart
48
 *      MS Shell 2.3 Release
227 dpurdie 49
 *
5659 dpurdie 50
 *      Revision 2.18  1994/02/23  09:23:38  istewart
51
 *      Beta 233 updates
227 dpurdie 52
 *
5659 dpurdie 53
 *      Revision 2.17  1994/02/01  10:25:20  istewart
54
 *      Release 2.3 Beta 2, including first NT port
227 dpurdie 55
 *
5659 dpurdie 56
 *      Revision 2.16  1994/01/20  14:51:43  istewart
57
 *      Release 2.3 Beta 1
227 dpurdie 58
 *
5659 dpurdie 59
 *      Revision 2.15  1994/01/11  17:55:25  istewart
60
 *      Release 2.3 Beta 0 patches
227 dpurdie 61
 *
5659 dpurdie 62
 *      Revision 2.14  1993/12/01  11:58:34  istewart
63
 *      Release 226 beta
227 dpurdie 64
 *
5659 dpurdie 65
 *      Revision 2.13  1993/11/09  10:39:49  istewart
66
 *      Beta 226 checking
227 dpurdie 67
 *
5659 dpurdie 68
 *      Revision 2.12  1993/08/25  16:03:57  istewart
69
 *      Beta 225 - see Notes file
227 dpurdie 70
 *
5659 dpurdie 71
 *      Revision 2.11  1993/07/02  10:21:35  istewart
72
 *      224 Beta fixes
227 dpurdie 73
 *
5659 dpurdie 74
 *      Revision 2.10  1993/06/16  12:55:49  istewart
75
 *      Fix the -s and -t options so they work
227 dpurdie 76
 *
5659 dpurdie 77
 *      Revision 2.9  1993/06/14  11:00:12  istewart
78
 *      More changes for 223 beta
227 dpurdie 79
 *
5659 dpurdie 80
 *      Revision 2.8  1993/06/02  09:52:35  istewart
81
 *      Beta 223 Updates - see Notes file
227 dpurdie 82
 *
5659 dpurdie 83
 *      Revision 2.7  1993/02/16  16:03:15  istewart
84
 *      Beta 2.22 Release
227 dpurdie 85
 *
5659 dpurdie 86
 *      Revision 2.6  1993/01/26  18:35:09  istewart
87
 *      Release 2.2 beta 0
227 dpurdie 88
 *
5659 dpurdie 89
 *      Revision 2.5  1992/12/14  10:54:56  istewart
90
 *      BETA 215 Fixes and 2.1 Release
227 dpurdie 91
 *
5659 dpurdie 92
 *      Revision 2.4  1992/11/06  10:03:44  istewart
93
 *      214 Beta test updates
227 dpurdie 94
 *
5659 dpurdie 95
 *      Revision 2.3  1992/09/03  18:54:45  istewart
96
 *      Beta 213 Updates
227 dpurdie 97
 *
5659 dpurdie 98
 *      Revision 2.2  1992/07/16  14:33:34  istewart
99
 *      Beta 212 Baseline
227 dpurdie 100
 *
5659 dpurdie 101
 *      Revision 2.1  1992/07/10  10:52:48  istewart
102
 *      211 Beta updates
227 dpurdie 103
 *
5659 dpurdie 104
 *      Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
227 dpurdie 105
 *     MS-Shell 2.0 Baseline release
106
 */
107
 
108
#include <sys/types.h>
109
#include <sys/stat.h>
110
#include <stdio.h>
111
#include <stdlib.h>
112
#include <signal.h>
113
#include <errno.h>
114
#include <setjmp.h>
115
#include <stdarg.h>
116
#include <string.h>
117
#include <unistd.h>
118
#include <ctype.h>
119
#include <fcntl.h>
120
#include <limits.h>
121
#include <dirent.h>
122
#include <time.h>
123
#include "sh.h"
124
 
125
/* OS2 or DOS, DEBUG MEMORY or normal malloc */
126
 
127
#ifdef OS2_DOSALLOC
128
#  ifdef DEBUG_MEMORY
5659 dpurdie 129
#    define RELEASE_MEMORY(x)   if (DosFreeSeg (SELECTOROF ((x))))      \
130
                                    fprintf(stderr, "Memory Release error\n");
227 dpurdie 131
#  else
5659 dpurdie 132
#    define RELEASE_MEMORY(x)   DosFreeSeg (SELECTOROF ((x)))
227 dpurdie 133
#  endif
134
 
135
#else
136
#  define RELEASE_MEMORY(x)     free ((x))
137
#endif
138
 
139
/*
140
 * Structure of Malloced space to allow release of space nolonger required
141
 * without having to know about it.
142
 */
143
 
144
typedef struct region {
5659 dpurdie 145
    struct region       *next;
146
    size_t              nbytes;
147
    int                 area;
227 dpurdie 148
} s_region;
149
 
5659 dpurdie 150
static struct region    *MemoryAreaHeader = (s_region *)NULL;
227 dpurdie 151
 
152
/*
153
 * default shell, search rules
154
 */
155
 
156
#if (OS_TYPE == OS_UNIX)
5659 dpurdie 157
static char             *shellname = "/bin/pksh";
158
static char             search[] = ":/bin:/usr/bin";
227 dpurdie 159
 
5659 dpurdie 160
extern char             **environ;
227 dpurdie 161
#else
5659 dpurdie 162
static char             *shellname = "c:/bin/sh.exe";
163
static char             search[] = ";c:/bin;c:/usr/bin";
227 dpurdie 164
#endif
5659 dpurdie 165
static char             *ymail = "You have mail";
166
static char             *ShellNameLiteral = "sh";
167
static char             *ShellOptions = "D:MPRX:abc:defghijklmnopqrtsuvwxyz0";
227 dpurdie 168
 
169
#if (OS_TYPE != OS_DOS)
5659 dpurdie 170
static char             DefaultWinTitle[] = "MS Shell";
227 dpurdie 171
#endif
172
 
173
#if (OS_TYPE == OS_OS2)
174
#  if (OS_SIZE == OS_32)
5659 dpurdie 175
static HEV              SessionQueueSema = 0;
176
static HQUEUE           SessionQueueHandler = 0;
227 dpurdie 177
#  else
5659 dpurdie 178
static HSEM             SessionQueueSema = 0;
179
static HQUEUE           SessionQueueHandler = 0;
227 dpurdie 180
#  endif
181
#endif
182
 
5659 dpurdie 183
static char             *tilde = "~";
184
static char             LIT_OSmode[] = "OSMODE";
185
static char             LIT_SHmode[] = "SHMODE";
186
static char             LIT_Dollar[] = "$";
227 dpurdie 187
#if (OS_TYPE == OS_DOS)
188
static char            *NOExit = "sh: ignoring attempt to leave lowest level shell";
189
#endif
5659 dpurdie 190
static bool             ProcessingDEBUGTrap = FALSE;
191
static bool             ProcessingERRORTrap = FALSE;
192
static unsigned int     ATOE_GFlags;    /* Twalk GLOBAL flags           */
193
static unsigned int     ATNE_Function;  /* Twalk GLOBAL flags           */
227 dpurdie 194
 
195
/*
196
 * Count value for counting the number entries in an array
197
 */
198
 
5659 dpurdie 199
static int              Count_Array;    /* Array size                   */
200
static char             *Count_Name;    /* Array name                   */
227 dpurdie 201
 
202
/* Integer Variables */
203
 
204
static struct ShellVariablesInit {
205
    char       *Name;                   /* Name of variable             */
5659 dpurdie 206
    int         Status;                 /* Initial status               */
227 dpurdie 207
    char       *CValue;
208
} InitialiseShellVariables[] = {
5659 dpurdie 209
    { LIT_COLUMNS,              STATUS_INTEGER,         "80"            },
210
    { HistorySizeVariable,      STATUS_INTEGER,         "100"           },
211
    { LineCountVariable,        STATUS_INTEGER,         "1"             },
212
    { LIT_LINES,                STATUS_INTEGER,         "25"            },
213
    { OptIndVariable,           STATUS_INTEGER,         "1"             },
214
    { StatusVariable,           STATUS_INTEGER,         "0"             },
215
    { RandomVariable,           (STATUS_EXPORT | STATUS_INTEGER),
216
                                                        null            },
217
    { SecondsVariable,          (STATUS_EXPORT | STATUS_INTEGER),
218
                                                        null            },
219
    { LIT_OSmode,               (STATUS_EXPORT | STATUS_CANNOT_UNSET |
220
                                 STATUS_INTEGER),       null            },
221
    { LIT_SHmode,               (STATUS_EXPORT | STATUS_CANNOT_UNSET |
222
                                 STATUS_INTEGER),       null            },
223
    { LIT_Dollar,               (STATUS_CANNOT_UNSET | STATUS_INTEGER),
224
                                                        null            },
227 dpurdie 225
 
5659 dpurdie 226
    { LastWordVariable,         STATUS_EXPORT,          null            },
227
    { PathLiteral,              (STATUS_EXPORT | STATUS_CANNOT_UNSET | STATUS_CONVERT_MSDOS),
228
                                                        search          },
229
    { IFS,                      (STATUS_EXPORT | STATUS_CANNOT_UNSET),
230
                                                        " \t\n"         },
231
    { PS1,                      (STATUS_EXPORT | STATUS_CANNOT_UNSET),
232
                                                        "%e$ "          },
233
    { PS2,                      (STATUS_EXPORT | STATUS_CANNOT_UNSET),
234
                                                        "> "            },
235
    { PS3,                      STATUS_EXPORT,          "#? "           },
236
    { PS4,                      STATUS_EXPORT,          "+ "            },
237
    { HomeVariableName,         STATUS_EXPORT,          null            },
238
    { ShellVariableName,        STATUS_EXPORT,          null            },
227 dpurdie 239
 
240
#if (OS_TYPE != OS_DOS)
5659 dpurdie 241
    { WinTitleVariable,         0,                      DefaultWinTitle },
227 dpurdie 242
#endif
243
 
5659 dpurdie 244
    { (char *)NULL,             0 }
227 dpurdie 245
};
246
 
247
/*
248
 * List of Editor variables
249
 */
250
 
251
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
5659 dpurdie 252
static char             *EditorVariables[] = {
227 dpurdie 253
    FCEditVariable, EditorVariable, VisualVariable, (char *)NULL
254
};
255
#endif
256
 
5659 dpurdie 257
                                        /* Entry directory              */
258
static char     Start_directory[PATH_MAX + 6] = { 0 };
259
static time_t   ShellStartTime = 0;     /* Load time of shell           */
260
                                        /* Original Interrupt 24 address */
227 dpurdie 261
#if (OS_TYPE == OS_DOS) && !defined (__EMX__)
262
#if defined (__WATCOMC__)
5659 dpurdie 263
#    define INTERRUPT_TYPE              __interrupt __far
227 dpurdie 264
#  else
5659 dpurdie 265
#    define INTERRUPT_TYPE              interrupt far
227 dpurdie 266
#  endif
5659 dpurdie 267
static void     (INTERRUPT_TYPE *Orig_I24_V) (void);
227 dpurdie 268
#endif
269
 
270
#ifdef SIGQUIT
271
static void     (_SIGDECL *qflag)(int) = SIG_IGN;
272
#endif
273
 
274
/* Functions */
275
 
5659 dpurdie 276
static int F_LOCAL      RunCommands (Source *);
227 dpurdie 277
static unsigned char * F_LOCAL  CheckClassExpression (unsigned char *, int, bool);
5659 dpurdie 278
static bool F_LOCAL     Initialise (int, char **);
279
static void F_LOCAL     CheckForMailArriving (void);
280
static void F_LOCAL     LoadGlobalVariableList (void);
281
static void F_LOCAL     LoadTheProfileFiles (void);
282
static void F_LOCAL     ConvertUnixPathToMSDOS (char *);
283
static void F_LOCAL     ClearUserPrompts (void);
284
static void F_LOCAL     SecondAndRandomEV (char *, long);
285
static void F_LOCAL     SetUpParameterEV (int, char **, char *);
286
static bool F_LOCAL     AllowedToSetVariable (VariableList *);
287
static void F_LOCAL     SetUpANumericValue (VariableList *, long, int);
288
static void F_LOCAL     ProcessErrorExit (char *, va_list);
289
static char * F_LOCAL   SuppressSpacesZeros (VariableList *, char *);
290
static void             AddToNewEnvironment (const void *, VISIT, int);
291
static void             AddToOldEnvironment (const void *, VISIT, int);
292
static void             DeleteEnvironment (const void *, VISIT, int);
293
static void F_LOCAL     CheckOPTIND (char *, long);
294
static void F_LOCAL     CreateIntegerVariables (void);
295
static bool F_LOCAL     ExecuteShellScript (char *);
296
static void             CountEnvironment (const void *, VISIT, int);
227 dpurdie 297
 
298
/*
299
 * Process termination
300
 */
301
 
302
#if (OS_TYPE != OS_DOS)
5659 dpurdie 303
static void F_LOCAL     CheckForTerminatedProcess (void);
227 dpurdie 304
 
305
#  if (OS_TYPE == OS_NT)
5659 dpurdie 306
static void             LookUpJobs (const void *, VISIT, int);
227 dpurdie 307
#  endif
308
 
309
#else
310
#  define CheckForTerminatedProcess()
311
#endif
312
 
313
/*
314
 * No real argv interface
315
 */
316
 
317
#if (OS_TYPE == OS_UNIX)
318
#define Pre_Process_Argv(a,b)
319
#else
5659 dpurdie 320
static void F_LOCAL     Pre_Process_Argv (char **, int *);
227 dpurdie 321
#endif
322
 
323
/*
324
 * OS/2 Session Queues
325
 */
326
 
327
#if (OS_TYPE == OS_OS2)
5659 dpurdie 328
static void F_LOCAL     CheckForSessionEnd (void);
329
static void F_LOCAL     CreateTerminationQueues (void);
227 dpurdie 330
#else
331
#  define CheckForSessionEnd()
332
#  define CreateTerminationQueues()
333
#endif
334
 
335
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
5659 dpurdie 336
static void F_LOCAL     SetEditorMode (char *);
227 dpurdie 337
#endif
338
 
339
/*
340
 * The Program Name and Command Line, set up by stdargv.c
341
 */
342
 
343
#if (OS_TYPE != OS_UNIX)
5659 dpurdie 344
extern char             *_APgmName;
345
extern char             *_ACmdLine;
227 dpurdie 346
#endif
347
 
255 dpurdie 348
/*
349
**  Debug level
350
*/
351
int debug_level = 0;
227 dpurdie 352
 
353
/*
354
 * The main program starts here
355
 */
356
#if defined(WIN32)
357
void __cdecl main(int argc, char **argv, char **envp)
358
#else
359
void main(int argc, char **argv)
360
#endif
361
{
5659 dpurdie 362
    int                 cflag = 0;
363
    int                 sc;
227 dpurdie 364
    char                *name;
5659 dpurdie 365
                                        /* Load up various parts of the */
366
                                        /* system                       */
227 dpurdie 367
    bool                OptionsRflag;
5659 dpurdie 368
    bool                OptionsXflag = FALSE;   /* -x option from       */
369
                                                /* command line         */
370
    bool                Level0Shell = FALSE;    /* Level 0 (read profile)*/
371
    jmp_buf             ReturnPoint;
372
    char                *cp;
373
    Source              *s;
374
    int                 fid;
375
    bool                TTYInput;
376
    bool                PIPEInput;
377
    bool                RootShell = FALSE;
227 dpurdie 378
 
379
    (void) envp;
380
 
381
    name = *argv;
382
    OptionsRflag = Initialise(argc, argv);
383
 
384
    SetWindowName ((char *)NULL);
385
 
386
/* Create Parse input */
387
 
388
    s = pushs (SFILE);
389
    s->u.file = stdin;
390
 
391
/* Set up start time */
392
 
393
    ShellStartTime = time ((time_t *)NULL);
394
 
395
/* Preprocess options to convert two character options of the form /x to
396
 * -x.  Some programs!!
397
 */
398
 
399
    if (argc > 1)
400
        Pre_Process_Argv (argv, &argc);
401
 
402
/* Save the start directory for when we exit */
403
 
404
    S_getcwd (Start_directory, 0);
405
 
303 dpurdie 406
/* Force Shell Globals as DOS */
407
#if (OS_TYPE == OS_NT) ||(OS_TYPE == OS_DOS)
5659 dpurdie 408
        ShellGlobalFlags |= FLAGS_MSDOS_FORMAT;
303 dpurdie 409
#endif
410
 
227 dpurdie 411
/* Process the options */
412
 
413
    while ((sc = GetOptions (argc, argv, ShellOptions, GETOPT_MESSAGE)) != EOF)
414
    {
5659 dpurdie 415
        switch (sc)
416
        {
417
            case '?':
418
                FinalExitCleanUp (1);
227 dpurdie 419
 
5659 dpurdie 420
            case '0':                           /* Level 0 flag for DOS */
421
                Level0Shell = TRUE;
422
                break;
227 dpurdie 423
 
5659 dpurdie 424
            case 'r':                           /* Restricted           */
425
                OptionsRflag = TRUE;
426
                break;
227 dpurdie 427
 
5659 dpurdie 428
            case 'c':                           /* Command on line      */
429
                ClearUserPrompts ();
430
                cflag = 1;
431
                s->type = SSTRING;
432
                s->str = OptionArgument;
433
                SetVariableFromString ("_cString", OptionArgument);
434
                break;
227 dpurdie 435
 
5659 dpurdie 436
            case 'q':                           /* No quit ints         */
227 dpurdie 437
#ifdef SIGQUIT
5659 dpurdie 438
                qflag = SIG_DFL;
227 dpurdie 439
#endif
5659 dpurdie 440
                break;
227 dpurdie 441
 
442
 
5659 dpurdie 443
            case 'X':
444
                if (!GotoDirectory (OptionArgument, GetCurrentDrive ()))
445
                {
446
                    PrintErrorMessage ("%s: bad directory", OptionArgument);
447
                    FinalExitCleanUp (1);
448
                }
227 dpurdie 449
 
5659 dpurdie 450
                break;
227 dpurdie 451
 
5659 dpurdie 452
            case 'x':
453
                OptionsXflag = TRUE;
454
                break;
227 dpurdie 455
 
5659 dpurdie 456
            case 'M':
457
                ShellGlobalFlags |= FLAGS_MSDOS_FORMAT;
458
                break;
227 dpurdie 459
 
5659 dpurdie 460
            case 'D':
461
                AssignVariableFromString (OptionArgument, (int *)NULL);
462
                break;
227 dpurdie 463
 
5659 dpurdie 464
            case 'R':
465
                RootShell = TRUE;
466
                ChangeInitLoad = TRUE;  /* Change load .ini pt.         */
467
                break;
227 dpurdie 468
 
469
#if (OS_TYPE != OS_DOS)
5659 dpurdie 470
            case 'P':                           /* Use real pipes       */
471
                ShellGlobalFlags |= FLAGS_REALPIPES;
472
                break;
227 dpurdie 473
#endif
474
 
5659 dpurdie 475
            case 's':                           /* standard input       */
476
                if (cflag)
477
                    PrintErrorMessage ("cannot use -s and -c together");
227 dpurdie 478
 
5659 dpurdie 479
            case 'i':                           /* Set interactive      */
480
                InteractiveFlag = TRUE;
227 dpurdie 481
 
5659 dpurdie 482
            default:
483
                if (islower (sc))
484
                    FL_SET (sc);
485
        }
227 dpurdie 486
 
487
/* If -s, set the argv to point to -s so that the rest of the parameters
488
 * get used as parameters ($digit) values.
489
 */
490
 
491
        if (FL_TEST (FLAG_POSITION))
5659 dpurdie 492
        {
493
            OptionIndex--;
494
            break;
495
        }
227 dpurdie 496
    }
497
 
498
/* Under UNIX, check for login shell */
499
 
500
#if (OS_TYPE == OS_UNIX)
501
    if (*argv[0] == '-')
5659 dpurdie 502
        Level0Shell = TRUE;
227 dpurdie 503
#endif
504
 
505
    argv += OptionIndex;
506
    argc -= OptionIndex;
507
 
508
/* Get configuration info */
509
 
510
    Configure_Keys ();
511
 
512
/*
513
 * Check for terminal input.  A special case for OS/2.  If pipe input and
514
 * output and no arguments, set interactive flag.
515
 *
516
 * Unset the variable after!
517
 */
518
 
519
    TTYInput  = C2bool ((IS_TTY (0) && IS_TTY (1)));
520
    PIPEInput = C2bool ((IS_Pipe (0) && IS_Pipe (1) &&
521
                         (GetVariableAsString (LIT_AllowTTY, FALSE) != null)));
522
 
523
    UnSetVariable (LIT_AllowTTY, -1, TRUE);
524
 
525
    if ((s->type == SFILE) &&
526
        ((FL_TEST (FLAG_INTERACTIVE)) || TTYInput || PIPEInput) &&
527
        !cflag &&
528
        ((argc == 0) || FL_TEST (FLAG_POSITION)))
529
    {
530
        s->type = STTY;
531
        FL_SET (FLAG_POSITION);
532
        FL_SET (FLAG_INTERACTIVE);
533
        InteractiveFlag = TRUE;
534
 
535
        if  (TTYInput)
536
            PrintVersionNumber (stderr);
537
    }
538
 
539
/* Root shell - check only tty devices */
540
 
541
    if (RootShell)
542
    {
543
       if ((s->type != STTY) || !TTYInput)
544
            PrintErrorMessage ("-R not valid on non-interactive shells");
545
 
546
#if (OS_TYPE == OS_DOS) && !defined (__EMX__)
547
        Orig_I24_V = (void (INTERRUPT_TYPE *)())NULL;
548
#endif
549
    }
550
 
551
/*
552
 * Execute commands from a file? - disable prompts
553
 */
554
 
555
    if ((s->type == SFILE) && (argc > 0) && !InteractiveFlag)
556
    {
557
        ClearUserPrompts ();
5659 dpurdie 558
        name = *argv;
227 dpurdie 559
 
5659 dpurdie 560
        if (((fid = S_open (FALSE, s->file = name, O_RMASK)) < 0) ||
561
            ((s->u.file = ReOpenFile (ReMapIOHandler (fid), sOpenReadMode))
562
                        == (FILE *)NULL))
563
        {
564
            PrintErrorMessage (LIT_Emsg, "cannot open script", name,
565
                               strerror (errno));
566
            FinalExitCleanUp (1);
567
        }
227 dpurdie 568
 
569
/* Un-map this file descriptor from the current environment so it does not
570
 * get closed at the wrong times
571
 */
572
        ChangeFileDescriptorStatus (fileno (s->u.file), FALSE);
573
 
574
#if (OS_TYPE != OS_DOS)
575
        SetVariableFromString (WinTitleVariable, name);
576
#endif
577
    }
578
 
579
/* Setup stderr, stdout buffering */
580
 
581
    setvbuf (stderr, (char *)NULL, _IONBF, 0);
582
 
583
    if (InteractiveFlag && !IS_TTY (1))
584
        setvbuf (stdout, (char *)NULL, _IOLBF, BUFSIZ);
585
 
586
/* Set up the $- variable */
587
 
588
    SetShellSwitches ();
589
 
590
#ifdef SIGQUIT
591
    signal (SIGQUIT, qflag);
592
#endif
593
 
594
/* Set up signals */
595
 
596
    if (InteractiveFlag)
597
        signal (SIGTERM, TerminateSignalled);
598
 
599
/* Load any parameters */
600
 
601
   SetUpParameterEV (argc, argv, name);
602
 
603
/* Return point */
604
 
605
    if (SetErrorPoint (ReturnPoint))
606
        ExitTheShell (FALSE);
607
 
608
    signal (SIGINT, InterruptSignalled);
609
 
610
/* Read profile ?.  Init EMAC first for binding keys */
611
 
612
    if (((name != (char *)NULL) && (*name == CHAR_HYPHEN)) || Level0Shell)
613
    {
614
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
615
        EMACS_Initialisation ();
616
#endif
617
        LoadTheProfileFiles ();
618
    }
619
 
620
/*
621
 * Load history and configure
622
 */
623
 
624
    if (s->type == STTY)
625
    {
626
        HistoryEnabled = TRUE;
627
        LoadHistory ();
628
    }
629
 
630
/*
631
 * If the x or r flag was set on the command line, set it now after the
632
 * profiles have been executed.
633
 */
634
 
255 dpurdie 635
    if ( debug_level & DEBUG_EXEC_ALL )
227 dpurdie 636
    {
5659 dpurdie 637
        FL_SET (FLAG_DEBUG_EXECUTE);
638
        FL_CLEAR (FLAG_WARNING);
227 dpurdie 639
    }
640
    if (OptionsXflag)
641
    {
642
        FL_SET (FLAG_PRINT_EXECUTE);
643
    }
644
 
645
    if (OptionsRflag)
646
    {
5659 dpurdie 647
        FL_SET (FLAG_READONLY_SHELL);
648
        RestrictedShellFlag = TRUE;
227 dpurdie 649
    }
650
 
651
/*
652
 * Execute $ENV
653
 *
654
 * TOCHECK - substitute (cp, DOTILDE);
655
 */
656
 
657
    if ((cp = GetVariableAsString (ENVVariable, FALSE)) != null)
658
        ExecuteShellScript (cp);
659
 
660
/* If interactive, set up Editor modes */
661
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
662
    if (InteractiveFlag)
663
    {
664
        char    **rep = EditorVariables;
665
 
5659 dpurdie 666
        while (*rep != (char *)NULL)
667
        {
668
            if ((cp = GetVariableAsString (*(rep++), FALSE)) != null)
669
            {
227 dpurdie 670
                SetEditorMode (cp);
5659 dpurdie 671
                break;
672
            }
673
        }
227 dpurdie 674
    }
675
#endif
676
 
677
/*
678
 * Execute what ever we have to do!!
679
 */
680
 
681
//  while (TRUE)
682
    for (;;)
683
    {
5659 dpurdie 684
        switch (SetErrorPoint (ReturnPoint))
685
        {
686
            case TERMINATE_POINT_SET:
687
                RunCommands (s);                /* Drop to exit         */
227 dpurdie 688
 
5659 dpurdie 689
            case TERMINATE_COMMAND:
690
            default:
691
                ExitTheShell (FALSE);
227 dpurdie 692
 
693
/* Re-set TTY input.  If we reach this point, the shell is a root shell and
694
 * the no exit message has been displayed.  Reset the shell for input from the
695
 * TTY.
696
 */
697
 
5659 dpurdie 698
            case TERMINATE_SHELL:
699
                s->type = STTY;
700
                break;
701
        }
227 dpurdie 702
    }
703
}
704
 
705
 
706
/*
707
 * Process a script file
708
 */
709
 
710
static bool F_LOCAL ExecuteShellScript (char *name)
711
{
5659 dpurdie 712
    FILE        *f = stdin;
713
    int         fp;
714
    Source      *s;
227 dpurdie 715
 
716
    if (strcmp (name, "-") != 0)
717
    {
5659 dpurdie 718
        if ((fp = OpenForExecution (name, (char **)NULL, (int *)NULL)) < 0)
719
            return FALSE;
227 dpurdie 720
 
5659 dpurdie 721
        if ((f = ReOpenFile (fp = ReMapIOHandler (fp),
722
                             sOpenReadMode)) == (FILE *)NULL)
723
            return FALSE;
227 dpurdie 724
    }
725
 
726
    (s = pushs (SFILE))->u.file = f;
727
    s->file = name;
728
 
729
    RunCommands (s);
730
 
731
    if (f != stdin)
5659 dpurdie 732
        CloseFile (f);
227 dpurdie 733
 
734
    return TRUE;
735
}
736
 
737
 
738
/*
739
 * run the commands from the input source, returning status.
740
 */
741
 
742
static int F_LOCAL RunCommands (Source *src)
743
{
5659 dpurdie 744
    int         i;
745
    jmp_buf     ReturnPoint;
746
    C_Op        *t = (C_Op *)NULL;
747
    bool        wastty;
748
    int         EntryMemoryLevel = MemoryAreaLevel + 1;
227 dpurdie 749
 
750
    CreateNewEnvironment ();
751
    e.ErrorReturnPoint = (ErrorPoint)NULL;
752
    e.line = GetAllocatedSpace (LINE_MAX);
753
 
754
/*
755
 * Run until the end
756
 */
757
 
758
//  while (TRUE)
759
    for (;;)
760
    {
761
 
762
/* Initialise space */
763
 
5659 dpurdie 764
        MemoryAreaLevel = EntryMemoryLevel;
765
        ReleaseMemoryArea (MemoryAreaLevel);
766
        SW_intr = 0;
767
        ProcessingEXECCommand = FALSE;
227 dpurdie 768
 
5659 dpurdie 769
        if (src->next == NULL)
770
            src->echo = C2bool (FL_TEST (FLAG_ECHO_INPUT));
227 dpurdie 771
 
772
/*
773
 * Set up a few things for console input - cursor, mail prompt etc
774
 */
775
 
5659 dpurdie 776
        if ((wastty = C2bool (src->type == STTY)) != FALSE)
777
        {
778
            PositionCursorInColumnZero ();
779
            CheckForMailArriving ();
780
            CheckForTerminatedProcess ();
781
            CloseAllHandlers ();        /* Clean up any open shell files */
782
        }
227 dpurdie 783
 
5659 dpurdie 784
        LastUserPrompt = PS1;
785
        FlushStreams ();                        /* Clear output */
227 dpurdie 786
 
787
/* Set execute function recursive level and the SubShell count to zero */
788
 
5659 dpurdie 789
        Execute_stack_depth = 0;
227 dpurdie 790
 
791
/* Set up Redirection IO (Saved) array and SubShell Environment information */
792
 
5659 dpurdie 793
        NSave_IO_E = 0;         /* Number of entries            */
794
        MSave_IO_E = 0;         /* Max Number of entries        */
795
        NSubShells = 0;         /* Number of entries            */
796
        MSubShells = 0;         /* Max Number of entries        */
797
        CurrentFunction = (FunctionList *)NULL;
798
        CurrentFunction = (FunctionList *)NULL;
799
        ProcessingDEBUGTrap = FALSE;
800
        ProcessingERRORTrap = FALSE;
801
        Break_List = (Break_C *)NULL;
802
        Return_List = (Break_C *)NULL;
803
        SShell_List = (Break_C *)NULL;
804
        ProcessingEXECCommand = FALSE;
227 dpurdie 805
 
806
/* Get the line and process it */
807
 
5659 dpurdie 808
        if (SetErrorPoint (ReturnPoint) ||
809
            ((t = BuildParseTree (src)) == (C_Op *)NULL) || SW_intr)
810
        {
811
            ScrapHereList ();
227 dpurdie 812
 
5659 dpurdie 813
            if ((!InteractiveFlag && SW_intr) || FL_TEST (FLAG_ONE_COMMAND))
814
                ExitTheShell (FALSE);
227 dpurdie 815
 
816
/* Go round again */
817
 
5659 dpurdie 818
            src->str = null;
819
            SW_intr = 0;
820
            continue;
821
        }
227 dpurdie 822
 
823
/* Ok - reset some variables and then execute the command tree */
824
 
5659 dpurdie 825
        SW_intr = 0;
826
        ProcessingEXECCommand = FALSE;
827
        FlushHistoryBuffer ();          /* Save history                 */
227 dpurdie 828
 
829
/* Check for exit */
830
 
5659 dpurdie 831
        if ((t != NULL) && (t->type == TEOF))
832
        {
833
            if (wastty && (ShellGlobalFlags & FLAGS_IGNOREEOF))
834
            {
835
                PrintWarningMessage ("Use `exit'");
836
                src->type = STTY;
837
                continue;
838
            }
227 dpurdie 839
 
5659 dpurdie 840
            else
841
                break;
842
        }
227 dpurdie 843
 
844
/* Execute the parse tree */
845
 
5659 dpurdie 846
        if ((SetErrorPoint (ReturnPoint) == 0) &&
847
            ((!FL_TEST (FLAG_NO_EXECUTE)) || (src->type == STTY)))
848
            ExecuteParseTree (t, NOPIPE, NOPIPE, 0);
227 dpurdie 849
 
850
/* Make sure the I/O and environment are back at level 0 and then clear them */
851
 
5659 dpurdie 852
        e.ErrorReturnPoint = (ErrorPoint)NULL;
853
        Execute_stack_depth = 0;
854
        ClearExtendedLineFile ();
227 dpurdie 855
 
5659 dpurdie 856
        if (NSubShells != 0)
857
            DeleteGlobalVariableList ();
227 dpurdie 858
 
5659 dpurdie 859
        if (NSave_IO_E)
860
            RestoreStandardIO (0, TRUE);
227 dpurdie 861
 
5659 dpurdie 862
        if (MSubShells)
863
            ReleaseMemoryCell ((void *)SubShells);
227 dpurdie 864
 
5659 dpurdie 865
        if (MSave_IO_E)
866
            ReleaseMemoryCell ((void *)SSave_IO);
227 dpurdie 867
 
868
    /* Check for interrupts */
869
 
5659 dpurdie 870
        if ((!InteractiveFlag && SW_intr) || FL_TEST (FLAG_ONE_COMMAND))
871
        {
872
            ProcessingEXECCommand = FALSE;
873
            ExitTheShell (FALSE);
874
        }
227 dpurdie 875
 
876
/* Run any traps that are required */
877
 
5659 dpurdie 878
        if ((i = InterruptTrapPending) != 0)
879
        {
880
            InterruptTrapPending = 0;
881
            RunTrapCommand (i);
882
        }
227 dpurdie 883
    }
884
 
885
/*
886
 * Terminate the current environment
887
 */
888
 
889
    QuitCurrentEnvironment ();
890
    return ExitStatus;
891
}
892
 
893
 
894
/*
895
 * Set up the value of $-
896
 */
897
 
898
void SetShellSwitches (void)
899
{
5659 dpurdie 900
    char        *cp, c;
901
    char        m['z' - 'a' + 2];
227 dpurdie 902
 
903
    for (cp = m, c = 'a'; c <= 'z'; ++c)
904
    {
5659 dpurdie 905
        if (FL_TEST (c))
906
            *(cp++) = c;
227 dpurdie 907
    }
908
 
909
    if (ShellGlobalFlags & FLAGS_MSDOS_FORMAT)
5659 dpurdie 910
        *(cp++) = 'M';
227 dpurdie 911
 
912
    *cp = 0;
913
    SetVariableFromString (ShellOptionsVariable, m);
914
}
915
 
916
 
917
/*
918
 * Terminate current environment with an error
919
 */
920
 
921
void TerminateCurrentEnvironment (int TValue)
922
{
5659 dpurdie 923
    FlushStreams ();                    /* Clear output */
227 dpurdie 924
 
925
    if (e.ErrorReturnPoint != (ErrorPoint)NULL)
5659 dpurdie 926
        ExitErrorPoint (TValue);
227 dpurdie 927
 
928
    /* NOTREACHED */
929
}
930
 
931
 
932
/*
933
 * Exit the shell
934
 */
935
 
936
void ExitTheShell (bool ReturnRequired)
937
{
5659 dpurdie 938
    FlushStreams ();                    /* Clear output */
227 dpurdie 939
 
940
    if (ProcessingEXECCommand)
5659 dpurdie 941
        TerminateCurrentEnvironment (TERMINATE_COMMAND);
227 dpurdie 942
 
943
#if (OS_TYPE == OS_DOS) && !defined (__EMX__)
944
    if (Orig_I24_V == (void (INTERRUPT_TYPE *)())NULL)
945
    {
5659 dpurdie 946
        feputs (NOExit);
227 dpurdie 947
 
5659 dpurdie 948
        if (!ReturnRequired)
949
            TerminateCurrentEnvironment (TERMINATE_SHELL);
227 dpurdie 950
    }
951
#else
952
    (void) ReturnRequired;
953
#endif
954
 
955
/* Clean up */
956
 
957
    ScrapHereList ();
958
    FreeAllHereDocuments (1);
959
 
960
/* Trap zero on exit */
961
 
962
    RunTrapCommand (0);
963
 
964
/* Dump history on exit */
965
 
966
    DumpHistory ();
967
 
968
    CloseAllHandlers ();
969
 
970
/* If this is a command only - restore the directory because DOS doesn't
971
 * and the user might expect it
972
 */
973
 
974
    if (*Start_directory)
5659 dpurdie 975
        RestoreCurrentDirectory (Start_directory);
227 dpurdie 976
 
977
/* If this happens during startup - we restart */
978
 
979
#if (OS_TYPE == OS_DOS) && !defined (__EMX__)
980
    if (Orig_I24_V == (void (INTERRUPT_TYPE *)())NULL)
5659 dpurdie 981
        return;
227 dpurdie 982
#endif
983
 
984
/*
985
 * Clean up any Here Document files left in the function tree
986
 */
987
 
988
    DeleteAllFunctions ();
989
 
990
/* Exit - hurray */
991
 
992
    FinalExitCleanUp (ExitStatus);
993
 
994
/* NOTREACHED */
995
}
996
 
997
 
998
/*
999
 * Output warning message
1000
 */
1001
 
1002
int PrintWarningMessage (char *fmt, ...)
1003
{
5659 dpurdie 1004
    va_list     ap;
227 dpurdie 1005
 
1006
    va_start (ap, fmt);
1007
    vfprintf (stderr, fmt, ap);
1008
    feputc (CHAR_NEW_LINE);
1009
    ExitStatus = -1;
1010
 
1011
/* If leave on error - exit */
1012
 
1013
    if (FL_TEST (FLAG_EXIT_ON_ERROR))
5659 dpurdie 1014
        ExitTheShell (FALSE);
227 dpurdie 1015
 
1016
    va_end (ap);
1017
    return 1;
1018
}
1019
 
1020
 
1021
/*
1022
 * Shell error message
1023
 */
1024
 
1025
void ShellErrorMessage (char *fmt, ...)
1026
{
5659 dpurdie 1027
    va_list     ap;
227 dpurdie 1028
 
1029
/* Error message processing */
1030
 
1031
    if (source->file == (char *)NULL)
5659 dpurdie 1032
        feputs ("sh: ");
227 dpurdie 1033
 
1034
    else
5659 dpurdie 1035
        fprintf (stderr, "%s: at line %d, ", source->file, source->line);
227 dpurdie 1036
 
1037
    va_start (ap, fmt);
1038
    ProcessErrorExit (fmt, ap);
1039
    va_end (ap);
1040
}
1041
 
1042
 
1043
/*
1044
 * Output error message
1045
 */
1046
 
1047
void PrintErrorMessage (char *fmt, ...)
1048
{
5659 dpurdie 1049
    va_list     ap;
227 dpurdie 1050
 
1051
/* Error message processing */
1052
 
1053
    va_start (ap, fmt);
1054
    ProcessErrorExit (fmt, ap);
1055
    va_end (ap);
1056
}
1057
 
1058
/*
1059
 * Common processing for PrintErrorMessage and ShellError Message
1060
 */
1061
 
1062
static void F_LOCAL ProcessErrorExit (char *fmt, va_list ap)
1063
{
1064
    vfprintf (stderr, fmt, ap);
1065
    feputc (CHAR_NEW_LINE);
1066
 
1067
    ExitStatus = -1;
1068
 
1069
    if (FL_TEST (FLAG_EXIT_ON_ERROR))
5659 dpurdie 1070
        ExitTheShell (FALSE);
227 dpurdie 1071
 
1072
/* Error processing */
1073
 
1074
    if (FL_TEST (FLAG_NO_EXECUTE))
5659 dpurdie 1075
        return;
227 dpurdie 1076
 
1077
/* If not interactive - exit */
1078
 
1079
    if (!InteractiveFlag)
5659 dpurdie 1080
        ExitTheShell (FALSE);
227 dpurdie 1081
 
1082
    if (e.ErrorReturnPoint != (ErrorPoint)NULL)
5659 dpurdie 1083
        ExitErrorPoint (TERMINATE_COMMAND);
227 dpurdie 1084
 
1085
/* CloseAllHandlers (); Removed - caused problems.  There may be problems
1086
 * remaining with files left open?
1087
 */
1088
}
1089
 
1090
 
1091
/*
1092
 * Create or delete a new environment.  If f is set, delete the environment
1093
 */
1094
 
1095
void CreateNewEnvironment (void)
1096
{
5659 dpurdie 1097
    ShellFileEnvironment        *ep;
227 dpurdie 1098
 
1099
/* Create a new environment */
1100
 
1101
    if ((ep = (ShellFileEnvironment *)
5659 dpurdie 1102
                GetAllocatedSpace (sizeof (ShellFileEnvironment)))
1103
                == (ShellFileEnvironment *)NULL)
227 dpurdie 1104
    {
5659 dpurdie 1105
        while (e.PreviousEnvironment)
1106
            QuitCurrentEnvironment ();
227 dpurdie 1107
 
5659 dpurdie 1108
        TerminateCurrentEnvironment (TERMINATE_COMMAND);
227 dpurdie 1109
    }
1110
 
1111
    *ep = e;
1112
    e.PreviousEnvironment = ep;
1113
    e.IOMap = 0L;
1114
    e.OpenStreams = (Word_B *)NULL;
1115
}
1116
 
1117
 
1118
/*
1119
 * Exit the current environment successfully
1120
 */
1121
 
1122
void QuitCurrentEnvironment (void)
1123
{
5659 dpurdie 1124
    ShellFileEnvironment        *ep;
1125
    unsigned long               FdMap;
1126
    Word_B                      *wb;
1127
    int                         NEntries;
1128
    int                         i;
227 dpurdie 1129
 
1130
/* Restore old environment, delete the space and close any files opened in
1131
 * this environment
1132
 */
1133
 
1134
    if ((ep = e.PreviousEnvironment) != (ShellFileEnvironment *)NULL)
1135
    {
1136
 
1137
/* Close opened streams */
1138
 
5659 dpurdie 1139
        wb = e.OpenStreams;
1140
        NEntries = WordBlockSize (wb);
227 dpurdie 1141
 
5659 dpurdie 1142
        for (i = 0; i < NEntries; i++)
1143
        {
1144
            if (wb->w_words[i] != (char *)NULL)
1145
                fclose ((FILE *)wb->w_words[i]);
1146
        }
227 dpurdie 1147
 
1148
/* Get the files used in this environment to close */
1149
 
5659 dpurdie 1150
        FdMap = e.IOMap;
1151
        e = *ep;
227 dpurdie 1152
 
5659 dpurdie 1153
        ReleaseMemoryCell ((void *)ep);
227 dpurdie 1154
 
5659 dpurdie 1155
        for (i = 0; i < 32; i++)
1156
        {
1157
            if (FdMap & (1L << i))
1158
                S_close (i + FDBASE, TRUE);
1159
        }
227 dpurdie 1160
    }
1161
}
1162
 
1163
/*
1164
 * Convert binary to ascii
1165
 */
1166
 
1167
char *IntegerToString (int n)
1168
{
5659 dpurdie 1169
    static char         nt[10];
227 dpurdie 1170
 
1171
    sprintf (nt, "%u", n);
1172
    return nt;
1173
}
1174
 
1175
/*
1176
 * SIGINT interrupt processing
1177
 */
1178
void _SIGDECL InterruptSignalled (int signo)
1179
{
1180
/* Restore signal processing and set SIGINT detected flag */
1181
 
1182
    signal (signo, InterruptSignalled);
1183
 
1184
#ifdef SIGNALDEBUG
1185
    fprintf (stderr, "Interrupt %d detected\n", signo); fflush (stderr);
1186
#endif
1187
 
1188
/* Under OS/2, if the Ignore Interrupts flag is set, ignore them.  To do
1189
 * with starting OS/2 programs in sh3.c
1190
 */
1191
 
1192
#if (OS_TYPE != OS_DOS)
1193
    if (IgnoreInterrupts)
1194
        return;
1195
#endif
1196
 
1197
/* Set interrupt detected */
1198
 
1199
    SW_intr = 1;
1200
 
1201
/* Are we talking to the user?  Yes - Abandon processing */
1202
 
1203
    if (InteractiveFlag)
5659 dpurdie 1204
        TerminateCurrentEnvironment (TERMINATE_COMMAND);
227 dpurdie 1205
 
1206
/* No - exit */
1207
 
1208
    else
1209
    {
5659 dpurdie 1210
        ProcessingEXECCommand = FALSE;
1211
        ExitStatus = 1;
1212
        ExitTheShell (FALSE);
227 dpurdie 1213
    }
1214
}
1215
 
1216
/*
1217
 * Grap some space and check for an error
1218
 */
1219
 
1220
void *GetAllocatedSpace (size_t n)
1221
{
5659 dpurdie 1222
    void        *cp;
227 dpurdie 1223
 
1224
    if ((cp = AllocateMemoryCell (n)) == (void *)NULL)
5659 dpurdie 1225
        PrintErrorMessage (BasicErrorMessage, ShellNameLiteral, Outofmemory1);
227 dpurdie 1226
 
1227
    return cp;
1228
}
1229
 
1230
/*
1231
 * Re-allocate some space
1232
 */
1233
 
1234
void *ReAllocateSpace (void *OldSpace, size_t NewSize)
1235
{
5659 dpurdie 1236
    void        *NewSpace;
227 dpurdie 1237
 
1238
    if ((NewSpace = GetAllocatedSpace (NewSize)) == (void *)NULL)
1239
        return NewSpace;
1240
 
1241
    if (OldSpace != (void *)NULL)
1242
    {
5659 dpurdie 1243
        size_t  OldSize = ((s_region *)((char *)OldSpace -
1244
                                        sizeof (s_region)))->nbytes;
227 dpurdie 1245
 
5659 dpurdie 1246
        SetMemoryAreaNumber (NewSpace, GetMemoryAreaNumber (OldSpace));
1247
        memcpy (NewSpace, OldSpace, OldSize);
1248
        ReleaseMemoryCell (OldSpace);
227 dpurdie 1249
    }
1250
 
1251
    return NewSpace;
1252
}
1253
 
1254
 
1255
/*
1256
 * Duplicate a memory Area
1257
 */
1258
 
1259
void *DuplicateMemoryCell (void *cell)
1260
{
5659 dpurdie 1261
    void        *new;
1262
    size_t      len = ((s_region *)((char *)cell - sizeof (s_region)))->nbytes;
227 dpurdie 1263
 
1264
    if ((new = AllocateMemoryCell (len)) == (void *)NULL)
5659 dpurdie 1265
        PrintErrorMessage (BasicErrorMessage, ShellNameLiteral, Outofmemory1);
227 dpurdie 1266
 
1267
    else
5659 dpurdie 1268
        memcpy (new, cell, len);
227 dpurdie 1269
 
1270
    return new;
1271
}
1272
 
1273
 
1274
/*
1275
 * Get memory Area size
1276
 */
1277
 
1278
size_t GetMemoryCellSize (void *cell)
1279
{
1280
    return ((s_region *)((char *)cell - sizeof (s_region)))->nbytes;
1281
}
1282
 
1283
/*
1284
 * Save a string in a given area
1285
 */
1286
 
1287
char *StringSave (char *s)
1288
{
5659 dpurdie 1289
    char        *cp;
227 dpurdie 1290
 
1291
    if ((cp = GetAllocatedSpace (strlen (s) + 1)) != (char *)NULL)
1292
    {
5659 dpurdie 1293
        SetMemoryAreaNumber ((void *)cp, 0);
1294
        return strcpy (cp, s);
227 dpurdie 1295
    }
1296
 
1297
    return null;
1298
}
1299
 
1300
/*
1301
 * Duplicate at current Memory level
1302
 */
1303
 
1304
char *StringCopy (char *s)
1305
{
5659 dpurdie 1306
    char        *cp;
227 dpurdie 1307
 
1308
    if ((cp = GetAllocatedSpace (strlen (s) + 1)) != (char *)NULL)
5659 dpurdie 1309
        return strcpy (cp, s);
227 dpurdie 1310
 
1311
    return null;
1312
}
1313
 
1314
/*
1315
 * trap handling - Save signal number and restore signal processing
1316
 */
1317
 
1318
void _SIGDECL TerminateSignalled (int i)
1319
{
5659 dpurdie 1320
    if (i == SIGINT)            /* Need this because swapper sets it    */
227 dpurdie 1321
    {
5659 dpurdie 1322
        SW_intr = 0;
227 dpurdie 1323
    }
1324
 
1325
    InterruptTrapPending = i;
1326
    signal (i, TerminateSignalled);
1327
}
1328
 
1329
/*
1330
 * Execute a trap command
1331
 *
1332
 *  0 - exit trap
1333
 * -1 - Debug Trap
1334
 * -2 - Error Trap
1335
 */
1336
 
1337
void RunTrapCommand (int i)
1338
{
5659 dpurdie 1339
    Source      *s;
1340
    char        *trapstr;
1341
    char        tval[10];
1342
    char        *tvalp = tval;
227 dpurdie 1343
 
1344
/* Check for special values and recursion */
1345
 
1346
    if (i == -1)
1347
    {
5659 dpurdie 1348
        tvalp = Trap_DEBUG;
227 dpurdie 1349
 
5659 dpurdie 1350
        if (ProcessingDEBUGTrap)
1351
            return;
227 dpurdie 1352
 
5659 dpurdie 1353
        ProcessingDEBUGTrap = TRUE;
227 dpurdie 1354
    }
1355
 
1356
/* Error trap */
1357
 
1358
    else if (i == -2)
1359
    {
5659 dpurdie 1360
        tvalp = Trap_ERR;
227 dpurdie 1361
 
5659 dpurdie 1362
        if (ProcessingERRORTrap)
1363
            return;
227 dpurdie 1364
 
5659 dpurdie 1365
        ProcessingERRORTrap = TRUE;
227 dpurdie 1366
    }
1367
 
1368
    else
5659 dpurdie 1369
        sprintf (tval, "~%d", i);
227 dpurdie 1370
 
1371
    if ((trapstr = GetVariableAsString (tvalp, FALSE)) == null)
5659 dpurdie 1372
        return;
227 dpurdie 1373
 
1374
/* If signal zero, save a copy of the trap value and then delete the trap */
1375
 
1376
    if (i == 0)
1377
    {
5659 dpurdie 1378
        trapstr = StringCopy (trapstr);
1379
        UnSetVariable (tval, -1, TRUE);
227 dpurdie 1380
    }
1381
 
1382
    (s = pushs (SSTRING))->str = trapstr;
1383
    RunACommand (s, (char **)NULL);
1384
 
1385
    ProcessingDEBUGTrap = FALSE;
1386
    ProcessingERRORTrap = FALSE;
1387
}
1388
 
1389
/*
1390
 * Find the given name in the dictionary and return its value.  If the name was
1391
 * not previously there, enter it now and return a null value.
1392
 */
1393
 
1394
VariableList    *LookUpVariable (char *name,    /* Variable name        */
5659 dpurdie 1395
                                 int  Index,    /* Array Index          */
1396
                                 bool cflag)    /* Create flag          */
227 dpurdie 1397
{
5659 dpurdie 1398
    VariableList                *vp;
1399
    VariableList                **vpp;
1400
    int                         c;
1401
    static VariableList         dummy;
227 dpurdie 1402
    void                        (_SIGDECL *save_signal)(int);
1403
 
1404
/* Set up the dummy variable */
1405
 
1406
    memset (&dummy, 0, sizeof (VariableList));
1407
    dummy.name = name;
1408
    dummy.status = STATUS_READONLY;
1409
    dummy.value = null;
1410
 
1411
/* If digit string - use the dummy to return the value */
1412
 
1413
    if (isdigit (*name))
1414
    {
5659 dpurdie 1415
        for (c = 0; isdigit (*name) && (c < 1000); name++)
1416
            c = c * 10 + *name - '0';
227 dpurdie 1417
 
5659 dpurdie 1418
        c += Index;
1419
        dummy.value = (c <= ParameterCount) ? ParameterArray[c] : null;
1420
        return &dummy;
227 dpurdie 1421
    }
1422
 
1423
/* Look up in list */
1424
 
1425
    dummy.index = Index;
1426
    vpp = (VariableList **)tfind (&dummy, &VariableTree, SearchVariable);
1427
 
1428
/* If we found it, return it */
1429
 
1430
    if (vpp != (VariableList **)NULL)
1431
    {
1432
        vp = *vpp;
1433
 
1434
/* Special processing for SECONDS and RANDOM */
1435
 
5659 dpurdie 1436
        if (!strcmp (name, SecondsVariable) &&
1437
            !(DisabledVariables & DISABLE_SECONDS))
1438
            SetUpANumericValue (vp, time ((time_t *)NULL) - ShellStartTime, 10);
227 dpurdie 1439
 
5659 dpurdie 1440
        else if (!strcmp (name, RandomVariable) &&
1441
                 !(DisabledVariables & DISABLE_RANDOM))
1442
            SetUpANumericValue (vp, (long)rand(), 10);
227 dpurdie 1443
 
5659 dpurdie 1444
        return vp;
227 dpurdie 1445
    }
1446
 
1447
/* If we don't want to create it, return a dummy */
1448
 
1449
    dummy.status |= STATUS_NOEXISTANT;
1450
 
1451
    if (!cflag)
5659 dpurdie 1452
        return &dummy;
227 dpurdie 1453
 
1454
/* Create a new variable.  If no memory, use the dummy */
1455
 
1456
    dummy.name = null;
1457
 
1458
    if ((vp = (VariableList *)GetAllocatedSpace (sizeof (VariableList)))
5659 dpurdie 1459
                == (VariableList *)NULL)
1460
        return &dummy;
227 dpurdie 1461
 
1462
    if ((vp->name = StringCopy (name)) == null)
1463
    {
5659 dpurdie 1464
        ReleaseMemoryCell ((void *)vp);
1465
        return &dummy;
227 dpurdie 1466
    }
1467
 
1468
/* Set values */
1469
 
1470
    vp->value = null;
1471
    vp->index = Index;
1472
    vp->status = NSubShells ? 0 : STATUS_GLOBAL;
1473
 
1474
/* Save signals */
1475
 
1476
    save_signal = signal (SIGINT, SIG_IGN);
1477
 
1478
/* Add to the tree */
1479
 
1480
    if (tsearch (vp, &VariableTree, SearchVariable) == (void *)NULL)
1481
    {
5659 dpurdie 1482
        ReleaseMemoryCell ((void *)vp->name);
1483
        ReleaseMemoryCell ((void *)vp);
227 dpurdie 1484
        vp = &dummy;
1485
    }
1486
 
1487
/* OK Added OK - set up memory */
1488
 
1489
    else
1490
    {
5659 dpurdie 1491
        SetMemoryAreaNumber ((void *)vp, 0);
1492
        SetMemoryAreaNumber ((void *)vp->name, 0);
227 dpurdie 1493
    }
1494
 
1495
/* Restore signals */
1496
 
1497
    signal (SIGINT, save_signal);
1498
 
1499
    return vp;
1500
}
1501
 
1502
/*
1503
 * Count the number of entries in an Array Variable
1504
 */
1505
 
1506
int     CountVariableArraySize (char *name)
1507
{
1508
    if (isdigit (*name))
5659 dpurdie 1509
        return ParameterCount;
227 dpurdie 1510
 
1511
    Count_Array = 0;
1512
    Count_Name = name;
1513
    twalk (VariableTree, CountEnvironment);
1514
    return Count_Array;
1515
}
1516
 
1517
/*
1518
 * TWALK - Count the Environment Variables in an array
1519
 */
1520
 
1521
static void CountEnvironment (const void *key, VISIT visit, int level)
1522
{
1523
    (void) level;
1524
 
1525
    if (((visit == postorder) || (visit == leaf)) &&
1526
       (strcmp (Count_Name, (*(VariableList **)key)->name) == 0))
5659 dpurdie 1527
        Count_Array++;
227 dpurdie 1528
}
1529
 
1530
/*
1531
 * TFIND & TSEARCH - Search the VARIABLE TREE for an entry
1532
 */
1533
 
5659 dpurdie 1534
int     SearchVariable (const void *key1, const void *key2)
227 dpurdie 1535
{
5659 dpurdie 1536
    int                 diff;
227 dpurdie 1537
 
1538
    if ((diff = strcmp (((VariableList *)key1)->name,
5659 dpurdie 1539
                        ((VariableList *)key2)->name)) != 0)
1540
        return diff;
227 dpurdie 1541
 
1542
    return ((VariableList *)key1)->index - ((VariableList *)key2)->index;
1543
}
1544
 
1545
/*
1546
 * Execute an assignment.  If a valid assignment, load it into the variable
1547
 * list.
1548
 *
1549
 * If value is not NULL, assign it.  Otherwise don't
1550
 */
1551
 
1552
bool    AssignVariableFromString (char *String, /* assignment string       */
1553
                                  int  *Index)  /* Index value returned    */
1554
{
5659 dpurdie 1555
    char        *cp;
1556
    long        value = 0;
227 dpurdie 1557
 
1558
/* Ignore if not valid environment variable - check alpha and equals */
1559
 
1560
    if (!GetVariableName (String, &value, &cp, (bool*)NULL) ||
5659 dpurdie 1561
        (*cp != CHAR_ASSIGN))
227 dpurdie 1562
    {
5659 dpurdie 1563
        if (value == -1)
1564
            PrintErrorMessage (LIT_BadArray, String);
227 dpurdie 1565
 
5659 dpurdie 1566
        return FALSE;
227 dpurdie 1567
    }
1568
 
1569
/* Change the = to a end of string */
1570
 
1571
    *(cp++) = 0;
1572
 
1573
/* Assign the value */
1574
 
1575
    SetVariableArrayFromString (String, (int)value, cp);
1576
 
1577
/* Return the index */
1578
 
1579
    if (Index != (int *)NULL)
5659 dpurdie 1580
        *Index = (int)value;
227 dpurdie 1581
 
1582
    return TRUE;
1583
}
1584
 
1585
/*
1586
 * Get variable name and index
1587
 *
1588
 * String either ends in a null or assignment
1589
 */
1590
 
1591
bool    GetVariableName (char *String,  /* The original string          */
5659 dpurdie 1592
                         long *Index,   /* Array index value found      */
1593
                         char **Value,  /* Pointer to the value         */
1594
                         bool *Array)   /* Array detected flag          */
227 dpurdie 1595
{
1596
    char        *cp, *sp;
5659 dpurdie 1597
    char        EndName;
227 dpurdie 1598
 
1599
    *Index = 0;
1600
 
1601
/* Ignore if not valid environment variable - check alpha and equals */
1602
 
1603
    if (((EndName = IsValidVariableName (String)) != CHAR_ASSIGN) &&
5659 dpurdie 1604
        (EndName != CHAR_OPEN_BRACKETS) && EndName)
1605
        return FALSE;
227 dpurdie 1606
 
1607
    if ((cp = strchr (String, CHAR_ASSIGN)) == (char *)NULL)
5659 dpurdie 1608
        cp = &String[strlen (String)];
227 dpurdie 1609
 
1610
    if (Array != (bool *)NULL)
5659 dpurdie 1611
        *Array = C2bool (EndName == CHAR_OPEN_BRACKETS);
227 dpurdie 1612
 
1613
/* Check for valid array */
1614
 
1615
    if (EndName == CHAR_OPEN_BRACKETS)
1616
    {
5659 dpurdie 1617
        if ((Index == (long *)NULL) || (*(cp - 1) != CHAR_CLOSE_BRACKETS))
1618
            return FALSE;
227 dpurdie 1619
 
1620
/* Terminate the name and remove the trailing bracket */
1621
 
5659 dpurdie 1622
        *(sp = strchr (String, CHAR_OPEN_BRACKETS)) = 0;
1623
        *(cp - 1) = 0;
227 dpurdie 1624
 
5659 dpurdie 1625
        if ((!ConvertNumericValue (sp + 1, Index, 10)) ||
1626
            (*Index < 0) || (*Index > INT_MAX))
1627
        {
1628
            *Index = -1;
1629
            return FALSE;
1630
        }
227 dpurdie 1631
    }
1632
 
1633
/* Return pointer to null or assignment */
1634
 
1635
    *Value = cp;
1636
    return TRUE;
1637
}
1638
 
1639
/*
1640
 * Duplicate the Variable List for a Subshell
1641
 *
1642
 * Create a new Var_list environment for a Sub Shell
1643
 */
1644
 
1645
int CreateGlobalVariableList (unsigned int Function)
1646
{
5659 dpurdie 1647
    int                 i;
1648
    S_SubShell          *sp;
227 dpurdie 1649
 
1650
    for (sp = SubShells, i = 0; (i < NSubShells) &&
5659 dpurdie 1651
                               (SubShells[i].depth < Execute_stack_depth);
1652
         i++);
227 dpurdie 1653
 
1654
/* If depth is greater or equal to the Execute_stack_depth - we should panic
1655
 * as this should not happen.  However, for the moment, I'll ignore it
1656
 */
1657
 
1658
    if (NSubShells == MSubShells)
1659
    {
5659 dpurdie 1660
        sp = (S_SubShell *)ReAllocateSpace ((MSubShells == 0) ? (void *)NULL
1661
                                                              : SubShells,
1662
                                            (MSubShells + SSAVE_IO_SIZE) *
1663
                                                sizeof (S_SubShell));
227 dpurdie 1664
/* Check for error */
1665
 
5659 dpurdie 1666
        if (sp == (S_SubShell *)NULL)
1667
            return -1;
227 dpurdie 1668
 
5659 dpurdie 1669
        SetMemoryAreaNumber ((void *)sp, 0);
1670
        SubShells = sp;
1671
        MSubShells += SSAVE_IO_SIZE;
227 dpurdie 1672
    }
1673
 
1674
/* Save the depth and the old Variable Tree value */
1675
 
1676
    sp = &SubShells[NSubShells++];
1677
    sp->OldVariableTree = VariableTree;
1678
    sp->depth  = Execute_stack_depth;
1679
    sp->GFlags = ShellGlobalFlags | Function;
1680
    sp->Eflags = flags;
1681
    VariableTree = (void *)NULL;
1682
 
1683
/* Duplicate the old Variable list */
1684
 
1685
    ATNE_Function = Function;
1686
    twalk (sp->OldVariableTree, AddToNewEnvironment);
1687
 
1688
/* Reset global values */
1689
 
1690
    LoadGlobalVariableList ();
1691
    return 0;
1692
}
1693
 
1694
/*
1695
 * TWALK - add to new environment
1696
 */
1697
 
1698
static void AddToNewEnvironment (const void *key, VISIT visit, int level)
1699
{
5659 dpurdie 1700
    VariableList        *vp = *(VariableList **)key;
1701
    VariableList        *vp1;
227 dpurdie 1702
 
1703
    (void) level;
1704
 
1705
    if ((visit == postorder) || (visit == leaf))
1706
    {
1707
 
1708
/* For functions, do not copy the traps */
1709
 
5659 dpurdie 1710
        if (ATNE_Function && (*vp->name == CHAR_TILDE) && vp->name[1])
1711
            return;
227 dpurdie 1712
 
1713
/* Create a new entry */
1714
 
5659 dpurdie 1715
        vp1 = LookUpVariable (vp->name, vp->index, TRUE);
227 dpurdie 1716
 
5659 dpurdie 1717
        if ((!(vp->status & STATUS_INTEGER)) && (vp->value != null))
1718
            vp1->value = StringSave (vp->value);
227 dpurdie 1719
 
1720
/* Copy some flags */
1721
 
5659 dpurdie 1722
        vp1->status = vp->status;
1723
        vp1->nvalue = vp->nvalue;
1724
        vp1->base = vp->base;
1725
        vp1->width = vp->width;
227 dpurdie 1726
    }
1727
}
1728
 
1729
/*
1730
 * Delete a SubShell environment and restore the original
1731
 */
1732
 
1733
void DeleteGlobalVariableList (void)
1734
{
5659 dpurdie 1735
    int                 j;
1736
    S_SubShell          *sp;
1737
    VariableList        *vp;
227 dpurdie 1738
    void                (_SIGDECL *save_signal)(int);
1739
 
1740
    for (j = NSubShells; j > 0; j--)
1741
    {
1742
       sp = &SubShells[j - 1];
1743
 
1744
       if (sp->depth < Execute_stack_depth)
5659 dpurdie 1745
           break;
227 dpurdie 1746
 
1747
/* Reduce number of entries */
1748
 
5659 dpurdie 1749
        --NSubShells;
227 dpurdie 1750
 
1751
/* Disable signals */
1752
 
5659 dpurdie 1753
        save_signal = signal (SIGINT, SIG_IGN);
227 dpurdie 1754
 
1755
/* Restore the previous level information */
1756
 
5659 dpurdie 1757
        vp = VariableTree;
1758
        VariableTree = sp->OldVariableTree;
1759
        ShellGlobalFlags = (unsigned int)(sp->GFlags & ~FLAGS_FUNCTION);
1760
        flags = sp->Eflags;
227 dpurdie 1761
 
1762
/* Release the space */
1763
 
5659 dpurdie 1764
        ATOE_GFlags = sp->GFlags;
227 dpurdie 1765
 
5659 dpurdie 1766
        twalk (vp, AddToOldEnvironment);
1767
        twalk (vp, DeleteEnvironment);
227 dpurdie 1768
 
1769
/* Restore signals */
1770
 
5659 dpurdie 1771
        signal (SIGINT, save_signal);
227 dpurdie 1772
 
5659 dpurdie 1773
        LoadGlobalVariableList ();
227 dpurdie 1774
    }
1775
}
1776
 
1777
/*
1778
 * TWALK - delete old environment tree
1779
 */
1780
 
1781
static void DeleteEnvironment (const void *key, VISIT visit, int level)
1782
{
5659 dpurdie 1783
    VariableList        *vp = *(VariableList **)key;
227 dpurdie 1784
 
1785
    (void) level;
1786
 
1787
    if ((visit == endorder) || (visit == leaf))
1788
    {
1789
        if (vp->value == null)
1790
            ReleaseMemoryCell ((void *)vp->value);
1791
 
1792
        ReleaseMemoryCell ((void *)vp->name);
1793
        ReleaseMemoryCell ((void *)vp);
1794
    }
1795
}
1796
 
1797
/*
1798
 * TWALK - Transfer Current Environment to the Old one
1799
 */
1800
 
1801
static void AddToOldEnvironment (const void *key, VISIT visit, int level)
1802
{
5659 dpurdie 1803
    VariableList        *vp = *(VariableList **)key;
1804
    VariableList        *vp1;
227 dpurdie 1805
 
1806
    (void) level;
1807
 
1808
    if ((visit == postorder) || (visit == leaf))
1809
    {
1810
 
1811
/* Skip local variables and traps */
1812
 
5659 dpurdie 1813
        if ((ATOE_GFlags & FLAGS_FUNCTION) && (!(vp->status & STATUS_LOCAL)) &&
1814
            (((*vp->name != CHAR_TILDE) || !vp->name[1])))
1815
        {
227 dpurdie 1816
 
1817
/* Get the entry in the old variable list and update it with the new
1818
 * parameters
1819
 */
5659 dpurdie 1820
            vp1 = LookUpVariable (vp->name, vp->index, TRUE);
227 dpurdie 1821
 
5659 dpurdie 1822
            if (vp1->value != null)
1823
                ReleaseMemoryCell ((void *)vp1->value);
227 dpurdie 1824
 
5659 dpurdie 1825
            vp1->value = vp->value;
1826
            vp->value = null;           /* Stop releaseing this as its tx */
227 dpurdie 1827
 
5659 dpurdie 1828
            vp1->status = vp->status;
1829
            vp1->nvalue = vp->nvalue;
1830
            vp1->base   = vp->base;
1831
            vp1->width  = vp->width;
1832
        }
227 dpurdie 1833
    }
1834
}
1835
 
1836
/*
1837
 * Load GLobal Var List values
1838
 */
1839
 
1840
static void F_LOCAL LoadGlobalVariableList (void)
1841
{
5659 dpurdie 1842
    VariableList        *cifs = LookUpVariable (IFS, 0, TRUE);
227 dpurdie 1843
 
1844
    CurrentDirectory = LookUpVariable (tilde, 0, TRUE);
1845
    RestoreCurrentDirectory (CurrentDirectory->value);
1846
    SetCharacterTypes (cifs->value, C_IFS);
1847
}
1848
 
1849
/*
1850
 * Match a pattern as in sh(1).  Enhancement to handle prefix processing
1851
 *
1852
 * IgnoreCase - ignore case on comparisions.
1853
 * end - end of match in 'string'.
1854
 * mode - mode for match processing - see GM_ flags in sh.h
1855
 *
1856
 * pattern character are prefixed with MAGIC by expand.
1857
 */
1858
 
5659 dpurdie 1859
bool GeneralPatternMatch (char          *string,        /* String       */
1860
                          unsigned char *pattern,       /* Pattern      */
1861
                          bool          IgnoreCase,     /* Ignorecase   */
1862
                          char          **end,          /* End of match */
1863
                          int           mode)           /* Mode         */
227 dpurdie 1864
{
5659 dpurdie 1865
    int         string_c, pattern_c;
1866
    char        *save_end;
227 dpurdie 1867
 
1868
    if ((string == (char *)NULL) || (pattern == (unsigned char *)NULL))
5659 dpurdie 1869
        return FALSE;
227 dpurdie 1870
 
1871
    while ((pattern_c = *(pattern++)) != 0)
1872
    {
5659 dpurdie 1873
        string_c = *(string++);
227 dpurdie 1874
 
5659 dpurdie 1875
        if (pattern_c != CHAR_MAGIC)
1876
        {
1877
            if (IgnoreCase)
1878
            {
1879
                string_c = tolower (string_c);
1880
                pattern_c = tolower (pattern_c);
1881
            }
227 dpurdie 1882
 
5659 dpurdie 1883
            if (string_c != pattern_c)
1884
                return FALSE;
227 dpurdie 1885
 
5659 dpurdie 1886
            continue;
1887
        }
227 dpurdie 1888
 
1889
/* Magic characters */
1890
 
5659 dpurdie 1891
        switch (*(pattern++))
1892
        {
1893
            case CHAR_OPEN_BRACKETS:    /* Class expression             */
1894
                if ((!string_c) ||
1895
                    ((pattern = CheckClassExpression (pattern, string_c,
1896
                                                     IgnoreCase)) ==
1897
                                (unsigned char *)NULL))
1898
                    return FALSE;
227 dpurdie 1899
 
5659 dpurdie 1900
                break;
227 dpurdie 1901
 
5659 dpurdie 1902
            case CHAR_MATCH_ANY:        /* Match any character          */
1903
                if (string_c == 0)
1904
                    return FALSE;
227 dpurdie 1905
 
5659 dpurdie 1906
                break;
227 dpurdie 1907
 
5659 dpurdie 1908
            case CHAR_MATCH_ALL:        /* Match as many as possible    */
1909
                --string;
1910
                save_end = (char *)NULL;
227 dpurdie 1911
 
5659 dpurdie 1912
                do
1913
                {
1914
                    if (!*pattern ||
1915
                        GeneralPatternMatch (string, pattern, IgnoreCase, end,
1916
                                             mode))
1917
                    {
1918
                        if (mode == GM_LONGEST)
1919
                            save_end = *end;
227 dpurdie 1920
 
5659 dpurdie 1921
                        else
1922
                            return TRUE;
1923
                    }
227 dpurdie 1924
 
5659 dpurdie 1925
                } while (*(string++));
227 dpurdie 1926
 
5659 dpurdie 1927
                if (end != (char **)NULL)
1928
                    *end = save_end;
227 dpurdie 1929
 
5659 dpurdie 1930
                return C2bool (save_end != (char *)NULL);
227 dpurdie 1931
 
5659 dpurdie 1932
            default:            /* Match                                */
1933
                if ((unsigned)string_c != pattern[-1])
1934
                    return FALSE;
227 dpurdie 1935
 
5659 dpurdie 1936
                break;
1937
        }
227 dpurdie 1938
    }
1939
 
1940
    if (end != (char **)NULL)
1941
    {
5659 dpurdie 1942
        *end = string;
1943
        return TRUE;
227 dpurdie 1944
    }
1945
 
1946
    return C2bool (*string == 0);
1947
}
1948
 
1949
/*
1950
 * Process a class expression - []
1951
 */
1952
 
1953
static unsigned char * F_LOCAL CheckClassExpression (
5659 dpurdie 1954
                                unsigned char   *pattern,
1955
                                int             string_c, /* Match char*/
1956
                                bool            IgnoreCase)/* Ic flag   */
227 dpurdie 1957
{
5659 dpurdie 1958
    int         llimit_c, ulimit_c;
1959
    bool        not = FALSE;
1960
    bool        found;
227 dpurdie 1961
 
1962
/* Exclusive or inclusive class */
1963
 
1964
    if ((*pattern == CHAR_MAGIC) &&
5659 dpurdie 1965
        ((*(pattern + 1) == CHAR_NOT) || (*(pattern + 1) == '!')))
227 dpurdie 1966
    {
5659 dpurdie 1967
        pattern += 2;
1968
        not = TRUE;
227 dpurdie 1969
    }
1970
 
1971
    found = not;
1972
 
1973
/* Process the pattern */
1974
 
1975
    do
1976
    {
5659 dpurdie 1977
        if (*pattern == CHAR_MAGIC)
1978
            pattern++;
227 dpurdie 1979
 
5659 dpurdie 1980
        if (!*pattern)
1981
            return (unsigned char *)NULL;
227 dpurdie 1982
 
1983
/* Get the next character in class, converting to lower case if necessary */
1984
 
5659 dpurdie 1985
        llimit_c = IgnoreCase ? tolower (*pattern) : *pattern;
227 dpurdie 1986
 
1987
/* If this is a range, get the end of range character */
1988
 
5659 dpurdie 1989
        if ((*(pattern + 1) == CHAR_MATCH_RANGE) &&
1990
            (*(pattern + 2) != CHAR_CLOSE_BRACKETS))
1991
        {
1992
            ulimit_c = IgnoreCase ? tolower (*(pattern + 2)) : *(pattern + 2);
1993
            pattern++;
1994
        }
227 dpurdie 1995
 
5659 dpurdie 1996
        else
1997
            ulimit_c = llimit_c;
227 dpurdie 1998
 
1999
/* Is the current character in the class? */
2000
 
5659 dpurdie 2001
        if ((llimit_c <= string_c) && (string_c <= ulimit_c))
2002
            found = C2bool (!not);
227 dpurdie 2003
 
2004
    } while (*(++pattern) != CHAR_CLOSE_BRACKETS);
2005
 
2006
    return found ? pattern + 1 : (unsigned char *)NULL;
2007
}
2008
 
2009
/*
2010
 * Suffix processing - find the longest/shortest suffix.
2011
 */
2012
 
5659 dpurdie 2013
bool SuffixPatternMatch (char *string,  /* String to match              */
2014
                         char *pattern, /* Pattern to match against     */
2015
                         char **start,  /* Start position               */
2016
                         int  mode)     /* Match mode                   */
227 dpurdie 2017
{
5659 dpurdie 2018
    char        *save_start = (char *)NULL;
227 dpurdie 2019
 
2020
/* Scan the string, looking for a match to the end */
2021
 
2022
    while (*string)
2023
    {
5659 dpurdie 2024
        if (GeneralPatternMatch (string, (unsigned char *)pattern, FALSE,
2025
                                 (char **)NULL, GM_ALL))
2026
        {
227 dpurdie 2027
 
2028
/* If longest, stop here */
2029
 
5659 dpurdie 2030
            if (mode == GM_LONGEST)
2031
            {
2032
                *start = string;
2033
                return TRUE;
2034
            }
227 dpurdie 2035
 
2036
/* Save the start of the shortest string so far and continue */
2037
 
5659 dpurdie 2038
            save_start = string;
2039
        }
227 dpurdie 2040
 
5659 dpurdie 2041
        ++string;
227 dpurdie 2042
    }
2043
 
2044
    return C2bool ((*start = save_start) != (char *)NULL);
2045
}
2046
 
2047
/*
2048
 * Get a string in a malloced area
2049
 */
2050
 
2051
char *AllocateMemoryCell (size_t nbytes)
2052
{
5659 dpurdie 2053
    s_region            *np;
227 dpurdie 2054
    void                (_SIGDECL *save_signal)(int);
2055
#ifdef OS2_DOSALLOC
5659 dpurdie 2056
    SEL                 sel;
227 dpurdie 2057
#endif
2058
 
2059
    if (nbytes == 0)
5659 dpurdie 2060
        abort ();       /* silly and defeats the algorithm */
227 dpurdie 2061
 
2062
/* Grab some space */
2063
 
2064
#ifdef OS2_DOSALLOC
2065
    if (DosAllocSeg (nbytes + sizeof (s_region), &sel, SEG_NONSHARED))
2066
    {
5659 dpurdie 2067
        errno = ENOMEM;
2068
        return (char *)NULL;
227 dpurdie 2069
    }
2070
 
2071
    np = (s_region *)MAKEP (sel, 0);
2072
    memset (np, 0, nbytes + sizeof (s_region));
2073
 
2074
#else
2075
    if ((np = (s_region *)calloc (nbytes + sizeof (s_region), 1))
5659 dpurdie 2076
                == (s_region *)NULL)
227 dpurdie 2077
    {
5659 dpurdie 2078
        errno = ENOMEM;
227 dpurdie 2079
        return (char *)NULL;
2080
    }
2081
#endif
2082
 
2083
/* Disable signals */
2084
 
2085
    save_signal = signal (SIGINT, SIG_IGN);
2086
 
2087
/* Link into chain */
2088
 
2089
    np->next = MemoryAreaHeader;
2090
    np->area = MemoryAreaLevel;
2091
    np->nbytes = nbytes;
2092
 
2093
    MemoryAreaHeader = np;
2094
 
2095
/* Restore signals */
2096
 
2097
    signal (SIGINT, save_signal);
2098
 
2099
    return ((char *)np) + sizeof (s_region);
2100
}
2101
 
2102
/*
2103
 * Release a array of strings
2104
 */
2105
 
5659 dpurdie 2106
void    ReleaseAList (char **list)
227 dpurdie 2107
{
5659 dpurdie 2108
    char        **ap = list;
227 dpurdie 2109
 
2110
    while (*ap != (char *)NULL)
5659 dpurdie 2111
        ReleaseMemoryCell (*(ap++));
227 dpurdie 2112
 
2113
    ReleaseMemoryCell (list);
2114
 
2115
}
2116
 
2117
/*
2118
 * Free a string in a malloced area
2119
 */
2120
 
2121
void ReleaseMemoryCell (void *s)
2122
{
5659 dpurdie 2123
    s_region            *cp = MemoryAreaHeader;
2124
    s_region            *lp = (s_region *)NULL;
2125
    s_region            *sp = (s_region *)((char *)s - sizeof (s_region));
227 dpurdie 2126
    void                (_SIGDECL *save_signal)(int);
2127
 
2128
/* Disable signals */
2129
 
2130
    save_signal = signal (SIGINT, SIG_IGN);
2131
 
2132
/* Find the string in the chain */
2133
 
2134
    if (s != (char *)NULL)
2135
    {
5659 dpurdie 2136
        while (cp != (s_region *)NULL)
2137
        {
2138
            if (cp != sp)
2139
            {
2140
                lp = cp;
2141
                cp = cp->next;
2142
                continue;
2143
            }
227 dpurdie 2144
 
2145
/* First in chain ? */
2146
 
5659 dpurdie 2147
            else if (lp == (s_region *)NULL)
2148
                MemoryAreaHeader = cp->next;
227 dpurdie 2149
 
2150
/* Delete the current entry and relink */
2151
 
5659 dpurdie 2152
            else
2153
                lp->next = cp->next;
227 dpurdie 2154
 
5659 dpurdie 2155
            RELEASE_MEMORY (cp);
2156
            break;
2157
        }
227 dpurdie 2158
    }
2159
 
2160
/* Restore signals */
2161
 
2162
    signal (SIGINT, save_signal);
2163
}
2164
 
2165
/*
2166
 * Check for memory leaks with a dump
2167
 */
2168
 
2169
#ifdef DEBUG_MEMORY
2170
void DumpMemoryCells (int status)
2171
{
5659 dpurdie 2172
    s_region            *cp = MemoryAreaHeader;
2173
    size_t              i;
2174
    char                buffer[17];
2175
    char                *sp;
227 dpurdie 2176
 
2177
/* Find the string in the chain */
2178
 
2179
    while (cp != (s_region *)NULL)
2180
    {
5659 dpurdie 2181
        fprintf (stderr, "Segment 0x%.8lx Area %5d Length %5d Link 0x%.8lx\n",
2182
                 cp, cp->area, cp->nbytes, cp->next);
227 dpurdie 2183
 
5659 dpurdie 2184
        memset (buffer, CHAR_SPACE, 17);
2185
        buffer[16] = 0;
227 dpurdie 2186
 
5659 dpurdie 2187
        sp = ((char *)cp) + sizeof (s_region);
227 dpurdie 2188
 
5659 dpurdie 2189
        for (i = 0; i < (((cp->nbytes - 1)/16) + 1) * 16; i++)
2190
        {
2191
            if (i >= cp->nbytes)
2192
            {
2193
                feputs ("   ");
2194
                buffer [i % 16] = CHAR_SPACE;
2195
            }
227 dpurdie 2196
 
5659 dpurdie 2197
            else
2198
            {
2199
                fprintf (stderr, "%.2x ", *sp & 0x0ff);
2200
                buffer [i % 16] = (char)(isprint (*sp) ? *sp : CHAR_PERIOD);
2201
            }
227 dpurdie 2202
 
5659 dpurdie 2203
            if (i % 16 == 15)
2204
                fprintf (stderr, "    [%s]\n", buffer);
227 dpurdie 2205
 
5659 dpurdie 2206
            sp++;
2207
        }
227 dpurdie 2208
 
5659 dpurdie 2209
        feputc (CHAR_NEW_LINE);
2210
        cp = cp->next;
227 dpurdie 2211
    }
2212
#undef exit
2213
    exit (status);
5659 dpurdie 2214
#define exit(x)         DumpMemoryCells (x)
227 dpurdie 2215
}
2216
#endif
2217
 
2218
/*
2219
 * Autodelete space nolonger required.  Ie. Free all the strings in a malloced
2220
 * area
2221
 */
2222
 
2223
void ReleaseMemoryArea (int a)
2224
{
5659 dpurdie 2225
    s_region            *cp = MemoryAreaHeader;
2226
    s_region            *lp = (s_region *)NULL;
227 dpurdie 2227
    void                (_SIGDECL *save_signal)(int);
2228
 
2229
/* Release the Here documents first */
2230
 
2231
    FreeAllHereDocuments (a);
2232
 
2233
/* Disable signals */
2234
 
2235
    save_signal = signal (SIGINT, SIG_IGN);
2236
 
2237
    while (cp != (s_region *)NULL)
2238
    {
2239
 
2240
/* Is the area number less than that specified - yes, continue */
2241
 
5659 dpurdie 2242
        if (cp->area < a)
2243
        {
2244
            lp = cp;
2245
            cp = cp->next;
2246
        }
227 dpurdie 2247
 
2248
/* OK - delete the area.  Is it the first in chain ?  Yes, delete, relink
2249
 * and update start location
2250
 */
2251
 
5659 dpurdie 2252
        else if (lp == (s_region *)NULL)
2253
        {
2254
            lp = cp;
2255
            cp = cp->next;
2256
            MemoryAreaHeader = cp;
227 dpurdie 2257
 
5659 dpurdie 2258
            RELEASE_MEMORY (lp);
2259
            lp = (s_region *)NULL;
2260
        }
227 dpurdie 2261
 
2262
/* Not first, delete the current entry and relink */
2263
 
5659 dpurdie 2264
        else
2265
        {
2266
            lp->next = cp->next;
2267
            RELEASE_MEMORY (cp);
2268
            cp = lp->next;
2269
        }
227 dpurdie 2270
    }
2271
 
2272
/* Restore signals */
2273
 
2274
    signal (SIGINT, save_signal);
2275
}
2276
 
2277
/*
2278
 * Set the area number for a malloced string.  This allows autodeletion of
2279
 * space that is nolonger required.
2280
 */
2281
 
2282
void SetMemoryAreaNumber (void *cp, int a)
2283
{
5659 dpurdie 2284
    s_region    *sp = (s_region *)((char *)cp - sizeof (s_region));
227 dpurdie 2285
 
2286
    if (cp != (void *)NULL)
5659 dpurdie 2287
        sp->area = a;
227 dpurdie 2288
}
2289
 
2290
/*
2291
 * Get the area number for a malloced string
2292
 */
2293
 
2294
int GetMemoryAreaNumber (void *cp)
2295
{
5659 dpurdie 2296
    s_region    *sp = (s_region *)((char *)cp - sizeof (s_region));
227 dpurdie 2297
 
2298
    return sp->area;
2299
}
2300
 
2301
/* Output one of the Prompt.  We save the prompt for the history part of
2302
 * the program
2303
 */
2304
 
2305
void OutputUserPrompt (char *s)
2306
{
5659 dpurdie 2307
    struct tm           *tm;
2308
    time_t              xtime = time ((time_t *)NULL);
2309
    int                 i;
2310
    char                buf[PATH_MAX + 4];
227 dpurdie 2311
 
2312
    if (LastUserPrompt != (char *)NULL)
2313
    {
5659 dpurdie 2314
        LastUserPrompt = s;             /* Save the Last prompt id      */
2315
        s = GetVariableAsString (s, TRUE); /* Get the string value      */
227 dpurdie 2316
 
5659 dpurdie 2317
        if (LastUserPrompt == PS1)
2318
            s = substitute (s, 0);
227 dpurdie 2319
    }
2320
 
2321
    else
5659 dpurdie 2322
        s = LastUserPrompt1;
227 dpurdie 2323
 
2324
    tm = localtime (&xtime);
2325
 
2326
    while (*s)
2327
    {
2328
 
2329
/* If a format character, process it */
2330
 
5659 dpurdie 2331
        if (*s == CHAR_FORMAT)
2332
        {
2333
            s++;
2334
            *s = (char)tolower(*s);
227 dpurdie 2335
 
5659 dpurdie 2336
            if (*s == CHAR_FORMAT)
2337
                fputchar (CHAR_FORMAT);
227 dpurdie 2338
 
5659 dpurdie 2339
            else
2340
            {
2341
                *buf = 0;
227 dpurdie 2342
 
5659 dpurdie 2343
                switch (*(s++))
2344
                {
2345
                    case 'e':               /* Current event number */
2346
                        if (HistoryEnabled)
2347
                            sprintf (buf, "%d", Current_Event + 1);
227 dpurdie 2348
 
5659 dpurdie 2349
                        break;
227 dpurdie 2350
 
5659 dpurdie 2351
                    case 't':               /* time         */
2352
                        sprintf (buf,"%.2d:%.2d", tm->tm_hour, tm->tm_min);
2353
                        break;
227 dpurdie 2354
 
5659 dpurdie 2355
                    case 'd':               /* date         */
2356
                        sprintf (buf, "%.3s %.2d-%.2d-%.2d",
2357
                                 &"SunMonTueWedThuFriSat"[tm->tm_wday * 3],
2358
                                 tm->tm_mday, tm->tm_mon + 1,
2359
                                 tm->tm_year % 100);
2360
                        break;
227 dpurdie 2361
 
5659 dpurdie 2362
                    case 'p':               /* directory    */
2363
                    case 'n':               /* default drive */
2364
                        strcpy (buf, CurrentDirectory->value);
227 dpurdie 2365
 
5659 dpurdie 2366
                        if (*(s - 1) == 'n')
2367
                            buf[1] = 0;
227 dpurdie 2368
 
5659 dpurdie 2369
                        break;
227 dpurdie 2370
 
2371
#if (OS_TYPE != OS_UNIX)
5659 dpurdie 2372
                    case 'v':               /* version      */
2373
                        sprintf (buf, "%s %.2d:%.2d", LIT_OSname,
227 dpurdie 2374
                                OS_VERS_N, OS_VERS_M);
5659 dpurdie 2375
                        break;
227 dpurdie 2376
#endif
5659 dpurdie 2377
                }
227 dpurdie 2378
 
2379
/* Output the string */
2380
 
5659 dpurdie 2381
                foputs (buf);
2382
            }
2383
        }
227 dpurdie 2384
 
2385
/* Escaped character ? */
2386
 
5659 dpurdie 2387
        else if (*s == CHAR_META)
2388
        {
2389
            ++s;
2390
            if ((i = ProcessOutputMetaCharacters (&s)) == -1)
2391
                i = 0;
227 dpurdie 2392
 
5659 dpurdie 2393
            fputchar ((char)i);
2394
        }
227 dpurdie 2395
 
5659 dpurdie 2396
        else
2397
            fputchar (*(s++));
227 dpurdie 2398
    }
2399
 
5659 dpurdie 2400
    FlushStreams ();                    /* Clear output */
227 dpurdie 2401
}
2402
 
2403
/*
2404
 * Get the current path in UNIX format and save it in the environment
2405
 * variable $~
2406
 */
2407
 
2408
void GetCurrentDirectoryPath (void)
2409
{
5659 dpurdie 2410
    char        ldir[PATH_MAX + 6];
2411
    char        *CurrentPWDValue;               /* Current directory    */
227 dpurdie 2412
 
2413
    S_getcwd (ldir, 0);
2414
 
2415
/* Save in environment */
2416
 
2417
    SetVariableFromString (tilde, ldir);
2418
    CurrentDirectory = LookUpVariable (tilde, 0, TRUE);
2419
 
2420
/* If we have changed directory, set PWD and OLDPWD */
2421
 
2422
    if (strcmp (CurrentPWDValue = GetVariableAsString (PWDVariable, FALSE),
5659 dpurdie 2423
                ldir))
227 dpurdie 2424
    {
5659 dpurdie 2425
        SetVariableFromString (OldPWDVariable, CurrentPWDValue);
2426
        SetVariableFromString (PWDVariable, ldir);
227 dpurdie 2427
    }
2428
}
2429
 
2430
/*
2431
 * Initialise the shell and Patch up various parts of the system for the
2432
 * shell.  At the moment, we modify the ctype table so that _ is an upper
2433
 * case character.
2434
 */
2435
 
2436
/* Is the path 'a' subset of 'p' ? */
2437
 
2438
#if (OS_TYPE == OS_NT)
2439
#define PATHSMAX    8
2440
#define PATHOFF     5
2441
 
2442
static int
2443
SubPath( const char *p, const char *a )
2444
{
2445
    int         pl, al, i;
2446
 
2447
    pl = strlen(p += PATHOFF);
2448
    al = strlen(a += PATHOFF);
2449
    for (i = 0; pl-- >= al; i++)
2450
        if (strnicmp( p++, a, al ) == 0)
2451
        {
2452
            if (i == 0 && (pl == al))
2453
                return (0);
2454
            return (i+1);
2455
        }
2456
    return (-1);
2457
}
2458
#endif
2459
 
2460
static bool F_LOCAL Initialise (int argc, char **argv)
2461
{
5659 dpurdie 2462
    char        *s, *s1;
2463
    char        **ap;
2464
    char        *name = *argv;
2465
    bool        OptionsRflag = FALSE;
227 dpurdie 2466
#if (OS_TYPE == OS_NT)
5659 dpurdie 2467
    bool        Level0 = FALSE;
2468
    int         sc;
227 dpurdie 2469
#endif
2470
 
2471
/*
2472
 * Determine the base OS if we can!
2473
 */
2474
 
2475
#if (OS_TYPE == OS_NT)
5659 dpurdie 2476
    BaseOS = BASE_OS_NT;        /* Default to NT - no other */
227 dpurdie 2477
#elif (OS_TYPE == OS_UNIX)
5659 dpurdie 2478
    BaseOS = BASE_OS_UNIX;      /* Default to UNIX - no other */
227 dpurdie 2479
#elif (OS_TYPE == OS_OS2)
5659 dpurdie 2480
    BaseOS = BASE_OS_OS2;       /* Default to OS2 - no other */
227 dpurdie 2481
#elif (OS_TYPE == OS_DOS)
2482
 
5659 dpurdie 2483
    BaseOS = BASE_OS_DOS;       /* Default to DOS */
227 dpurdie 2484
 
2485
    if (_osmajor > 10)          /* Rather crude check */
5659 dpurdie 2486
        BaseOS = BASE_OS_OS2;
227 dpurdie 2487
 
2488
/* Know to stop NT ? */
2489
 
2490
    else
2491
    {
5659 dpurdie 2492
        union REGS      r;
2493
        r.h.ah = 0x16;
2494
        r.h.al = 0;
227 dpurdie 2495
 
5659 dpurdie 2496
        SystemInterrupt (0x2f, &r, &r);
227 dpurdie 2497
 
5659 dpurdie 2498
        if (r.h.al > 0)
2499
            BaseOS = BASE_OS_WIN;
227 dpurdie 2500
 
5659 dpurdie 2501
        else
2502
        {
2503
            r.x.REG_AX = 0x3306;
2504
            SystemInterrupt (0x21, &r, &r);
227 dpurdie 2505
 
5659 dpurdie 2506
            if ((r.x.REG_AX == 0x3306) && (r.x.REG_BX == 0x3205))
2507
                BaseOS = BASE_OS_NT;
2508
        }
227 dpurdie 2509
    }
2510
#endif
2511
 
2512
/*
2513
 * For MSDOS: Get original interrupt 24 address and set up our new interrupt
5659 dpurdie 2514
 *            24 address.
227 dpurdie 2515
 * For OS/2 : Set noignore interrupts.
2516
 */
2517
 
2518
#if (OS_TYPE == OS_DOS) && !defined (__EMX__)
2519
    Orig_I24_V = GetInterruptVector (0x24);
2520
#  if (OS_SIZE == OS_16)
2521
#   if (XXX)
2522
    SetInterruptVector (0x24, SW_Int24);
2523
#   endif
2524
#  else
2525
    _harderr (HardErrorHandler);
2526
#  endif
2527
#elif (OS_TYPE != OS_DOS)
2528
    IgnoreInterrupts = FALSE;
2529
#endif
2530
 
2531
/* Create terminations queues - OS/2 only */
2532
 
2533
    CreateTerminationQueues ();
2534
 
2535
/* Set up character maps */
2536
 
2537
    InitialiseCharacterTypes ();
2538
 
2539
/* Create the integer variables, in case they are loaded from the
2540
 * environment
2541
 */
2542
    CreateIntegerVariables ();
2543
 
2544
/* Initialise Path Extension lists */
2545
 
2546
    BuildExtensionLists ();
2547
 
2548
/* For NT, we need to know now if this is a level 0 shell because NT has a
2549
 * nasty habit of being case in-sensitive!  Not only for file names, but
2550
 * also environment variables.  So scan the command line for the -0 option!
2551
 */
2552
 
2553
#if (OS_TYPE == OS_NT)
2554
    while ((sc = GetOptions (argc, argv, ShellOptions, 0)) != EOF)
2555
    {
5659 dpurdie 2556
        if (sc == '0')
2557
        {
2558
            Level0 = TRUE;
2559
            break;
2560
        }
227 dpurdie 2561
    }
2562
 
2563
    ResetGetOptions ();
2564
#endif
2565
 
2566
/* Load the environment into our structures */
2567
 
2568
    if ((ap = environ) != NOWORDS)
2569
    {
2570
#if (OS_TYPE == OS_NT)
2571
        const char *paths[PATHSMAX];
2572
        int pathcnt = 0;
2573
#endif
2574
 
5659 dpurdie 2575
        for (ap = environ; *ap != (char *)NULL; ap++)
2576
        {
227 dpurdie 2577
 
2578
/* Set up any variables.  Note there is an assumption that
2579
 * AssignVariableFromString sets the equals sign to 0, hiding the value;
2580
 */
5659 dpurdie 2581
            if (!strncmp ("SECONDS=", *ap, 8))
2582
                continue;
227 dpurdie 2583
 
2584
/* NT is case in-sensitive - what a PAIN! */
2585
 
2586
#if (OS_TYPE == OS_NT)
2587
                                                /* special PATH handling */
2588
            if (strnicmp ("PATH=", *ap, 5) == 0)
2589
            {
2590
                if (pathcnt < PATHSMAX)
2591
                    paths[ pathcnt++ ] = *ap;
2592
                continue;                       /* next -- process on exit */
2593
            }
2594
 
5659 dpurdie 2595
            if (Level0)
227 dpurdie 2596
            {
5659 dpurdie 2597
                s = *ap;
227 dpurdie 2598
 
5659 dpurdie 2599
                while (*s && (*s != CHAR_ASSIGN))
2600
                {                               /* convert to upper case */
2601
                    *s = (char)toupper (*s);
2602
                    s++;
2603
                }
2604
            }
227 dpurdie 2605
#endif
5659 dpurdie 2606
            if (AssignVariableFromString (*ap, (int *)NULL))
2607
                SetVariableStatus (*ap, STATUS_EXPORT);
2608
        }
227 dpurdie 2609
 
255 dpurdie 2610
    /*
2611
    **  Can not access varibales from the environment
2612
    **  Set up debug level
2613
    */
2614
    debug_level = GetVariableAsNumeric ("SHDEBUGEXEC" );
2615
 
227 dpurdie 2616
#if (OS_TYPE == OS_NT)
2617
        if (pathcnt)
2618
        {                                       /* import */
2619
            const char   *p;                    /* path and alternative */
255 dpurdie 2620
            int dbg = (debug_level & DEBUG_MULTIPATH);
227 dpurdie 2621
            p = paths[0];
2622
            if (pathcnt > 1)
2623
            {
255 dpurdie 2624
                int      err, i;
227 dpurdie 2625
                int      pl, al;
2626
 
2627
                pl = -1;
2628
                for (i=0; i<pathcnt; i++) {     /* select greater */
2629
                    if ((al = strlen(paths[i])) > pl) {
2630
                         p = paths[i];
2631
                         pl = al;
2632
                    }
2633
                }
2634
 
2635
                if (dbg) {
255 dpurdie 2636
                    fprintf ( stderr, "Encountered %d path definitions ...\n", pathcnt );
227 dpurdie 2637
                }
2638
 
2639
                for (err=0, i=0; i<pathcnt; i++) {
2640
                                                /* diff alternatives */
2641
                    if (dbg) {
2642
                        fprintf ( stderr, "[%d] %s", i, paths[i] );
2643
                    }
2644
 
2645
                    if (p == paths[i]) {
2646
                        if (dbg) {              /* .. selection */
2647
                            fprintf ( stderr, " .. using.\n" );
2648
                        }
2649
                    } else {
2650
                        int     ret;
2651
 
2652
                        if ((ret = SubPath(p, paths[i])) == -1)
2653
                        {                       /* .. different */
2654
                            if (dbg) {
2655
                                fprintf ( stderr, " .. different!\n" );
2656
                            }
2657
 
5659 dpurdie 2658
                            if (!FL_TEST (FLAG_WARNING)) {
227 dpurdie 2659
                                if (err++ == 0)
255 dpurdie 2660
                                    PrintWarningMessage ( "sh: %d path definitions encountered.", pathcnt );
2661
                                PrintWarningMessage ( "sh: ignoring differing alternative '%.4s'\n %s", paths[i], paths[i] );
227 dpurdie 2662
                            }
2663
 
2664
                        } else if (ret == 0) {
2665
                            if (dbg) {          /* .. same value */
2666
                                fprintf ( stderr, " .. same.\n" );
2667
                            }
2668
 
2669
                        } else {                /* .. substr */
2670
                            if (dbg) {
2671
                                fprintf ( stderr, " .. substr.\n" );
2672
                            }
2673
                        }
2674
                    }
2675
                }
2676
 
2677
                if (err) {
2678
                    PrintWarningMessage ( "sh: using '%.4s'\n %s.", p, p );
2679
                }
2680
            }
255 dpurdie 2681
            else if ( dbg )
2682
            {
2683
                    fprintf ( stderr, "Only one PATH definition seen\n", pathcnt );
2684
            }
227 dpurdie 2685
 
2686
            SetVariableFromString (PathLiteral, (char *)(p + PATHOFF));
2687
            SetVariableStatus (PathLiteral, STATUS_EXPORT);
2688
        }
2689
 
2690
        if (GetVariableAsString (UserLiteral, FALSE) == null)
2691
        {                                       /* set user */
2692
            char name[200];
2693
            u_long size = sizeof(name);
2694
 
2695
            if (GetUserName( name, &size )) 
2696
            {
2697
               SetVariableFromString (UserLiteral, name);
2698
               SetVariableStatus (UserLiteral, STATUS_EXPORT);
2699
            }
2700
        }
2701
 
2702
#endif  /*OS_NT*/
2703
    }
2704
 
2705
/* Change COMSPEC to unix format for execution */
2706
 
2707
    PATH_TO_UNIX (GetVariableAsString (ComspecVariable, FALSE));
2708
    SetVariableStatus (ComspecVariable, STATUS_CONVERT_MSDOS);
2709
 
2710
/* Zap all files */
2711
 
2712
    CloseAllHandlers ();
2713
    MemoryAreaLevel = 1;
2714
 
2715
/* Get the current directory */
2716
 
2717
    GetCurrentDirectoryPath ();
2718
 
2719
/* Initialise the getopts command */
2720
 
2721
    ResetGetoptsValues (TRUE);
2722
 
2723
/* Set up SHELL variable.  First check for a restricted shell.  Check the
2724
 * restricted shell
2725
 */
2726
 
2727
    SetVariableFromString (LastWordVariable, name);
2728
 
2729
/* For OS/2, we prefer the full path name and not that in argv[0].  Save a
2730
 * copy of the string
2731
 */
2732
#if (OS_TYPE == OS_OS2) || (OS_TYPE == OS_NT)
2733
    if (_APgmName)
2734
    {
2735
        PATH_TO_UNIX ((name = GetAllocatedSpace (strlen (_APgmName) + 4)));
2736
        SetMemoryAreaNumber ((void *)name, 0);
2737
        strcpy (name, _APgmName);
2738
    }
2739
#endif
2740
 
2741
 
2742
/* Has the program name got a .exe extension - Yes probably DOS 3+.  So
2743
 * save it as the Shell name.  Under OS/2, make sure we use .exe
2744
 */
2745
    if (GetVariableAsString (ShellVariableName, FALSE) == null)
2746
    {
2747
#if (OS_TYPE == OS_OS2) || (OS_TYPE == OS_NT)
5659 dpurdie 2748
        if ((s1 = strrchr (name, CHAR_PERIOD)) == (char *)NULL)
2749
            strcat (name, EXEExtension);
227 dpurdie 2750
 
5659 dpurdie 2751
        SetVariableFromString (ShellVariableName, name);
227 dpurdie 2752
 
5659 dpurdie 2753
        ReleaseMemoryCell (name);
227 dpurdie 2754
#elif (OS_TYPE == OS_DOS)
5659 dpurdie 2755
        if (((s1 = strrchr (name, CHAR_PERIOD)) != (char *)NULL) &&
2756
            (stricmp (s1 + 1, EXEExtension + 1) == 0))
2757
            SetVariableFromString (ShellVariableName, PATH_TO_UNIX (name));
227 dpurdie 2758
#elif (OS_TYPE == OS_UNIX)
5659 dpurdie 2759
        SetVariableFromString (ShellVariableName,
2760
                                (*name == '-') ? name + 1 : name);
227 dpurdie 2761
#endif
2762
    }
2763
 
2764
/* Default if necessary */
2765
 
2766
    if (GetVariableAsString (ShellVariableName, FALSE) == null)
5659 dpurdie 2767
        SetVariableFromString (ShellVariableName, shellname);
227 dpurdie 2768
 
2769
    PATH_TO_UNIX (s1 = GetVariableAsString (ShellVariableName, FALSE));
2770
 
2771
/* Check for restricted shell */
2772
 
2773
    if ((s = FindLastPathCharacter (s1)) == (char *)NULL)
5659 dpurdie 2774
        s = s1;
227 dpurdie 2775
 
2776
    else
5659 dpurdie 2777
        s++;
227 dpurdie 2778
 
2779
    if (*s == 'r')
5659 dpurdie 2780
        OptionsRflag = TRUE;
227 dpurdie 2781
 
2782
/* Set up home directory */
2783
 
2784
    if (GetVariableAsString (HomeVariableName, FALSE) == null)
2785
    {
2786
        if ((s = GetVariableAsString ("INIT", FALSE)) == null)
2787
            s = CurrentDirectory->value;
2788
 
5659 dpurdie 2789
        SetVariableFromString (HomeVariableName, s);
227 dpurdie 2790
    }
2791
 
2792
/* Set up OS Mode */
2793
 
2794
#if (OS_TYPE == OS_UNIX) || defined(WIN32)
2795
    SetVariableFromNumeric (LIT_OSmode, 3L);
2796
#elif defined (__TURBOC__)
2797
    SetVariableFromNumeric (LIT_OSmode, 0L);
2798
#elif (__WATCOMC__)
2799
    SetVariableFromNumeric (LIT_OSmode, (long)OS_TYPE - 1);
2800
#else
2801
    SetVariableFromNumeric (LIT_OSmode, (long)_osmode);
2802
#endif
2803
 
2804
#if (OS_SIZE == OS_32)
2805
    SetVariableFromNumeric (LIT_SHmode, 32L);
2806
#else
2807
    SetVariableFromNumeric (LIT_SHmode, 16L);
2808
#endif
2809
 
2810
/* Set up history file location */
2811
 
2812
    SetVariableFromNumeric (LIT_Dollar, (long)getpid ());
2813
 
2814
    LoadGlobalVariableList ();
2815
    PATH_TO_UNIX (GetVariableAsString (PathLiteral, FALSE));
2816
    PATH_TO_UNIX (GetVariableAsString (CDPathLiteral, FALSE));
2817
 
2818
    return OptionsRflag;
2819
}
2820
 
2821
/*
2822
 * Mail Check processing.  Every $MAILCHECK seconds, we check either $MAIL
2823
 * or $MAILPATH to see if any file has changed its modification time since
2824
 * we last looked.  In $MAILCHECK, the files are separated by semi-colon (;).
2825
 * If the filename contains a %, the string following the % is the message
2826
 * to display if the file has changed.
2827
 */
2828
 
2829
static void F_LOCAL CheckForMailArriving (void)
2830
{
5659 dpurdie 2831
    int                 delay = (int)GetVariableAsNumeric (MailCheckVariable);
2832
    char                *mail = GetVariableAsString ("MAIL", FALSE);
2833
    char                *mailp = GetVariableAsString ("MAILPATH", FALSE);
2834
    static time_t       last = 0L;
2835
    time_t              current = time ((time_t *)NULL);
2836
    struct stat         st;
2837
    char                *cp, *sp, *ap;
227 dpurdie 2838
 
2839
/* Have we waited long enough */
2840
 
2841
    if (((current - last) < delay) || (DisabledVariables & DISABLE_MAILCHECK))
5659 dpurdie 2842
        return;
227 dpurdie 2843
 
2844
/* Yes - Check $MAILPATH.  If it is defined, process it.  Otherwise, use
2845
 * $MAIL
2846
 */
2847
 
2848
    if (mailp != null)
2849
    {
2850
 
2851
/* Check MAILPATH */
2852
 
5659 dpurdie 2853
        sp = mailp;
227 dpurdie 2854
 
2855
/* Look for the next separator */
2856
 
5659 dpurdie 2857
        while ((cp = strchr (sp, CHAR_PATH_SEPARATOR)) != (char *)NULL)
2858
        {
2859
            *cp = 0;
227 dpurdie 2860
 
2861
/* % in string ? */
2862
 
5659 dpurdie 2863
            if ((ap = strchr (sp, CHAR_FORMAT)) != (char *)NULL)
2864
                *ap = 0;
227 dpurdie 2865
 
2866
/* Check the file name */
2867
 
5659 dpurdie 2868
            if ((S_stat (sp, &st)) && (st.st_mtime > last) && st.st_size)
2869
            {
2870
                feputs ((ap != (char *)NULL) ? ap + 1 : ymail);
2871
                feputc (CHAR_NEW_LINE);
2872
            }
227 dpurdie 2873
 
2874
/* Restore the % */
2875
 
5659 dpurdie 2876
            if (ap != (char *)NULL)
2877
                *ap = CHAR_FORMAT;
227 dpurdie 2878
 
2879
/* Restore the semi-colon and find the next one */
2880
 
5659 dpurdie 2881
            *cp = CHAR_PATH_SEPARATOR;
2882
            sp = cp + 1;
2883
        }
227 dpurdie 2884
    }
2885
 
2886
/* Just check MAIL */
2887
 
2888
    else if ((mail != null) && (S_stat (mail, &st)) &&
5659 dpurdie 2889
             (st.st_mtime > last) && st.st_size)
227 dpurdie 2890
    {
5659 dpurdie 2891
        feputs (ymail);
2892
        feputc (CHAR_NEW_LINE);
227 dpurdie 2893
    }
2894
 
2895
/* Save the last check time */
2896
 
2897
    last = current;
2898
}
2899
 
2900
/*
2901
 * Preprocess Argv to get handle of options in the format /x
2902
 *
2903
 * Some programs invoke the shell using / instead of - to mark the options.
2904
 * We need to convert to -.  Also /c is a special case.  The rest of the
2905
 * command line is the command to execute.  So, we get the command line
2906
 * from the original buffer instead of argv array.
2907
 */
2908
 
2909
#if (OS_TYPE != OS_UNIX)
2910
static void F_LOCAL Pre_Process_Argv (char **argv, int *argc1)
2911
{
5659 dpurdie 2912
    int         argc = 1;
2913
    char        *ocl = _ACmdLine;
2914
    int         i;
227 dpurdie 2915
 
2916
/* Check for these options */
2917
 
2918
    while ((*++argv != (char *)NULL) && (strlen (*argv) == 2) &&
5659 dpurdie 2919
           (**argv == '/'))
227 dpurdie 2920
    {
5659 dpurdie 2921
        argc++;
2922
        *strlwr (*argv) = CHAR_SWITCH;
227 dpurdie 2923
 
2924
/* Get the original information from the command line */
2925
 
5659 dpurdie 2926
        if ((*argv)[1] == 'c')
2927
        {
227 dpurdie 2928
 
2929
/*
2930
 * In some case under OS/2, we get /c, but with EMX style.  So all we need
2931
 * to do is change the / to a - and return.
2932
 */
2933
 
2934
#  if (OS_TYPE == OS_OS2)
5659 dpurdie 2935
            if (EMXStyleParameters)
2936
                return;
227 dpurdie 2937
#  endif
2938
 
2939
/*
2940
 * Otherwise, parse the command line again, looking for the /c
2941
 */
2942
 
5659 dpurdie 2943
            while ((*ocl != '/') && (*(ocl + 1) != 'c') &&
2944
                   (*ocl) && (*ocl != CHAR_RETURN))
2945
                ++ocl;
227 dpurdie 2946
 
5659 dpurdie 2947
            if (*ocl != '/')
2948
                continue;
227 dpurdie 2949
 
2950
/* Find the start of the string */
2951
 
5659 dpurdie 2952
            ocl += 2;
227 dpurdie 2953
 
5659 dpurdie 2954
            while (isspace (*ocl) && (*ocl != CHAR_RETURN))
2955
                ++ocl;
227 dpurdie 2956
 
5659 dpurdie 2957
            if (*ocl == CHAR_RETURN)
2958
                continue;
227 dpurdie 2959
 
2960
/* Found the start.  Set up next parameter and ignore the rest */
2961
 
5659 dpurdie 2962
            if (*(argv + 1) == (char *)NULL)
2963
                continue;
227 dpurdie 2964
 
5659 dpurdie 2965
            argc++;
227 dpurdie 2966
 
2967
/* Remove quotes from string, if they are there */
2968
 
5659 dpurdie 2969
            if ((*ocl == CHAR_DOUBLE_QUOTE) &&
2970
                (ocl[i = (strlen (ocl) - 1)] == CHAR_DOUBLE_QUOTE))
2971
            {
2972
                ocl[i] = 0;
2973
                ocl++;
2974
            }
227 dpurdie 2975
 
2976
/* Set up new argument array */
2977
 
5659 dpurdie 2978
            *(argv + 1) = ocl;
2979
            *(argv + 2) = (char *)NULL;
2980
            *argc1 = argc;
227 dpurdie 2981
 
5659 dpurdie 2982
            if ((ocl = strchr (ocl, CHAR_RETURN)) != (char *)NULL)
2983
                *ocl = 0;
227 dpurdie 2984
 
5659 dpurdie 2985
            return;
2986
        }
227 dpurdie 2987
    }
2988
}
2989
#endif
2990
 
2991
/*
2992
 * Convert path format to/from UNIX
2993
 */
2994
 
2995
char *ConvertPathToFormat (char *path, char in, char out)
2996
{
2997
#if (OS_TYPE == OS_UNIX)
2998
    return path;
2999
#else
5659 dpurdie 3000
    char        *s = path;
227 dpurdie 3001
 
3002
    while ((path = strchr (path, in)) != (char *)NULL)
5659 dpurdie 3003
        *path = out;
227 dpurdie 3004
 
3005
    return s;
3006
#endif
3007
}
3008
 
3009
/* Load profiles onto I/O Stack */
3010
 
3011
static void F_LOCAL LoadTheProfileFiles (void)
3012
{
5659 dpurdie 3013
    char        *name;
3014
    char        *Pname;
227 dpurdie 3015
 
3016
    if ((Pname = GetVariableAsString ("ETCPROFILE", FALSE)) == null)
3017
    {
5659 dpurdie 3018
        char PnameDefault[] = "x:/etc/profile";
3019
        Pname = PnameDefault; 
3020
        *Pname = GetDriveLetter (GetRootDiskDrive ());
227 dpurdie 3021
    }
3022
 
3023
    InteractiveFlag = TRUE;
3024
    ExecuteShellScript (Pname);
3025
 
3026
/*
3027
 * Check $HOME format.  If in DOS format, mark and convert to UNIX
3028
 */
3029
 
3030
    if (strchr (name = GetVariableAsString (HomeVariableName, FALSE),
5659 dpurdie 3031
                CHAR_DOS_PATH) != (char *)NULL)
227 dpurdie 3032
    {
5659 dpurdie 3033
        PATH_TO_UNIX (name);
3034
        SetVariableStatus (HomeVariableName, STATUS_CONVERT_MSDOS);
227 dpurdie 3035
    }
3036
 
5659 dpurdie 3037
    name = BuildFileName ("profile");   /* Set up home profile */
227 dpurdie 3038
    ExecuteShellScript (name);
3039
    ReleaseMemoryCell ((void *)name);
3040
}
3041
 
3042
/*
3043
 * Convert Unix PATH to MSDOS PATH
3044
 */
3045
 
3046
static void F_LOCAL ConvertUnixPathToMSDOS (char *cp)
3047
{
5659 dpurdie 3048
    char        *scp = cp;
3049
    int         colon = 0;
227 dpurdie 3050
 
3051
/* If there is a semi-colon or a backslash, we assume this is a DOS format
3052
 * path
3053
 */
3054
 
3055
    if ((strchr (cp, CHAR_PATH_SEPARATOR) != (char *)NULL) ||
5659 dpurdie 3056
        (strchr (cp, CHAR_DOS_PATH) != (char *)NULL))
3057
        return;
227 dpurdie 3058
 
3059
/* Count the number of colons */
3060
 
3061
    while ((cp = strchr (cp, CHAR_COLON)) != (char *)NULL)
3062
    {
5659 dpurdie 3063
        ++colon;
3064
        ++cp;
227 dpurdie 3065
    }
3066
 
3067
/* If there are no colons or there is one colon as the second character, it
3068
 * is probably an MSDOS path
3069
 */
3070
 
3071
    cp = scp;
3072
    if ((colon == 0) || ((colon == 1) && (*(cp + 1) == CHAR_COLON)))
5659 dpurdie 3073
        return;
227 dpurdie 3074
 
3075
/* Otherwise, convert all colons to semis */
3076
 
3077
    while ((cp = strchr (cp, CHAR_COLON)) != (char *)NULL)
5659 dpurdie 3078
        *(cp++) = CHAR_PATH_SEPARATOR;
227 dpurdie 3079
}
3080
 
3081
/* Generate a file name from a directory and name.  Return null if an error
3082
 * occurs or some malloced space containing the file name otherwise
3083
 */
3084
 
3085
char *BuildFileName (char *name)
3086
{
5659 dpurdie 3087
    char        *dir = GetVariableAsString (HomeVariableName, FALSE);
3088
    char        *cp;
227 dpurdie 3089
 
3090
/* Get some space */
3091
 
3092
    if ((cp = AllocateMemoryCell (strlen (dir) + strlen (name) + 2))
5659 dpurdie 3093
                == (char *)NULL)
3094
        return null;
227 dpurdie 3095
 
3096
/* Addend the directory and a / if the directory does not end in one */
3097
 
3098
    strcpy (cp, dir);
3099
 
3100
    if (!IsPathCharacter (cp[strlen (cp) - 1]))
5659 dpurdie 3101
        strcat (cp, DirectorySeparator);
227 dpurdie 3102
 
3103
/* Append the file name */
3104
 
3105
    return strcat (cp, name);
3106
}
3107
 
3108
/* Clear prompts */
3109
 
3110
static void F_LOCAL ClearUserPrompts (void)
3111
{
3112
    ClearVariableStatus (PS1, STATUS_EXPORT);
3113
    ClearVariableStatus (PS2, STATUS_EXPORT);
3114
    ClearVariableStatus (PS3, STATUS_EXPORT);
3115
    SetVariableFromString (PS1, null);
3116
    SetVariableFromString (PS2, null);
3117
    SetVariableFromString (PS3, null);
3118
}
3119
 
3120
/* Process setting of SECONDS and RANDOM environment variables */
3121
 
3122
static void F_LOCAL SecondAndRandomEV (char *name, long val)
3123
{
3124
    if (!strcmp (name, SecondsVariable) &&
5659 dpurdie 3125
        !(DisabledVariables & DISABLE_SECONDS))
3126
        ShellStartTime = time ((time_t *)NULL) - val;
227 dpurdie 3127
 
3128
    else if (!strcmp (name, RandomVariable) &&
5659 dpurdie 3129
             !(DisabledVariables & DISABLE_RANDOM))
3130
        srand ((int)val);
227 dpurdie 3131
}
3132
 
3133
/*
3134
 * Set up the Window name.  Give up if it does not work.
3135
 */
3136
 
3137
#if (OS_TYPE == OS_OS2)
5659 dpurdie 3138
void    SetWindowName (char *title)
227 dpurdie 3139
{
5659 dpurdie 3140
    HSWITCH             hswitch;
3141
    SWCNTRL             swctl;
3142
    char                *cp;
227 dpurdie 3143
 
3144
    if ((!(hswitch = WinQuerySwitchHandle (0, getpid ()))) ||
5659 dpurdie 3145
        (WinQuerySwitchEntry (hswitch, &swctl)))
3146
        return;
227 dpurdie 3147
 
3148
    if (title != (char *)NULL)
3149
        cp = title;
3150
 
3151
    else if ((DisabledVariables & DISABLE_WINTITLE) ||
5659 dpurdie 3152
             ((cp = GetVariableAsString (WinTitleVariable, FALSE)) == null))
3153
        cp = DefaultWinTitle;
227 dpurdie 3154
 
3155
    strncpy (swctl.szSwtitle, cp, sizeof (swctl.szSwtitle));
3156
    swctl.szSwtitle[sizeof (swctl.szSwtitle) - 1] = 0;
3157
    WinChangeSwitchEntry (hswitch, &swctl);
3158
}
3159
#endif
3160
 
3161
/* NT Version */
3162
 
3163
#if (OS_TYPE == OS_NT)
5659 dpurdie 3164
void    SetWindowName (char *title)
227 dpurdie 3165
{
5659 dpurdie 3166
    char                *cp;
227 dpurdie 3167
 
3168
    if (title != (char *)NULL)
3169
        cp = title;
3170
 
3171
    else if ((DisabledVariables & DISABLE_WINTITLE) ||
5659 dpurdie 3172
             ((cp = GetVariableAsString (WinTitleVariable, FALSE)) == null))
3173
        cp = DefaultWinTitle;
227 dpurdie 3174
 
3175
    SetConsoleTitle (cp);
3176
}
3177
#endif
3178
 
3179
/*
3180
 * In OS/2, check for terminated processes
3181
 */
3182
 
3183
#if (OS_TYPE == OS_OS2)
3184
static void F_LOCAL CheckForTerminatedProcess (void)
3185
{
5659 dpurdie 3186
    RESULTCODES         rescResults;
3187
    PID                 pidProcess;
3188
    char                *s;
3189
    OSCALL_RET          rc;
227 dpurdie 3190
 
3191
#  if (OS_TYPE == OS_OS2)
3192
   CheckForSessionEnd ();
3193
#  endif
3194
 
3195
/* Check for tasks terminating */
3196
 
3197
    while (TRUE)
3198
    {
5659 dpurdie 3199
        while ((rc = DosCwait (DCWA_PROCESSTREE, DCWW_NOWAIT, &rescResults,
3200
                               &pidProcess, 0)) == ERROR_INTERRUPT)
3201
            continue;
227 dpurdie 3202
 
3203
/* Ignore errors */
3204
 
5659 dpurdie 3205
        if (rc)
3206
            return;
227 dpurdie 3207
 
3208
/* Remove the job */
3209
 
5659 dpurdie 3210
        DeleteJob (pidProcess);
227 dpurdie 3211
 
5659 dpurdie 3212
        switch (rescResults.codeTerminate)
3213
        {
3214
            case TC_EXIT:
3215
                s = "Normal Exit";
3216
                break;
227 dpurdie 3217
 
5659 dpurdie 3218
            case TC_HARDERROR:
3219
                s = "Hard error";
3220
                break;
227 dpurdie 3221
 
5659 dpurdie 3222
            case TC_TRAP:
3223
                s = "Trapped";
3224
                break;
227 dpurdie 3225
 
5659 dpurdie 3226
            case TC_KILLPROCESS:
3227
                s = "Killed";
3228
                break;
227 dpurdie 3229
 
5659 dpurdie 3230
            default:
3231
                s = "Unknown";
3232
                break;
227 dpurdie 3233
 
5659 dpurdie 3234
        }
227 dpurdie 3235
 
5659 dpurdie 3236
        fprintf (stderr, "Process %d terminated - %s (%d)\n", pidProcess, s,
3237
                 rescResults.codeTerminate);
227 dpurdie 3238
    }
3239
}
3240
#endif
3241
 
3242
 
3243
/* NT Version */
3244
 
3245
#if (OS_TYPE == OS_NT)
3246
static void F_LOCAL CheckForTerminatedProcess (void)
3247
{
3248
    twalk (JobTree, LookUpJobs);
3249
}
3250
 
3251
 
3252
/*
3253
 * Walk the NT job tree looking for terminated processes
3254
 */
3255
 
3256
static void LookUpJobs (const void *key, VISIT visit, int level)
3257
{
5659 dpurdie 3258
    JobList     *job = *(JobList **)key;
3259
    HANDLE      hp;
3260
    DWORD       res;
3261
    DWORD       ExitCode;
227 dpurdie 3262
 
3263
    (void) level;
3264
 
3265
    if ((visit == postorder) || (visit == leaf))
3266
    {
5659 dpurdie 3267
        if ((hp = OpenProcess (PROCESS_ALL_ACCESS, (BOOL)TRUE,
3268
                               job->pid)) == NULL)
3269
        {
3270
            PrintWarningMessage ("sh: Cannot open process %d\n%s", job->pid,
3271
                                 GetOSSystemErrorMessage (GetLastError ()));
3272
            DeleteJob (job->pid);
3273
        }
227 dpurdie 3274
 
3275
/* Wait for the object to exit */
3276
 
5659 dpurdie 3277
        else if ((res = WaitForSingleObject (hp, 0)) == WAIT_OBJECT_0)
3278
        {
3279
            DeleteJob (job->pid);
227 dpurdie 3280
 
5659 dpurdie 3281
            if (!GetExitCodeProcess (hp, &ExitCode))
3282
                PrintWarningMessage (
3283
                        "sh: Cannot get termination code for process %d\n%s",
3284
                        job->pid, GetOSSystemErrorMessage (GetLastError ()));
3285
            else
3286
                fprintf (stderr, "Process %d terminated (%ld)\n", job->pid,
3287
                         ExitCode);
3288
        }
227 dpurdie 3289
 
3290
/* Failed?  - error */
3291
 
5659 dpurdie 3292
        else if (res == WAIT_FAILED)
3293
        {
3294
            PrintWarningMessage ("sh: Cannot wait for process %d\n%s",
3295
                                 job->pid,
3296
                                 GetOSSystemErrorMessage (GetLastError ()));
227 dpurdie 3297
 
5659 dpurdie 3298
            DeleteJob (job->pid);
3299
        }
227 dpurdie 3300
 
5659 dpurdie 3301
        CloseHandle (hp);
227 dpurdie 3302
    }
3303
}
3304
#endif
3305
 
3306
 
3307
/* UNIX version */
3308
 
3309
#if (OS_TYPE == OS_UNIX)
3310
static void F_LOCAL CheckForTerminatedProcess (void)
3311
{
3312
    fputs ("UNIX: CheckForTerminatedProcess NI\n", stderr);
3313
}
3314
#endif
3315
 
3316
 
3317
/*
3318
 * Check for end of a Session
3319
 */
3320
 
3321
#if (OS_TYPE == OS_OS2)
5659 dpurdie 3322
static void F_LOCAL     CheckForSessionEnd (void)
227 dpurdie 3323
{
5659 dpurdie 3324
    OSCALL_PARAM        DataLength;
3325
    OSCALL_RET          rc;
3326
    BYTE                bElemPriority;
227 dpurdie 3327
    struct SessionEnd
3328
    {
5659 dpurdie 3329
        unsigned short  SessionId;
3330
        unsigned short  ExitCode;
3331
    }                   *DataAddress;
227 dpurdie 3332
 
3333
#  if (OS_SIZE == OS_32)
5659 dpurdie 3334
    REQUESTDATA         Request;
227 dpurdie 3335
#  else
5659 dpurdie 3336
    QUEUERESULT         Request;
227 dpurdie 3337
#  endif
3338
 
3339
/* Check for sessions terminating */
3340
 
3341
    while ((rc = DosReadQueue (SessionQueueHandler, &Request, &DataLength,
5659 dpurdie 3342
                               (PVOID *)&DataAddress,
3343
                               0, DCWW_NOWAIT, &bElemPriority,
3344
                               SessionQueueSema)) == NO_ERROR)
227 dpurdie 3345
    {
5659 dpurdie 3346
        DeleteJobBySession (DataAddress->SessionId);
227 dpurdie 3347
 
5659 dpurdie 3348
        fprintf (stderr, "Session %d terminated - Normal Exit (%d)\n",
3349
                 DataAddress->SessionId, DataAddress->ExitCode);
227 dpurdie 3350
 
3351
#  if (OS_SIZE == OS_32)
5659 dpurdie 3352
        DosFreeMem (DataAddress);
227 dpurdie 3353
#  else
5659 dpurdie 3354
        DosFreeSeg (SELECTOROF ((DataAddress)));
227 dpurdie 3355
#  endif
3356
    }
3357
}
3358
#endif
3359
 
3360
/*
3361
 * Set up the Parameter Environment variables
3362
 */
3363
 
3364
static void F_LOCAL SetUpParameterEV (int argc, char **argv, char *name)
3365
{
5659 dpurdie 3366
    Word_B      *wb = (Word_B *)NULL;
3367
    char        *Value;
3368
    int         i;
227 dpurdie 3369
 
3370
    if ((Value = StringSave (name)) == null)
3371
    {
5659 dpurdie 3372
        fprintf (stderr, BasicErrorMessage, ShellNameLiteral, Outofmemory1);
3373
        return;
227 dpurdie 3374
    }
3375
 
3376
    wb = AddParameter (Value, wb, ShellNameLiteral);
3377
 
3378
    for (i = 1; i < argc; ++i)
3379
    {
5659 dpurdie 3380
        if ((!AssignVariableFromString (argv[i], (int *)NULL)) &&
3381
            (wb != (Word_B *)NULL))
3382
        {
3383
            if ((Value = StringSave (argv[i])) != null)
3384
                wb = AddParameter (Value, wb, ShellNameLiteral);
227 dpurdie 3385
 
5659 dpurdie 3386
            else
3387
            {
3388
                fprintf (stderr, BasicErrorMessage, ShellNameLiteral,
3389
                         Outofmemory1);
3390
                return;
3391
            }
3392
        }
227 dpurdie 3393
    }
3394
 
3395
    if (wb != (Word_B *)NULL)
5659 dpurdie 3396
        wb = AddParameter ((char *)NULL, wb, ShellNameLiteral);
227 dpurdie 3397
}
3398
 
3399
/*
3400
 * Update the Seconds and Random variables
3401
 */
3402
 
3403
void HandleSECONDandRANDOM (void)
3404
{
3405
    if (!(DisabledVariables & DISABLE_SECONDS))
5659 dpurdie 3406
        LookUpVariable (SecondsVariable, 0, TRUE);
227 dpurdie 3407
 
3408
    if (!(DisabledVariables & DISABLE_RANDOM))
5659 dpurdie 3409
        LookUpVariable (RandomVariable, 0, TRUE);
227 dpurdie 3410
}
3411
 
3412
/*
3413
 * Set the status of an environment variable
3414
 */
3415
 
3416
void SetVariableStatus (char *name,             /* Variable name        */
5659 dpurdie 3417
                        int  flag)              /* New status           */
227 dpurdie 3418
{
5659 dpurdie 3419
    VariableList        *vp = LookUpVariable (name, 0, TRUE);
227 dpurdie 3420
 
5659 dpurdie 3421
    if (IS_VariableFC ((int)*vp->name)) /* not an internal symbol ($# etc) */
3422
        vp->status |= flag;
227 dpurdie 3423
}
3424
 
3425
/*
3426
 * Array version - only 0 is exported
3427
 */
3428
 
5659 dpurdie 3429
void SetVariableArrayStatus (char *name,        /* Variable name        */
3430
                             int  index,        /* Array index          */
3431
                             int  flag)         /* New status           */
227 dpurdie 3432
{
5659 dpurdie 3433
    VariableList        *vp = LookUpVariable (name, index, TRUE);
227 dpurdie 3434
 
5659 dpurdie 3435
    if (IS_VariableFC ((int)*vp->name)) /* not an internal symbol ($# etc) */
227 dpurdie 3436
    {
5659 dpurdie 3437
        vp->status |= flag;
227 dpurdie 3438
 
5659 dpurdie 3439
        if (index)
3440
            vp->status &= ~STATUS_EXPORT;
227 dpurdie 3441
    }
3442
}
3443
 
3444
/*
3445
 * Set the status of an environment variable
3446
 */
3447
 
3448
void ClearVariableStatus (char *name, int flag)
3449
{
5659 dpurdie 3450
    VariableList        *vp = LookUpVariable (name, 0, TRUE);
227 dpurdie 3451
 
5659 dpurdie 3452
    if (IS_VariableFC ((int)*vp->name)) /* not an internal symbol ($# etc) */
3453
        vp->status &= ~flag;
227 dpurdie 3454
}
3455
 
3456
/*
3457
 * Check allowed to set variable
3458
 */
3459
 
3460
static bool F_LOCAL AllowedToSetVariable (VariableList *vp)
3461
{
3462
    if (vp->status & STATUS_READONLY)
3463
    {
5659 dpurdie 3464
        ShellErrorMessage (LIT_2Strings, vp->name, LIT_IsReadonly);
3465
        return FALSE;
227 dpurdie 3466
    }
3467
 
3468
/* Check for $PATH, $SHELL or $ENV reset in restricted shell */
3469
 
3470
    if ((!strcmp (vp->name, PathLiteral) || !strcmp (vp->name, ENVVariable) ||
5659 dpurdie 3471
         !strcmp (vp->name, ShellVariableName)) &&
3472
        CheckForRestrictedShell (PathLiteral))
3473
        return FALSE;
227 dpurdie 3474
 
3475
    return TRUE;
3476
}
3477
 
3478
/*
3479
 * Set up a variable from a string
3480
 */
3481
 
3482
void SetVariableFromString (char *name, char *val)
3483
{
3484
    SetVariableArrayFromString (name, 0, val);
3485
}
3486
 
3487
/*
3488
 * Array index version
3489
 */
3490
 
3491
void SetVariableArrayFromString (char *name, int Index, char *val)
3492
{
5659 dpurdie 3493
    VariableList        *vp = LookUpVariable (name, Index, TRUE);
3494
    char                *xp = null;
3495
    long                nval;
227 dpurdie 3496
 
3497
/* Check if allowed to set variable */
3498
 
3499
    if (!AllowedToSetVariable (vp))
5659 dpurdie 3500
        return;
227 dpurdie 3501
 
3502
/* If we change the PATH to a new value, we need to untrack some aliases */
3503
 
3504
    if (!strcmp (name, PathLiteral) && strcmp (vp->value, val))
5659 dpurdie 3505
        UnTrackAllAliases ();
227 dpurdie 3506
 
3507
    CheckOPTIND (name, atol (val));
3508
 
3509
/* Save the new value */
3510
 
3511
    if ((!(vp->status & STATUS_INTEGER)) && (val != null) && strlen (val) &&
5659 dpurdie 3512
        ((xp = StringSave (val = SuppressSpacesZeros (vp, val))) == null))
3513
            return;
227 dpurdie 3514
 
3515
/* Free the old value if appropriate */
3516
 
3517
    if (vp->value != null)
5659 dpurdie 3518
        ReleaseMemoryCell ((void *)vp->value);
227 dpurdie 3519
 
3520
    vp->value = null;
3521
 
3522
/* String value? */
3523
 
3524
    if (!(vp->status & STATUS_INTEGER))
3525
    {
5659 dpurdie 3526
        vp->value = xp;
227 dpurdie 3527
 
5659 dpurdie 3528
        if (!vp->width)
3529
            vp->width = strlen (val);
227 dpurdie 3530
    }
3531
 
3532
/* No - Number value */
3533
 
3534
    else if (!ValidMathsExpression (val, &nval))
3535
    {
5659 dpurdie 3536
        SecondAndRandomEV (name, nval);
3537
        SetUpANumericValue (vp, nval, -1);
227 dpurdie 3538
    }
3539
 
3540
 
3541
/* Check to see if it should be exported */
3542
 
3543
    if (FL_TEST (FLAG_ALL_EXPORT))
5659 dpurdie 3544
        vp->status |= STATUS_EXPORT;
227 dpurdie 3545
 
3546
/* Convert UNIX to DOS for PATH variable */
3547
 
3548
    if (!strcmp (name, PathLiteral))
5659 dpurdie 3549
        ConvertUnixPathToMSDOS (GetVariableAsString (PathLiteral, FALSE));
227 dpurdie 3550
 
3551
    else if (!strcmp (name, CDPathLiteral))
5659 dpurdie 3552
        ConvertUnixPathToMSDOS (GetVariableAsString (CDPathLiteral, FALSE));
227 dpurdie 3553
 
3554
    else if (!strcmp (name, PathExtsLiteral))
5659 dpurdie 3555
        BuildExtensionLists ();
227 dpurdie 3556
 
3557
/* Set up IFS characters */
3558
 
3559
    else if (!strcmp (name, IFS))
5659 dpurdie 3560
        SetCharacterTypes (val, C_IFS);
227 dpurdie 3561
 
3562
/* Check for title change */
3563
 
3564
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
3565
    else if (!strcmp (name, FCEditVariable))
5659 dpurdie 3566
        SetEditorMode (val);
227 dpurdie 3567
 
3568
    else if (!strcmp (name, EditorVariable))
5659 dpurdie 3569
        SetEditorMode (val);
227 dpurdie 3570
 
3571
    else if (!strcmp (name, VisualVariable))
5659 dpurdie 3572
        SetEditorMode (val);
227 dpurdie 3573
#endif
3574
 
3575
#if (OS_TYPE != OS_DOS)
3576
    else if ((!(DisabledVariables & DISABLE_WINTITLE)) &&
5659 dpurdie 3577
             (!strcmp (name, WinTitleVariable)))
3578
        SetWindowName ((char *)NULL);
227 dpurdie 3579
#endif
3580
}
3581
 
3582
 
3583
/*
3584
 * Set a variable from a numeric
3585
 */
3586
 
3587
void SetVariableFromNumeric (char *name, long value)
3588
{
3589
    SetVariableArrayFromNumeric (name, 0, value);
3590
}
3591
 
3592
 
3593
/* Array version */
3594
 
3595
void SetVariableArrayFromNumeric (char *name, int Index, long value)
3596
{
5659 dpurdie 3597
    VariableList        *vp = LookUpVariable (name, Index, TRUE);
3598
    char                NumericBuffer[20];
227 dpurdie 3599
 
3600
/* Check if allowed to set variable */
3601
 
3602
    if (!AllowedToSetVariable (vp))
5659 dpurdie 3603
        return;
227 dpurdie 3604
 
3605
    CheckOPTIND (name, value);
3606
 
3607
    if (!(vp->status & STATUS_INTEGER))
3608
    {
5659 dpurdie 3609
        sprintf (NumericBuffer, "%ld", value);
3610
        SetVariableFromString (name, NumericBuffer);
227 dpurdie 3611
    }
3612
 
3613
/* Save the integer value */
3614
 
3615
    else
5659 dpurdie 3616
        SetUpANumericValue (vp, value, -1);
227 dpurdie 3617
 
3618
    SecondAndRandomEV (name, value);
3619
}
3620
 
3621
 
3622
/*
3623
 * Get variable as a numeric
3624
 */
3625
 
3626
long GetVariableAsNumeric (char *name)
3627
{
3628
    return GetVariableArrayAsNumeric (name, 0);
3629
}
3630
 
3631
 
3632
/* Array version */
3633
 
3634
long GetVariableArrayAsNumeric (char *name, int Index)
3635
{
5659 dpurdie 3636
    VariableList        *vp = LookUpVariable (name, Index, FALSE);
227 dpurdie 3637
 
3638
    if (vp->status & STATUS_INTEGER)
5659 dpurdie 3639
        return vp->nvalue;
227 dpurdie 3640
 
3641
    else
5659 dpurdie 3642
        return atol (vp->value);
227 dpurdie 3643
}
3644
 
3645
 
3646
/*
3647
 * Get variable as a formatted string
3648
 */
3649
 
3650
char *GetVariableAsString (char *name, bool Format)
3651
{
3652
    return GetVariableArrayAsString (name, 0, Format);
3653
}
3654
 
3655
 
3656
/*
3657
 * Indexed version
3658
 */
3659
 
3660
char *GetVariableArrayAsString (char *name, int Index, bool Format)
3661
{
5659 dpurdie 3662
    VariableList        *vp = LookUpVariable (name, Index, FALSE);
3663
    char                *Value = vp->value;
3664
    char                *xp;
3665
    size_t              len;
3666
    char                *NumericBuffer;
227 dpurdie 3667
 
3668
    if (vp->status & STATUS_INTEGER)
3669
    {
5659 dpurdie 3670
        if ((NumericBuffer = GetAllocatedSpace (40)) == (char *)NULL)
3671
            return null;
227 dpurdie 3672
 
5659 dpurdie 3673
        if (vp->base != 10)
3674
        {
3675
            sprintf (NumericBuffer, LIT_BNumber, vp->base);
3676
            xp = NumericBuffer + strlen (NumericBuffer);
3677
        }
227 dpurdie 3678
 
5659 dpurdie 3679
        else
3680
            xp = NumericBuffer;
227 dpurdie 3681
 
3682
        ltoa (vp->nvalue, xp, vp->base);
5659 dpurdie 3683
        return NumericBuffer;
227 dpurdie 3684
    }
3685
 
3686
/* Handle a string variable, if no formating required, return it */
3687
 
3688
    if (!Format)
5659 dpurdie 3689
        return vp->value;
227 dpurdie 3690
 
3691
/* Left justify ? */
3692
 
3693
    if (vp->status & STATUS_LEFT_JUSTIFY)
3694
    {
5659 dpurdie 3695
        xp = SuppressSpacesZeros (vp, Value);
227 dpurdie 3696
 
5659 dpurdie 3697
        if ((Value = GetAllocatedSpace (vp->width + 1)) == (char *)NULL)
3698
            return null;
227 dpurdie 3699
 
5659 dpurdie 3700
        memset (Value, CHAR_SPACE, vp->width);
3701
        Value[vp->width] = 0;
227 dpurdie 3702
 
5659 dpurdie 3703
        if ((len = strlen (xp)) > vp->width)
3704
            len = vp->width;
227 dpurdie 3705
 
5659 dpurdie 3706
        memcpy (Value, xp, len);
227 dpurdie 3707
    }
3708
 
3709
/* Right justify ? */
3710
 
3711
    else if (vp->status & (STATUS_RIGHT_JUSTIFY | STATUS_ZERO_FILL))
3712
    {
5659 dpurdie 3713
        if ((xp = GetAllocatedSpace (vp->width + 1)) == (char *)NULL)
3714
            return null;
227 dpurdie 3715
 
5659 dpurdie 3716
        if ((len = strlen (Value)) < vp->width)
3717
        {
3718
            memset (xp, ((vp->status & STATUS_ZERO_FILL) &&
3719
                         (isdigit (*Value))) ? '0' : CHAR_SPACE, vp->width);
227 dpurdie 3720
 
5659 dpurdie 3721
            memcpy (xp + (vp->width - len), Value, len);
3722
        }
227 dpurdie 3723
 
5659 dpurdie 3724
        else
3725
            memcpy (xp, Value + vp->width - len, vp->width);
227 dpurdie 3726
 
5659 dpurdie 3727
        *(xp + vp->width) = 0;
3728
        Value = xp;
227 dpurdie 3729
    }
3730
 
3731
/* Handle upper and lower case conversions */
3732
 
3733
    if (vp->status & STATUS_LOWER_CASE)
5659 dpurdie 3734
        Value = strlwr (StringCopy (Value));
227 dpurdie 3735
 
3736
    if (vp->status & STATUS_UPPER_CASE)
5659 dpurdie 3737
        Value = strupr (StringCopy (Value));
227 dpurdie 3738
 
3739
    return Value;
3740
}
3741
 
3742
 
3743
/*
3744
 * Set up a numeric value
3745
 */
3746
 
3747
static void F_LOCAL SetUpANumericValue (VariableList *vp, long value, int base)
3748
{
3749
    vp->nvalue = value;
3750
    vp->status |= STATUS_INTEGER;
3751
 
3752
    if (vp->base == 0)
5659 dpurdie 3753
        vp->base = (base > 1) ? base
3754
                              : ((LastNumberBase != -1) ? LastNumberBase
3755
                                                        : 10);
227 dpurdie 3756
 
3757
    if (vp->value != null)
5659 dpurdie 3758
        ReleaseMemoryCell ((void *)vp->value);
227 dpurdie 3759
 
3760
    vp->value = null;
3761
}
3762
 
3763
 
3764
/*
3765
 * Suppress leading spaces and zeros
3766
 */
3767
 
3768
static char * F_LOCAL SuppressSpacesZeros (VariableList *vp, char *value)
3769
{
3770
    if (vp->status & STATUS_LEFT_JUSTIFY)
3771
    {
5659 dpurdie 3772
        while (*value == CHAR_SPACE)
3773
            value++;
227 dpurdie 3774
 
5659 dpurdie 3775
        if (vp->status & STATUS_ZERO_FILL)
3776
        {
3777
            while (*value == '0')
3778
                value++;
3779
        }
227 dpurdie 3780
    }
3781
 
3782
    return value;
3783
}
3784
 
3785
 
3786
/*
3787
 * Check to see if a reset of CheckOPTIND has occured
3788
 */
3789
 
3790
static void F_LOCAL CheckOPTIND (char *name, long value)
3791
{
3792
    if ((value == 1) && (!(DisabledVariables & DISABLE_OPTIND)) &&
5659 dpurdie 3793
        (strcmp (OptIndVariable, name) == 0))
3794
        ResetGetoptsValues (FALSE);
227 dpurdie 3795
}
3796
 
3797
 
3798
/*
3799
 * Initialise the Integer variables by creating them
3800
 */
3801
 
3802
static void F_LOCAL CreateIntegerVariables (void)
3803
{
5659 dpurdie 3804
    struct ShellVariablesInit   *wp = InitialiseShellVariables;
227 dpurdie 3805
 
3806
    while  (wp->Name != (char *)NULL)
3807
    {
5659 dpurdie 3808
        SetVariableStatus (wp->Name, wp->Status);
227 dpurdie 3809
 
5659 dpurdie 3810
        if (wp->CValue != null)
3811
            SetVariableFromString (wp->Name, wp->CValue);
227 dpurdie 3812
 
5659 dpurdie 3813
        wp++;
227 dpurdie 3814
    }
3815
}
3816
 
3817
 
3818
/*
3819
 * Close up and exit
3820
 */
3821
 
3822
void FinalExitCleanUp (int status)
3823
{
3824
#if (OS_TYPE == OS_OS)
3825
#  if (OS_SIZE == OS_32)
3826
    DosCloseEventSem (SessionQueueSema);
3827
    DosCloseQueue (SessionQueueHandler);
3828
#  else
3829
    DosCloseSem (SessionQueueSema);
3830
    DosCloseQueue (SessionQueueHandler);
3831
#  endif
3832
#endif
3833
 
3834
    exit (status);
3835
}
3836
 
3837
 
3838
/*
3839
 * Create Session termination semaphores and queues.  Also get the number
3840
 * file handlers.
3841
 */
3842
 
3843
#if (OS_TYPE == OS_OS2)
3844
static void F_LOCAL CreateTerminationQueues (void)
3845
{
5659 dpurdie 3846
    int                 count = 0;
3847
    static char         Name[25];
3848
    OSCALL_RET          rc;
227 dpurdie 3849
#  if (OS_SIZE == OS_32)
5659 dpurdie 3850
    LONG                ReqCount = 0;           /* Increment            */
3851
    ULONG               CurMaxFH;               /* Available File handlers */
227 dpurdie 3852
 
3853
    DosSetRelMaxFH (&ReqCount, &CurMaxFH);
3854
    MaxNumberofFDs = min (CurMaxFH, 32 + FDBASE);
3855
#  endif
3856
 
3857
/* Create semaphore for queue */
3858
 
3859
    while (TRUE)
3860
    {
3861
#  if (OS_SIZE == OS_32)
3862
        sprintf (Name, "\\SEM32\\SHELL\\%.5d", count++);
3863
#  else
3864
        sprintf (Name, "\\SEM\\SHELL\\%.5d", count++);
3865
#  endif
3866
 
3867
#  if (OS_SIZE == OS_32)
5659 dpurdie 3868
        if ((rc = DosCreateEventSem (Name, &SessionQueueSema,
3869
                                     DC_SEM_SHARED, TRUE)) == NO_ERROR)
3870
            break;
227 dpurdie 3871
#  else
5659 dpurdie 3872
        if ((rc = DosCreateSem (CSEM_PUBLIC, &SessionQueueSema,
3873
                                Name)) == NO_ERROR)
3874
        {
3875
            DosSemClear (SessionQueueSema);
3876
            break;
3877
        }
227 dpurdie 3878
#  endif
3879
 
3880
/* Check for error */
3881
 
3882
#  if (OS_SIZE == OS_32)
5659 dpurdie 3883
        if (rc != ERROR_DUPLICATE_NAME)
227 dpurdie 3884
#  else
5659 dpurdie 3885
        if (rc != ERROR_ALREADY_EXISTS)
227 dpurdie 3886
#  endif
5659 dpurdie 3887
        {
3888
            SessionQueueSema = 0;
3889
            PrintErrorMessage ("DosCreateSem: Cannot create semaphore\n%s",
3890
                               GetOSSystemErrorMessage (rc));
3891
        }
227 dpurdie 3892
    }
3893
 
3894
/* Create the queue */
3895
 
3896
    count = 0;
3897
 
3898
    while (TRUE)
3899
    {
3900
#  if (OS_SIZE == OS_32)
3901
        sprintf (Name, "\\QUEUES\\SHELL\\%.5d", count++);
3902
#  else
3903
        sprintf (Name, "\\QUEUES\\SHQ%.5d", count++);
3904
#  endif
3905
 
5659 dpurdie 3906
        if ((rc = DosCreateQueue (&SessionQueueHandler,
227 dpurdie 3907
#ifdef QUE_CONVERT_ADDRESS
5659 dpurdie 3908
                                  QUE_FIFO | QUE_CONVERT_ADDRESS,
227 dpurdie 3909
#else
5659 dpurdie 3910
                                  QUE_FIFO,
227 dpurdie 3911
#endif
3912
 
5659 dpurdie 3913
                                  Name)) == NO_ERROR)
3914
            break;
227 dpurdie 3915
 
3916
/* Check for error */
3917
 
5659 dpurdie 3918
        if (rc != ERROR_QUE_DUPLICATE)
3919
        {
3920
            SessionQueueHandler = 0;
3921
            PrintErrorMessage ("DosCreateQueue: Cannot create queue\n%s",
3922
                               GetOSSystemErrorMessage (rc));
3923
        }
227 dpurdie 3924
    }
3925
 
3926
    SessionEndQName = Name;
3927
}
3928
#endif
3929
 
3930
/*
3931
 * Set up Edit mode
3932
 */
3933
 
3934
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
3935
static void F_LOCAL SetEditorMode (char *ed)
3936
{
5659 dpurdie 3937
    char        *rcp;
227 dpurdie 3938
 
3939
    if ((rcp = strrchr (ed, '/')) != (char *)NULL)
5659 dpurdie 3940
        ed = rcp + 1;
227 dpurdie 3941
 
3942
#  ifdef FLAGS_EMACS
3943
    if (strstr (ed, "emacs"))
3944
    {
5659 dpurdie 3945
        ShellGlobalFlags &= ~FLAGS_EDITORS;
3946
        ShellGlobalFlags |= FLAGS_EMACS;
227 dpurdie 3947
    }
3948
#  endif
3949
 
3950
#  ifdef FLAGS_VI
3951
    if (strstr (ed, "vi"))
3952
    {
5659 dpurdie 3953
        ShellGlobalFlags &= ~FLAGS_EDITORS;
3954
        ShellGlobalFlags |= FLAGS_VI;
227 dpurdie 3955
    }
3956
#  endif
3957
 
3958
#  ifdef FLAGS_GMACS
3959
    if (strstr (ed, "gmacs"))
3960
    {
5659 dpurdie 3961
        ShellGlobalFlags &= ~FLAGS_EDITORS;
3962
        ShellGlobalFlags |= FLAGS_GMACS;
227 dpurdie 3963
    }
3964
#  endif
3965
}
3966
#endif
5659 dpurdie 3967
 
3968
/*----------------------------------------------------------------------------
3969
** FUNCTION           : localRealloc
3970
**
3971
** DESCRIPTION        : A local replacement for realloc, except it avoids
3972
**                      compiler warnings
3973
**
3974
**
3975
** INPUTS             : ptr     - ref to current memory
3976
**                      size    - new size required
3977
**
3978
** RETURNS            : Ref to new memory or NULL on error
3979
**
3980
----------------------------------------------------------------------------*/
3981
 
3982
void *localRealloc(void *ptr, size_t size)
3983
{
3984
    void *rv = realloc(ptr, size);
3985
    if (! rv)
3986
    {
3987
        free( ptr);
3988
        return 0;
3989
    }
3990
 
3991
    return rv;
3992
}