1 /* exp_clib.c - top-level functions in the expect C library, libexpect.a
2 
3 Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90
4 
5 Design and implementation of this program was paid for by U.S. tax
6 dollars.  Therefore it is public domain.  However, the author and NIST
7 would appreciate credit if this program or parts of it are used.
8 */
9 
10 #include "expect_cf.h"
11 #include <stdio.h>
12 #include <setjmp.h>
13 #ifdef HAVE_INTTYPES_H
14 #  include <inttypes.h>
15 #endif
16 #include <sys/types.h>
17 #include <sys/ioctl.h>
18 
19 #ifdef TIME_WITH_SYS_TIME
20 # include <sys/time.h>
21 # include <time.h>
22 #else
23 # if HAVE_SYS_TIME_H
24 #  include <sys/time.h>
25 # else
26 #  include <time.h>
27 # endif
28 #endif
29 
30 #ifdef CRAY
31 # ifndef TCSETCTTY
32 #  if defined(HAVE_TERMIOS)
33 #   include <termios.h>
34 #  else
35 #   include <termio.h>
36 #  endif
37 # endif
38 #endif
39 
40 #ifdef HAVE_SYS_FCNTL_H
41 #  include <sys/fcntl.h>
42 #else
43 #  include <fcntl.h>
44 #endif
45 
46 #ifdef HAVE_STRREDIR_H
47 #include <sys/strredir.h>
48 # ifdef SRIOCSREDIR
49 #  undef TIOCCONS
50 # endif
51 #endif
52 
53 #include <signal.h>
54 /*#include <memory.h> - deprecated - ANSI C moves them into string.h */
55 #include "string.h"
56 
57 #include <errno.h>
58 
59 #ifdef NO_STDLIB_H
60 
61 /*
62  * Tcl's compat/stdlib.h
63  */
64 
65 /*
66  * stdlib.h --
67  *
68  *	Declares facilities exported by the "stdlib" portion of
69  *	the C library.  This file isn't complete in the ANSI-C
70  *	sense;  it only declares things that are needed by Tcl.
71  *	This file is needed even on many systems with their own
72  *	stdlib.h (e.g. SunOS) because not all stdlib.h files
73  *	declare all the procedures needed here (such as strtod).
74  *
75  * Copyright (c) 1991 The Regents of the University of California.
76  * Copyright (c) 1994 Sun Microsystems, Inc.
77  *
78  * See the file "license.terms" for information on usage and redistribution
79  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
80  *
81  * RCS: @(#) $Id: exp_clib.c,v 5.38 2010/07/01 00:53:49 eee Exp $
82  */
83 
84 #ifndef _STDLIB
85 #define _STDLIB
86 
87 extern void		abort _ANSI_ARGS_((void));
88 extern double		atof _ANSI_ARGS_((CONST char *string));
89 extern int		atoi _ANSI_ARGS_((CONST char *string));
90 extern long		atol _ANSI_ARGS_((CONST char *string));
91 extern char *		calloc _ANSI_ARGS_((unsigned int numElements,
92 			    unsigned int size));
93 extern void		exit _ANSI_ARGS_((int status));
94 extern int		free _ANSI_ARGS_((char *blockPtr));
95 extern char *		getenv _ANSI_ARGS_((CONST char *name));
96 extern char *		malloc _ANSI_ARGS_((unsigned int numBytes));
97 extern void		qsort _ANSI_ARGS_((VOID *base, int n, int size,
98 			    int (*compar)(CONST VOID *element1, CONST VOID
99 			    *element2)));
100 extern char *		realloc _ANSI_ARGS_((char *ptr, unsigned int numBytes));
101 extern double		strtod _ANSI_ARGS_((CONST char *string, char **endPtr));
102 extern long		strtol _ANSI_ARGS_((CONST char *string, char **endPtr,
103 			    int base));
104 extern unsigned long	strtoul _ANSI_ARGS_((CONST char *string,
105 			    char **endPtr, int base));
106 
107 #endif /* _STDLIB */
108 
109 /*
110  * end of Tcl's compat/stdlib.h
111  */
112 
113 #else
114 #include <stdlib.h>		/* for malloc */
115 #endif
116 
117 #include <tcl.h>
118 #include "expect.h"
119 #define TclRegError exp_TclRegError
120 
121 /*
122  * regexp code - from tcl8.0.4/generic/regexp.c
123  */
124 
125 /*
126  * TclRegComp and TclRegExec -- TclRegSub is elsewhere
127  *
128  *	Copyright (c) 1986 by University of Toronto.
129  *	Written by Henry Spencer.  Not derived from licensed software.
130  *
131  *	Permission is granted to anyone to use this software for any
132  *	purpose on any computer system, and to redistribute it freely,
133  *	subject to the following restrictions:
134  *
135  *	1. The author is not responsible for the consequences of use of
136  *		this software, no matter how awful, even if they arise
137  *		from defects in it.
138  *
139  *	2. The origin of this software must not be misrepresented, either
140  *		by explicit claim or by omission.
141  *
142  *	3. Altered versions must be plainly marked as such, and must not
143  *		be misrepresented as being the original software.
144  *
145  * Beware that some of this code is subtly aware of the way operator
146  * precedence is structured in regular expressions.  Serious changes in
147  * regular-expression syntax might require a total rethink.
148  *
149  * *** NOTE: this code has been altered slightly for use in Tcl: ***
150  * *** 1. Use ckalloc and ckfree instead of  malloc and free.	 ***
151  * *** 2. Add extra argument to regexp to specify the real	 ***
152  * ***    start of the string separately from the start of the	 ***
153  * ***    current search. This is needed to search for multiple	 ***
154  * ***    matches within a string.				 ***
155  * *** 3. Names have been changed, e.g. from regcomp to		 ***
156  * ***    TclRegComp, to avoid clashes with other 		 ***
157  * ***    regexp implementations used by applications. 		 ***
158  * *** 4. Added errMsg declaration and TclRegError procedure	 ***
159  * *** 5. Various lint-like things, such as casting arguments	 ***
160  * ***	  in procedure calls.					 ***
161  *
162  * *** NOTE: This code has been altered for use in MT-Sturdy Tcl ***
163  * *** 1. All use of static variables has been changed to access ***
164  * ***    fields of a structure.                                 ***
165  * *** 2. This in addition to changes to TclRegError makes the   ***
166  * ***    code multi-thread safe.                                ***
167  *
168  * RCS: @(#) $Id: exp_clib.c,v 5.38 2010/07/01 00:53:49 eee Exp $
169  */
170 
171 #if 0
172 #include "tclInt.h"
173 #include "tclPort.h"
174 #endif
175 
176 /*
177  * The variable below is set to NULL before invoking regexp functions
178  * and checked after those functions.  If an error occurred then TclRegError
179  * will set the variable to point to a (static) error message.  This
180  * mechanism unfortunately does not support multi-threading, but the
181  * procedures TclRegError and TclGetRegError can be modified to use
182  * thread-specific storage for the variable and thereby make the code
183  * thread-safe.
184  */
185 
186 static char *errMsg = NULL;
187 
188 /*
189  * The "internal use only" fields in regexp.h are present to pass info from
190  * compile to execute that permits the execute phase to run lots faster on
191  * simple cases.  They are:
192  *
193  * regstart	char that must begin a match; '\0' if none obvious
194  * reganch	is the match anchored (at beginning-of-line only)?
195  * regmust	string (pointer into program) that match must include, or NULL
196  * regmlen	length of regmust string
197  *
198  * Regstart and reganch permit very fast decisions on suitable starting points
199  * for a match, cutting down the work a lot.  Regmust permits fast rejection
200  * of lines that cannot possibly match.  The regmust tests are costly enough
201  * that TclRegComp() supplies a regmust only if the r.e. contains something
202  * potentially expensive (at present, the only such thing detected is * or +
203  * at the start of the r.e., which can involve a lot of backup).  Regmlen is
204  * supplied because the test in TclRegExec() needs it and TclRegComp() is
205  * computing it anyway.
206  */
207 
208 /*
209  * Structure for regexp "program".  This is essentially a linear encoding
210  * of a nondeterministic finite-state machine (aka syntax charts or
211  * "railroad normal form" in parsing technology).  Each node is an opcode
212  * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
213  * all nodes except BRANCH implement concatenation; a "next" pointer with
214  * a BRANCH on both ends of it is connecting two alternatives.  (Here we
215  * have one of the subtle syntax dependencies:  an individual BRANCH (as
216  * opposed to a collection of them) is never concatenated with anything
217  * because of operator precedence.)  The operand of some types of node is
218  * a literal string; for others, it is a node leading into a sub-FSM.  In
219  * particular, the operand of a BRANCH node is the first node of the branch.
220  * (NB this is *not* a tree structure:  the tail of the branch connects
221  * to the thing following the set of BRANCHes.)  The opcodes are:
222  */
223 
224 /* definition	number	opnd?	meaning */
225 #define	END	0	/* no	End of program. */
226 #define	BOL	1	/* no	Match "" at beginning of line. */
227 #define	EOL	2	/* no	Match "" at end of line. */
228 #define	ANY	3	/* no	Match any one character. */
229 #define	ANYOF	4	/* str	Match any character in this string. */
230 #define	ANYBUT	5	/* str	Match any character not in this string. */
231 #define	BRANCH	6	/* node	Match this alternative, or the next... */
232 #define	BACK	7	/* no	Match "", "next" ptr points backward. */
233 #define	EXACTLY	8	/* str	Match this string. */
234 #define	NOTHING	9	/* no	Match empty string. */
235 #define	STAR	10	/* node	Match this (simple) thing 0 or more times. */
236 #define	PLUS	11	/* node	Match this (simple) thing 1 or more times. */
237 #define	OPEN	20	/* no	Mark this point in input as start of #n. */
238 			/*	OPEN+1 is number 1, etc. */
239 #define	CLOSE	(OPEN+NSUBEXP)	/* no	Analogous to OPEN. */
240 
241 /*
242  * Opcode notes:
243  *
244  * BRANCH	The set of branches constituting a single choice are hooked
245  *		together with their "next" pointers, since precedence prevents
246  *		anything being concatenated to any individual branch.  The
247  *		"next" pointer of the last BRANCH in a choice points to the
248  *		thing following the whole choice.  This is also where the
249  *		final "next" pointer of each individual branch points; each
250  *		branch starts with the operand node of a BRANCH node.
251  *
252  * BACK		Normal "next" pointers all implicitly point forward; BACK
253  *		exists to make loop structures possible.
254  *
255  * STAR,PLUS	'?', and complex '*' and '+', are implemented as circular
256  *		BRANCH structures using BACK.  Simple cases (one character
257  *		per match) are implemented with STAR and PLUS for speed
258  *		and to minimize recursive plunges.
259  *
260  * OPEN,CLOSE	...are numbered at compile time.
261  */
262 
263 /*
264  * A node is one char of opcode followed by two chars of "next" pointer.
265  * "Next" pointers are stored as two 8-bit pieces, high order first.  The
266  * value is a positive offset from the opcode of the node containing it.
267  * An operand, if any, simply follows the node.  (Note that much of the
268  * code generation knows about this implicit relationship.)
269  *
270  * Using two bytes for the "next" pointer is vast overkill for most things,
271  * but allows patterns to get big without disasters.
272  */
273 #define	OP(p)	(*(p))
274 #define	NEXT(p)	(((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
275 #define	OPERAND(p)	((p) + 3)
276 
277 /*
278  * See regmagic.h for one further detail of program structure.
279  */
280 
281 
282 /*
283  * Utility definitions.
284  */
285 #ifndef CHARBITS
286 #define	UCHARAT(p)	((int)*(unsigned char *)(p))
287 #else
288 #define	UCHARAT(p)	((int)*(p)&CHARBITS)
289 #endif
290 
291 #define	FAIL(m)	{ TclRegError(m); return(NULL); }
292 #define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?')
293 #define	META	"^$.[()|?+*\\"
294 
295 /*
296  * Flags to be passed up and down.
297  */
298 #define	HASWIDTH	01	/* Known never to match null string. */
299 #define	SIMPLE		02	/* Simple enough to be STAR/PLUS operand. */
300 #define	SPSTART		04	/* Starts with * or +. */
301 #define	WORST		0	/* Worst case. */
302 
303 /*
304  * Global work variables for TclRegComp().
305  */
306 struct regcomp_state  {
307     char *regparse;		/* Input-scan pointer. */
308     int regnpar;		/* () count. */
309     char *regcode;		/* Code-emit pointer; &regdummy = don't. */
310     long regsize;		/* Code size. */
311 };
312 
313 static char regdummy;
314 
315 /*
316  * The first byte of the regexp internal "program" is actually this magic
317  * number; the start node begins in the second byte.
318  */
319 #define	MAGIC	0234
320 
321 
322 /*
323  * Forward declarations for TclRegComp()'s friends.
324  */
325 
326 static char *		reg _ANSI_ARGS_((int paren, int *flagp,
327 			    struct regcomp_state *rcstate));
328 static char *		regatom _ANSI_ARGS_((int *flagp,
329 			    struct regcomp_state *rcstate));
330 static char *		regbranch _ANSI_ARGS_((int *flagp,
331 			    struct regcomp_state *rcstate));
332 static void		regc _ANSI_ARGS_((int b,
333 			    struct regcomp_state *rcstate));
334 static void		reginsert _ANSI_ARGS_((int op, char *opnd,
335 			    struct regcomp_state *rcstate));
336 static char *		regnext _ANSI_ARGS_((char *p));
337 static char *		regnode _ANSI_ARGS_((int op,
338 			    struct regcomp_state *rcstate));
339 static void 		regoptail _ANSI_ARGS_((char *p, char *val));
340 static char *		regpiece _ANSI_ARGS_((int *flagp,
341 			    struct regcomp_state *rcstate));
342 static void 		regtail _ANSI_ARGS_((char *p, char *val));
343 
344 #ifdef STRCSPN
345 static int strcspn _ANSI_ARGS_((char *s1, char *s2));
346 #endif
347 
348 /*
349  - TclRegComp - compile a regular expression into internal code
350  *
351  * We can't allocate space until we know how big the compiled form will be,
352  * but we can't compile it (and thus know how big it is) until we've got a
353  * place to put the code.  So we cheat:  we compile it twice, once with code
354  * generation turned off and size counting turned on, and once "for real".
355  * This also means that we don't allocate space until we are sure that the
356  * thing really will compile successfully, and we never have to move the
357  * code and thus invalidate pointers into it.  (Note that it has to be in
358  * one piece because free() must be able to free it all.)
359  *
360  * Beware that the optimization-preparation code in here knows about some
361  * of the structure of the compiled regexp.
362  */
363 regexp *
TclRegComp(exp)364 TclRegComp(exp)
365 char *exp;
366 {
367 	register regexp *r;
368 	register char *scan;
369 	register char *longest;
370 	register int len;
371 	int flags;
372 	struct regcomp_state state;
373 	struct regcomp_state *rcstate= &state;
374 
375 	if (exp == NULL)
376 		FAIL("NULL argument");
377 
378 	/* First pass: determine size, legality. */
379 	rcstate->regparse = exp;
380 	rcstate->regnpar = 1;
381 	rcstate->regsize = 0L;
382 	rcstate->regcode = &regdummy;
383 	regc(MAGIC, rcstate);
384 	if (reg(0, &flags, rcstate) == NULL)
385 		return(NULL);
386 
387 	/* Small enough for pointer-storage convention? */
388 	if (rcstate->regsize >= 32767L)		/* Probably could be 65535L. */
389 		FAIL("regexp too big");
390 
391 	/* Allocate space. */
392 	r = (regexp *)ckalloc(sizeof(regexp) + (unsigned)rcstate->regsize);
393 	if (r == NULL)
394 		FAIL("out of space");
395 
396 	/* Second pass: emit code. */
397 	rcstate->regparse = exp;
398 	rcstate->regnpar = 1;
399 	rcstate->regcode = r->program;
400 	regc(MAGIC, rcstate);
401 	if (reg(0, &flags, rcstate) == NULL) {
402 	  ckfree ((char*) r);
403 	  return(NULL);
404 	}
405 
406 	/* Dig out information for optimizations. */
407 	r->regstart = '\0';	/* Worst-case defaults. */
408 	r->reganch = 0;
409 	r->regmust = NULL;
410 	r->regmlen = 0;
411 	scan = r->program+1;			/* First BRANCH. */
412 	if (OP(regnext(scan)) == END) {		/* Only one top-level choice. */
413 		scan = OPERAND(scan);
414 
415 		/* Starting-point info. */
416 		if (OP(scan) == EXACTLY)
417 			r->regstart = *OPERAND(scan);
418 		else if (OP(scan) == BOL)
419 			r->reganch++;
420 
421 		/*
422 		 * If there's something expensive in the r.e., find the
423 		 * longest literal string that must appear and make it the
424 		 * regmust.  Resolve ties in favor of later strings, since
425 		 * the regstart check works with the beginning of the r.e.
426 		 * and avoiding duplication strengthens checking.  Not a
427 		 * strong reason, but sufficient in the absence of others.
428 		 */
429 		if (flags&SPSTART) {
430 			longest = NULL;
431 			len = 0;
432 			for (; scan != NULL; scan = regnext(scan))
433 				if (OP(scan) == EXACTLY && ((int) strlen(OPERAND(scan))) >= len) {
434 					longest = OPERAND(scan);
435 					len = strlen(OPERAND(scan));
436 				}
437 			r->regmust = longest;
438 			r->regmlen = len;
439 		}
440 	}
441 
442 	return(r);
443 }
444 
445 /*
446  - reg - regular expression, i.e. main body or parenthesized thing
447  *
448  * Caller must absorb opening parenthesis.
449  *
450  * Combining parenthesis handling with the base level of regular expression
451  * is a trifle forced, but the need to tie the tails of the branches to what
452  * follows makes it hard to avoid.
453  */
454 static char *
reg(paren,flagp,rcstate)455 reg(paren, flagp, rcstate)
456 int paren;			/* Parenthesized? */
457 int *flagp;
458 struct regcomp_state *rcstate;
459 {
460 	register char *ret;
461 	register char *br;
462 	register char *ender;
463 	register int parno = 0;
464 	int flags;
465 
466 	*flagp = HASWIDTH;	/* Tentatively. */
467 
468 	/* Make an OPEN node, if parenthesized. */
469 	if (paren) {
470 		if (rcstate->regnpar >= NSUBEXP)
471 			FAIL("too many ()");
472 		parno = rcstate->regnpar;
473 		rcstate->regnpar++;
474 		ret = regnode(OPEN+parno,rcstate);
475 	} else
476 		ret = NULL;
477 
478 	/* Pick up the branches, linking them together. */
479 	br = regbranch(&flags,rcstate);
480 	if (br == NULL)
481 		return(NULL);
482 	if (ret != NULL)
483 		regtail(ret, br);	/* OPEN -> first. */
484 	else
485 		ret = br;
486 	if (!(flags&HASWIDTH))
487 		*flagp &= ~HASWIDTH;
488 	*flagp |= flags&SPSTART;
489 	while (*rcstate->regparse == '|') {
490 		rcstate->regparse++;
491 		br = regbranch(&flags,rcstate);
492 		if (br == NULL)
493 			return(NULL);
494 		regtail(ret, br);	/* BRANCH -> BRANCH. */
495 		if (!(flags&HASWIDTH))
496 			*flagp &= ~HASWIDTH;
497 		*flagp |= flags&SPSTART;
498 	}
499 
500 	/* Make a closing node, and hook it on the end. */
501 	ender = regnode((paren) ? CLOSE+parno : END,rcstate);
502 	regtail(ret, ender);
503 
504 	/* Hook the tails of the branches to the closing node. */
505 	for (br = ret; br != NULL; br = regnext(br))
506 		regoptail(br, ender);
507 
508 	/* Check for proper termination. */
509 	if (paren && *rcstate->regparse++ != ')') {
510 		FAIL("unmatched ()");
511 	} else if (!paren && *rcstate->regparse != '\0') {
512 		if (*rcstate->regparse == ')') {
513 			FAIL("unmatched ()");
514 		} else
515 			FAIL("junk on end");	/* "Can't happen". */
516 		/* NOTREACHED */
517 	}
518 
519 	return(ret);
520 }
521 
522 /*
523  - regbranch - one alternative of an | operator
524  *
525  * Implements the concatenation operator.
526  */
527 static char *
regbranch(flagp,rcstate)528 regbranch(flagp, rcstate)
529 int *flagp;
530 struct regcomp_state *rcstate;
531 {
532 	register char *ret;
533 	register char *chain;
534 	register char *latest;
535 	int flags;
536 
537 	*flagp = WORST;		/* Tentatively. */
538 
539 	ret = regnode(BRANCH,rcstate);
540 	chain = NULL;
541 	while (*rcstate->regparse != '\0' && *rcstate->regparse != '|' &&
542 				*rcstate->regparse != ')') {
543 		latest = regpiece(&flags, rcstate);
544 		if (latest == NULL)
545 			return(NULL);
546 		*flagp |= flags&HASWIDTH;
547 		if (chain == NULL)	/* First piece. */
548 			*flagp |= flags&SPSTART;
549 		else
550 			regtail(chain, latest);
551 		chain = latest;
552 	}
553 	if (chain == NULL)	/* Loop ran zero times. */
554 		(void) regnode(NOTHING,rcstate);
555 
556 	return(ret);
557 }
558 
559 /*
560  - regpiece - something followed by possible [*+?]
561  *
562  * Note that the branching code sequences used for ? and the general cases
563  * of * and + are somewhat optimized:  they use the same NOTHING node as
564  * both the endmarker for their branch list and the body of the last branch.
565  * It might seem that this node could be dispensed with entirely, but the
566  * endmarker role is not redundant.
567  */
568 static char *
regpiece(flagp,rcstate)569 regpiece(flagp, rcstate)
570 int *flagp;
571 struct regcomp_state *rcstate;
572 {
573 	register char *ret;
574 	register char op;
575 	register char *next;
576 	int flags;
577 
578 	ret = regatom(&flags,rcstate);
579 	if (ret == NULL)
580 		return(NULL);
581 
582 	op = *rcstate->regparse;
583 	if (!ISMULT(op)) {
584 		*flagp = flags;
585 		return(ret);
586 	}
587 
588 	if (!(flags&HASWIDTH) && op != '?')
589 		FAIL("*+ operand could be empty");
590 	*flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
591 
592 	if (op == '*' && (flags&SIMPLE))
593 		reginsert(STAR, ret, rcstate);
594 	else if (op == '*') {
595 		/* Emit x* as (x&|), where & means "self". */
596 		reginsert(BRANCH, ret, rcstate);			/* Either x */
597 		regoptail(ret, regnode(BACK,rcstate));		/* and loop */
598 		regoptail(ret, ret);			/* back */
599 		regtail(ret, regnode(BRANCH,rcstate));		/* or */
600 		regtail(ret, regnode(NOTHING,rcstate));		/* null. */
601 	} else if (op == '+' && (flags&SIMPLE))
602 		reginsert(PLUS, ret, rcstate);
603 	else if (op == '+') {
604 		/* Emit x+ as x(&|), where & means "self". */
605 		next = regnode(BRANCH,rcstate);			/* Either */
606 		regtail(ret, next);
607 		regtail(regnode(BACK,rcstate), ret);		/* loop back */
608 		regtail(next, regnode(BRANCH,rcstate));		/* or */
609 		regtail(ret, regnode(NOTHING,rcstate));		/* null. */
610 	} else if (op == '?') {
611 		/* Emit x? as (x|) */
612 		reginsert(BRANCH, ret, rcstate);			/* Either x */
613 		regtail(ret, regnode(BRANCH,rcstate));		/* or */
614 		next = regnode(NOTHING,rcstate);		/* null. */
615 		regtail(ret, next);
616 		regoptail(ret, next);
617 	}
618 	rcstate->regparse++;
619 	if (ISMULT(*rcstate->regparse))
620 		FAIL("nested *?+");
621 
622 	return(ret);
623 }
624 
625 /*
626  - regatom - the lowest level
627  *
628  * Optimization:  gobbles an entire sequence of ordinary characters so that
629  * it can turn them into a single node, which is smaller to store and
630  * faster to run.  Backslashed characters are exceptions, each becoming a
631  * separate node; the code is simpler that way and it's not worth fixing.
632  */
633 static char *
regatom(flagp,rcstate)634 regatom(flagp, rcstate)
635 int *flagp;
636 struct regcomp_state *rcstate;
637 {
638 	register char *ret;
639 	int flags;
640 
641 	*flagp = WORST;		/* Tentatively. */
642 
643 	switch (*rcstate->regparse++) {
644 	case '^':
645 		ret = regnode(BOL,rcstate);
646 		break;
647 	case '$':
648 		ret = regnode(EOL,rcstate);
649 		break;
650 	case '.':
651 		ret = regnode(ANY,rcstate);
652 		*flagp |= HASWIDTH|SIMPLE;
653 		break;
654 	case '[': {
655 			register int clss;
656 			register int classend;
657 
658 			if (*rcstate->regparse == '^') {	/* Complement of range. */
659 				ret = regnode(ANYBUT,rcstate);
660 				rcstate->regparse++;
661 			} else
662 				ret = regnode(ANYOF,rcstate);
663 			if (*rcstate->regparse == ']' || *rcstate->regparse == '-')
664 				regc(*rcstate->regparse++,rcstate);
665 			while (*rcstate->regparse != '\0' && *rcstate->regparse != ']') {
666 				if (*rcstate->regparse == '-') {
667 					rcstate->regparse++;
668 					if (*rcstate->regparse == ']' || *rcstate->regparse == '\0')
669 						regc('-',rcstate);
670 					else {
671 						clss = UCHARAT(rcstate->regparse-2)+1;
672 						classend = UCHARAT(rcstate->regparse);
673 						if (clss > classend+1)
674 							FAIL("invalid [] range");
675 						for (; clss <= classend; clss++)
676 							regc((char)clss,rcstate);
677 						rcstate->regparse++;
678 					}
679 				} else
680 					regc(*rcstate->regparse++,rcstate);
681 			}
682 			regc('\0',rcstate);
683 			if (*rcstate->regparse != ']')
684 				FAIL("unmatched []");
685 			rcstate->regparse++;
686 			*flagp |= HASWIDTH|SIMPLE;
687 		}
688 		break;
689 	case '(':
690 		ret = reg(1, &flags, rcstate);
691 		if (ret == NULL)
692 			return(NULL);
693 		*flagp |= flags&(HASWIDTH|SPSTART);
694 		break;
695 	case '\0':
696 	case '|':
697 	case ')':
698 		FAIL("internal urp");	/* Supposed to be caught earlier. */
699 		/* NOTREACHED */
700 	case '?':
701 	case '+':
702 	case '*':
703 		FAIL("?+* follows nothing");
704 		/* NOTREACHED */
705 	case '\\':
706 		if (*rcstate->regparse == '\0')
707 			FAIL("trailing \\");
708 		ret = regnode(EXACTLY,rcstate);
709 		regc(*rcstate->regparse++,rcstate);
710 		regc('\0',rcstate);
711 		*flagp |= HASWIDTH|SIMPLE;
712 		break;
713 	default: {
714 			register int len;
715 			register char ender;
716 
717 			rcstate->regparse--;
718 			len = strcspn(rcstate->regparse, META);
719 			if (len <= 0)
720 				FAIL("internal disaster");
721 			ender = *(rcstate->regparse+len);
722 			if (len > 1 && ISMULT(ender))
723 				len--;		/* Back off clear of ?+* operand. */
724 			*flagp |= HASWIDTH;
725 			if (len == 1)
726 				*flagp |= SIMPLE;
727 			ret = regnode(EXACTLY,rcstate);
728 			while (len > 0) {
729 				regc(*rcstate->regparse++,rcstate);
730 				len--;
731 			}
732 			regc('\0',rcstate);
733 		}
734 		break;
735 	}
736 
737 	return(ret);
738 }
739 
740 /*
741  - regnode - emit a node
742  */
743 static char *			/* Location. */
regnode(op,rcstate)744 regnode(op, rcstate)
745 int op;
746 struct regcomp_state *rcstate;
747 {
748 	register char *ret;
749 	register char *ptr;
750 
751 	ret = rcstate->regcode;
752 	if (ret == &regdummy) {
753 		rcstate->regsize += 3;
754 		return(ret);
755 	}
756 
757 	ptr = ret;
758 	*ptr++ = (char)op;
759 	*ptr++ = '\0';		/* Null "next" pointer. */
760 	*ptr++ = '\0';
761 	rcstate->regcode = ptr;
762 
763 	return(ret);
764 }
765 
766 /*
767  - regc - emit (if appropriate) a byte of code
768  */
769 static void
regc(b,rcstate)770 regc(b, rcstate)
771 int b;
772 struct regcomp_state *rcstate;
773 {
774 	if (rcstate->regcode != &regdummy)
775 		*rcstate->regcode++ = (char)b;
776 	else
777 		rcstate->regsize++;
778 }
779 
780 /*
781  - reginsert - insert an operator in front of already-emitted operand
782  *
783  * Means relocating the operand.
784  */
785 static void
reginsert(op,opnd,rcstate)786 reginsert(op, opnd, rcstate)
787 int op;
788 char *opnd;
789 struct regcomp_state *rcstate;
790 {
791 	register char *src;
792 	register char *dst;
793 	register char *place;
794 
795 	if (rcstate->regcode == &regdummy) {
796 		rcstate->regsize += 3;
797 		return;
798 	}
799 
800 	src = rcstate->regcode;
801 	rcstate->regcode += 3;
802 	dst = rcstate->regcode;
803 	while (src > opnd)
804 		*--dst = *--src;
805 
806 	place = opnd;		/* Op node, where operand used to be. */
807 	*place++ = (char)op;
808 	*place++ = '\0';
809 	*place = '\0';
810 }
811 
812 /*
813  - regtail - set the next-pointer at the end of a node chain
814  */
815 static void
regtail(p,val)816 regtail(p, val)
817 char *p;
818 char *val;
819 {
820 	register char *scan;
821 	register char *temp;
822 	register int offset;
823 
824 	if (p == &regdummy)
825 		return;
826 
827 	/* Find last node. */
828 	scan = p;
829 	for (;;) {
830 		temp = regnext(scan);
831 		if (temp == NULL)
832 			break;
833 		scan = temp;
834 	}
835 
836 	if (OP(scan) == BACK)
837 		offset = scan - val;
838 	else
839 		offset = val - scan;
840 	*(scan+1) = (char)((offset>>8)&0377);
841 	*(scan+2) = (char)(offset&0377);
842 }
843 
844 /*
845  - regoptail - regtail on operand of first argument; nop if operandless
846  */
847 static void
regoptail(p,val)848 regoptail(p, val)
849 char *p;
850 char *val;
851 {
852 	/* "Operandless" and "op != BRANCH" are synonymous in practice. */
853 	if (p == NULL || p == &regdummy || OP(p) != BRANCH)
854 		return;
855 	regtail(OPERAND(p), val);
856 }
857 
858 /*
859  * TclRegExec and friends
860  */
861 
862 /*
863  * Global work variables for TclRegExec().
864  */
865 struct regexec_state  {
866     char *reginput;		/* String-input pointer. */
867     char *regbol;		/* Beginning of input, for ^ check. */
868     char **regstartp;	/* Pointer to startp array. */
869     char **regendp;		/* Ditto for endp. */
870 };
871 
872 /*
873  * Forwards.
874  */
875 static int 		regtry _ANSI_ARGS_((regexp *prog, char *string,
876 			    struct regexec_state *restate));
877 static int 		regmatch _ANSI_ARGS_((char *prog,
878 			    struct regexec_state *restate));
879 static int 		regrepeat _ANSI_ARGS_((char *p,
880 			    struct regexec_state *restate));
881 
882 #ifdef DEBUG
883 int regnarrate = 0;
884 void regdump _ANSI_ARGS_((regexp *r));
885 static char *regprop _ANSI_ARGS_((char *op));
886 #endif
887 
888 /*
889  - TclRegExec - match a regexp against a string
890  */
891 int
TclRegExec(prog,string,start)892 TclRegExec(prog, string, start)
893 register regexp *prog;
894 register char *string;
895 char *start;
896 {
897 	register char *s;
898 	struct regexec_state state;
899 	struct regexec_state *restate= &state;
900 
901 	/* Be paranoid... */
902 	if (prog == NULL || string == NULL) {
903 		TclRegError("NULL parameter");
904 		return(0);
905 	}
906 
907 	/* Check validity of program. */
908 	if (UCHARAT(prog->program) != MAGIC) {
909 		TclRegError("corrupted program");
910 		return(0);
911 	}
912 
913 	/* If there is a "must appear" string, look for it. */
914 	if (prog->regmust != NULL) {
915 		s = string;
916 		while ((s = strchr(s, prog->regmust[0])) != NULL) {
917 			if (strncmp(s, prog->regmust, (size_t) prog->regmlen)
918 			    == 0)
919 				break;	/* Found it. */
920 			s++;
921 		}
922 		if (s == NULL)	/* Not present. */
923 			return(0);
924 	}
925 
926 	/* Mark beginning of line for ^ . */
927 	restate->regbol = start;
928 
929 	/* Simplest case:  anchored match need be tried only once. */
930 	if (prog->reganch)
931 		return(regtry(prog, string, restate));
932 
933 	/* Messy cases:  unanchored match. */
934 	s = string;
935 	if (prog->regstart != '\0')
936 		/* We know what char it must start with. */
937 		while ((s = strchr(s, prog->regstart)) != NULL) {
938 			if (regtry(prog, s, restate))
939 				return(1);
940 			s++;
941 		}
942 	else
943 		/* We don't -- general case. */
944 		do {
945 			if (regtry(prog, s, restate))
946 				return(1);
947 		} while (*s++ != '\0');
948 
949 	/* Failure. */
950 	return(0);
951 }
952 
953 /*
954  - regtry - try match at specific point
955  */
956 static int			/* 0 failure, 1 success */
regtry(prog,string,restate)957 regtry(prog, string, restate)
958 regexp *prog;
959 char *string;
960 struct regexec_state *restate;
961 {
962 	register int i;
963 	register char **sp;
964 	register char **ep;
965 
966 	restate->reginput = string;
967 	restate->regstartp = prog->startp;
968 	restate->regendp = prog->endp;
969 
970 	sp = prog->startp;
971 	ep = prog->endp;
972 	for (i = NSUBEXP; i > 0; i--) {
973 		*sp++ = NULL;
974 		*ep++ = NULL;
975 	}
976 	if (regmatch(prog->program + 1,restate)) {
977 		prog->startp[0] = string;
978 		prog->endp[0] = restate->reginput;
979 		return(1);
980 	} else
981 		return(0);
982 }
983 
984 /*
985  - regmatch - main matching routine
986  *
987  * Conceptually the strategy is simple:  check to see whether the current
988  * node matches, call self recursively to see whether the rest matches,
989  * and then act accordingly.  In practice we make some effort to avoid
990  * recursion, in particular by going through "ordinary" nodes (that don't
991  * need to know whether the rest of the match failed) by a loop instead of
992  * by recursion.
993  */
994 static int			/* 0 failure, 1 success */
regmatch(prog,restate)995 regmatch(prog, restate)
996 char *prog;
997 struct regexec_state *restate;
998 {
999     register char *scan;	/* Current node. */
1000     char *next;		/* Next node. */
1001 
1002     scan = prog;
1003 #ifdef DEBUG
1004     if (scan != NULL && regnarrate)
1005 	fprintf(stderr, "%s(\n", regprop(scan));
1006 #endif
1007     while (scan != NULL) {
1008 #ifdef DEBUG
1009 	if (regnarrate)
1010 	    fprintf(stderr, "%s...\n", regprop(scan));
1011 #endif
1012 	next = regnext(scan);
1013 
1014 	switch (OP(scan)) {
1015 	    case BOL:
1016 		if (restate->reginput != restate->regbol) {
1017 		    return 0;
1018 		}
1019 		break;
1020 	    case EOL:
1021 		if (*restate->reginput != '\0') {
1022 		    return 0;
1023 		}
1024 		break;
1025 	    case ANY:
1026 		if (*restate->reginput == '\0') {
1027 		    return 0;
1028 		}
1029 		restate->reginput++;
1030 		break;
1031 	    case EXACTLY: {
1032 		register int len;
1033 		register char *opnd;
1034 
1035 		opnd = OPERAND(scan);
1036 		/* Inline the first character, for speed. */
1037 		if (*opnd != *restate->reginput) {
1038 		    return 0 ;
1039 		}
1040 		len = strlen(opnd);
1041 		if (len > 1 && strncmp(opnd, restate->reginput, (size_t) len)
1042 			!= 0) {
1043 		    return 0;
1044 		}
1045 		restate->reginput += len;
1046 		break;
1047 	    }
1048 	    case ANYOF:
1049 		if (*restate->reginput == '\0'
1050 			|| strchr(OPERAND(scan), *restate->reginput) == NULL) {
1051 		    return 0;
1052 		}
1053 		restate->reginput++;
1054 		break;
1055 	    case ANYBUT:
1056 		if (*restate->reginput == '\0'
1057 			|| strchr(OPERAND(scan), *restate->reginput) != NULL) {
1058 		    return 0;
1059 		}
1060 		restate->reginput++;
1061 		break;
1062 	    case NOTHING:
1063 		break;
1064 	    case BACK:
1065 		break;
1066 	    case OPEN+1:
1067 	    case OPEN+2:
1068 	    case OPEN+3:
1069 	    case OPEN+4:
1070 	    case OPEN+5:
1071 	    case OPEN+6:
1072 	    case OPEN+7:
1073 	    case OPEN+8:
1074 	    case OPEN+9: {
1075 		register int no;
1076 		register char *save;
1077 
1078 	doOpen:
1079 		no = OP(scan) - OPEN;
1080 		save = restate->reginput;
1081 
1082 		if (regmatch(next,restate)) {
1083 		    /*
1084 		     * Don't set startp if some later invocation of the
1085 		     * same parentheses already has.
1086 		     */
1087 		    if (restate->regstartp[no] == NULL) {
1088 			restate->regstartp[no] = save;
1089 		    }
1090 		    return 1;
1091 		} else {
1092 		    return 0;
1093 		}
1094 	    }
1095 	    case CLOSE+1:
1096 	    case CLOSE+2:
1097 	    case CLOSE+3:
1098 	    case CLOSE+4:
1099 	    case CLOSE+5:
1100 	    case CLOSE+6:
1101 	    case CLOSE+7:
1102 	    case CLOSE+8:
1103 	    case CLOSE+9: {
1104 		register int no;
1105 		register char *save;
1106 
1107 	doClose:
1108 		no = OP(scan) - CLOSE;
1109 		save = restate->reginput;
1110 
1111 		if (regmatch(next,restate)) {
1112 				/*
1113 				 * Don't set endp if some later
1114 				 * invocation of the same parentheses
1115 				 * already has.
1116 				 */
1117 		    if (restate->regendp[no] == NULL)
1118 			restate->regendp[no] = save;
1119 		    return 1;
1120 		} else {
1121 		    return 0;
1122 		}
1123 	    }
1124 	    case BRANCH: {
1125 		register char *save;
1126 
1127 		if (OP(next) != BRANCH) { /* No choice. */
1128 		    next = OPERAND(scan); /* Avoid recursion. */
1129 		} else {
1130 		    do {
1131 			save = restate->reginput;
1132 			if (regmatch(OPERAND(scan),restate))
1133 			    return(1);
1134 			restate->reginput = save;
1135 			scan = regnext(scan);
1136 		    } while (scan != NULL && OP(scan) == BRANCH);
1137 		    return 0;
1138 		}
1139 		break;
1140 	    }
1141 	    case STAR:
1142 	    case PLUS: {
1143 		register char nextch;
1144 		register int no;
1145 		register char *save;
1146 		register int min;
1147 
1148 		/*
1149 		 * Lookahead to avoid useless match attempts
1150 		 * when we know what character comes next.
1151 		 */
1152 		nextch = '\0';
1153 		if (OP(next) == EXACTLY)
1154 		    nextch = *OPERAND(next);
1155 		min = (OP(scan) == STAR) ? 0 : 1;
1156 		save = restate->reginput;
1157 		no = regrepeat(OPERAND(scan),restate);
1158 		while (no >= min) {
1159 		    /* If it could work, try it. */
1160 		    if (nextch == '\0' || *restate->reginput == nextch)
1161 			if (regmatch(next,restate))
1162 			    return(1);
1163 		    /* Couldn't or didn't -- back up. */
1164 		    no--;
1165 		    restate->reginput = save + no;
1166 		}
1167 		return(0);
1168 	    }
1169 	    case END:
1170 		return(1);	/* Success! */
1171 	    default:
1172 		if (OP(scan) > OPEN && OP(scan) < OPEN+NSUBEXP) {
1173 		    goto doOpen;
1174 		} else if (OP(scan) > CLOSE && OP(scan) < CLOSE+NSUBEXP) {
1175 		    goto doClose;
1176 		}
1177 		TclRegError("memory corruption");
1178 		return 0;
1179 	}
1180 
1181 	scan = next;
1182     }
1183 
1184     /*
1185      * We get here only if there's trouble -- normally "case END" is
1186      * the terminating point.
1187      */
1188     TclRegError("corrupted pointers");
1189     return(0);
1190 }
1191 
1192 /*
1193  - regrepeat - repeatedly match something simple, report how many
1194  */
1195 static int
regrepeat(p,restate)1196 regrepeat(p, restate)
1197 char *p;
1198 struct regexec_state *restate;
1199 {
1200 	register int count = 0;
1201 	register char *scan;
1202 	register char *opnd;
1203 
1204 	scan = restate->reginput;
1205 	opnd = OPERAND(p);
1206 	switch (OP(p)) {
1207 	case ANY:
1208 		count = strlen(scan);
1209 		scan += count;
1210 		break;
1211 	case EXACTLY:
1212 		while (*opnd == *scan) {
1213 			count++;
1214 			scan++;
1215 		}
1216 		break;
1217 	case ANYOF:
1218 		while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
1219 			count++;
1220 			scan++;
1221 		}
1222 		break;
1223 	case ANYBUT:
1224 		while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
1225 			count++;
1226 			scan++;
1227 		}
1228 		break;
1229 	default:		/* Oh dear.  Called inappropriately. */
1230 		TclRegError("internal foulup");
1231 		count = 0;	/* Best compromise. */
1232 		break;
1233 	}
1234 	restate->reginput = scan;
1235 
1236 	return(count);
1237 }
1238 
1239 /*
1240  - regnext - dig the "next" pointer out of a node
1241  */
1242 static char *
regnext(p)1243 regnext(p)
1244 register char *p;
1245 {
1246 	register int offset;
1247 
1248 	if (p == &regdummy)
1249 		return(NULL);
1250 
1251 	offset = NEXT(p);
1252 	if (offset == 0)
1253 		return(NULL);
1254 
1255 	if (OP(p) == BACK)
1256 		return(p-offset);
1257 	else
1258 		return(p+offset);
1259 }
1260 
1261 #ifdef DEBUG
1262 
1263 static char *regprop();
1264 
1265 /*
1266  - regdump - dump a regexp onto stdout in vaguely comprehensible form
1267  */
1268 void
regdump(r)1269 regdump(r)
1270 regexp *r;
1271 {
1272 	register char *s;
1273 	register char op = EXACTLY;	/* Arbitrary non-END op. */
1274 	register char *next;
1275 
1276 
1277 	s = r->program + 1;
1278 	while (op != END) {	/* While that wasn't END last time... */
1279 		op = OP(s);
1280 		printf("%2d%s", s-r->program, regprop(s));	/* Where, what. */
1281 		next = regnext(s);
1282 		if (next == NULL)		/* Next ptr. */
1283 			printf("(0)");
1284 		else
1285 			printf("(%d)", (s-r->program)+(next-s));
1286 		s += 3;
1287 		if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
1288 			/* Literal string, where present. */
1289 			while (*s != '\0') {
1290 				putchar(*s);
1291 				s++;
1292 			}
1293 			s++;
1294 		}
1295 		putchar('\n');
1296 	}
1297 
1298 	/* Header fields of interest. */
1299 	if (r->regstart != '\0')
1300 		printf("start `%c' ", r->regstart);
1301 	if (r->reganch)
1302 		printf("anchored ");
1303 	if (r->regmust != NULL)
1304 		printf("must have \"%s\"", r->regmust);
1305 	printf("\n");
1306 }
1307 
1308 /*
1309  - regprop - printable representation of opcode
1310  */
1311 static char *
regprop(op)1312 regprop(op)
1313 char *op;
1314 {
1315 	register char *p;
1316 	static char buf[50];
1317 
1318 	(void) strcpy(buf, ":");
1319 
1320 	switch (OP(op)) {
1321 	case BOL:
1322 		p = "BOL";
1323 		break;
1324 	case EOL:
1325 		p = "EOL";
1326 		break;
1327 	case ANY:
1328 		p = "ANY";
1329 		break;
1330 	case ANYOF:
1331 		p = "ANYOF";
1332 		break;
1333 	case ANYBUT:
1334 		p = "ANYBUT";
1335 		break;
1336 	case BRANCH:
1337 		p = "BRANCH";
1338 		break;
1339 	case EXACTLY:
1340 		p = "EXACTLY";
1341 		break;
1342 	case NOTHING:
1343 		p = "NOTHING";
1344 		break;
1345 	case BACK:
1346 		p = "BACK";
1347 		break;
1348 	case END:
1349 		p = "END";
1350 		break;
1351 	case OPEN+1:
1352 	case OPEN+2:
1353 	case OPEN+3:
1354 	case OPEN+4:
1355 	case OPEN+5:
1356 	case OPEN+6:
1357 	case OPEN+7:
1358 	case OPEN+8:
1359 	case OPEN+9:
1360 		sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
1361 		p = NULL;
1362 		break;
1363 	case CLOSE+1:
1364 	case CLOSE+2:
1365 	case CLOSE+3:
1366 	case CLOSE+4:
1367 	case CLOSE+5:
1368 	case CLOSE+6:
1369 	case CLOSE+7:
1370 	case CLOSE+8:
1371 	case CLOSE+9:
1372 		sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
1373 		p = NULL;
1374 		break;
1375 	case STAR:
1376 		p = "STAR";
1377 		break;
1378 	case PLUS:
1379 		p = "PLUS";
1380 		break;
1381 	default:
1382 		if (OP(op) > OPEN && OP(op) < OPEN+NSUBEXP) {
1383 		    sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
1384 		    p = NULL;
1385 		    break;
1386 		} else if (OP(op) > CLOSE && OP(op) < CLOSE+NSUBEXP) {
1387 		    sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
1388 		    p = NULL;
1389 		} else {
1390 		    TclRegError("corrupted opcode");
1391 		}
1392 		break;
1393 	}
1394 	if (p != NULL)
1395 		(void) strcat(buf, p);
1396 	return(buf);
1397 }
1398 #endif
1399 
1400 /*
1401  * The following is provided for those people who do not have strcspn() in
1402  * their C libraries.  They should get off their butts and do something
1403  * about it; at least one public-domain implementation of those (highly
1404  * useful) string routines has been published on Usenet.
1405  */
1406 #ifdef STRCSPN
1407 /*
1408  * strcspn - find length of initial segment of s1 consisting entirely
1409  * of characters not from s2
1410  */
1411 
1412 static int
strcspn(s1,s2)1413 strcspn(s1, s2)
1414 char *s1;
1415 char *s2;
1416 {
1417 	register char *scan1;
1418 	register char *scan2;
1419 	register int count;
1420 
1421 	count = 0;
1422 	for (scan1 = s1; *scan1 != '\0'; scan1++) {
1423 		for (scan2 = s2; *scan2 != '\0';)	/* ++ moved down. */
1424 			if (*scan1 == *scan2++)
1425 				return(count);
1426 		count++;
1427 	}
1428 	return(count);
1429 }
1430 #endif
1431 
1432 /*
1433  *----------------------------------------------------------------------
1434  *
1435  * TclRegError --
1436  *
1437  *	This procedure is invoked by the regexp code when an error
1438  *	occurs.  It saves the error message so it can be seen by the
1439  *	code that called Spencer's code.
1440  *
1441  * Results:
1442  *	None.
1443  *
1444  * Side effects:
1445  *	The value of "string" is saved in "errMsg".
1446  *
1447  *----------------------------------------------------------------------
1448  */
1449 
1450 void
exp_TclRegError(string)1451 exp_TclRegError(string)
1452     char *string;			/* Error message. */
1453 {
1454     errMsg = string;
1455 }
1456 
1457 char *
TclGetRegError()1458 TclGetRegError()
1459 {
1460     return errMsg;
1461 }
1462 
1463 /*
1464  * end of regexp definitions and code
1465  */
1466 
1467 /*
1468  * stolen from exp_log.c - this function is called from the Expect library
1469  * but the one that the library supplies calls Tcl functions.  So we supply
1470  * our own.
1471  */
1472 
1473 static
1474 void
expDiagLogU(str)1475 expDiagLogU(str)
1476      char *str;
1477 {
1478   if (exp_is_debugging) {
1479     fprintf(stderr,str);
1480     if (exp_logfile) fprintf(exp_logfile,str);
1481   }
1482 }
1483 
1484 /*
1485  * expect-specific definitions and code
1486  */
1487 
1488 #include "expect.h"
1489 #include "exp_int.h"
1490 
1491 /* exp_glob.c - expect functions for doing glob
1492  *
1493  * Based on Tcl's glob functions but modified to support anchors and to
1494  * return information about the possibility of future matches
1495  *
1496  * Modifications by: Don Libes, NIST, 2/6/90
1497  */
1498 
1499 /* The following functions implement expect's glob-style string
1500  * matching Exp_StringMatch allow's implements the unanchored front
1501  * (or conversely the '^') feature.  Exp_StringMatch2 does the rest of
1502  * the work.
1503  */
1504 
1505 /* Exp_StringMatch2 --
1506  *
1507  * Like Tcl_StringMatch except that
1508  * 1) returns number of characters matched, -1 if failed.
1509  *	(Can return 0 on patterns like "" or "$")
1510  * 2) does not require pattern to match to end of string
1511  * 3) much of code is stolen from Tcl_StringMatch
1512  * 4) front-anchor is assumed (Tcl_StringMatch retries for non-front-anchor)
1513  */
1514 static
1515 int
Exp_StringMatch2(string,pattern)1516 Exp_StringMatch2(string,pattern)
1517     register char *string;	/* String. */
1518     register char *pattern;	/* Pattern, which may contain
1519 				 * special characters. */
1520 {
1521     char c2;
1522     int match = 0;	/* # of chars matched */
1523 
1524     while (1) {
1525 	/* If at end of pattern, success! */
1526 	if (*pattern == 0) {
1527 		return match;
1528 	}
1529 
1530 	/* If last pattern character is '$', verify that entire
1531 	 * string has been matched.
1532 	 */
1533 	if ((*pattern == '$') && (pattern[1] == 0)) {
1534 		if (*string == 0) return(match);
1535 		else return(-1);
1536 	}
1537 
1538 	/* Check for a "*" as the next pattern character.  It matches
1539 	 * any substring.  We handle this by calling ourselves
1540 	 * recursively for each postfix of string, until either we
1541 	 * match or we reach the end of the string.
1542 	 */
1543 
1544 	if (*pattern == '*') {
1545 	    int head_len;
1546 	    char *tail;
1547 	    pattern += 1;
1548 	    if (*pattern == 0) {
1549 		return(strlen(string)+match); /* DEL */
1550 	    }
1551 	    /* find longest match - switched to this on 12/31/93 */
1552 	    head_len = strlen(string);	/* length before tail */
1553 	    tail = string + head_len;
1554 	    while (head_len >= 0) {
1555 		int rc;
1556 
1557 		if (-1 != (rc = Exp_StringMatch2(tail, pattern))) {
1558 		    return rc + match + head_len;	/* DEL */
1559 		}
1560 		tail--;
1561 		head_len--;
1562 	    }
1563 	    return -1;					/* DEL */
1564 	}
1565 
1566 	/*
1567 	 * after this point, all patterns must match at least one
1568 	 * character, so check this
1569 	 */
1570 
1571 	if (*string == 0) return -1;
1572 
1573 	/* Check for a "?" as the next pattern character.  It matches
1574 	 * any single character.
1575 	 */
1576 
1577 	if (*pattern == '?') {
1578 	    goto thisCharOK;
1579 	}
1580 
1581 	/* Check for a "[" as the next pattern character.  It is followed
1582 	 * by a list of characters that are acceptable, or by a range
1583 	 * (two characters separated by "-").
1584 	 */
1585 
1586 	if (*pattern == '[') {
1587 	    pattern += 1;
1588 	    while (1) {
1589 		if ((*pattern == ']') || (*pattern == 0)) {
1590 		    return -1;			/* was 0; DEL */
1591 		}
1592 		if (*pattern == *string) {
1593 		    break;
1594 		}
1595 		if (pattern[1] == '-') {
1596 		    c2 = pattern[2];
1597 		    if (c2 == 0) {
1598 			return -1;		/* DEL */
1599 		    }
1600 		    if ((*pattern <= *string) && (c2 >= *string)) {
1601 			break;
1602 		    }
1603 		    if ((*pattern >= *string) && (c2 <= *string)) {
1604 			break;
1605 		    }
1606 		    pattern += 2;
1607 		}
1608 		pattern += 1;
1609 	    }
1610 
1611 	    while (*pattern != ']') {
1612 		if (*pattern == 0) {
1613 		    pattern--;
1614 		    break;
1615 	        }
1616 		pattern += 1;
1617 	    }
1618 	    goto thisCharOK;
1619 	}
1620 
1621 	/* If the next pattern character is backslash, strip it off
1622 	 * so we do exact matching on the character that follows.
1623 	 */
1624 
1625 	if (*pattern == '\\') {
1626 	    pattern += 1;
1627 	    if (*pattern == 0) {
1628 		return -1;
1629 	    }
1630 	}
1631 
1632 	/* There's no special character.  Just make sure that the next
1633 	 * characters of each string match.
1634 	 */
1635 
1636 	if (*pattern != *string) {
1637 	    return -1;
1638 	}
1639 
1640 	thisCharOK: pattern += 1;
1641 	string += 1;
1642 	match++;
1643     }
1644 }
1645 
1646 
1647 static
1648 int	/* returns # of chars that matched */
Exp_StringMatch(string,pattern,offset)1649 Exp_StringMatch(string, pattern,offset)
1650 char *string;
1651 char *pattern;
1652 int *offset;	/* offset from beginning of string where pattern matches */
1653 {
1654 	char *s;
1655 	int sm;	/* count of chars matched or -1 */
1656 	int caret = FALSE;
1657 	int star = FALSE;
1658 
1659 	*offset = 0;
1660 
1661 	if (pattern[0] == '^') {
1662 		caret = TRUE;
1663 		pattern++;
1664 	} else if (pattern[0] == '*') {
1665 		star = TRUE;
1666 	}
1667 
1668 	/*
1669 	 * test if pattern matches in initial position.
1670 	 * This handles front-anchor and 1st iteration of non-front-anchor.
1671 	 * Note that 1st iteration must be tried even if string is empty.
1672 	 */
1673 
1674 	sm = Exp_StringMatch2(string,pattern);
1675 	if (sm >= 0) return(sm);
1676 
1677 	if (caret) return -1;
1678 	if (star) return -1;
1679 
1680 	if (*string == '\0') return -1;
1681 
1682 	for (s = string+1;*s;s++) {
1683  		sm = Exp_StringMatch2(s,pattern);
1684 		if (sm != -1) {
1685 			*offset = s-string;
1686 			return(sm);
1687 		}
1688 	}
1689 	return -1;
1690 }
1691 
1692 
1693 #define EXP_MATCH_MAX	2000
1694 /* public */
1695 char *exp_buffer = 0;
1696 char *exp_buffer_end = 0;
1697 char *exp_match = 0;
1698 char *exp_match_end = 0;
1699 int exp_match_max = EXP_MATCH_MAX;	/* bytes */
1700 int exp_full_buffer = FALSE;		/* don't return on full buffer */
1701 int exp_remove_nulls = TRUE;
1702 int exp_timeout = 10;			/* seconds */
1703 int exp_pty_timeout = 5;		/* seconds - see CRAY below */
1704 int exp_autoallocpty = TRUE;		/* if TRUE, we do allocation */
1705 int exp_pty[2];				/* master is [0], slave is [1] */
1706 int exp_pid;
1707 char *exp_stty_init = 0;		/* initial stty args */
1708 int exp_ttycopy = TRUE;			/* copy tty parms from /dev/tty */
1709 int exp_ttyinit = TRUE;			/* set tty parms to sane state */
1710 int exp_console = FALSE;		/* redirect console */
1711 void (*exp_child_exec_prelude)() = 0;
1712 void (*exp_close_in_child)() = 0;
1713 
1714 #ifdef HAVE_SIGLONGJMP
1715 sigjmp_buf exp_readenv;		/* for interruptable read() */
1716 #else
1717 jmp_buf exp_readenv;		/* for interruptable read() */
1718 #endif /* HAVE_SIGLONGJMP */
1719 
1720 int exp_reading = FALSE;	/* whether we can longjmp or not */
1721 
1722 int exp_is_debugging = FALSE;
1723 FILE *exp_debugfile = 0;
1724 
1725 FILE *exp_logfile = 0;
1726 int exp_logfile_all = FALSE;	/* if TRUE, write log of all interactions */
1727 int exp_loguser = TRUE;		/* if TRUE, user sees interactions on stdout */
1728 
1729 
1730 char *exp_printify();
1731 int exp_getptymaster();
1732 int exp_getptyslave();
1733 
1734 #define sysreturn(x)	return(errno = x, -1)
1735 
1736 void exp_init_pty();
1737 
1738 /*
1739    The following functions are linked from the Tcl library.  They
1740    don't cause anything else in the library to be dragged in, so it
1741    shouldn't cause any problems (e.g., bloat).
1742 
1743    The functions are relatively small but painful enough that I don't care
1744    to recode them.  You may, if you absolutely want to get rid of any
1745    vestiges of Tcl.
1746 */
1747 
1748 static unsigned int bufsiz = 2*EXP_MATCH_MAX;
1749 
1750 static struct f {
1751 	int valid;
1752 
1753 	char *buffer;		/* buffer of matchable chars */
1754 	char *buffer_end;	/* one beyond end of matchable chars */
1755 	char *match_end;	/* one beyond end of matched string */
1756 	int msize;		/* size of allocate space */
1757 				/* actual size is one larger for null */
1758 } *fs = 0;
1759 
1760 static int fd_alloc_max = -1;	/* max fd allocated */
1761 
1762 /* translate fd or fp to fd */
1763 static struct f *
fdfp2f(fd,fp)1764 fdfp2f(fd,fp)
1765 int fd;
1766 FILE *fp;
1767 {
1768 	if (fd == -1) return(fs + fileno(fp));
1769 	else return(fs + fd);
1770 }
1771 
1772 static struct f *
fd_new(fd)1773 fd_new(fd)
1774 int fd;
1775 {
1776 	int i, low;
1777 	struct f *fp;
1778 	struct f *newfs;	/* temporary, so we don't lose old fs */
1779 
1780 	if (fd > fd_alloc_max) {
1781 		if (!fs) {	/* no fd's yet allocated */
1782 			newfs = (struct f *)malloc(sizeof(struct f)*(fd+1));
1783 			low = 0;
1784 		} else {		/* enlarge fd table */
1785 			newfs = (struct f *)realloc((char *)fs,sizeof(struct f)*(fd+1));
1786 			low = fd_alloc_max+1;
1787 		}
1788 		fs = newfs;
1789 		fd_alloc_max = fd;
1790 		for (i = low; i <= fd_alloc_max; i++) { /* init new entries */
1791 			fs[i].valid = FALSE;
1792 		}
1793 	}
1794 
1795 	fp = fs+fd;
1796 
1797 	if (!fp->valid) {
1798 		/* initialize */
1799 		fp->buffer = malloc((unsigned)(bufsiz+1));
1800 		if (!fp->buffer) return 0;
1801 		fp->msize = bufsiz;
1802 		fp->valid = TRUE;
1803 	}
1804 	fp->buffer_end = fp->buffer;
1805 	fp->match_end = fp->buffer;
1806 	return fp;
1807 
1808 }
1809 
1810 static
1811 void
exp_setpgrp()1812 exp_setpgrp()
1813 {
1814 #ifdef MIPS_BSD
1815     /* required on BSD side of MIPS OS <jmsellen@watdragon.waterloo.edu> */
1816 #   include <sysv/sys.s>
1817     syscall(SYS_setpgrp);
1818 #endif
1819 
1820 #ifdef SETPGRP_VOID
1821     (void) setpgrp();
1822 #else
1823     (void) setpgrp(0,0);
1824 #endif
1825 }
1826 
1827 /* returns fd of master side of pty */
1828 int
exp_spawnv(file,argv)1829 exp_spawnv(file,argv)
1830 char *file;
1831 char *argv[];	/* some compiler complains about **argv? */
1832 {
1833 	int cc;
1834 	int errorfd;	/* place to stash fileno(stderr) in child */
1835 			/* while we're setting up new stderr */
1836 	int ttyfd;
1837 	int sync_fds[2];
1838 	int sync2_fds[2];
1839 	int status_pipe[2];
1840 	int child_errno;
1841 	char sync_byte;
1842 #ifdef PTYTRAP_DIES
1843 	int slave_write_ioctls = 1;
1844 		/* by default, slave will be write-ioctled this many times */
1845 #endif
1846 
1847 	static int first_time = TRUE;
1848 
1849 	if (first_time) {
1850 		first_time = FALSE;
1851 		exp_init_pty();
1852 		exp_init_tty();
1853 		expDiagLogPtrSet(expDiagLogU);
1854 
1855 		/*
1856 		 * TIP 27; It is unclear why this code produces a
1857 		 * warning. The equivalent code in exp_main_sub.c
1858 		 * (line 512) does not generate a warning !
1859 		 */
1860 
1861 		expErrnoMsgSet(Tcl_ErrnoMsg);
1862 	}
1863 
1864 	if (!file || !argv) sysreturn(EINVAL);
1865 	if (!argv[0] || strcmp(file,argv[0])) {
1866 		exp_debuglog("expect: warning: file (%s) != argv[0] (%s)\n",
1867 			file,
1868 			argv[0]?argv[0]:"");
1869 	}
1870 
1871 #ifdef PTYTRAP_DIES
1872 /* any extraneous ioctl's that occur in slave must be accounted for
1873 when trapping, see below in child half of fork */
1874 #if defined(TIOCSCTTY) && !defined(CIBAUD) && !defined(sun) && !defined(hp9000s300)
1875 	slave_write_ioctls++;
1876 #endif
1877 #endif /*PTYTRAP_DIES*/
1878 
1879 	if (exp_autoallocpty) {
1880 		if (0 > (exp_pty[0] = exp_getptymaster())) sysreturn(ENODEV);
1881 	}
1882 	fcntl(exp_pty[0],F_SETFD,1);	/* close on exec */
1883 #ifdef PTYTRAP_DIES
1884 	exp_slave_control(exp_pty[0],1);*/
1885 #endif
1886 
1887 	if (!fd_new(exp_pty[0])) {
1888 		errno = ENOMEM;
1889 		return -1;
1890 	}
1891 
1892 	if (-1 == (pipe(sync_fds))) {
1893 		return -1;
1894 	}
1895 	if (-1 == (pipe(sync2_fds))) {
1896 		close(sync_fds[0]);
1897 		close(sync_fds[1]);
1898 		return -1;
1899 	}
1900 
1901 	if (-1 == pipe(status_pipe)) {
1902 		close(sync_fds[0]);
1903 		close(sync_fds[1]);
1904 		close(sync2_fds[0]);
1905 		close(sync2_fds[1]);
1906 		return -1;
1907 	}
1908 
1909 	if ((exp_pid = fork()) == -1) return(-1);
1910 	if (exp_pid) {
1911 		/* parent */
1912 		close(sync_fds[1]);
1913 		close(sync2_fds[0]);
1914 		close(status_pipe[1]);
1915 
1916 		if (!exp_autoallocpty) close(exp_pty[1]);
1917 
1918 #ifdef PTYTRAP_DIES
1919 #ifdef HAVE_PTYTRAP
1920 		if (exp_autoallocpty) {
1921 			/* trap initial ioctls in a feeble attempt to not */
1922 			/* block the initially.  If the process itself */
1923 			/* ioctls /dev/tty, such blocks will be trapped */
1924 			/* later during normal event processing */
1925 
1926 			while (slave_write_ioctls) {
1927 				int cc;
1928 
1929 				cc = exp_wait_for_slave_open(exp_pty[0]);
1930 #if defined(TIOCSCTTY) && !defined(CIBAUD) && !defined(sun) && !defined(hp9000s300)
1931 				if (cc == TIOCSCTTY) slave_write_ioctls = 0;
1932 #endif
1933 				if (cc & IOC_IN) slave_write_ioctls--;
1934 				else if (cc == -1) {
1935 					printf("failed to trap slave pty");
1936 					return -1;
1937 				}
1938 			}
1939 		}
1940 #endif
1941 #endif /*PTYTRAP_DIES*/
1942 
1943 		/*
1944 		 * wait for slave to initialize pty before allowing
1945 		 * user to send to it
1946 		 */
1947 
1948 		exp_debuglog("parent: waiting for sync byte\r\n");
1949 		cc = read(sync_fds[0],&sync_byte,1);
1950 		if (cc == -1) {
1951 		  exp_errorlog("parent sync byte read: %s\r\n",Tcl_ErrnoMsg(errno));
1952 		  return -1;
1953 		}
1954 
1955 		/* turn on detection of eof */
1956 		exp_slave_control(exp_pty[0],1);
1957 
1958 		/*
1959 		 * tell slave to go on now now that we have initialized pty
1960 		 */
1961 
1962 		exp_debuglog("parent: telling child to go ahead\r\n");
1963 		cc = write(sync2_fds[1]," ",1);
1964 		if (cc == -1) {
1965 		  exp_errorlog("parent sync byte write: %s\r\n",Tcl_ErrnoMsg(errno));
1966 		  return -1;
1967 		}
1968 
1969 		exp_debuglog("parent: now unsynchronized from child\r\n");
1970 
1971 		close(sync_fds[0]);
1972 		close(sync2_fds[1]);
1973 
1974 		/* see if child's exec worked */
1975 
1976 	retry:
1977 		switch (read(status_pipe[0],&child_errno,sizeof child_errno)) {
1978 		case -1:
1979 			if (errno == EINTR) goto retry;
1980 			/* well it's not really the child's errno */
1981 			/* but it can be treated that way */
1982 			child_errno = errno;
1983 			break;
1984 		case 0:
1985 			/* child's exec succeeded */
1986 			child_errno = 0;
1987 			break;
1988 		default:
1989 			/* child's exec failed; err contains exec's errno  */
1990 			waitpid(exp_pid, NULL, 0);
1991 			errno = child_errno;
1992 			exp_pty[0] = -1;
1993 		}
1994 		close(status_pipe[0]);
1995 		return(exp_pty[0]);
1996 	}
1997 
1998 	/*
1999 	 * child process - do not return from here!  all errors must exit()
2000 	 */
2001 
2002 	close(sync_fds[0]);
2003 	close(sync2_fds[1]);
2004 	close(status_pipe[0]);
2005 	fcntl(status_pipe[1],F_SETFD,1);	/* close on exec */
2006 
2007 #ifdef CRAY
2008 	(void) close(exp_pty[0]);
2009 #endif
2010 
2011 /* ultrix (at least 4.1-2) fails to obtain controlling tty if setsid */
2012 /* is called.  setpgrp works though.  */
2013 #if defined(POSIX) && !defined(ultrix)
2014 #define DO_SETSID
2015 #endif
2016 #ifdef __convex__
2017 #define DO_SETSID
2018 #endif
2019 
2020 #ifdef DO_SETSID
2021 	setsid();
2022 #else
2023 #ifdef SYSV3
2024 #ifndef CRAY
2025 	exp_setpgrp();
2026 #endif /* CRAY */
2027 #else /* !SYSV3 */
2028 	exp_setpgrp();
2029 
2030 #ifdef TIOCNOTTY
2031 	ttyfd = open("/dev/tty", O_RDWR);
2032 	if (ttyfd >= 0) {
2033 		(void) ioctl(ttyfd, TIOCNOTTY, (char *)0);
2034 		(void) close(ttyfd);
2035 	}
2036 #endif /* TIOCNOTTY */
2037 
2038 #endif /* SYSV3 */
2039 #endif /* DO_SETSID */
2040 
2041 	/* save error fd while we're setting up new one */
2042 	errorfd = fcntl(2,F_DUPFD,3);
2043 	/* and here is the macro to restore it */
2044 #define restore_error_fd {close(2);fcntl(errorfd,F_DUPFD,2);}
2045 
2046 	if (exp_autoallocpty) {
2047 
2048 	    close(0);
2049 	    close(1);
2050 	    close(2);
2051 
2052 	    /* since we closed fd 0, open of pty slave must return fd 0 */
2053 
2054 	    if (0 > (exp_pty[1] = exp_getptyslave(exp_ttycopy,exp_ttyinit,
2055 						exp_stty_init))) {
2056 		restore_error_fd
2057 		fprintf(stderr,"open(slave pty): %s\n",Tcl_ErrnoMsg(errno));
2058 		exit(-1);
2059 	    }
2060 	    /* sanity check */
2061 	    if (exp_pty[1] != 0) {
2062 		restore_error_fd
2063 		fprintf(stderr,"exp_getptyslave: slave = %d but expected 0\n",
2064 								exp_pty[1]);
2065 		exit(-1);
2066 	    }
2067 	} else {
2068 		if (exp_pty[1] != 0) {
2069 			close(0);	fcntl(exp_pty[1],F_DUPFD,0);
2070 		}
2071 		close(1);		fcntl(0,F_DUPFD,1);
2072 		close(2);		fcntl(0,F_DUPFD,1);
2073 		close(exp_pty[1]);
2074 	}
2075 
2076 
2077 
2078 /* The test for hpux may have to be more specific.  In particular, the */
2079 /* code should be skipped on the hp9000s300 and hp9000s720 (but there */
2080 /* is no documented define for the 720!) */
2081 
2082 #if defined(TIOCSCTTY) && !defined(sun) && !defined(hpux)
2083 	/* 4.3+BSD way to acquire controlling terminal */
2084 	/* according to Stevens - Adv. Prog..., p 642 */
2085 #ifdef __QNX__ /* posix in general */
2086 	if (tcsetct(0, getpid()) == -1) {
2087 	  restore_error_fd
2088 	  expErrorLog("failed to get controlling terminal using TIOCSCTTY");
2089 	  exit(-1);
2090 	}
2091 #else
2092 	(void) ioctl(0,TIOCSCTTY,(char *)0);
2093 	/* ignore return value - on some systems, it is defined but it
2094 	 * fails and it doesn't seem to cause any problems.  Or maybe
2095 	 * it works but returns a bogus code.  Noone seems to be able
2096 	 * to explain this to me.  The systems are an assortment of
2097 	 * different linux systems (and FreeBSD 2.5), RedHat 5.2 and
2098 	 * Debian 2.0
2099 	 */
2100 #endif
2101 #endif
2102 
2103 #ifdef CRAY
2104  	(void) setsid();
2105  	(void) ioctl(0,TCSETCTTY,0);
2106  	(void) close(0);
2107  	if (open("/dev/tty", O_RDWR) < 0) {
2108 		restore_error_fd
2109  		fprintf(stderr,"open(/dev/tty): %s\r\n",Tcl_ErrnoMsg(errno));
2110  		exit(-1);
2111  	}
2112  	(void) close(1);
2113  	(void) close(2);
2114  	(void) dup(0);
2115  	(void) dup(0);
2116 	setptyutmp();	/* create a utmp entry */
2117 
2118 	/* _CRAY2 code from Hal Peterson <hrp@cray.com>, Cray Research, Inc. */
2119 #ifdef _CRAY2
2120 	/*
2121 	 * Interpose a process between expect and the spawned child to
2122 	 * keep the slave side of the pty open to allow time for expect
2123 	 * to read the last output.  This is a workaround for an apparent
2124 	 * bug in the Unicos pty driver on Cray-2's under Unicos 6.0 (at
2125 	 * least).
2126 	 */
2127 	if ((pid = fork()) == -1) {
2128 		restore_error_fd
2129 		fprintf(stderr,"second fork: %s\r\n",Tcl_ErrnoMsg(errno));
2130 		exit(-1);
2131 	}
2132 
2133 	if (pid) {
2134  		/* Intermediate process. */
2135 		int status;
2136 		int timeout;
2137 		char *t;
2138 
2139 		/* How long should we wait? */
2140 		timeout = exp_pty_timeout;
2141 
2142 		/* Let the spawned process run to completion. */
2143  		while (wait(&status) < 0 && errno == EINTR)
2144 			/* empty body */;
2145 
2146 		/* Wait for the pty to clear. */
2147 		sleep(timeout);
2148 
2149 		/* Duplicate the spawned process's status. */
2150 		if (WIFSIGNALED(status))
2151 			kill(getpid(), WTERMSIG(status));
2152 
2153 		/* The kill may not have worked, but this will. */
2154  		exit(WEXITSTATUS(status));
2155 	}
2156 #endif /* _CRAY2 */
2157 #endif /* CRAY */
2158 
2159 	if (exp_console) {
2160 #ifdef SRIOCSREDIR
2161 		int fd;
2162 
2163 		if ((fd = open("/dev/console", O_RDONLY)) == -1) {
2164 			restore_error_fd
2165 			fprintf(stderr, "spawn %s: cannot open console, check permissions of /dev/console\n",argv[0]);
2166 			exit(-1);
2167 		}
2168 		if (ioctl(fd, SRIOCSREDIR, 0) == -1) {
2169 			restore_error_fd
2170 			fprintf(stderr, "spawn %s: cannot redirect console, check permissions of /dev/console\n",argv[0]);
2171 		}
2172 		close(fd);
2173 #endif
2174 
2175 #ifdef TIOCCONS
2176 		int on = 1;
2177 		if (ioctl(0,TIOCCONS,(char *)&on) == -1) {
2178 			restore_error_fd
2179 			fprintf(stderr, "spawn %s: cannot open console, check permissions of /dev/console\n",argv[0]);
2180 			exit(-1);
2181 		}
2182 #endif /* TIOCCONS */
2183 	}
2184 
2185 	/* tell parent that we are done setting up pty */
2186 	/* The actual char sent back is irrelevant. */
2187 
2188 	/* exp_debuglog("child: telling parent that pty is initialized\r\n");*/
2189 	cc = write(sync_fds[1]," ",1);
2190 	if (cc == -1) {
2191 		restore_error_fd
2192 		fprintf(stderr,"child: sync byte write: %s\r\n",Tcl_ErrnoMsg(errno));
2193 		exit(-1);
2194 	}
2195 	close(sync_fds[1]);
2196 
2197 	/* wait for master to let us go on */
2198 	cc = read(sync2_fds[0],&sync_byte,1);
2199 	if (cc == -1) {
2200 		restore_error_fd
2201 		exp_errorlog("child: sync byte read: %s\r\n",Tcl_ErrnoMsg(errno));
2202 		exit(-1);
2203 	}
2204 	close(sync2_fds[0]);
2205 
2206 	/* exp_debuglog("child: now unsynchronized from parent\r\n"); */
2207 
2208 	/* (possibly multiple) masters are closed automatically due to */
2209 	/* earlier fcntl(,,CLOSE_ON_EXEC); */
2210 
2211 	/* just in case, allow user to explicitly close other files */
2212 	if (exp_close_in_child) (*exp_close_in_child)();
2213 
2214 	/* allow user to do anything else to child */
2215 	if (exp_child_exec_prelude) (*exp_child_exec_prelude)();
2216 
2217         (void) execvp(file,argv);
2218 
2219 	/* Unfortunately, by now we've closed fd's to stderr, logfile
2220 	 * and debugfile.  The only reasonable thing to do is to send
2221 	 * *back the error as part of the program output.  This will
2222 	 * be *picked up in an expect or interact command.
2223 	 */
2224 
2225 	write(status_pipe[1], &errno, sizeof errno);
2226 	exit(-1);
2227 	/*NOTREACHED*/
2228 }
2229 
2230 /* returns fd of master side of pty */
2231 /*VARARGS*/
2232 int
TCL_VARARGS_DEF(char *,arg1)2233 exp_spawnl TCL_VARARGS_DEF(char *,arg1)
2234 /*exp_spawnl(va_alist)*/
2235 /*va_dcl*/
2236 {
2237 	va_list args; /* problematic line here */
2238 	int i;
2239 	char *arg, **argv;
2240 
2241 	arg = TCL_VARARGS_START(char *,arg1,args);
2242 	/*va_start(args);*/
2243 	for (i=1;;i++) {
2244 		arg = va_arg(args,char *);
2245 		if (!arg) break;
2246 	}
2247 	va_end(args);
2248 	if (i == 0) sysreturn(EINVAL);
2249 	if (!(argv = (char **)malloc((i+1)*sizeof(char *)))) sysreturn(ENOMEM);
2250 	argv[0] = TCL_VARARGS_START(char *,arg1,args);
2251 	/*va_start(args);*/
2252 	for (i=1;;i++) {
2253 		argv[i] = va_arg(args,char *);
2254 		if (!argv[i]) break;
2255 	}
2256 	i = exp_spawnv(argv[0],argv+1);
2257 	free((char *)argv);
2258 	return(i);
2259 }
2260 
2261 /* allow user-provided fd to be passed to expect funcs */
2262 int
exp_spawnfd(fd)2263 exp_spawnfd(fd)
2264 int fd;
2265 {
2266 	if (!fd_new(fd)) {
2267 		errno = ENOMEM;
2268 		return -1;
2269 	}
2270 	return fd;
2271 }
2272 
2273 /* remove nulls from s.  Initially, the number of chars in s is c, */
2274 /* not strlen(s).  This count does not include the trailing null. */
2275 /* returns number of nulls removed. */
2276 static int
rm_nulls(s,c)2277 rm_nulls(s,c)
2278 char *s;
2279 int c;
2280 {
2281 	char *s2 = s;	/* points to place in original string to put */
2282 			/* next non-null character */
2283 	int count = 0;
2284 	int i;
2285 
2286 	for (i=0;i<c;i++,s++) {
2287 		if (0 == *s) {
2288 			count++;
2289 			continue;
2290 		}
2291 		if (count) *s2 = *s;
2292 		s2++;
2293 	}
2294 	return(count);
2295 }
2296 
2297 static int i_read_errno;/* place to save errno, if i_read() == -1, so it
2298 			   doesn't get overwritten before we get to read it */
2299 
2300 /*ARGSUSED*/
2301 static void
sigalarm_handler(n)2302 sigalarm_handler(n)
2303 int n;			/* signal number, unused by us */
2304 {
2305 #ifdef REARM_SIG
2306 	signal(SIGALRM,sigalarm_handler);
2307 #endif
2308 
2309 #ifdef HAVE_SIGLONGJMP
2310 	siglongjmp(exp_readenv,1);
2311 #else
2312 	longjmp(exp_readenv,1);
2313 #endif /* HAVE_SIGLONGJMP */
2314 }
2315 
2316 /* interruptable read */
2317 static int
i_read(fd,fp,buffer,length,timeout)2318 i_read(fd,fp,buffer,length,timeout)
2319 int fd;
2320 FILE *fp;
2321 char *buffer;
2322 int length;
2323 int timeout;
2324 {
2325 	int cc = -2;
2326 
2327 	/* since setjmp insists on returning 1 upon longjmp(,0), */
2328 	/* longjmp(,2 (EXP_RESTART)) instead. */
2329 
2330 	/* no need to set alarm if -1 (infinite) or 0 (poll with */
2331 	/* guaranteed data) */
2332 
2333 	if (timeout > 0) alarm(timeout);
2334 
2335 	/* restart read if setjmp returns 0 (first time) or 2 (EXP_RESTART). */
2336 	/* abort if setjmp returns 1 (EXP_ABORT). */
2337 #ifdef HAVE_SIGLONGJMP
2338         if (EXP_ABORT != sigsetjmp(exp_readenv,1)) {
2339 #else
2340 	if (EXP_ABORT != setjmp(exp_readenv)) {
2341 #endif /* HAVE_SIGLONGJMP */
2342 		exp_reading = TRUE;
2343 		if (fd == -1) {
2344 			int c;
2345 			c = getc(fp);
2346 			if (c == EOF) {
2347 /*fprintf(stderr,"<<EOF>>",c);fflush(stderr);*/
2348 				if (feof(fp)) cc = 0;
2349 				else cc = -1;
2350 			} else {
2351 /*fprintf(stderr,"<<%c>>",c);fflush(stderr);*/
2352 				buffer[0] = c;
2353 				cc = 1;
2354 			}
2355 		} else {
2356 #ifndef HAVE_PTYTRAP
2357 			cc = read(fd,buffer,length);
2358 #else
2359 #  include <sys/ptyio.h>
2360 
2361 			fd_set rdrs;
2362 			fd_set excep;
2363 
2364 		restart:
2365 			FD_ZERO(&rdrs);
2366 			FD_ZERO(&excep);
2367 			FD_SET(fd,&rdrs);
2368 			FD_SET(fd,&excep);
2369 			if (-1 == (cc = select(fd+1,
2370 					 (SELECT_MASK_TYPE *)&rdrs,
2371 					 (SELECT_MASK_TYPE *)0,
2372 					 (SELECT_MASK_TYPE *)&excep,
2373 					 (struct timeval *)0))) {
2374 				/* window refreshes trigger EINTR, ignore */
2375 				if (errno == EINTR) goto restart;
2376 			}
2377 			if (FD_ISSET(fd,&rdrs)) {
2378 				cc = read(fd,buffer,length);
2379 			} else if (FD_ISSET(fd,&excep)) {
2380 				struct request_info ioctl_info;
2381 				ioctl(fd,TIOCREQCHECK,&ioctl_info);
2382 				if (ioctl_info.request == TIOCCLOSE) {
2383 					cc = 0; /* indicate eof */
2384 				} else {
2385 					ioctl(fd, TIOCREQSET, &ioctl_info);
2386 					/* presumably, we trapped an open here */
2387 					goto restart;
2388 				}
2389 			}
2390 #endif /* HAVE_PTYTRAP */
2391 		}
2392 #if 0
2393 		/* can't get fread to return early! */
2394 		else {
2395 			if (!(cc = fread(buffer,1,length,fp))) {
2396 				if (ferror(fp)) cc = -1;
2397 			}
2398 		}
2399 #endif
2400 		i_read_errno = errno;	/* errno can be overwritten by the */
2401 					/* time we return */
2402 	}
2403 	exp_reading = FALSE;
2404 
2405 	if (timeout > 0) alarm(0);
2406 	return(cc);
2407 }
2408 
2409 /* I tried really hard to make the following two functions share the code */
2410 /* that makes the ecase array, but I kept running into a brick wall when */
2411 /* passing var args into the funcs and then again into a make_cases func */
2412 /* I would very much appreciate it if someone showed me how to do it right */
2413 
2414 /* takes triplets of args, with a final "exp_last" arg */
2415 /* triplets are type, pattern, and then int to return */
2416 /* returns negative value if error (or EOF/timeout) occurs */
2417 /* some negative values can also have an associated errno */
2418 
2419 /* the key internal variables that this function depends on are:
2420 	exp_buffer
2421 	exp_buffer_end
2422 	exp_match_end
2423 */
2424 static int
expectv(fd,fp,ecases)2425 expectv(fd,fp,ecases)
2426 int fd;
2427 FILE *fp;
2428 struct exp_case *ecases;
2429 {
2430 	int cc = 0;		/* number of chars returned in a single read */
2431 	int buf_length;		/* numbers of chars in exp_buffer */
2432 	int old_length;		/* old buf_length */
2433 	int first_time = TRUE;	/* force old buffer to be tested before */
2434 				/* additional reads */
2435 	int polled = 0;		/* true if poll has caused read() to occur */
2436 
2437 	struct exp_case *ec;	/* points to current ecase */
2438 
2439 	time_t current_time;	/* current time (when we last looked)*/
2440 	time_t end_time;	/* future time at which to give up */
2441 	int remtime;		/* remaining time in timeout */
2442 
2443 	struct f *f;
2444 	int return_val;
2445 	int sys_error = 0;
2446 #define return_normally(x)	{return_val = x; goto cleanup;}
2447 #define return_errno(x)	{sys_error = x; goto cleanup;}
2448 
2449 	f = fdfp2f(fd,fp);
2450 	if (!f) return_errno(ENOMEM);
2451 
2452 	exp_buffer = f->buffer;
2453 	exp_buffer_end = f->buffer_end;
2454 	exp_match_end = f->match_end;
2455 
2456 	buf_length = exp_buffer_end - exp_match_end;
2457 	if (buf_length) {
2458 		/*
2459 		 * take end of previous match to end of buffer
2460 		 * and copy to beginning of buffer
2461 		 */
2462 		memmove(exp_buffer,exp_match_end,buf_length);
2463 	}
2464 	exp_buffer_end = exp_buffer + buf_length;
2465 	*exp_buffer_end = '\0';
2466 
2467 	if (!ecases) return_errno(EINVAL);
2468 
2469 	/* compile if necessary */
2470 	for (ec=ecases;ec->type != exp_end;ec++) {
2471 		if ((ec->type == exp_regexp) && !ec->re) {
2472 			TclRegError((char *)0);
2473 			if (!(ec->re = TclRegComp(ec->pattern))) {
2474 				fprintf(stderr,"regular expression %s is bad: %s",ec->pattern,TclGetRegError());
2475 				return_errno(EINVAL);
2476 			  }
2477 		  }
2478 	}
2479 
2480 	/* get the latest buffer size.  Double the user input for two */
2481 	/* reasons.  1) Need twice the space in case the match */
2482 	/* straddles two bufferfuls, 2) easier to hack the division by */
2483 	/* two when shifting the buffers later on */
2484 
2485 	bufsiz = 2*exp_match_max;
2486 	if (f->msize != bufsiz) {
2487 		/* if truncated, forget about some data */
2488 		if (buf_length > bufsiz) {
2489 			/* copy end of buffer down */
2490 
2491 			/* copy one less than what buffer can hold to avoid */
2492 			/* triggering buffer-full handling code below */
2493 			/* which will immediately dump the first half */
2494 			/* of the buffer */
2495 			memmove(exp_buffer,exp_buffer+(buf_length - bufsiz)+1,
2496 				bufsiz-1);
2497 			buf_length = bufsiz-1;
2498 		}
2499 		exp_buffer = realloc(exp_buffer,bufsiz+1);
2500 		if (!exp_buffer) return_errno(ENOMEM);
2501 		exp_buffer[buf_length] = '\0';
2502 		exp_buffer_end = exp_buffer + buf_length;
2503 		f->msize = bufsiz;
2504 	}
2505 
2506 	/* some systems (i.e., Solaris) require fp be flushed when switching */
2507 	/* directions - do this again afterwards */
2508 	if (fd == -1) fflush(fp);
2509 
2510 	if (exp_timeout != -1) signal(SIGALRM,sigalarm_handler);
2511 
2512 	/* remtime and current_time updated at bottom of loop */
2513 	remtime = exp_timeout;
2514 
2515 	time(&current_time);
2516 	end_time = current_time + remtime;
2517 
2518 	for (;;) {
2519 		/* when buffer fills, copy second half over first and */
2520 		/* continue, so we can do matches over multiple buffers */
2521 		if (buf_length == bufsiz) {
2522 			int first_half, second_half;
2523 
2524 			if (exp_full_buffer) {
2525 				exp_debuglog("expect: full buffer\r\n");
2526 				exp_match = exp_buffer;
2527 				exp_match_end = exp_buffer + buf_length;
2528 				exp_buffer_end = exp_match_end;
2529 				return_normally(EXP_FULLBUFFER);
2530 			}
2531 			first_half = bufsiz/2;
2532 			second_half = bufsiz - first_half;
2533 
2534 			memcpy(exp_buffer,exp_buffer+first_half,second_half);
2535 			buf_length = second_half;
2536 			exp_buffer_end = exp_buffer + second_half;
2537 		}
2538 
2539 		/*
2540 		 * always check first if pattern is already in buffer
2541 		 */
2542 		if (first_time) {
2543 			first_time = FALSE;
2544 			goto after_read;
2545 		}
2546 
2547 		/*
2548 		 * check for timeout
2549  		 * we should timeout if either
2550  		 *   1) exp_timeout > remtime <= 0 (normal)
2551  		 *   2) exp_timeout == 0 and we have polled at least once
2552 		 *
2553 		 */
2554 		if (((exp_timeout > remtime) && (remtime <= 0)) ||
2555  		    ((exp_timeout == 0) && polled)) {
2556 			exp_debuglog("expect: timeout\r\n");
2557 			exp_match_end = exp_buffer;
2558 			return_normally(EXP_TIMEOUT);
2559 		}
2560 
2561  		/* remember that we have actually checked at least once */
2562  		polled = 1;
2563 
2564 		cc = i_read(fd,fp,
2565 				exp_buffer_end,
2566 				bufsiz - buf_length,
2567 				remtime);
2568 
2569 		if (cc == 0) {
2570 			exp_debuglog("expect: eof\r\n");
2571 			return_normally(EXP_EOF);	/* normal EOF */
2572 		} else if (cc == -1) {			/* abnormal EOF */
2573 			/* ptys produce EIO upon EOF - sigh */
2574 			if (i_read_errno == EIO) {
2575 				/* convert to EOF indication */
2576 				exp_debuglog("expect: eof\r\n");
2577 				return_normally(EXP_EOF);
2578 			}
2579 			exp_debuglog("expect: error (errno = %d)\r\n",i_read_errno);
2580 			return_errno(i_read_errno);
2581 		} else if (cc == -2) {
2582 			exp_debuglog("expect: timeout\r\n");
2583 			exp_match_end = exp_buffer;
2584 			return_normally(EXP_TIMEOUT);
2585 		}
2586 
2587 		old_length = buf_length;
2588 		buf_length += cc;
2589 		exp_buffer_end += buf_length;
2590 
2591 		if (exp_logfile_all || (exp_loguser && exp_logfile)) {
2592 			fwrite(exp_buffer + old_length,1,cc,exp_logfile);
2593 		}
2594 		if (exp_loguser) fwrite(exp_buffer + old_length,1,cc,stdout);
2595 		if (exp_debugfile) fwrite(exp_buffer + old_length,1,cc,exp_debugfile);
2596 
2597 		/* if we wrote to any logs, flush them */
2598 		if (exp_debugfile) fflush(exp_debugfile);
2599 		if (exp_loguser) {
2600 			fflush(stdout);
2601 			if (exp_logfile) fflush(exp_logfile);
2602 		}
2603 
2604 		/* remove nulls from input, so we can use C-style strings */
2605 		/* doing it here lets them be sent to the screen, just */
2606 		/*  in case they are involved in formatting operations */
2607 		if (exp_remove_nulls) {
2608 			buf_length -= rm_nulls(exp_buffer + old_length, cc);
2609 		}
2610 		/* cc should be decremented as well, but since it will not */
2611 		/* be used before being set again, there is no need */
2612 		exp_buffer_end = exp_buffer + buf_length;
2613 		*exp_buffer_end = '\0';
2614                 exp_match_end = exp_buffer;
2615 
2616 	after_read:
2617 		exp_debuglog("expect: does {%s} match ",exp_printify(exp_buffer));
2618 		/* pattern supplied */
2619 		for (ec=ecases;ec->type != exp_end;ec++) {
2620 			int matched = -1;
2621 
2622 			exp_debuglog("{%s}? ",exp_printify(ec->pattern));
2623 			if (ec->type == exp_glob) {
2624 				int offset;
2625 				matched = Exp_StringMatch(exp_buffer,ec->pattern,&offset);
2626 				if (matched >= 0) {
2627 					exp_match = exp_buffer + offset;
2628 					exp_match_end = exp_match + matched;
2629 				}
2630 			} else if (ec->type == exp_exact) {
2631 				char *p = strstr(exp_buffer,ec->pattern);
2632 				if (p) {
2633 					matched = 1;
2634 					exp_match = p;
2635 					exp_match_end = p + strlen(ec->pattern);
2636 				}
2637 			} else if (ec->type == exp_null) {
2638 				char *p;
2639 
2640 				for (p=exp_buffer;p<exp_buffer_end;p++) {
2641 					if (*p == 0) {
2642 						matched = 1;
2643 						exp_match = p;
2644 						exp_match_end = p+1;
2645 					}
2646 				}
2647 			} else {
2648 				TclRegError((char *)0);
2649 				if (TclRegExec(ec->re,exp_buffer,exp_buffer)) {
2650 					matched = 1;
2651 					exp_match = ec->re->startp[0];
2652 					exp_match_end = ec->re->endp[0];
2653 				} else if (TclGetRegError()) {
2654 			    		fprintf(stderr,"r.e. match (pattern %s) failed: %s",ec->pattern,TclGetRegError());
2655 				}
2656 			}
2657 
2658 			if (matched != -1) {
2659 				exp_debuglog("yes\nexp_buffer is {%s}\n",
2660 						exp_printify(exp_buffer));
2661 				return_normally(ec->value);
2662 			} else exp_debuglog("no\n");
2663 		}
2664 
2665 		/*
2666 		 * Update current time and remaining time.
2667 		 * Don't bother if we are waiting forever or polling.
2668 		 */
2669 		if (exp_timeout > 0) {
2670 			time(&current_time);
2671 			remtime = end_time - current_time;
2672 		}
2673 	}
2674  cleanup:
2675 	f->buffer     = exp_buffer;
2676 	f->buffer_end = exp_buffer_end;
2677 	f->match_end  = exp_match_end;
2678 
2679 	/* some systems (i.e., Solaris) require fp be flushed when switching */
2680 	/* directions - do this before as well */
2681 	if (fd == -1) fflush(fp);
2682 
2683 	if (sys_error) {
2684 		errno = sys_error;
2685 		return -1;
2686 	}
2687 	return return_val;
2688 }
2689 
2690 int
exp_fexpectv(fp,ecases)2691 exp_fexpectv(fp,ecases)
2692 FILE *fp;
2693 struct exp_case *ecases;
2694 {
2695 	return(expectv(-1,fp,ecases));
2696 }
2697 
2698 int
exp_expectv(fd,ecases)2699 exp_expectv(fd,ecases)
2700 int fd;
2701 struct exp_case *ecases;
2702 {
2703 	return(expectv(fd,(FILE *)0,ecases));
2704 }
2705 
2706 /*VARARGS*/
2707 int
TCL_VARARGS_DEF(int,arg1)2708 exp_expectl TCL_VARARGS_DEF(int,arg1)
2709 /*exp_expectl(va_alist)*/
2710 /*va_dcl*/
2711 {
2712 	va_list args;
2713 	int fd;
2714 	struct exp_case *ec, *ecases;
2715 	int i;
2716 	enum exp_type type;
2717 
2718 	fd = TCL_VARARGS_START(int,arg1,args);
2719 	/* va_start(args);*/
2720 	/* fd = va_arg(args,int);*/
2721 	/* first just count the arg sets */
2722 	for (i=0;;i++) {
2723 		type = va_arg(args,enum exp_type);
2724 		if (type == exp_end) break;
2725 
2726 		/* Ultrix 4.2 compiler refuses enumerations comparison!? */
2727 		if ((int)type < 0 || (int)type >= (int)exp_bogus) {
2728 			fprintf(stderr,"bad type (set %d) in exp_expectl\n",i);
2729 			sysreturn(EINVAL);
2730 		}
2731 
2732 		va_arg(args,char *);		/* COMPUTED BUT NOT USED */
2733 		if (type == exp_compiled) {
2734 			va_arg(args,regexp *);	/* COMPUTED BUT NOT USED */
2735 		}
2736 		va_arg(args,int);		/* COMPUTED BUT NOT USED*/
2737 	}
2738 	va_end(args);
2739 
2740 	if (!(ecases = (struct exp_case *)
2741 				malloc((1+i)*sizeof(struct exp_case))))
2742 		sysreturn(ENOMEM);
2743 
2744 	/* now set up the actual cases */
2745 	fd = TCL_VARARGS_START(int,arg1,args);
2746 	/*va_start(args);*/
2747 	/*va_arg(args,int);*/		/*COMPUTED BUT NOT USED*/
2748 	for (ec=ecases;;ec++) {
2749 		ec->type = va_arg(args,enum exp_type);
2750 		if (ec->type == exp_end) break;
2751 		ec->pattern = va_arg(args,char *);
2752 		if (ec->type == exp_compiled) {
2753 			ec->re = va_arg(args,regexp *);
2754 		} else {
2755 			ec->re = 0;
2756 		}
2757 		ec->value = va_arg(args,int);
2758 	}
2759 	va_end(args);
2760 	i = expectv(fd,(FILE *)0,ecases);
2761 
2762 	for (ec=ecases;ec->type != exp_end;ec++) {
2763 		/* free only if regexp and we compiled it for user */
2764 		if (ec->type == exp_regexp) {
2765 			free((char *)ec->re);
2766 		}
2767 	}
2768 	free((char *)ecases);
2769 	return(i);
2770 }
2771 
2772 int
TCL_VARARGS_DEF(FILE *,arg1)2773 exp_fexpectl TCL_VARARGS_DEF(FILE *,arg1)
2774 /*exp_fexpectl(va_alist)*/
2775 /*va_dcl*/
2776 {
2777 	va_list args;
2778 	FILE *fp;
2779 	struct exp_case *ec, *ecases;
2780 	int i;
2781 	enum exp_type type;
2782 
2783 	fp = TCL_VARARGS_START(FILE *,arg1,args);
2784 	/*va_start(args);*/
2785 	/*fp = va_arg(args,FILE *);*/
2786 	/* first just count the arg-pairs */
2787 	for (i=0;;i++) {
2788 		type = va_arg(args,enum exp_type);
2789 		if (type == exp_end) break;
2790 
2791 		/* Ultrix 4.2 compiler refuses enumerations comparison!? */
2792 		if ((int)type < 0 || (int)type >= (int)exp_bogus) {
2793 			fprintf(stderr,"bad type (set %d) in exp_expectl\n",i);
2794 			sysreturn(EINVAL);
2795 		}
2796 
2797 		va_arg(args,char *);		/* COMPUTED BUT NOT USED */
2798 		if (type == exp_compiled) {
2799 			va_arg(args,regexp *);	/* COMPUTED BUT NOT USED */
2800 		}
2801 		va_arg(args,int);		/* COMPUTED BUT NOT USED*/
2802 	}
2803 	va_end(args);
2804 
2805 	if (!(ecases = (struct exp_case *)
2806 					malloc((1+i)*sizeof(struct exp_case))))
2807 		sysreturn(ENOMEM);
2808 
2809 #if 0
2810 	va_start(args);
2811 	va_arg(args,FILE *);		/*COMPUTED, BUT NOT USED*/
2812 #endif
2813 	(void) TCL_VARARGS_START(FILE *,arg1,args);
2814 
2815 	for (ec=ecases;;ec++) {
2816 		ec->type = va_arg(args,enum exp_type);
2817 		if (ec->type == exp_end) break;
2818 		ec->pattern = va_arg(args,char *);
2819 		if (ec->type == exp_compiled) {
2820 			ec->re = va_arg(args,regexp *);
2821 		} else {
2822 			ec->re = 0;
2823 		}
2824 		ec->value = va_arg(args,int);
2825 	}
2826 	va_end(args);
2827 	i = expectv(-1,fp,ecases);
2828 
2829 	for (ec=ecases;ec->type != exp_end;ec++) {
2830 		/* free only if regexp and we compiled it for user */
2831 		if (ec->type == exp_regexp) {
2832 			free((char *)ec->re);
2833 		}
2834 	}
2835 	free((char *)ecases);
2836 	return(i);
2837 }
2838 
2839 /* like popen(3) but works in both directions */
2840 FILE *
exp_popen(program)2841 exp_popen(program)
2842 char *program;
2843 {
2844 	FILE *fp;
2845 	int ec;
2846 
2847 	if (0 > (ec = exp_spawnl("sh","sh","-c",program,(char *)0))) return(0);
2848 	if (!(fp = fdopen(ec,"r+"))) return(0);
2849 	setbuf(fp,(char *)0);
2850 	return(fp);
2851 }
2852 
2853 int
exp_disconnect()2854 exp_disconnect()
2855 {
2856 	int ttyfd;
2857 
2858 #ifndef EALREADY
2859 #define EALREADY 37
2860 #endif
2861 
2862 	/* presumably, no stderr, so don't bother with error message */
2863 	if (exp_disconnected) sysreturn(EALREADY);
2864 	exp_disconnected = TRUE;
2865 
2866 	freopen("/dev/null","r",stdin);
2867 	freopen("/dev/null","w",stdout);
2868 	freopen("/dev/null","w",stderr);
2869 
2870 #ifdef POSIX
2871 	setsid();
2872 #else
2873 #ifdef SYSV3
2874 	/* put process in our own pgrp, and lose controlling terminal */
2875 	exp_setpgrp();
2876 	signal(SIGHUP,SIG_IGN);
2877 	if (fork()) exit(0);	/* first child exits (as per Stevens, */
2878 	/* UNIX Network Programming, p. 79-80) */
2879 	/* second child process continues as daemon */
2880 #else /* !SYSV3 */
2881 	exp_setpgrp();
2882 /* Pyramid lacks this defn */
2883 #ifdef TIOCNOTTY
2884 	ttyfd = open("/dev/tty", O_RDWR);
2885 	if (ttyfd >= 0) {
2886 		/* zap controlling terminal if we had one */
2887 		(void) ioctl(ttyfd, TIOCNOTTY, (char *)0);
2888 		(void) close(ttyfd);
2889 	}
2890 #endif /* TIOCNOTTY */
2891 #endif /* SYSV3 */
2892 #endif /* POSIX */
2893 	return(0);
2894 }
2895 
2896 /* send to log if open and debugging enabled */
2897 /* send to stderr if debugging enabled */
2898 /* use this function for recording unusual things in the log */
2899 /*VARARGS*/
2900 void
TCL_VARARGS_DEF(char *,arg1)2901 exp_debuglog TCL_VARARGS_DEF(char *,arg1)
2902 {
2903     char *fmt;
2904     va_list args;
2905 
2906     fmt = TCL_VARARGS_START(char *,arg1,args);
2907     if (exp_debugfile) vfprintf(exp_debugfile,fmt,args);
2908     if (exp_is_debugging) {
2909 	vfprintf(stderr,fmt,args);
2910 	if (exp_logfile) vfprintf(exp_logfile,fmt,args);
2911     }
2912 
2913     va_end(args);
2914 }
2915 
2916 
2917 /* send to log if open */
2918 /* send to stderr */
2919 /* use this function for error conditions */
2920 /*VARARGS*/
2921 void
TCL_VARARGS_DEF(char *,arg1)2922 exp_errorlog TCL_VARARGS_DEF(char *,arg1)
2923 {
2924     char *fmt;
2925     va_list args;
2926 
2927     fmt = TCL_VARARGS_START(char *,arg1,args);
2928     vfprintf(stderr,fmt,args);
2929     if (exp_debugfile) vfprintf(exp_debugfile,fmt,args);
2930     if (exp_logfile) vfprintf(exp_logfile,fmt,args);
2931     va_end(args);
2932 }
2933 
2934 #include <ctype.h>
2935 
2936 char *
exp_printify(s)2937 exp_printify(s)
2938 char *s;
2939 {
2940 	static int destlen = 0;
2941 	static char *dest = 0;
2942 	char *d;		/* ptr into dest */
2943 	unsigned int need;
2944 
2945 	if (s == 0) return("<null>");
2946 
2947 	/* worst case is every character takes 4 to printify */
2948 	need = strlen(s)*4 + 1;
2949 	if (need > destlen) {
2950 		if (dest) ckfree(dest);
2951 		dest = ckalloc(need);
2952 		destlen = need;
2953 	}
2954 
2955 	for (d = dest;*s;s++) {
2956 		if (*s == '\r') {
2957 			strcpy(d,"\\r");		d += 2;
2958 		} else if (*s == '\n') {
2959 			strcpy(d,"\\n");		d += 2;
2960 		} else if (*s == '\t') {
2961 			strcpy(d,"\\t");		d += 2;
2962 		} else if (isascii(*s) && isprint(*s)) {
2963 			*d = *s;			d += 1;
2964 		} else {
2965 			sprintf(d,"\\x%02x",*s & 0xff);	d += 4;
2966 		}
2967 	}
2968 	*d = '\0';
2969 	return(dest);
2970 }
2971