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