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