1 /*
2  * CDDL HEADER START
3  *
4  * This file and its contents are supplied under the terms of the
5  * Common Development and Distribution License ("CDDL"), version 1.0.
6  * You may use this file only in accordance with the terms of version
7  * 1.0 of the CDDL.
8  *
9  * A full copy of the text of the CDDL should have accompanied this
10  * source.  A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 /*
24  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * @(#)misc.cc 1.31 06/12/12
29  */
30 
31 #pragma	ident	"@(#)misc.cc	1.31	06/12/12"
32 
33 /*
34  * Copyright 2017-2021 J. Schilling
35  *
36  * @(#)misc.cc	1.16 21/08/15 2017-2021 J. Schilling
37  */
38 #include <schily/mconfig.h>
39 #ifndef lint
40 static	UConst char sccsid[] =
41 	"@(#)misc.cc	1.16 21/08/15 2017-2021 J. Schilling";
42 #endif
43 
44 /*
45  *	misc.cc
46  *
47  *	This file contains various unclassified routines. Some main groups:
48  *		getname
49  *		Memory allocation
50  *		String handling
51  *		Property handling
52  *		Error message handling
53  *		Make internal state dumping
54  *		main routine support
55  */
56 
57 /*
58  * Included files
59  */
60 #include <bsd/bsd.h>		/* bsd_signal() */
61 #include <mksh/i18n.h>		/* get_char_semantics_value() */
62 #include <mksh/misc.h>
63 #include <stdarg.h>		/* va_list, va_start(), va_end() */
64 #if defined(SCHILY_BUILD) || defined(SCHILY_INCLUDES)
65 #include <schily/wait.h>	/* wait() */
66 #else
67 #include <sys/wait.h>		/* wait() */
68 #define	WAIT_T	int
69 #endif
70 
71 /*
72  * Defined macros
73  */
74 
75 #ifndef	HAVE_VSNPRINTF
76 #ifdef	__hpux
77 extern "C" {
78 int	_vsnprintf(char*, int, const char*, va_list);
79 }
80 #define	vsnprintf	_vsnprintf
81 #endif
82 #endif
83 
84 
85 /*
86  * typedefs & structs
87  */
88 
89 /*
90  * Static variables
91  */
92 #ifdef	ultrix		/* No prototypes in SIG_DFL macro */
93 #undef	SUN5_0
94 #endif
95 
96 #ifdef SUN5_0
97 extern "C" {
98 	void		(*sigivalue)(int) = SIG_DFL;
99 	void		(*sigqvalue)(int) = SIG_DFL;
100 	void		(*sigtvalue)(int) = SIG_DFL;
101 	void		(*sighvalue)(int) = SIG_DFL;
102 }
103 #else
104 static	void		(*sigivalue)(int) = (void (*) (int)) SIG_DFL;
105 static	void		(*sigqvalue)(int) = (void (*) (int)) SIG_DFL;
106 static	void		(*sigtvalue)(int) = (void (*) (int)) SIG_DFL;
107 static	void		(*sighvalue)(int) = (void (*) (int)) SIG_DFL;
108 #endif
109 
110 long	getname_bytes_count = 0;
111 long	getname_names_count = 0;
112 long	getname_struct_count = 0;
113 
114 long	freename_bytes_count = 0;
115 long	freename_names_count = 0;
116 long	freename_struct_count = 0;
117 
118 long	expandstring_count = 0;
119 long	getwstring_count = 0;
120 
121 /*
122  * File table of contents
123  */
124 static void	expand_string(register String string, register int length);
125 
126 #define	FATAL_ERROR_MSG_SIZE 200
127 
128 /*
129  *	getmem(size)
130  *
131  *	malloc() version that checks the returned value.
132  *
133  *	Return value:
134  *				The memory chunk we allocated
135  *
136  *	Parameters:
137  *		size		The size of the chunk we need
138  *
139  *	Global variables used:
140  */
141 char *
getmem(register int size)142 getmem(register int size)
143 {
144 	register char          *result = (char *) malloc((unsigned) size);
145 	if (result == NULL) {
146 		char buf[FATAL_ERROR_MSG_SIZE];
147 		sprintf(buf, NOCATGETS("*** Error: malloc(%d) failed: %s\n"), size, strerror(errno));
148 		strcat(buf, gettext("mksh: Fatal error: Out of memory\n"));
149 		fputs(buf, stderr);
150 		exit_status = 1;
151 		exit(1);
152 	}
153 	return result;
154 }
155 
156 /*
157  *	retmem(p)
158  *
159  *	Cover funtion for free() to make it possible to insert advises.
160  *
161  *	Parameters:
162  *		p		The memory block to free
163  *
164  *	Global variables used:
165  */
166 void
retmem(wchar_t * p)167 retmem(wchar_t *p)
168 {
169 	(void) free((char *) p);
170 }
171 
172 void
retmem_mb(caddr_t p)173 retmem_mb(caddr_t p)
174 {
175 	(void) free(p);
176 }
177 
178 /*
179  *	getname_fn(name, len, dont_enter)
180  *
181  *	Hash a name string to the corresponding nameblock.
182  *
183  *	Return value:
184  *				The Name block for the string
185  *
186  *	Parameters:
187  *		name		The string we want to internalize
188  *		len		The length of that string
189  *		dont_enter	Don't enter the name if it does not exist
190  *
191  *	Global variables used:
192  *		funny		The vector of semantic tags for characters
193  *		hashtab		The hashtable used for the nametable
194  */
195 Name
getname_fn(wchar_t * name,register int len,register Boolean dont_enter,register Boolean * foundp)196 getname_fn(wchar_t *name, register int len, register Boolean dont_enter, register Boolean * foundp)
197 {
198 	register int		length;
199 	register wchar_t	*cap = name;
200 	register Name		np;
201 	static Name_rec		empty_Name;
202 	char			*tmp_mbs_buffer = NULL;
203 	char			*mbs_name = mbs_buffer;
204 
205 	/*
206 	 * First figure out how long the string is.
207 	 * If the len argument is -1 we count the chars here.
208 	 */
209 	if (len == FIND_LENGTH) {
210 		length = wcslen(name);
211 	} else {
212 		length = len;
213 	}
214 
215 	Wstring ws;
216 	ws.init(name, length);
217 	if (length >= MAXPATHLEN) {
218 		mbs_name = tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
219 	}
220 	(void) wcstombs(mbs_name, ws.get_string(), (length * MB_LEN_MAX) + 1);
221 
222 	/* Look for the string */
223 	if (dont_enter || (foundp != 0)) {
224 		np = hashtab.lookup(mbs_name);
225 		if (foundp != 0) {
226 			*foundp = (np != 0) ? true : false;
227 		}
228 		if ((np != 0) || dont_enter) {
229 			if(tmp_mbs_buffer != NULL) {
230 				retmem_mb(tmp_mbs_buffer);
231 			}
232 			return np;
233 		} else {
234 			np = ALLOC(Name);
235 		}
236 	} else {
237 		Boolean found;
238 		np = hashtab.insert(mbs_name, found);
239 		if (found) {
240 			if(tmp_mbs_buffer != NULL) {
241 				retmem_mb(tmp_mbs_buffer);
242 			}
243 			return np;
244 		}
245 	}
246 	getname_struct_count += sizeof(struct _Name);
247 	*np = empty_Name;
248 
249 	np->string_mb = strdup(mbs_name);
250 	if(tmp_mbs_buffer != NULL) {
251 		retmem_mb(tmp_mbs_buffer);
252 		mbs_name = tmp_mbs_buffer = NULL;
253 	}
254 	getname_bytes_count += strlen(np->string_mb) + 1;
255 	/* Fill in the new Name */
256 	np->stat.time = file_no_time;
257 	np->hash.length = length;
258 	/* Scan the namestring to classify it */
259 	for (cap = name, len = 0; --length >= 0;) {
260 		len |= get_char_semantics_value(*cap++);
261 	}
262 	np->dollar = BOOLEAN((len & (int) dollar_sem) != 0);
263 	np->meta = BOOLEAN((len & (int) meta_sem) != 0);
264 	np->percent = BOOLEAN((len & (int) percent_sem) != 0);
265 	np->wildcard = BOOLEAN((len & (int) wildcard_sem) != 0);
266 	np->colon = BOOLEAN((len & (int) colon_sem) != 0);
267 	np->parenleft = BOOLEAN((len & (int) parenleft_sem) != 0);
268 	getname_names_count++;
269 	return np;
270 }
271 
272 void
store_name(Name name)273 store_name(Name name)
274 {
275 	hashtab.insert(name);
276 }
277 
278 void
free_name(Name name)279 free_name(Name name)
280 {
281 	freename_names_count++;
282 	freename_struct_count += sizeof(struct _Name);
283 	freename_bytes_count += strlen(name->string_mb) + 1;
284 	retmem_mb(name->string_mb);
285 	for (Property next, p = name->prop; p != NULL; p = next) {
286 		next = p->next;
287 		free(p);
288 	}
289 	free(name);
290 }
291 
292 /*
293  *	enable_interrupt(handler)
294  *
295  *	This routine sets a new interrupt handler for the signals make
296  *	wants to deal with.
297  *
298  *	Parameters:
299  *		handler		The function installed as interrupt handler
300  *
301  *	Static variables used:
302  *		sigivalue	The original signal handler
303  *		sigqvalue	The original signal handler
304  *		sigtvalue	The original signal handler
305  *		sighvalue	The original signal handler
306  */
307 void
enable_interrupt(register void (* handler)(int))308 enable_interrupt(register void (*handler) (int))
309 {
310 #ifdef SUN5_0
311 	if (sigivalue != SIG_IGN) {
312 #else
313 	if (sigivalue != (void (*) (int)) SIG_IGN) {
314 #endif
315 		(void) bsd_signal(SIGINT, (SIG_PF) handler);
316 	}
317 #ifdef SUN5_0
318 	if (sigqvalue != SIG_IGN) {
319 #else
320 	if (sigqvalue != (void (*) (int)) SIG_IGN) {
321 #endif
322 		(void) bsd_signal(SIGQUIT, (SIG_PF) handler);
323 	}
324 #ifdef SUN5_0
325 	if (sigtvalue != SIG_IGN) {
326 #else
327 	if (sigtvalue != (void (*) (int)) SIG_IGN) {
328 #endif
329 		(void) bsd_signal(SIGTERM, (SIG_PF) handler);
330 	}
331 #ifdef SUN5_0
332 	if (sighvalue != SIG_IGN) {
333 #else
334 	if (sighvalue != (void (*) (int)) SIG_IGN) {
335 #endif
336 		(void) bsd_signal(SIGHUP, (SIG_PF) handler);
337 	}
338 }
339 
340 /*
341  *	setup_char_semantics()
342  *
343  *	Load the vector char_semantics[] with lexical markers
344  *
345  *	Parameters:
346  *
347  *	Global variables used:
348  *		char_semantics	The vector of character semantics that we set
349  */
350 void
351 setup_char_semantics(void)
352 {
353 	const char	*s;
354 	wchar_t		wc_buffer[1];
355 	int		entry;
356 
357 	if (svr4) {
358 		s = "@-";
359 	} else {
360 		s = "=@-?!+";
361 	}
362 	for (; MBTOWC(wc_buffer, s); s++) {
363 		entry = get_char_semantics_entry(*wc_buffer);
364 		char_semantics[entry] |= (int) command_prefix_sem;
365 	}
366 	char_semantics[dollar_char_entry] |= (int) dollar_sem;
367 	for (s = "#|=^();&<>*?[]:$`'\"\\\n"; MBTOWC(wc_buffer, s); s++) {
368 		entry = get_char_semantics_entry(*wc_buffer);
369 		char_semantics[entry] |= (int) meta_sem;
370 	}
371 	char_semantics[percent_char_entry] |= (int) percent_sem;
372 	for (s = "@*<%?^"; MBTOWC(wc_buffer, s); s++) {
373 		entry = get_char_semantics_entry(*wc_buffer);
374 		char_semantics[entry] |= (int) special_macro_sem;
375 	}
376 	for (s = "?[*"; MBTOWC(wc_buffer, s); s++) {
377 		entry = get_char_semantics_entry(*wc_buffer);
378 		char_semantics[entry] |= (int) wildcard_sem;
379 	}
380 	char_semantics[colon_char_entry] |= (int) colon_sem;
381 	char_semantics[parenleft_char_entry] |= (int) parenleft_sem;
382 }
383 
384 /*
385  *	errmsg(errnum)
386  *
387  *	Return the error message for a system call error
388  *
389  *	Return value:
390  *				An error message string
391  *
392  *	Parameters:
393  *		errnum		The number of the error we want to describe
394  *
395  *	Global variables used:
396  *		sys_errlist	A vector of error messages
397  *		sys_nerr	The size of sys_errlist
398  */
399 char *
400 errmsg(int errnum)
401 {
402 #ifdef	HAVE_STRERROR
403 	char			*emsg;
404 #else
405 	extern int		sys_nerr;
406 	extern char		*sys_errlist[];
407 #endif
408 	char			*errbuf;
409 
410 #ifdef	HAVE_STRERROR
411 	emsg = strerror(errnum);
412 	if ((emsg) == NULL) {
413 		/*
414 		 * XXX use better length estimation
415 		 */
416 		errbuf = getmem(6+1+11+1);
417 		(void) sprintf(errbuf, gettext("Error %d"), errnum);
418 		return (errbuf);
419 	} else {
420 		return (emsg);
421 	}
422 #else
423 	if ((errnum < 0) || (errnum > sys_nerr)) {
424 		errbuf = getmem(6+1+11+1);
425 		(void) sprintf(errbuf, gettext("Error %d"), errnum);
426 		return errbuf;
427 	} else {
428 		return (sys_errlist[errnum]);
429 	}
430 #endif
431 }
432 
433 static char static_buf[MAXPATHLEN*3];
434 
435 /*
436  *	fatal_mksh(format, args...)
437  *
438  *	Print a message and die
439  *
440  *	Parameters:
441  *		format		printf type format string
442  *		args		Arguments to match the format
443  */
444 /*VARARGS*/
445 void
446 fatal_mksh(const char *message, ...)
447 {
448 	va_list args;
449 	char    *buf = static_buf;
450 	char	*mksh_fat_err = gettext("mksh: Fatal error: ");
451 	char	*cur_wrk_dir = gettext("Current working directory: ");
452 	int	mksh_fat_err_len = strlen(mksh_fat_err);
453 
454 	va_start(args, message);
455 	(void) fflush(stdout);
456 	(void) strcpy(buf, mksh_fat_err);
457 	size_t buf_len = vsnprintf(static_buf + mksh_fat_err_len,
458 				   sizeof(static_buf) - mksh_fat_err_len,
459 				   message, args)
460 			+ mksh_fat_err_len
461 			+ strlen(cur_wrk_dir)
462 			+ strlen(get_current_path_mksh())
463 			+ 3; // "\n\n"
464 	va_end(args);
465 	if (buf_len >= sizeof(static_buf)) {
466 		buf = getmem(buf_len);
467 		(void) strcpy(buf, mksh_fat_err);
468 		va_start(args, message);
469 		(void) vsprintf(buf + mksh_fat_err_len, message, args);
470 		va_end(args);
471 	}
472 	(void) strcat(buf, "\n");
473 /*
474 	if (report_pwd) {
475  */
476 	if (1) {
477 		(void) strcat(buf, cur_wrk_dir);
478 		(void) strcat(buf, get_current_path_mksh());
479 		(void) strcat(buf, "\n");
480 	}
481 	(void) fputs(buf, stderr);
482 	(void) fflush(stderr);
483 	if (buf != static_buf) {
484 		retmem_mb(buf);
485 	}
486 	exit_status = 1;
487 	exit(1);
488 }
489 
490 /*
491  *	fatal_reader_mksh(format, args...)
492  *
493  *	Parameters:
494  *		format		printf style format string
495  *		args		arguments to match the format
496  */
497 /*VARARGS*/
498 void
499 fatal_reader_mksh(const char *pattern, ...)
500 {
501 	va_list args;
502 	char	message[1000];
503 
504 	va_start(args, pattern);
505 /*
506 	if (file_being_read != NULL) {
507 		WCSTOMBS(mbs_buffer, file_being_read);
508 		if (line_number != 0) {
509 			(void) sprintf(message,
510 				       gettext("%s, line %d: %s"),
511 				       mbs_buffer,
512 				       line_number,
513 				       pattern);
514 		} else {
515 			(void) sprintf(message,
516 				       "%s: %s",
517 				       mbs_buffer,
518 				       pattern);
519 		}
520 		pattern = message;
521 	}
522  */
523 
524 	(void) fflush(stdout);
525 	(void) fprintf(stderr, gettext("mksh: Fatal error in reader: "));
526 	(void) vfprintf(stderr, pattern, args);
527 	(void) fprintf(stderr, "\n");
528 	va_end(args);
529 
530 /*
531 	if (temp_file_name != NULL) {
532 		(void) fprintf(stderr,
533 			       gettext("mksh: Temp-file %s not removed\n"),
534 			       temp_file_name->string_mb);
535 		temp_file_name = NULL;
536 	}
537  */
538 
539 /*
540 	if (report_pwd) {
541  */
542 	if (1) {
543 		(void) fprintf(stderr,
544 			       gettext("Current working directory %s\n"),
545 			       get_current_path_mksh());
546 	}
547 	(void) fflush(stderr);
548 	exit_status = 1;
549 	exit(1);
550 }
551 
552 /*
553  *	warning_mksh(format, args...)
554  *
555  *	Print a message and continue.
556  *
557  *	Parameters:
558  *		format		printf type format string
559  *		args		Arguments to match the format
560  */
561 /*VARARGS*/
562 void
563 warning_mksh(char * message, ...)
564 {
565 	va_list args;
566 
567 	va_start(args, message);
568 	(void) fflush(stdout);
569 	(void) fprintf(stderr, gettext("mksh: Warning: "));
570 	(void) vfprintf(stderr, message, args);
571 	(void) fprintf(stderr, "\n");
572 	va_end(args);
573 /*
574 	if (report_pwd) {
575  */
576 	if (1) {
577 		(void) fprintf(stderr,
578 			       gettext("Current working directory %s\n"),
579 			       get_current_path_mksh());
580 	}
581 	(void) fflush(stderr);
582 }
583 
584 /*
585  *	get_current_path_mksh()
586  *
587  *	Stuff current_path with the current path if it isnt there already.
588  *
589  *	Parameters:
590  *
591  *	Global variables used:
592  */
593 char *
594 get_current_path_mksh(void)
595 {
596 	char			pwd[(MAXPATHLEN * MB_LEN_MAX)];
597 	static char		*current_path;
598 
599 	if (current_path == NULL) {
600 		pwd[0] = (int) nul_char;
601 
602 		if (getcwd(pwd, sizeof(pwd)) == NULL ||
603 		    pwd[0] == (int) nul_char) {
604 			pwd[0] = (int) slash_char;
605 			pwd[1] = (int) nul_char;
606 		}
607 		current_path = strdup(pwd);
608 	}
609 	return current_path;
610 }
611 
612 /*
613  *	append_prop(target, type)
614  *
615  *	Create a new property and append it to the property list of a Name.
616  *
617  *	Return value:
618  *				A new property block for the target
619  *
620  *	Parameters:
621  *		target		The target that wants a new property
622  *		type		The type of property being requested
623  *
624  *	Global variables used:
625  */
626 Property
627 append_prop(register Name target, register Property_id type)
628 {
629 	register Property	*insert = &target->prop;
630 	register Property	prop = *insert;
631 	register int		size;
632 
633 	switch (type) {
634 	case conditional_prop:
635 		size = sizeof (struct Conditional);
636 		break;
637 	case line_prop:
638 		size = sizeof (struct Line);
639 		break;
640 	case macro_prop:
641 		size = sizeof (struct _Macro);
642 		break;
643 	case makefile_prop:
644 		size = sizeof (struct Makefile);
645 		break;
646 	case member_prop:
647 		size = sizeof (struct Member);
648 		break;
649 	case recursive_prop:
650 		size = sizeof (struct Recursive);
651 		break;
652 	case sccs_prop:
653 		size = sizeof (struct Sccs);
654 		break;
655 	case suffix_prop:
656 		size = sizeof (struct Suffix);
657 		break;
658 	case target_prop:
659 		size = sizeof (struct Target);
660 		break;
661 	case time_prop:
662 		size = sizeof (struct STime);
663 		break;
664 	case vpath_alias_prop:
665 		size = sizeof (struct Vpath_alias);
666 		break;
667 	case long_member_name_prop:
668 		size = sizeof (struct Long_member_name);
669 		break;
670 	case macro_append_prop:
671 		size = sizeof (struct _Macro_appendix);
672 		break;
673 	case env_mem_prop:
674 		size = sizeof (struct _Env_mem);
675 		break;
676 	default:
677 		fatal_mksh(gettext("Internal error. Unknown prop type %d"), type);
678 	}
679 	for (; prop != NULL; insert = &prop->next, prop = *insert);
680 	size += PROPERTY_HEAD_SIZE;
681 	*insert = prop = (Property) getmem(size);
682 	memset((char *) prop, 0, size);
683 	prop->type = type;
684 	prop->next = NULL;
685 	return prop;
686 }
687 
688 /*
689  *	maybe_append_prop(target, type)
690  *
691  *	Append a property to the Name if none of this type exists
692  *	else return the one already there
693  *
694  *	Return value:
695  *				A property of the requested type for the target
696  *
697  *	Parameters:
698  *		target		The target that wants a new property
699  *		type		The type of property being requested
700  *
701  *	Global variables used:
702  */
703 Property
704 maybe_append_prop(register Name target, register Property_id type)
705 {
706 	register Property	prop;
707 
708 	if ((prop = get_prop(target->prop, type)) != NULL) {
709 		return prop;
710 	}
711 	return append_prop(target, type);
712 }
713 
714 /*
715  *	get_prop(start, type)
716  *
717  *	Scan the property list of a Name to find the next property
718  *	of a given type.
719  *
720  *	Return value:
721  *				The first property of the type, if any left
722  *
723  *	Parameters:
724  *		start		The first property block to check for type
725  *		type		The type of property block we need
726  *
727  *	Global variables used:
728  */
729 Property
730 get_prop(register Property start, register Property_id type)
731 {
732 	for (; start != NULL; start = start->next) {
733 		if (start->type == type) {
734 			return start;
735 		}
736 	}
737 	return NULL;
738 }
739 
740 /*
741  *	append_string(from, to, length)
742  *
743  *	Append a C string to a make string expanding it if nessecary
744  *
745  *	Parameters:
746  *		from		The source (C style) string
747  *		to		The destination (make style) string
748  *		length		The length of the from string
749  *
750  *	Global variables used:
751  */
752 void
753 append_string(register wchar_t *from, register String to, register int length)
754 {
755 	if (length == FIND_LENGTH) {
756 		length = wcslen(from);
757 	}
758 	if (to->buffer.start == NULL) {
759 		expand_string(to, 32 + length);
760 	}
761 	if (to->buffer.end - to->text.p <= length) {
762 		expand_string(to,
763 			      (to->buffer.end - to->buffer.start) * 2 +
764 			      length);
765 	}
766 	if (length > 0) {
767 		(void) wcsncpy(to->text.p, from, length);
768 		to->text.p += length;
769 	}
770 	*(to->text.p) = (int) nul_char;
771 }
772 
773 wchar_t * get_wstring(char *from) {
774 	if(from == NULL) {
775 		return NULL;
776 	}
777 	getwstring_count++;
778 	wchar_t * wcbuf = ALLOC_WC(strlen(from) + 1);
779 	mbstowcs(wcbuf, from, strlen(from)+1);
780 	return wcbuf;
781 }
782 
783 void
784 append_string(register char *from, register String to, register int length)
785 {
786 	if (length == FIND_LENGTH) {
787 		length = strlen(from);
788 	}
789 	if (to->buffer.start == NULL) {
790 		expand_string(to, 32 + length);
791 	}
792 	if (to->buffer.end - to->text.p <= length) {
793 		expand_string(to,
794 			      (to->buffer.end - to->buffer.start) * 2 +
795 			      length);
796 	}
797 	if (length > 0) {
798 		(void) mbstowcs(to->text.p, from, length);
799 		to->text.p += length;
800 	}
801 	*(to->text.p) = (int) nul_char;
802 }
803 
804 /*
805  *	expand_string(string, length)
806  *
807  *	Allocate more memory for strings that run out of space.
808  *
809  *	Parameters:
810  *		string		The make style string we want to expand
811  *		length		The new length we need
812  *
813  *	Global variables used:
814  */
815 static void
816 expand_string(register String string, register int length)
817 {
818 	register wchar_t	*p;
819 
820 	if (string->buffer.start == NULL) {
821 		/* For strings that have no memory allocated */
822 		string->buffer.start =
823 		  string->text.p =
824 		    string->text.end =
825 		      ALLOC_WC(length);
826 		string->buffer.end = string->buffer.start + length;
827 		string->text.p[0] = (int) nul_char;
828 		string->free_after_use = true;
829 		expandstring_count++;
830 		return;
831 	}
832 	if (string->buffer.end - string->buffer.start >= length) {
833 		/* If we really don't need more memory. */
834 		return;
835 	}
836 	/*
837 	 * Get more memory, copy the string and free the old buffer if
838 	 * it is was malloc()'ed.
839 	 */
840 	expandstring_count++;
841 	p = ALLOC_WC(length);
842 	(void) wcscpy(p, string->buffer.start);
843 	string->text.p = p + (string->text.p - string->buffer.start);
844 	string->text.end = p + (string->text.end - string->buffer.start);
845 	string->buffer.end = p + length;
846 	if (string->free_after_use) {
847 		retmem(string->buffer.start);
848 	}
849 	string->buffer.start = p;
850 	string->free_after_use = true;
851 }
852 
853 /*
854  *	append_char(from, to)
855  *
856  *	Append one char to a make string expanding it if nessecary
857  *
858  *	Parameters:
859  *		from		Single character to append to string
860  *		to		The destination (make style) string
861  *
862  *	Global variables used:
863  */
864 void
865 append_char(wchar_t from, register String to)
866 {
867 	if (to->buffer.start == NULL) {
868 		expand_string(to, 32);
869 	}
870 	if (to->buffer.end - to->text.p <= 2) {
871 		expand_string(to, to->buffer.end - to->buffer.start + 32);
872 	}
873 	*(to->text.p)++ = from;
874 	*(to->text.p) = (int) nul_char;
875 }
876 
877 /*
878  *	handle_interrupt_mksh()
879  *
880  *	This is where C-C traps are caught.
881  */
882 void
883 handle_interrupt_mksh(int)
884 {
885 	(void) fflush(stdout);
886 	/* Make sure the processes running under us terminate first. */
887 	if (childPid > 0) {
888 		kill(childPid, SIGTERM);
889 		childPid = -1;
890 	}
891 	while (wait((WAIT_T *) NULL) != -1);
892 	exit_status = 2;
893 	exit(2);
894 }
895 
896 /*
897  *	setup_interrupt()
898  *
899  *	This routine saves the original interrupt handler pointers
900  *
901  *	Parameters:
902  *
903  *	Static variables used:
904  *		sigivalue	The original signal handler
905  *		sigqvalue	The original signal handler
906  *		sigtvalue	The original signal handler
907  *		sighvalue	The original signal handler
908  */
909 void
910 setup_interrupt(register void (*handler) (int))
911 {
912 #ifdef SUN5_0
913 	sigivalue = bsd_signal(SIGINT, SIG_IGN);
914 	sigqvalue = bsd_signal(SIGQUIT, SIG_IGN);
915 	sigtvalue = bsd_signal(SIGTERM, SIG_IGN);
916 	sighvalue = bsd_signal(SIGHUP, SIG_IGN);
917 #else
918 	sigivalue = (void (*) (int)) bsd_signal(SIGINT, (void (*) (int)) SIG_IGN);
919 	sigqvalue = (void (*) (int)) bsd_signal(SIGQUIT, (void (*) (int)) SIG_IGN);
920 	sigtvalue = (void (*) (int)) bsd_signal(SIGTERM, (void (*) (int)) SIG_IGN);
921 	sighvalue = (void (*) (int)) bsd_signal(SIGHUP, (void (*) (int)) SIG_IGN);
922 #endif
923 	enable_interrupt(handler);
924 }
925 
926 
927 void
928 mbstowcs_with_check(wchar_t *pwcs, const char *s, size_t n)
929 {
930 	if(mbstowcs(pwcs, s, n) == -1) {
931 		const unsigned char *p;
932 
933 		p = (unsigned char *)setlocale(LC_CTYPE, NULL);
934 
935 		/*
936 		 * Work around a Linux bug:
937 		 * POSIX requires: In the POSIX locale an [EILSEQ] error cannot
938 		 * occur since all byte values are valid characters.
939 		 * But Linux ignores this ant this is why we did come here.
940 		 */
941 		if (p[0] == 'C' && p[1] == '\0') {
942 			wchar_t	*wp = pwcs;
943 
944 			p = (const unsigned char *)s;
945 			if (n == 0)
946 				return;
947 			do {
948 				if ((*wp++ = *p++) == '\0')
949 					break;
950 			} while (--n > 0);
951 			return;
952 		}
953 		fatal_mksh(gettext("The string `%s' is not valid in current locale"), s);
954 	}
955 }
956 
957 
958 
959 Wstring::Wstring()
960 {
961 	INIT_STRING_FROM_STACK(string, string_buf);
962 }
963 
964 Wstring::Wstring(struct _Name * name)
965 {
966 	INIT_STRING_FROM_STACK(string, string_buf);
967 	append_string(name->string_mb, &string, name->hash.length);
968 }
969 
970 Wstring::~Wstring()
971 {
972 	if(string.free_after_use) {
973 		retmem(string.buffer.start);
974 	}
975 }
976 
977 void
978 Wstring::init(struct _Name * name)
979 {
980 	if(string.free_after_use) {
981 		retmem(string.buffer.start);
982 	}
983 	INIT_STRING_FROM_STACK(string, string_buf);
984 	append_string(name->string_mb, &string, name->hash.length);
985 }
986 
987 void
988 Wstring::init(wchar_t * name, unsigned length)
989 {
990 	INIT_STRING_FROM_STACK(string, string_buf);
991 	append_string(name, &string, length);
992 	string.buffer.start[length] = 0;
993 }
994 
995 Boolean
996 Wstring::equaln(wchar_t * str, unsigned length)
997 {
998 	return (Boolean)IS_WEQUALN(string.buffer.start, str, length);
999 }
1000 
1001 Boolean
1002 Wstring::equaln(Wstring * str, unsigned length)
1003 {
1004 	return (Boolean)IS_WEQUALN(string.buffer.start, str->string.buffer.start, length);
1005 }
1006 
1007 Boolean
1008 Wstring::equal(wchar_t * str, unsigned off, unsigned length)
1009 {
1010 	return (Boolean)IS_WEQUALN(string.buffer.start + off, str, length);
1011 }
1012 
1013 Boolean
1014 Wstring::equal(wchar_t * str, unsigned off)
1015 {
1016 	return (Boolean)IS_WEQUAL(string.buffer.start + off, str);
1017 }
1018 
1019 Boolean
1020 Wstring::equal(wchar_t * str)
1021 {
1022 	return equal(str, 0);
1023 }
1024 
1025 Boolean
1026 Wstring::equal(Wstring * str, unsigned off, unsigned length)
1027 {
1028 	return (Boolean)IS_WEQUALN(string.buffer.start + off, str->string.buffer.start, length);
1029 }
1030 
1031 Boolean
1032 Wstring::equal(Wstring * str)
1033 {
1034 	return equal(str, 0);
1035 }
1036 
1037 Boolean
1038 Wstring::equal(Wstring * str, unsigned off)
1039 {
1040 	return (Boolean)IS_WEQUAL(string.buffer.start + off, str->string.buffer.start);
1041 }
1042 
1043 void
1044 Wstring::append_to_str(struct _String * str, unsigned off, unsigned length)
1045 {
1046 	append_string(string.buffer.start + off, str, length);
1047 }
1048 
1049 Name
1050 Name_set::lookup(const char *key)
1051 {
1052 	for (entry *node = root; node != 0;) {
1053 		int res = strcmp(key, node->name->string_mb);
1054 		if (res < 0) {
1055 			node = node->left;
1056 		} else if (res > 0) {
1057 			node = node->right;
1058 		} else {
1059 			return node->name;
1060 		}
1061 	}
1062 	return 0;
1063 }
1064 
1065 Name
1066 Name_set::insert(const char *key, Boolean &found)
1067 {
1068 	Name	name = 0;
1069 
1070 	if (root != 0) {
1071 		for (entry *node = root; name == 0;) {
1072 			int res = strcmp(key, node->name->string_mb);
1073 			if (res < 0) {
1074 				if (node->left != 0) {
1075 					node = node->left;
1076 				} else {
1077 					found = false;
1078 					name = ALLOC(Name);
1079 
1080 					node->left = new entry(name, node);
1081 					rebalance(node);
1082 				}
1083 			} else if (res > 0) {
1084 				if (node->right != 0) {
1085 					node = node->right;
1086 				} else {
1087 					found = false;
1088 					name = ALLOC(Name);
1089 
1090 					node->right = new entry(name, node);
1091 					rebalance(node);
1092 				}
1093 			} else {
1094 				found = true;
1095 				name = node->name;
1096 			}
1097 		}
1098 	} else {
1099 		found = false;
1100 		name = ALLOC(Name);
1101 
1102 		root = new entry(name, 0);
1103 	}
1104 	return name;
1105 }
1106 
1107 void
1108 Name_set::insert(Name name) {
1109 	if (root != 0) {
1110 		for (entry *node = root;;) {
1111 			int res = strcmp(name->string_mb, node->name->string_mb);
1112 			if (res < 0) {
1113 				if (node->left != 0) {
1114 					node = node->left;
1115 				} else {
1116 					node->left = new entry(name, node);
1117 					rebalance(node);
1118 					break;
1119 				}
1120 			} else if (res > 0) {
1121 				if (node->right != 0) {
1122 					node = node->right;
1123 				} else {
1124 					node->right = new entry(name, node);
1125 					rebalance(node);
1126 					break;
1127 				}
1128 			} else {
1129 				// should be an error: inserting already existing name
1130 				break;
1131 			}
1132 		}
1133 	} else {
1134 		root = new entry(name, 0);
1135 	}
1136 }
1137 
1138 void
1139 Name_set::rebalance(Name_set::entry *node) {
1140 	for (; node != 0; node = node->parent) {
1141 		entry *right = node->right;
1142 		entry *left = node->left;
1143 
1144 		unsigned rdepth = (right != 0) ? right->depth : 0;
1145 		unsigned ldepth = (left != 0) ? left->depth : 0;
1146 
1147 		if (ldepth > rdepth + 1) {
1148 			if ((node->left = left->right) != 0) {
1149 				left->right->parent = node;
1150 			}
1151 			if ((left->parent = node->parent) != 0) {
1152 				if (node == node->parent->right) {
1153 					node->parent->right = left;
1154 				} else {
1155 					node->parent->left = left;
1156 				}
1157 			} else {
1158 				root = left;
1159 			}
1160 			left->right = node;
1161 			node->parent = left;
1162 
1163 			node->setup_depth();
1164 			node = left;
1165 		} else if (rdepth > ldepth + 1) {
1166 			if ((node->right = right->left) != 0) {
1167 				right->left->parent = node;
1168 			}
1169 			if ((right->parent = node->parent) != 0) {
1170 				if (node == node->parent->right) {
1171 					node->parent->right = right;
1172 				} else {
1173 					node->parent->left = right;
1174 				}
1175 			} else {
1176 				root = right;
1177 			}
1178 			right->left = node;
1179 			node->parent = right;
1180 
1181 			node->setup_depth();
1182 			node = right;
1183 		}
1184 		node->setup_depth();
1185 	}
1186 }
1187 
1188 Name_set::iterator
1189 Name_set::begin() const {
1190 	for (entry *node = root; node != 0; node = node->left) {
1191 		if (node->left == 0) {
1192 			return iterator(node);
1193 		}
1194 	}
1195 	return iterator();
1196 }
1197 
1198 Name_set::iterator&
1199 Name_set::iterator::operator++() {
1200 	if (node != 0) {
1201 		if (node->right != 0) {
1202 			node = node->right;
1203 			while (node->left != 0) {
1204 				node = node->left;
1205 			}
1206 		} else {
1207 			while ((node->parent != 0) && (node->parent->right == node)) {
1208 				node = node->parent;
1209 			}
1210 			node = node->parent;
1211 		}
1212 	}
1213 	return *this;
1214 }
1215