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