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