Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - Function Processing
3
 *
4
 * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited
5
 *
6
 * This code is subject to the following copyright restrictions:
7
 *
8
 * 1.  Redistribution and use in source and binary forms are permitted
9
 *     provided that the above copyright notice is duplicated in the
10
 *     source form and the copyright notice in file sh6.c is displayed
11
 *     on entry to the program.
12
 *
13
 * 2.  The sources (or parts thereof) or objects generated from the sources
14
 *     (or parts of sources) cannot be sold under any circumstances.
15
 *
16
 * Note:  1.  The PrintProcessTree code is based on code written by Kai Uwe
17
 *	      Rommel
18
 *
19
 *	  2.  When parts of the original 2.1 shell were replaced by the Lexical
20
 *	      Analsyer written by Simon J. Gerraty (for his Public Domain Korn
21
 *	      Shell, which is also based on Charles Forsyth original idea), a
22
 *	      number of changes were made to reflect the changes Simon made to
23
 *	      the Parse output tree.  Some parts of this code in this module
24
 *	      are based on the algorithms/ideas that he incorporated into his
25
 *	      shell, in particular the Function Processing functions.
26
 *
27
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/SH10.C,v 1.1 2002/08/02 06:49:32 adamy Exp $
28
 *
29
 *    $Log: SH10.C,v $
30
 *    Revision 1.1  2002/08/02 06:49:32  adamy
31
 *    imported (reference only)
32
 *
33
 *    Revision 1.1  2001/07/20 05:55:42  ayoung
34
 *    WIN32 support
35
 *
36
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
37
 *    UTIL
38
 *
39
 *	Revision 2.15  1994/08/25  20:49:11  istewart
40
 *	MS Shell 2.3 Release
41
 *
42
 *	Revision 2.14  1994/02/23  09:23:38  istewart
43
 *	Beta 233 updates
44
 *
45
 *	Revision 2.13  1994/02/01  10:25:20  istewart
46
 *	Release 2.3 Beta 2, including first NT port
47
 *
48
 *	Revision 2.12  1994/01/11  17:55:25  istewart
49
 *	Release 2.3 Beta 0 patches
50
 *
51
 *	Revision 2.11  1993/12/01  11:58:34  istewart
52
 *	Release 226 beta
53
 *
54
 *	Revision 2.10  1993/08/25  16:03:57  istewart
55
 *	Beta 225 - see Notes file
56
 *
57
 *	Revision 2.9  1993/07/02  10:21:35  istewart
58
 *	224 Beta fixes
59
 *
60
 *	Revision 2.8  1993/06/14  11:01:44  istewart
61
 *	More changes for 223 beta
62
 *
63
 *	Revision 2.7  1993/06/02  09:52:35  istewart
64
 *	Beta 223 Updates - see Notes file
65
 *
66
 *	Revision 2.6  1993/02/16  16:03:15  istewart
67
 *	Beta 2.22 Release
68
 *
69
 *	Revision 2.5  1993/01/26  18:35:09  istewart
70
 *	Release 2.2 beta 0
71
 *
72
 *	Revision 2.4  1992/12/14  10:54:56  istewart
73
 *	BETA 215 Fixes and 2.1 Release
74
 *
75
 *	Revision 2.3  1992/11/06  10:03:44  istewart
76
 *	214 Beta test updates
77
 *
78
 *	Revision 2.2  1992/07/16  14:33:34  istewart
79
 *	Beta 212 Baseline
80
 *
81
 *	Revision 2.1  1992/07/10  10:52:48  istewart
82
 *	211 Beta updates
83
 *
84
 *	Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
85
 *	MS-Shell 2.0 Baseline release
86
 *
87
 */
88
 
89
#include <sys/types.h>
90
#include <sys/stat.h>
91
#include <stdio.h>
92
#include <signal.h>
93
#include <errno.h>
94
#include <setjmp.h>
95
#include <ctype.h>
96
#include <string.h>
97
#include <unistd.h>
98
#include <stdlib.h>
99
#include <fcntl.h>
100
#include <limits.h>
101
#include <dirent.h>
102
#include "sh.h"
103
 
104
#if (OS_TYPE == OS_UNIX)
105
#  include <sys/times.h>
106
#endif 
107
 
108
/* Function declarations */
109
 
110
static void F_LOCAL	PrintCommand (C_Op *, int);
111
static void F_LOCAL	PrintIOInformation (IO_Actions *);
112
static void F_LOCAL	PrintCaseCommand (C_Op *);
113
static void F_LOCAL	PrintIndentedString (char *, int, int);
114
static void F_LOCAL	PrintVarArg (unsigned char *);
115
static void F_LOCAL	fputMagicChar (unsigned int);
116
static void F_LOCAL	PrintMode (int);
117
 
118
static void F_LOCAL	SaveReleaseExecuteTree (C_Op *, void (*)(void *));
119
static void F_LOCAL	SaveReleaseWordList (char **, void (*)(void *));
120
static void F_LOCAL	SaveReleaseIOActions (IO_Actions **, void (*)(void *));
121
static void		SaveTreeEntry (void *);
122
 
123
static C_Op *	F_LOCAL	DuplicateFunctionTree (C_Op *);
124
static char **  F_LOCAL	DuplicateWordList (char **list);
125
static IO_Actions ** F_LOCAL DuplicateIOActions (IO_Actions **);
126
 
127
static int		FindFunction (const void *, const void *);
128
static int		SearchFunction (const void *, const void *);
129
static void		DisplayFunction (const void *, VISIT, int);
130
static void		DeleteAFunction (const void *, VISIT, int);
131
 
132
static int		FindAlias (const void *, const void *);
133
static int		SearchAlias (const void *, const void *);
134
static void		UntrackAlias (const void *, VISIT, int);
135
static void		DisplayAlias (const void *, VISIT, int);
136
 
137
#if (OS_TYPE != OS_DOS)
138
static void		DisplayJob (const void *, VISIT, int);
139
static void		CountJob (const void *, VISIT, int);
140
static int		SearchJob (const void *, const void *);
141
static int		FindJob (const void *, const void *);
142
static void		FindJobByString (const void *, VISIT, int);
143
static int		FindJobByPID (const void *, const void *);
144
static int		FindJobBySession (const void *, const void *);
145
#endif
146
 
147
#if (OS_TYPE == OS_OS2)
148
#  if (OS_SIZE == OS_32)
149
#    if !defined (__EMX__)
150
#      define Dos32GetPrty	DosGetPrty
151
#      define Dos32QProcStatus	DosQProcStatus
152
#      pragma linkage (DosQProcStatus, far16 pascal)
153
#      pragma linkage (DosGetPrty, far16 pascal)
154
#    else
155
USHORT _THUNK_FUNCTION (Dos16GetPrty) ();
156
USHORT _THUNK_FUNCTION (Dos16QProcStatus) ();
157
#    endif
158
extern USHORT			Dos32QProcStatus (PVOID, USHORT);
159
extern USHORT			Dos32GetPrty (USHORT, PUSHORT, USHORT);
160
#  else
161
#    define Dos32QProcStatus	DosQProcStatus
162
#    define Dos32GetPrty	DosGetPrty
163
extern USHORT APIENTRY		Dos32QProcStatus (PVOID, USHORT);
164
#  endif
165
#endif
166
 
167
/*
168
 * OS/2 Process Information structures
169
 *
170
 *
171
 * Declare OS2 1.x 16-bit version structures
172
 */
173
 
174
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_16)
175
typedef struct process
176
{
177
    USHORT	pid;
178
    USHORT	ppid;
179
    USHORT	threads;
180
    USHORT	children;
181
    USHORT	modhandle;
182
    USHORT	module;
183
} V1Process_t;
184
 
185
typedef struct module
186
{
187
    USHORT	modhandle;
188
    USHORT	max_dependents;
189
    USHORT	*dependents;
190
    UCHAR	*modname;
191
} V1Module_t;
192
 
193
typedef struct ProcessInfo
194
{
195
    V1Process_t		**V1Processes;
196
    V1Module_t		**V1Modules;
197
    USHORT		M_Processes;
198
    USHORT		N_Processes;
199
    USHORT		M_Modules;
200
    USHORT		N_Modules;
201
} V1ProcessStatus_t;
202
#endif
203
 
204
/*
205
 * OS2 2.0 - 32 Bit version structures
206
 */
207
 
208
#if (OS_TYPE == OS_OS2)
209
#  if (OS_SIZE == OS_32)
210
#    define PTR(ptr)	(ptr)
211
#  else
212
#    define PTR(ptr)	((void *)((((ULONG)ps)     & 0xFFFF0000L) |	\
213
				  (((ULONG)(ptr))  & 0x0000FFFFL) ))
214
#  endif
215
 
216
#  define PROCESS_END_INDICATOR	3
217
 
218
/* Process Status structures */
219
 
220
#  if (OS_SIZE == OS_32)
221
#    pragma pack(1)
222
#  endif
223
 
224
/*
225
 * Thread Info
226
 */
227
 
228
typedef struct thread2
229
{
230
    ULONG	ulRecType;		/* Record type (thread = 100)	*/
231
    USHORT	tidWithinProcess;	/* TID within process (TID is	*/
232
    					/* 4 bytes!!)			*/
233
    USHORT	usSlot;			/* Unique thread slot number	*/
234
    ULONG	ulBlockId;		/* Sleep id thread is sleeping on*/
235
    ULONG	ulPriority;		/* Priority			*/
236
    ULONG	ulSysTime;		/* Thread System Time		*/
237
    ULONG	ulUserTime;		/* Thread User Time		*/
238
    UCHAR	uchState;		/* 1=ready,2=blocked,5=running	*/
239
    UCHAR	uchPad;			/* Filler			*/
240
    USHORT	usPad;			/* Filler			*/
241
} V2Thread_t;
242
 
243
/*
244
 * Process Information
245
 */
246
 
247
typedef struct process2
248
{
249
    ULONG	ulEndIndicator;		/* 1 means not end, 3 means	*/
250
    					/* last entry			*/
251
    V2Thread_t	*ptiFirst;		/* Address of the 1st Thread	*/
252
    					/* Control Blk			*/
253
    USHORT	pid;			/* Process ID (2 bytes - PID	*/
254
    					/* is 4 bytes)			*/
255
    USHORT	pidParent;		/* Parent's process ID		*/
256
    ULONG	ulType;			/* Process Type			*/
257
    ULONG	ulStatus;		/* Process Status		*/
258
    ULONG	idSession;		/* Session ID			*/
259
    USHORT	hModRef;		/* Module handle of EXE		*/
260
    USHORT	usThreadCount;		/* Number of threads in this	*/
261
    					/* process			*/
262
    ULONG	ulSessionType;		/* Session Type			*/
263
    PVOID	pvReserved;		/* Unknown			*/
264
    USHORT	usSem16Count;		/* Number of 16-bit system	*/
265
    					/* semaphores			*/
266
    USHORT	usDllCount;		/* Number of Dlls used by	*/
267
    					/* process			*/
268
    USHORT	usShrMemHandles;	/* Number of shared memory	*/
269
    					/* handles			*/
270
    USHORT	usReserved;		/* Unknown			*/
271
    PUSHORT	pusSem16TableAddr;	/* Address of a 16-bit semaphore*/
272
    					/* table			*/
273
    PUSHORT	pusDllTableAddr;	/* Address of a Dll table	*/
274
    PUSHORT	pusShrMemTableAddr;	/* Address of a shared memory	*/
275
    					/* table			*/
276
} V2Process_t;
277
 
278
/*
279
 * Process Status header
280
 */
281
 
282
typedef struct processstatus2
283
{
284
    PVOID	psumm;		/* SUMMARY section ptr			*/
285
    V2Process_t	*ppi;		/* PROCESS section ptr			*/
286
    PVOID	psi;		/* SEM section ptr (add 16 to offset)	*/
287
    PVOID	pDontKnow1;	/*					*/
288
    PVOID	psmi;		/* SHARED MEMORY section ptr		*/
289
    PVOID	pmi;		/* MODULE section ptr			*/
290
    PVOID	pDontKnow2;	/*					*/
291
    PVOID	pDontKnow3;	/*					*/
292
} V2ProcessStatus_t;
293
 
294
#  if (OS_SIZE == OS_32)
295
#    pragma pack()
296
#  endif
297
#endif
298
 
299
/*
300
 * Associated functions
301
 */
302
 
303
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_16)
304
static int			SortV1Processes (void *, void *);
305
static void F_LOCAL		PrintV1ProcessTree (pid_t, int,
306
						    V1ProcessStatus_t *);
307
static bool F_LOCAL		Parse_V1ProcessTable (UCHAR *,
308
						      V1ProcessStatus_t *);
309
#endif
310
 
311
#if (OS_TYPE == OS_OS2)
312
static void F_LOCAL		V2_DisplayProcessTree (USHORT, USHORT,
313
						       V2ProcessStatus_t *);
314
static V2ProcessStatus_t * F_LOCAL GetProcessStatus (char *);
315
#endif
316
 
317
#if (OS_TYPE != OS_DOS)
318
static char	*JobSearchKey;		/* Job search string		*/
319
static int	NumberOfJobs = 0;	/* Number of Jobs		*/
320
static JobList	**JobSearchEntry;	/* Matching entry		*/
321
#endif
322
 
323
static bool	DisplayListMode = FALSE;/* Mode for Display Job/Alias	*/
324
static int	Print_indent;		/* Current indent level		*/
325
 
326
					/* IO types			*/
327
static char	*IOTypes [] = { "<", ">", "<>", "<<", ">>", ">&" };
328
 
329
/*
330
 * Duplicate a memory area
331
 */
332
 
333
#define DuplicateMemoryArea(area, type)					\
334
		(type)((area == (void *)NULL)				\
335
		    ? (void *)NULL					\
336
		    : DuplicateMemoryCell (area))
337
 
338
/*
339
 * Print ALL functions
340
 */
341
 
342
int PrintAllFunctions (void)
343
{
344
    twalk (FunctionTree, DisplayFunction);
345
    return 0;
346
}
347
 
348
/*
349
 * TWALK function to display the JOB, FUNCTION and ALIAS trees
350
 */
351
 
352
#if (OS_TYPE != OS_DOS)
353
static void CountJob (const void *key, VISIT visit, int level)
354
{
355
    if ((visit == postorder) || (visit == leaf))
356
	NumberOfJobs++;
357
}
358
 
359
static void DisplayJob (const void *key, VISIT visit, int level)
360
{
361
    if ((visit == postorder) || (visit == leaf))
362
    {
363
	printf ("[%d] %c", (*(JobList **)key)->Number,
364
		((*(JobList **)key)->Number == CurrentJob)
365
			? CHAR_PLUS
366
			: (((*(JobList **)key)->Number == PreviousJob)
367
			    ? CHAR_HYPHEN : CHAR_SPACE));
368
 
369
	if (DisplayListMode)
370
	    printf (" %d", (*(JobList **)key)->pid);
371
 
372
	fputchar (CHAR_TAB);
373
	FlushStreams ();
374
	DisplayLineWithControl ((*(JobList **)key)->Command);
375
	fputchar (CHAR_NEW_LINE);
376
    }
377
}
378
#endif
379
 
380
static void DisplayFunction (const void *key, VISIT visit, int level)
381
{
382
    if ((visit == postorder) || (visit == leaf))
383
        PrintFunction ((*(FunctionList **)key)->tree, PF_MODE_NORMAL);
384
 
385
}
386
 
387
static void DisplayAlias (const void *key, VISIT visit, int level)
388
{
389
    if (((visit == postorder) || (visit == leaf)) &&
390
	(!DisplayListMode || (*(AliasList **)key)->AFlags & ALIAS_TRACKED))
391
	PrintAlias ((*(AliasList **)key)->name);
392
}
393
 
394
 
395
/*
396
 * DISPLAY A FUNCTION TREE
397
 */
398
 
399
/*
400
 * print the execute tree - used for displaying functions
401
 */
402
 
403
void PrintFunction (register C_Op *t, int mode)
404
{
405
    char		**wp;
406
 
407
    if (t == (C_Op *)NULL)
408
	return;
409
 
410
/* Check for start of print */
411
 
412
    if (t->type == TFUNC)
413
    {
414
	Print_indent = 0;
415
	printf (LIT_2Strings, t->str, "()");
416
	PrintFunction (t->left, PF_MODE_NORMAL);
417
	FlushStreams ();
418
	return;
419
    }
420
 
421
/* Otherwise, process the tree and print it */
422
 
423
    switch (t->type)
424
    {
425
	case TASYNC:			/* Asyn commands		*/
426
	    PrintFunction (t->left, PF_MODE_ASYNC);
427
	    return;
428
 
429
	case TCOPROCESS:		/* Co-process			*/
430
	    PrintFunction (t->left, PF_MODE_COPROC);
431
	    return;
432
 
433
	case TPAREN:			/* ()				*/
434
	case TCOM:			/* A command process		*/
435
	    PrintCommand (t, mode);
436
	    return;
437
 
438
	case TPIPE:			/* Pipe processing		*/
439
	    PrintFunction (t->left, PF_MODE_NORMAL);
440
	    PrintIndentedString ("|\n", 0, PF_MODE_NORMAL);
441
	    PrintFunction (t->right, mode);
442
	    return;
443
 
444
	case TLIST:			/* Entries in a for statement	*/
445
	    PrintFunction (t->left, PF_MODE_NORMAL);
446
	    PrintFunction (t->right, mode);
447
	    return;
448
 
449
	case TOR:			/* || and &&			*/
450
	case TAND:
451
	    PrintFunction (t->left, PF_MODE_NORMAL);
452
 
453
	    if (t->right != (C_Op *)NULL)
454
	    {
455
		PrintIndentedString ((t->type == TAND) ? "&&\n" : "||\n",
456
				     0, PF_MODE_NORMAL);
457
		PrintFunction (t->right, mode);
458
	    }
459
 
460
	    return;
461
 
462
	case TFOR:			/* First part of a for statement*/
463
	case TSELECT:
464
	    PrintIndentedString ((t->type == TFOR) ? "for " : "select ",
465
				 0, PF_MODE_NORMAL);
466
	    foputs (t->str);
467
 
468
	    if ((wp = t->vars) != NOWORDS)
469
	    {
470
		foputs (" in");
471
 
472
		while (*wp != NOWORD)
473
		{
474
		    fputchar (CHAR_SPACE);
475
		    PrintVarArg ((unsigned char *)*(wp++));
476
		}
477
	    }
478
 
479
	    fputchar (CHAR_NEW_LINE);
480
	    PrintIndentedString ("do\n", 1, PF_MODE_NORMAL);
481
	    PrintFunction (t->left, PF_MODE_NORMAL);
482
	    PrintIndentedString (LIT_done, -1, mode);
483
	    return;
484
 
485
	case TWHILE:			/* WHILE and UNTIL functions	*/
486
	case TUNTIL:
487
	    PrintIndentedString ((t->type == TWHILE) ? "while\n" : "until\n",
488
				 1, PF_MODE_NORMAL);
489
	    PrintFunction (t->left, PF_MODE_NORMAL);
490
	    Print_indent--;
491
	    PrintIndentedString ("do\n", 1, PF_MODE_NORMAL);
492
	    PrintFunction (t->right, PF_MODE_NORMAL);
493
	    PrintIndentedString (LIT_done, -1, mode);
494
	    return;
495
 
496
	case TIF:			/* IF and ELSE IF functions	*/
497
	case TELIF:
498
	    if (t->type == TIF)
499
		PrintIndentedString ("if\n", 1, PF_MODE_NORMAL);
500
 
501
	    else
502
		PrintIndentedString ("elif\n", 1, PF_MODE_NORMAL);
503
 
504
	    PrintFunction (t->left, PF_MODE_NORMAL);
505
 
506
	    if (t->right != (C_Op *)NULL)
507
	    {
508
		Print_indent -= 1;
509
		PrintIndentedString ("then\n", 1, PF_MODE_NORMAL);
510
		PrintFunction (t->right->left, PF_MODE_NORMAL);
511
 
512
		if (t->right->right != (C_Op *)NULL)
513
		{
514
		    Print_indent -= 1;
515
 
516
		    if (t->right->right->type != TELIF)
517
			PrintIndentedString ("else\n", 1, PF_MODE_NORMAL);
518
 
519
		    PrintFunction (t->right->right, PF_MODE_NORMAL);
520
		}
521
	    }
522
 
523
	    if (t->type == TIF)
524
		PrintIndentedString ("fi", -1, mode);
525
 
526
	    return;
527
 
528
	case TCASE:			/* CASE function		*/
529
	    PrintIndentedString ("case ", 1, PF_MODE_NORMAL);
530
	    PrintVarArg ((unsigned char *)t->str);
531
	    puts (" in");
532
	    PrintCaseCommand (t->left);
533
	    PrintIndentedString ("esac", -1, mode);
534
	    return;
535
 
536
	case TBRACE:			/* {} statement			*/
537
	    PrintIndentedString ("{\n", 1, PF_MODE_NORMAL);
538
	    if (t->left != (C_Op *)NULL)
539
		PrintFunction (t->left, mode);
540
 
541
	    PrintIndentedString ("}", -1, PF_MODE_NORMAL);
542
	    return;
543
 
544
	case TTIME:
545
	    PrintIndentedString ("time\n", 1, PF_MODE_NORMAL);
546
	    PrintFunction (t->left, mode);
547
	    Print_indent--;
548
	    return;
549
    }
550
}
551
 
552
 
553
/*
554
 * Print a command line
555
 */
556
 
557
static void F_LOCAL PrintCommand (register C_Op *t, int mode)
558
{
559
    IO_Actions	**iopp;
560
    char	**wp;
561
    int		i;
562
 
563
/* Parenthesis ? */
564
 
565
    if (t->type == TPAREN)
566
    {
567
	PrintIndentedString ("(\n", 1, PF_MODE_NORMAL);
568
	PrintFunction (t->left, PF_MODE_NORMAL);
569
	PrintIndentedString (")", -1, PF_MODE_NO);
570
 
571
    }
572
 
573
    else
574
    {
575
	PrintIndentedString (null, 0, PF_MODE_NORMAL);
576
 
577
 /* Process arguments and assigments */
578
 
579
	for (i = 0, wp = t->vars; i < 2; i++)
580
	{
581
	    if (wp != NOWORDS)
582
	    {
583
		while (*wp != NOWORD)
584
		{
585
		    PrintVarArg ((unsigned char *)*(wp++));
586
 
587
		    if (*wp != NOWORD)
588
			fputchar (CHAR_SPACE);
589
		}
590
	    }
591
 
592
	    wp = t->args;
593
	}
594
    }
595
 
596
/* Set up anyother IO required */
597
 
598
    if ((iopp = t->ioact) != (IO_Actions **)NULL)
599
    {
600
	while (*iopp != (IO_Actions *)NULL)
601
	    PrintIOInformation (*(iopp++));
602
    }
603
 
604
    PrintMode (mode);
605
}
606
 
607
/*
608
 * Print an argument or variable assigment string
609
 */
610
 
611
static void F_LOCAL PrintVarArg (unsigned char *string)
612
{
613
    register unsigned 	c;
614
    register bool	quoted = FALSE;
615
 
616
    while (1)
617
    {
618
	switch ((c = *(string++)))
619
	{
620
	    case WORD_EOS:	/* end of string			*/
621
		return;
622
 
623
	    case WORD_CHAR:	/* unquoted character			*/
624
		fputMagicChar (*(string++));
625
		break;
626
 
627
	    case WORD_QCHAR:	/* quoted character			*/
628
	    case WORD_QTCHAR:
629
		if (!quoted)
630
		    fputchar (CHAR_META);
631
 
632
		fputMagicChar (*(string++));
633
		break;
634
 
635
	    case WORD_OQUOTE:	/* opening " or '			*/
636
	    case WORD_ODQUOTE:
637
		quoted = TRUE;
638
		fputchar ((c == WORD_OQUOTE) ? CHAR_SINGLE_QUOTE
639
					     : CHAR_DOUBLE_QUOTE);
640
		break;
641
 
642
	    case WORD_CQUOTE:	/* closing " or '			*/
643
	    case WORD_CDQUOTE:
644
		quoted = FALSE;
645
		fputchar ((c == WORD_CQUOTE) ? CHAR_SINGLE_QUOTE
646
					     : CHAR_DOUBLE_QUOTE);
647
		break;
648
 
649
	    case WORD_OARRAY:	/* Opening ${...[...] ...		*/
650
		fputchar (CHAR_OPEN_BRACKETS);
651
		break;
652
 
653
	    case WORD_CARRAY:	/* Closing ${...[...] ...		*/
654
	    case WORD_OSUBST:	/* opening ${ substitution		*/
655
		if (c == WORD_CARRAY)
656
		    fputchar (CHAR_CLOSE_BRACKETS);
657
 
658
/* Start of variable - output the name */
659
 
660
		else
661
		{
662
		    fputchar (CHAR_VARIABLE);
663
		    fputchar (CHAR_OPEN_BRACES);
664
 
665
		    while ((c = *(string++)) != 0)
666
			fputchar (c);
667
		}
668
 
669
/* Check for some special characters */
670
 
671
		if ((*string != WORD_CSUBST) && (*string != WORD_OARRAY))
672
		{
673
		    if (((c = *(string++)) & CHAR_MAGIC) &&
674
			(IS_VarOp (c & 0x7f)))
675
		    {
676
 
677
/* Check for %% or ## */
678
			if (((c &= 0x7f) == CHAR_MATCH_START) ||
679
			    (c == CHAR_MATCH_END))
680
			    fputMagicChar (c);
681
 
682
/* :?string case */
683
			else
684
			    fputMagicChar (':');
685
 
686
		    }
687
 
688
		    fputMagicChar (c);
689
		}
690
 
691
		break;
692
 
693
	    case WORD_CSUBST:	/* closing } of above			*/
694
		fputchar (CHAR_CLOSE_BRACES);
695
		break;
696
 
697
	    case WORD_COMSUB:	/* $() substitution (0 terminated)	*/
698
	    case WORD_OMATHS:	/* opening $(()) substitution (0 term)	*/
699
		fputchar (CHAR_VARIABLE);
700
		fputchar (CHAR_OPEN_PARATHENSIS);
701
 
702
		if (c == WORD_OMATHS)
703
		    fputchar (CHAR_OPEN_PARATHENSIS);
704
 
705
		while (*string != 0)
706
		    fputMagicChar (*(string++));
707
 
708
		string++;		/* Skip over the terminator	*/
709
		fputchar (CHAR_CLOSE_PARATHENSIS);
710
 
711
		if (c == WORD_OMATHS)
712
		    fputchar (CHAR_CLOSE_PARATHENSIS);
713
 
714
		break;
715
	}
716
    }
717
}
718
 
719
 
720
/*
721
 * Output a potentially magic character
722
 */
723
 
724
static void F_LOCAL fputMagicChar (unsigned int c)
725
{
726
    if ((c & 0x60) == 0)
727
    {
728
	fputchar ((c & CHAR_MAGIC) ? CHAR_VARIABLE : '^');
729
	fputchar (((c & 0x7F) | 0x40));
730
    }
731
 
732
    else if ((c&0x7F) == 0x7F)
733
    {
734
	fputchar ((c & CHAR_MAGIC) ? CHAR_VARIABLE : '^');
735
	fputchar ('?');
736
    }
737
 
738
    else
739
	fputchar (c);
740
}
741
 
742
 
743
/*
744
 * Print the IO re-direction
745
 */
746
 
747
static void F_LOCAL PrintIOInformation (register IO_Actions *iop)
748
{
749
    int		unit = iop->io_unit;
750
    int		IOflag = iop->io_flag & IOTYPE;
751
    char	*type;
752
    bool	TermQuote = FALSE;
753
 
754
/* Set up the IO type string and display it */
755
 
756
    type = IOTypes [IOflag - 1];
757
 
758
    if ((IOflag == IODUP) && (!unit))
759
	type = "<&";
760
 
761
    printf (" %d%s", unit, type);
762
 
763
/* Print clobber override and skip tabs information on here documents */
764
 
765
    if (iop->io_flag & IOCLOBBER)
766
	fputchar (CHAR_PIPE);
767
 
768
    if (iop->io_flag & IOSKIP)
769
	fputchar (CHAR_HYPHEN);
770
 
771
/* Quoted here document ? */
772
 
773
    if ((TermQuote = C2bool ((IOflag == IOHERE) && (!(iop->io_flag & IOEVAL)))))
774
	fputchar (CHAR_SINGLE_QUOTE);
775
 
776
/* Here document names are in expanded format */
777
 
778
    (IOflag == IOHERE) ? (void)foputs (iop->io_name)
779
		       : (void)PrintVarArg ((unsigned char *)iop->io_name);
780
 
781
    if (TermQuote)
782
	fputchar (CHAR_SINGLE_QUOTE);
783
}
784
 
785
/*
786
 * Print out the contents of a case statement
787
 */
788
 
789
static void F_LOCAL PrintCaseCommand (C_Op *t)
790
{
791
    register char	**wp;
792
 
793
    while (t != (C_Op *)NULL)
794
    {
795
 
796
/* Print patterns (the conditions) */
797
 
798
	PrintIndentedString (null, 0, PF_MODE_NORMAL);
799
 
800
	for (wp = t->vars; *wp != NOWORD; )
801
	{
802
	    PrintVarArg ((unsigned char *)*(wp++));
803
 
804
	    if (*wp != NOWORD)
805
		foputs (" | ");
806
	}
807
 
808
	puts (" )");
809
	Print_indent += 1;
810
 
811
/* print the functions */
812
 
813
	PrintFunction (t->left, PF_MODE_NORMAL);
814
	PrintIndentedString (";;", -1, PF_MODE_NORMAL);
815
	t = t->right;
816
    }
817
}
818
 
819
/*
820
 * Print an indented string
821
 */
822
 
823
static void F_LOCAL PrintIndentedString (char *cp, int indent, int mode)
824
{
825
    int		i;
826
 
827
    if (indent < 0)
828
	Print_indent += indent;
829
 
830
    for (i = 0; i < (Print_indent / 2); i++)
831
	fputchar (CHAR_TAB);
832
 
833
    if (Print_indent % 2)
834
	foputs ("    ");
835
 
836
    foputs (cp);
837
 
838
/* Append the mode */
839
 
840
    if ((mode != PF_MODE_NORMAL) || (indent < 0))
841
	PrintMode (mode);
842
 
843
    if (indent > 0)
844
	Print_indent += indent;
845
}
846
 
847
/*
848
 * Output mode
849
 */
850
 
851
static void F_LOCAL PrintMode (int mode)
852
{
853
    if (mode == PF_MODE_ASYNC)
854
	foputs (" &\n");
855
 
856
    else if (mode == PF_MODE_COPROC)
857
	foputs (" |&\n");
858
 
859
    else if (mode == PF_MODE_NORMAL)
860
	fputchar (CHAR_NEW_LINE);
861
}
862
 
863
/*
864
 * TWALK and TDELETE compare functions for FUNCTION, ALIAS and JOB trees
865
 *
866
 * Note: We know about these two function, so we know the key is always
867
 *       the first parameter.  So we only pass the char * not the FunctionList
868
 *       pointer (in the case of JOB, its an int *)
869
 */
870
 
871
static int FindFunction (const void *key1, const void *key2)
872
{
873
    return strcmp (key1, ((FunctionList *)key2)->tree->str);
874
}
875
 
876
static int FindAlias (const void *key1, const void *key2)
877
{
878
    return strcmp (key1, ((AliasList *)key2)->name);
879
}
880
 
881
/* By string name */
882
 
883
#if (OS_TYPE != OS_DOS)
884
static void FindJobByString (const void *key, VISIT visit, int level)
885
{
886
    if (JobSearchEntry != (JobList **)NULL)
887
	return;
888
 
889
    if (((visit == postorder) || (visit == leaf)) &&
890
	(((*JobSearchKey == CHAR_MATCH_ANY) &&
891
	  (strstr (((JobList *)key)->Command, JobSearchKey) != (char *)NULL)) ||
892
	 ((*JobSearchKey != CHAR_MATCH_ANY) &&
893
	  (strncmp (JobSearchKey, ((JobList *)key)->Command,
894
		   strlen (JobSearchKey)) == 0))))
895
	JobSearchEntry = (JobList **)&key;
896
}
897
 
898
/* By process id */
899
 
900
static int FindJobByPID (const void *key1, const void *key2)
901
{
902
    return *(PID *)key1 - ((JobList *)key2)->pid;
903
}
904
 
905
/* By session id */
906
 
907
static int FindJobBySession (const void *key1, const void *key2)
908
{
909
    return *(unsigned short *)key1 - ((JobList *)key2)->SessionId;
910
}
911
 
912
/* By job number */
913
 
914
static int FindJob (const void *key1, const void *key2)
915
{
916
    return *(int *)key1 - ((JobList *)key2)->Number;
917
}
918
#endif
919
 
920
/*
921
 * Look up a function in the save tree
922
 */
923
 
924
FunctionList *LookUpFunction (char *name, bool AllowDot)
925
{
926
    FunctionList	**fp = (FunctionList **)NULL;
927
 
928
    if (AllowDot || (*name != '.'))
929
	fp = (FunctionList **)tfind (name, &FunctionTree, FindFunction);
930
 
931
    return fp != (FunctionList **)NULL ? *fp : (FunctionList *)NULL;
932
}
933
 
934
 
935
/*
936
 * TSEARCH compare functions for FUNCTION, ALIAS and JOB trees
937
 */
938
 
939
static int SearchFunction (const void *key1, const void *key2)
940
{
941
    return strcmp (((FunctionList *)key1)->tree->str,
942
		   ((FunctionList *)key2)->tree->str);
943
}
944
 
945
static int SearchAlias (const void *key1, const void *key2)
946
{
947
    return strcmp (((AliasList *)key1)->name, ((AliasList *)key2)->name);
948
}
949
 
950
#if (OS_TYPE != OS_DOS)
951
static int SearchJob (const void *key1, const void *key2)
952
{
953
    return ((JobList *)key1)->Number - ((JobList *)key2)->Number;
954
}
955
#endif
956
 
957
/*
958
 * SAVE/DELETE A FUNCTION
959
 */
960
 
961
/*
962
 * Save a function tree
963
 */
964
 
965
bool SaveFunction (C_Op *t)
966
{
967
    char			*name = t->str;
968
    register FunctionList	*fp;
969
    void                        (_SIGDECL *save_signal)(int);
970
    char			*sname = name;
971
 
972
/* Allow dot as the first character */
973
 
974
    if ((*name == '.') && (strlen (name) > (size_t)1))
975
	sname++;
976
 
977
    if (!IsValidAliasName (sname, FALSE))
978
    {
979
	PrintWarningMessage (BasicErrorMessage, name, LIT_Invalidfunction);
980
	return FALSE;
981
    }
982
 
983
/* Create new entry */
984
 
985
    if ((fp = (FunctionList *)GetAllocatedSpace (sizeof (FunctionList)))
986
	== (FunctionList *)NULL)
987
	return FALSE;
988
 
989
/* Delete the old function if it exists */
990
 
991
    DeleteFunction (t);
992
 
993
/* Disable signals */
994
 
995
    save_signal = signal (SIGINT, SIG_IGN);
996
    fp->tree = t;
997
    fp->Traced = FALSE;
998
 
999
/* Set up the tree */
1000
 
1001
    if (tsearch (fp, &FunctionTree, SearchFunction) != (void *)NULL)
1002
    {
1003
	SetMemoryAreaNumber ((void *)fp, 0);
1004
	SaveReleaseExecuteTree (t, SaveTreeEntry);
1005
    }
1006
 
1007
/* Restore signals */
1008
 
1009
    signal (SIGINT, save_signal);
1010
    return TRUE;
1011
}
1012
 
1013
/*
1014
 * Clean up functions on exit.  We should just delete the files, but its
1015
 * easier to delete the functions
1016
 */
1017
 
1018
void DeleteAllFunctions (void)
1019
{
1020
    void                        (_SIGDECL *save_signal)(int);
1021
 
1022
    save_signal = signal (SIGINT, SIG_IGN);
1023
    twalk (FunctionTree, DeleteAFunction);
1024
    signal (SIGINT, save_signal);
1025
}
1026
 
1027
/*
1028
 * Associate TREE WALK function to delete all functions
1029
 */
1030
 
1031
static void DeleteAFunction (const void *key, VISIT visit, int level)
1032
{
1033
    if ((visit == postorder) || (visit == leaf))
1034
	SaveReleaseExecuteTree ((*(FunctionList **)key)->tree,
1035
			        ReleaseMemoryCell);
1036
}
1037
 
1038
/*
1039
 * Delete a function tree
1040
 */
1041
 
1042
void DeleteFunction (C_Op *t)
1043
{
1044
    char			*name = t->str;
1045
    register FunctionList	*fp = LookUpFunction (name, TRUE);
1046
    void                        (_SIGDECL *save_signal)(int);
1047
 
1048
    if (fp == (FunctionList *)NULL)
1049
	return;
1050
 
1051
/* Disable signals */
1052
 
1053
    save_signal = signal (SIGINT, SIG_IGN);
1054
 
1055
/* Free the tree and delete the entry */
1056
 
1057
    tdelete (name, &FunctionTree, FindFunction);
1058
    SaveReleaseExecuteTree (fp->tree, ReleaseMemoryCell);
1059
    ReleaseMemoryCell ((void *)fp);
1060
 
1061
/* Restore signals */
1062
 
1063
    signal (SIGINT, save_signal);
1064
}
1065
 
1066
 
1067
/*
1068
 * Set ExTree areas to zero function
1069
 */
1070
 
1071
static void  SaveTreeEntry (void *s)
1072
{
1073
    SetMemoryAreaNumber (s, 0);
1074
}
1075
 
1076
/*
1077
 * Set/Free function tree area by recursively processing of tree
1078
 */
1079
 
1080
static void F_LOCAL SaveReleaseExecuteTree (C_Op *t, void (* func)(void *))
1081
{
1082
    if (t == (C_Op *)NULL)
1083
	return;
1084
 
1085
/*
1086
 * Process the tree - saving or deleting
1087
 */
1088
 
1089
    if (t->str != (char *)NULL)
1090
	(*func)((void *)t->str);
1091
 
1092
    SaveReleaseWordList (t->vars, func);
1093
    SaveReleaseWordList (t->args, func);
1094
    SaveReleaseIOActions (t->ioact, func);
1095
    SaveReleaseExecuteTree (t->left, func);
1096
    SaveReleaseExecuteTree (t->right, func);
1097
 
1098
    (*func)((void *)t);
1099
}
1100
 
1101
 
1102
/*
1103
 * Save/Release a Block of words
1104
 */
1105
 
1106
static void F_LOCAL SaveReleaseWordList (char **list, void (* func)(void *))
1107
{
1108
    char	**Slist = list;
1109
 
1110
    if (list == NOWORDS)
1111
        return;
1112
 
1113
/* Ok - save/release it */
1114
 
1115
    while (*list != NOWORD)
1116
	(*func)((void *)*(list++));
1117
 
1118
/* Handle the block itself */
1119
 
1120
    (*func)((void *)Slist);
1121
}
1122
 
1123
 
1124
/*
1125
 * Save/Release the IO Actions block
1126
 */
1127
 
1128
static void F_LOCAL SaveReleaseIOActions (IO_Actions **list, void (* func)(void *))
1129
{
1130
    IO_Actions	**Slist = list;
1131
 
1132
    if (list == (IO_Actions **)NULL)
1133
        return;
1134
 
1135
/* Ok - save/release it */
1136
 
1137
    while (*list != (IO_Actions *)NULL)
1138
    {
1139
 
1140
/*
1141
 * If this is a Here Document, we need some clever processing to stop it
1142
 * beening deleted or to delete it when the function disappears
1143
 */
1144
 
1145
	if (((*list)->io_flag & IOTYPE) == IOHERE)
1146
	{
1147
 
1148
/*
1149
 * Mark this is a function file name.  This should stop the here processing
1150
 * from deleting it
1151
 */
1152
 
1153
	    (*list)->io_flag |= IOFUNCTION;
1154
 
1155
/* If this is a delete - delete the file name */
1156
 
1157
	    if (func == ReleaseMemoryCell)
1158
		unlink ((*list)->io_name);
1159
	}
1160
 
1161
/* OK, normal processing now!! */
1162
 
1163
	(*func)((void *)(*list)->io_name);
1164
	(*func)((void *)*(list++));
1165
    }
1166
 
1167
/* Handle the block itself */
1168
 
1169
    (*func)((void *)Slist);
1170
}
1171
 
1172
 
1173
/*
1174
 * FUNCTION TREE DUPLICATION
1175
 */
1176
 
1177
/*
1178
 * Copy function tree area by recursively processing of tree
1179
 */
1180
 
1181
static C_Op * F_LOCAL DuplicateFunctionTree (C_Op *Old_t)
1182
{
1183
    C_Op	*New_t;
1184
 
1185
    if (Old_t == (C_Op *)NULL)
1186
	return (C_Op *)NULL;
1187
 
1188
/*
1189
 * This will copy function and for identifiers quite accidently
1190
 */
1191
 
1192
    New_t        = (C_Op *)DuplicateMemoryCell (Old_t);
1193
    New_t->str   = DuplicateMemoryArea (Old_t->str, char *);
1194
    New_t->vars  = DuplicateWordList (Old_t->vars);
1195
    New_t->args  = DuplicateWordList (Old_t->args);
1196
    New_t->ioact = DuplicateIOActions (Old_t->ioact);
1197
    New_t->left  = DuplicateFunctionTree (Old_t->left);
1198
    New_t->right = DuplicateFunctionTree (Old_t->right);
1199
    return New_t;
1200
}
1201
 
1202
 
1203
/*
1204
 * Duplicate a Block of words
1205
 */
1206
 
1207
static char ** F_LOCAL DuplicateWordList (char **list)
1208
{
1209
    char	**Nlist;
1210
    char	**Np;
1211
 
1212
    if ((Nlist = DuplicateMemoryArea (list, char **)) == (char **)NULL)
1213
        return NOWORDS;
1214
 
1215
/* Ok - dup it */
1216
 
1217
    for (Np = Nlist; *list != NOWORD; list++)
1218
	*(Np++) = DuplicateMemoryArea (*list, char *);
1219
 
1220
/* Terminate it */
1221
 
1222
    *Np = NOWORD;
1223
 
1224
    return Nlist;
1225
}
1226
 
1227
 
1228
/*
1229
 * Duplicate the IO Actions block
1230
 */
1231
 
1232
static IO_Actions ** F_LOCAL DuplicateIOActions (IO_Actions **list)
1233
{
1234
    IO_Actions	**Nlist;
1235
    IO_Actions	**Np;
1236
 
1237
    if ((Nlist = DuplicateMemoryArea (list,
1238
				      IO_Actions **)) == (IO_Actions **)NULL)
1239
        return (IO_Actions **)NULL;
1240
 
1241
/* Ok - dup it */
1242
 
1243
    for (Np = Nlist; *list != (IO_Actions *)NULL; list++, Np++)
1244
    {
1245
	*Np = (IO_Actions *)DuplicateMemoryCell (*list);
1246
	(*Np)->io_name = DuplicateMemoryArea ((*list)->io_name, char *);
1247
    }
1248
 
1249
/* Terminate it */
1250
 
1251
    *Np = (IO_Actions *)NULL;
1252
    return Nlist;
1253
}
1254
 
1255
 
1256
/*
1257
 * Duplicate the tree
1258
 */
1259
 
1260
C_Op		*CopyFunction (C_Op *Old_t)
1261
{
1262
    ErrorPoint	save_ErrorReturnPoint;
1263
    jmp_buf	new_ErrorReturnPoint;
1264
    C_Op	*New_t = (C_Op *)NULL;
1265
 
1266
/* Set up for error handling - like out of space */
1267
 
1268
    save_ErrorReturnPoint = e.ErrorReturnPoint;
1269
 
1270
    if (SetErrorPoint (new_ErrorReturnPoint) == 0)
1271
	New_t = DuplicateFunctionTree (Old_t);
1272
 
1273
    e.ErrorReturnPoint = save_ErrorReturnPoint;
1274
    return New_t;
1275
}
1276
 
1277
/*
1278
 * Alias processing
1279
 */
1280
 
1281
void PrintAlias (char *name)
1282
{
1283
    register AliasList	*al = LookUpAlias (name, FALSE);
1284
 
1285
    if ((al == (AliasList *)NULL) || (al->value == null))
1286
	return;
1287
 
1288
    printf (ListVarFormat, name, al->value);
1289
}
1290
 
1291
/*
1292
 * Print All Aliases
1293
 */
1294
 
1295
int  PrintAllAlias (bool tracked)
1296
{
1297
    DisplayListMode = tracked;		/* Set mode			*/
1298
 
1299
    twalk (AliasTree, DisplayAlias);
1300
    return 0;
1301
}
1302
 
1303
/*
1304
 * Save an alias
1305
 */
1306
 
1307
bool SaveAlias (char *name, char *arguments, bool tracked)
1308
{
1309
    register AliasList	*al;
1310
    void                (_SIGDECL *save_signal)(int);
1311
 
1312
 
1313
/* Create new entry */
1314
 
1315
    if (((al = (AliasList *)GetAllocatedSpace (sizeof (AliasList)))
1316
		== (AliasList *)NULL) ||
1317
	((al->name = GetAllocatedSpace (strlen (name) + 1)) == (char *)NULL))
1318
	return FALSE;
1319
 
1320
    if ((arguments != null) &&
1321
	((al->value = GetAllocatedSpace (strlen (arguments) + 1))
1322
		== (char *)NULL))
1323
	return FALSE;
1324
 
1325
/* Delete old name */
1326
 
1327
    DeleteAlias (name);
1328
 
1329
/* Disable signals */
1330
 
1331
    save_signal = signal (SIGINT, SIG_IGN);
1332
    strcpy (al->name, name);
1333
 
1334
/* Add it to the tree */
1335
 
1336
    if (tsearch (al, &AliasTree, SearchAlias) != (void *)NULL)
1337
    {
1338
	SetMemoryAreaNumber ((void *)al, 0);
1339
	SetMemoryAreaNumber ((void *)al->name, 0);
1340
 
1341
	if (arguments != null)
1342
	    SetMemoryAreaNumber ((void *)strcpy (al->value, arguments), 0);
1343
 
1344
	else
1345
	    al->value = null;
1346
 
1347
        if (tracked)
1348
	    al->AFlags = ALIAS_TRACKED;
1349
    }
1350
 
1351
 
1352
/* Restore signals */
1353
 
1354
    signal (SIGINT, save_signal);
1355
    return TRUE;
1356
}
1357
 
1358
/*
1359
 * Delete an alias
1360
 */
1361
 
1362
void DeleteAlias (char *name)
1363
{
1364
    register AliasList	**alp = (AliasList **)tfind (name, &AliasTree,
1365
						     FindAlias);
1366
    void                (_SIGDECL *save_signal)(int);
1367
    register AliasList	*al;
1368
 
1369
    if (alp == (AliasList **)NULL)
1370
	return;
1371
 
1372
/* Disable signals */
1373
 
1374
    save_signal = signal (SIGINT, SIG_IGN);
1375
 
1376
/* Delete the tree entry and release the memory */
1377
 
1378
    al = *alp;
1379
    tdelete (name, &AliasTree, FindAlias);
1380
    ReleaseMemoryCell ((void *)al->name);
1381
 
1382
    if (al->value != null)
1383
	ReleaseMemoryCell ((void *)al->value);
1384
 
1385
    ReleaseMemoryCell ((void *)al);
1386
 
1387
/* Restore signals */
1388
 
1389
    signal (SIGINT, save_signal);
1390
}
1391
 
1392
/*
1393
 * Search for an Alias
1394
 */
1395
 
1396
AliasList	*LookUpAlias (char *name, bool CreateTracked)
1397
{
1398
    AliasList	**alp = (AliasList **)tfind (name, &AliasTree, FindAlias);
1399
    char	*path;
1400
 
1401
/* If we found a tracked alias, which has been untracked, re-track it if
1402
 * necesary
1403
 */
1404
 
1405
    if ((alp != (AliasList **)NULL) && ((*alp)->value == null))
1406
    {
1407
        if (CreateTracked &&
1408
	    ((path = AllocateMemoryCell (FFNAME_MAX)) != (char *)NULL) &&
1409
	    (FindLocationOfExecutable (path, name) != EXTENSION_NOT_FOUND))
1410
        {
1411
	    SetMemoryAreaNumber ((void *)path, 0);
1412
	    (*alp)->value = PATH_TO_UNIX (path);
1413
	    return *alp;
1414
        }
1415
 
1416
        else
1417
            return (AliasList *)NULL;
1418
    }
1419
 
1420
    return (alp == (AliasList **)NULL) ? (AliasList *)NULL : *alp;
1421
}
1422
 
1423
/*
1424
 * Check for valid alias name
1425
 */
1426
 
1427
bool IsValidAliasName (char *s, bool alias)
1428
{
1429
    if (!IS_VariableFC ((int)*s) || LookUpSymbol (s))
1430
	return FALSE;
1431
 
1432
    while (IS_VariableSC ((int)*s))
1433
        ++s;
1434
 
1435
    return C2bool (!*s);
1436
}
1437
 
1438
/*
1439
 * Untrack all Aliases
1440
 */
1441
 
1442
void UnTrackAllAliases (void)
1443
{
1444
    twalk (AliasTree, UntrackAlias);
1445
}
1446
 
1447
/*
1448
 * The associate TWALK function
1449
 */
1450
 
1451
static void  UntrackAlias (const void *key, VISIT visit, int level)
1452
{
1453
    AliasList	*al = *(AliasList **)key;
1454
 
1455
    if (((visit == postorder) || (visit == leaf)) &&
1456
	(al->AFlags & ALIAS_TRACKED) && (al->value != null))
1457
    {
1458
	 ReleaseMemoryCell ((void *)al->value);
1459
	 al->value = null;
1460
    }
1461
}
1462
 
1463
/*
1464
 * Look up a job in the save tree
1465
 */
1466
 
1467
#if (OS_TYPE != OS_DOS)
1468
JobList *LookUpJob (int JobNumber)
1469
{
1470
    JobList	**jp = (JobList **)tfind (&JobNumber, &JobTree, FindJob);
1471
 
1472
    return jp != (JobList **)NULL ? *jp : (JobList *)NULL;
1473
}
1474
 
1475
/*
1476
 * Search for a job
1477
 */
1478
 
1479
JobList	*SearchForJob (char *String)
1480
{
1481
    JobSearchKey = String;
1482
    JobSearchEntry = (JobList **)NULL;
1483
 
1484
    if ((strcmp (String, "%") == 0) || (strcmp (String, "+") == 0))
1485
	return LookUpJob (CurrentJob);
1486
 
1487
    else if (strcmp (String, "-") == 0)
1488
	return LookUpJob (PreviousJob);
1489
 
1490
/* Search for it */
1491
 
1492
    twalk (JobTree, FindJobByString);
1493
    return JobSearchEntry != (JobList **)NULL ? *JobSearchEntry
1494
					      : (JobList *)NULL;
1495
}
1496
 
1497
/*
1498
 * Delete a job by Session ID
1499
 */
1500
 
1501
void	DeleteJobBySession (unsigned short SessionId)
1502
{
1503
    register JobList	**jpp = (JobList **)tfind (&SessionId, &JobTree,
1504
						   FindJobBySession);
1505
 
1506
    if (jpp != (JobList **)NULL)
1507
	DeleteJob ((*jpp)->pid);
1508
}
1509
 
1510
/*
1511
 * Delete a job by Process ID
1512
 */
1513
 
1514
void DeleteJob (PID pid)
1515
{
1516
    register JobList	**jpp = (JobList **)tfind (&pid, &JobTree,
1517
						   FindJobByPID);
1518
    void                (_SIGDECL *save_signal)(int);
1519
    JobList		*jp;
1520
 
1521
    if (jpp == (JobList **)NULL)
1522
	return;
1523
 
1524
/* Disable signals */
1525
 
1526
    save_signal = signal (SIGINT, SIG_IGN);
1527
    jp = *jpp;
1528
 
1529
/* Free the tree and delete the entry */
1530
 
1531
    tdelete (&pid, &JobTree, FindJobByPID);
1532
 
1533
    if (jp->Number == PreviousJob)
1534
	PreviousJob = 0;
1535
 
1536
    if (jp->Number == CurrentJob)
1537
	CurrentJob = PreviousJob;
1538
 
1539
    ReleaseMemoryCell ((void *)jp->Command);
1540
    ReleaseMemoryCell ((void *)jp);
1541
 
1542
/* Restore signals */
1543
 
1544
    signal (SIGINT, save_signal);
1545
}
1546
 
1547
/*
1548
 * Save a job ID
1549
 */
1550
 
1551
int	AddNewJob (PID pid, unsigned short SessionId, char *command)
1552
{
1553
    register JobList	*jp;
1554
    static int		JobNumber = 1;
1555
    void                (_SIGDECL *save_signal)(int);
1556
    char		*tmp;
1557
 
1558
/* We if we can get the full command */
1559
 
1560
   if ((tmp = GetLastHistoryString ()) != (char *)NULL)
1561
       command = tmp;
1562
 
1563
/* Create new entry */
1564
 
1565
    if (((jp = (JobList *)GetAllocatedSpace (sizeof (JobList))) == (JobList *)NULL) ||
1566
	((jp->Command = GetAllocatedSpace (strlen (command) + 1)) == (char *)NULL))
1567
	return 0;
1568
 
1569
/* Get the next available job number */
1570
 
1571
    while (TRUE)
1572
    {
1573
	jp->pid = pid;
1574
	jp->Number = JobNumber++;
1575
	jp->SessionId = SessionId;
1576
 
1577
	if (JobNumber > 32000)
1578
	    JobNumber = 1;
1579
 
1580
	if (tfind (jp, &JobTree, SearchJob) == (void *)NULL)
1581
	    break;
1582
    }
1583
 
1584
/* Disable signals */
1585
 
1586
    save_signal = signal (SIGINT, SIG_IGN);
1587
 
1588
    if (tsearch (jp, &JobTree, SearchJob) != (void *)NULL)
1589
    {
1590
	SetMemoryAreaNumber ((void *)jp, 0);
1591
	SetMemoryAreaNumber ((void *)strcpy (jp->Command, command), 0);
1592
	PATH_TO_UNIX (jp->Command);
1593
    }
1594
 
1595
/* Restore signals */
1596
 
1597
    signal (SIGINT, save_signal);
1598
 
1599
    PreviousJob = CurrentJob;
1600
    return CurrentJob = jp->Number;
1601
}
1602
 
1603
/*
1604
 * Display Jobs
1605
 */
1606
 
1607
int PrintJobs (bool Mode)
1608
{
1609
    DisplayListMode = Mode;		/* Set mode			*/
1610
 
1611
    twalk (JobTree, DisplayJob);
1612
    return 0;
1613
}
1614
 
1615
/*
1616
 * Count the number of active jobs
1617
 */
1618
 
1619
int NumberOfActiveJobs (void)
1620
{
1621
    NumberOfJobs = 0;
1622
 
1623
    twalk (JobTree, CountJob);
1624
    return NumberOfJobs;
1625
}
1626
#endif
1627
 
1628
/*
1629
 * OS2 1.x - Parse the kernel process information
1630
 */
1631
 
1632
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_16)
1633
static bool F_LOCAL Parse_V1ProcessTable (UCHAR * bBuf, V1ProcessStatus_t *pi)
1634
{
1635
    USHORT	sel, offs;
1636
    USHORT	type, tpid;
1637
    USHORT	count, kount;
1638
    UCHAR	buffer[256];
1639
    UCHAR	*cptr, *ptr;
1640
 
1641
    ptr = bBuf;
1642
    sel = SELECTOROF (ptr);
1643
 
1644
    while ((type = *(USHORT *) ptr) != 0xFFFFU )
1645
    {
1646
	ptr += 2;
1647
	offs = *(USHORT *) ptr;
1648
	ptr += 2;
1649
 
1650
	switch ( type )
1651
	{
1652
	    case 0:					/* Process */
1653
		if (pi->N_Processes >= pi->M_Processes)
1654
		{
1655
		    V1Process_t	**newp = (V1Process_t **)ReAllocateSpace (
1656
		    				(void *)pi->V1Processes,
1657
			       			(pi->M_Processes + 50) *
1658
						    sizeof (V1Process_t *));
1659
 
1660
		    if (newp == (V1Process_t **)NULL)
1661
			return TRUE;
1662
 
1663
		    pi->V1Processes = newp;
1664
		    pi->M_Processes += 50;
1665
		}
1666
 
1667
/* Create the process entry */
1668
 
1669
		pi->V1Processes[pi->N_Processes] =
1670
		    (V1Process_t *) GetAllocatedSpace (sizeof (V1Process_t));
1671
 
1672
		if (pi->V1Processes[pi->N_Processes] == (V1Process_t *)NULL)
1673
		    return TRUE;
1674
 
1675
		pi->V1Processes[pi->N_Processes]->pid = *(USHORT *)ptr;
1676
		ptr += 2;
1677
		pi->V1Processes[pi->N_Processes]->ppid = *(USHORT *) ptr;
1678
		ptr += 2;
1679
		ptr += 2;
1680
		pi->V1Processes[pi->N_Processes]->modhandle = *(USHORT *) ptr;
1681
		pi->V1Processes[pi->N_Processes++]->threads = 0;
1682
 
1683
		break;
1684
 
1685
	    case 1:				 /* Thread	 */
1686
		ptr += 2;
1687
		tpid = *(USHORT *) ptr;
1688
 
1689
/* Increment the thread count for the process */
1690
 
1691
		for (count = 0; count < pi->N_Processes; count++)
1692
		{
1693
		    if (pi->V1Processes[count]->pid == tpid)
1694
		    {
1695
			++pi->V1Processes[count]->threads;
1696
			break;
1697
		    }
1698
		}
1699
 
1700
		break;
1701
 
1702
	    case 2:					/* module	*/
1703
		if (pi->N_Modules >= pi->M_Modules)
1704
		{
1705
		    V1Module_t	**newm = (V1Module_t **)ReAllocateSpace (
1706
		    				(void *)pi->V1Modules,
1707
						(pi->M_Modules + 50) *
1708
						    sizeof (V1Module_t *));
1709
 
1710
		    if (newm == (V1Module_t **)NULL)
1711
			return TRUE;
1712
 
1713
		    pi->V1Modules = newm;
1714
		    pi->M_Modules += 50;
1715
		}
1716
 
1717
		pi->V1Modules[pi->N_Modules]
1718
		    = (V1Module_t *)GetAllocatedSpace (sizeof(V1Module_t));
1719
 
1720
		if (pi->V1Modules[pi->N_Modules] == (V1Module_t *)NULL)
1721
		    return TRUE;
1722
 
1723
		pi->V1Modules[pi->N_Modules]->modhandle = *(USHORT *) ptr;
1724
		ptr += 2;
1725
		pi->V1Modules[pi->N_Modules]->max_dependents = *(USHORT *) ptr;
1726
		ptr += 2;
1727
		ptr += 2;
1728
		ptr += 2;
1729
 
1730
		if (pi->V1Modules[pi->N_Modules] -> max_dependents)
1731
		    ptr += (pi->V1Modules[pi->N_Modules] -> max_dependents) * 2;
1732
 
1733
		for (cptr = buffer; *cptr++ = *ptr++;)
1734
		    continue;
1735
 
1736
		if ((pi->V1Modules[pi->N_Modules]->modname =
1737
			StringCopy (buffer)) == null)
1738
		    return 1;
1739
 
1740
		++pi->N_Modules;
1741
 
1742
		break;
1743
 
1744
	    case 3:				/* system semaphore	*/
1745
	    case 4:				/* shared memory	*/
1746
		break;
1747
	}
1748
 
1749
	ptr = MAKEP(sel, offs);
1750
    }
1751
 
1752
/* Count modules */
1753
 
1754
    for (count = 0; count < pi->N_Processes; count++)
1755
    {
1756
	for (kount = 0; kount < pi->N_Modules; kount++)
1757
	{
1758
	    if (pi->V1Processes[count]->modhandle ==
1759
		pi->V1Modules[kount]->modhandle)
1760
	    {
1761
		pi->V1Processes[count]->module = kount;
1762
		break;
1763
	    }
1764
	}
1765
    }
1766
 
1767
/* Count children */
1768
 
1769
    for (count = 0; count < pi->N_Processes; count++)
1770
    {
1771
	for (kount = 0; kount < pi->N_Processes; kount++)
1772
	{
1773
	    if (pi->V1Processes[count]->pid == pi->V1Processes[kount]->ppid)
1774
		(pi->V1Processes[count]->children)++;
1775
	}
1776
    }
1777
 
1778
    return FALSE;
1779
}
1780
 
1781
/*
1782
 * Process the process information
1783
 */
1784
 
1785
static void F_LOCAL PrintV1ProcessTree (pid_t pid, int indent,
1786
					V1ProcessStatus_t *pi)
1787
{
1788
    USHORT	count;
1789
    UCHAR	*mName, pName[256];
1790
 
1791
    for (count = 0; count < pi->N_Processes; count++)
1792
    {
1793
	if ((indent &&    (pi->V1Processes[count]->ppid == (USHORT)pid)) ||
1794
	    ((!indent) && (pi->V1Processes[count]->pid == (USHORT)pid)))
1795
	{
1796
	    if (pi->V1Processes[count]->module)
1797
	    {
1798
		mName = pi->V1Modules[pi->V1Processes[count]->module]->modname;
1799
		DosGetModName (pi->V1Processes[count]->modhandle,
1800
			       sizeof(pName), pName);
1801
	    }
1802
 
1803
	    else
1804
	    {
1805
		mName = "unknown";  /* Zombie process,	*/
1806
		pName[0] = 0;
1807
	    }
1808
 
1809
	    printf ("%5d %5d %3d %-8s %*s%s\n", pi->V1Processes[count]->pid,
1810
		    pi->V1Processes[count]->ppid,
1811
		    pi->V1Processes[count]->threads, mName, indent, "", pName);
1812
 
1813
	    PrintV1ProcessTree (pi->V1Processes[count]->pid, indent + 2, pi);
1814
	}
1815
    }
1816
}
1817
 
1818
 
1819
static int SortV1Processes (void *p1, void *p2)
1820
{
1821
    return (*(V1Process_t **)p1)->pid - (*(V1Process_t **)p2)->pid;
1822
}
1823
#endif
1824
 
1825
/*
1826
 * OS/2 2.x 32-bit version - Display Process Tree
1827
 */
1828
 
1829
#if (OS_TYPE == OS_OS2)
1830
static void F_LOCAL V2_DisplayProcessTree (USHORT pid, USHORT indent,
1831
					   V2ProcessStatus_t *ps)
1832
{
1833
    V2Process_t		*proc;
1834
    UCHAR		name[FFNAME_MAX];
1835
    USHORT		prty;
1836
 
1837
/* Not sure if there isn't another termination method	*/
1838
 
1839
    for (proc = PTR (ps->ppi); (proc->ulEndIndicator != PROCESS_END_INDICATOR);
1840
         proc = (V2Process_t *) PTR (proc->ptiFirst + proc->usThreadCount))
1841
    {
1842
	if ((indent    && (proc->pidParent == pid)) ||
1843
	    ((!indent) && (proc->pid == pid)))
1844
	{
1845
#  if (OS_SIZE == OS_32)
1846
	    if (DosQueryModuleName (proc->hModRef, sizeof (name), name))
1847
#  else
1848
	    if (DosGetModName (proc->hModRef, sizeof (name), name))
1849
#  endif
1850
		strcpy(name, "<unknown>");
1851
 
1852
	    if (Dos32GetPrty (PRTYS_PROCESS, &prty, proc->pid))
1853
		prty = 0;
1854
 
1855
	    printf ("%5d %5d %3d %04x %*s%s\n", proc->pid, proc->pidParent,
1856
	    	    proc->usThreadCount, prty, indent, "", name);
1857
 
1858
	    V2_DisplayProcessTree (proc->pid, indent + 2, ps);
1859
	}
1860
    }
1861
}
1862
 
1863
/*
1864
 * Print the Process Tree
1865
 */
1866
 
1867
int PrintProcessTree (pid_t pid)
1868
{
1869
#  if (OS_SIZE == OS_16)
1870
    USHORT		rc;
1871
 
1872
/* Switch on release number */
1873
 
1874
    if (_osmajor < 20)
1875
    {
1876
	UCHAR			*pBuf = GetAllocatedSpace (0x2000);
1877
	USHORT			count;
1878
	V1ProcessStatus_t	pi;
1879
 
1880
	pi.M_Processes = pi.M_Modules = pi.N_Processes = pi.N_Modules = 0;
1881
	pi.V1Processes = NULL;
1882
	pi.V1Modules = NULL;
1883
 
1884
	if (pBuf == (UCHAR *)NULL)
1885
	    return 1;
1886
 
1887
	if (rc = Dos32QProcStatus (pBuf, 0x2000))
1888
	    return PrintWarningMessage ("jobs: DosQProcStatus failed\n%s",
1889
	    				GetOSSystemErrorMessage (rc));
1890
 
1891
	if (Parse_V1ProcessTable (pBuf, &pi))
1892
	   return 1;
1893
 
1894
	ReleaseMemoryCell ((void *)pBuf);
1895
 
1896
	qsort ((void *)pi.V1Processes, pi.N_Processes, sizeof (V1Process_t *),
1897
		SortV1Processes);
1898
 
1899
        puts ("   PID  PPID TC Name     Program");
1900
	PrintV1ProcessTree (pid, 0, &pi);
1901
 
1902
	for (count = 0; count < pi.N_Processes; count++)
1903
	    ReleaseMemoryCell ((void *)pi.V1Processes[count]);
1904
 
1905
	for (count = 0; count < pi.N_Modules; count++)
1906
	{
1907
	    ReleaseMemoryCell ((void *)pi.V1Modules[count] -> modname);
1908
	    ReleaseMemoryCell ((void *)pi.V1Modules[count]);
1909
	}
1910
 
1911
	ReleaseMemoryCell ((void *)pi.V1Processes);
1912
	ReleaseMemoryCell ((void *)pi.V1Modules);
1913
    }
1914
 
1915
/*
1916
 * OS2 2.0 - grap space, get the information and display it
1917
 */
1918
 
1919
    else
1920
#  endif
1921
#  if defined (__WATCOMC__)
1922
    {
1923
	int	res;
1924
 
1925
	if ((res = spawnlp (P_WAIT, "ps.exe", "ps", IntegerToString (pid),
1926
			    (char *)NULL)) < 0)
1927
	    return PrintWarningMessage ("jobs: cannot find ps.exe\n");
1928
 
1929
	else if (res)
1930
	    return 1;
1931
    }
1932
#  else
1933
    {
1934
	V2ProcessStatus_t	*ps;
1935
 
1936
	if ((ps = GetProcessStatus ("jobs")) == (V2ProcessStatus_t *)NULL)
1937
	    return 1;
1938
 
1939
        puts ("   PID  PPID TC PRI  Program");
1940
	V2_DisplayProcessTree (pid, 0, ps);
1941
	ReleaseMemoryCell ((void *)ps);
1942
    }
1943
#  endif
1944
    return 0;
1945
}
1946
 
1947
/*
1948
 * Get OS/2 2.x Process Structure
1949
 */
1950
 
1951
static V2ProcessStatus_t * F_LOCAL GetProcessStatus (char *name)
1952
{
1953
    OSCALL_RET		rc;
1954
    V2ProcessStatus_t	*ps;
1955
 
1956
    if ((ps = (V2ProcessStatus_t *)GetAllocatedSpace (0x8000))
1957
	    == (V2ProcessStatus_t *)NULL)
1958
	return (V2ProcessStatus_t *)NULL;
1959
 
1960
    if ((rc = Dos32QProcStatus (ps, 0x8000)))
1961
    {
1962
	PrintWarningMessage ("%s: DosQProcStatus failed\n%s", name,
1963
			     GetOSSystemErrorMessage (rc));
1964
	return (V2ProcessStatus_t *)NULL;
1965
    }
1966
 
1967
    return ps;
1968
}
1969
#endif
1970
 
1971
/*
1972
 * A unix version of print process tree
1973
 */
1974
 
1975
#if (OS_TYPE == OS_UNIX)
1976
int PrintProcessTree (pid_t pid)
1977
{
1978
    return  system ("ps") ? PrintWarningMessage ("jobs: cannot find ps\n")
1979
			  : 0;
1980
}
1981
#endif
1982
 
1983
/*
1984
 * A sort of times is available for OS/2. Not quite the complete UNIX
1985
 * emulation, since it only reports current children.  However!
1986
 * I think the times in the process structure are in 1/100th second.
1987
 */
1988
 
1989
#if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32)
1990
int PrintTimes (void)
1991
{
1992
    V2ProcessStatus_t	*ps;
1993
    V2Process_t		*ppiLocal;
1994
    V2Thread_t		*ptiCurrent;
1995
    time_t		*Utime;
1996
    time_t		*Stime;
1997
    int			i;
1998
    USHORT		pid = getpid ();
1999
    time_t		tms_utime = 0;
2000
    time_t		tms_stime = 0;
2001
    time_t		tms_cutime = 0;
2002
    time_t		tms_cstime = 0;
2003
 
2004
/* Initialise */
2005
 
2006
    if ((ps = GetProcessStatus ("times")) == (V2ProcessStatus_t *)NULL)
2007
	return 1;
2008
 
2009
/* Scan the process tree */
2010
 
2011
    for (ppiLocal = ps->ppi;
2012
	 (ppiLocal->ulEndIndicator != PROCESS_END_INDICATOR);
2013
         ppiLocal = (V2Process_t *) (ppiLocal->ptiFirst +
2014
	 			     ppiLocal->usThreadCount))
2015
    {
2016
	if (ppiLocal->pidParent == pid)
2017
	{
2018
	    Utime = &tms_cutime;
2019
	    Stime = &tms_cstime;
2020
	}
2021
 
2022
	else if (ppiLocal->pid == pid)
2023
	{
2024
	    Utime = &tms_utime;
2025
	    Stime = &tms_stime;
2026
	}
2027
 
2028
/* If neither - skip */
2029
 
2030
	else
2031
	    continue;
2032
 
2033
/* Process threads */
2034
 
2035
	ptiCurrent = ppiLocal->ptiFirst;
2036
 
2037
	for (i = 0; i < ppiLocal->usThreadCount; i++, ptiCurrent++)
2038
	{
2039
	    *Utime += ptiCurrent->ulUserTime;
2040
	    *Stime += ptiCurrent->ulSysTime;
2041
	}
2042
    }
2043
 
2044
/* Dump the info */
2045
 
2046
    printf ("%ldm%.2ld.%.2lds %ldm%ld.%.2lds\n",
2047
	    tms_utime / 6000L,  (tms_utime % 6000L) / 100L,  tms_utime % 100L,
2048
	    tms_stime / 6000L,  (tms_stime % 6000L) / 100L,  tms_stime % 100L);
2049
    printf ("%ldm%.2ld.%.2lds %ldm%ld.%.2lds\n",
2050
	    tms_cutime / 6000L, (tms_cutime % 6000L) / 100L, tms_cutime % 100L,
2051
	    tms_cstime / 6000L, (tms_cstime % 6000L) / 100L, tms_cstime % 100L);
2052
 
2053
    return 0;
2054
}
2055
#endif
2056
 
2057
/* NT Version */
2058
 
2059
#if (OS_TYPE == OS_NT)
2060
int PrintTimes (void)
2061
{
2062
    FILETIME	CreationTime;
2063
    FILETIME	ExitTime;
2064
    FILETIME	KernelTime;
2065
    FILETIME	UserTime;
2066
 
2067
    if (!GetProcessTimes (0, &CreationTime, &ExitTime, &KernelTime, &UserTime))
2068
	return PrintWarningMessage ("times: GetProcesTimes failed\n%s",
2069
				    GetOSSystemErrorMessage (GetLastError ()));
2070
 
2071
    printf ("Kernel Time = %ld %ld\n", KernelTime.dwHighDateTime,
2072
	    KernelTime.dwLowDateTime);
2073
    printf ("User Time   = %ld %ld\n", UserTime.dwHighDateTime,
2074
	    UserTime.dwLowDateTime);
2075
 
2076
    return 0;
2077
}
2078
#endif
2079
 
2080
/* UNIX Version */
2081
 
2082
#if (OS_TYPE == OS_UNIX)
2083
int PrintTimes (void)
2084
{
2085
    struct tms		tms;
2086
 
2087
    times (&tms);
2088
 
2089
    printf ("%dm%.2d.%.2ds %dm%d.%.2ds\n%dm%.2d.%.2ds %dm%d.%.2ds\n",
2090
	    tms.tms_utime / (60L * (long)CLK_TCK),
2091
	      (tms.tms_utime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
2092
	      tms.tms_utime % (long)CLK_TCK,
2093
	    tms.tms_stime / (60L * (long)CLK_TCK),
2094
	      (tms.tms_stime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
2095
	      tms.tms_stime % (long)CLK_TCK,
2096
	    tms.tms_cutime / (60L * (long)CLK_TCK),
2097
	      (tms.tms_cutime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
2098
	      tms.tms_cutime % (long)CLK_TCK,
2099
	    tms.tms_cstime / (60L * (long)CLK_TCK),
2100
	      (tms.tms_cstime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
2101
	      tms.tms_cstime % (long)CLK_TCK);
2102
 
2103
    return 0;
2104
}
2105
#endif
2106
 
2107
/*
2108
 * Specials for EMX
2109
 */
2110
 
2111
#if defined (__EMX__) && (OS_TYPE == OS_OS2)
2112
USHORT	Dos32GetPrty (USHORT usScope, PUSHORT pusPriority, USHORT pid)
2113
{
2114
    return ((USHORT)
2115
	    (_THUNK_PROLOG (2 + 4 + 2);
2116
	     _THUNK_SHORT (usScope);
2117
	     _THUNK_FLAT (pusPriority);
2118
	     _THUNK_SHORT (pid);
2119
	     _THUNK_CALL (Dos16GetPrty)));
2120
}
2121
 
2122
USHORT	Dos32QProcStatus (PVOID pvProcData, USHORT usSize)
2123
{
2124
    return ((USHORT)
2125
	    (_THUNK_PROLOG (4 + 2);
2126
	     _THUNK_FLAT (pvProcData);
2127
	     _THUNK_SHORT (usSize);
2128
	     _THUNK_CALL (Dos16QProcStatus)));
2129
}
2130
#endif