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; ®dummy = 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 = ®dummy;
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 == ®dummy) {
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 != ®dummy)
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 == ®dummy) {
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 == ®dummy)
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 == ®dummy || 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 == ®dummy)
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(¤t_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(¤t_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