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