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