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