Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - Internal Command Processing
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.  The
8
 * code for the test (dotest) command was based on code written by
9
 * Erik Baalbergen.  The following copyright conditions apply:
10
 *
11
 * 1.  Redistribution and use in source and binary forms are permitted
12
 *     provided that the above copyright notice is duplicated in the
13
 *     source form and the copyright notice in file sh6.c is displayed
14
 *     on entry to the program.
15
 *
16
 * 2.  The sources (or parts thereof) or objects generated from the sources
17
 *     (or parts of sources) cannot be sold under any circumstances.
18
 *
19
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/Sh7.c,v 1.2 2004/05/10 09:30:07 ayoung Exp $
20
 *
21
 *    $Log: Sh7.c,v $
22
 *    Revision 1.2  2004/05/10 09:30:07  ayoung
23
 *    improved Path/PATH handling
24
 *    Quote CreateProcess arg0 if embedded spaces are  encountered
25
 *    Native NT exec dont need to check command line length
26
 *    Warning when '@' within redirect list
27
 *    DEBUG_EXEC option, split from PRINT_EXEC option and improved
28
 *
29
 *    Revision 1.1  2002/08/02 06:49:34  adamy
30
 *    imported (reference only)
31
 *
32
 *    Revision 1.1  2001/07/20 05:55:44  ayoung
33
 *    WIN32 support
34
 *
35
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
36
 *    UTIL
37
 *
38
 *	Revision 2.18  1994/08/25  20:49:11  istewart
39
 *	MS Shell 2.3 Release
40
 *
41
 *	Revision 2.17  1994/02/23  09:23:38  istewart
42
 *	Beta 233 updates
43
 *
44
 *	Revision 2.16  1994/02/01  10:25:20  istewart
45
 *	Release 2.3 Beta 2, including first NT port
46
 *
47
 *	Revision 2.15  1994/01/20  14:51:43  istewart
48
 *	Release 2.3 Beta 1
49
 *
50
 *	Revision 2.14  1994/01/11  17:55:25  istewart
51
 *	Release 2.3 Beta 0 patches
52
 *
53
 *	Revision 2.13  1993/12/01  11:58:34  istewart
54
 *	Release 226 beta
55
 *
56
 *	Revision 2.12  1993/11/09  10:39:49  istewart
57
 *	Beta 226 checking
58
 *
59
 *	Revision 2.11  1993/08/25  16:03:57  istewart
60
 *	Beta 225 - see Notes file
61
 *
62
 *	Revision 2.10  1993/07/02  10:21:35  istewart
63
 *	224 Beta fixes
64
 *
65
 *	Revision 2.9  1993/06/14  11:00:12  istewart
66
 *	More changes for 223 beta
67
 *
68
 *	Revision 2.8  1993/06/02  09:52:35  istewart
69
 *	Beta 223 Updates - see Notes file
70
 *
71
 *	Revision 2.7  1993/02/16  16:03:15  istewart
72
 *	Beta 2.22 Release
73
 *
74
 *	Revision 2.6  1993/01/26  18:35:09  istewart
75
 *	Release 2.2 beta 0
76
 *
77
 *	Revision 2.5  1992/12/14  10:54:56  istewart
78
 *	BETA 215 Fixes and 2.1 Release
79
 *
80
 *	Revision 2.4  1992/11/06  10:03:44  istewart
81
 *	214 Beta test updates
82
 *
83
 *	Revision 2.3  1992/09/03  18:54:45  istewart
84
 *	Beta 213 Updates
85
 *
86
 *	Revision 2.2  1992/07/16  14:33:34  istewart
87
 *	Beta 212 Baseline
88
 *
89
 *	Revision 2.1  1992/07/10  10:52:48  istewart
90
 *	211 Beta updates
91
 *
92
 *	Revision 2.0  1992/05/07  21:33:35  Ian_Stewartson
93
 *	MS-Shell 2.0 Baseline release
94
 *
95
 */
96
 
97
#include <sys/types.h>
98
#include <sys/stat.h>
99
#if defined (__EMX__)
100
#  include <sys/wait.h>
101
#endif
102
#include <stdio.h>
103
#include <signal.h>
104
#include <errno.h>
105
#include <setjmp.h>
106
#include <ctype.h>
107
#include <string.h>
108
#include <unistd.h>
109
#include <stdlib.h>
110
#include <fcntl.h>
111
#include <limits.h>
112
#include <dirent.h>
113
#include <stdarg.h>
114
#include <time.h>
115
#include "sh.h"
116
 
117
#define	SECS		60L
118
#define	MINS		3600L
119
 
120
#if (OS_TYPE == OS_OS2)
121
#  if defined (__EMX__)
122
#    define  PGM_TITLE_TYPE	unsigned char
123
#  else
124
#    define  PGM_TITLE_TYPE	char
125
#  endif
126
#endif
127
/* Definitions for echo and print */
128
 
129
#define ECHO_ESCAPE	0x01
130
#define ECHO_NO_EOL	0x02
131
#define ECHO_HISTORY	0x04
132
 
133
/* Definitions for test */
134
 
135
#define END_OF_INPUT	0
136
#define FILE_READABLE	1
137
#define FILE_WRITABLE	2
138
#define FILE_REGULAR	3
139
#define FILE_DIRECTRY	4
140
#define FILE_NONZERO	5
141
#define FILE_TERMINAL	6
142
#define STRING_ZERO	7
143
#define STRING_NONZERO	8
144
#define STRING_EQUAL	9
145
#define STRING_NOTEQUAL	10
146
#define NUMBER_EQUAL	11
147
#define NUMBER_NOTEQUAL	12
148
#define NUMBER_EQ_GREAT	13
149
#define NUMBER_GREATER	14
150
#define NUMBER_EQ_LESS	15
151
#define NUMBER_LESS	16
152
#define UNARY_NOT	17
153
#define BINARY_AND	18
154
#define BINARY_OR	19
155
#define LPAREN		20
156
#define RPAREN		21
157
#define OPERAND		22
158
#define FILE_EXECUTABLE	23
159
#define FILE_USER	24
160
#define FILE_GROUP	25
161
#define FILE_TEXT	26
162
#define FILE_BLOCK	27
163
#define FILE_CHARACTER	28
164
#define FILE_FIFO	29
165
#define FILE_NEWER	30
166
#define FILE_OLDER	31
167
#define STRING_LESS	32
168
#define STRING_GREATER	33
169
#define FILE_EXISTS	34
170
#define TEST_OPTION	35
171
#define FILE_SYMBOLIC	36
172
#define FILE_OWNER	37
173
#define FILE_GROUPER	38
174
#define FILE_SOCKET	39
175
#define FILE_EQUAL	40
176
 
177
#define UNARY_OP	1
178
#define BINARY_OP	2
179
#define B_UNARY_OP	3
180
#define B_BINARY_OP	4
181
#define PAREN		5
182
 
183
/* This is the list of operators and the conversion values */
184
 
185
static struct TestOperator {
186
    char	*OperatorName;
187
    short 	OperatorID;
188
    short 	OperatorType;
189
} ListOfTestOperators[] = {
190
 
191
/* These two entries are modified depending on the test program. The
192
 * alternative values are shown in the following comment.
193
 */
194
 
195
    {"-a",	FILE_EXISTS,		UNARY_OP},
196
    /* {"-a",	BINARY_AND,		B_BINARY_OP}, */
197
    {"-o",	TEST_OPTION,		UNARY_OP},
198
    /* {"-o",	BINARY_OR,		B_BINARY_OP}, */
199
 
200
/* Add new entries after here */
201
 
202
    {"-r",	FILE_READABLE,		UNARY_OP},
203
    {"-w",	FILE_WRITABLE,		UNARY_OP},
204
    {"-x",	FILE_EXECUTABLE,	UNARY_OP},
205
    {"-f",	FILE_REGULAR,		UNARY_OP},
206
    {"-d",	FILE_DIRECTRY,		UNARY_OP},
207
    {"-s",	FILE_NONZERO,		UNARY_OP},
208
    {"-t",	FILE_TERMINAL,		UNARY_OP},
209
    {"-z",	STRING_ZERO,		UNARY_OP},
210
    {"-n",	STRING_NONZERO,		UNARY_OP},
211
    {"=",	STRING_EQUAL,		BINARY_OP},
212
    {"!=",	STRING_NOTEQUAL,	BINARY_OP},
213
    {"<",	STRING_LESS,		BINARY_OP},
214
    {">",	STRING_GREATER,		BINARY_OP},
215
    {"-eq",	NUMBER_EQUAL,		BINARY_OP},
216
    {"-ne",	NUMBER_NOTEQUAL,	BINARY_OP},
217
    {"-ge",	NUMBER_EQ_GREAT,	BINARY_OP},
218
    {"-gt",	NUMBER_GREATER,		BINARY_OP},
219
    {"-le",	NUMBER_EQ_LESS,		BINARY_OP},
220
    {"-lt",	NUMBER_LESS,		BINARY_OP},
221
    {"!",	UNARY_NOT,		B_UNARY_OP},
222
    {"(",	LPAREN,			PAREN},
223
    {")",	RPAREN,			PAREN},
224
    {"&&",	BINARY_AND,		B_BINARY_OP},
225
    {"||",	BINARY_OR,		B_BINARY_OP},
226
    {"-c",	FILE_CHARACTER,		UNARY_OP},
227
    {"-b",	FILE_BLOCK,		UNARY_OP},
228
    {"-u",	FILE_USER,		UNARY_OP},
229
    {"-g",	FILE_GROUP,		UNARY_OP},
230
    {"-k",	FILE_TEXT,		UNARY_OP},
231
    {"-p",	FILE_FIFO,		UNARY_OP},
232
    {"-h",	FILE_SYMBOLIC,		UNARY_OP},
233
    {"-L",	FILE_SYMBOLIC,		UNARY_OP},
234
    {"-O",	FILE_OWNER,		UNARY_OP},
235
    {"-G",	FILE_GROUPER,		UNARY_OP},
236
    {"-S",	FILE_SOCKET,		UNARY_OP},
237
    {"-nt",	FILE_NEWER,		BINARY_OP},
238
    {"-ot",	FILE_OLDER,		BINARY_OP},
239
    {"-ef",	FILE_EQUAL,		BINARY_OP},
240
    {(char *)NULL,	0,		0}
241
};
242
 
243
/*
244
 * -o values for set
245
 */
246
 
247
static struct SetOptions {
248
    char		*OptionName;		/* Option name		*/
249
    unsigned int	FlagValue;		/* Option flag		*/
250
    bool		HasOptionValue;		/* Has -x value		*/
251
} SetOptions[] = {
252
    { "alternation",	FLAGS_ALTERNATION,	FALSE },
253
    { "allexport",	'a',			TRUE },
254
 
255
#ifdef FLAGS_BREAK_SWITCH
256
    { "break",		FLAGS_BREAK_SWITCH,	FALSE },
257
#endif
258
 
259
#ifdef FLAGS_EMACS
260
    { "emacs",		FLAGS_EMACS,		FALSE },
261
#endif
262
 
263
    { "errexit",	'e',			TRUE },
264
 
265
#ifdef FLAGS_GMACS
266
    { "gmacs",		FLAGS_GMACS,		FALSE },
267
#endif
268
 
269
#if (OS_TYPE == OS_NT) || (OS_TYPE == OS_OS2)
270
    { "ignorecase",	FLAGS_NOCASE,		FALSE },
271
#endif
272
 
273
    { "ignoreeof",	FLAGS_IGNOREEOF,	FALSE },
274
    { "keyword",	'k',			TRUE },
275
    { "markdirs",	FLAGS_MARKDIRECTORY,	FALSE },
276
    { "msdos",		FLAGS_MSDOS_FORMAT,	FALSE },
277
    { "noclobber",	FLAGS_NOCLOBER,		FALSE },
278
    { "noexec",		'n',			TRUE },
279
    { "noglob",		'f',			TRUE },
280
    { "nounset",	'u',			TRUE },
281
 
282
#ifdef FLAGS_SET_OS2
283
    { "os2",		FLAGS_SET_OS2,		FALSE },
284
#endif
285
 
286
    { "privileged",	'p',			TRUE },
287
 
288
#if (OS_TYPE == OS_NT) || (OS_TYPE == OS_OS2)
289
    { "realpipes",	FLAGS_REALPIPES,	FALSE },
290
#endif
291
 
292
    { "trackall",	'h',			TRUE },
293
 
294
#ifdef FLAGS_VI
295
    { "vi",		FLAGS_VI,		FALSE },
296
#endif
297
 
298
    { "verbose",	'v',			TRUE },
299
    { "verify",		FLAGS_VERIFY_SWITCH,	FALSE },
300
 
301
#ifdef FLAGS_SET_NT
302
    { "winnt",		FLAGS_SET_NT,		FALSE },
303
#endif
304
 
305
    { "xtrace",		'x',			TRUE },
306
    { (char *)NULL,	0,	FALSE }
307
};
308
 
309
/*
310
 * Getopts values
311
 */
312
 
313
static GetoptsIndex	GetOptsIndex = { 1, 1 };
314
 
315
/*
316
 * Signal Name structure
317
 *
318
 * Note that the first two entries are constructed such that the character
319
 * before the name is a ~.
320
 */
321
 
322
#define MAX_TRAP_SIGNALS	ARRAY_SIZE (TrapSignalList)
323
#define SIG_SPECIAL		-1		/* Error or trap */
324
#define SIG_NO_MAP		-2		/* No DOS mapping */
325
 
326
#if (OS_TYPE == OS_UNIX)
327
#define MAX_SIG_MAP		NSIG
328
#else
329
#define MAX_SIG_MAP		ARRAY_SIZE (UnixToDosSignals)
330
#endif
331
 
332
/*
333
 * Signal name to number mapping
334
 */
335
 
336
static struct TrapSignalList {
337
    char	*name;
338
    int		signo;
339
} TrapSignalList [] = {
340
    { Trap_DEBUG + 1,		SIG_SPECIAL },
341
    { Trap_ERR + 1,		SIG_SPECIAL },
342
    { LIT_exit,			0 },
343
    { "SIGINT",			SIGINT },
344
    { "SIGFPE",			SIGFPE },
345
    { "SIGILL",			SIGILL },
346
    { "SIGSEGV",		SIGSEGV },
347
    { "SIGABRT",		SIGABRT },
348
 
349
#ifdef SIGTERM
350
    { "SIGTERM",		SIGTERM },
351
#endif
352
 
353
#ifdef SIGBREAK
354
    { "SIGBREAK",		SIGBREAK },
355
#endif
356
 
357
#ifdef SIGUSR1
358
    { "SIGUSR1",		SIGUSR1 },
359
#endif
360
 
361
#ifdef SIGUSR2
362
    { "SIGUSR2",		SIGUSR2 },
363
#endif
364
 
365
#ifdef SIGUSR3
366
    { "SIGUSR3",		SIGUSR3 },
367
#endif
368
 
369
#ifdef SIGIDIVZ
370
    { "SIGIDIVZ",		SIGIDIVZ },
371
#endif
372
 
373
#ifdef SIGIOVFL
374
    { "SIGIOVFL",		SIGIOVFL },
375
#endif
376
 
377
#if (OS_TYPE == OS_UNIX)
378
    { "SIGHUP",			SIGHUP },
379
    { "SIGQUIT",		SIGQUIT },
380
    { "SIGTRAP",		SIGTRAP },
381
    { "SIGIOT",			SIGIOT },
382
    { "SIGEMT",			SIGEMT },
383
    { "SIGKILL",		SIGKILL },
384
    { "SIGBUS",			SIGBUS },
385
    { "SIGSYS",			SIGSYS },
386
    { "SIGPIPE",		SIGPIPE },
387
    { "SIGALRM",		SIGALRM },
388
    { "SIGTERM",		SIGTERM },
389
    { "SIGUSR1",		SIGUSR1 },
390
    { "SIGUSR2",		SIGUSR2 },
391
    { "SIGCLD",			SIGCLD },
392
    { "SIGPWR",			SIGPWR },
393
    { "SIGWINCH",		SIGWINCH },
394
    { "SIGURG",			SIGURG },
395
    { "SIGPOLL",		SIGPOLL },
396
    { "SIGIO",			SIGIO },
397
    { "SIGSTOP",		SIGSTOP },
398
    { "SIGTSTP",		SIGTSTP },
399
    { "SIGCONT",		SIGCONT },
400
    { "SIGTTIN",		SIGTTIN },
401
    { "SIGTTOU",		SIGTTOU },
402
    { "SIGVTALRM",		SIGVTALRM },
403
    { "SIGPROF",		SIGPROF },
404
    { "SIGXCPU",		SIGXCPU },
405
    { "SIGXFSZ",		SIGXFSZ },
406
#endif
407
};
408
 
409
/*
410
 * UNIX to DOS signal number mapping.  We only have 15 mappings because
411
 * only the fdirst 15 signal numbers are common
412
 */
413
 
414
#if (OS_TYPE != OS_UNIX)
415
static int	UnixToDosSignals [] = {
416
    0,			/* 0 - On exit				*/
417
    SIG_NO_MAP,		/* 1 - hangup				*/
418
    SIGINT,		/* 2 - interrupt (DEL)			*/
419
    SIG_NO_MAP,		/* 3 - quit (ASCII FS)			*/
420
    SIGILL,		/* 4 - illegal instruction		*/
421
    SIG_NO_MAP,		/* 5 - trace trap			*/
422
    SIG_NO_MAP,		/* 6 - IOT instruction			*/
423
    SIG_NO_MAP,		/* 7 - EMT instruction			*/
424
    SIGFPE,		/* 8 - floating point exception		*/
425
    SIG_NO_MAP,		/* 9 - kill				*/
426
    SIG_NO_MAP,		/* 10 - bus error			*/
427
    SIGSEGV,		/* 11 - segmentation violation		*/
428
    SIG_NO_MAP,		/* 12 - bad argument to system call	*/
429
    SIG_NO_MAP,		/* 13 - write on a pipe with no reader	*/
430
    SIG_NO_MAP,		/* 14 - alarm clock			*/
431
    SIGTERM		/* 15 - software termination signal	*/
432
};
433
#endif
434
 
435
 
436
/*
437
 * General Functions
438
 */
439
 
440
static int		DeleteAllVariables (const void *, const void *);
441
static int F_LOCAL	doOutofMemory (char *);
442
static int F_LOCAL	TestProcessNextExpression (int);
443
static int F_LOCAL	TestANDExpression (int);
444
static int F_LOCAL	TestPrimaryExpression (int);
445
static int F_LOCAL	TestUnaryOperand (int);
446
static int F_LOCAL	TestBinaryOperand (void);
447
static int F_LOCAL	TestLexicalAnalysis (void);
448
static struct TestOperator *
449
	   F_LOCAL	TestLookupOperator (char *);
450
static long F_LOCAL	GetNumberForTest (char *);
451
static void F_LOCAL	TestSyntaxError (void);
452
static void F_LOCAL	SetVerifyStatus (bool);
453
static void F_LOCAL     WhenceLocation (bool, const char *, const char *);
454
static void F_LOCAL     WhenceType (const char *);
455
static int F_LOCAL	PrintOptionSettings (void);
456
static int F_LOCAL      CheckFAccess (const char *, int);
457
static int F_LOCAL      CheckFType (const char *, int);
458
static int F_LOCAL      CheckFMode (const char *, int);
459
static int F_LOCAL      CheckFSize (const char *);
460
static int F_LOCAL      CheckForFD (const char *);
461
 
462
#if (OS_TYPE != OS_UNIX)
463
static OSCALL_RET F_LOCAL OS_GetFHAttributes (int, OSCALL_PARAM *);
464
#endif
465
 
466
#if (OS_TYPE == OS_DOS)
467
static void F_LOCAL	SetBreakStatus (bool);
468
#else
469
#  define SetBreakStatus(a)
470
#endif
471
 
472
static bool F_LOCAL	CheckPhysLogical (char *, bool *);
473
static char * F_LOCAL	GetPhysicalPath (char *, bool);
474
static bool F_LOCAL	ReadALine (int, char *, bool, bool, int *);
475
static bool F_LOCAL	WriteOutLine (int);
476
static bool F_LOCAL	ChangeOptionValue (char *, bool);
477
static void F_LOCAL	SetClearFlag (int, bool);
478
static void F_LOCAL	RemoveVariable (char *, int);
479
static int F_LOCAL	BreakContinueProcessing (char *, int);
480
static int F_LOCAL	SetUpNewParameterVariables (char **, int, int, char *);
481
static int F_LOCAL	UsageError (char *);
482
static void F_LOCAL 	PrintEntry (VariableList *, bool, unsigned int);
483
static int F_LOCAL 	UpdateVariableStatus (char **, unsigned int);
484
static int F_LOCAL	TypesetVariables (char **);
485
static int F_LOCAL	ListAllVariables (unsigned int, bool);
486
static int F_LOCAL	HandleFunction (char *);
487
static int F_LOCAL	TestOptionValue (char *, bool);
488
static int F_LOCAL	GetUnitNumber (char *);
489
static struct SetOptions * F_LOCAL LookUpOptionValue (char *);
490
static void		DisplayVariableEntry (const void *, VISIT, int);
491
static struct TrapSignalList * F_LOCAL LookupSignalName (char *);
492
 
493
#if (OS_TYPE != OS_DOS)
494
static bool F_LOCAL	ConvertJobToPid (char *, PID *);
495
 
496
#  if (OS_TYPE == OS_OS2)
497
static void F_LOCAL	DisplayStartData (STARTDATA *);
498
#  endif
499
 
500
#  if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32)
501
APIRET	 		DosQFileMode (PSZ, PULONG);
502
 
503
#    if !defined (__EMX__)
504
#      define Dos32FlagProcess		DosFlagProcess
505
#      pragma linkage (DosFlagProcess, far16 pascal)
506
#    else
507
USHORT	_THUNK_FUNCTION (Dos16FlagProcess) ();
508
#    endif
509
 
510
extern USHORT		Dos32FlagProcess (PID, USHORT, USHORT, USHORT);
511
 
512
#  endif
513
 
514
#  if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_16)
515
#      define Dos32FlagProcess		DosFlagProcess
516
#  endif
517
 
518
#  if (OS_TYPE == OS_NT)
519
int                      DosQFileMode (const char *, DWORD *);
520
#  endif
521
#endif
522
 
523
/*
524
 * Builtin Commands
525
 */
526
 
527
static int	doexport (int, char **);
528
static int	doreadonly (int, char **);
529
static int	domsdos (int, char **);
530
static int	dotypeset (int, char **);
531
static int	dounalias (int, char **);
532
static int	doalias (int, char **);
533
static int	dolabel (int, char **);
534
static int	dofalse (int, char **);
535
static int	dochdir (int, char **);
536
static int	dodrive (int, char **);
537
static int	doshift (int, char **);
538
static int	doumask (int, char **);
539
static int	dodot (int, char **);
540
static int	doecho (int, char **);
541
static int	dolet (int, char **);
542
static int	doshellinfo (int, char **);
543
 
544
#if (OS_TYPE == OS_OS2)
545
static int	dostart (int, char **);
546
#endif
547
 
548
#if (OS_TYPE != OS_DOS)
549
static int	dodetach (int, char **);
550
static int	dokill (int, char **);
551
static int	dojobs (int, char **);
552
static int	dowait (int, char **);
553
#endif
554
 
555
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
556
static int	dobind (int, char **);
557
#endif
558
 
559
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32) && !defined (__WATCOMC__)
560
static int	dotimes (int, char **);
561
#endif
562
 
563
#if (OS_TYPE == OS_NT) || (OS_TYPE == OS_UNIX)
564
static int	dotimes (int, char **);
565
#endif
566
 
567
static int	dogetopts (int, char **);
568
static int	dopwd (int, char **);
569
static int	doswap (int, char **);
570
static int	dounset (int, char **);
571
static int	dowhence (int, char **);
572
static int	dofc (int, char **);
573
static int	dotest (int, char **);
574
static int	dover (int, char **);
575
static int	doread (int, char **);
576
static int	doeval (int, char **);
577
static int	dotrap (int, char **);
578
static int	dobuiltin (int, char **);
579
static int	dobreak (int, char **);
580
static int	docontinue (int, char **);
581
static int	doexit (int, char **);
582
static int	doreturn (int, char **);
583
static int	doset (int, char **);
584
static int	dofunctions (int, char **);
585
static int	dohistory (int, char **);
586
 
587
/*
588
 * TWALK global values for DisplayVariable
589
 */
590
 
591
static unsigned int	DVE_Mask;
592
static bool 		DVE_PrintValue;
593
 
594
/*
595
 * Local data structure for test command
596
 */
597
 
598
static char			**TestArgumentList;
599
static struct TestOperator	*CurrentTestOperator;
600
static jmp_buf			TestErrorReturn;
601
static char			*TestProgram;
602
static bool			NewTestProgram;
603
 
604
/*
605
 * Static structure for typeset
606
 */
607
 
608
static struct TypesetValues {
609
    unsigned int	Flags_On;
610
    unsigned int	Flags_Off;
611
    int			Base;
612
    int			Width;
613
} TypesetValues;
614
 
615
/*
616
 * Current position in Getoption string
617
 */
618
 
619
static int	GetOptionPosition = 1;		/* Current position	*/
620
static int	BadOptionValue = 0;		/* The bad option value	*/
621
 
622
/*
623
 * Common strings
624
 */
625
 
626
static char	*DoubleHypen = "--";
627
static char	*TypeSetUsage = "typeset [ [ [+|-][Hflprtux] ] [+|-][LRZi[n]] [ name [=value] ...]";
628
static char	*NotBuiltinCommand = "not a builtin";
629
static char	*NotAnAlias = "%s: %s is not an alias";
630
static char	*NotValidAlias = "Invalid alias name";
631
static char	*Reply_Array[] = {LIT_REPLY, (char *)NULL};
632
static char	*BadDrive = "%c: bad drive";
633
static char	*ShellInternalCommand = "is a shell internal command";
634
static char	*FCTooLong = "fc: command line too long";
635
static char	LIT_alias[] = "alias";
636
static char	LIT_print[] = "print";
637
static char	LIT_read[] = "read";
638
static char	LIT_shift[] = "shift";
639
static char	LIT_break[] = "break";
640
static char	LIT_builtin[] = "builtin";
641
static char	LIT_devfd[] = "/dev/fd/";
642
static char	*BuiltinUsage = "builtin [ -ads ] [ commands ]";
643
static char	*WhenceUsage = "whence [ -pvt ] [ commands ]";
644
static char	LIT_continue[] = "continue";
645
static char	LIT_type[] = "type";
646
static char	LIT_unalias[] = "unalias";
647
static char	LIT_unfunction[] = "unfunction";
648
static char	*LIT_bun = "bad unit number";
649
static char	*HistoryUsage = "history [ -iedsl ] [ number ]";
650
static char	*ReturnUsage = "return [ value ]";
651
 
652
#if (OS_TYPE == OS_OS2)
653
static char	*StartUsage =
654
"start -O [dos | pm] [ -hHfWPFxibID ] [ -c [ vilsna ]] [ -t title ]\n                   [ -e string ]\n       start [ -dfWPFibCISxhH ] [ -c [ vilsna ]] [ -t title ] [ -e string ]\n                   [ -X directory ] [ args.. ]\n       start -A sessionId";
655
static char	*Start_NoSession = "start: Cannot switch to session %lu\n%s";
656
#endif
657
 
658
#if (OS_TYPE != OS_DOS)
659
static char	*JobUsage = "jobs [-lp] [ -P pid]";
660
static char	*KillUsage = "kill [ [-l] | [ [-sig] [ process id | %job number ] ... ] ]";
661
#endif
662
 
663
/*
664
 * Disable variables mapping
665
 */
666
 
667
struct	DisableVariableMap {
668
    char	*name;
669
    int		flag;
670
} DisableVariableMap [] = {
671
    { MailCheckVariable,	DISABLE_MAILCHECK },
672
    { OptArgVariable,		DISABLE_OPTARG },
673
    { OptIndVariable,		DISABLE_OPTIND },
674
    { SecondsVariable,		DISABLE_SECONDS },
675
    { RandomVariable,		DISABLE_RANDOM },
676
    { LastWordVariable,		DISABLE_LASTWORD },
677
    { LineCountVariable,	DISABLE_LINECOUNT },
678
 
679
#if (OS_TYPE != OS_DOS)
680
    { WinTitleVariable,		DISABLE_WINTITLE },
681
#endif
682
    { (char *)NULL,		0 },
683
};
684
 
685
/*
686
 * built-in commands: : and true
687
 */
688
 
689
static int dolabel (int argc, char **argv)
690
{
691
    (void) argc, argv;
692
    return 0;
693
}
694
 
695
static int dofalse (int argc, char **argv)
696
{
697
    (void) argc, argv;
698
    return 1;
699
}
700
 
701
/*
702
 * Getopts - split arguments.  getopts optstring name [ arg ... ]
703
 */
704
 
705
static int dogetopts (int argc, char **argv)
706
{
707
    char	**Arguments;
708
    char	*OptionString;
709
    int		result;
710
    char	SResult[3];
711
    char	BadResult[2];
712
    int		Mode = GETOPT_MESSAGE | GETOPT_PLUS;
713
 
714
    if (argc < 3)
715
	return UsageError ("getopts optstring name [ arg ... ]");
716
 
717
    memset (SResult, 0, 3);
718
 
719
/*
720
 * A leading : in optstring causes getopts to store the letter of an
721
 * invalid option in OPTARG, and to set name to ? for an unknown option and
722
 * to : when a required option is missing.
723
 */
724
 
725
    if (*(OptionString = argv[1]) == ':')
726
    {
727
	OptionString++;
728
	Mode = GETOPT_PLUS;
729
    }
730
 
731
/*
732
 * Use positional parameters
733
 */
734
 
735
    if (argc == 3)
736
    {
737
	argc = ParameterCount + 1;
738
	Arguments = ParameterArray;
739
    }
740
 
741
/* No - use supplied */
742
 
743
    else
744
    {
745
	Arguments = &argv[2];		/* Adjust pointers		*/
746
	argc -= 2;
747
    }
748
 
749
/*
750
 * Get the value of OPTIND and initialise the getopt function
751
 */
752
 
753
    if (!(DisabledVariables & DISABLE_OPTIND))
754
	OptionIndex = (int)GetVariableAsNumeric (OptIndVariable);
755
 
756
    else
757
	OptionIndex = GetOptsIndex.Index;
758
 
759
/* Initialise the other values */
760
 
761
    GetOptionPosition = GetOptsIndex.SubIndex;
762
    OptionArgument = (char *)NULL;
763
 
764
    result = GetOptions (argc, Arguments, OptionString, Mode);
765
 
766
/* Save new positions */
767
 
768
    SaveGetoptsValues (OptionIndex, GetOptionPosition);
769
 
770
/* Check for EOF */
771
 
772
    if (result == EOF)
773
	return 1;
774
 
775
/* Set up result string */
776
 
777
    *SResult = (char)result;
778
 
779
/* Did we get an error.  Yes.  If message output, don't put value
780
 * in OPTARG
781
 */
782
 
783
    if (result == '?')
784
    {
785
	if (Mode & GETOPT_MESSAGE)
786
	    OptionArgument = (char *)NULL;
787
 
788
/* Error, set up values in optarg and the result */
789
 
790
	else
791
	{
792
	    SResult[0] = (char)((OptionArgument == (char *)NULL) ? '?' : ':');
793
	    *(OptionArgument = BadResult) = (char)BadOptionValue;
794
	    *(OptionArgument + 1) = 0;
795
	}
796
    }
797
 
798
/* If the argument started with a +, tell them */
799
 
800
    else if (OptionStart == '+')
801
    {
802
      SResult[1] = (char)result;
803
      SResult[0] = '+';
804
    }
805
 
806
/* If we got an argument, set the various shell variables */
807
 
808
    if ((OptionArgument != (char *)NULL) &&
809
	(!(DisabledVariables & DISABLE_OPTARG)))
810
	SetVariableFromString (OptArgVariable, OptionArgument);
811
 
812
    SetVariableFromString (argv[2], SResult);
813
    return 0;
814
}
815
 
816
/*
817
 * Reset the getopts values
818
 */
819
 
820
void	ResetGetoptsValues (bool Variable)
821
{
822
    if (Variable && (!(DisabledVariables & DISABLE_OPTIND)))
823
	SetVariableFromNumeric (OptIndVariable, 1L);
824
 
825
    GetOptsIndex.Index = 1;
826
    GetOptsIndex.SubIndex = 1;
827
}
828
 
829
/*
830
 * Save the new Getopts values
831
 */
832
 
833
void	SaveGetoptsValues (int Index, int Position)
834
{
835
    if (!(DisabledVariables & DISABLE_OPTIND))
836
	SetVariableFromNumeric (OptIndVariable, (long)Index);
837
 
838
    GetOptsIndex.Index = Index;
839
    GetOptsIndex.SubIndex = Position;
840
}
841
 
842
/*
843
 * Get the current Getopts values
844
 */
845
 
846
void	GetGetoptsValues (GetoptsIndex *values)
847
{
848
    values->Index = GetOptsIndex.Index;
849
    values->SubIndex = GetOptsIndex.SubIndex;
850
}
851
 
852
/*
853
 * Echo the parameters:  echo [ -n ] parameters
854
 */
855
 
856
static int doecho (int argc, char **argv)
857
{
858
    int		flags = ECHO_ESCAPE;
859
    int		fid = 1;
860
    char	*ip;			/* Input pointer		*/
861
    char	*op;
862
    int		c, c1;
863
    int		R_flag = GETOPT_PRINT;	/* Enable -n test		*/
864
 
865
    ResetGetOptions ();			/* Reset GetOptions		*/
866
 
867
/* Echo or print? */
868
 
869
    if (strcmp (*argv, LIT_print) == 0)
870
    {
871
	R_flag = 0;			/* Reset		*/
872
 
873
	while ((c = GetOptions (argc, argv, "Rnprsu:", R_flag)) != EOF)
874
	{
875
	    switch (c)
876
	    {
877
		case 'R':
878
		    R_flag = GETOPT_PRINT;
879
		    flags &= ~ECHO_ESCAPE;
880
		    break;
881
 
882
		case 'n':
883
		    flags = ECHO_NO_EOL;
884
		    break;
885
 
886
		case 'r':
887
		    flags &= ~ECHO_ESCAPE;
888
		    break;
889
 
890
		case 's':
891
		    flags |= ECHO_HISTORY;
892
		    break;
893
 
894
		case 'p':
895
		    break;
896
 
897
		case 'u':
898
		    if ((fid = GetUnitNumber (LIT_print)) == -1)
899
			return 1;
900
 
901
		    break;
902
 
903
		default:
904
		    return UsageError ("print [ -Rpnrsu[unit] ] ...");
905
	    }
906
	}
907
    }
908
 
909
    if ((OptionIndex < argc) && (R_flag == GETOPT_PRINT) &&
910
	(!strcmp (argv[OptionIndex], "-n")))
911
    {
912
	flags |= ECHO_NO_EOL;
913
	++OptionIndex;
914
    }
915
 
916
    argv += OptionIndex;
917
 
918
/* Clear the history buffer so we can use it */
919
 
920
    FlushHistoryBuffer ();
921
    op = ConsoleLineBuffer;
922
 
923
/* Process the arguments.  Process \ as a special if necessary */
924
 
925
    while ((ip = *(argv++)) != NOWORD)
926
    {
927
 
928
/* Process the character */
929
 
930
	while ((c = (int)(*(ip++))) != 0)
931
	{
932
 
933
/* If echo too big - disable history save */
934
 
935
	    if ((op - ConsoleLineBuffer) > LINE_MAX - 4)
936
	    {
937
		*op = 0;
938
 
939
		if (!WriteOutLine (fid))
940
		    return 1;
941
 
942
		op = ConsoleLineBuffer;
943
 
944
		if (flags & ECHO_HISTORY)
945
		    fprintf (stderr, BasicErrorMessage,
946
			     "Line too long for history", LIT_print);
947
 
948
		flags &= ~ECHO_HISTORY;
949
	    }
950
 
951
	    if ((flags & ECHO_ESCAPE) && (c == CHAR_META))
952
	    {
953
		c1 = *ip;
954
 
955
		if ((c = ProcessOutputMetaCharacters (&ip)) == -1)
956
		{
957
		    flags |= ECHO_NO_EOL;
958
		    continue;
959
		}
960
 
961
/* If unchanged - output backslash */
962
 
963
		else if ((c == c1) && (c != CHAR_META))
964
		    *(op++) = CHAR_META;
965
	    }
966
 
967
	    *(op++) = (char)c;
968
	}
969
 
970
/* End of string - check to see if a space if required */
971
 
972
	if (*argv != NOWORD)
973
	    *(op++) = CHAR_SPACE;
974
    }
975
 
976
/* Is EOL required ? */
977
 
978
    if (!(flags & ECHO_NO_EOL))
979
    {
980
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32)
981
	if (IS_Console (fid))
982
	    *(op++) = CHAR_RETURN;
983
#endif
984
	*(op++) = CHAR_NEW_LINE;
985
    }
986
 
987
    *op = 0;
988
 
989
    if (!WriteOutLine (fid))
990
        return 1;
991
 
992
/* Save history */
993
 
994
    if (flags & ECHO_HISTORY)
995
    {
996
	CleanUpBuffer (op - ConsoleLineBuffer, ConsoleLineBuffer, 0x1a);
997
	AddHistory (FALSE);
998
    }
999
 
1000
    return 0;
1001
}
1002
 
1003
/*
1004
 * Write out the current line
1005
 */
1006
 
1007
static bool F_LOCAL WriteOutLine (int fid)
1008
{
1009
    size_t	Len = strlen (ConsoleLineBuffer);
1010
 
1011
    if (write (fid, ConsoleLineBuffer, Len) != (int)Len)
1012
    {
1013
        PrintWarningMessage ("print: write error on unit %d\n", fid);
1014
	return FALSE;
1015
    }
1016
 
1017
    return TRUE;
1018
 
1019
}
1020
 
1021
/*
1022
 * Display the current version: ver
1023
 */
1024
 
1025
static int dover (int argc, char **argv)
1026
{
1027
    (void) argc, argv;
1028
    PrintVersionNumber (stdout);
1029
    return 0;
1030
}
1031
 
1032
#ifdef OS_SWAPPING
1033
static char	*swap_device[] = {"disk", "extend", "expand"};
1034
#endif
1035
 
1036
/*
1037
 * Modify swapping information: swap [ options ]
1038
 */
1039
 
1040
static int doswap (int argc, char **argv)
1041
{
1042
#if (OS_TYPE != OS_DOS)
1043
    (void) argc, argv;
1044
    printf ("Swapping not available on %s", LIT_OSname);
1045
#elif !defined (OS_SWAPPING)
1046
    (void) argc, argv;
1047
    puts ("Swapping not available in 32-bit mode");
1048
#else
1049
    int		n = 1;
1050
    char	*cp;
1051
 
1052
/* Display current values ? */
1053
 
1054
    if (argv[1] == NOWORD)
1055
    {
1056
	if (Swap_Mode == SWAP_OFF)
1057
	    puts ("Swapping disabled");
1058
 
1059
	else
1060
	{
1061
	    int		j;
1062
 
1063
	    foputs ("Swap devices: ");
1064
 
1065
	    for (j = 0, n = 1; j < 3; ++j, n <<= 1)
1066
	    {
1067
		if (Swap_Mode & n)
1068
		{
1069
		    printf ("%s ", swap_device[j]);
1070
		}
1071
	    }
1072
 
1073
	    fputchar (CHAR_NEW_LINE);
1074
	}
1075
 
1076
	return 0;
1077
    }
1078
 
1079
/* Set up new values */
1080
 
1081
    Swap_Mode = SWAP_OFF;
1082
 
1083
    while ((cp = argv[n++]) != NOWORD)
1084
    {
1085
	if (strcmp (cp, "off") == 0)
1086
	    Swap_Mode = SWAP_OFF;
1087
 
1088
	else if (strcmp (cp, "on") == 0)
1089
	    Swap_Mode = SWAP_DISK | SWAP_EXPAND | SWAP_EXTEND;
1090
 
1091
/* Scan for valid arguments */
1092
 
1093
	else
1094
	{
1095
	    int		j, k;
1096
 
1097
	    for (j = 0, k = 1; j < 3; ++j, k <<= 1)
1098
	    {
1099
		if (strcmp (cp, swap_device[j]) == 0)
1100
		{
1101
		    Swap_Mode |= k;
1102
		    break;
1103
		}
1104
	    }
1105
 
1106
	    if (j == 3)
1107
		return UsageError ("swap [ on | off | disk | expand | extend [ address ] ] ...");
1108
	}
1109
    }
1110
 
1111
#endif
1112
    return 0;
1113
}
1114
 
1115
/*
1116
 * Output the current path: pwd [drives]
1117
 */
1118
 
1119
static int dopwd (int argc, char **argv)
1120
{
1121
    int			i;
1122
    int			Start = 1;
1123
    int			RetVal = 0;
1124
    char		*sp;
1125
    char		ndrive;
1126
    char		ldir[PATH_MAX + 6];
1127
    bool		Physical = FALSE;
1128
 
1129
    if ((argc > 1) && CheckPhysLogical (argv[1], &Physical))
1130
	Start++;
1131
 
1132
/* Print the current directories on the selected drive */
1133
 
1134
    i = Start;
1135
 
1136
    while ((sp = argv[i++]) != NOWORD)
1137
    {
1138
 
1139
/* Select the drive and get the path */
1140
 
1141
	while ((ndrive = *(sp++)) != 0)
1142
	{
1143
	    errno = 0;
1144
 
1145
	    if (!S_getcwd (ldir, GetDriveNumber (ndrive)) || errno)
1146
		RetVal = PrintWarningMessage (BadDrive, ndrive);
1147
 
1148
	    else if (Physical)
1149
		printf ("%c: path is %s\n", tolower (ndrive),
1150
			GetPhysicalPath (ldir, TRUE));
1151
 
1152
	    else
1153
		puts (ldir);
1154
	}
1155
    }
1156
 
1157
/* Print the current directory */
1158
 
1159
    if (argv[Start] == NOWORD)
1160
    {
1161
	strcpy (ldir, CurrentDirectory->value);
1162
	puts ((Physical) ? GetPhysicalPath (ldir, TRUE) : ldir);
1163
    }
1164
 
1165
    return RetVal;
1166
}
1167
 
1168
/*
1169
 * Unset a variable: unset [ flag ] [ variable name... ]
1170
 * Delete a function: unfunction <names ...>
1171
 */
1172
 
1173
static int dounset (int argc, char **argv)
1174
{
1175
    int			n = 1;
1176
    bool		Fnc = FALSE;
1177
    FunctionList 	*fp;
1178
    char		*cp;
1179
    int			i;
1180
 
1181
/* -f, functions */
1182
 
1183
    if (strcmp (*argv, LIT_unfunction) == 0)
1184
	Fnc = TRUE;
1185
 
1186
    else if ((argc > 1) && (strcmp (argv[1], "-f") == 0))
1187
    {
1188
	n++;
1189
	Fnc = TRUE;
1190
    }
1191
 
1192
/* Unset the variables, flags or functions */
1193
 
1194
    while ((cp = argv[n++]) != NOWORD)
1195
    {
1196
	if (!Fnc)
1197
	{
1198
	    UnSetVariable (cp, -1, FALSE);
1199
 
1200
	    for (i = 0; DisableVariableMap[i].name != (char *)NULL; i++)
1201
	    {
1202
		if (strcmp (DisableVariableMap[i].name, cp) == 0)
1203
		{
1204
		    DisabledVariables |= DisableVariableMap[i].flag;
1205
		    break;
1206
		}
1207
	    }
1208
	}
1209
 
1210
	else if ((fp = LookUpFunction (cp, TRUE)) != (FunctionList *)NULL)
1211
	    DeleteFunction (fp->tree);
1212
    }
1213
 
1214
    return 0;
1215
}
1216
 
1217
/* Delete a variable.  If all is set, system variables can be deleted.
1218
 * This is used to delete the trap functions
1219
 */
1220
 
1221
void	UnSetVariable (char *cp,	/* Variable name		*/
1222
		       int  OIndex,	/* Index preprocessed value	*/
1223
		       bool all)	/* Any variable			*/
1224
{
1225
    long		Index;
1226
    char		*term;
1227
    bool		ArrayDetected;
1228
 
1229
/* Unset a flag */
1230
 
1231
    if (*cp == '-')
1232
    {
1233
	while (*(++cp) != 0)
1234
	{
1235
	    if (islower (*cp))
1236
		FL_CLEAR (*cp);
1237
	}
1238
 
1239
	SetShellSwitches ();
1240
	return;
1241
    }
1242
 
1243
/* Ok - unset a variable and not a local value */
1244
 
1245
    if (!all && !(IS_VariableFC ((int)*cp)))
1246
	return;
1247
 
1248
/* Check in list */
1249
 
1250
    if (!GetVariableName (cp, &Index, &term, &ArrayDetected) || *term)
1251
	return;
1252
 
1253
    if (OIndex != -1)
1254
	Index = OIndex;
1255
 
1256
/*  Delete a specific entry or all? */
1257
 
1258
    if (!((ArrayDetected || (OIndex != -1))))
1259
	Index = -1;
1260
 
1261
    RemoveVariable (cp, (int)Index);
1262
}
1263
 
1264
/*
1265
 * Delete a variable
1266
 *
1267
 * Index = -1 implies all references
1268
 */
1269
 
1270
static void F_LOCAL RemoveVariable (char *name,	/* Variable name	*/
1271
				    int  Index)	/* Array index		*/
1272
{
1273
    VariableList	**vpp;
1274
    VariableList	*vp;
1275
    VariableList	dummy;
1276
    void                (_SIGDECL *save_signal)(int);
1277
 
1278
    while (TRUE)
1279
    {
1280
	dummy.name = name;
1281
	dummy.index = (int)Index;
1282
 
1283
	vpp = (VariableList **)tfind (&dummy, &VariableTree,
1284
				      DeleteAllVariables);
1285
 
1286
/* If not found, Ignore unset request */
1287
 
1288
	if (vpp == (VariableList **)NULL)
1289
	    return;
1290
 
1291
/* Error if read-only */
1292
 
1293
	vp = *vpp;
1294
 
1295
	if (vp->status & (STATUS_READONLY | STATUS_CANNOT_UNSET))
1296
	{
1297
	    PrintWarningMessage ("unset: %s %s", vp->name,
1298
				 (vp->status & STATUS_CANNOT_UNSET)
1299
				    ? "cannot be unset" : LIT_IsReadonly);
1300
	    return;
1301
	}
1302
 
1303
/* Disable signals */
1304
 
1305
	save_signal = signal (SIGINT, SIG_IGN);
1306
 
1307
/* Delete it */
1308
 
1309
	dummy.index = vp->index;
1310
	tdelete (&dummy, &VariableTree, SearchVariable);
1311
	ReleaseMemoryCell ((void *)vp->name);
1312
 
1313
	if (vp->value != null)
1314
	    ReleaseMemoryCell ((void *)vp->value);
1315
 
1316
	ReleaseMemoryCell ((void *)vp);
1317
 
1318
/* Restore signals */
1319
 
1320
	signal (SIGINT, save_signal);
1321
    }
1322
}
1323
 
1324
/*
1325
 * TFIND - Search the VARIABLE TREE for an entry to delete
1326
 */
1327
 
1328
static int DeleteAllVariables (const void *key1, const void *key2)
1329
{
1330
    int			diff;
1331
 
1332
    if ((diff = strcmp (((VariableList *)key1)->name,
1333
			((VariableList *)key2)->name)) != 0)
1334
	return diff;
1335
 
1336
    if (((VariableList *)key1)->index == -1)
1337
        return 0;
1338
 
1339
    return ((VariableList *)key1)->index - ((VariableList *)key2)->index;
1340
}
1341
 
1342
/*
1343
 * Execute a test: test <arguments>
1344
 */
1345
 
1346
static int dotest (int argc, char **argv)
1347
{
1348
    int		st = 0;
1349
    char	*End;
1350
 
1351
    (void)argc;
1352
 
1353
    NewTestProgram = (bool)(strcmp (TestProgram = *argv, LIT_Test) == 0);
1354
 
1355
/* Note that -a and -o change meaning if [[ ... ]] is used */
1356
 
1357
    if (NewTestProgram)
1358
    {
1359
	End = "]]";
1360
	ListOfTestOperators[0].OperatorID = FILE_EXISTS;
1361
	ListOfTestOperators[0].OperatorType = UNARY_OP;
1362
	ListOfTestOperators[1].OperatorID = TEST_OPTION;
1363
	ListOfTestOperators[1].OperatorType = UNARY_OP;
1364
    }
1365
 
1366
    else
1367
    {
1368
	End = "]";
1369
	ListOfTestOperators[0].OperatorID = BINARY_AND;
1370
	ListOfTestOperators[0].OperatorType = B_BINARY_OP;
1371
	ListOfTestOperators[1].OperatorID = BINARY_OR;
1372
	ListOfTestOperators[1].OperatorType = B_BINARY_OP;
1373
    }
1374
 
1375
/* Check out */
1376
 
1377
    CurrentTestOperator = (struct TestOperator *)NULL;
1378
 
1379
/* If [ <arguments> ] or [[ <arguments> ]] form, check for end ] or ]] and
1380
 * remove it
1381
 */
1382
 
1383
    if (NewTestProgram || (strcmp (*argv, "[") == 0))
1384
    {
1385
	while (argv[++st] != NOWORD)
1386
	    ;
1387
 
1388
	if (strcmp (argv[--st], End) != 0)
1389
	    return PrintWarningMessage ("%s: missing '%s'", TestProgram, End);
1390
 
1391
	else
1392
	    argv[st] = NOWORD;
1393
    }
1394
 
1395
/* Check for null expression */
1396
 
1397
    if (*(TestArgumentList = &argv[1]) == NOWORD)
1398
	return 1;
1399
 
1400
/* Set abort address */
1401
 
1402
    if (setjmp (TestErrorReturn))
1403
	return 1;
1404
 
1405
    st = !TestProcessNextExpression (TestLexicalAnalysis ());
1406
 
1407
    if (*(TestArgumentList + 1) != NOWORD)
1408
	TestSyntaxError ();
1409
 
1410
    return (st);
1411
}
1412
 
1413
/*
1414
 * Process next test expression
1415
 */
1416
 
1417
static int F_LOCAL TestProcessNextExpression (int n)
1418
{
1419
    int		res;
1420
 
1421
    if (n == END_OF_INPUT)
1422
	TestSyntaxError ();
1423
 
1424
    res = TestANDExpression (n);
1425
 
1426
    TestArgumentList++;
1427
 
1428
    if (TestLexicalAnalysis () == BINARY_OR)
1429
    {
1430
	TestArgumentList++;
1431
 
1432
	return TestProcessNextExpression (TestLexicalAnalysis ()) || res;
1433
    }
1434
 
1435
    TestArgumentList--;
1436
    return res;
1437
}
1438
 
1439
/*
1440
 * Binary expression ( a AND b)
1441
 */
1442
 
1443
static int F_LOCAL TestANDExpression (int n)
1444
{
1445
    int res;
1446
 
1447
    if (n == END_OF_INPUT)
1448
	TestSyntaxError ();
1449
 
1450
    res = TestPrimaryExpression (n);
1451
    TestArgumentList++;
1452
 
1453
    if (TestLexicalAnalysis () == BINARY_AND)
1454
    {
1455
	TestArgumentList++;
1456
	return TestANDExpression (TestLexicalAnalysis ()) && res;
1457
    }
1458
 
1459
    TestArgumentList--;
1460
    return res;
1461
}
1462
 
1463
/*
1464
 * Handle Primary expression
1465
 */
1466
 
1467
static int F_LOCAL TestPrimaryExpression (int n)
1468
{
1469
    int			res;
1470
 
1471
    switch (n)
1472
    {
1473
	case END_OF_INPUT:
1474
	    TestSyntaxError ();
1475
 
1476
    	case UNARY_NOT:
1477
	    TestArgumentList++;
1478
	    return !TestPrimaryExpression (TestLexicalAnalysis ());
1479
 
1480
	case LPAREN:
1481
	    TestArgumentList++;
1482
	    res = TestProcessNextExpression (TestLexicalAnalysis ());
1483
 
1484
	    TestArgumentList++;
1485
	    if (TestLexicalAnalysis () != RPAREN)
1486
		TestSyntaxError ();
1487
 
1488
	    return res;
1489
 
1490
/* Operand */
1491
 
1492
	case OPERAND:
1493
	    return TestBinaryOperand ();
1494
 
1495
/* unary expression */
1496
 
1497
	default:
1498
	    if ((CurrentTestOperator->OperatorType != UNARY_OP) ||
1499
		(*++TestArgumentList == 0))
1500
		TestSyntaxError ();
1501
 
1502
	    return TestUnaryOperand (n);
1503
    }
1504
}
1505
 
1506
/*
1507
 * Handle a Binary Operand
1508
 */
1509
 
1510
static int F_LOCAL TestBinaryOperand (void)
1511
{
1512
    char		*opnd1, *opnd2;
1513
    struct stat		s, s1;
1514
    short		op;
1515
 
1516
    opnd1 = *(TestArgumentList++);
1517
    (void) TestLexicalAnalysis ();
1518
 
1519
    if ((CurrentTestOperator != (struct TestOperator *)NULL) &&
1520
	(CurrentTestOperator->OperatorType == BINARY_OP))
1521
    {
1522
	op = CurrentTestOperator->OperatorID;
1523
 
1524
	TestArgumentList++;
1525
 
1526
	if ((opnd2 = *TestArgumentList) == NOWORD)
1527
	    TestSyntaxError ();
1528
 
1529
	switch (op)
1530
	{
1531
 
1532
/* String lengths */
1533
 
1534
	    case STRING_EQUAL:
1535
		return strcmp (opnd1, opnd2) == 0;
1536
 
1537
	    case STRING_NOTEQUAL:
1538
		return strcmp (opnd1, opnd2) != 0;
1539
 
1540
	    case STRING_LESS:
1541
		return strcmp (opnd1, opnd2) < 0;
1542
 
1543
	    case STRING_GREATER:
1544
		return strcmp (opnd1, opnd2) > 0;
1545
 
1546
/* Numeric comparisions */
1547
 
1548
	    case NUMBER_EQUAL:
1549
		return GetNumberForTest (opnd1) == GetNumberForTest (opnd2);
1550
 
1551
	    case NUMBER_NOTEQUAL:
1552
		return GetNumberForTest (opnd1) != GetNumberForTest (opnd2);
1553
 
1554
	    case NUMBER_EQ_GREAT:
1555
		return GetNumberForTest (opnd1) >= GetNumberForTest (opnd2);
1556
 
1557
	    case NUMBER_GREATER:
1558
		return GetNumberForTest (opnd1) > GetNumberForTest (opnd2);
1559
 
1560
	    case NUMBER_EQ_LESS:
1561
		return GetNumberForTest (opnd1) <= GetNumberForTest (opnd2);
1562
 
1563
	    case NUMBER_LESS:
1564
		return GetNumberForTest (opnd1) < GetNumberForTest (opnd2);
1565
 
1566
/* Older and Newer - if file not found - set to current time */
1567
 
1568
	    case FILE_NEWER:
1569
	    case FILE_OLDER:
1570
		if (!S_stat (opnd1, &s))
1571
		    return 0;
1572
 
1573
		if (!S_stat (opnd2, &s1))
1574
		    s1.st_mtime = 0L;
1575
 
1576
		return (op == FILE_NEWER) ? (s.st_mtime > s1.st_mtime)
1577
					  : (s.st_mtime < s1.st_mtime);
1578
 
1579
/*
1580
 * Equals - difficult on DOS.  So just do want UNIX says, but first compare
1581
 * the absolute path names
1582
 */
1583
 
1584
	    case FILE_EQUAL:
1585
	    {
1586
#if (OS_TYPE != OS_UNIX)
1587
		char	*a_opnd1;
1588
		char	*a_opnd2;
1589
		int	res;
1590
#endif
1591
 
1592
		if ((!S_stat (opnd1, &s)) || (!S_stat (opnd2, &s1)))
1593
		    return 0;
1594
 
1595
#if (OS_TYPE == OS_UNIX)
1596
		return ((s.st_dev == s1.st_dev) && (s.st_ino == s1.st_ino));
1597
#else
1598
 
1599
		a_opnd1 = AllocateMemoryCell (FFNAME_MAX);
1600
		a_opnd2 = AllocateMemoryCell (FFNAME_MAX);
1601
 
1602
		if ((a_opnd1 == (char *)NULL) || (a_opnd1 == (char *)NULL))
1603
		{
1604
		    doOutofMemory (LIT_Test);
1605
		    return 0;
1606
		}
1607
 
1608
		GenerateFullExecutablePath (strcpy (a_opnd1, opnd1));
1609
		GenerateFullExecutablePath (strcpy (a_opnd2, opnd2));
1610
 
1611
/* If this is OS/2, we need to decide if to check for HPFS */
1612
 
1613
#  if (OS_TYPE != OS_DOS)
1614
		res = ((!IsHPFSFileSystem (a_opnd1)) ||
1615
		       (ShellGlobalFlags & FLAGS_NOCASE))
1616
			    ? stricmp (a_opnd1, a_opnd2)
1617
			    : strcmp (a_opnd1, a_opnd2);
1618
#  else
1619
		res = stricmp (a_opnd1, a_opnd2);
1620
#  endif
1621
 
1622
		ReleaseMemoryCell (a_opnd1);
1623
		ReleaseMemoryCell (a_opnd2);
1624
 
1625
		return (res == 0) ? 1
1626
				  : ((s.st_dev == s1.st_dev) &&
1627
				     (s.st_ino == s1.st_ino));
1628
#endif
1629
	    }
1630
	}
1631
    }
1632
 
1633
    TestArgumentList--;
1634
    return strlen (opnd1) != 0;
1635
}
1636
 
1637
/*
1638
 * Handle a Unary Operand
1639
 */
1640
 
1641
static int F_LOCAL TestUnaryOperand (int n)
1642
{
1643
    switch (n)
1644
    {
1645
	case STRING_ZERO:
1646
	    return strlen (*TestArgumentList) == 0;
1647
 
1648
	case STRING_NONZERO:
1649
	    return strlen (*TestArgumentList) != 0;
1650
 
1651
	case TEST_OPTION:
1652
	    return TestOptionValue (*TestArgumentList, TRUE) != 0;
1653
 
1654
/* File functions */
1655
 
1656
	case FILE_EXISTS:
1657
	    return CheckFAccess (*TestArgumentList, F_OK);
1658
 
1659
	case FILE_READABLE:
1660
	    return CheckFAccess (*TestArgumentList, R_OK);
1661
 
1662
	case FILE_WRITABLE:
1663
	    return CheckFAccess (*TestArgumentList, W_OK);
1664
 
1665
	case FILE_EXECUTABLE:
1666
	    return CheckFAccess (*TestArgumentList, X_OK);
1667
 
1668
	case FILE_REGULAR:
1669
	    return CheckFType (*TestArgumentList, S_IFREG);
1670
 
1671
	case FILE_DIRECTRY:
1672
	    return CheckFType (*TestArgumentList, S_IFDIR);
1673
 
1674
	case FILE_NONZERO:
1675
	    return CheckFSize (*TestArgumentList);
1676
 
1677
	case FILE_TERMINAL:
1678
	    return IS_TTY ((int)GetNumberForTest (*TestArgumentList));
1679
 
1680
/* The following have no meaning on MSDOS or OS/2.  So we always return
1681
 * fail for compatability
1682
 */
1683
 
1684
#if (OS_TYPE == OS_UNIX)
1685
	case FILE_USER:
1686
	    return CheckFMode (*TestArgumentList, S_ISUID);
1687
 
1688
	case FILE_GROUP:
1689
	    return CheckFMode (*TestArgumentList, S_ISGID);
1690
 
1691
	case FILE_TEXT:
1692
	    return CheckFMode (*TestArgumentList, S_ISVTX);
1693
#else
1694
	case FILE_USER:
1695
	    return CheckFMode (*TestArgumentList, OS_FILE_HIDDEN);
1696
 
1697
	case FILE_GROUP:
1698
	    return CheckFMode (*TestArgumentList, OS_FILE_SYSTEM);
1699
 
1700
	case FILE_TEXT:
1701
	    return CheckFMode (*TestArgumentList, OS_FILE_ARCHIVED);
1702
#endif
1703
 
1704
	case FILE_BLOCK:
1705
	    return CheckFType (*TestArgumentList, S_IFBLK);
1706
 
1707
	case FILE_CHARACTER:
1708
	    return CheckFType (*TestArgumentList, S_IFCHR);
1709
 
1710
#if (OS_TYPE == OS_UNIX)
1711
	case FILE_FIFO:
1712
	    return CheckFType (*TestArgumentList, S_IFIFO);
1713
 
1714
	case FILE_SYMBOLIC:
1715
	    return CheckFType (*TestArgumentList, S_IFLNK);
1716
 
1717
	case FILE_SOCKET:
1718
	    return CheckFType (*TestArgumentList, S_IFSOCK);
1719
#else
1720
	case FILE_FIFO:
1721
	case FILE_SYMBOLIC:
1722
	case FILE_SOCKET:
1723
	    return 0;
1724
#endif
1725
 
1726
/* Under MSDOS and OS/2, we always own the file.  Not necessarily true on
1727
 * networked versions.  But there is no common way of finding out
1728
 */
1729
 
1730
#if (OS_TYPE == OS_UNIX)
1731
	case FILE_OWNER:
1732
	    return CheckFOwner (*TestArgumentList);
1733
 
1734
	case FILE_GROUPER:
1735
	    return CheckFGroup (*TestArgumentList);
1736
#else
1737
	case FILE_OWNER:
1738
	case FILE_GROUPER:
1739
	    return 1;
1740
#endif
1741
    }
1742
 
1743
    return 0;
1744
}
1745
 
1746
/* Operator or Operand ? */
1747
 
1748
static int F_LOCAL TestLexicalAnalysis (void)
1749
{
1750
    struct TestOperator		*op;
1751
    char			*s = *TestArgumentList;
1752
 
1753
    if (s == NOWORD)
1754
	return END_OF_INPUT;
1755
 
1756
/* This is a real pain.  If the current string is a unary operator and the
1757
 * next string is a binary operator, assume the current string is a parameter
1758
 * to the binary operator and not a unary operator.
1759
 */
1760
 
1761
    if ((CurrentTestOperator = TestLookupOperator (s))
1762
			     != (struct TestOperator *)NULL)
1763
    {
1764
	s = *(TestArgumentList + 1);
1765
 
1766
	if ((CurrentTestOperator->OperatorType != UNARY_OP) ||
1767
	    (s == (char *)NULL) ||
1768
	    ((op = TestLookupOperator (s)) == (struct TestOperator *)NULL) ||
1769
	    (op->OperatorType != BINARY_OP))
1770
	    return CurrentTestOperator->OperatorID;
1771
    }
1772
 
1773
    CurrentTestOperator = (struct TestOperator *)NULL;
1774
    return OPERAND;
1775
}
1776
 
1777
/*
1778
 * Look up the string and test for operator
1779
 */
1780
 
1781
static struct TestOperator * F_LOCAL TestLookupOperator (char *s)
1782
{
1783
    struct TestOperator		*op = ListOfTestOperators;
1784
 
1785
    while (op->OperatorName)
1786
    {
1787
	if (strcmp (s, op->OperatorName) == 0)
1788
	    return op;
1789
 
1790
	op++;
1791
    }
1792
 
1793
    return (struct TestOperator *)NULL;
1794
}
1795
 
1796
/*
1797
 * Get a long numeric value
1798
 */
1799
 
1800
static long F_LOCAL GetNumberForTest (char *s)
1801
{
1802
    long	l;
1803
 
1804
    if (!ConvertNumericValue (s, &l, 10))
1805
	TestSyntaxError ();
1806
 
1807
    return l;
1808
}
1809
 
1810
/*
1811
 * test syntax error - abort
1812
 */
1813
 
1814
static void F_LOCAL TestSyntaxError (void)
1815
{
1816
    PrintWarningMessage (BasicErrorMessage, TestProgram, LIT_SyntaxError);
1817
    longjmp (TestErrorReturn, 1);
1818
}
1819
 
1820
/*
1821
 * Select a new drive: x:
1822
 *
1823
 * Select the drive, get the current directory and check that we have
1824
 * actually selected the drive
1825
 */
1826
 
1827
static int dodrive (int argc, char **argv)
1828
{
1829
    unsigned int	ndrive = GetDriveNumber (**argv);
1830
    char		ldir[PATH_MAX + 6];
1831
    bool		bad = FALSE;
1832
 
1833
    if (argc != 1)
1834
	return UsageError ("drive:");
1835
 
1836
    if (SetCurrentDrive (ndrive) == -1)
1837
	bad = TRUE;
1838
 
1839
    else if (!S_getcwd (ldir, ndrive))
1840
	bad = TRUE;
1841
 
1842
    else
1843
    {
1844
	GetCurrentDirectoryPath ();
1845
 
1846
	if (ndrive != GetCurrentDrive ())
1847
	    bad = TRUE;
1848
    }
1849
 
1850
    if (bad)
1851
	return PrintWarningMessage (BadDrive, **argv);
1852
 
1853
    else
1854
	return 0;
1855
}
1856
 
1857
/*
1858
 * Check for -L or -P switch
1859
 */
1860
 
1861
static bool F_LOCAL CheckPhysLogical (char *string, bool *physical)
1862
{
1863
    if (strcmp (string, "-L") == 0)
1864
    {
1865
	*physical = FALSE;
1866
	return TRUE;
1867
    }
1868
 
1869
    if (strcmp (string, "-P") == 0)
1870
    {
1871
	*physical = TRUE;
1872
	return TRUE;
1873
    }
1874
 
1875
    return FALSE;
1876
}
1877
 
1878
/*
1879
 * Select a new directory:
1880
 *
1881
 * cd [ directory ]			Select new directory
1882
 * cd - 				Select previous directory
1883
 * cd <search string> <new string>	Select directory based on current
1884
 * cd					Select Home directory
1885
 * cd [-L | -P]				Use Logical or physical mapping
1886
 *					sort of symbolic links
1887
 */
1888
 
1889
static int dochdir (int argc, char **argv)
1890
{
1891
    char		*NewDirectory;	/* Original new directory	*/
1892
    char		*CNDirectory;	/* New directory		*/
1893
    char		*cp;		/* In CDPATH Pointer		*/
1894
    char		*directory;
1895
    bool		first = TRUE;
1896
    unsigned int	Length;
1897
    unsigned int	cdrive;
1898
    bool		Physical = FALSE;
1899
    int			Start = 1;
1900
    int			dcount;
1901
 
1902
/* If restricted shell - illegal */
1903
 
1904
    if (CheckForRestrictedShell ("cd"))
1905
	return 1;
1906
 
1907
    if ((argc > 1) && CheckPhysLogical (argv[1], &Physical))
1908
	Start = 2;
1909
 
1910
    if (argc - Start > 2)
1911
	return UsageError ("cd [ -P | -L ] [ directory | - | search replace ]");
1912
 
1913
/* Use default ? */
1914
 
1915
    if (((NewDirectory = argv[Start]) == NOWORD) &&
1916
	((NewDirectory = GetVariableAsString (HomeVariableName,
1917
					      FALSE)) == null))
1918
	return PrintWarningMessage ("cd: no home directory");
1919
 
1920
    if ((directory = AllocateMemoryCell (FFNAME_MAX)) == (char *)NULL)
1921
	return doOutofMemory ("cd");
1922
 
1923
    if ((strcmp (NewDirectory, ShellOptionsVariable) == 0) &&
1924
	((NewDirectory = GetVariableAsString (OldPWDVariable, FALSE)) == null))
1925
	return PrintWarningMessage ("cd: no previous directory");
1926
 
1927
/* Check for substitue */
1928
 
1929
    if ((argv[Start] != NOWORD) && (argv[Start + 1] != NOWORD))
1930
    {
1931
	if ((cp = strstr (CurrentDirectory->value, argv[Start]))
1932
		== (char *)NULL)
1933
	    return PrintWarningMessage ("cd: string not in pwd: %s",
1934
					argv[Start]);
1935
 
1936
	if (strlen (CurrentDirectory->value) - strlen (argv[Start]) +
1937
	    strlen (argv[Start + 1]) >= (size_t)FFNAME_MAX)
1938
	    return PrintWarningMessage ("cd: new directory string too long: %s",
1939
					argv[Start]);
1940
/* Do the substitution */
1941
 
1942
	Length = cp - CurrentDirectory->value;
1943
	strncpy (NewDirectory, CurrentDirectory->value, Length);
1944
	strcpy (NewDirectory + Length, argv[Start + 1]);
1945
	strcat (NewDirectory,
1946
		CurrentDirectory->value + strlen (argv[Start]) + Length);
1947
    }
1948
 
1949
/* Save the current drive */
1950
 
1951
    cdrive = GetCurrentDrive ();
1952
 
1953
/* Remove trailing / */
1954
 
1955
    Length = strlen (NewDirectory) - 1;
1956
 
1957
    if (IsPathCharacter (NewDirectory[Length]) &&
1958
	(!((!Length) || ((Length == 2) && IsDriveCharacter (NewDirectory[1])))))
1959
	NewDirectory[Length] = 0;
1960
 
1961
/*
1962
 * Special case for . and .., it seems
1963
 */
1964
 
1965
    if ((strcmp (NewDirectory, CurrentDirLiteral) == 0) &&
1966
	S_chdir (NewDirectory))
1967
    {
1968
	GetCurrentDirectoryPath ();
1969
	return  0;
1970
    }
1971
 
1972
    if (strcmp (NewDirectory, ParentDirLiteral) == 0)
1973
    {
1974
	if (S_chdir (NewDirectory))
1975
	{
1976
	    GetCurrentDirectoryPath ();
1977
	    return  0;
1978
	}
1979
 
1980
/* If we are in the root directory, .. does not move you! */
1981
 
1982
	dcount = 0;
1983
	cp = CurrentDirectory->value;
1984
 
1985
	while ((cp = strchr (cp, CHAR_UNIX_DIRECTORY)) != (char *)NULL)
1986
	{
1987
	    cp++;
1988
 
1989
	    if (++dcount == 2)
1990
	        break;
1991
	}
1992
 
1993
	if (dcount == 1)
1994
	{
1995
	    GetCurrentDirectoryPath ();
1996
	    return  0;
1997
	}
1998
    }
1999
 
2000
 
2001
/* Scan for the directory.  If there is not a / or : at start, use the
2002
 * CDPATH variable
2003
 */
2004
 
2005
    cp = (IsPathCharacter (*NewDirectory) ||
2006
          IsDriveCharacter (*(NewDirectory + 1)))
2007
		? null : GetVariableAsString (CDPathLiteral, FALSE);
2008
 
2009
    do
2010
    {
2011
	cp = BuildNextFullPathName (cp, NewDirectory, directory);
2012
 
2013
/* Check for new disk drive */
2014
 
2015
	if (Physical && (GetPhysicalPath (directory, FALSE) == (char *)NULL))
2016
	    return doOutofMemory ("cd");
2017
 
2018
	CNDirectory = directory;
2019
 
2020
/* Was the change successful? */
2021
 
2022
	if (GotoDirectory (CNDirectory, cdrive))
2023
	{
2024
 
2025
/* OK - reset the current directory (in the shell) and display the new
2026
 * path if appropriate
2027
 */
2028
 
2029
	    GetCurrentDirectoryPath ();
2030
 
2031
	    if (!first)
2032
		puts (CurrentDirectory->value);
2033
 
2034
	    return 0;
2035
	}
2036
 
2037
	first = FALSE;
2038
 
2039
    } while (cp != (char *)NULL);
2040
 
2041
/* Restore our original drive and restore directory info */
2042
 
2043
    GetCurrentDirectoryPath ();
2044
 
2045
    return PrintWarningMessage (BasicErrorMessage, NewDirectory,
2046
				"bad directory");
2047
}
2048
 
2049
/*
2050
 * Execute a shift command: shift [ n ]
2051
 */
2052
 
2053
static int doshift (int argc, char **argv)
2054
{
2055
    int		n;
2056
    char	*Nvalue = argv[1];
2057
 
2058
    if (argc > 2)
2059
	return UsageError ("shift [ count ]");
2060
 
2061
    n = (Nvalue != NOWORD) ? GetNumericValue (Nvalue) : 1;
2062
 
2063
    if (n < 0)
2064
	return PrintWarningMessage (LIT_Emsg, LIT_shift, "bad shift value",
2065
				    Nvalue);
2066
 
2067
    if (ParameterCount < n)
2068
	return PrintWarningMessage (BasicErrorMessage, LIT_shift,
2069
				    "nothing to shift");
2070
 
2071
    return SetUpNewParameterVariables (ParameterArray, n + 1,
2072
				       ParameterCount + 1, LIT_shift);
2073
}
2074
 
2075
/*
2076
 * Execute a umask command: umask [ n ]
2077
 */
2078
 
2079
static int doumask (int argc, char **argv)
2080
{
2081
    int		i;
2082
    char	*cp;
2083
    long	value = 0;
2084
 
2085
    if (argc > 2)
2086
	return UsageError ("umask [ new mask ]");
2087
 
2088
    if ((cp = argv[1]) == NOWORD)
2089
    {
2090
	umask ((i = umask (0)));
2091
	printf ("%o\n", i);
2092
    }
2093
 
2094
    else if (!ConvertNumericValue (cp, &value, 8))
2095
	return PrintWarningMessage ("umask: bad mask (%s)", cp);
2096
 
2097
#if (__OS2__)
2098
    else if (umask ((int)value) == 0xffff)
2099
	return PrintWarningMessage ("umask: bad value (%s)", cp);
2100
#else
2101
    umask ((int)value);
2102
#endif
2103
 
2104
    return 0;
2105
}
2106
 
2107
/*
2108
 * Execute an exec command: exec [ arguments ]
2109
 */
2110
 
2111
int	doexec (C_Op *t)
2112
{
2113
    int		i = 0;
2114
    jmp_buf	ex;
2115
    ErrorPoint	OldERP;
2116
 
2117
/* Shift arguments */
2118
 
2119
    do
2120
    {
2121
	t->args[i] = t->args[i + 1];
2122
	i++;
2123
 
2124
    } while (t->args[i] != NOWORD);
2125
 
2126
/* Left the I/O as it is */
2127
 
2128
    if (i == 1)
2129
	return RestoreStandardIO (0, FALSE);
2130
 
2131
    ProcessingEXECCommand = TRUE;
2132
    OldERP = e.ErrorReturnPoint;
2133
 
2134
/* Set execute function recursive level to zero */
2135
 
2136
    Execute_stack_depth = 0;
2137
    t->ioact = (IO_Actions **)NULL;
2138
 
2139
    if (SetErrorPoint (ex) == 0)
2140
	ExecuteParseTree (t, NOPIPE, NOPIPE, EXEC_WITHOUT_FORK);
2141
 
2142
/* Clear the extended file if an interrupt happened */
2143
 
2144
    ClearExtendedLineFile ();
2145
    e.ErrorReturnPoint = OldERP;
2146
    ProcessingEXECCommand = FALSE;
2147
    return 1;
2148
}
2149
 
2150
/*
2151
 * Execute a script in the current shell: . <filename>
2152
 */
2153
 
2154
static int dodot (int argc, char **argv)
2155
{
2156
    int		i;
2157
    char	*sp;
2158
    char	*cp;
2159
    char	*l_path;
2160
    Source	*s;
2161
    FILE	*Fp;
2162
 
2163
    (void)argc;
2164
 
2165
    if ((cp = argv[1]) == NOWORD)
2166
	return 0;
2167
 
2168
/* Get some space */
2169
 
2170
    if ((l_path = AllocateMemoryCell (FFNAME_MAX)) == (char *)NULL)
2171
	return doOutofMemory (".");
2172
 
2173
/* Save the current drive */
2174
 
2175
    sp = ((FindPathCharacter (cp) != (char *)NULL) || IsDriveCharacter (*(cp + 1)))
2176
	  ? null
2177
	  : GetVariableAsString (PathLiteral, FALSE);
2178
 
2179
    do
2180
    {
2181
	sp = BuildNextFullPathName (sp, cp, l_path);
2182
 
2183
	if ((i = OpenForExecution (l_path, (char **)NULL, (int *)NULL)) >= 0)
2184
	{
2185
	    if ((Fp = ReOpenFile (ReMapIOHandler (i),
2186
	    			  sOpenReadMode)) == (FILE *)NULL)
2187
		return PrintWarningMessage ("Cannot remap file");
2188
 
2189
	    (s = pushs (SFILE))->u.file = Fp;
2190
	    s->file = cp;
2191
 
2192
	    RunACommand (s, &argv[1]);
2193
	    S_fclose (Fp, TRUE);
2194
 
2195
	    return (int)GetVariableAsNumeric (StatusVariable);
2196
	}
2197
 
2198
    } while (sp != (char *)NULL);
2199
 
2200
    return PrintWarningMessage (BasicErrorMessage, cp, NotFound);
2201
}
2202
 
2203
/*
2204
 * Read from standard input into a variable list
2205
 *
2206
 * read [-prs] [-u unit] [ variable list ]
2207
 */
2208
 
2209
static int doread (int argc, char **argv)
2210
{
2211
    char	*cp, *op;
2212
    int		i;
2213
    int		Unit = STDIN_FILENO;
2214
    bool	EndOfInputDetected = FALSE;
2215
    int		PreviousCharacter = 0;
2216
    bool	SaveMode = FALSE;
2217
    bool	RawMode = FALSE;
2218
    char	*Prompt = (char *)NULL;
2219
    char	*NewBuffer;
2220
    int		eofc;
2221
 
2222
    if ((NewBuffer = AllocateMemoryCell (LINE_MAX + 2)) == (char *)NULL)
2223
	return doOutofMemory (LIT_read);
2224
 
2225
/* Check for variable name.  If not defined, use $REPLY */
2226
 
2227
    ResetGetOptions ();			/* Reset GetOptions		*/
2228
 
2229
    while ((i = GetOptions (argc, argv, "prsu:", 0)) != EOF)
2230
    {
2231
	switch (i)
2232
	{
2233
	    case 'p':			/* Clean up process		*/
2234
		break;
2235
 
2236
	    case 'r':			/* Raw Mode			*/
2237
		RawMode = TRUE;
2238
		break;
2239
 
2240
	    case 's':			/* Save a command		*/
2241
		SaveMode = TRUE;
2242
		break;
2243
 
2244
	    case 'u':			/* Specify input unit		*/
2245
		if ((Unit = GetUnitNumber (LIT_read)) == -1)
2246
		    return 2;
2247
 
2248
	    default:
2249
		return UsageError ("read [ -prs ] [ -u unit ] [ name?prompt ] [ name ... ]");
2250
	}
2251
    }
2252
 
2253
    argv += OptionIndex;
2254
    argc -= OptionIndex;
2255
 
2256
    if (!argc)
2257
	argv = Reply_Array;
2258
 
2259
/* Get the prompt and write it */
2260
 
2261
    LastUserPrompt = null;
2262
 
2263
    if ((Prompt = strchr (argv[0], '?')) != (char *)NULL)
2264
    {
2265
	*(Prompt++) = 0;
2266
	LastUserPrompt1 = Prompt;
2267
	LastUserPrompt = (char *)NULL;
2268
    }
2269
 
2270
/* Check we have a name */
2271
 
2272
    if (!strlen (argv[0]))
2273
	argv = Reply_Array;
2274
 
2275
/* Check for valid names */
2276
 
2277
    for (i = 0; argv[i] != (char *)NULL; i++)
2278
    {
2279
	if (IsValidVariableName (argv[i]))
2280
	{
2281
	    PrintErrorMessage (BasicErrorMessage, argv[i], LIT_BadID);
2282
	    return 1;
2283
	}
2284
    }
2285
 
2286
/* Clear the history buffer */
2287
 
2288
    FlushHistoryBuffer ();
2289
 
2290
/* Read the line from the device */
2291
 
2292
    if (ReadALine (Unit, Prompt, SaveMode, FALSE, &eofc))
2293
	return 1;
2294
 
2295
    cp = ConsoleLineBuffer;
2296
 
2297
/* For each variable, read the data until a white space is detected */
2298
 
2299
    while (*argv != NOWORD)
2300
    {
2301
 
2302
/* Read in until end of line, file or a field separator is detected */
2303
 
2304
	op = (char *)NULL;
2305
 
2306
	while (!EndOfInputDetected && *cp)
2307
	{
2308
 
2309
/* End of file */
2310
 
2311
	    if (*cp == (char)eofc)
2312
		return 1;
2313
 
2314
/* Check for Newline or IFS character */
2315
 
2316
	    if ((*cp == CHAR_NEW_LINE) ||
2317
		((argv[1] != NOWORD) &&
2318
		 strchr (GetVariableAsString (IFS, FALSE),
2319
			 *cp) != (char *)NULL))
2320
	    {
2321
		if (*cp != CHAR_NEW_LINE)
2322
		     ;
2323
 
2324
		else if ((PreviousCharacter != CHAR_META) || (RawMode))
2325
		    EndOfInputDetected = TRUE;
2326
 
2327
/* Handle continuation line */
2328
 
2329
		else if (ReadALine (Unit, Prompt, SaveMode, TRUE, &eofc))
2330
		    return 1;
2331
 
2332
		else
2333
		{
2334
		    cp = ConsoleLineBuffer;
2335
		    PreviousCharacter = 0;
2336
		    continue;
2337
		}
2338
 
2339
		break;
2340
	    }
2341
 
2342
/* Save the current character */
2343
 
2344
	    if (op == (char *)NULL)
2345
		op = NewBuffer;
2346
 
2347
	    *(op++) = *cp;
2348
	    PreviousCharacter = *(cp++);
2349
	}
2350
 
2351
/* Skip over terminating character */
2352
 
2353
	if (*cp)
2354
	    ++cp;
2355
 
2356
/* Check for null string */
2357
 
2358
	if (op == (char *)NULL)
2359
	    op = null;
2360
 
2361
/* Terminate the string */
2362
 
2363
	else
2364
	{
2365
	    *op = 0;
2366
 
2367
	    if (!strlen (NewBuffer))
2368
		continue;
2369
 
2370
	    else
2371
		op = NewBuffer;
2372
	}
2373
 
2374
/* Save the string value */
2375
 
2376
	SetVariableFromString (*(argv++), op);
2377
    }
2378
 
2379
    ReleaseMemoryCell ((void *)NewBuffer);
2380
 
2381
    return 0;
2382
}
2383
 
2384
/*
2385
 * Read a line from either the console or a file for the read command.
2386
 * The line is returned in the ConsoleLineBuffer.
2387
 */
2388
 
2389
static bool F_LOCAL ReadALine (int  Unit,	/* Unit to read from	*/
2390
			       char *Prompt,	/* User prompt		*/
2391
			       bool SaveMode,	/* Save in history	*/
2392
			       bool Append,	/* Append to history	*/
2393
			       int *eofc)	/* EOF character	*/
2394
{
2395
    int		NumberBytesRead;
2396
    char	*cp;
2397
    int		x;
2398
 
2399
/* Generate the prompt */
2400
 
2401
    if ((Prompt != (char *)NULL) && (!IS_Console (Unit)) &&
2402
	(!IS_TTY (Unit) || (write (Unit, Prompt, strlen (Prompt)) == -1)))
2403
	feputs (Prompt);
2404
 
2405
/* Read the line */
2406
 
2407
    *eofc = 0x1a;
2408
 
2409
    if (IS_Console (Unit))
2410
    {
2411
	*eofc = GetEOFKey ();
2412
 
2413
	if (!GetConsoleInput ())		/* get input	*/
2414
	    strcpy (ConsoleLineBuffer, LIT_NewLine);
2415
    }
2416
 
2417
    else
2418
    {
2419
	NumberBytesRead = 0;
2420
	cp =  ConsoleLineBuffer;
2421
 
2422
	while (NumberBytesRead++ < LINE_MAX)
2423
	{
2424
	    if ((x = read (Unit, cp, 1)) == -1)
2425
		return TRUE;
2426
 
2427
/* EOF detected as first character on line */
2428
 
2429
	    if ((NumberBytesRead == 1) && ((!x) || (*cp == (char)*eofc)))
2430
		return TRUE;
2431
 
2432
/* End read if NEWLINE or EOF character detected */
2433
 
2434
	    if ((!x) || (*cp == CHAR_NEW_LINE) || (*cp == (char)*eofc))
2435
		break;
2436
 
2437
	    cp++;
2438
	}
2439
 
2440
/* Terminate the line the same in all cases */
2441
 
2442
	*(cp++) = CHAR_NEW_LINE;
2443
	*cp = 0;
2444
    }
2445
 
2446
/* Save the history.  Clean it up first */
2447
 
2448
    if (SaveMode)
2449
    {
2450
	char	save;
2451
 
2452
	save = CleanUpBuffer (strlen (ConsoleLineBuffer), ConsoleLineBuffer,
2453
			      *eofc);
2454
	AddHistory (Append);
2455
	ConsoleLineBuffer[strlen(ConsoleLineBuffer)] = save;
2456
    }
2457
 
2458
    return FALSE;
2459
}
2460
 
2461
/*
2462
 * Evaluate an expression: eval <expression>
2463
 */
2464
 
2465
static int doeval (int argc, char **argv)
2466
{
2467
    Source	*s;
2468
 
2469
    (void)argc;
2470
 
2471
    (s = pushs (SWORDS))->u.strv = argv + 1;
2472
    return RunACommand (s, (char **)NULL);
2473
}
2474
 
2475
/*
2476
 * Map signals.  
2477
 *
2478
 * Numeric values are assumed to be UNIX - map to appropriate DOS signal.
2479
 * Character values are just mapped to the DOS signal
2480
 */
2481
 
2482
static struct TrapSignalList * F_LOCAL LookupSignalName (char *name)
2483
{
2484
    static struct TrapSignalList	Numeric = {NULL, 0};
2485
    int				n;
2486
 
2487
    if (isdigit (*name))
2488
    {
2489
	if (((n = GetNumericValue (name)) < 0) || (n >= MAX_SIG_MAP))
2490
	    return (struct TrapSignalList *)NULL;
2491
 
2492
#if (OS_TYPE == OS_UNIX)
2493
	Numeric.signo = n;
2494
#else
2495
	Numeric.signo = UnixToDosSignals [n];
2496
#endif
2497
	return &Numeric;
2498
    }
2499
 
2500
/* Check the character names */
2501
 
2502
    for (n = 0; n < MAX_TRAP_SIGNALS; n++)
2503
    {
2504
        if (stricmp (name, TrapSignalList[n].name) == 0)
2505
	    return &TrapSignalList[n];
2506
    }
2507
 
2508
    return (struct TrapSignalList *)NULL;
2509
}
2510
 
2511
/*
2512
 * Execute a trap: trap [ number... ] [ command ]
2513
 */
2514
 
2515
static int dotrap (int argc, char **argv)
2516
{
2517
    int				i;
2518
    bool			SetSignal;
2519
    char			tval[10];
2520
    char			*cp;
2521
    struct TrapSignalList	*SignalInfo;
2522
    void                        (_SIGDECL *NewSignalFunc)(int);
2523
 
2524
    if ((argc == 2) && (strcmp (argv[1], "-l") == 0))
2525
    {
2526
	for (i = 3; i < MAX_TRAP_SIGNALS; i++)
2527
	    puts (TrapSignalList[i].name);
2528
 
2529
	return 0;
2530
    }
2531
 
2532
/* Display active traps ? */
2533
 
2534
    if (argc < 2)
2535
    {
2536
 
2537
/* Display trap - look up each trap and print those we find */
2538
 
2539
	for (i = 0; i < NSIG; i++)
2540
	{
2541
	    sprintf (tval, "~%d", i);
2542
 
2543
	    if ((cp = GetVariableAsString (tval, FALSE)) != null)
2544
		printf ("%u: %s\n", i, cp);
2545
	}
2546
 
2547
	if ((cp = GetVariableAsString (Trap_DEBUG, FALSE)) != null)
2548
	    printf (BasicErrorMessage, &Trap_DEBUG[1], cp);
2549
 
2550
	if ((cp = GetVariableAsString (Trap_ERR, FALSE)) != null)
2551
	    printf (BasicErrorMessage, &Trap_ERR[1], cp);
2552
 
2553
	return 0;
2554
    }
2555
 
2556
/* Check to see if signal re-set */
2557
 
2558
    SetSignal = C2bool(LookupSignalName (argv[1]) ==
2559
				(struct TrapSignalList *)NULL);
2560
 
2561
    for (i = SetSignal ? 2 : 1; argv[i] != NOWORD; ++i)
2562
    {
2563
	if ((SignalInfo = LookupSignalName (argv[i]))
2564
			== (struct TrapSignalList *)NULL)
2565
	    return PrintWarningMessage ("trap: bad signal number - %s",
2566
	    				argv[i]);
2567
 
2568
/* Check for no UNIX to DOS mapping */
2569
 
2570
	if (SignalInfo->signo == SIG_NO_MAP)
2571
	{
2572
	    if (!FL_TEST (FLAG_WARNING))
2573
		PrintWarningMessage ("trap: No UNIX to DOS signal map for %s",
2574
				     argv[i]);
2575
 
2576
	    continue;
2577
	}
2578
 
2579
/* Check for ERR or DEBUG.  cp points to the variable name */
2580
 
2581
	if (SignalInfo->signo == SIG_SPECIAL)
2582
	    cp = (SignalInfo->name) - 1;
2583
 
2584
/* Generate the variable name for a numeric value */
2585
 
2586
	else
2587
	    sprintf (cp = tval, "~%d", SignalInfo->signo);
2588
 
2589
/* Remove the old processing */
2590
 
2591
	RemoveVariable (cp, 0);
2592
 
2593
/* Default to new function of ignore! */
2594
 
2595
	NewSignalFunc = SIG_DFL;
2596
 
2597
/* Re-define signal processing */
2598
 
2599
	if (SetSignal)
2600
	{
2601
	    if (*argv[1] != 0)
2602
	    {
2603
		SetVariableFromString (cp, argv[1]);
2604
		NewSignalFunc = TerminateSignalled;
2605
	    }
2606
 
2607
	    else
2608
		NewSignalFunc = SIG_IGN;
2609
	}
2610
 
2611
/* Clear signal processing */
2612
 
2613
	else if (InteractiveFlag)
2614
	{
2615
	    if (SignalInfo->signo == SIGINT)
2616
		NewSignalFunc = InterruptSignalled;
2617
 
2618
#ifdef SIGQUIT
2619
	    else 
2620
		NewSignalFunc = (SignalInfo->signo == SIGQUIT)
2621
					? SIG_IGN : SIG_DFL;
2622
#endif
2623
	}
2624
 
2625
/* Set up new signal function */
2626
 
2627
	if (SignalInfo->signo > 0)
2628
	    signal (SignalInfo->signo, NewSignalFunc);
2629
 
2630
    }
2631
 
2632
    return 0;
2633
}
2634
 
2635
/*
2636
 * BREAK and CONTINUE processing: break/continue [ n ]
2637
 */
2638
 
2639
static int dobreak (int argc, char **argv)
2640
{
2641
    if (argc > 2)
2642
	return UsageError ("break [ count ]");
2643
 
2644
    return BreakContinueProcessing (argv[1], BC_BREAK);
2645
}
2646
 
2647
static int docontinue (int argc, char **argv)
2648
{
2649
    if (argc > 2)
2650
	return UsageError ("continue [ count ]");
2651
 
2652
    return BreakContinueProcessing (argv[1], BC_CONTINUE);
2653
}
2654
 
2655
static int F_LOCAL	BreakContinueProcessing (char *NumberOfLevels,
2656
						 int Type)
2657
{
2658
    Break_C	*Break_Loc;
2659
    int		LevelNumber;
2660
    char	*cType = (Type == BC_BREAK) ? LIT_break : LIT_continue;
2661
 
2662
 
2663
    LevelNumber = (NumberOfLevels == (char *)NULL)
2664
			? 1 : GetNumericValue (NumberOfLevels);
2665
 
2666
    if (LevelNumber < 0)
2667
	return PrintWarningMessage (LIT_Emsg, cType, "bad level number",
2668
				    NumberOfLevels);
2669
 
2670
/* If level is invalid - clear all levels */
2671
 
2672
    if (LevelNumber <= 0)
2673
	LevelNumber = 999;
2674
 
2675
/* Move down the stack */
2676
 
2677
    do
2678
    {
2679
	if ((Break_Loc = Break_List) == (Break_C *)NULL)
2680
	    break;
2681
 
2682
	Break_List = Break_Loc->NextExitLevel;
2683
 
2684
    } while (--LevelNumber);
2685
 
2686
/* Check level */
2687
 
2688
    if (LevelNumber)
2689
	return PrintWarningMessage (BasicErrorMessage, cType, "bad level");
2690
 
2691
    longjmp (Break_Loc->CurrentReturnPoint, Type);
2692
 
2693
/* NOTREACHED */
2694
    return 1;
2695
}
2696
 
2697
/*
2698
 * Exit function: exit [ status ]
2699
 */
2700
 
2701
static int doexit (int argc, char **argv)
2702
{
2703
    Break_C	*SShell_Loc = SShell_List;
2704
 
2705
    ProcessingEXECCommand = FALSE;
2706
 
2707
    if (argc > 2)
2708
	return UsageError ("exit [ status ]");
2709
 
2710
/* Set up error codes */
2711
 
2712
    ExitStatus = (argv[1] != NOWORD) ? GetNumericValue (argv[1]) : 0;
2713
 
2714
    SetVariableFromNumeric (StatusVariable, (long)abs (ExitStatus));
2715
 
2716
/* Are we in a subshell.  Yes - do a longjmp instead of an exit */
2717
 
2718
    if (SShell_Loc != (Break_C *)NULL)
2719
    {
2720
	SShell_List = SShell_Loc->NextExitLevel;
2721
	longjmp (SShell_Loc->CurrentReturnPoint, ExitStatus);
2722
    }
2723
 
2724
/*
2725
 * Check for active jobs
2726
 */
2727
 
2728
#if (OS_TYPE != OS_DOS)
2729
    if (!ExitWithJobsActive)
2730
    {
2731
	if (NumberOfActiveJobs () && InteractiveFlag)
2732
	{
2733
	    feputs ("You have running jobs.\n");
2734
	    ExitWithJobsActive = TRUE;
2735
	    return 0;
2736
	}
2737
    }
2738
#endif
2739
 
2740
    ExitTheShell (FALSE);
2741
    return ExitStatus;
2742
}
2743
 
2744
/*
2745
 * Function return: return [ status ]
2746
 *
2747
 * Set exit value and return via a long jmp
2748
 */
2749
 
2750
static int doreturn (int argc, char **argv)
2751
{
2752
    Break_C	*Return_Loc = Return_List;
2753
    int		Retval = 0;
2754
 
2755
    if ((argc > 2) || 
2756
	((argc == 2) && ((Retval = GetNumericValue (argv[1])) == -1)))
2757
	return UsageError (ReturnUsage);
2758
 
2759
    SetVariableFromNumeric (StatusVariable, (long) abs (Retval));
2760
 
2761
/* If the return address is defined - return to it.  Otherwise, return
2762
 * the value
2763
 */
2764
 
2765
    if (Return_Loc != (Break_C *)NULL)
2766
    {
2767
	Return_List = Return_Loc->NextExitLevel;
2768
	longjmp (Return_Loc->CurrentReturnPoint, 1);
2769
    }
2770
 
2771
    return Retval;
2772
}
2773
 
2774
/*
2775
 * Set function:  set [ -/+flags ] [ parameters... ]
2776
 */
2777
 
2778
static int doset (int argc, char **argv)
2779
{
2780
    int			i;
2781
 
2782
/* Display ? */
2783
 
2784
    if (argc < 2)
2785
	return ListAllVariables (0xffff, TRUE);
2786
 
2787
/* Set/Unset a flag ? */
2788
 
2789
    ResetGetOptions ();			/* Reset GetOptions		*/
2790
 
2791
    while ((i = GetOptions (argc, argv, "VMA:abcdefghijklmno:pqrstuvwxyz",
2792
			    GETOPT_PLUS | GETOPT_AMISSING)) != EOF)
2793
    {
2794
	switch (i)
2795
	{
2796
	    case '?':			/* Unknown */
2797
		if (BadOptionValue != 'o')
2798
		    return UsageError ("set [ [-|+][switches] ] [ [-|+]o option ] [ parameter=value ] args");
2799
 
2800
		return PrintOptionSettings ();
2801
 
2802
	    case 'r':
2803
		return PrintWarningMessage ("set: r switch cannot be changed");
2804
 
2805
	    case 'o':
2806
		if ((!ChangeInitialisationValue (OptionArgument,
2807
					        OptionStart == '-')) &&
2808
		    (!ChangeOptionValue (OptionArgument,
2809
					 (bool)(OptionStart == '-'))))
2810
		    return PrintWarningMessage ("set: -o bad option (%s)",
2811
						OptionArgument);
2812
 
2813
		break;
2814
 
2815
	    case 'A':
2816
		if (OptionStart == '-')		/* If -, remove all values */
2817
		    RemoveVariable (OptionArgument, -1);
2818
 
2819
		i = 0;
2820
 
2821
		while (argv[OptionIndex] != NOWORD)
2822
		    SetVariableArrayFromString (OptionArgument, i++,
2823
						argv[OptionIndex++]);
2824
 
2825
		return 0;
2826
 
2827
	    case 'M':
2828
		if (OptionStart == '-')		/* If -, remove all values */
2829
		    ShellGlobalFlags |= FLAGS_MSDOS_FORMAT;
2830
 
2831
		else
2832
		    ShellGlobalFlags &= ~FLAGS_MSDOS_FORMAT;
2833
 
2834
	        break;
2835
 
2836
	    case 'V':
2837
		SetVerifyStatus (C2bool (OptionStart == '-'));
2838
		break;
2839
 
2840
	    default:
2841
		if ((i == 'e') && InteractiveFlag)
2842
		    continue;
2843
 
2844
		SetClearFlag (i, (bool)(OptionStart == '-'));
2845
	}
2846
    }
2847
 
2848
    SetShellSwitches ();
2849
 
2850
/* Check for --, ++, - and +, which we skip */
2851
 
2852
    if ((OptionIndex != argc) &&
2853
	((!strcmp (argv[OptionIndex], DoubleHypen))		||
2854
	 (!strcmp (argv[OptionIndex], ShellOptionsVariable))	||
2855
	 (!strcmp (argv[OptionIndex], "+"))))
2856
	OptionIndex++;
2857
 
2858
/* Set up parameters ? */
2859
 
2860
    if (OptionIndex != argc)
2861
    {
2862
	ResetGetoptsValues (TRUE);
2863
	return SetUpNewParameterVariables (argv, OptionIndex, argc, "set");
2864
    }
2865
 
2866
    else
2867
	return 0;
2868
}
2869
 
2870
 
2871
/*
2872
 * Print the list of functions: functions [ names ]
2873
 */
2874
 
2875
static int dofunctions (int argc, char **argv)
2876
{
2877
    FunctionList	*fp;
2878
    int			i;
2879
 
2880
    if (argc < 2)
2881
	return PrintAllFunctions ();
2882
 
2883
    for (i = 1; argv[i] != NOWORD; ++i)
2884
    {
2885
	if ((fp = LookUpFunction (argv[i], TRUE)) != (FunctionList *)NULL)
2886
	    PrintFunction (fp->tree, PF_MODE_NORMAL);
2887
 
2888
	else
2889
	    PrintWarningMessage ("functions: %s is not a function", argv[i]);
2890
    }
2891
 
2892
    return 0;
2893
}
2894
 
2895
/*
2896
 * History functions - history [-ieds]
2897
 */
2898
 
2899
static int dohistory (int argc, char **argv)
2900
{
2901
    int		i;
2902
    int		Start;
2903
    long	value;
2904
 
2905
    if (!InteractiveFlag)
2906
	return 1;
2907
 
2908
    if (argc < 2)
2909
        Start = GetLastHistoryEvent () + 1;
2910
 
2911
/*
2912
 * Check for options
2913
 */
2914
 
2915
    else if (**(argv + 1) == CHAR_SWITCH)
2916
    {
2917
	ResetGetOptions ();		/* Reset GetOptions		*/
2918
 
2919
	while ((i = GetOptions (argc, argv, "sidel", 0)) != EOF)
2920
	{
2921
	    switch (i)
2922
	    {
2923
		case 's':
2924
		    DumpHistory ();
2925
		    break;
2926
 
2927
		case 'i':
2928
		    ClearHistory ();
2929
		    break;
2930
 
2931
		case 'l':
2932
		    LoadHistory ();
2933
		    break;
2934
 
2935
		case 'd':
2936
		    HistoryEnabled = FALSE;
2937
		    break;
2938
 
2939
		case 'e':
2940
		    HistoryEnabled = TRUE;
2941
		    break;
2942
 
2943
		default:
2944
		    return UsageError (HistoryUsage);
2945
	    }
2946
	}
2947
 
2948
	return (OptionIndex != argc) ? UsageError (HistoryUsage) : 0;
2949
    }
2950
 
2951
/* Check for number of display */
2952
 
2953
    else if ((argc == 2) && ConvertNumericValue (*(argv + 1), &value, 0))
2954
	Start = (int)value + 1;
2955
 
2956
    else
2957
	return UsageError (HistoryUsage);
2958
 
2959
/*
2960
 * Display history
2961
 */
2962
 
2963
    if ((i = (GetLastHistoryEvent () + 1) - Start) < 0)
2964
	i = 0;
2965
 
2966
    PrintHistory (FALSE, TRUE, i, GetLastHistoryEvent () + 1, stdout);
2967
    return 0;
2968
}
2969
 
2970
/*
2971
 * Type function: type [ command ]
2972
 *
2973
 * For each name, indicate how it would be interpreted
2974
 */
2975
 
2976
static int dowhence (int argc, char **argv)
2977
{
2978
    char		*cp;
2979
    int			n;			/* Argument count	*/
2980
    int			inb;			/* Inbuilt function	*/
2981
    bool		v_flag;
2982
    bool		p_flag = FALSE;
2983
    bool		t_flag = FALSE;
2984
    char		*l_path;
2985
    AliasList		*al;
2986
 
2987
/* Get some memory for the buffer */
2988
 
2989
    if ((l_path = AllocateMemoryCell (FFNAME_MAX + 4)) == (char *)NULL)
2990
	return doOutofMemory (*argv);
2991
 
2992
    v_flag = (bool)(strcmp (*argv, LIT_type) == 0);
2993
 
2994
    ResetGetOptions ();			/* Reset GetOptions		*/
2995
 
2996
    while ((n = GetOptions (argc, argv, "pvt", 0)) != EOF)
2997
    {
2998
	switch (n)
2999
	{
3000
	    case 'v':	v_flag = TRUE;	break;
3001
	    case 'p':	p_flag = TRUE;	break;
3002
	    case 't':	t_flag = TRUE;	break;
3003
 
3004
	    default:
3005
		return UsageError (WhenceUsage);
3006
	}
3007
    }
3008
 
3009
/* Process each parameter */
3010
 
3011
    while ((cp = argv[OptionIndex++]) != NOWORD)
3012
    {
3013
 
3014
/* Check for alias */
3015
 
3016
	if ((al = LookUpAlias (cp, FALSE)) != (AliasList *)NULL)
3017
	{
3018
	    if (v_flag)
3019
		printf ("%s is %s alias for %s", cp,
3020
			(al->AFlags & ALIAS_TRACKED) ? "a tracked"
3021
						     : "an", al->value);
3022
 
3023
	    else
3024
		foputs (al->value);
3025
	}
3026
 
3027
 
3028
/* Check for currently use inbuilt version */
3029
 
3030
	else if (!p_flag && IsCommandBuiltIn (cp, &inb) && (inb & BLT_CURRENT))
3031
	    WhenceLocation (v_flag, cp, ShellInternalCommand);
3032
 
3033
/* Check for a function */
3034
 
3035
	else if (!p_flag &&
3036
		 (LookUpFunction (cp, FALSE) != (FunctionList *)NULL))
3037
	    WhenceLocation (v_flag, cp, "is a function");
3038
 
3039
/* Scan the path for an executable */
3040
 
3041
	else if (FindLocationOfExecutable (l_path, cp) != EXTENSION_NOT_FOUND)
3042
	{
3043
	    PATH_TO_LOWER_CASE (l_path);
3044
 
3045
	    if (v_flag)
3046
		printf ("%s is ", cp);
3047
 
3048
	    foputs (PATH_TO_UNIX (l_path));
3049
 
3050
	    if (t_flag)
3051
	        WhenceType (l_path);
3052
	}
3053
 
3054
/* If not found, check for inbuilt version */
3055
 
3056
	else if (!p_flag && (IsCommandBuiltIn (cp, &inb)))
3057
	    WhenceLocation (v_flag, cp, ShellInternalCommand);
3058
 
3059
	else if (!p_flag && LookUpSymbol (cp))
3060
	    WhenceLocation (v_flag, cp, "is a shell keyword");
3061
 
3062
	else if (v_flag)
3063
	{
3064
	    PrintWarningMessage (LIT_2Strings, cp, NotFound);
3065
	    continue;
3066
	}
3067
 
3068
	fputchar (CHAR_NEW_LINE);
3069
    }
3070
 
3071
    return 0;
3072
}
3073
 
3074
/*
3075
 * Output file type
3076
 */
3077
 
3078
static char	 *ExeType_Error[] = {
3079
    "Not known",
3080
    "Bad image",
3081
    "Not executable",
3082
    "File not found"
3083
};
3084
 
3085
static char	*ExeType_Dos[] = {
3086
    "DOS Character",
3087
    "Windows 16-bit",
3088
    "Watcom 32 bit",
3089
    "OS/2 Bound"
3090
};
3091
 
3092
static char	*ExeType_OS2[] = {
3093
   "Not PM compatible",
3094
   "PM compatible",
3095
   "PM"
3096
};
3097
 
3098
static char	*ExeType_NT[] = {
3099
    "Native",
3100
    "Windows GUI",
3101
    "Windows CUI",
3102
    "OS2",
3103
    "POSIX"
3104
};
3105
 
3106
static void F_LOCAL WhenceType (const char *path)
3107
{
3108
    unsigned long type = QueryApplicationType (path);
3109
 
3110
    foputs ("  [");
3111
 
3112
    if (type & EXETYPE_ERROR)
3113
	foputs (ExeType_Error [type - 1]);
3114
 
3115
    else if (type & EXETYPE_DOS)
3116
	foputs (ExeType_Dos [(type >> 4) - 1]);
3117
 
3118
    else if (type & EXETYPE_OS2)
3119
	printf ("OS2 %dbit %s", (type & EXETYPE_OS2_32) ? 32 : 16,
3120
		 ExeType_OS2 [((type & EXETYPE_OS2_TYPE) >> 8) - 1]);
3121
 
3122
    else if (type & EXETYPE_NT)
3123
	printf ("Win NT %s subsystem", ExeType_NT [(type >> 12) - 1]);
3124
 
3125
    fputchar (']');
3126
}
3127
 
3128
 
3129
void WhenceTypeDebug (unsigned long type)
3130
{
3131
    fprintf(stderr, " Type: %04x = ", type );
3132
 
3133
    if (type & EXETYPE_ERROR)
3134
	fprintf (stderr, ExeType_Error [type - 1]);
3135
 
3136
    else if (type & EXETYPE_DOS)
3137
	fprintf (stderr, ExeType_Dos [(type >> 4) - 1]);
3138
 
3139
    else if (type & EXETYPE_OS2)
3140
	fprintf (stderr, "OS2 %dbit %s", (type & EXETYPE_OS2_32) ? 32 : 16,
3141
		 ExeType_OS2 [((type & EXETYPE_OS2_TYPE) >> 8) - 1]);
3142
 
3143
    else if (type & EXETYPE_NT)
3144
	fprintf (stderr, "Win NT %s subsystem", ExeType_NT [(type >> 12) - 1]);
3145
 
3146
    fprintf(stderr, "\n");
3147
}
3148
 
3149
/*
3150
 * Output location
3151
 */
3152
 
3153
static void F_LOCAL WhenceLocation (bool v_flag, const char *cp, const char *mes)
3154
{
3155
    foputs (cp);
3156
 
3157
    if (v_flag)
3158
	printf (" %s", mes);
3159
}
3160
 
3161
/*
3162
 * Table of internal commands.  Note that this table is sort in alphabetic
3163
 * order.
3164
 */
3165
 
3166
static struct builtin	builtin[] = {
3167
	{ "((",		dolet,		(BLT_ALWAYS | BLT_CURRENT) },
3168
	{ ".",		dodot,		(BLT_ALWAYS | BLT_CURRENT |
3169
					 BLT_CENVIRON) },
3170
	{ ":",		dolabel,	(BLT_ALWAYS | BLT_CURRENT |
3171
					 BLT_CENVIRON) },
3172
	{ "[",		dotest,		BLT_CURRENT },
3173
	{ LIT_Test,	dotest,		(BLT_ALWAYS | BLT_CURRENT |
3174
					 BLT_CENVIRON | BLT_NOGLOB) },
3175
	{ LIT_alias,	doalias,	(BLT_ALWAYS | BLT_CURRENT |
3176
					 BLT_CENVIRON | BLT_NOGLOB |
3177
					 BLT_NOWORDS) },
3178
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
3179
	{ "bind",	dobind,		(BLT_CURRENT | BLT_CENVIRON) },
3180
#endif
3181
	{ LIT_break,	dobreak,	(BLT_CURRENT | BLT_CENVIRON) },
3182
	{ LIT_builtin,	dobuiltin,	(BLT_ALWAYS | BLT_CURRENT) },
3183
	{ "cd",		dochdir,	BLT_CURRENT },
3184
	{ "chdir",	dochdir,	(BLT_ALWAYS | BLT_CURRENT) },
3185
	{ LIT_continue,	docontinue,	(BLT_CURRENT | BLT_CENVIRON) },
3186
 
3187
#if (OS_TYPE != OS_DOS) 
3188
	{ "detach",	dodetach,	(BLT_ALWAYS | BLT_CURRENT) },
3189
#endif
3190
 
3191
	{ "echo",	doecho,		BLT_CURRENT },
3192
	{ "eval",	doeval,		(BLT_CURRENT | BLT_CENVIRON) },
3193
	{ LIT_exec,	(int (*)(int, char **)) doexec,
3194
					(BLT_CURRENT | BLT_CENVIRON) },
3195
	{ LIT_exit,	doexit,		(BLT_CURRENT | BLT_CENVIRON) },
3196
	{ LIT_export,	doexport,	(BLT_CURRENT | BLT_CENVIRON |
3197
					 BLT_NOGLOB | BLT_NOWORDS) },
3198
 
3199
#if (OS_TYPE == OS_OS2)
3200
	{ "extproc",	dolabel,	(BLT_CURRENT | BLT_CENVIRON) },
3201
#endif
3202
 
3203
	{ "false",	dofalse,	BLT_CURRENT },
3204
	{ "fc",		dofc,		BLT_CURRENT },
3205
	{ "functions",	dofunctions,	(BLT_ALWAYS | BLT_CURRENT) },
3206
	{ "getopts",	dogetopts,	BLT_CURRENT },
3207
	{ LIT_history,	dohistory,	BLT_CURRENT },
3208
 
3209
#if (OS_TYPE != OS_DOS) 
3210
	{ "jobs",	dojobs,		BLT_CURRENT },
3211
	{ "kill",	dokill,		BLT_CURRENT },
3212
#endif
3213
 
3214
	{ "let",	dolet,		BLT_CURRENT },
3215
	{ "msdos",	domsdos,	BLT_CURRENT },
3216
	{ LIT_print,	doecho,		BLT_CURRENT },
3217
	{ "pwd",	dopwd,		BLT_CURRENT },
3218
	{ LIT_read,	doread,		BLT_CURRENT },
3219
	{ "readonly",	doreadonly,	(BLT_CURRENT | BLT_CENVIRON |
3220
					 BLT_NOGLOB | BLT_NOWORDS) },
3221
	{ "return",	doreturn,	(BLT_CURRENT | BLT_CENVIRON) },
3222
	{ "set",	doset,		BLT_CURRENT },
3223
	{ "shellinfo",	doshellinfo,	BLT_CURRENT },
3224
	{ LIT_shift,	doshift,	(BLT_CURRENT | BLT_CENVIRON) },
3225
 
3226
#if (OS_TYPE == OS_OS2)
3227
	{ "start",	dostart,	BLT_CURRENT },
3228
#endif
3229
 
3230
	{ "swap",	doswap,		BLT_CURRENT },
3231
	{ "test",	dotest,		BLT_CURRENT },
3232
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32) && !defined (__WATCOMC__)
3233
	{ "times",	dotimes,	BLT_CURRENT },
3234
#endif
3235
#if (OS_TYPE == OS_NT) || (OS_TYPE == OS_UNIX)
3236
	{ "times",	dotimes,	BLT_CURRENT },
3237
#endif
3238
	{ "trap",	dotrap,		(BLT_CURRENT | BLT_CENVIRON) },
3239
	{ "true",	dolabel,	BLT_CURRENT },
3240
	{ LIT_type,	dowhence,	BLT_CURRENT },
3241
	{ "typeset",	dotypeset,	(BLT_CURRENT | BLT_CENVIRON |
3242
					 BLT_NOGLOB | BLT_NOWORDS) },
3243
	{ "umask",	doumask,	BLT_CURRENT },
3244
	{ LIT_unalias,	dounalias,	(BLT_ALWAYS | BLT_CURRENT) },
3245
	{ LIT_unfunction,
3246
			dounset,	BLT_CURRENT },
3247
	{ "unset",	dounset,	BLT_CURRENT },
3248
	{ "ver",	dover,		BLT_CURRENT },
3249
 
3250
#if (OS_TYPE != OS_DOS)
3251
	{ "wait",	dowait,		BLT_CURRENT },
3252
#endif
3253
 
3254
	{ "whence",	dowhence,	BLT_CURRENT },
3255
	{ (char *)NULL,	(int (*)(int, char **))NULL,	0 }
3256
};
3257
 
3258
/*
3259
 * Look up a built in command
3260
 */
3261
 
3262
int (*IsCommandBuiltIn (char *s, int *b))(int, char **)
3263
{
3264
    struct builtin	*bp;
3265
    int			res;
3266
 
3267
    *b = 0;
3268
 
3269
/* Check for change drive */
3270
 
3271
    if ((strlen (s) == 2) && isalpha (*s) && IsDriveCharacter (*(s + 1)))
3272
    {
3273
	*b = BLT_ALWAYS | BLT_CURRENT;
3274
        return (int (*)(int, char **)) dodrive;
3275
    }
3276
 
3277
/* Search for command */
3278
 
3279
    for (bp = builtin; bp->command != (char *)NULL; bp++)
3280
    {
3281
	if ((res = NOCASE_COMPARE (bp->command, s)) >= 0)
3282
	{
3283
	    if (res != 0)
3284
	    {
3285
		if (!isalpha (*(bp->command)))
3286
		    continue;
3287
 
3288
	        break;
3289
	    }
3290
 
3291
	    *b = bp->mode;
3292
	    return bp->fn;
3293
	}
3294
    }
3295
 
3296
    return (int (*)(int, char **))NULL;
3297
}
3298
 
3299
/*
3300
 * Builtin - either list builtins or execute it
3301
 *
3302
 * builtin [-asd] [ names ]
3303
 */
3304
 
3305
static int dobuiltin (int argc, char **argv)
3306
{
3307
    struct builtin	*bp;
3308
    int			(*shcom)(int, char **) = (int (*)(int, char **))NULL;
3309
    int			ReturnValue = 0;
3310
    char		*carg;
3311
    int			mode;
3312
    int			action = -1;
3313
    int			i;
3314
 
3315
    if (argc < 2)
3316
    {
3317
	for (bp = builtin; bp->command != (char *)NULL; bp++)
3318
	    printf (LIT_3Strings, LIT_builtin, bp->command,
3319
		      (bp->mode & BLT_CURRENT) ? " - preferred" : "");
3320
	return 0;
3321
    }
3322
 
3323
/* Check for changing options */
3324
 
3325
    ResetGetOptions ();			/* Reset GetOptions		*/
3326
 
3327
    while ((i = GetOptions (argc, argv, "sad", 0)) != EOF)
3328
    {
3329
	switch (i)
3330
	{
3331
	    case 's':	action = 0;	break;
3332
	    case 'a':	action = 1;	break;
3333
	    case 'd':	action = 2;	break;
3334
 
3335
	    default:
3336
		return UsageError (BuiltinUsage);
3337
	}
3338
    }
3339
 
3340
/* Check to see if we know about the builtin version */
3341
 
3342
    if (action == -1)
3343
    {
3344
	if ((shcom = IsCommandBuiltIn (argv[1], &mode))
3345
		   == (int (*)(int, char **))NULL)
3346
	{
3347
	    printf (BasicErrorMessage, argv[1], NotBuiltinCommand);
3348
	    return 1;
3349
	}
3350
 
3351
/* Yes - so execute the builtin version.  Set up the word list correctly */
3352
 
3353
	argv++;
3354
	ReturnValue = (*shcom)(CountNumberArguments (argv), argv);
3355
	argv--;
3356
	return ReturnValue;
3357
    }
3358
 
3359
/* Execute the requested functions against the builtin commands */
3360
 
3361
    while ((carg = argv[OptionIndex++]) != NOWORD)
3362
    {
3363
	for (bp = builtin;
3364
	    (bp->command != (char *)NULL) && (NOCASE_COMPARE (bp->command, carg) != 0);
3365
	    bp++)
3366
	    continue;
3367
 
3368
/* Command is not builtin */
3369
 
3370
	if (bp->command == (char *)NULL)
3371
	{
3372
	    printf (BasicErrorMessage, carg, NotBuiltinCommand);
3373
	    ReturnValue = 1;
3374
	    continue;
3375
	}
3376
 
3377
/* Update on the action */
3378
 
3379
	switch (action)
3380
	{
3381
	    case 0:
3382
		printf (BasicErrorMessage, carg, (bp->mode & BLT_CURRENT)
3383
						    ? LIT_builtin : "external");
3384
		break;
3385
 
3386
	    case 1:
3387
		bp->mode |= BLT_CURRENT;
3388
		break;
3389
 
3390
	    case 2:
3391
		if (bp->mode & BLT_ALWAYS)
3392
		    printf (BasicErrorMessage, carg, "always builtin");
3393
 
3394
		else
3395
		    bp->mode &= ~BLT_CURRENT;
3396
 
3397
		break;
3398
	}
3399
    }
3400
 
3401
    return ReturnValue;
3402
}
3403
 
3404
/*
3405
 * Report Usage error
3406
 */
3407
 
3408
static int F_LOCAL	UsageError (char *string)
3409
{
3410
    return PrintWarningMessage ("Usage: %s", string) + 1;
3411
}
3412
 
3413
/*
3414
 * Alias command: alias [ -t] [ name [=commands] ]...
3415
 */
3416
 
3417
static int doalias (int argc, char **argv)
3418
{
3419
    int			ReturnValue = 0;
3420
    int			i = 1;
3421
    bool		tracked = FALSE;
3422
    char		*path = (char *)NULL;
3423
    char		*cp;
3424
 
3425
/* Check for tracked aliases */
3426
 
3427
    if ((argc > 1) && (strcmp (argv[1], "-t") == 0))
3428
    {
3429
	++i;
3430
	tracked = TRUE;
3431
    }
3432
 
3433
/* List only? */
3434
 
3435
    if (argc <= i)
3436
	return PrintAllAlias (tracked);
3437
 
3438
/* Set them up or print them */
3439
 
3440
    while (i < argc)
3441
    {
3442
 
3443
/* Not tracked - either set alias value if there is an equals or display
3444
 * the alias value
3445
 */
3446
 
3447
	if (!tracked)
3448
	{
3449
	    if ((cp = strchr (argv[i], '=')) != (char *)NULL)
3450
		*(cp++) = 0;
3451
 
3452
/* Check for valid name */
3453
 
3454
	    if (!IsValidAliasName (argv[i], TRUE))
3455
		return PrintWarningMessage (LIT_Emsg, LIT_alias, NotValidAlias,
3456
					    argv[i]);
3457
 
3458
/* Save it if appropriate */
3459
 
3460
	    if (cp != (char *)NULL)
3461
	    {
3462
		if (!SaveAlias (argv[i], cp, tracked))
3463
		    ReturnValue = 1;
3464
	    }
3465
 
3466
/* Print it */
3467
 
3468
	    else if (LookUpAlias (argv[i], FALSE) == (AliasList *)NULL)
3469
	    {
3470
		PrintWarningMessage (NotAnAlias, LIT_alias, argv[i]);
3471
		ReturnValue = 1;
3472
	    }
3473
 
3474
	    else
3475
		PrintAlias (argv[i]);
3476
	}
3477
 
3478
/* Set up tracked alias */
3479
 
3480
	else if (!IsValidAliasName (argv[i], TRUE))
3481
	    return PrintWarningMessage (LIT_Emsg, LIT_alias, NotValidAlias,
3482
					argv[i]);
3483
 
3484
	else if ((path == (char *)NULL) &&
3485
		 ((path = AllocateMemoryCell (FFNAME_MAX + 4)) == (char *)NULL))
3486
	    return doOutofMemory (*argv);
3487
 
3488
/* Save the new path for the alias */
3489
 
3490
	else if (SaveAlias (argv[i],
3491
			    (FindLocationOfExecutable (path, argv[i])
3492
				!= EXTENSION_NOT_FOUND) ? path : null, tracked))
3493
	    ReturnValue = 1;
3494
 
3495
	++i;
3496
    }
3497
 
3498
    return ReturnValue;
3499
}
3500
 
3501
/*
3502
 * UnAlias command: unalias name...
3503
 */
3504
 
3505
static int dounalias (int argc, char **argv)
3506
{
3507
    int			i;
3508
 
3509
/* Set them up or print them */
3510
 
3511
    for (i = 1; i < argc; ++i)
3512
    {
3513
	if (LookUpAlias (argv[i], FALSE) != (AliasList *)NULL)
3514
	    DeleteAlias (argv[i]);
3515
 
3516
	else
3517
	    PrintWarningMessage (NotAnAlias, LIT_unalias, argv[i]);
3518
    }
3519
 
3520
    return 0;
3521
}
3522
 
3523
/*
3524
 * OS2 detach function
3525
 */
3526
 
3527
#if (OS_TYPE != OS_DOS)
3528
static int	dodetach (int argc, char **argv)
3529
{
3530
    int		RetVal;
3531
 
3532
    if (argc < 2)
3533
	return UsageError ("detach program [ parameters ... ]");
3534
 
3535
    argv++;
3536
    RetVal = ExecuteACommand (argv, EXEC_SPAWN_DETACH);
3537
    argv--;
3538
    return RetVal;
3539
}
3540
#endif
3541
 
3542
/*
3543
 * Start a session
3544
 */
3545
 
3546
#if (OS_TYPE == OS_OS2)
3547
static int dostart (int argc, char **argv)
3548
{
3549
    bool		Direct = FALSE;
3550
    bool		UseCMD = FALSE;
3551
    STARTDATA		stdata;
3552
    STARTDATA		*sdp = &stdata;
3553
    Word_B		*wb = (Word_B *)NULL;
3554
    Word_B		*ep = (Word_B *)NULL;
3555
    int			c;
3556
    bool		options = FALSE;
3557
    bool		SetDefault = FALSE;
3558
    char		ChangeEnv = 0;
3559
    bool		FirstArg = TRUE;
3560
    bool		Display = FALSE;
3561
    OSCALL_RET		rc;
3562
    OSCALL_PARAM	ulSessID;
3563
    char		*sp;
3564
    char		p_name[FFNAME_MAX];
3565
    char		*SetPWD = GetVariableAsString (PWDVariable, FALSE);
3566
 
3567
/* Initialise the session control info */
3568
 
3569
    memset (&stdata, 0, sizeof (STARTDATA));
3570
    stdata.Length = sizeof (STARTDATA);
3571
    stdata.FgBg = SSF_FGBG_BACK;	/* Set background session	*/
3572
    stdata.PgmTitle = (PGM_TITLE_TYPE *)NULL;
3573
    stdata.Related = SSF_RELATED_CHILD;
3574
    stdata.TraceOpt = SSF_TRACEOPT_NONE;
3575
    stdata.InheritOpt = SSF_INHERTOPT_SHELL;
3576
    stdata.IconFile = (char *)NULL;
3577
    stdata.PgmHandle = 0L;
3578
    stdata.PgmControl = SSF_CONTROL_NOAUTOCLOSE;
3579
    stdata.InitXPos = 0;
3580
    stdata.InitYPos = 0;
3581
    stdata.InitXSize = 100;
3582
    stdata.InitYSize = 100;
3583
 
3584
/* These values get reset somewhere along the line */
3585
 
3586
#  if (OS_SIZE == OS_16)
3587
    stdata.SessionType = SSF_TYPE_WINDOWABLEVIO;
3588
#  else
3589
    stdata.SessionType = SSF_TYPE_DEFAULT;
3590
#  endif
3591
 
3592
    stdata.Environment = (PBYTE)1;	/* Build the environment */
3593
 
3594
/* Switch on the arguments */
3595
 
3596
    ResetGetOptions ();			/* Reset GetOptions		*/
3597
 
3598
    while ((c = GetOptions (argc, argv,
3599
			    SetDefault ? "t:hHfWPFibIDxe:c:"
3600
				       : "O:St:dhHfWPFxibCIe:c:A:X:", 0)) != EOF)
3601
    {
3602
	switch (c)
3603
	{
3604
	    case 'O':
3605
		if (!FirstArg)
3606
		    return UsageError (StartUsage);
3607
 
3608
		else if (!stricmp (OptionArgument, LIT_dos))
3609
		    sdp = &DOS_SessionControlBlock;
3610
 
3611
		else if (!stricmp (OptionArgument, "pm"))
3612
		    sdp = &PM_SessionControlBlock;
3613
 
3614
		else
3615
		    return UsageError (StartUsage);
3616
 
3617
		SetDefault = TRUE;
3618
		break;
3619
 
3620
	    case 'A':
3621
	        if ((options) || (OptionIndex != argc))
3622
		    return UsageError (StartUsage);
3623
 
3624
		 ulSessID = (OSCALL_PARAM) strtoul (OptionArgument, &sp, 0);
3625
 
3626
		 if (*sp)
3627
		    return UsageError (StartUsage);
3628
 
3629
#  if (OS_SIZE == OS_16)
3630
		 if ((rc = DosSelectSession (ulSessID, 0L)))
3631
#  else
3632
		 if ((rc = DosSelectSession (ulSessID)))
3633
#  endif
3634
		    return PrintWarningMessage (Start_NoSession, ulSessID,
3635
					        GetOSSystemErrorMessage (rc));
3636
		 return 0;
3637
 
3638
	    case 'c':		/* Set program control		*/
3639
	    {
3640
		sdp->PgmControl = 0;
3641
		sp = OptionArgument;
3642
 
3643
		while (*sp)
3644
		{
3645
		    switch (*(sp++))
3646
		    {
3647
			case 'v':
3648
			    sdp->PgmControl |= SSF_CONTROL_VISIBLE;
3649
			    sdp->PgmControl &= ~SSF_CONTROL_INVISIBLE;
3650
			    break;
3651
 
3652
			case 'i':
3653
			    sdp->PgmControl |= SSF_CONTROL_INVISIBLE;
3654
			    sdp->PgmControl &= ~SSF_CONTROL_VISIBLE;
3655
			    break;
3656
 
3657
			case 'l':
3658
			    sdp->PgmControl |= SSF_CONTROL_MAXIMIZE;
3659
			    sdp->PgmControl &= ~SSF_CONTROL_MINIMIZE;
3660
			    break;
3661
 
3662
			case 's':
3663
			    sdp->PgmControl |= SSF_CONTROL_MINIMIZE;
3664
			    sdp->PgmControl &= ~SSF_CONTROL_MAXIMIZE;
3665
			    break;
3666
 
3667
			case 'n':
3668
			    sdp->PgmControl |= SSF_CONTROL_NOAUTOCLOSE;
3669
			    break;
3670
 
3671
			case 'a':
3672
			    sdp->PgmControl &= ~SSF_CONTROL_NOAUTOCLOSE;
3673
			    break;
3674
 
3675
			default:
3676
			    return PrintWarningMessage
3677
				("start: option must be one of [vilsna]") + 1;
3678
		    }
3679
		}
3680
 
3681
		break;
3682
	    }
3683
 
3684
	    case 'X':			/* Set startup directory	*/
3685
		SetPWD = OptionArgument;
3686
		break;
3687
 
3688
	    case 't':			/* Set title			*/
3689
		if (SetDefault && (sdp->PgmTitle != (PGM_TITLE_TYPE *)NULL))
3690
		    ReleaseMemoryCell (sdp->PgmTitle);
3691
 
3692
		sdp->PgmTitle = (!strlen (OptionArgument))
3693
				    ? (char *)NULL
3694
				    : SetDefault
3695
					? StringSave (OptionArgument)
3696
				        : OptionArgument;
3697
 
3698
		if (strlen (OptionArgument) > 32)
3699
		    sdp->PgmTitle[33] = 0;
3700
 
3701
		break;
3702
 
3703
	    case 'S':			/* Script			*/
3704
		Direct = FALSE;
3705
		break;
3706
 
3707
	    case 'd':			/* Direct 			*/
3708
		Direct = TRUE;
3709
		break;
3710
 
3711
	    case 'H':			/* Inherit options		*/
3712
		sdp->InheritOpt = SSF_INHERTOPT_SHELL;
3713
		break;
3714
 
3715
	    case 'h':			/* Inherit options		*/
3716
		sdp->InheritOpt = SSF_INHERTOPT_PARENT;
3717
		break;
3718
 
3719
	    case 'f':			/* Foreground			*/
3720
		sdp->FgBg = SSF_FGBG_FORE;
3721
		break;
3722
 
3723
	    case 'b':			/* Background			*/
3724
		sdp->FgBg = SSF_FGBG_BACK;
3725
		break;
3726
 
3727
    	    case 'I':
3728
		sdp->Related = SSF_RELATED_INDEPENDENT;
3729
		break;
3730
 
3731
    	    case 'x':
3732
		sdp->Related = SSF_RELATED_CHILD;
3733
		break;
3734
 
3735
	    case 'W':			/* PM Window			*/
3736
		sdp->FgBg = SSF_FGBG_FORE;
3737
	        sdp->SessionType = (sdp == &DOS_SessionControlBlock)
3738
					? SSF_TYPE_WINDOWABLEVIO
3739
					: SSF_TYPE_WINDOWEDVDM;
3740
		break;
3741
 
3742
	    case 'P':			/* PM Session			*/
3743
		sdp->FgBg = SSF_FGBG_FORE;
3744
	        sdp->SessionType = (sdp == &DOS_SessionControlBlock)
3745
					? SSF_TYPE_PM
3746
					: SSF_TYPE_WINDOWEDVDM;
3747
		break;
3748
 
3749
	    case 'F':			/* Full Screen			*/
3750
		sdp->FgBg = SSF_FGBG_FORE;
3751
	        sdp->SessionType = (sdp == &DOS_SessionControlBlock)
3752
					? SSF_TYPE_FULLSCREEN
3753
					: SSF_TYPE_VDM;
3754
		break;
3755
 
3756
	    case 'C':			/* Use the CMD processor	*/
3757
		UseCMD = TRUE;
3758
		break;
3759
 
3760
	    case 'D':			/* Show options			*/
3761
		Display = TRUE;
3762
		break;
3763
 
3764
	    case 'e':			/* Define environment		*/
3765
		if (ChangeEnv == 'i')
3766
		    return UsageError (StartUsage);
3767
 
3768
		if ((sdp->Environment != (PBYTE)NULL) &&
3769
		    (sdp->Environment != (PBYTE)1))
3770
		{
3771
		    ReleaseMemoryCell (sdp->Environment);
3772
		    sdp->Environment = (PBYTE)NULL;
3773
		}
3774
 
3775
		ChangeEnv = 'e';
3776
		ep = AddWordToBlock (OptionArgument, ep);
3777
		break;
3778
 
3779
	    case 'i':			/* Inherit environment		*/
3780
		if (ChangeEnv == 'e')
3781
		    return UsageError (StartUsage);
3782
 
3783
		if ((sdp->Environment != (PBYTE)NULL) &&
3784
		    (sdp->Environment != (PBYTE)1))
3785
		    ReleaseMemoryCell (sdp->Environment);
3786
 
3787
		ChangeEnv = 'i';
3788
		sdp->Environment = (PBYTE)NULL;
3789
		break;
3790
 
3791
	    default:
3792
		return UsageError (StartUsage);
3793
	}
3794
 
3795
	FirstArg = FALSE;
3796
	options = TRUE;
3797
    }
3798
 
3799
/* If setting default, no more parameters allowed */
3800
 
3801
    if (SetDefault)
3802
    {
3803
	if (OptionIndex != argc) 
3804
	    return UsageError (StartUsage);
3805
    }
3806
 
3807
    else
3808
    {
3809
 
3810
/* Check for script */
3811
 
3812
	if ((OptionIndex != argc) && (!UseCMD) && (!Direct) &&
3813
	    (FindLocationOfExecutable (p_name, argv[OptionIndex])
3814
				     == EXTENSION_EXECUTABLE))
3815
	    Direct = TRUE;
3816
 
3817
/* Find the program to start */
3818
 
3819
	if ((OptionIndex == argc) || (!Direct))
3820
	{
3821
	    if (!UseCMD)
3822
	    {
3823
		wb = AddWordToBlock (GetVariableAsString (ShellVariableName,
3824
							  FALSE), wb);
3825
		if (SetPWD != null)
3826
		{
3827
		    wb = AddWordToBlock ("-X", wb);
3828
		    wb = AddWordToBlock (SetPWD, wb);
3829
		}
3830
	    }
3831
 
3832
	    else
3833
	    {
3834
		wb = AddWordToBlock (GetVariableAsString (ComspecVariable,
3835
							  FALSE), wb);
3836
		if (OptionIndex != argc)
3837
		    wb = AddWordToBlock ("/c", wb);
3838
	    }
3839
	}
3840
 
3841
	else
3842
	    wb = AddWordToBlock (argv[OptionIndex++], wb);
3843
    }
3844
 
3845
/* Set up environment */
3846
 
3847
    if ((ep != (Word_B *)NULL) &&
3848
	((sdp->Environment =
3849
	    BuildOS2String (GetWordList (AddWordToBlock (NOWORD, ep)), 0))
3850
			    == (PBYTE)NULL))
3851
	return doOutofMemory ("start");
3852
 
3853
/* OK, if we set the default, processing is completed */
3854
 
3855
    if (SetDefault)
3856
    {
3857
	if (ep != (Word_B *)NULL)
3858
	    SetMemoryAreaNumber (sdp->Environment, 0);
3859
 
3860
	if (Display)
3861
	   DisplayStartData (sdp);
3862
 
3863
	return 0;
3864
    }
3865
 
3866
/* Set up the session block and execute the command */
3867
 
3868
    SessionControlBlock = &stdata;
3869
 
3870
/* Build the argument block */
3871
 
3872
    while (OptionIndex != argc)
3873
	wb = AddWordToBlock (argv[OptionIndex++], wb);
3874
 
3875
/* Start the session */
3876
 
3877
    argv = GetWordList (AddWordToBlock (NOWORD, wb));
3878
 
3879
    return (ExecuteACommand (argv, 0) == -1) ? 1 : 0;
3880
}
3881
 
3882
/*
3883
 * Clean up the start data structure, removing allocated space
3884
 */
3885
 
3886
static void F_LOCAL DisplayStartData (STARTDATA *sdp)
3887
{
3888
    char	*sp;
3889
 
3890
    printf ("Start session defaults for %s mode\n",
3891
	    (sdp == &DOS_SessionControlBlock) ? LIT_dos : "PM");
3892
 
3893
    printf ("    Window mode: %s%s%s %sautoclose.\n",
3894
	    (sdp->PgmControl & SSF_CONTROL_INVISIBLE)
3895
		? "invisible" : "visible",
3896
	    (sdp->PgmControl & SSF_CONTROL_MINIMIZE)
3897
		? " minimised" : null,
3898
	    (sdp->PgmControl & SSF_CONTROL_MAXIMIZE)
3899
		? " maximised" : null,
3900
	    (sdp->PgmControl & SSF_CONTROL_NOAUTOCLOSE)
3901
		? "no " : "");
3902
 
3903
    if (sdp->PgmTitle != (PGM_TITLE_TYPE *)NULL)
3904
	printf ("    Program Title: %s\n", sdp->PgmTitle);
3905
 
3906
    printf ("    Run in %s.\n", (sdp->FgBg == SSF_FGBG_FORE)
3907
				    ? "foreground" : "background");
3908
 
3909
    printf ("    %s session.\n",
3910
	    (sdp->Related == SSF_RELATED_INDEPENDENT)
3911
		? "Independent" : "Dependent");
3912
 
3913
    printf ("    Session type: %s.\n", 
3914
	    (sdp->SessionType == SSF_TYPE_WINDOWABLEVIO)
3915
	    ? "Windowed"
3916
	    : (sdp->SessionType == SSF_TYPE_PM)
3917
		? "PM"
3918
		: (sdp->SessionType == SSF_TYPE_FULLSCREEN)
3919
		    ? "Full screen"
3920
		    : (sdp->SessionType == SSF_TYPE_WINDOWEDVDM)
3921
			? "DOS Windowed"
3922
			: (sdp->SessionType == SSF_TYPE_VDM)
3923
			    ? "DOS Full screen"
3924
			    : "Default");
3925
 
3926
    printf ("    Inherit %s environment\n", 
3927
	    (sdp->InheritOpt == SSF_INHERTOPT_SHELL) ? "start up" : "current");
3928
 
3929
    if (sdp->Environment == (PBYTE)1)
3930
	puts ("    Use current environment variables.");
3931
 
3932
    else if (sdp->Environment == (PBYTE)NULL)
3933
	puts ("    Use start up environment variables.");
3934
 
3935
    else
3936
    {
3937
	sp = sdp->Environment;
3938
	printf ("    Environment variables:\n");
3939
 
3940
	while (*sp)
3941
	{
3942
	    printf ("        %s\n", sp);
3943
	    sp += strlen (sp) + 1;
3944
	}
3945
    }
3946
}
3947
#endif
3948
 
3949
 
3950
/*
3951
 * Set up new Parameter Variables
3952
 */
3953
 
3954
static int F_LOCAL SetUpNewParameterVariables (char **Array,/* New values*/
3955
					       int  Offset, /* Start offset */
3956
					       int  Max, /* Number	*/
3957
					       char *function)
3958
{
3959
    int		n;
3960
    Word_B	*wb = (Word_B *)NULL;
3961
    char	*cp;
3962
    bool	Duplicate = (bool)(strcmp (function, LIT_shift) == 0);
3963
 
3964
    if ((wb = AddParameter (ParameterArray[0], wb, function)) == (Word_B *)NULL)
3965
	return 1;
3966
 
3967
    for (n = Offset; n < Max; ++n)
3968
    {
3969
	if ((cp = (Duplicate) ? StringSave (Array[n]) : Array[n])
3970
		== null)
3971
	    return doOutofMemory (function);
3972
 
3973
	if ((wb = AddParameter (cp, wb, function)) == (Word_B *)NULL)
3974
	    return 1;
3975
    }
3976
 
3977
    return (AddParameter (NOWORD, wb, function) == (Word_B *)NULL)
3978
		? 1 : 0;
3979
}
3980
 
3981
/*
3982
 * dolet - Each arg is an arithmetic expression to be evaluated.
3983
 */
3984
 
3985
static int dolet (int argc, char **argv)
3986
{
3987
    long	Value = 0;
3988
    int		i;
3989
 
3990
/* If (( )), ignore the terminating )) */
3991
 
3992
    if ((strcmp (argv[0], "((") == 0) &&
3993
	(strcmp (argv[argc - 1], "))") == 0))
3994
	argv[argc - 1] = NOWORD;
3995
 
3996
    ExpansionErrorDetected = FALSE;
3997
 
3998
    for (i = 1; !ExpansionErrorDetected && (argv[i] != NOWORD); ++i)
3999
	Value = EvaluateMathsExpression (argv[i]);
4000
 
4001
    return !Value || ExpansionErrorDetected ? 1 : 0;
4002
}
4003
 
4004
/*
4005
 * Out of memory error
4006
 */
4007
 
4008
static int F_LOCAL doOutofMemory (char *s)
4009
{
4010
    return PrintWarningMessage (BasicErrorMessage, s, Outofmemory1);
4011
}
4012
 
4013
/*
4014
 * MSDOS, EXPORT and READONLY functions: xxxx [ variable names... ]
4015
 */
4016
 
4017
static int doexport (int argc, char **argv)
4018
{
4019
    (void)argc;
4020
    return UpdateVariableStatus (argv + 1, STATUS_EXPORT);
4021
}
4022
 
4023
static int doreadonly (int argc, char **argv)
4024
{
4025
    (void)argc;
4026
    return UpdateVariableStatus (argv + 1, STATUS_READONLY);
4027
}
4028
 
4029
static int domsdos (int argc, char **argv)
4030
{
4031
    (void)argc;
4032
    return UpdateVariableStatus (argv + 1, STATUS_CONVERT_MSDOS);
4033
}
4034
 
4035
static int F_LOCAL UpdateVariableStatus (char **argv, unsigned int Mask)
4036
{
4037
    if (*argv == NOWORD)
4038
        return ListAllVariables (Mask, FALSE);
4039
 
4040
    else
4041
    {
4042
	memset (&TypesetValues, 0, sizeof (TypesetValues));
4043
	TypesetValues.Flags_On = Mask;
4044
	return TypesetVariables (argv);
4045
    }
4046
}
4047
 
4048
/*
4049
 * List All variables matching a STATUS
4050
 */
4051
 
4052
static int F_LOCAL ListAllVariables (unsigned int Mask, bool PrintValue)
4053
{
4054
    HandleSECONDandRANDOM ();
4055
 
4056
    DVE_Mask = Mask;
4057
    DVE_PrintValue = PrintValue;
4058
 
4059
    twalk (VariableTree, DisplayVariableEntry);
4060
    return 0;
4061
}
4062
 
4063
/*
4064
 * TWALK Function - display VARIABLE tree
4065
 */
4066
 
4067
static void DisplayVariableEntry (const void *key, VISIT visit, int level)
4068
{
4069
    VariableList	*vp = *(VariableList **)key;
4070
 
4071
    (void)level;
4072
 
4073
    if ((visit == postorder) || (visit == leaf))
4074
    {
4075
	if ((IS_VariableFC ((int)*vp->name)) &&
4076
	    ((vp->status & DVE_Mask) ||
4077
             (((vp->status & ~STATUS_GLOBAL) == 0) && (DVE_Mask == 0xffff))))
4078
	    PrintEntry (vp, DVE_PrintValue,
4079
			(DVE_Mask == 0xffff) ? 0 : DVE_Mask);
4080
    }
4081
}
4082
 
4083
/*
4084
 * typeset function - [ [ [+-][Hflprtux] ] [+-][LRZi[n]] [ name [=value] ...]
4085
 */
4086
 
4087
static int dotypeset (int argc, char **argv)
4088
{
4089
    int			ReturnValue = 0;
4090
    bool		f_flag = FALSE;
4091
    unsigned int	*CurrentFlags;
4092
    int			tmp = 0;
4093
    char		c_opt;
4094
    char		*cp;
4095
 
4096
/* Initialise save area */
4097
 
4098
    memset (&TypesetValues, 0, sizeof (TypesetValues));
4099
    OptionIndex = 1;
4100
 
4101
/* Scan the options */
4102
 
4103
    while ((cp = argv[OptionIndex]) != NOWORD)
4104
    {
4105
	if ((*cp != '-') && (*cp != '+'))
4106
	    break;
4107
 
4108
	CurrentFlags = (*cp == '-') ? &TypesetValues.Flags_On
4109
				    : &TypesetValues.Flags_Off;
4110
 
4111
	while (*(++cp))
4112
	{
4113
	    switch (*cp)
4114
	    {
4115
		case 'p':
4116
		    fprintf (stderr, "typeset: Option (%c) not supported\n",
4117
			     *cp);
4118
		    break;
4119
 
4120
		case 'H':
4121
		    *CurrentFlags |= STATUS_CONVERT_MSDOS;
4122
		    break;
4123
 
4124
		case 'f':		/* Function only		*/
4125
		    f_flag = TRUE;
4126
		    break;
4127
 
4128
		case 'l':
4129
		    *CurrentFlags |= STATUS_LOWER_CASE;
4130
		    break;
4131
 
4132
		case 'r':
4133
		    *CurrentFlags |= STATUS_READONLY;
4134
		    break;
4135
 
4136
		case 't':
4137
		    *CurrentFlags |= STATUS_TAGGED;
4138
		    break;
4139
 
4140
		case 'u':
4141
		    *CurrentFlags |= STATUS_UPPER_CASE;
4142
		    break;
4143
 
4144
		case 'x':
4145
		    *CurrentFlags |= STATUS_EXPORT;
4146
		    break;
4147
 
4148
		case 'L':
4149
		case 'R':
4150
		case 'Z':
4151
		case 'i':
4152
		{
4153
		    switch (c_opt = *cp)
4154
		    {
4155
			case 'L':
4156
			    *CurrentFlags |= STATUS_LEFT_JUSTIFY;
4157
			    break;
4158
 
4159
			case 'R':
4160
			    *CurrentFlags |= STATUS_RIGHT_JUSTIFY;
4161
			    break;
4162
 
4163
			case 'Z':
4164
			    *CurrentFlags |= STATUS_ZERO_FILL;
4165
			    break;
4166
 
4167
			case 'i':
4168
			    *CurrentFlags |= STATUS_INTEGER;
4169
			    break;
4170
		    }
4171
 
4172
/* Only set width on on */
4173
 
4174
		    if (CurrentFlags != &TypesetValues.Flags_On)
4175
			break;
4176
 
4177
/* Check for following numeric */
4178
 
4179
		    if (isdigit (*(cp + 1)))
4180
			tmp = (int)strtol (cp + 1, &cp, 10);
4181
 
4182
		    else if ((*(cp + 1) == 0) &&
4183
			     (OptionIndex + 1 < argc) &&
4184
			     isdigit (*argv[OptionIndex + 1]))
4185
			tmp = (int)strtol (argv[++OptionIndex], &cp, 10);
4186
 
4187
		    else
4188
			break;
4189
 
4190
/* Check for invalid numeric */
4191
 
4192
		    if (!tmp || *(cp--))
4193
			return UsageError (TypeSetUsage);
4194
 
4195
/* Width or base */
4196
 
4197
		    if (c_opt == 'i')
4198
			TypesetValues.Base = tmp;
4199
 
4200
		    else
4201
			TypesetValues.Width = tmp;
4202
 
4203
		    break;
4204
		}
4205
 
4206
		default:
4207
		    return UsageError (TypeSetUsage);
4208
	    }
4209
	}
4210
 
4211
	++OptionIndex;
4212
    }
4213
 
4214
/* Check for f flag - function processing. */
4215
 
4216
    if (f_flag)
4217
    {
4218
	if (((TypesetValues.Flags_On | TypesetValues.Flags_Off) &
4219
		~(STATUS_TAGGED | STATUS_EXPORT)) ||
4220
	    (!(TypesetValues.Flags_On | TypesetValues.Flags_Off)))
4221
	    return PrintWarningMessage ("typeset: Only -xt allowed with -f");
4222
 
4223
	for (tmp = OptionIndex; tmp < argc; tmp++)
4224
	    ReturnValue |= HandleFunction (argv[tmp]);
4225
 
4226
	return ReturnValue;
4227
    }
4228
 
4229
/* Process variable assignments */
4230
 
4231
    return TypesetVariables (&argv[OptionIndex]);
4232
}
4233
 
4234
static int F_LOCAL TypesetVariables (char **argv)
4235
{
4236
    bool		PrintValue = C2bool (TypesetValues.Flags_Off);
4237
    VariableList	*vp;
4238
    char		*CurrentName;
4239
    char		*NewValue;
4240
    char		*OldValue;
4241
    int			OldStatus;
4242
    long		NValue;
4243
    char		*xp;
4244
    int			Retval = 0;
4245
    unsigned int	Mask;
4246
    long		Index;
4247
 
4248
    if ((Mask = (TypesetValues.Flags_On | TypesetValues.Flags_Off)) == 0)
4249
	Mask = 0xffff;
4250
 
4251
/* Switch off any appropriate flags */
4252
 
4253
    if (TypesetValues.Flags_On & STATUS_LOWER_CASE)
4254
	TypesetValues.Flags_Off |= STATUS_UPPER_CASE;
4255
 
4256
    if (TypesetValues.Flags_On & STATUS_UPPER_CASE)
4257
	TypesetValues.Flags_Off |= STATUS_LOWER_CASE;
4258
 
4259
    if (TypesetValues.Flags_On & STATUS_RIGHT_JUSTIFY)
4260
	TypesetValues.Flags_Off |= STATUS_LEFT_JUSTIFY;
4261
 
4262
    if (TypesetValues.Flags_On & STATUS_LEFT_JUSTIFY)
4263
	TypesetValues.Flags_Off |= STATUS_RIGHT_JUSTIFY;
4264
 
4265
/* If no arguments, print all values matching the mask */
4266
 
4267
    if (*argv == NOWORD)
4268
	return ListAllVariables (Mask, PrintValue);
4269
 
4270
/* Process each argument.  If no flags, print it */
4271
 
4272
    while ((CurrentName = *(argv++)) != NOWORD)
4273
    {
4274
	if (!GetVariableName (CurrentName, &Index, &NewValue, (bool *)NULL))
4275
	{
4276
	    PrintErrorMessage (BasicErrorMessage, CurrentName, LIT_BadID);
4277
	    return 1;
4278
	}
4279
 
4280
/* Convert the = to a null so we get the name and value */
4281
 
4282
	if (*NewValue)
4283
	    *(NewValue++) = 0;
4284
 
4285
	else
4286
	    NewValue = (char *)NULL;
4287
 
4288
/* If valid - update, otherwise print a message */
4289
 
4290
	if ((Mask != 0xffff) || (NewValue != (char *)NULL))
4291
	{
4292
 
4293
/* Get the original value */
4294
 
4295
	    vp = LookUpVariable (CurrentName, (int)Index, TRUE);
4296
	    OldStatus = vp->status;
4297
	    OldValue = GetVariableArrayAsString (CurrentName, (int)Index,
4298
						 FALSE);
4299
 
4300
/* Update status */
4301
 
4302
	    vp->status &= ~(TypesetValues.Flags_Off);
4303
	    vp->status |= TypesetValues.Flags_On;
4304
 
4305
	    if ((CurrentFunction != (FunctionList *)NULL) &&
4306
		(!(vp->status & STATUS_GLOBAL)))
4307
		vp->status |= STATUS_LOCAL;
4308
 
4309
	    if (Index)
4310
		vp->status &= ~(STATUS_EXPORT);
4311
 
4312
/* Set up a new integer value.  If the variable was not an integer
4313
 * originally and there is an error, unset it
4314
 */
4315
 
4316
	    xp = (NewValue != (char *)NULL) ? NewValue : OldValue;
4317
 
4318
	    if (vp->status & STATUS_INTEGER)
4319
	    {
4320
		if (ValidMathsExpression (xp, &NValue))
4321
		{
4322
		    Retval = PrintWarningMessage (LIT_Emsg, "bad numeric value",
4323
						  CurrentName, xp);
4324
 
4325
		    if (!(OldStatus & STATUS_INTEGER))
4326
			UnSetVariable (CurrentName, (int)Index, FALSE);
4327
 
4328
		    continue;
4329
		}
4330
 
4331
		else if (OldStatus & STATUS_READONLY)
4332
		{
4333
		    Retval = PrintWarningMessage (LIT_2Strings, vp->name,
4334
						  LIT_IsReadonly);
4335
		    continue;
4336
		}
4337
 
4338
/* Save the new integer value and set up base etc */
4339
 
4340
		vp->nvalue = NValue;
4341
 
4342
		if (!vp->base)
4343
		    vp->base = (LastNumberBase != -1) ? LastNumberBase : 10;
4344
 
4345
		if (TypesetValues.Base)
4346
		    vp->base = TypesetValues.Base;
4347
 
4348
		if (vp->value != null)
4349
		    ReleaseMemoryCell ((void *)vp->value);
4350
 
4351
		vp->value = null;
4352
	    }
4353
 
4354
/* String - update if appropriate, both the value and the width */
4355
 
4356
	    else if ((OldStatus & STATUS_READONLY) ||
4357
		     (!(vp->status & STATUS_READONLY)))
4358
		SetVariableArrayFromString (CurrentName, (int)Index, xp);
4359
 
4360
/* New status is readonly - allow set, then stop them */
4361
 
4362
	    else
4363
	    {
4364
		vp->status &= ~STATUS_READONLY;
4365
		SetVariableArrayFromString (CurrentName, (int)Index, xp);
4366
		vp->status |= STATUS_READONLY;
4367
	    }
4368
 
4369
	    if (TypesetValues.Width)
4370
		vp->width = TypesetValues.Width;
4371
	}
4372
 
4373
/* Print if appropriate */
4374
 
4375
	else
4376
	    PrintEntry (LookUpVariable (CurrentName, (int)Index, FALSE),
4377
			PrintValue, Mask);
4378
    }
4379
 
4380
    return Retval;
4381
}
4382
 
4383
static void F_LOCAL PrintEntry (VariableList	*vp,
4384
			        bool		PrintValue,
4385
			        unsigned int	Mask)
4386
{
4387
    unsigned int	Flags = vp->status & Mask;
4388
 
4389
    if (vp->status & STATUS_NOEXISTANT)
4390
	return;
4391
 
4392
    if (Flags & STATUS_INTEGER)
4393
	printf ("integer ");
4394
 
4395
    if (Flags & STATUS_LEFT_JUSTIFY)
4396
	printf ("left justified %d ", vp->width);
4397
 
4398
    if (Flags & STATUS_RIGHT_JUSTIFY)
4399
	printf ("right justified %d ", vp->width);
4400
 
4401
    if (Flags & STATUS_ZERO_FILL)
4402
	printf ("zero filled %d ", vp->width);
4403
 
4404
    if (Flags & STATUS_CONVERT_MSDOS)
4405
	printf ("MS-DOS Format ");
4406
 
4407
    if (Flags & STATUS_LOWER_CASE)
4408
	printf ("lowercase ");
4409
 
4410
    if (Flags & STATUS_UPPER_CASE)
4411
	printf ("uppercase ");
4412
 
4413
    if (Flags & STATUS_READONLY)
4414
	printf ("readonly ");
4415
 
4416
    if (Flags & STATUS_TAGGED)
4417
	printf ("tagged ");
4418
 
4419
    if (Flags & STATUS_EXPORT)
4420
	printf ("exported ");
4421
 
4422
/* Print the value */
4423
 
4424
    foputs (vp->name);
4425
 
4426
    if (vp->index || CountVariableArraySize (vp->name) > 1)
4427
	printf (LIT_BNumber, vp->index);
4428
 
4429
    if (PrintValue)
4430
	printf ("=%s", GetVariableArrayAsString (vp->name, vp->index, TRUE));
4431
 
4432
    fputchar (CHAR_NEW_LINE);
4433
}
4434
 
4435
/*
4436
 * Handle typeset -f
4437
 */
4438
 
4439
static int F_LOCAL HandleFunction (char *name)
4440
{
4441
    FunctionList	*fop;
4442
 
4443
    if (strchr (name, CHAR_ASSIGN) != (char *)NULL)
4444
	return PrintWarningMessage ("typeset: cannot assign to functions");
4445
 
4446
    if ((fop = LookUpFunction (name, FALSE)) == (FunctionList *)NULL)
4447
	return PrintWarningMessage ("typeset: function %s does not exist",
4448
				    name);
4449
 
4450
    fop->Traced = C2bool (TypesetValues.Flags_On & STATUS_TAGGED);
4451
    return 0;
4452
}
4453
 
4454
/*
4455
 * Modified version of getopt for shell
4456
 */
4457
 
4458
void	ResetGetOptions (void)
4459
{
4460
    OptionIndex = 1;			/* Reset the optind flag	*/
4461
    GetOptionPosition = 1;		/* Current position	*/
4462
}
4463
 
4464
int	GetOptions (int		argc,		/* Argument count	*/
4465
		    char	**argv,		/* Argument array	*/
4466
		    char	*optstring,	/* Options string	*/
4467
		    int		flags)		/* Control flags	*/
4468
{
4469
    int		cur_option;		/* Current option		*/
4470
    char	*cp;			/* Character pointer		*/
4471
 
4472
    BadOptionValue = 0;
4473
 
4474
    if (GetOptionPosition == 1)
4475
    {
4476
 
4477
/* Special for doecho */
4478
 
4479
	if (flags & GETOPT_PRINT)
4480
	    return EOF;
4481
 
4482
/* Check for out of range, correct start character and not single */
4483
 
4484
	if ((OptionIndex >= argc) ||
4485
	    (!(((OptionStart = *argv[OptionIndex]) == '-') ||
4486
	       (((flags & GETOPT_PLUS) && (OptionStart == '+'))))) ||
4487
	    (!argv[OptionIndex][1]))
4488
	    return EOF;
4489
 
4490
	if (!strcmp (argv[OptionIndex], DoubleHypen))
4491
	    return EOF;
4492
    }
4493
 
4494
/* Get the current character from the current argument vector */
4495
 
4496
    cur_option = argv[OptionIndex][GetOptionPosition];
4497
 
4498
/* Validate it */
4499
 
4500
    if ((cur_option == ':') ||
4501
	((cp = strchr (optstring, cur_option)) == (char *)NULL))
4502
    {
4503
	if (flags & GETOPT_MESSAGE)
4504
	    PrintWarningMessage ("%s: illegal option -- %c", argv[0],
4505
				 cur_option);
4506
 
4507
/* Save the bad option value and move to the next offset */
4508
 
4509
	BadOptionValue = cur_option;
4510
 
4511
	if (!argv[OptionIndex][++GetOptionPosition])
4512
	{
4513
	    OptionIndex++;
4514
	    GetOptionPosition = 1;
4515
	}
4516
 
4517
	return '?';
4518
    }
4519
 
4520
/* Parameters following ? */
4521
 
4522
    OptionArgument = (char *)NULL;
4523
 
4524
    if (*(++cp) == ':')
4525
    {
4526
	if (argv[OptionIndex][GetOptionPosition + 1])
4527
	    OptionArgument = &argv[OptionIndex++][GetOptionPosition + 1];
4528
 
4529
	else if (++OptionIndex >= argc)
4530
	{
4531
	    if ((flags & (GETOPT_MESSAGE | GETOPT_AMISSING)) == GETOPT_MESSAGE)
4532
		PrintWarningMessage ("%s: option (%c) requires an argument",
4533
				     argv[0], cur_option);
4534
 
4535
	    BadOptionValue = cur_option;
4536
	    OptionArgument = (char *)-1;
4537
	    GetOptionPosition = 1;
4538
	    return '?';
4539
	}
4540
 
4541
	else
4542
	    OptionArgument = argv[OptionIndex++];
4543
 
4544
	GetOptionPosition = 1;
4545
    }
4546
 
4547
    else if (!argv[OptionIndex][++GetOptionPosition])
4548
    {
4549
	GetOptionPosition = 1;
4550
	OptionIndex++;
4551
    }
4552
 
4553
    return cur_option;
4554
}
4555
 
4556
 
4557
/*
4558
 * Kill the specified processes
4559
 */
4560
 
4561
#if (OS_TYPE != OS_DOS)
4562
static struct KillSignalList {
4563
    char	*Name;
4564
    int		SigVal;
4565
} KillSignalList [] = {
4566
    {"term",	-1 },
4567
#  if (OS_TYPE == OS_OS2)
4568
    {"usr1",	PFLG_A },
4569
    {"usr2",	PFLG_B },
4570
    {"usr3",	PFLG_C },
4571
#  elif (OS_TYPE == OS_NT)
4572
    {"break",	CTRL_BREAK_EVENT},
4573
    {"int",	CTRL_C_EVENT},
4574
#  endif
4575
};
4576
 
4577
#define MAX_KILL_SIGNALS	ARRAY_SIZE (KillSignalList)
4578
 
4579
static int dokill (int argc, char **argv)
4580
{
4581
    int		i;
4582
    int		Sigv = -1;
4583
    char	*cp;
4584
    PID		pidProcess = 0;
4585
    long	value = 0;
4586
#  if (OS_TYPE == OS_NT)
4587
    HANDLE	hp = 0;
4588
#  elif (OS_TYPE == OS_OS2)
4589
    USHORT	rc;
4590
#  endif
4591
 
4592
    if (argc < 2)
4593
	return UsageError (KillUsage);
4594
 
4595
/* List signals ? */
4596
 
4597
    if (!strcmp (argv[1], "-l"))
4598
    {
4599
	for (i = 0; i < MAX_KILL_SIGNALS; ++i)
4600
	    puts (KillSignalList[i].Name);
4601
 
4602
	return 0;
4603
    }
4604
 
4605
/* Look up signal name */
4606
 
4607
    if (**(++argv) == '-')
4608
    {
4609
	cp = &argv[0][1];
4610
 
4611
	for (i = 0; i < MAX_KILL_SIGNALS; ++i)
4612
	{
4613
	    if (!stricmp (KillSignalList[i].Name, cp))
4614
		break;
4615
	}
4616
 
4617
	if (i == MAX_KILL_SIGNALS)
4618
	    return PrintWarningMessage ("kill: bad signal name (%s)", cp);
4619
 
4620
	Sigv = KillSignalList[i].SigVal;
4621
 
4622
	if (*(++argv) == NOWORD)
4623
	    return UsageError (KillUsage);
4624
    }
4625
 
4626
/* Kill the processes */
4627
 
4628
    while (*argv != NOWORD)
4629
    {
4630
 
4631
/* Find the PID */
4632
 
4633
        if (((**argv == CHAR_JOBID) && !ConvertJobToPid ((*argv) + 1, &pidProcess)) ||
4634
	    ((**argv != CHAR_JOBID) && !ConvertNumericValue (*argv, &value, 0)))
4635
	    return PrintWarningMessage ("kill: bad process/job id (%s)",
4636
					 *argv);
4637
 
4638
/* If Process ID, its in value */
4639
 
4640
 	if (**argv != CHAR_JOBID)
4641
	    pidProcess = (PID)value;
4642
 
4643
/* Send the signal */
4644
 
4645
#  if (OS_TYPE == OS_OS2)
4646
	if (Sigv == -1)
4647
	{
4648
#    if (OS_SIZE == OS_16)
4649
	    rc = DosKillProcess (DKP_PROCESSTREE, pidProcess);
4650
#    else
4651
	    if ((rc = DosKillProcess (DKP_PROCESSTREE, pidProcess)))
4652
		 rc = (USHORT)DosSendSignalException (pidProcess,
4653
						      XCPT_SIGNAL_BREAK);
4654
#    endif
4655
	}
4656
 
4657
	else
4658
	    rc = Dos32FlagProcess (pidProcess, FLGP_SUBTREE, Sigv, 0);
4659
 
4660
	if (rc)
4661
	    return PrintWarningMessage ("kill: Cannot signal process %s\n%s",
4662
					 *argv,
4663
					 GetOSSystemErrorMessage (rc));
4664
#  elif (OS_TYPE == OS_NT)
4665
 
4666
/* Check for Ctl C or Break */
4667
 
4668
	if ((Sigv == CTRL_BREAK_EVENT) || (Sigv == CTRL_C_EVENT))
4669
	{
4670
	    if (!GenerateConsoleCtrlEvent (Sigv, pidProcess))
4671
		return PrintWarningMessage ("kill: Cannot kill process %s\n%s",
4672
					    *argv, 
4673
				     GetOSSystemErrorMessage (GetLastError ()));
4674
 
4675
	}
4676
 
4677
/* Open the process and terminate it */
4678
 
4679
	else if ((hp = OpenProcess (PROCESS_ALL_ACCESS, TRUE,
4680
				    pidProcess)) == NULL)
4681
	    return PrintWarningMessage ("kill: Cannot access process %s\n%s",
4682
					*argv, 
4683
				    GetOSSystemErrorMessage (GetLastError ()));
4684
	else if (!TerminateProcess (hp, 1))
4685
	{
4686
	    PrintWarningMessage ("kill: Cannot kill process %s\n%s", *argv, 
4687
				 GetOSSystemErrorMessage (GetLastError ()));
4688
	    CloseHandle (hp);
4689
	    return 1;
4690
	}
4691
 
4692
	CloseHandle (hp);
4693
#  endif
4694
 
4695
	argv++;
4696
    }
4697
 
4698
    return 0;
4699
}
4700
 
4701
/*
4702
 * Wait for process to end
4703
 */
4704
 
4705
static int dowait (int argc, char **argv)
4706
{
4707
    PID		pidProcess;
4708
    int		TermStat;
4709
#  if (OS_TYPE != OS_NT)
4710
    int		ReturnValue;
4711
#  endif
4712
    long	value;
4713
 
4714
/* Check usage */
4715
 
4716
    if (argc > 2)
4717
	return UsageError ("wait [ job ]");
4718
 
4719
/* Wait for all jobs ? */
4720
 
4721
    if (argc < 2)
4722
    {
4723
#  if (OS_TYPE == OS_NT)
4724
	return PrintWarningMessage ("wait: any job not supported on NT");
4725
#  else
4726
	TermStat = -1;
4727
 
4728
/* Yes - wait until wait returns an error */
4729
 
4730
	while ((pidProcess = wait (&ReturnValue)) != -1)
4731
	{
4732
	    DeleteJob (pidProcess);
4733
	    TermStat = ReturnValue;
4734
	}
4735
#  endif
4736
    }
4737
 
4738
/* Wait for a specific process.  Job or PID? */
4739
 
4740
    else
4741
    {
4742
 
4743
/* Move to the ID */
4744
 
4745
	argv++;
4746
 
4747
/* Find the PID */
4748
 
4749
        if (((**argv == CHAR_JOBID) &&
4750
	     !ConvertJobToPid ((*argv) + 1, &pidProcess)) ||
4751
	    ((**argv != CHAR_JOBID) &&
4752
	     !ConvertNumericValue (*argv, &value, 0)))
4753
	    return PrintWarningMessage ("wait: bad process/job id (%s)",
4754
					 *argv);
4755
 
4756
/* If Process ID, its in value */
4757
 
4758
 	if (**argv != CHAR_JOBID)
4759
	    pidProcess = (PID)value;
4760
 
4761
/* Wait for the specified process */
4762
 
4763
#  if (OS_TYPE == OS_UNIX)
4764
	fputs ("UNIX: Wait for process NI\n", stderr);
4765
 
4766
#  else
4767
	if (cwait (&TermStat, pidProcess, WAIT_GRANDCHILD) == -1)
4768
	    return PrintWarningMessage ("wait: Process id (%s) not active",
4769
					*argv);
4770
#  endif
4771
 
4772
	DeleteJob (pidProcess);
4773
    }
4774
 
4775
/* Convert termination status to return code */
4776
 
4777
    if (TermStat == -1)
4778
	return -1;
4779
 
4780
    else if (TermStat & 0x00ff)
4781
	return TermStat & 0x00ff;
4782
 
4783
    else
4784
	return (TermStat >> 8) & 0x00ff;
4785
}
4786
 
4787
/*
4788
 * Print the job info
4789
 */
4790
 
4791
static int dojobs (int argc, char **argv)
4792
{
4793
    bool	ListMode = FALSE;
4794
#  if (OS_TYPE == OS_OS2) || (OS_TYPE == OS_UNIX)
4795
    pid_t	p = getpid ();
4796
    bool	ListTree = FALSE;
4797
    long	value;
4798
#  endif
4799
    int		i;
4800
 
4801
/* List signals ? */
4802
 
4803
    ResetGetOptions ();			/* Reset GetOptions		*/
4804
 
4805
    while ((i = GetOptions (argc, argv, "plP:", 0)) != EOF)
4806
    {
4807
        switch (i)
4808
        {
4809
	    case 'l':
4810
		ListMode = TRUE;
4811
		break;
4812
 
4813
#  if (OS_TYPE == OS_OS2) || (OS_TYPE == OS_UNIX)
4814
	    case 'p':
4815
		ListTree = TRUE;
4816
		break;
4817
 
4818
	    case 'P':
4819
		ListTree = TRUE;
4820
 
4821
		if (!ConvertNumericValue (OptionArgument, &value, 0))
4822
		    return PrintWarningMessage ("jobs: bad process id (%s)",
4823
		    				OptionArgument);
4824
 
4825
		p = (pid_t)value;
4826
 
4827
		break;
4828
#  endif
4829
 
4830
	    default:
4831
		return UsageError (JobUsage);
4832
	}
4833
    }
4834
 
4835
#  if (OS_TYPE == OS_OS2) || (OS_TYPE == OS_UNIX)
4836
    if (ListTree)
4837
        return PrintProcessTree (p);
4838
#  endif
4839
 
4840
/* Look up job name */
4841
 
4842
    return PrintJobs (ListMode);
4843
}
4844
#endif
4845
 
4846
/*
4847
 * Print the option settings
4848
 */
4849
 
4850
static int F_LOCAL	PrintOptionSettings (void)
4851
{
4852
    int		i;
4853
 
4854
    puts ("Current option settings:");
4855
 
4856
    for (i = 0; SetOptions[i].OptionName != (char *)NULL; i++)
4857
	printf ("%-16s%s\n", SetOptions[i].OptionName,
4858
		TestOptionValue (SetOptions[i].OptionName, FALSE)
4859
			? "on" : "off");
4860
    return 0;
4861
}
4862
 
4863
/*
4864
 * Change option value
4865
 */
4866
 
4867
static bool F_LOCAL ChangeOptionValue (char *value, bool set)
4868
{
4869
    struct SetOptions	*entry = LookUpOptionValue (value);
4870
 
4871
    if (entry == (struct SetOptions *)NULL)
4872
	return FALSE;
4873
 
4874
    else if (entry->HasOptionValue)
4875
	SetClearFlag (entry->FlagValue, set);
4876
 
4877
/* If one of the Editor flags, disable all editor flags first */
4878
 
4879
    else if (entry->FlagValue == FLAGS_VERIFY_SWITCH)
4880
	SetVerifyStatus (set);
4881
 
4882
#ifdef FLAGS_BREAK_SWITCH
4883
    else if (entry->FlagValue == FLAGS_BREAK_SWITCH)
4884
	SetBreakStatus (set);
4885
#endif
4886
 
4887
#ifdef FLAGS_SET_OS2
4888
    else if (entry->FlagValue == FLAGS_SET_OS2)
4889
        BaseOS = (set) ? BASE_OS_OS2 : BASE_OS_DOS;
4890
#endif
4891
 
4892
#ifdef FLAGS_SET_NT
4893
    else if (entry->FlagValue == FLAGS_SET_NT)
4894
        BaseOS = (set) ? BASE_OS_NT : BASE_OS_DOS;
4895
#endif
4896
 
4897
/* Change the editor flags */
4898
 
4899
    else if (set)
4900
    {
4901
	if (entry->FlagValue & FLAGS_EDITORS)
4902
	    ShellGlobalFlags &= ~(FLAGS_EDITORS);
4903
 
4904
	ShellGlobalFlags |= entry->FlagValue;
4905
    }
4906
 
4907
    else
4908
	ShellGlobalFlags &= ~(entry->FlagValue);
4909
 
4910
 
4911
    return TRUE;
4912
}
4913
 
4914
/*
4915
 * Update shell switches
4916
 */
4917
 
4918
static void F_LOCAL SetClearFlag (int Flag, bool set)
4919
{
4920
    if (set)
4921
	FL_SET (Flag);
4922
 
4923
    else
4924
	FL_CLEAR (Flag);
4925
}
4926
 
4927
/*
4928
 * Test an option
4929
 */
4930
 
4931
static int F_LOCAL TestOptionValue (char *value, bool AllowJump)
4932
{
4933
    struct SetOptions	*entry = LookUpOptionValue (value);
4934
 
4935
    if (entry == (struct SetOptions *)NULL)
4936
    {
4937
	PrintWarningMessage ("%s: unknown option - %s", TestProgram, value);
4938
 
4939
	if (AllowJump)
4940
	    longjmp (TestErrorReturn, 1);
4941
 
4942
	return 0;
4943
    }
4944
 
4945
    else if (entry->FlagValue == FLAGS_VERIFY_SWITCH)
4946
    {
4947
#if (OS_TYPE == OS_OS2)
4948
	BOOL	fVerifyOn;
4949
 
4950
	DosQVerify (&fVerifyOn);
4951
	return fVerifyOn;
4952
 
4953
#elif (OS_TYPE != OS_DOS)
4954
 
4955
	return FALSE;
4956
 
4957
#elif (OS_TYPE == OS_DOS)
4958
 
4959
	union REGS	r;
4960
 
4961
	r.x.REG_AX = 0x5400;
4962
	DosInterrupt (&r, &r);
4963
	return r.h.al;
4964
#endif
4965
    }
4966
 
4967
#if (OS_TYPE == OS_DOS)
4968
    else if (entry->FlagValue == FLAGS_BREAK_SWITCH)
4969
    {
4970
	union REGS	r;
4971
 
4972
	r.x.REG_AX = 0x3300;
4973
	DosInterrupt (&r, &r);
4974
	return r.h.dl;
4975
    }
4976
#endif
4977
 
4978
#ifdef FLAGS_SET_OS2
4979
    else if (entry->FlagValue == FLAGS_SET_OS2)
4980
        return BaseOS == BASE_OS_OS2;
4981
#endif
4982
 
4983
#ifdef FLAGS_SET_NT
4984
    else if (entry->FlagValue == FLAGS_SET_NT)
4985
        return BaseOS == BASE_OS_NT;
4986
#endif
4987
 
4988
    else if (entry->HasOptionValue)
4989
	return (FL_TEST (entry->FlagValue) != 0);
4990
 
4991
    return (ShellGlobalFlags & entry->FlagValue);
4992
}
4993
 
4994
/*
4995
 * Find an Option entry
4996
 */
4997
 
4998
static struct SetOptions * F_LOCAL LookUpOptionValue (char *value)
4999
{
5000
    int		i = 0;
5001
    char	*cp;
5002
 
5003
    while ((cp = SetOptions[i].OptionName) != (char *)NULL)
5004
    {
5005
	if (!strcmp (cp, value))
5006
	    return &SetOptions[i];
5007
 
5008
	++i;
5009
    }
5010
 
5011
    return (struct SetOptions *)NULL;
5012
}
5013
 
5014
/*
5015
 * Get Unit number
5016
 */
5017
 
5018
static int F_LOCAL GetUnitNumber (char *prog)
5019
{
5020
    int		Unit;
5021
 
5022
    if (((Unit = GetNumericValue (OptionArgument)) < 0) || (Unit > 9))
5023
    {
5024
	PrintWarningMessage (LIT_Emsg, LIT_bun, prog, OptionArgument);
5025
	return -1;
5026
    }
5027
 
5028
    return Unit;
5029
}
5030
 
5031
/*
5032
 * fc function - fc [-e EditorName] [-nlr] [First [Last]]
5033
 *		 fc -e - [Old=New] [Command]
5034
 */
5035
 
5036
static int dofc (int argc, char **argv)
5037
{
5038
    char		*Editor = GetVariableAsString (FCEditVariable, FALSE);
5039
    bool		n_flag = TRUE;
5040
    bool		l_flag = FALSE;
5041
    bool		r_flag = FALSE;
5042
    int			EventNumber[2];
5043
    char		*Temp;
5044
    char		*Change = (char *)NULL;
5045
    char		*Change1;
5046
    char		*NewBuffer;
5047
    char		*NewArg[3];
5048
    int			i;
5049
    FILE		*fp;
5050
 
5051
/* Check status */
5052
 
5053
    if (!(InteractiveFlag && IS_TTY (0)))
5054
	return PrintWarningMessage ("fc: only available in interactive mode");
5055
 
5056
    if ((NewBuffer = AllocateMemoryCell (LINE_MAX + 3)) == (char *)NULL)
5057
	return doOutofMemory ("fc");
5058
 
5059
/* Process options */
5060
 
5061
    ResetGetOptions ();			/* Reset GetOptions		*/
5062
 
5063
    while ((i = GetOptions (argc, argv, "e:nlr", 0)) != EOF)
5064
    {
5065
	switch (i)
5066
	{
5067
	    case 'e':			/* editor name			*/
5068
		Editor = OptionArgument;
5069
		break;
5070
 
5071
	    case 'n':	n_flag = FALSE;	break;
5072
	    case 'l':	l_flag = TRUE;	break;
5073
	    case 'r':	r_flag = TRUE;	break;
5074
 
5075
	    default:
5076
		return UsageError ("fc [ -e EditorName ] [ -nlr ] [ First [Last]]\n       fc -e - [ Old=New ] [ Command ]");
5077
	}
5078
    }
5079
 
5080
    argv += OptionIndex;
5081
    argc -= OptionIndex;
5082
 
5083
/* Check for [old=new] */
5084
 
5085
    if (argc && ((Change1 = strchr (*argv, CHAR_ASSIGN)) != (char *)NULL))
5086
    {
5087
	Change = *(argv++);
5088
	*(Change1++) = 0;
5089
	--argc;
5090
    }
5091
 
5092
    if (!l_flag)
5093
	DeleteLastHistory ();
5094
 
5095
/* Get the first and last event number */
5096
 
5097
    for (i = 0; i < 2; i++)
5098
    {
5099
	EventNumber[i] = 0;
5100
 
5101
	if (argc)
5102
	{
5103
	    EventNumber[i] = (int)strtol (*argv, &Temp, 10);
5104
 
5105
	    if (*Temp)
5106
		EventNumber[i] = SearchHistory (*argv);
5107
 
5108
	    else if (EventNumber[i] < 0)
5109
		EventNumber[i] += GetLastHistoryEvent () - 1;
5110
 
5111
	    if (EventNumber[i] <= 0)
5112
		return PrintWarningMessage ("fc: event <%s> not found",
5113
					    *argv);
5114
 
5115
	    argv++;
5116
	    --argc;
5117
	}
5118
    }
5119
 
5120
/* Set up first and last values */
5121
 
5122
    i = GetLastHistoryEvent () - 1;
5123
 
5124
    if (!EventNumber[0])
5125
    {
5126
        if ((EventNumber[0] = (l_flag) ? i - 16 : i) <= 0)
5127
	    EventNumber[0] = 1;
5128
    }
5129
 
5130
    if (!EventNumber[1])
5131
        EventNumber[1] = (l_flag) ? i : EventNumber[0];
5132
 
5133
/* If l - print */
5134
 
5135
    if (l_flag)
5136
	fp = stdout;
5137
 
5138
    else if (Editor == null)
5139
	return PrintWarningMessage ("fc: editor not defined");
5140
 
5141
    else if ((fp = FOpenFile ((Temp = GenerateTemporaryFileName ()),
5142
    			      sOpenWriteBinaryMode)) == (FILE *)NULL)
5143
	return PrintWarningMessage ("fc: cannot create %s", Temp);
5144
 
5145
/* Process history */
5146
 
5147
    if (!l_flag)
5148
	n_flag = FALSE;
5149
 
5150
    PrintHistory (r_flag, n_flag, EventNumber[0], EventNumber[1], fp);
5151
 
5152
    if (l_flag)
5153
	return 0;
5154
 
5155
/* Check that we found some history */
5156
 
5157
    if (!ftell (fp))
5158
	l_flag = TRUE;
5159
 
5160
    if (fp != stdout)
5161
	CloseFile (fp);
5162
 
5163
    if (l_flag)
5164
    {
5165
	unlink (Temp);
5166
	return PrintWarningMessage ("fc: no matches");
5167
    }
5168
 
5169
/* Invoke the editor */
5170
 
5171
    if (strcmp (Editor, ShellOptionsVariable))
5172
    {
5173
	NewArg[0] = Editor;
5174
	NewArg[1] = Temp;
5175
	NewArg[2] = (char *)NULL;
5176
 
5177
	if (ExecuteACommand (NewArg, 0) == -1)
5178
	{
5179
	    unlink (Temp);
5180
	    return 1;
5181
	}
5182
    }
5183
 
5184
/* Now execute it */
5185
 
5186
    if ((i = S_open (TRUE, Temp, O_RMASK)) < 0)
5187
	return PrintWarningMessage ("fc: cannot re-open edit file (%s)",
5188
				    Temp);
5189
 
5190
    argc = read (i, NewBuffer, LINE_MAX + 1);
5191
    S_close (i, TRUE);
5192
 
5193
    if (argc <= 0)
5194
	return (argc == 0) ? 0 : 1;
5195
 
5196
    else if (argc >= LINE_MAX - 1)
5197
	return PrintWarningMessage (FCTooLong);
5198
 
5199
/* Strip off trailing EOFs and EOLs */
5200
 
5201
    CleanUpBuffer (argc, NewBuffer, 0x1a);
5202
 
5203
/* Check for substitution */
5204
 
5205
    if (Change == (char *)NULL)
5206
	strcpy (ConsoleLineBuffer, NewBuffer);
5207
 
5208
    else
5209
    {
5210
	if ((Temp = strstr (NewBuffer, Change)) == (char *)NULL)
5211
	    return PrintWarningMessage ("fc: string not found");
5212
 
5213
	if ((i = strlen (NewBuffer) - strlen (Change) +
5214
		 strlen (Change1)) >= LINE_MAX - 2)
5215
	    return PrintWarningMessage (FCTooLong);
5216
 
5217
/* Do the substitution */
5218
 
5219
	i = Temp - NewBuffer;
5220
	strncpy (ConsoleLineBuffer, NewBuffer, i);
5221
	strcpy (ConsoleLineBuffer + i, Change1);
5222
	strcat (ConsoleLineBuffer, NewBuffer + strlen (Change) + i);
5223
    }
5224
 
5225
    ReleaseMemoryCell ((void *)NewBuffer);
5226
 
5227
/* Tell the user what we've done */
5228
 
5229
    puts (ConsoleLineBuffer);
5230
 
5231
/* Flag the console driver not to read from the console, but use the
5232
 * current contents of the ConsoleLineBuffer
5233
 */
5234
 
5235
    UseConsoleBuffer = TRUE;
5236
    return 0;
5237
}
5238
 
5239
/*
5240
 * Convert Job ID to process id
5241
 */
5242
 
5243
 
5244
#if (OS_TYPE != OS_DOS) 
5245
static bool F_LOCAL ConvertJobToPid (char *String, PID *pid)
5246
{
5247
    long	value;
5248
    JobList	*jp;
5249
 
5250
/* If numeric value, look up the job number */
5251
 
5252
    if (ConvertNumericValue (String, &value, 0))
5253
	jp = LookUpJob ((int)value);
5254
 
5255
    else
5256
	jp = SearchForJob (String);
5257
 
5258
    if (jp == (JobList *)NULL)
5259
	return FALSE;
5260
 
5261
    PreviousJob = CurrentJob;
5262
    CurrentJob = jp->pid;
5263
 
5264
    *pid = jp->pid;
5265
    return TRUE;
5266
}
5267
#endif
5268
 
5269
/*
5270
 * Missing OS2 2.x API
5271
 */
5272
 
5273
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32)
5274
APIRET	 DosQFileMode (PSZ pszFName, PULONG pusAttr)
5275
{
5276
    APIRET	rc;
5277
    FILESTATUS3	status;
5278
 
5279
    if ((rc = DosQueryPathInfo (pszFName, FIL_STANDARD, &status,
5280
			       sizeof (FILESTATUS3))) == 0)
5281
	*pusAttr = status.attrFile;
5282
 
5283
    return rc;
5284
}
5285
#endif
5286
 
5287
#if (OS_TYPE == OS_NT)
5288
int      DosQFileMode (const char *pszFName, DWORD *pusAttr)
5289
{
5290
    *pusAttr = GetFileAttributes (pszFName);
5291
    return (*pusAttr == 0xffffffff) ? -1 : 0;
5292
}
5293
#endif
5294
 
5295
/*
5296
 * A sort of version of times
5297
 */
5298
 
5299
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32) && !defined (__WATCOMC__)
5300
static int dotimes (int argc, char **argv)
5301
{
5302
    (void) argc;
5303
    (void) argv;
5304
 
5305
    return PrintTimes ();
5306
}
5307
#endif
5308
 
5309
#if (OS_TYPE == OS_NT) || (OS_TYPE == OS_UNIX)
5310
static int dotimes (int argc, char **argv)
5311
{
5312
    (void) argc;
5313
    (void) argv;
5314
 
5315
    return PrintTimes ();
5316
}
5317
#endif
5318
 
5319
/*
5320
 * Convert logical path to physical path, skipping out SUBST drives
5321
 */
5322
 
5323
#if (OS_TYPE == OS_OS2)
5324
static char * F_LOCAL GetPhysicalPath (char *inpath, bool AllowNetwork)
5325
{
5326
#  ifndef __EMX__
5327
    char		*op;
5328
    char		*res;
5329
 
5330
    if ((op = AllocateMemoryCell (FFNAME_MAX)) == (char *)NULL)
5331
	return inpath;
5332
 
5333
    if ((res = _fullpath (op, inpath, PATH_MAX + 6)) != (char *)NULL)
5334
	strcpy (inpath, op);
5335
 
5336
    PATH_TO_LOWER_CASE (inpath);
5337
    ReleaseMemoryCell (op);
5338
#  endif
5339
 
5340
    (void) AllowNetwork;
5341
 
5342
    return PATH_TO_UNIX (inpath);
5343
}
5344
#endif
5345
 
5346
/* NT Version */
5347
 
5348
#if (OS_TYPE == OS_NT)
5349
static char * F_LOCAL GetPhysicalPath (char *inpath, bool AllowNetwork)
5350
{
5351
    char		*op;
5352
    char		*res;
5353
 
5354
    (void) AllowNetwork;
5355
 
5356
    if ((op = AllocateMemoryCell (FFNAME_MAX)) == (char *)NULL)
5357
	return inpath;
5358
 
5359
    if (!GetFullPathName (inpath, FFNAME_MAX, op, &res))
5360
	strcpy (inpath, op);
5361
 
5362
    PATH_TO_LOWER_CASE (inpath);
5363
    ReleaseMemoryCell (op);
5364
    return PATH_TO_UNIX (inpath);
5365
}
5366
#endif
5367
 
5368
/* DOS version */
5369
 
5370
#if (OS_TYPE == OS_DOS)
5371
static char * F_LOCAL GetPhysicalPath (char *inpath, bool AllowNetwork)
5372
{
5373
#  ifndef __EMX__
5374
    char		*op;
5375
    union REGS		r;
5376
    struct SREGS	sr;
5377
 
5378
    if ((op = AllocateMemoryCell (FFNAME_MAX)) == (char *)NULL)
5379
	return inpath;
5380
 
5381
    PATH_TO_DOS (inpath);
5382
 
5383
    r.h.ah     = 0x60;
5384
    r.x.REG_SI = FP_OFF (inpath);
5385
    sr.ds      = FP_SEG (inpath);
5386
 
5387
    r.x.REG_DI = FP_OFF (op);
5388
    sr.es      = FP_SEG (op);
5389
 
5390
    DosExtendedInterrupt (&r, &r, &sr);
5391
 
5392
/* If we are succesfully and this is not a networked drive, replace the
5393
 * original path
5394
 */
5395
 
5396
    if ((!(r.x.REG_CFLAGS & 1)) &&
5397
        (AllowNetwork || (strncmp (op, "\\\\", 2) != 0)))
5398
    {
5399
	strlwr (strcpy (inpath, op));
5400
	ReleaseMemoryCell (op);
5401
    }
5402
#  endif
5403
 
5404
    (void) AllowNetwork;
5405
 
5406
    return PATH_TO_UNIX (inpath);
5407
}
5408
#endif
5409
 
5410
/* UNIX Version */
5411
 
5412
#if (OS_TYPE == OS_UNIX)
5413
static char * F_LOCAL GetPhysicalPath (char *inpath, bool AllowNetwork)
5414
{
5415
#  ifdef S_IFLNK
5416
    char		*op;
5417
    struct stat		s;
5418
    char		*res;
5419
    int			len;
5420
 
5421
    if (((op = AllocateMemoryCell (FFNAME_MAX)) == (char *)NULL) ||
5422
	(lstat (inpath, &s) != 0) || (s.st_mode & S_IFMT) != S_IFLNK)
5423
	return inpath;
5424
 
5425
    if ((len = readlink (inpath, op, FFNAME_MAX)) == -1)
5426
	return inpath;
5427
 
5428
    op [len] = 0;
5429
    strcpy (inpath, op);
5430
    ReleaseMemoryCell (op);
5431
 
5432
#  endif
5433
 
5434
    return inpath;
5435
}
5436
#endif
5437
 
5438
 
5439
/*
5440
 * Change the verify status.  No NT or UNIX functionality.
5441
 */
5442
 
5443
static void F_LOCAL SetVerifyStatus (bool On)
5444
{
5445
#if (OS_TYPE == OS_OS2) 
5446
    DosSetVerify (On);
5447
#elif (OS_TYPE == OS_DOS)
5448
    union REGS	r;
5449
 
5450
    r.x.REG_AX = On ? 0x2e01 : 0x2e00;
5451
    r.x.REG_DX = 0;
5452
    DosInterrupt (&r, &r);
5453
#else
5454
    (void) On;
5455
#endif
5456
}
5457
 
5458
/*
5459
 * Change the break status
5460
 */
5461
 
5462
#if (OS_TYPE == OS_DOS)
5463
static void F_LOCAL SetBreakStatus (bool On)
5464
{
5465
    union REGS	r;
5466
 
5467
    r.x.REG_AX = 0x3301;
5468
    r.h.dl = (unsigned char)(On ? 1 : 0);
5469
    DosInterrupt (&r, &r);
5470
}
5471
#endif
5472
 
5473
/*
5474
 * Bind an EMACS keystroke to a editing command
5475
 */
5476
 
5477
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
5478
static int	dobind (int argc, char **argv)
5479
{
5480
    bool	macro = FALSE;
5481
    char	*cp;
5482
    int		c;
5483
 
5484
    ResetGetOptions ();			/* Reset GetOptions		*/
5485
 
5486
    while ((c = GetOptions (argc, argv, "m", 0)) != EOF)
5487
    {
5488
	if (c == 'm')
5489
	    macro = TRUE;
5490
 
5491
	else
5492
	    return UsageError ("bind [ -m ] [ keystroke=edit command ] ...");
5493
    }
5494
 
5495
    argv += OptionIndex;
5496
 
5497
/* List All ? */
5498
 
5499
    if (*argv == (char *)NULL)	/* list all */
5500
	return BindKeyStroke ((char *)NULL, (char *)NULL, FALSE);
5501
 
5502
/* Otherwise, bind */
5503
 
5504
    c = 0;
5505
 
5506
    while (*argv != (char *)NULL)
5507
    {
5508
	if ((cp = strchr (*argv, '=')) != (char *)NULL)
5509
	    *(cp++) = 0;
5510
 
5511
	c |= BindKeyStroke (*(argv++), cp, macro);
5512
    }
5513
 
5514
    return c;
5515
}
5516
#endif
5517
 
5518
static int	doshellinfo (int argc, char **argv)
5519
{
5520
    static char		*OSName [] = { LIT_dos, "Windows", "OS/2", "Win NT",
5521
    				       "UNIX"};
5522
 
5523
    (void) argc;
5524
    (void) argv;
5525
 
5526
    printf ("Global Flags              = 0x%.4x\n", ShellGlobalFlags);
5527
    printf ("Max # of File descriptors = %d\n", MaxNumberofFDs);
5528
    printf ("Disabled Variables        = 0x%.4x\n", DisabledVariables);
5529
    printf ("Execute stack depth       = %d\n", Execute_stack_depth);
5530
    printf ("Memory stack depth        = %d\n", MemoryAreaLevel);
5531
    printf ("IO stack depth            = %d\n", NSave_IO_E);
5532
    printf ("Subshell stack depth      = %d\n", NSubShells);
5533
    printf ("Underlying OS             = <%s>\n", OSName[BaseOS]);
5534
    return 0;
5535
}
5536
 
5537
/*
5538
 * Flag OS/2 process for _EMX_
5539
 */
5540
 
5541
#if defined (__EMX__) && (OS_TYPE == OS_OS2)
5542
USHORT	Dos32FlagProcess (PID pid, USHORT fScope, USHORT usFlagNum,
5543
			  USHORT usFlagArg)
5544
{
5545
    return ((USHORT)
5546
	    (_THUNK_PROLOG (2 + 2 + 2 + 2);
5547
	     _THUNK_SHORT (pid);
5548
	     _THUNK_SHORT (fScope);
5549
	     _THUNK_SHORT (usFlagNum);
5550
	     _THUNK_SHORT (usFlagArg);
5551
	     _THUNK_CALL (Dos16FlagProcess)));
5552
}
5553
#endif
5554
 
5555
/*
5556
 * Check file access
5557
 */
5558
 
5559
static int F_LOCAL CheckFAccess (const char *Name, int mode)
5560
{
5561
    int                 fdn = CheckForFD (CheckDOSFileName (Name, NULL));
5562
#if (OS_TYPE == OS_UNIX)
5563
    struct stat		s;
5564
    int                 tm = 0;
5565
#else
5566
    OSCALL_PARAM	usAttr;
5567
#endif
5568
 
5569
    if (fdn < 0)
5570
	return S_access (Name, mode);
5571
 
5572
#if (OS_TYPE == OS_UNIX)
5573
    if (fstat (fdn, &s) < 0)
5574
        return 0;
5575
 
5576
    if (mode == 0)
5577
	return 1;
5578
 
5579
/* Find which bits to check */
5580
 
5581
    if (mode & W_OK)
5582
	tm |= S_IWUSR;
5583
 
5584
    if (mode & R_OK)
5585
	tm |= S_IRUSR;
5586
 
5587
    if (mode & X_OK)
5588
	tm |= S_IXUSR;
5589
 
5590
/* Are we the owner, or group owner? */
5591
 
5592
    if (getuid () != st.st_uid)
5593
    {
5594
	tm >>= 3;
5595
 
5596
	if (getgid () != st.st_gid)
5597
	    tm >>= 3;
5598
    }
5599
 
5600
    return s.st_mode & tm;
5601
#else
5602
 
5603
/* Non-Unix is almost as much pain */
5604
 
5605
    if (OS_GetFHAttributes (fdn, &usAttr) != 0)
5606
        return 0;
5607
 
5608
    if ((mode & W_OK) && (usAttr & OS_FILE_READONLY))
5609
        return 0;
5610
 
5611
    if (mode & X_OK)
5612
        return 0;
5613
 
5614
    return 1;
5615
#endif
5616
}
5617
 
5618
/*
5619
 * Check file type
5620
 */
5621
 
5622
static int F_LOCAL CheckFType (const char *Name, int mode)
5623
{
5624
    struct stat		s;
5625
    int                 fdn = CheckForFD (CheckDOSFileName (Name, NULL));
5626
#if (OS_TYPE != OS_UNIX)
5627
    int			ftype;
5628
#endif
5629
 
5630
/*
5631
 * File Name
5632
 */
5633
 
5634
    if (fdn < 0)
5635
        return (S_stat (Name, &s) && ((s.st_mode & S_IFMT) == mode)) ? 1 : 0;
5636
 
5637
/*
5638
 * File descriptor
5639
 */
5640
#if (OS_TYPE == OS_UNIX)
5641
    return ((fstat (fdn, &s) >= 0) && ((s.st_mode & S_IFMT) == mode)) ? 1 : 0;
5642
#else
5643
 
5644
/* Usual OS/2, MSDOS, WINNT pain */
5645
    ftype = GetDescriptorType (fdn);
5646
 
5647
    if ((mode == S_IFREG) && (ftype == DESCRIPTOR_FILE))
5648
        return 1;
5649
 
5650
    if ((mode == S_IFCHR) && 
5651
        ((ftype == DESCRIPTOR_DEVICE) || (ftype == DESCRIPTOR_CONSOLE)))
5652
        return 1;
5653
 
5654
    return 0;
5655
#endif
5656
}
5657
 
5658
/*
5659
 * Check file mode
5660
 */
5661
 
5662
static int F_LOCAL CheckFMode (const char *Name, int mode)
5663
{
5664
    int                 fdn = CheckForFD (CheckDOSFileName (Name, NULL));
5665
#if (OS_TYPE == OS_UNIX)
5666
    struct stat		s;
5667
#else
5668
    OSCALL_PARAM	usAttr;
5669
#endif
5670
 
5671
#if (OS_TYPE == OS_UNIX)
5672
    if (((fdn < 0) && !S_stat (Name, &s)) ||
5673
	((fdn >= 0) && (fstat (fdn, &s) < 0)))
5674
	return 0;
5675
 
5676
    return (s.st_mode & mode);
5677
#else
5678
    if (fdn < 0)
5679
	return (OS_GetFileAttributes (Name, &usAttr) == 0) && (usAttr & mode);
5680
 
5681
    return (OS_GetFHAttributes (fdn, &usAttr) == 0) && (usAttr & mode);
5682
#endif
5683
}
5684
 
5685
/*
5686
 * Check file size
5687
 */
5688
 
5689
static int F_LOCAL CheckFSize (const char *Name)
5690
{
5691
    struct stat		s;
5692
    int                 fdn = CheckForFD (CheckDOSFileName (Name, NULL));
5693
 
5694
    if (((fdn < 0) && !S_stat (Name, &s)) ||
5695
#if (OS_TYPE == OS_UNIX)
5696
	((fdn >= 0) && (fstat (fdn, &s) < 0)))
5697
#else
5698
	((fdn >= 0) && ((s.st_size = filelength (fdn)) < 0)))
5699
#endif
5700
	return 0;
5701
 
5702
    return (s.st_size > 0L);
5703
}
5704
 
5705
/*
5706
 * Does this refer to a file descriptor - check for /dev/fd/n
5707
 */
5708
 
5709
static int F_LOCAL CheckForFD (const char *name)
5710
{
5711
    if (strncmp (name, LIT_devfd, sizeof (LIT_devfd) - 1) != 0)
5712
	return -1;
5713
 
5714
    return atoi (name + sizeof (LIT_devfd) - 1);
5715
}
5716
 
5717
/*
5718
 * Get File Handler Attributes
5719
 */
5720
 
5721
/*
5722
 * Under DOS, there is no way to get the file attributes
5723
 */
5724
 
5725
#if (OS_TYPE == OS_DOS)
5726
static OSCALL_RET F_LOCAL OS_GetFHAttributes (int fd, OSCALL_PARAM *usAttr)
5727
{
5728
    if (lseek (fd, 0L, SEEK_CUR) == -1L)
5729
        return -1;
5730
 
5731
    *usAttr = 0;
5732
    return 0;
5733
}
5734
#endif
5735
 
5736
/*
5737
 * OS/2 Version
5738
 */
5739
 
5740
#if (OS_TYPE == OS_OS2)
5741
static OSCALL_RET F_LOCAL OS_GetFHAttributes (int fd, OSCALL_PARAM *usAttr)
5742
{
5743
    OSCALL_RET		rc;
5744
#  if (OS_SIZE == OS_32)
5745
    FILESTATUS3		info;
5746
#  else
5747
    FILESTATUS		info;
5748
#  endif
5749
 
5750
    rc = DosQFileInfo (fd, FIL_STANDARD, &info, sizeof (info));
5751
 
5752
    if (rc != 0)
5753
	return rc;
5754
 
5755
    *usAttr = info.attrFile;
5756
    return 0;
5757
}
5758
#endif
5759
 
5760
/*
5761
 * NT Version
5762
 */
5763
 
5764
#if (OS_TYPE == OS_NT)
5765
static OSCALL_RET F_LOCAL OS_GetFHAttributes (int fd, OSCALL_PARAM *usAttr)
5766
{
5767
    extern long _CRTAPI1	_get_osfhandle (int);
5768
    BY_HANDLE_FILE_INFORMATION	info;
5769
    HANDLE                      osfp = (HANDLE)_get_osfhandle (fd);
5770
 
5771
    switch (GetFileType (osfp))
5772
 
5773
    if (!GetFileInformationByHandle(osfp, &info))
5774
	return 1;
5775
 
5776
    *usAttr = info.dwFileAttributes;
5777
    return 0;
5778
}
5779
#endif