1 | /* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.h,v 1.4 1997-12-13 18:41:33 ghudson Exp $ */ |
---|
2 | /* |
---|
3 | * sh.h: Catch it all globals and includes file! |
---|
4 | */ |
---|
5 | /*- |
---|
6 | * Copyright (c) 1980, 1991 The Regents of the University of California. |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer in the |
---|
16 | * documentation and/or other materials provided with the distribution. |
---|
17 | * 3. All advertising materials mentioning features or use of this software |
---|
18 | * must display the following acknowledgement: |
---|
19 | * This product includes software developed by the University of |
---|
20 | * California, Berkeley and its contributors. |
---|
21 | * 4. Neither the name of the University nor the names of its contributors |
---|
22 | * may be used to endorse or promote products derived from this software |
---|
23 | * without specific prior written permission. |
---|
24 | * |
---|
25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
35 | * SUCH DAMAGE. |
---|
36 | */ |
---|
37 | #ifndef _h_sh |
---|
38 | #define _h_sh |
---|
39 | |
---|
40 | #include "config.h" |
---|
41 | |
---|
42 | #ifndef EXTERN |
---|
43 | # define EXTERN extern |
---|
44 | #endif /* EXTERN */ |
---|
45 | /* |
---|
46 | * Sanity |
---|
47 | */ |
---|
48 | #if defined(_POSIX_SOURCE) && !defined(POSIX) |
---|
49 | # define POSIX |
---|
50 | #endif |
---|
51 | |
---|
52 | #if defined(POSIXJOBS) && !defined(BSDJOBS) |
---|
53 | # define BSDJOBS |
---|
54 | #endif |
---|
55 | |
---|
56 | #if defined(POSIXSIGS) && !defined(BSDSIGS) |
---|
57 | # define BSDSIGS |
---|
58 | #endif |
---|
59 | |
---|
60 | #ifdef SHORT_STRINGS |
---|
61 | typedef short Char; |
---|
62 | # define SAVE(a) (Strsave(str2short(a))) |
---|
63 | #else |
---|
64 | typedef char Char; |
---|
65 | # define SAVE(a) (strsave(a)) |
---|
66 | #endif |
---|
67 | |
---|
68 | #ifdef PURIFY |
---|
69 | /* Re-define those, cause purify might use them */ |
---|
70 | # define xprintf printf |
---|
71 | # define xsprintf sprintf |
---|
72 | # define xvprintf vprintf |
---|
73 | /* exit normally, allowing purify to trace leaks */ |
---|
74 | # define _exit exit |
---|
75 | #endif /* PURIFY */ |
---|
76 | |
---|
77 | /* |
---|
78 | * If your compiler complains, then you can either |
---|
79 | * throw it away and get gcc or, use the following define |
---|
80 | * and get rid of the typedef. |
---|
81 | * [The 4.2/3BSD vax compiler does not like that] |
---|
82 | */ |
---|
83 | #ifdef SIGVOID |
---|
84 | # if (defined(vax) || defined(uts)) && !defined(__GNUC__) |
---|
85 | # define sigret_t void |
---|
86 | # else |
---|
87 | typedef void sigret_t; |
---|
88 | # endif |
---|
89 | #else |
---|
90 | typedef int sigret_t; |
---|
91 | #endif /* SIGVOID */ |
---|
92 | |
---|
93 | |
---|
94 | /* |
---|
95 | * Fundamental definitions which may vary from system to system. |
---|
96 | * |
---|
97 | * BUFSIZE The i/o buffering size; also limits word size |
---|
98 | * MAILINTVL How often to mailcheck; more often is more expensive |
---|
99 | */ |
---|
100 | #ifdef BUFSIZE |
---|
101 | # if BUFSIZE < 1024 |
---|
102 | # undef BUFSIZE |
---|
103 | # define BUFSIZE 1024 /* buffer size should be no less than this */ |
---|
104 | # endif |
---|
105 | #else |
---|
106 | # define BUFSIZE 1024 |
---|
107 | #endif /* BUFSIZE */ |
---|
108 | |
---|
109 | #define FORKSLEEP 10 /* delay loop on non-interactive fork failure */ |
---|
110 | #define MAILINTVL 600 /* 10 minutes */ |
---|
111 | |
---|
112 | #ifndef INBUFSIZE |
---|
113 | # define INBUFSIZE 2*BUFSIZE /* Num input characters on the command line */ |
---|
114 | #endif /* INBUFSIZE */ |
---|
115 | |
---|
116 | |
---|
117 | /* |
---|
118 | * What our builtin echo looks like |
---|
119 | */ |
---|
120 | #define NONE_ECHO 0 |
---|
121 | #define BSD_ECHO 1 |
---|
122 | #define SYSV_ECHO 2 |
---|
123 | #define BOTH_ECHO (BSD_ECHO|SYSV_ECHO) |
---|
124 | |
---|
125 | #ifndef ECHO_STYLE |
---|
126 | # if SYSVREL > 0 |
---|
127 | # define ECHO_STYLE SYSV_ECHO |
---|
128 | # else /* SYSVREL == 0 */ |
---|
129 | # define ECHO_STYLE BSD_ECHO |
---|
130 | # endif /* SYSVREL */ |
---|
131 | #endif /* ECHO_STYLE */ |
---|
132 | |
---|
133 | /* |
---|
134 | * The shell moves std in/out/diag and the old std input away from units |
---|
135 | * 0, 1, and 2 so that it is easy to set up these standards for invoked |
---|
136 | * commands. |
---|
137 | */ |
---|
138 | #define FSHTTY 15 /* /dev/tty when manip pgrps */ |
---|
139 | #define FSHIN 16 /* Preferred desc for shell input */ |
---|
140 | #define FSHOUT 17 /* ... shell output */ |
---|
141 | #define FSHDIAG 18 /* ... shell diagnostics */ |
---|
142 | #define FOLDSTD 19 /* ... old std input */ |
---|
143 | |
---|
144 | #ifdef PROF |
---|
145 | #define xexit(n) done(n) |
---|
146 | #endif |
---|
147 | |
---|
148 | #ifdef cray |
---|
149 | # define word word_t /* sys/types.h defines word.. bad move! */ |
---|
150 | #endif |
---|
151 | |
---|
152 | #include <sys/types.h> |
---|
153 | |
---|
154 | #ifdef cray |
---|
155 | # undef word |
---|
156 | #endif |
---|
157 | |
---|
158 | /* |
---|
159 | * Path separator in environment variables |
---|
160 | */ |
---|
161 | #ifndef PATHSEP |
---|
162 | # ifdef __EMX__ |
---|
163 | # define PATHSEP ';' |
---|
164 | # else /* unix */ |
---|
165 | # define PATHSEP ':' |
---|
166 | # endif /* __EMX__ */ |
---|
167 | #endif /* !PATHSEP */ |
---|
168 | |
---|
169 | /* |
---|
170 | * This macro compares the st_dev field of struct stat. On aix on ibmESA |
---|
171 | * st_dev is a structure, so comparison does not work. |
---|
172 | */ |
---|
173 | #ifndef DEV_DEV_COMPARE |
---|
174 | # define DEV_DEV_COMPARE(x,y) ((x) == (y)) |
---|
175 | #endif /* DEV_DEV_COMPARE */ |
---|
176 | |
---|
177 | #ifdef _SEQUENT_ |
---|
178 | # include <sys/procstats.h> |
---|
179 | #endif /* _SEQUENT_ */ |
---|
180 | #if defined(POSIX) || SYSVREL > 0 |
---|
181 | # include <sys/times.h> |
---|
182 | #endif /* POSIX || SYSVREL > 0 */ |
---|
183 | |
---|
184 | #ifdef NLS |
---|
185 | # include <locale.h> |
---|
186 | #endif |
---|
187 | |
---|
188 | #if !defined(_MINIX) && !defined(_VMS_POSIX) |
---|
189 | #include <sys/param.h> |
---|
190 | #endif /* _MINIX && vmsposix atp */ |
---|
191 | #include <sys/stat.h> |
---|
192 | |
---|
193 | #if defined(BSDTIMES) || defined(BSDLIMIT) |
---|
194 | # include <sys/time.h> |
---|
195 | # include <sys/resource.h> |
---|
196 | #endif /* BSDTIMES */ |
---|
197 | |
---|
198 | #ifndef POSIX |
---|
199 | # ifdef TERMIO |
---|
200 | # include <termio.h> |
---|
201 | # else /* SGTTY */ |
---|
202 | # include <sgtty.h> |
---|
203 | # endif /* TERMIO */ |
---|
204 | #else /* POSIX */ |
---|
205 | # include <termios.h> |
---|
206 | # if SYSVREL > 3 |
---|
207 | # undef TIOCGLTC /* we don't need those, since POSIX has them */ |
---|
208 | # undef TIOCSLTC |
---|
209 | # undef CSWTCH |
---|
210 | # define CSWTCH _POSIX_VDISABLE /* So job control works */ |
---|
211 | # endif /* SYSVREL > 3 */ |
---|
212 | #endif /* POSIX */ |
---|
213 | #ifdef DGUX |
---|
214 | # undef CSWTCH |
---|
215 | # define CSWTCH _POSIX_VDISABLE /* So job control works */ |
---|
216 | #endif /* DGUX */ |
---|
217 | |
---|
218 | #ifdef sonyrisc |
---|
219 | # include <sys/ttold.h> |
---|
220 | #endif /* sonyrisc */ |
---|
221 | |
---|
222 | #ifdef POSIX |
---|
223 | /* |
---|
224 | * We should be using setpgid and setpgid |
---|
225 | * by now, but in some systems we use the |
---|
226 | * old routines... |
---|
227 | */ |
---|
228 | # define getpgrp __getpgrp |
---|
229 | # define setpgrp __setpgrp |
---|
230 | # include <unistd.h> |
---|
231 | # undef getpgrp |
---|
232 | # undef setpgrp |
---|
233 | extern int getpgrp(); |
---|
234 | extern int setpgrp(); |
---|
235 | |
---|
236 | /* |
---|
237 | * the gcc+protoize version of <stdlib.h> |
---|
238 | * redefines malloc(), so we define the following |
---|
239 | * to avoid it. |
---|
240 | */ |
---|
241 | # ifdef linux |
---|
242 | # define NO_FIX_MALLOC |
---|
243 | # include <stdlib.h> |
---|
244 | # else /* linux */ |
---|
245 | # define _GNU_STDLIB_H |
---|
246 | # define malloc __malloc |
---|
247 | # define free __free |
---|
248 | # define calloc __calloc |
---|
249 | # define realloc __realloc |
---|
250 | # include <stdlib.h> |
---|
251 | # undef malloc |
---|
252 | # undef free |
---|
253 | # undef calloc |
---|
254 | # undef realloc |
---|
255 | # endif /* linux */ |
---|
256 | # include <limits.h> |
---|
257 | #endif /* POSIX */ |
---|
258 | |
---|
259 | #if SYSVREL > 0 || defined(_IBMR2) || defined(_MINIX) |
---|
260 | # if !defined(pyr) && !defined(stellar) |
---|
261 | # include <time.h> |
---|
262 | # ifdef _MINIX |
---|
263 | # define HZ CLOCKS_PER_SEC |
---|
264 | # endif /* _MINIX */ |
---|
265 | # endif /* !pyr && !stellar */ |
---|
266 | #endif /* SYSVREL > 0 || _IBMR2 */ |
---|
267 | |
---|
268 | #if !((defined(SUNOS4) || defined(_MINIX)) && defined(TERMIO)) |
---|
269 | # if !defined(COHERENT) && !defined(_VMS_POSIX) |
---|
270 | # include <sys/ioctl.h> |
---|
271 | # endif |
---|
272 | #endif |
---|
273 | |
---|
274 | #if !defined(FIOCLEX) && defined(SUNOS4) |
---|
275 | # include <sys/filio.h> |
---|
276 | #endif /* !FIOCLEX && SUNOS4 */ |
---|
277 | |
---|
278 | #if !defined(_MINIX) && !defined(COHERENT) |
---|
279 | # include <sys/file.h> |
---|
280 | #endif /* !_MINIX && !COHERENT */ |
---|
281 | |
---|
282 | #if !defined(O_RDONLY) || !defined(O_NDELAY) |
---|
283 | # include <fcntl.h> |
---|
284 | #endif |
---|
285 | |
---|
286 | #include <errno.h> |
---|
287 | |
---|
288 | #include <setjmp.h> |
---|
289 | |
---|
290 | #if __STDC__ |
---|
291 | # include <stdarg.h> |
---|
292 | #else |
---|
293 | #ifdef _MINIX |
---|
294 | # include "mi.varargs.h" |
---|
295 | #else |
---|
296 | # include <varargs.h> |
---|
297 | #endif /* _MINIX */ |
---|
298 | #endif |
---|
299 | |
---|
300 | #ifdef DIRENT |
---|
301 | # include <dirent.h> |
---|
302 | #else |
---|
303 | # ifdef hp9000s500 |
---|
304 | # include <ndir.h> |
---|
305 | # else |
---|
306 | # include <sys/dir.h> |
---|
307 | # endif |
---|
308 | # define dirent direct |
---|
309 | #endif /* DIRENT */ |
---|
310 | #if defined(hpux) || defined(sgi) || defined(OREO) || defined(COHERENT) |
---|
311 | # include <stdio.h> /* So the fgetpwent() prototypes work */ |
---|
312 | #endif /* hpux || sgi || OREO || COHERENT */ |
---|
313 | #include <pwd.h> |
---|
314 | #ifdef PW_SHADOW |
---|
315 | # include <shadow.h> |
---|
316 | #endif /* PW_SHADOW */ |
---|
317 | #ifdef PW_AUTH |
---|
318 | # include <auth.h> |
---|
319 | #endif /* PW_AUTH */ |
---|
320 | #ifdef BSD |
---|
321 | # include <strings.h> |
---|
322 | # define strchr(a, b) index(a, b) |
---|
323 | # define strrchr(a, b) rindex(a, b) |
---|
324 | #else |
---|
325 | # include <string.h> |
---|
326 | #endif /* BSD */ |
---|
327 | |
---|
328 | /* |
---|
329 | * IRIX-5.0 has <sys/cdefs.h>, but most system include files do not |
---|
330 | * include it yet, so we include it here |
---|
331 | */ |
---|
332 | #if defined(sgi) && SYSVREL > 3 |
---|
333 | # include <sys/cdefs.h> |
---|
334 | #endif /* sgi && SYSVREL > 3 */ |
---|
335 | |
---|
336 | /* |
---|
337 | * ANSIisms... These must be *after* the system include and |
---|
338 | * *before* our includes, so that BSDreno has time to define __P |
---|
339 | */ |
---|
340 | #ifndef __P |
---|
341 | # if __STDC__ |
---|
342 | # define __P(a) a |
---|
343 | # else |
---|
344 | # define __P(a) () |
---|
345 | # define const |
---|
346 | # ifndef apollo |
---|
347 | # define volatile /* Apollo 'c' extensions need this */ |
---|
348 | # endif /* apollo */ |
---|
349 | # endif |
---|
350 | #endif |
---|
351 | |
---|
352 | |
---|
353 | typedef int bool; |
---|
354 | |
---|
355 | #include "sh.types.h" |
---|
356 | |
---|
357 | #ifndef lint |
---|
358 | typedef ptr_t memalign_t; |
---|
359 | #else |
---|
360 | typedef union { |
---|
361 | char am_char, *am_char_p; |
---|
362 | short am_short, *am_short_p; |
---|
363 | int am_int, *am_int_p; |
---|
364 | long am_long, *am_long_p; |
---|
365 | float am_float, *am_float_p; |
---|
366 | double am_double, *am_double_p; |
---|
367 | } *memalign_t; |
---|
368 | |
---|
369 | # define malloc lint_malloc |
---|
370 | # define free lint_free |
---|
371 | # define realloc lint_realloc |
---|
372 | # define calloc lint_calloc |
---|
373 | #endif |
---|
374 | |
---|
375 | #ifdef MDEBUG |
---|
376 | extern memalign_t DebugMalloc __P((unsigned, char *, int)); |
---|
377 | extern memalign_t DebugRealloc __P((ptr_t, unsigned, char *, int)); |
---|
378 | extern memalign_t DebugCalloc __P((unsigned, unsigned, char *, int)); |
---|
379 | extern void DebugFree __P((ptr_t, char *, int)); |
---|
380 | # define xmalloc(i) DebugMalloc(i, __FILE__, __LINE__) |
---|
381 | # define xrealloc(p, i)((p) ? DebugRealloc(p, i, __FILE__, __LINE__) : \ |
---|
382 | DebugMalloc(i, __FILE__, __LINE__)) |
---|
383 | # define xcalloc(n, s) DebugCalloc(n, s, __FILE__, __LINE__) |
---|
384 | # define xfree(p) if (p) DebugFree(p, __FILE__, __LINE__) |
---|
385 | #else |
---|
386 | # ifdef SYSMALLOC |
---|
387 | # define xmalloc(i) smalloc(i) |
---|
388 | # define xrealloc(p, i) srealloc(p, i) |
---|
389 | # define xcalloc(n, s) scalloc(n, s) |
---|
390 | # define xfree(p) sfree(p) |
---|
391 | # else |
---|
392 | # define xmalloc(i) malloc(i) |
---|
393 | # define xrealloc(p, i) realloc(p, i) |
---|
394 | # define xcalloc(n, s) calloc(n, s) |
---|
395 | # define xfree(p) free(p) |
---|
396 | # endif /* SYSMALLOC */ |
---|
397 | #endif /* MDEBUG */ |
---|
398 | #include "sh.char.h" |
---|
399 | #include "sh.err.h" |
---|
400 | #include "sh.dir.h" |
---|
401 | #include "sh.proc.h" |
---|
402 | |
---|
403 | #include "pathnames.h" |
---|
404 | |
---|
405 | |
---|
406 | /* |
---|
407 | * C shell |
---|
408 | * |
---|
409 | * Bill Joy, UC Berkeley |
---|
410 | * October, 1978; May 1980 |
---|
411 | * |
---|
412 | * Jim Kulp, IIASA, Laxenburg Austria |
---|
413 | * April, 1980 |
---|
414 | */ |
---|
415 | |
---|
416 | #if !defined(MAXNAMLEN) && defined(_D_NAME_MAX) |
---|
417 | # define MAXNAMLEN _D_NAME_MAX |
---|
418 | #endif /* MAXNAMLEN */ |
---|
419 | |
---|
420 | #ifndef MAXHOSTNAMELEN |
---|
421 | # define MAXHOSTNAMELEN 255 |
---|
422 | #endif /* MAXHOSTNAMELEN */ |
---|
423 | |
---|
424 | |
---|
425 | |
---|
426 | #define eq(a, b) (Strcmp(a, b) == 0) |
---|
427 | |
---|
428 | /* globone() flags */ |
---|
429 | #define G_ERROR 0 /* default action: error if multiple words */ |
---|
430 | #define G_IGNORE 1 /* ignore the rest of the words */ |
---|
431 | #define G_APPEND 2 /* make a sentence by cat'ing the words */ |
---|
432 | |
---|
433 | /* |
---|
434 | * Global flags |
---|
435 | */ |
---|
436 | EXTERN bool chkstop; /* Warned of stopped jobs... allow exit */ |
---|
437 | |
---|
438 | #if (defined(FIOCLEX) && defined(FIONCLEX)) || defined(F_SETFD) |
---|
439 | # define CLOSE_ON_EXEC |
---|
440 | #else |
---|
441 | EXTERN bool didcch; /* Have closed unused fd's for child */ |
---|
442 | #endif /* (FIOCLEX && FIONCLEX) || F_SETFD */ |
---|
443 | |
---|
444 | EXTERN bool didfds; /* Have setup i/o fd's for child */ |
---|
445 | EXTERN bool doneinp; /* EOF indicator after reset from readc */ |
---|
446 | EXTERN bool exiterr; /* Exit if error or non-zero exit status */ |
---|
447 | EXTERN bool child; /* Child shell ... errors cause exit */ |
---|
448 | EXTERN bool haderr; /* Reset was because of an error */ |
---|
449 | EXTERN bool intty; /* Input is a tty */ |
---|
450 | EXTERN bool intact; /* We are interactive... therefore prompt */ |
---|
451 | EXTERN bool justpr; /* Just print because of :p hist mod */ |
---|
452 | EXTERN bool loginsh; /* We are a loginsh -> .login/.logout */ |
---|
453 | EXTERN bool neednote; /* Need to pnotify() */ |
---|
454 | EXTERN bool noexec; /* Don't execute, just syntax check */ |
---|
455 | EXTERN bool pjobs; /* want to print jobs if interrupted */ |
---|
456 | EXTERN bool setintr; /* Set interrupts on/off -> Wait intr... */ |
---|
457 | EXTERN bool timflg; /* Time the next waited for command */ |
---|
458 | EXTERN bool havhash; /* path hashing is available */ |
---|
459 | EXTERN bool editing; /* doing filename expansion and line editing */ |
---|
460 | EXTERN bool bslash_quote; /* PWP: tcsh-style quoting? (in sh.c) */ |
---|
461 | EXTERN bool isoutatty; /* is SHOUT a tty */ |
---|
462 | EXTERN bool isdiagatty; /* is SHDIAG a tty */ |
---|
463 | EXTERN bool is1atty; /* is file descriptor 1 a tty (didfds mode) */ |
---|
464 | EXTERN bool is2atty; /* is file descriptor 2 a tty (didfds mode) */ |
---|
465 | |
---|
466 | /* |
---|
467 | * Global i/o info |
---|
468 | */ |
---|
469 | EXTERN Char *arginp; /* Argument input for sh -c and internal `xx` */ |
---|
470 | EXTERN int onelflg; /* 2 -> need line for -t, 1 -> exit on read */ |
---|
471 | extern Char *ffile; /* Name of shell file for $0 */ |
---|
472 | |
---|
473 | extern char *seterr; /* Error message from scanner/parser */ |
---|
474 | extern int errno; /* Error from C library routines */ |
---|
475 | EXTERN Char *shtemp; /* Temp name for << shell files in /tmp */ |
---|
476 | |
---|
477 | #ifdef BSDTIMES |
---|
478 | EXTERN struct timeval time0; /* Time at which the shell started */ |
---|
479 | EXTERN struct rusage ru0; |
---|
480 | #else |
---|
481 | # ifdef _SEQUENT_ |
---|
482 | EXTERN timeval_t time0; /* time at which shell started */ |
---|
483 | EXTERN struct process_stats ru0; |
---|
484 | # else /* _SEQUENT_ */ |
---|
485 | # ifndef POSIX |
---|
486 | EXTERN time_t time0; /* time at which shell started */ |
---|
487 | # else /* POSIX */ |
---|
488 | EXTERN clock_t time0; /* time at which shell started */ |
---|
489 | EXTERN clock_t clk_tck; |
---|
490 | # endif /* POSIX */ |
---|
491 | EXTERN struct tms shtimes; /* shell and child times for process timing */ |
---|
492 | # endif /* _SEQUENT_ */ |
---|
493 | #endif /* BSDTIMES */ |
---|
494 | |
---|
495 | #ifndef HZ |
---|
496 | # define HZ 100 /* for division into seconds */ |
---|
497 | #endif |
---|
498 | |
---|
499 | /* |
---|
500 | * Miscellany |
---|
501 | */ |
---|
502 | EXTERN Char *doldol; /* Character pid for $$ */ |
---|
503 | EXTERN int backpid; /* pid of the last background job */ |
---|
504 | |
---|
505 | /* |
---|
506 | * Ideally these should be uid_t, gid_t, pid_t. I cannot do that right now |
---|
507 | * cause pid's could be unsigned and that would break our -1 flag, and |
---|
508 | * uid_t and gid_t are not defined in all the systems so I would have to |
---|
509 | * make special cases for them. In the future... |
---|
510 | */ |
---|
511 | EXTERN int uid, euid, /* Invokers real and effective */ |
---|
512 | gid, egid; /* User and group ids */ |
---|
513 | EXTERN int opgrp, /* Initial pgrp and tty pgrp */ |
---|
514 | shpgrp, /* Pgrp of shell */ |
---|
515 | tpgrp; /* Terminal process group */ |
---|
516 | /* If tpgrp is -1, leave tty alone! */ |
---|
517 | |
---|
518 | EXTERN Char PromptBuf[INBUFSIZE*2]; /* buffer for the actual printed prompt. |
---|
519 | * this must be large enough to contain |
---|
520 | * the input line and the prompt, in |
---|
521 | * case a correction occured... |
---|
522 | */ |
---|
523 | |
---|
524 | /* |
---|
525 | * To be able to redirect i/o for builtins easily, the shell moves the i/o |
---|
526 | * descriptors it uses away from 0,1,2. |
---|
527 | * Ideally these should be in units which are closed across exec's |
---|
528 | * (this saves work) but for version 6, this is not usually possible. |
---|
529 | * The desired initial values for these descriptors are defined in |
---|
530 | * sh.local.h. |
---|
531 | */ |
---|
532 | EXTERN int SHIN; /* Current shell input (script) */ |
---|
533 | EXTERN int SHOUT; /* Shell output */ |
---|
534 | EXTERN int SHDIAG; /* Diagnostic output... shell errs go here */ |
---|
535 | EXTERN int OLDSTD; /* Old standard input (def for cmds) */ |
---|
536 | |
---|
537 | /* |
---|
538 | * Error control |
---|
539 | * |
---|
540 | * Errors in scanning and parsing set up an error message to be printed |
---|
541 | * at the end and complete. Other errors always cause a reset. |
---|
542 | * Because of source commands and .cshrc we need nested error catches. |
---|
543 | */ |
---|
544 | |
---|
545 | #ifdef NO_STRUCT_ASSIGNMENT |
---|
546 | |
---|
547 | typedef jmp_buf jmp_buf_t; |
---|
548 | |
---|
549 | /* bugfix by Jak Kirman @ Brown U.: remove the (void) cast here, see sh.c */ |
---|
550 | # define setexit() setjmp(reslab) |
---|
551 | # define reset() longjmp(reslab, 1) |
---|
552 | # define getexit(a) (void) memmove((ptr_t)(a), (ptr_t)reslab, sizeof(reslab)) |
---|
553 | # define resexit(a) (void) memmove((ptr_t)reslab, ((ptr_t)(a)), sizeof(reslab)) |
---|
554 | |
---|
555 | #else |
---|
556 | |
---|
557 | typedef struct { jmp_buf j; } jmp_buf_t; |
---|
558 | |
---|
559 | # define setexit() setjmp(reslab.j) |
---|
560 | # define reset() longjmp(reslab.j, 1) |
---|
561 | # define getexit(a) ((a) = reslab) |
---|
562 | # define resexit(a) (reslab = (a)) |
---|
563 | |
---|
564 | #endif /* NO_STRUCT_ASSIGNMENT */ |
---|
565 | |
---|
566 | extern jmp_buf_t reslab; |
---|
567 | |
---|
568 | EXTERN Char *gointr; /* Label for an onintr transfer */ |
---|
569 | |
---|
570 | EXTERN sigret_t (*parintr) (); /* Parents interrupt catch */ |
---|
571 | EXTERN sigret_t (*parterm) (); /* Parents terminate catch */ |
---|
572 | |
---|
573 | /* |
---|
574 | * Lexical definitions. |
---|
575 | * |
---|
576 | * All lexical space is allocated dynamically. |
---|
577 | * The eighth/sixteenth bit of characters is used to prevent recognition, |
---|
578 | * and eventually stripped. |
---|
579 | */ |
---|
580 | #define META 0200 |
---|
581 | #define ASCII 0177 |
---|
582 | #ifdef SHORT_STRINGS |
---|
583 | # define QUOTE ((Char) 0100000)/* 16nth char bit used for 'ing */ |
---|
584 | # define TRIM 0077777 /* Mask to strip quote bit */ |
---|
585 | # define UNDER 0040000 /* Underline flag */ |
---|
586 | # define BOLD 0020000 /* Bold flag */ |
---|
587 | # define STANDOUT 0010000 /* Standout flag */ |
---|
588 | # define LITERAL 0004000 /* Literal character flag */ |
---|
589 | # define ATTRIBUTES 0074000 /* The bits used for attributes */ |
---|
590 | # define CHAR 0000377 /* Mask to mask out the character */ |
---|
591 | #else |
---|
592 | # define QUOTE ((Char) 0200) /* Eighth char bit used for 'ing */ |
---|
593 | # define TRIM 0177 /* Mask to strip quote bit */ |
---|
594 | # define UNDER 0000000 /* No extra bits to do both */ |
---|
595 | # define BOLD 0000000 /* Bold flag */ |
---|
596 | # define STANDOUT META /* Standout flag */ |
---|
597 | # define LITERAL 0000000 /* Literal character flag */ |
---|
598 | # define ATTRIBUTES 0200 /* The bits used for attributes */ |
---|
599 | # define CHAR 0000177 /* Mask to mask out the character */ |
---|
600 | #endif |
---|
601 | |
---|
602 | EXTERN int AsciiOnly; /* If set only 7 bits expected in characters */ |
---|
603 | |
---|
604 | /* |
---|
605 | * Each level of input has a buffered input structure. |
---|
606 | * There are one or more blocks of buffered input for each level, |
---|
607 | * exactly one if the input is seekable and tell is available. |
---|
608 | * In other cases, the shell buffers enough blocks to keep all loops |
---|
609 | * in the buffer. |
---|
610 | */ |
---|
611 | EXTERN struct Bin { |
---|
612 | off_t Bfseekp; /* Seek pointer */ |
---|
613 | off_t Bfbobp; /* Seekp of beginning of buffers */ |
---|
614 | off_t Bfeobp; /* Seekp of end of buffers */ |
---|
615 | int Bfblocks; /* Number of buffer blocks */ |
---|
616 | Char **Bfbuf; /* The array of buffer blocks */ |
---|
617 | } B; |
---|
618 | |
---|
619 | /* |
---|
620 | * This structure allows us to seek inside aliases |
---|
621 | */ |
---|
622 | struct Ain { |
---|
623 | int type; |
---|
624 | #define I_SEEK -1 /* Invalid seek */ |
---|
625 | #define A_SEEK 0 /* Alias seek */ |
---|
626 | #define F_SEEK 1 /* File seek */ |
---|
627 | #define E_SEEK 2 /* Eval seek */ |
---|
628 | off_t f_seek; |
---|
629 | Char **a_seek; |
---|
630 | } ; |
---|
631 | |
---|
632 | extern int aret; /* Type of last char returned */ |
---|
633 | #define SEEKEQ(a, b) ((a)->type == (b)->type && \ |
---|
634 | (a)->f_seek == (b)->f_seek && \ |
---|
635 | (a)->a_seek == (b)->a_seek) |
---|
636 | |
---|
637 | #define fseekp B.Bfseekp |
---|
638 | #define fbobp B.Bfbobp |
---|
639 | #define feobp B.Bfeobp |
---|
640 | #define fblocks B.Bfblocks |
---|
641 | #define fbuf B.Bfbuf |
---|
642 | |
---|
643 | /* |
---|
644 | * The shell finds commands in loops by reseeking the input |
---|
645 | * For whiles, in particular, it reseeks to the beginning of the |
---|
646 | * line the while was on; hence the while placement restrictions. |
---|
647 | */ |
---|
648 | EXTERN struct Ain lineloc; |
---|
649 | |
---|
650 | EXTERN bool cantell; /* Is current source tellable ? */ |
---|
651 | |
---|
652 | /* |
---|
653 | * Input lines are parsed into doubly linked circular |
---|
654 | * lists of words of the following form. |
---|
655 | */ |
---|
656 | struct wordent { |
---|
657 | Char *word; |
---|
658 | struct wordent *prev; |
---|
659 | struct wordent *next; |
---|
660 | }; |
---|
661 | |
---|
662 | /* |
---|
663 | * During word building, both in the initial lexical phase and |
---|
664 | * when expanding $ variable substitutions, expansion by `!' and `$' |
---|
665 | * must be inhibited when reading ahead in routines which are themselves |
---|
666 | * processing `!' and `$' expansion or after characters such as `\' or in |
---|
667 | * quotations. The following flags are passed to the getC routines |
---|
668 | * telling them which of these substitutions are appropriate for the |
---|
669 | * next character to be returned. |
---|
670 | */ |
---|
671 | #define DODOL 1 |
---|
672 | #define DOEXCL 2 |
---|
673 | #define DOALL DODOL|DOEXCL |
---|
674 | |
---|
675 | /* |
---|
676 | * Labuf implements a general buffer for lookahead during lexical operations. |
---|
677 | * Text which is to be placed in the input stream can be stuck here. |
---|
678 | * We stick parsed ahead $ constructs during initial input, |
---|
679 | * process id's from `$$', and modified variable values (from qualifiers |
---|
680 | * during expansion in sh.dol.c) here. |
---|
681 | */ |
---|
682 | EXTERN Char *lap; |
---|
683 | |
---|
684 | /* |
---|
685 | * Parser structure |
---|
686 | * |
---|
687 | * Each command is parsed to a tree of command structures and |
---|
688 | * flags are set bottom up during this process, to be propagated down |
---|
689 | * as needed during the semantics/exeuction pass (sh.sem.c). |
---|
690 | */ |
---|
691 | struct command { |
---|
692 | short t_dtyp; /* Type of node */ |
---|
693 | #define NODE_COMMAND 1 /* t_dcom <t_dlef >t_drit */ |
---|
694 | #define NODE_PAREN 2 /* ( t_dspr ) <t_dlef >t_drit */ |
---|
695 | #define NODE_PIPE 3 /* t_dlef | t_drit */ |
---|
696 | #define NODE_LIST 4 /* t_dlef ; t_drit */ |
---|
697 | #define NODE_OR 5 /* t_dlef || t_drit */ |
---|
698 | #define NODE_AND 6 /* t_dlef && t_drit */ |
---|
699 | short t_dflg; /* Flags, e.g. F_AMPERSAND|... */ |
---|
700 | /* save these when re-doing */ |
---|
701 | #ifndef apollo |
---|
702 | #define F_SAVE (F_NICE|F_TIME|F_NOHUP) |
---|
703 | #else |
---|
704 | #define F_SAVE (F_NICE|F_TIME|F_NOHUP|F_VER) |
---|
705 | #endif |
---|
706 | #define F_AMPERSAND (1<<0) /* executes in background */ |
---|
707 | #define F_APPEND (1<<1) /* output is redirected >> */ |
---|
708 | #define F_PIPEIN (1<<2) /* input is a pipe */ |
---|
709 | #define F_PIPEOUT (1<<3) /* output is a pipe */ |
---|
710 | #define F_NOFORK (1<<4) /* don't fork, last ()ized cmd */ |
---|
711 | #define F_NOINTERRUPT (1<<5) /* should be immune from intr's */ |
---|
712 | /* spare */ |
---|
713 | #define F_STDERR (1<<7) /* redirect unit 2 with unit 1 */ |
---|
714 | #define F_OVERWRITE (1<<8) /* output was ! */ |
---|
715 | #define F_READ (1<<9) /* input redirection is << */ |
---|
716 | #define F_REPEAT (1<<10) /* reexec aft if, repeat,... */ |
---|
717 | #define F_NICE (1<<11) /* t_nice is meaningful */ |
---|
718 | #define F_NOHUP (1<<12) /* nohup this command */ |
---|
719 | #define F_TIME (1<<13) /* time this command */ |
---|
720 | #define F_BACKQ (1<<14) /* command is in `` */ |
---|
721 | #ifdef apollo |
---|
722 | #define F_VER (1<<15) /* execute command under SYSTYPE */ |
---|
723 | #endif |
---|
724 | union { |
---|
725 | Char *T_dlef; /* Input redirect word */ |
---|
726 | struct command *T_dcar; /* Left part of list/pipe */ |
---|
727 | } L; |
---|
728 | union { |
---|
729 | Char *T_drit; /* Output redirect word */ |
---|
730 | struct command *T_dcdr; /* Right part of list/pipe */ |
---|
731 | } R; |
---|
732 | #define t_dlef L.T_dlef |
---|
733 | #define t_dcar L.T_dcar |
---|
734 | #define t_drit R.T_drit |
---|
735 | #define t_dcdr R.T_dcdr |
---|
736 | Char **t_dcom; /* Command/argument vector */ |
---|
737 | struct command *t_dspr; /* Pointer to ()'d subtree */ |
---|
738 | short t_nice; |
---|
739 | #ifdef F_VER |
---|
740 | short t_systype; |
---|
741 | #endif |
---|
742 | }; |
---|
743 | |
---|
744 | |
---|
745 | /* |
---|
746 | * The keywords for the parser |
---|
747 | */ |
---|
748 | #define TC_BREAK 0 |
---|
749 | #define TC_BRKSW 1 |
---|
750 | #define TC_CASE 2 |
---|
751 | #define TC_DEFAULT 3 |
---|
752 | #define TC_ELSE 4 |
---|
753 | #define TC_END 5 |
---|
754 | #define TC_ENDIF 6 |
---|
755 | #define TC_ENDSW 7 |
---|
756 | #define TC_EXIT 8 |
---|
757 | #define TC_FOREACH 9 |
---|
758 | #define TC_GOTO 10 |
---|
759 | #define TC_IF 11 |
---|
760 | #define TC_LABEL 12 |
---|
761 | #define TC_LET 13 |
---|
762 | #define TC_SET 14 |
---|
763 | #define TC_SWITCH 15 |
---|
764 | #define TC_TEST 16 |
---|
765 | #define TC_THEN 17 |
---|
766 | #define TC_WHILE 18 |
---|
767 | |
---|
768 | /* |
---|
769 | * These are declared here because they want to be |
---|
770 | * initialized in sh.init.c (to allow them to be made readonly) |
---|
771 | */ |
---|
772 | |
---|
773 | extern struct biltins { |
---|
774 | char *bname; |
---|
775 | #if defined(hpux) && defined(__STDC__) && !defined(__GNUC__) |
---|
776 | /* Avoid hpux ansi mode spurious warnings */ |
---|
777 | void (*bfunct) (); |
---|
778 | #else |
---|
779 | void (*bfunct) __P((Char **, struct command *)); |
---|
780 | #endif /* hpux && __STDC__ && !__GNUC__ */ |
---|
781 | int minargs, maxargs; |
---|
782 | } bfunc[]; |
---|
783 | extern int nbfunc; |
---|
784 | |
---|
785 | extern struct srch { |
---|
786 | char *s_name; |
---|
787 | int s_value; |
---|
788 | } srchn[]; |
---|
789 | extern int nsrchn; |
---|
790 | |
---|
791 | /* |
---|
792 | * Structure defining the existing while/foreach loops at this |
---|
793 | * source level. Loops are implemented by seeking back in the |
---|
794 | * input. For foreach (fe), the word list is attached here. |
---|
795 | */ |
---|
796 | EXTERN struct whyle { |
---|
797 | struct Ain w_start; /* Point to restart loop */ |
---|
798 | struct Ain w_end; /* End of loop (0 if unknown) */ |
---|
799 | Char **w_fe, **w_fe0; /* Current/initial wordlist for fe */ |
---|
800 | Char *w_fename; /* Name for fe */ |
---|
801 | struct whyle *w_next; /* Next (more outer) loop */ |
---|
802 | } *whyles; |
---|
803 | |
---|
804 | /* |
---|
805 | * Variable structure |
---|
806 | * |
---|
807 | * Aliases and variables are stored in AVL balanced binary trees. |
---|
808 | */ |
---|
809 | EXTERN struct varent { |
---|
810 | Char **vec; /* Array of words which is the value */ |
---|
811 | Char *v_name; /* Name of variable/alias */ |
---|
812 | struct varent *v_link[3]; /* The links, see below */ |
---|
813 | int v_bal; /* Balance factor */ |
---|
814 | } shvhed, aliases; |
---|
815 | |
---|
816 | #define v_left v_link[0] |
---|
817 | #define v_right v_link[1] |
---|
818 | #define v_parent v_link[2] |
---|
819 | |
---|
820 | #define adrof(v) adrof1(v, &shvhed) |
---|
821 | #define value(v) value1(v, &shvhed) |
---|
822 | |
---|
823 | /* |
---|
824 | * The following are for interfacing redo substitution in |
---|
825 | * aliases to the lexical routines. |
---|
826 | */ |
---|
827 | EXTERN struct wordent *alhistp; /* Argument list (first) */ |
---|
828 | EXTERN struct wordent *alhistt; /* Node after last in arg list */ |
---|
829 | EXTERN Char **alvec, *alvecp; /* The (remnants of) alias vector */ |
---|
830 | |
---|
831 | /* |
---|
832 | * Filename/command name expansion variables |
---|
833 | */ |
---|
834 | EXTERN int gflag; /* After tglob -> is globbing needed? */ |
---|
835 | |
---|
836 | #define MAXVARLEN 30 /* Maximum number of char in a variable name */ |
---|
837 | |
---|
838 | #ifndef MAXPATHLEN |
---|
839 | # define MAXPATHLEN 2048 |
---|
840 | #endif /* MAXPATHLEN */ |
---|
841 | |
---|
842 | #ifndef MAXNAMLEN |
---|
843 | # define MAXNAMLEN 512 |
---|
844 | #endif /* MAXNAMLEN */ |
---|
845 | |
---|
846 | #ifndef HAVENOLIMIT |
---|
847 | /* |
---|
848 | * resource limits |
---|
849 | */ |
---|
850 | extern struct limits { |
---|
851 | int limconst; |
---|
852 | char *limname; |
---|
853 | int limdiv; |
---|
854 | char *limscale; |
---|
855 | } limits[]; |
---|
856 | #endif /* !HAVENOLIMIT */ |
---|
857 | |
---|
858 | /* |
---|
859 | * Variables for filename expansion |
---|
860 | */ |
---|
861 | extern Char **gargv; /* Pointer to the (stack) arglist */ |
---|
862 | extern long gargc; /* Number args in gargv */ |
---|
863 | |
---|
864 | /* |
---|
865 | * Variables for command expansion. |
---|
866 | */ |
---|
867 | extern Char **pargv; /* Pointer to the argv list space */ |
---|
868 | EXTERN Char *pargs; /* Pointer to start current word */ |
---|
869 | EXTERN long pnleft; /* Number of chars left in pargs */ |
---|
870 | EXTERN Char *pargcp; /* Current index into pargs */ |
---|
871 | |
---|
872 | /* |
---|
873 | * History list |
---|
874 | * |
---|
875 | * Each history list entry contains an embedded wordlist |
---|
876 | * from the scanner, a number for the event, and a reference count |
---|
877 | * to aid in discarding old entries. |
---|
878 | * |
---|
879 | * Essentially "invisible" entries are put on the history list |
---|
880 | * when history substitution includes modifiers, and thrown away |
---|
881 | * at the next discarding since their event numbers are very negative. |
---|
882 | */ |
---|
883 | EXTERN struct Hist { |
---|
884 | struct wordent Hlex; |
---|
885 | int Hnum; |
---|
886 | int Href; |
---|
887 | time_t Htime; |
---|
888 | Char *histline; |
---|
889 | struct Hist *Hnext; |
---|
890 | } Histlist; |
---|
891 | |
---|
892 | EXTERN struct wordent paraml; /* Current lexical word list */ |
---|
893 | EXTERN int eventno; /* Next events number */ |
---|
894 | EXTERN int lastev; /* Last event reference (default) */ |
---|
895 | |
---|
896 | EXTERN Char HIST; /* history invocation character */ |
---|
897 | EXTERN Char HISTSUB; /* auto-substitute character */ |
---|
898 | |
---|
899 | /* |
---|
900 | * strings.h: |
---|
901 | */ |
---|
902 | #ifndef SHORT_STRINGS |
---|
903 | #define Strchr(a, b) strchr(a, b) |
---|
904 | #define Strrchr(a, b) strrchr(a, b) |
---|
905 | #define Strcat(a, b) strcat(a, b) |
---|
906 | #define Strncat(a, b, c) strncat(a, b, c) |
---|
907 | #define Strcpy(a, b) strcpy(a, b) |
---|
908 | #define Strncpy(a, b, c) strncpy(a, b, c) |
---|
909 | #define Strlen(a) strlen(a) |
---|
910 | #define Strcmp(a, b) strcmp(a, b) |
---|
911 | #define Strncmp(a, b, c) strncmp(a, b, c) |
---|
912 | |
---|
913 | #define Strspl(a, b) strspl(a, b) |
---|
914 | #define Strsave(a) strsave(a) |
---|
915 | #define Strend(a) strend(a) |
---|
916 | #define Strstr(a, b) strstr(a, b) |
---|
917 | |
---|
918 | #define str2short(a) (a) |
---|
919 | #define blk2short(a) saveblk(a) |
---|
920 | #define short2blk(a) saveblk(a) |
---|
921 | #define short2str(a) strip(a) |
---|
922 | #else |
---|
923 | #define Strchr(a, b) s_strchr(a, b) |
---|
924 | #define Strrchr(a, b) s_strrchr(a, b) |
---|
925 | #define Strcat(a, b) s_strcat(a, b) |
---|
926 | #define Strncat(a, b, c) s_strncat(a, b, c) |
---|
927 | #define Strcpy(a, b) s_strcpy(a, b) |
---|
928 | #define Strncpy(a, b, c) s_strncpy(a, b, c) |
---|
929 | #define Strlen(a) s_strlen(a) |
---|
930 | #define Strcmp(a, b) s_strcmp(a, b) |
---|
931 | #define Strncmp(a, b, c) s_strncmp(a, b, c) |
---|
932 | |
---|
933 | #define Strspl(a, b) s_strspl(a, b) |
---|
934 | #define Strsave(a) s_strsave(a) |
---|
935 | #define Strend(a) s_strend(a) |
---|
936 | #define Strstr(a, b) s_strstr(a, b) |
---|
937 | #endif |
---|
938 | |
---|
939 | /* |
---|
940 | * setname is a macro to save space (see sh.err.c) |
---|
941 | */ |
---|
942 | EXTERN char *bname; |
---|
943 | |
---|
944 | #define setname(a) (bname = (a)) |
---|
945 | |
---|
946 | #ifdef VFORK |
---|
947 | EXTERN Char *Vsav; |
---|
948 | EXTERN Char *Vdp; |
---|
949 | EXTERN Char *Vexpath; |
---|
950 | EXTERN char **Vt; |
---|
951 | #endif /* VFORK */ |
---|
952 | |
---|
953 | EXTERN Char **evalvec; |
---|
954 | EXTERN Char *evalp; |
---|
955 | |
---|
956 | extern struct mesg { |
---|
957 | char *iname; /* name from /usr/include */ |
---|
958 | char *pname; /* print name */ |
---|
959 | } mesg[]; |
---|
960 | extern int mesg_size; /* number of entries in mesg, may be fewer than NSIG */ |
---|
961 | |
---|
962 | /* word_chars is set by default to WORD_CHARS but can be overridden by |
---|
963 | the worchars variable--if unset, reverts to WORD_CHARS */ |
---|
964 | |
---|
965 | EXTERN Char *word_chars; |
---|
966 | |
---|
967 | #define WORD_CHARS "*?_-.[]~=" /* default chars besides alnums in words */ |
---|
968 | |
---|
969 | EXTERN Char *STR_SHELLPATH; |
---|
970 | |
---|
971 | #ifdef _PATH_BSHELL |
---|
972 | EXTERN Char *STR_BSHELL; |
---|
973 | #endif |
---|
974 | EXTERN Char *STR_WORD_CHARS; |
---|
975 | EXTERN Char **STR_environ; |
---|
976 | |
---|
977 | extern int dont_free; /* Tell free that we are in danger if we free */ |
---|
978 | |
---|
979 | #include "tc.h" |
---|
980 | #include "sh.decls.h" |
---|
981 | |
---|
982 | #endif /* _h_sh */ |
---|