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.
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.
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]
22 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 * This file contains various unclassified routines. Some main groups:
35 * Error message handling
36 * Make internal state dumping
37 * main routine support
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() */
51 #include <string.h> /* strerror() */
67 void (*sigivalue
)(int) = SIG_DFL
;
68 void (*sigqvalue
)(int) = SIG_DFL
;
69 void (*sigtvalue
)(int) = SIG_DFL
;
70 void (*sighvalue
)(int) = SIG_DFL
;
73 long getname_bytes_count
= 0;
74 long getname_names_count
= 0;
75 long getname_struct_count
= 0;
77 long freename_bytes_count
= 0;
78 long freename_names_count
= 0;
79 long freename_struct_count
= 0;
81 long expandstring_count
= 0;
82 long getwstring_count
= 0;
85 * File table of contents
87 static void expand_string(register String string
, register int length
);
89 #define FATAL_ERROR_MSG_SIZE 200
94 * malloc() version that checks the returned value.
97 * The memory chunk we allocated
100 * size The size of the chunk we need
102 * Global variables used:
105 getmem(register int size
)
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"));
122 * Cover funtion for free() to make it possible to insert advises.
125 * p The memory block to free
127 * Global variables used:
132 (void) free((char *) p
);
142 * getname_fn(name, len, dont_enter)
144 * Hash a name string to the corresponding nameblock.
147 * The Name block for the string
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
154 * Global variables used:
155 * funny The vector of semantic tags for characters
156 * hashtab The hashtable used for the nametable
159 getname_fn(wchar_t *name
, register int len
, register Boolean dont_enter
, register Boolean
* foundp
)
162 register wchar_t *cap
= name
;
164 static Name_rec empty_Name
;
165 char *tmp_mbs_buffer
= NULL
;
166 char *mbs_name
= mbs_buffer
;
169 * First figure out how long the string is.
170 * If the len argument is -1 we count the chars here.
172 if (len
== FIND_LENGTH
) {
173 length
= wcslen(name
);
179 ws
.init(name
, length
);
180 if (length
>= MAXPATHLEN
) {
181 mbs_name
= tmp_mbs_buffer
= getmem((length
* MB_LEN_MAX
) + 1);
183 (void) wcstombs(mbs_name
, ws
.get_string(), (length
* MB_LEN_MAX
) + 1);
185 /* Look for the string */
186 if (dont_enter
|| (foundp
!= 0)) {
187 np
= hashtab
.lookup(mbs_name
);
189 *foundp
= (np
!= 0) ? true : false;
191 if ((np
!= 0) || dont_enter
) {
192 if(tmp_mbs_buffer
!= NULL
) {
193 retmem_mb(tmp_mbs_buffer
);
201 np
= hashtab
.insert(mbs_name
, found
);
203 if(tmp_mbs_buffer
!= NULL
) {
204 retmem_mb(tmp_mbs_buffer
);
209 getname_struct_count
+= sizeof(struct _Name
);
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
;
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
++);
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
++;
236 store_name(Name name
)
238 hashtab
.insert(name
);
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
) {
256 * enable_interrupt(handler)
258 * This routine sets a new interrupt handler for the signals make
259 * wants to deal with.
262 * handler The function installed as interrupt handler
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
271 enable_interrupt(register void (*handler
) (int))
273 if (sigivalue
!= SIG_IGN
) {
274 (void) bsd_signal(SIGINT
, (SIG_PF
) handler
);
276 if (sigqvalue
!= SIG_IGN
) {
277 (void) bsd_signal(SIGQUIT
, (SIG_PF
) handler
);
279 if (sigtvalue
!= SIG_IGN
) {
280 (void) bsd_signal(SIGTERM
, (SIG_PF
) handler
);
282 if (sighvalue
!= SIG_IGN
) {
283 (void) bsd_signal(SIGHUP
, (SIG_PF
) handler
);
288 * setup_char_semantics()
290 * Load the vector char_semantics[] with lexical markers
294 * Global variables used:
295 * char_semantics The vector of character semantics that we set
298 setup_char_semantics(void)
301 wchar_t wc_buffer
[1];
309 for (s
; MBTOWC(wc_buffer
, s
); s
++) {
310 entry
= get_char_semantics_entry(*wc_buffer
);
311 char_semantics
[entry
] |= (int) command_prefix_sem
;
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
;
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
;
323 for (s
= "?[*"; MBTOWC(wc_buffer
, s
); s
++) {
324 entry
= get_char_semantics_entry(*wc_buffer
);
325 char_semantics
[entry
] |= (int) wildcard_sem
;
327 char_semantics
[colon_char_entry
] |= (int) colon_sem
;
328 char_semantics
[parenleft_char_entry
] |= (int) parenleft_sem
;
334 * Return the error message for a system call error
337 * An error message string
340 * errnum The number of the error we want to describe
342 * Global variables used:
343 * sys_errlist A vector of error messages
344 * sys_nerr The size of sys_errlist
353 if ((errnum
< 0) || (errnum
> sys_nerr
)) {
354 errbuf
= getmem(6+1+11+1);
355 (void) sprintf(errbuf
, gettext("Error %d"), errnum
);
358 return strerror(errnum
);
363 static char static_buf
[MAXPATHLEN
*3];
366 * fatal_mksh(format, args...)
368 * Print a message and die
371 * format printf type format string
372 * args Arguments to match the format
376 fatal_mksh(const char *message
, ...)
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
);
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
,
391 + strlen(cur_wrk_dir
)
392 + strlen(get_current_path_mksh())
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
);
402 (void) strcat(buf
, "\n");
407 (void) strcat(buf
, cur_wrk_dir
);
408 (void) strcat(buf
, get_current_path_mksh());
409 (void) strcat(buf
, "\n");
411 (void) fputs(buf
, stderr
);
412 (void) fflush(stderr
);
413 if (buf
!= static_buf
) {
421 * fatal_reader_mksh(format, args...)
424 * format printf style format string
425 * args arguments to match the format
429 fatal_reader_mksh(const char * pattern
, ...)
434 va_start(args
, pattern
);
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"),
445 (void) sprintf(message,
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");
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;
473 (void) fprintf(stderr
,
474 gettext("Current working directory %s\n"),
475 get_current_path_mksh());
477 (void) fflush(stderr
);
483 * warning_mksh(format, args...)
485 * Print a message and continue.
488 * format printf type format string
489 * args Arguments to match the format
493 warning_mksh(char * message
, ...)
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");
507 (void) fprintf(stderr
,
508 gettext("Current working directory %s\n"),
509 get_current_path_mksh());
511 (void) fflush(stderr
);
515 * get_current_path_mksh()
517 * Stuff current_path with the current path if it isnt there already.
521 * Global variables used:
524 get_current_path_mksh(void)
526 char pwd
[(MAXPATHLEN
* MB_LEN_MAX
)];
527 static char *current_path
;
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
;
535 current_path
= strdup(pwd
);
541 * append_prop(target, type)
543 * Create a new property and append it to the property list of a Name.
546 * A new property block for the target
549 * target The target that wants a new property
550 * type The type of property being requested
552 * Global variables used:
555 append_prop(register Name target
, register Property_id type
)
557 register Property
*insert
= &target
->prop
;
558 register Property prop
= *insert
;
562 case conditional_prop
:
563 size
= sizeof (struct Conditional
);
566 size
= sizeof (struct Line
);
569 size
= sizeof (struct _Macro
);
572 size
= sizeof (struct Makefile
);
575 size
= sizeof (struct Member
);
578 size
= sizeof (struct Recursive
);
581 size
= sizeof (struct Sccs
);
584 size
= sizeof (struct Suffix
);
587 size
= sizeof (struct Target
);
590 size
= sizeof (struct STime
);
592 case vpath_alias_prop
:
593 size
= sizeof (struct Vpath_alias
);
595 case long_member_name_prop
:
596 size
= sizeof (struct Long_member_name
);
598 case macro_append_prop
:
599 size
= sizeof (struct _Macro_appendix
);
602 size
= sizeof (struct _Env_mem
);
605 fatal_mksh(gettext("Internal error. Unknown prop type %d"), type
);
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
);
617 * maybe_append_prop(target, type)
619 * Append a property to the Name if none of this type exists
620 * else return the one already there
623 * A property of the requested type for the target
626 * target The target that wants a new property
627 * type The type of property being requested
629 * Global variables used:
632 maybe_append_prop(register Name target
, register Property_id type
)
634 register Property prop
;
636 if ((prop
= get_prop(target
->prop
, type
)) != NULL
) {
639 return append_prop(target
, type
);
643 * get_prop(start, type)
645 * Scan the property list of a Name to find the next property
649 * The first property of the type, if any left
652 * start The first property block to check for type
653 * type The type of property block we need
655 * Global variables used:
658 get_prop(register Property start
, register Property_id type
)
660 for (; start
!= NULL
; start
= start
->next
) {
661 if (start
->type
== type
) {
669 * append_string(from, to, length)
671 * Append a C string to a make string expanding it if nessecary
674 * from The source (C style) string
675 * to The destination (make style) string
676 * length The length of the from string
678 * Global variables used:
681 append_string(register wchar_t *from
, register String to
, register int length
)
683 if (length
== FIND_LENGTH
) {
684 length
= wcslen(from
);
686 if (to
->buffer
.start
== NULL
) {
687 expand_string(to
, 32 + length
);
689 if (to
->buffer
.end
- to
->text
.p
<= length
) {
691 (to
->buffer
.end
- to
->buffer
.start
) * 2 +
695 (void) wcsncpy(to
->text
.p
, from
, length
);
696 to
->text
.p
+= length
;
698 *(to
->text
.p
) = (int) nul_char
;
701 wchar_t * get_wstring(char *from
) {
706 wchar_t * wcbuf
= ALLOC_WC(strlen(from
) + 1);
707 mbstowcs(wcbuf
, from
, strlen(from
)+1);
712 append_string(register char *from
, register String to
, register int length
)
714 if (length
== FIND_LENGTH
) {
715 length
= strlen(from
);
717 if (to
->buffer
.start
== NULL
) {
718 expand_string(to
, 32 + length
);
720 if (to
->buffer
.end
- to
->text
.p
<= length
) {
722 (to
->buffer
.end
- to
->buffer
.start
) * 2 +
726 (void) mbstowcs(to
->text
.p
, from
, length
);
727 to
->text
.p
+= length
;
729 *(to
->text
.p
) = (int) nul_char
;
733 * expand_string(string, length)
735 * Allocate more memory for strings that run out of space.
738 * string The make style string we want to expand
739 * length The new length we need
741 * Global variables used:
744 expand_string(register String string
, register int length
)
748 if (string
->buffer
.start
== NULL
) {
749 /* For strings that have no memory allocated */
750 string
->buffer
.start
=
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
++;
760 if (string
->buffer
.end
- string
->buffer
.start
>= length
) {
761 /* If we really don't need more memory. */
765 * Get more memory, copy the string and free the old buffer if
766 * it is was malloc()'ed.
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
);
777 string
->buffer
.start
= p
;
778 string
->free_after_use
= true;
782 * append_char(from, to)
784 * Append one char to a make string expanding it if nessecary
787 * from Single character to append to string
788 * to The destination (make style) string
790 * Global variables used:
793 append_char(wchar_t from
, register String to
)
795 if (to
->buffer
.start
== NULL
) {
796 expand_string(to
, 32);
798 if (to
->buffer
.end
- to
->text
.p
<= 2) {
799 expand_string(to
, to
->buffer
.end
- to
->buffer
.start
+ 32);
801 *(to
->text
.p
)++ = from
;
802 *(to
->text
.p
) = (int) nul_char
;
806 * handle_interrupt_mksh()
808 * This is where C-C traps are caught.
811 handle_interrupt_mksh(int)
813 (void) fflush(stdout
);
814 /* Make sure the processes running under us terminate first. */
816 kill(childPid
, SIGTERM
);
819 while (wait((int *) NULL
) != -1);
827 * This routine saves the original interrupt handler pointers
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
838 setup_interrupt(register void (*handler
) (int))
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
);
849 mbstowcs_with_check(wchar_t *pwcs
, const char *s
, size_t n
)
851 if(mbstowcs(pwcs
, s
, n
) == -1) {
852 fatal_mksh(gettext("The string `%s' is not valid in current locale"), s
);
860 INIT_STRING_FROM_STACK(string
, string_buf
);
863 Wstring::Wstring(struct _Name
* name
)
865 INIT_STRING_FROM_STACK(string
, string_buf
);
866 append_string(name
->string_mb
, &string
, name
->hash
.length
);
871 if(string
.free_after_use
) {
872 retmem(string
.buffer
.start
);
877 Wstring::init(struct _Name
* name
)
879 if(string
.free_after_use
) {
880 retmem(string
.buffer
.start
);
882 INIT_STRING_FROM_STACK(string
, string_buf
);
883 append_string(name
->string_mb
, &string
, name
->hash
.length
);
887 Wstring::init(wchar_t * name
, unsigned length
)
889 INIT_STRING_FROM_STACK(string
, string_buf
);
890 append_string(name
, &string
, length
);
891 string
.buffer
.start
[length
] = 0;
895 Wstring::equaln(wchar_t * str
, unsigned length
)
897 return (Boolean
)IS_WEQUALN(string
.buffer
.start
, str
, length
);
901 Wstring::equaln(Wstring
* str
, unsigned length
)
903 return (Boolean
)IS_WEQUALN(string
.buffer
.start
, str
->string
.buffer
.start
, length
);
907 Wstring::equal(wchar_t * str
, unsigned off
, unsigned length
)
909 return (Boolean
)IS_WEQUALN(string
.buffer
.start
+ off
, str
, length
);
913 Wstring::equal(wchar_t * str
, unsigned off
)
915 return (Boolean
)IS_WEQUAL(string
.buffer
.start
+ off
, str
);
919 Wstring::equal(wchar_t * str
)
921 return equal(str
, 0);
925 Wstring::equal(Wstring
* str
, unsigned off
, unsigned length
)
927 return (Boolean
)IS_WEQUALN(string
.buffer
.start
+ off
, str
->string
.buffer
.start
, length
);
931 Wstring::equal(Wstring
* str
)
933 return equal(str
, 0);
937 Wstring::equal(Wstring
* str
, unsigned off
)
939 return (Boolean
)IS_WEQUAL(string
.buffer
.start
+ off
, str
->string
.buffer
.start
);
943 Wstring::append_to_str(struct _String
* str
, unsigned off
, unsigned length
)
945 append_string(string
.buffer
.start
+ off
, str
, length
);
949 Name_set::lookup(const char *key
)
951 for (entry
*node
= root
; node
!= 0;) {
952 int res
= strcmp(key
, node
->name
->string_mb
);
955 } else if (res
> 0) {
965 Name_set::insert(const char *key
, Boolean
&found
)
970 for (entry
*node
= root
; name
== 0;) {
971 int res
= strcmp(key
, node
->name
->string_mb
);
973 if (node
->left
!= 0) {
979 node
->left
= new entry(name
, node
);
982 } else if (res
> 0) {
983 if (node
->right
!= 0) {
989 node
->right
= new entry(name
, node
);
1001 root
= new entry(name
, 0);
1007 Name_set::insert(Name name
) {
1009 for (entry
*node
= root
;;) {
1010 int res
= strcmp(name
->string_mb
, node
->name
->string_mb
);
1012 if (node
->left
!= 0) {
1015 node
->left
= new entry(name
, node
);
1019 } else if (res
> 0) {
1020 if (node
->right
!= 0) {
1023 node
->right
= new entry(name
, node
);
1028 // should be an error: inserting already existing name
1033 root
= new entry(name
, 0);
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
;
1043 unsigned rdepth
= (right
!= 0) ? right
->depth
: 0;
1044 unsigned ldepth
= (left
!= 0) ? left
->depth
: 0;
1046 if (ldepth
> rdepth
+ 1) {
1047 if ((node
->left
= left
->right
) != 0) {
1048 left
->right
->parent
= node
;
1050 if ((left
->parent
= node
->parent
) != 0) {
1051 if (node
== node
->parent
->right
) {
1052 node
->parent
->right
= left
;
1054 node
->parent
->left
= left
;
1060 node
->parent
= left
;
1062 node
->setup_depth();
1064 } else if (rdepth
> ldepth
+ 1) {
1065 if ((node
->right
= right
->left
) != 0) {
1066 right
->left
->parent
= node
;
1068 if ((right
->parent
= node
->parent
) != 0) {
1069 if (node
== node
->parent
->right
) {
1070 node
->parent
->right
= right
;
1072 node
->parent
->left
= right
;
1078 node
->parent
= right
;
1080 node
->setup_depth();
1083 node
->setup_depth();
1088 Name_set::begin() const {
1089 for (entry
*node
= root
; node
!= 0; node
= node
->left
) {
1090 if (node
->left
== 0) {
1091 return iterator(node
);
1098 Name_set::iterator::operator++() {
1100 if (node
->right
!= 0) {
1102 while (node
->left
!= 0) {
1106 while ((node
->parent
!= 0) && (node
->parent
->right
== node
)) {
1107 node
= node
->parent
;
1109 node
= node
->parent
;