diff options
Diffstat (limited to 'usr/src/make_src/Make/lib/mksh')
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/Makefile | 29 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/Makefile | 50 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/Variant.mk | 58 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/dosys.cc | 851 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/globals.cc | 140 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/i18n.cc | 100 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/libmksh.msg | 81 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/macro.cc | 1414 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/misc.cc | 1178 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/mksh.cc | 286 | ||||
-rw-r--r-- | usr/src/make_src/Make/lib/mksh/src/read.cc | 174 |
11 files changed, 4361 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/lib/mksh/Makefile b/usr/src/make_src/Make/lib/mksh/Makefile new file mode 100644 index 0000000..fd663cd --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 1996 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# @(#)Makefile 1.5 06/12/12 +# + +TOP = ../../.. +include $(TOP)/rules/variant.mk +include $(TOP)/rules/derived.mk diff --git a/usr/src/make_src/Make/lib/mksh/src/Makefile b/usr/src/make_src/Make/lib/mksh/src/Makefile new file mode 100644 index 0000000..ebed78f --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/Makefile @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 1996 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# @(#)Makefile 1.3 06/12/12 +# + +# Generic makefile for use in src directories. Knows how to make common things +# in the right $(VARIANT) directory. + +#TOP = ../../../.. +include $(TOP)/rules/variant.mk + +all := TARG = all +install := TARG = install +clean := TARG = clean +test := TARG = test +l10n_install := TARG = l10n_install +i18n_install := TARG = i18n_install + +SRC = ../src +MFLAGS += SRC=$(SRC) + +# See $(TOP)/rules/master.mk for how these are built. +%.h %.cc %.C %.E %.o all install clean test l10n_install i18n_install: FRC + @ if [ ! -d ../$(VARIANT) ]; then \ + mkdir ../$(VARIANT) ; \ + fi + cd ../$(VARIANT); $(MAKE) $(MFLAGS) -f $(SRC)/Variant.mk DESTDIR=$(DESTDIR) $@ + +FRC: diff --git a/usr/src/make_src/Make/lib/mksh/src/Variant.mk b/usr/src/make_src/Make/lib/mksh/src/Variant.mk new file mode 100644 index 0000000..427ba54 --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/Variant.mk @@ -0,0 +1,58 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# @(#)Variant.mk 1.19 06/12/12 +# + +TOP = ../../../.. +include $(TOP)/rules/master.mk +include $(TOP)/rules/dmake.mk + +PKG_TOP = $(TOP)/Make +CPPFLAGS += -I$(PKG_TOP)/include + +CCSRCS = \ + dosys.cc \ + globals.cc \ + i18n.cc \ + macro.cc \ + misc.cc \ + mksh.cc \ + read.cc + +HDRS_DIR = $(PKG_TOP)/include/mksh +HDRS_LIST = $(HDRS_DIR)/defs.h \ + $(CCSRCS:%.cc=$(HDRS_DIR)/%.h) \ + $(CSRCS:%.c=$(HDRS_DIR)/%.h) + +.INIT: $(HDRS_LIST) + +LIBNAME = libmksh.a +MSG_FILE = libmksh.msg +I18N_DIRS = $(SRC) + +#CPPFLAGS += -DTEAMWARE_MAKE_CMN -DDISTRIBUTED + +include $(TOP)/Make/lib/Lib.mk +include $(TOP)/rules/lib.mk + diff --git a/usr/src/make_src/Make/lib/mksh/src/dosys.cc b/usr/src/make_src/Make/lib/mksh/src/dosys.cc new file mode 100644 index 0000000..fc4306b --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/dosys.cc @@ -0,0 +1,851 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)dosys.cc 1.38 06/12/12 + */ + +#pragma ident "@(#)dosys.cc 1.38 06/12/12" + +/* + * dosys.cc + * + * Execute one commandline + */ + +/* + * Included files + */ +#include <sys/wait.h> /* WIFEXITED(status) */ +#include <avo/avo_alloca.h> /* alloca() */ + +#if defined(TEAMWARE_MAKE_CMN) || defined(MAKETOOL) /* tolik */ +# include <avo/strings.h> /* AVO_STRDUP() */ +#if defined(DISTRIBUTED) +# include <dm/Avo_CmdOutput.h> +# include <rw/xdrstrea.h> +#endif +#endif + +#include <stdio.h> /* errno */ +#include <errno.h> /* errno */ +#include <fcntl.h> /* open() */ +#include <mksh/dosys.h> +#include <mksh/macro.h> /* getvar() */ +#include <mksh/misc.h> /* getmem(), fatal_mksh(), errmsg() */ +#include <mksdmsi18n/mksdmsi18n.h> /* libmksdmsi18n_init() */ +#include <sys/signal.h> /* SIG_DFL */ +#include <sys/stat.h> /* open() */ +#include <sys/wait.h> /* wait() */ +#include <ulimit.h> /* ulimit() */ +#include <unistd.h> /* close(), dup2() */ + +#if defined (HP_UX) || defined (linux) +# include <sys/param.h> +# include <wctype.h> +# include <wchar.h> +#endif + +#if defined (linux) +# define wslen(x) wcslen(x) +# define wscpy(x,y) wcscpy(x,y) +#endif + +/* + * Defined macros + */ +#if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */ +#define SEND_MTOOL_MSG(cmds) \ + if (send_mtool_msgs) { \ + cmds \ + } +#else +#define SEND_MTOOL_MSG(cmds) +#endif + +/* + * typedefs & structs + */ + +/* + * Static variables + */ + +/* + * File table of contents + */ +static Boolean exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path); + +/* + * Workaround for NFS bug. Sometimes, when running 'open' on a remote + * dmake server, it fails with "Stale NFS file handle" error. + * The second attempt seems to work. + */ +int +my_open(const char *path, int oflag, mode_t mode) { + int res = open(path, oflag, mode); +#ifdef linux +// Workaround for NFS problem: even when all directories in 'path' +// exist, 'open' (file creation) fails with ENOENT. + int nattempt = 0; + while (res < 0 && (errno == ESTALE || errno == EAGAIN || errno == ENOENT)) { + nattempt++; + if(nattempt > 30) { + break; + } + sleep(1); +#else + if (res < 0 && (errno == ESTALE || errno == EAGAIN)) { +#endif + /* Stale NFS file handle. Try again */ + res = open(path, oflag, mode); + } + return res; +} + +/* + * void + * redirect_io(char *stdout_file, char *stderr_file) + * + * Redirects stdout and stderr for a child mksh process. + */ +void +redirect_io(char *stdout_file, char *stderr_file) +{ + long descriptor_limit; + int i; + +#if defined (HP_UX) || defined (linux) + /* + * HP-UX does not support the UL_GDESLIM command for ulimit(). + * NOFILE == max num open files per process (from <sys/param.h>) + */ + descriptor_limit = NOFILE; +#else + if ((descriptor_limit = ulimit(UL_GDESLIM)) < 0) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 89, "ulimit() failed: %s"), errmsg(errno)); + } +#endif + for (i = 3; i < descriptor_limit; i++) { + (void) close(i); + } + if ((i = my_open(stdout_file, + O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC, + S_IREAD | S_IWRITE)) < 0) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 90, "Couldn't open standard out temp file `%s': %s"), + stdout_file, + errmsg(errno)); + } else { + if (dup2(i, 1) == -1) { + fatal_mksh(NOCATGETS("*** Error: dup2(3, 1) failed: %s"), + errmsg(errno)); + } + close(i); + } + if (stderr_file == NULL) { + if (dup2(1, 2) == -1) { + fatal_mksh(NOCATGETS("*** Error: dup2(1, 2) failed: %s"), + errmsg(errno)); + } + } else if ((i = my_open(stderr_file, + O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC, + S_IREAD | S_IWRITE)) < 0) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 91, "Couldn't open standard error temp file `%s': %s"), + stderr_file, + errmsg(errno)); + } else { + if (dup2(i, 2) == -1) { + fatal_mksh(NOCATGETS("*** Error: dup2(3, 2) failed: %s"), + errmsg(errno)); + } + close(i); + } +} + +/* + * dosys_mksh(command, ignore_error, call_make, silent_error, target) + * + * Check if command string contains meta chars and dispatch to + * the proper routine for executing one command line. + * + * Return value: + * Indicates if the command execution failed + * + * Parameters: + * command The command to run + * ignore_error Should we abort when an error is seen? + * call_make Did command reference $(MAKE) ? + * silent_error Should error messages be suppressed for dmake? + * target Target we are building + * + * Global variables used: + * do_not_exec_rule Is -n on? + * working_on_targets We started processing real targets + */ +Doname +dosys_mksh(register Name command, register Boolean ignore_error, register Boolean call_make, Boolean silent_error, Boolean always_exec, Name target, Boolean redirect_out_err, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio) +{ + register int length = command->hash.length; + register wchar_t *p; + register wchar_t *q; + register wchar_t *cmd_string; + struct stat before; + Doname result; + Boolean working_on_targets_mksh = true; + Wstring wcb(command); + p = wcb.get_string(); + cmd_string = p; + + /* Strip spaces from head of command string */ + while (iswspace(*p)) { + p++, length--; + } + if (*p == (int) nul_char) { + return build_failed; + } + /* If we are faking it we just return */ + if (do_not_exec_rule && + working_on_targets_mksh && + !call_make && + !always_exec) { + return build_ok; + } + + /* Copy string to make it OK to write it. */ + q = ALLOC_WC(length + 1); + (void) wscpy(q, p); + /* Write the state file iff this command uses make. */ +/* XXX - currently does not support recursive make's, $(MAKE)'s + if (call_make && command_changed) { + write_state_file(0, false); + } + (void) stat(make_state->string_mb, &before); + */ + /* + * Run command directly if it contains no shell meta chars, + * else run it using the shell. + */ + /* XXX - command->meta *may* not be set correctly */ + if (await(ignore_error, + silent_error, + target, + cmd_string, + command->meta ? + doshell(q, ignore_error, redirect_out_err, stdout_file, stderr_file, nice_prio) : + doexec(q, ignore_error, redirect_out_err, stdout_file, stderr_file, vroot_path, nice_prio), + false, + NULL, + -1)) { + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in dosys_mksh(), and await() returned result of build_ok.")); +#endif + + result = build_ok; + } else { + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in dosys_mksh(), and await() returned result of build_failed.")); +#endif + + result = build_failed; + } + retmem(q); + +/* XXX - currently does not support recursive make's, $(MAKE)'s + if ((report_dependencies_level == 0) && + call_make) { + make_state->stat.time = (time_t)file_no_time; + (void)exists(make_state); + if (before.st_mtime == make_state->stat.time) { + return result; + } + makefile_type = reading_statefile; + if (read_trace_level > 1) { + trace_reader = true; + } + (void) read_simple_file(make_state, + false, + false, + false, + false, + false, + true); + trace_reader = false; + } + */ + return result; +} + +/* + * doshell(command, ignore_error) + * + * Used to run command lines that include shell meta-characters. + * The make macro SHELL is supposed to contain a path to the shell. + * + * Return value: + * The pid of the process we started + * + * Parameters: + * command The command to run + * ignore_error Should we abort on error? + * + * Global variables used: + * filter_stderr If -X is on we redirect stderr + * shell_name The Name "SHELL", used to get the path to shell + */ +int +doshell(wchar_t *command, register Boolean ignore_error, Boolean redirect_out_err, char *stdout_file, char *stderr_file, int nice_prio) +{ + char *argv[6]; + int argv_index = 0; + int cmd_argv_index; + int length; + char nice_prio_buf[MAXPATHLEN]; + register Name shell = getvar(shell_name); + register char *shellname; + char *tmp_mbs_buffer; + + + if (IS_EQUAL(shell->string_mb, "")) { + shell = shell_name; + } + if ((shellname = strrchr(shell->string_mb, (int) slash_char)) == NULL) { + shellname = shell->string_mb; + } else { + shellname++; + } + + /* + * Only prepend the /usr/bin/nice command to the original command + * if the nice priority, nice_prio, is NOT zero (0). + * Nice priorities can be a positive or a negative number. + */ + if (nice_prio != 0) { + argv[argv_index++] = NOCATGETS("nice"); + (void) sprintf(nice_prio_buf, NOCATGETS("-%d"), nice_prio); + argv[argv_index++] = strdup(nice_prio_buf); + } + argv[argv_index++] = shellname; +#if defined(linux) + if(0 == strcmp(shell->string_mb, (char*)NOCATGETS("/bin/sh"))) { + argv[argv_index++] = (char*)(ignore_error ? NOCATGETS("-c") : NOCATGETS("-ce")); + } else { + argv[argv_index++] = (char*)NOCATGETS("-c"); + } +#else + argv[argv_index++] = (char*)(ignore_error ? NOCATGETS("-c") : NOCATGETS("-ce")); +#endif + if ((length = wslen(command)) >= MAXPATHLEN) { + tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); + (void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1); + cmd_argv_index = argv_index; + argv[argv_index++] = strdup(tmp_mbs_buffer); + retmem_mb(tmp_mbs_buffer); + } else { + WCSTOMBS(mbs_buffer, command); + cmd_argv_index = argv_index; +#if defined(linux) + int mbl = strlen(mbs_buffer); + if(mbl > 2) { + if(mbs_buffer[mbl-1] == '\n' && mbs_buffer[mbl-2] == '\\') { + mbs_buffer[mbl] = '\n'; + mbs_buffer[mbl+1] = 0; + } + } +#endif + argv[argv_index++] = strdup(mbs_buffer); + } + argv[argv_index] = NULL; + (void) fflush(stdout); + if ((childPid = fork()) == 0) { + enable_interrupt((void (*) (int)) SIG_DFL); + if (redirect_out_err) { + redirect_io(stdout_file, stderr_file); + } +#if 0 + if (filter_stderr) { + redirect_stderr(); + } +#endif + if (nice_prio != 0) { + (void) execve(NOCATGETS("/usr/bin/nice"), argv, environ); + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 92, "Could not load `/usr/bin/nice': %s"), + errmsg(errno)); + } else { + (void) execve(shell->string_mb, argv, environ); + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 93, "Could not load Shell from `%s': %s"), + shell->string_mb, + errmsg(errno)); + } + } + if (childPid == -1) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 94, "fork failed: %s"), + errmsg(errno)); + } + retmem_mb(argv[cmd_argv_index]); + return childPid; +} + +/* + * exec_vp(name, argv, envp, ignore_error) + * + * Like execve, but does path search. + * This starts command when make invokes it directly (without a shell). + * + * Return value: + * Returns false if the exec failed + * + * Parameters: + * name The name of the command to run + * argv Arguments for the command + * envp The environment for it + * ignore_error Should we abort on error? + * + * Global variables used: + * shell_name The Name "SHELL", used to get the path to shell + * vroot_path The path used by the vroot package + */ +static Boolean +exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path) +{ + register Name shell = getvar(shell_name); + register char *shellname; + char *shargv[4]; + Name tmp_shell; + + if (IS_EQUAL(shell->string_mb, "")) { + shell = shell_name; + } + + for (int i = 0; i < 5; i++) { + (void) execve_vroot(name, + argv + 1, + envp, + vroot_path, + VROOT_DEFAULT); + switch (errno) { + case ENOEXEC: + case ENOENT: + /* That failed. Let the shell handle it */ + shellname = strrchr(shell->string_mb, (int) slash_char); + if (shellname == NULL) { + shellname = shell->string_mb; + } else { + shellname++; + } + shargv[0] = shellname; + shargv[1] = (char*)(ignore_error ? NOCATGETS("-c") : NOCATGETS("-ce")); + shargv[2] = argv[0]; + shargv[3] = NULL; + tmp_shell = getvar(shell_name); + if (IS_EQUAL(tmp_shell->string_mb, "")) { + tmp_shell = shell_name; + } + (void) execve_vroot(tmp_shell->string_mb, + shargv, + envp, + vroot_path, + VROOT_DEFAULT); + return failed; + case ETXTBSY: + /* + * The program is busy (debugged?). + * Wait and then try again. + */ + (void) sleep((unsigned) i); + case EAGAIN: + break; + default: + return failed; + } + } + return failed; +} + +/* + * doexec(command, ignore_error) + * + * Will scan an argument string and split it into words + * thus building an argument list that can be passed to exec_ve() + * + * Return value: + * The pid of the process started here + * + * Parameters: + * command The command to run + * ignore_error Should we abort on error? + * + * Global variables used: + * filter_stderr If -X is on we redirect stderr + */ +int +doexec(register wchar_t *command, register Boolean ignore_error, Boolean redirect_out_err, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio) +{ + int arg_count = 5; + char **argv; + int length; + char nice_prio_buf[MAXPATHLEN]; + register char **p; + wchar_t *q; + register wchar_t *t; + char *tmp_mbs_buffer; + + /* + * Only prepend the /usr/bin/nice command to the original command + * if the nice priority, nice_prio, is NOT zero (0). + * Nice priorities can be a positive or a negative number. + */ + if (nice_prio != 0) { + arg_count += 2; + } + for (t = command; *t != (int) nul_char; t++) { + if (iswspace(*t)) { + arg_count++; + } + } + argv = (char **)alloca(arg_count * (sizeof(char *))); + /* + * Reserve argv[0] for sh in case of exec_vp failure. + * Don't worry about prepending /usr/bin/nice command to argv[0]. + * In fact, doing it may cause the sh command to fail! + */ + p = &argv[1]; + if ((length = wslen(command)) >= MAXPATHLEN) { + tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); + (void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1); + argv[0] = strdup(tmp_mbs_buffer); + retmem_mb(tmp_mbs_buffer); + } else { + WCSTOMBS(mbs_buffer, command); + argv[0] = strdup(mbs_buffer); + } + + if (nice_prio != 0) { + *p++ = strdup(NOCATGETS("/usr/bin/nice")); + (void) sprintf(nice_prio_buf, NOCATGETS("-%d"), nice_prio); + *p++ = strdup(nice_prio_buf); + } + /* Build list of argument words. */ + for (t = command; *t;) { + if (p >= &argv[arg_count]) { + /* This should never happen, right? */ + WCSTOMBS(mbs_buffer, command); + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 95, "Command `%s' has more than %d arguments"), + mbs_buffer, + arg_count); + } + q = t; + while (!iswspace(*t) && (*t != (int) nul_char)) { + t++; + } + if (*t) { + for (*t++ = (int) nul_char; iswspace(*t); t++); + } + if ((length = wslen(q)) >= MAXPATHLEN) { + tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); + (void) wcstombs(tmp_mbs_buffer, q, (length * MB_LEN_MAX) + 1); + *p++ = strdup(tmp_mbs_buffer); + retmem_mb(tmp_mbs_buffer); + } else { + WCSTOMBS(mbs_buffer, q); + *p++ = strdup(mbs_buffer); + } + } + *p = NULL; + + /* Then exec the command with that argument list. */ + (void) fflush(stdout); + if ((childPid = fork()) == 0) { + enable_interrupt((void (*) (int)) SIG_DFL); + if (redirect_out_err) { + redirect_io(stdout_file, stderr_file); + } +#if 0 + if (filter_stderr) { + redirect_stderr(); + } +#endif + (void) exec_vp(argv[1], argv, environ, ignore_error, vroot_path); + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 96, "Cannot load command `%s': %s"), argv[1], errmsg(errno)); + } + if (childPid == -1) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 97, "fork failed: %s"), + errmsg(errno)); + } + for (int i = 0; argv[i] != NULL; i++) { + retmem_mb(argv[i]); + } + return childPid; +} + +/* + * await(ignore_error, silent_error, target, command, running_pid) + * + * Wait for one child process and analyzes + * the returned status when the child process terminates. + * + * Return value: + * Returns true if commands ran OK + * + * Parameters: + * ignore_error Should we abort on error? + * silent_error Should error messages be suppressed for dmake? + * target The target we are building, for error msgs + * command The command we ran, for error msgs + * running_pid The pid of the process we are waiting for + * + * Static variables used: + * filter_file The fd for the filter file + * filter_file_name The name of the filter file + * + * Global variables used: + * filter_stderr Set if -X is on + */ +#if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */ +Boolean +await(register Boolean ignore_error, register Boolean silent_error, Name target, wchar_t *command, pid_t running_pid, Boolean send_mtool_msgs, XDR *xdrs_p, int job_msg_id) +#else +Boolean +await(register Boolean ignore_error, register Boolean silent_error, Name target, wchar_t *command, pid_t running_pid, Boolean send_mtool_msgs, void *xdrs_p, int job_msg_id) +#endif +{ +#ifdef SUN5_0 + int status; +#else +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat) stat.w_T.w_Retcode +#endif +#ifndef WTERMSIG +#define WTERMSIG(stat) stat.w_T.w_Termsig +#endif +#ifndef WCOREDUMP +#define WCOREDUMP(stat) stat.w_T.w_Coredump +#endif +#if defined (HP_UX) || defined (linux) + int status; +#else + union wait status; +#endif +#endif + char *buffer; + int core_dumped; + int exit_status; +#if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */ + Avo_CmdOutput *make_output_msg; +#endif + FILE *outfp; + register pid_t pid; + struct stat stat_buff; + int termination_signal; + char tmp_buf[MAXPATHLEN]; +#if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */ + RWCollectable *xdr_msg; +#endif + + while ((pid = wait(&status)) != running_pid) { + if (pid == -1) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 98, "wait() failed: %s"), errmsg(errno)); + } + } + (void) fflush(stdout); + (void) fflush(stderr); + +#if defined(SUN5_0) || defined(HP_UX) || defined(linux) + if (status == 0) { + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in await(), and status is 0.")); +#endif + + return succeeded; + } + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in await(), and status is *NOT* 0.")); +#endif + +#else + if (status.w_status == 0) { + return succeeded; + } +#endif + + exit_status = WEXITSTATUS(status); + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in await(), and exit_status is %d."), exit_status); +#endif + + termination_signal = WTERMSIG(status); + core_dumped = WCOREDUMP(status); + + /* + * If the child returned an error, we now try to print a + * nice message about it. + */ + SEND_MTOOL_MSG( + make_output_msg = new Avo_CmdOutput(); + (void) sprintf(tmp_buf, "%d", job_msg_id); + make_output_msg->appendOutput(AVO_STRDUP(tmp_buf)); + ); + + tmp_buf[0] = (int) nul_char; + if (!silent_error) { + if (exit_status != 0) { + (void) fprintf(stdout, + catgets(libmksdmsi18n_catd, 1, 103, "*** Error code %d"), + exit_status); + SEND_MTOOL_MSG( + (void) sprintf(&tmp_buf[strlen(tmp_buf)], + catgets(libmksdmsi18n_catd, 1, 104, "*** Error code %d"), + exit_status); + ); + } else { +#if ! defined(SUN5_0) && ! defined(HP_UX) && ! defined(linux) + if (termination_signal > NSIG) { +#endif + (void) fprintf(stdout, + catgets(libmksdmsi18n_catd, 1, 105, "*** Signal %d"), + termination_signal); + SEND_MTOOL_MSG( + (void) sprintf(&tmp_buf[strlen(tmp_buf)], + catgets(libmksdmsi18n_catd, 1, 106, "*** Signal %d"), + termination_signal); + ); +#if ! defined(SUN5_0) && ! defined(HP_UX) && ! defined(linux) + } else { + (void) fprintf(stdout, + "*** %s", + sys_siglist[termination_signal]); + SEND_MTOOL_MSG( + (void) sprintf(&tmp_buf[strlen(tmp_buf)], + "*** %s", + sys_siglist[termination_signal]); + ); + } +#endif + if (core_dumped) { + (void) fprintf(stdout, + catgets(libmksdmsi18n_catd, 1, 107, " - core dumped")); + SEND_MTOOL_MSG( + (void) sprintf(&tmp_buf[strlen(tmp_buf)], + catgets(libmksdmsi18n_catd, 1, 108, " - core dumped")); + ); + } + } + if (ignore_error) { + (void) fprintf(stdout, + catgets(libmksdmsi18n_catd, 1, 109, " (ignored)")); + SEND_MTOOL_MSG( + (void) sprintf(&tmp_buf[strlen(tmp_buf)], + catgets(libmksdmsi18n_catd, 1, 110, " (ignored)")); + ); + } + (void) fprintf(stdout, "\n"); + (void) fflush(stdout); + SEND_MTOOL_MSG( + make_output_msg->appendOutput(AVO_STRDUP(tmp_buf)); + ); + } + SEND_MTOOL_MSG( + xdr_msg = (RWCollectable*) make_output_msg; + xdr(xdrs_p, xdr_msg); + delete make_output_msg; + ); + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in await(), returning failed.")); +#endif + + return failed; +} + +/* + * sh_command2string(command, destination) + * + * Run one sh command and capture the output from it. + * + * Return value: + * + * Parameters: + * command The command to run + * destination Where to deposit the output from the command + * + * Static variables used: + * + * Global variables used: + */ +void +sh_command2string(register String command, register String destination) +{ + register FILE *fd; + register int chr; + int status; + Boolean command_generated_output = false; + + command->text.p = (int) nul_char; + WCSTOMBS(mbs_buffer, command->buffer.start); + if ((fd = popen(mbs_buffer, "r")) == NULL) { + WCSTOMBS(mbs_buffer, command->buffer.start); + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 111, "Could not run command `%s' for :sh transformation"), + mbs_buffer); + } + while ((chr = getc(fd)) != EOF) { + if (chr == (int) newline_char) { + chr = (int) space_char; + } + command_generated_output = true; + append_char(chr, destination); + } + + /* + * We don't want to keep the last LINE_FEED since usually + * the output of the 'sh:' command is used to evaluate + * some MACRO. ( /bin/sh and other shell add a line feed + * to the output so that the prompt appear in the right place. + * We don't need that + */ + if (command_generated_output){ + if ( *(destination->text.p-1) == (int) space_char) { + * (-- destination->text.p) = '\0'; + } + } else { + /* + * If the command didn't generate any output, + * set the buffer to a null string. + */ + *(destination->text.p) = '\0'; + } + + status = pclose(fd); + if (status != 0) { + WCSTOMBS(mbs_buffer, command->buffer.start); + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 112, "The command `%s' returned status `%d'"), + mbs_buffer, + WEXITSTATUS(status)); + } +} + + diff --git a/usr/src/make_src/Make/lib/mksh/src/globals.cc b/usr/src/make_src/Make/lib/mksh/src/globals.cc new file mode 100644 index 0000000..2d36d24 --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/globals.cc @@ -0,0 +1,140 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)globals.cc 1.16 06/12/12 + */ + +#pragma ident "@(#)globals.cc 1.16 06/12/12" + +/* + * globals.cc + * + * This declares all global variables + */ + +/* + * Included files + */ +#include <mksh/globals.h> + +/* + * Defined macros + */ + +/* + * typedefs & structs + */ + +/* + * Global variables + */ +char char_semantics[CHAR_SEMANTICS_ENTRIES]; +wchar_t char_semantics_char[] = { + ampersand_char, + asterisk_char, + at_char, + backquote_char, + backslash_char, + bar_char, + bracketleft_char, + bracketright_char, + colon_char, + dollar_char, + doublequote_char, + equal_char, + exclam_char, + greater_char, + hat_char, + hyphen_char, + less_char, + newline_char, + numbersign_char, + parenleft_char, + parenright_char, + percent_char, + plus_char, + question_char, + quote_char, + semicolon_char, +#ifdef SGE_SUPPORT + space_char, + tab_char, +#endif + nul_char +}; +Macro_list cond_macro_list; +Boolean conditional_macro_used; +Boolean do_not_exec_rule; /* `-n' */ +Boolean dollarget_seen; +Boolean dollarless_flag; +Name dollarless_value; +Envvar envvar; +#ifdef lint +char **environ; +#endif +#ifdef SUN5_0 +int exit_status; +#endif +wchar_t *file_being_read; +/* Variable gnu_style=true if env. var. SUN_MAKE_COMPAT_MODE=GNU (RFE 4866328) */ +Boolean gnu_style = false; +Name_set hashtab; +Name host_arch; +Name host_mach; +int line_number; +char *make_state_lockfile; +Boolean make_word_mentioned; +Makefile_type makefile_type = reading_nothing; +char mbs_buffer[(MAXPATHLEN * MB_LEN_MAX)]; +Name path_name; +Boolean posix = true; +Name hat; +Name query; +Boolean query_mentioned; +Boolean reading_environment; +Name shell_name; +Boolean svr4 = false; +Name target_arch; +Name target_mach; +Boolean tilde_rule; +Name virtual_root; +Boolean vpath_defined; +Name vpath_name; +wchar_t wcs_buffer[MAXPATHLEN]; +Boolean working_on_targets; +#if defined (TEAMWARE_MAKE_CMN) && defined(REDIRECT_ERR) +Boolean out_err_same; +#endif +pid_t childPid = -1; // This variable is used for killing child's process + // Such as qrsh, running command, etc. + +/* + * timestamps defined in defs.h + */ +const timestruc_t file_no_time = { -1, 0 }; +const timestruc_t file_doesnt_exist = { 0, 0 }; +const timestruc_t file_is_dir = { 1, 0 }; +const timestruc_t file_min_time = { 2, 0 }; +const timestruc_t file_max_time = { INT_MAX, 0 }; diff --git a/usr/src/make_src/Make/lib/mksh/src/i18n.cc b/usr/src/make_src/Make/lib/mksh/src/i18n.cc new file mode 100644 index 0000000..f12341e --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/i18n.cc @@ -0,0 +1,100 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)i18n.cc 1.3 06/12/12 + */ + +#pragma ident "@(#)i18n.cc 1.3 06/12/12" + +/* + * i18n.cc + * + * Deal with internationalization conversions + */ + +/* + * Included files + */ +#include <mksh/i18n.h> +#include <mksh/misc.h> /* setup_char_semantics() */ +#if defined (linux) +# include <wctype.h> +# include <wchar.h> +# define wschr(x,y) wcschr(x,y) +#endif + +/* + * get_char_semantics_value(ch) + * + * Return value: + * The character semantics of ch. + * + * Parameters: + * ch character we want semantics for. + * + */ +char +get_char_semantics_value(wchar_t ch) +{ + static Boolean char_semantics_setup; + + if (!char_semantics_setup) { + setup_char_semantics(); + char_semantics_setup = true; + } + return char_semantics[get_char_semantics_entry(ch)]; +} + +/* + * get_char_semantics_entry(ch) + * + * Return value: + * The slot number in the array for special make chars, + * else the slot number of the last array entry. + * + * Parameters: + * ch The wide character + * + * Global variables used: + * char_semantics_char[] array of special wchar_t chars + * "&*@`\\|[]:$=!>-\n#()%?;^<'\"" + */ +int +get_char_semantics_entry(wchar_t ch) +{ + wchar_t *char_sem_char; + + char_sem_char = (wchar_t *) wschr(char_semantics_char, ch); + if (char_sem_char == NULL) { + /* + * Return the integer entry for the last slot, + * whose content is empty. + */ + return (CHAR_SEMANTICS_ENTRIES - 1); + } else { + return (char_sem_char - char_semantics_char); + } +} + diff --git a/usr/src/make_src/Make/lib/mksh/src/libmksh.msg b/usr/src/make_src/Make/lib/mksh/src/libmksh.msg new file mode 100644 index 0000000..d1994aa --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/libmksh.msg @@ -0,0 +1,81 @@ + +$quote " + + +$set 1 +$ +$ CDDL HEADER START +$ +$ The contents of this file are subject to the terms of the +$ Common Development and Distribution License (the "License"). +$ You may not use this file except in compliance with the License. +$ +$ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +$ or http://www.opensolaris.org/os/licensing. +$ See the License for the specific language governing permissions +$ and limitations under the License. +$ +$ When distributing Covered Code, include this CDDL HEADER in each +$ file and include the License file at usr/src/OPENSOLARIS.LICENSE. +$ If applicable, add the following below this CDDL HEADER, with the +$ fields enclosed by brackets "[]" replaced with your own identifying +$ information: Portions Copyright [yyyy] [name of copyright owner] +$ +$ CDDL HEADER END +$ +$ Copyright 1996 Sun Microsystems, Inc. All rights reserved. +$ Use is subject to license terms. +$ +$ @(#)libmksh.msg 1.2 06/12/12 +$ +89 "ulimit() failed: %s" +90 "Couldn't open standard out temp file `%s': %s" +91 "Couldn't open standard error temp file `%s': %s" +92 "Could not load `/usr/bin/nice': %s" +93 "Could not load Shell from `%s': %s" +94 "fork failed: %s" +95 "Command `%s' has more than %d arguments" +96 "Cannot load command `%s': %s" +97 "fork failed: %s" +98 "wait() failed: %s" +99 "Could not open filter file for -X" +100 "Could not stat filter file for -X" +101 "\n**** Error: Directory %s Target %s:\n%s\n" +102 "**** Error: Directory %s Target %s\n" +103 "*** Error code %d" +104 "*** Error code %d" +105 "*** Signal %d" +106 "*** Signal %d" +107 " - core dumped" +108 " - core dumped" +109 " (ignored)" +110 " (ignored)" +111 "Could not run command `%s' for :sh transformation" +112 "The command `%s' returned status `%d'" +113 "Loop detected when expanding macro value `%s'" +114 "'$' at end of string `%s'" +115 "'$' at end of line" +116 "Unmatched `%c' in string `%s'" +117 "Premature EOF" +118 "Unmatched `%c' on line" +119 "Illegal macro reference `%s'" +120 "= missing from replacement macro reference" +121 "= missing from replacement macro reference" +122 "%% missing from replacement macro reference" +123 "%% missing from replacement macro reference" +124 "Too many %% in pattern" +125 "Conditional macro `%s' referenced on line %d" +126 "Out of memory" +127 "Error %d" +128 "mksh: Fatal error: " +129 "Current working directory %s\n" +131 "mksh: Fatal error in reader: " +133 "Current working directory %s\n" +134 "mksh: Warning: " +135 "Current working directory %s\n" +136 "Internal error. Unknown prop type %d" +137 "`cd %s' failed, and conversion of %s to automounter pathname also failed" +138 "`cd %s' and `cd %s' both failed" +139 "The following command caused the error:\n%s\n" +140 "Error reading `%s': Premature EOF" +141 "Error reading `%s': %s" diff --git a/usr/src/make_src/Make/lib/mksh/src/macro.cc b/usr/src/make_src/Make/lib/mksh/src/macro.cc new file mode 100644 index 0000000..43d7603 --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/macro.cc @@ -0,0 +1,1414 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)macro.cc 1.22 06/12/12 + */ + +#pragma ident "@(#)macro.cc 1.22 06/12/12" + +/* + * macro.cc + * + * Handle expansion of make macros + */ + +/* + * Included files + */ +#include <mksh/dosys.h> /* sh_command2string() */ +#include <mksh/i18n.h> /* get_char_semantics_value() */ +#include <mksh/macro.h> +#include <mksh/misc.h> /* retmem() */ +#include <mksh/read.h> /* get_next_block_fn() */ +#include <mksdmsi18n/mksdmsi18n.h> /* libmksdmsi18n_init() */ + +/* + * File table of contents + */ +static void add_macro_to_global_list(Name macro_to_add); +#ifdef NSE +static void expand_value_with_daemon(Name name, register Property macro, register String destination, Boolean cmd); +#else +static void expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd); +#endif + +static void init_arch_macros(void); +static void init_mach_macros(void); +static Boolean init_arch_done = false; +static Boolean init_mach_done = false; + + +long env_alloc_num = 0; +long env_alloc_bytes = 0; + +/* + * getvar(name) + * + * Return expanded value of macro. + * + * Return value: + * The expanded value of the macro + * + * Parameters: + * name The name of the macro we want the value for + * + * Global variables used: + */ +Name +getvar(register Name name) +{ + String_rec destination; + wchar_t buffer[STRING_BUFFER_LENGTH]; + register Name result; + + if ((name == host_arch) || (name == target_arch)) { + if (!init_arch_done) { + init_arch_done = true; + init_arch_macros(); + } + } + if ((name == host_mach) || (name == target_mach)) { + if (!init_mach_done) { + init_mach_done = true; + init_mach_macros(); + } + } + + INIT_STRING_FROM_STACK(destination, buffer); + expand_value(maybe_append_prop(name, macro_prop)->body.macro.value, + &destination, + false); + result = GETNAME(destination.buffer.start, FIND_LENGTH); + if (destination.free_after_use) { + retmem(destination.buffer.start); + } + return result; +} + +/* + * expand_value(value, destination, cmd) + * + * Recursively expands all macros in the string value. + * destination is where the expanded value should be appended. + * + * Parameters: + * value The value we are expanding + * destination Where to deposit the expansion + * cmd If we are evaluating a command line we + * turn \ quoting off + * + * Global variables used: + */ +void +expand_value(Name value, register String destination, Boolean cmd) +{ + Source_rec sourceb; + register Source source = &sourceb; + register wchar_t *source_p = NULL; + register wchar_t *source_end = NULL; + wchar_t *block_start = NULL; + int quote_seen = 0; + + if (value == NULL) { + /* + * Make sure to get a string allocated even if it + * will be empty. + */ + MBSTOWCS(wcs_buffer, ""); + append_string(wcs_buffer, destination, FIND_LENGTH); + destination->text.end = destination->text.p; + return; + } + if (!value->dollar) { + /* + * If the value we are expanding does not contain + * any $, we don't have to parse it. + */ + APPEND_NAME(value, + destination, + (int) value->hash.length + ); + destination->text.end = destination->text.p; + return; + } + + if (value->being_expanded) { + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 113, "Loop detected when expanding macro value `%s'"), + value->string_mb); + } + value->being_expanded = true; + /* Setup the structure we read from */ + Wstring vals(value); + sourceb.string.text.p = sourceb.string.buffer.start = wsdup(vals.get_string()); + sourceb.string.free_after_use = true; + sourceb.string.text.end = + sourceb.string.buffer.end = + sourceb.string.text.p + value->hash.length; + sourceb.previous = NULL; + sourceb.fd = -1; + sourceb.inp_buf = + sourceb.inp_buf_ptr = + sourceb.inp_buf_end = NULL; + sourceb.error_converting = false; + /* Lift some pointers from the struct to local register variables */ + CACHE_SOURCE(0); +/* We parse the string in segments */ +/* We read chars until we find a $, then we append what we have read so far */ +/* (since last $ processing) to the destination. When we find a $ we call */ +/* expand_macro() and let it expand that particular $ reference into dest */ + block_start = source_p; + quote_seen = 0; + for (; 1; source_p++) { + switch (GET_CHAR()) { + case backslash_char: + /* Quote $ in macro value */ + if (!cmd) { + quote_seen = ~quote_seen; + } + continue; + case dollar_char: + /* Save the plain string we found since */ + /* start of string or previous $ */ + if (quote_seen) { + append_string(block_start, + destination, + source_p - block_start - 1); + block_start = source_p; + break; + } + append_string(block_start, + destination, + source_p - block_start); + source->string.text.p = ++source_p; + UNCACHE_SOURCE(); + /* Go expand the macro reference */ + expand_macro(source, destination, sourceb.string.buffer.start, cmd); + CACHE_SOURCE(1); + block_start = source_p + 1; + break; + case nul_char: + /* The string ran out. Get some more */ + append_string(block_start, + destination, + source_p - block_start); + GET_NEXT_BLOCK_NOCHK(source); + if (source == NULL) { + destination->text.end = destination->text.p; + value->being_expanded = false; + return; + } + if (source->error_converting) { + fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_value()")); + } + block_start = source_p; + source_p--; + continue; + } + quote_seen = 0; + } + retmem(sourceb.string.buffer.start); +} + +/* + * expand_macro(source, destination, current_string, cmd) + * + * Should be called with source->string.text.p pointing to + * the first char after the $ that starts a macro reference. + * source->string.text.p is returned pointing to the first char after + * the macro name. + * It will read the macro name, expanding any macros in it, + * and get the value. The value is then expanded. + * destination is a String that is filled in with the expanded macro. + * It may be passed in referencing a buffer to expand the macro into. + * Note that most expansions are done on demand, e.g. right + * before the command is executed and not while the file is + * being parsed. + * + * Parameters: + * source The source block that references the string + * to expand + * destination Where to put the result + * current_string The string we are expanding, for error msg + * cmd If we are evaluating a command line we + * turn \ quoting off + * + * Global variables used: + * funny Vector of semantic tags for characters + * is_conditional Set if a conditional macro is refd + * make_word_mentioned Set if the word "MAKE" is mentioned + * makefile_type We deliver extra msg when reading makefiles + * query The Name "?", compared against + * query_mentioned Set if the word "?" is mentioned + */ +void +expand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd) +{ + static Name make = (Name)NULL; + static wchar_t colon_sh[4]; + static wchar_t colon_shell[7]; + String_rec string; + wchar_t buffer[STRING_BUFFER_LENGTH]; + register wchar_t *source_p = source->string.text.p; + register wchar_t *source_end = source->string.text.end; + register int closer = 0; + wchar_t *block_start = (wchar_t *)NULL; + int quote_seen = 0; + register int closer_level = 1; + Name name = (Name)NULL; + wchar_t *colon = (wchar_t *)NULL; + wchar_t *percent = (wchar_t *)NULL; + wchar_t *eq = (wchar_t *) NULL; + Property macro = NULL; + wchar_t *p = (wchar_t*)NULL; + String_rec extracted; + wchar_t extracted_string[MAXPATHLEN]; + wchar_t *left_head = NULL; + wchar_t *left_tail = NULL; + wchar_t *right_tail = NULL; + int left_head_len = 0; + int left_tail_len = 0; + int tmp_len = 0; + wchar_t *right_hand[128]; + int i = 0; + enum { + no_extract, + dir_extract, + file_extract + } extraction = no_extract; + enum { + no_replace, + suffix_replace, + pattern_replace, + sh_replace + } replacement = no_replace; + + if (make == NULL) { + MBSTOWCS(wcs_buffer, NOCATGETS("MAKE")); + make = GETNAME(wcs_buffer, FIND_LENGTH); + + MBSTOWCS(colon_sh, NOCATGETS(":sh")); + MBSTOWCS(colon_shell, NOCATGETS(":shell")); + } + + right_hand[0] = NULL; + + /* First copy the (macro-expanded) macro name into string. */ + INIT_STRING_FROM_STACK(string, buffer); +recheck_first_char: + /* Check the first char of the macro name to figure out what to do. */ + switch (GET_CHAR()) { + case nul_char: + GET_NEXT_BLOCK_NOCHK(source); + if (source == NULL) { + WCSTOMBS(mbs_buffer, current_string); + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 114, "'$' at end of string `%s'"), + mbs_buffer); + } + if (source->error_converting) { + fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_macro()")); + } + goto recheck_first_char; + case parenleft_char: + /* Multi char name. */ + closer = (int) parenright_char; + break; + case braceleft_char: + /* Multi char name. */ + closer = (int) braceright_char; + break; + case newline_char: + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 115, "'$' at end of line")); + default: + /* Single char macro name. Just suck it up */ + append_char(*source_p, &string); + source->string.text.p = source_p + 1; + goto get_macro_value; + } + + /* Handle multi-char macro names */ + block_start = ++source_p; + quote_seen = 0; + for (; 1; source_p++) { + switch (GET_CHAR()) { + case nul_char: + append_string(block_start, + &string, + source_p - block_start); + GET_NEXT_BLOCK_NOCHK(source); + if (source == NULL) { + if (current_string != NULL) { + WCSTOMBS(mbs_buffer, current_string); + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 116, "Unmatched `%c' in string `%s'"), + closer == + (int) braceright_char ? + (int) braceleft_char : + (int) parenleft_char, + mbs_buffer); + } else { + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 117, "Premature EOF")); + } + } + if (source->error_converting) { + fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_macro()")); + } + block_start = source_p; + source_p--; + continue; + case newline_char: + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 118, "Unmatched `%c' on line"), + closer == (int) braceright_char ? + (int) braceleft_char : + (int) parenleft_char); + case backslash_char: + /* Quote dollar in macro value. */ + if (!cmd) { + quote_seen = ~quote_seen; + } + continue; + case dollar_char: + /* + * Macro names may reference macros. + * This expands the value of such macros into the + * macro name string. + */ + if (quote_seen) { + append_string(block_start, + &string, + source_p - block_start - 1); + block_start = source_p; + break; + } + append_string(block_start, + &string, + source_p - block_start); + source->string.text.p = ++source_p; + UNCACHE_SOURCE(); + expand_macro(source, &string, current_string, cmd); + CACHE_SOURCE(0); + block_start = source_p; + source_p--; + break; + case parenleft_char: + /* Allow nested pairs of () in the macro name. */ + if (closer == (int) parenright_char) { + closer_level++; + } + break; + case braceleft_char: + /* Allow nested pairs of {} in the macro name. */ + if (closer == (int) braceright_char) { + closer_level++; + } + break; + case parenright_char: + case braceright_char: + /* + * End of the name. Save the string in the macro + * name string. + */ + if ((*source_p == closer) && (--closer_level <= 0)) { + source->string.text.p = source_p + 1; + append_string(block_start, + &string, + source_p - block_start); + goto get_macro_value; + } + break; + } + quote_seen = 0; + } + /* + * We got the macro name. We now inspect it to see if it + * specifies any translations of the value. + */ +get_macro_value: + name = NULL; + /* First check if we have a $(@D) type translation. */ + if ((get_char_semantics_value(string.buffer.start[0]) & + (int) special_macro_sem) && + (string.text.p - string.buffer.start >= 2) && + ((string.buffer.start[1] == 'D') || + (string.buffer.start[1] == 'F'))) { + switch (string.buffer.start[1]) { + case 'D': + extraction = dir_extract; + break; + case 'F': + extraction = file_extract; + break; + default: + WCSTOMBS(mbs_buffer, string.buffer.start); + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 119, "Illegal macro reference `%s'"), + mbs_buffer); + } + /* Internalize the macro name using the first char only. */ + name = GETNAME(string.buffer.start, 1); + (void) wscpy(string.buffer.start, string.buffer.start + 2); + } + /* Check for other kinds of translations. */ + if ((colon = (wchar_t *) wschr(string.buffer.start, + (int) colon_char)) != NULL) { + /* + * We have a $(FOO:.c=.o) type translation. + * Get the name of the macro proper. + */ + if (name == NULL) { + name = GETNAME(string.buffer.start, + colon - string.buffer.start); + } + /* Pickup all the translations. */ + if (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell)) { + replacement = sh_replace; + } else if ((svr4) || + ((percent = (wchar_t *) wschr(colon + 1, + (int) percent_char)) == NULL)) { + while (colon != NULL) { + if ((eq = (wchar_t *) wschr(colon + 1, + (int) equal_char)) == NULL) { + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 120, "= missing from replacement macro reference")); + } + left_tail_len = eq - colon - 1; + if(left_tail) { + retmem(left_tail); + } + left_tail = ALLOC_WC(left_tail_len + 1); + (void) wsncpy(left_tail, + colon + 1, + eq - colon - 1); + left_tail[eq - colon - 1] = (int) nul_char; + replacement = suffix_replace; + if ((colon = (wchar_t *) wschr(eq + 1, + (int) colon_char)) != NULL) { + tmp_len = colon - eq; + if(right_tail) { + retmem(right_tail); + } + right_tail = ALLOC_WC(tmp_len); + (void) wsncpy(right_tail, + eq + 1, + colon - eq - 1); + right_tail[colon - eq - 1] = + (int) nul_char; + } else { + if(right_tail) { + retmem(right_tail); + } + right_tail = ALLOC_WC(wslen(eq) + 1); + (void) wscpy(right_tail, eq + 1); + } + } + } else { + if ((eq = (wchar_t *) wschr(colon + 1, + (int) equal_char)) == NULL) { + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 121, "= missing from replacement macro reference")); + } + if ((percent = (wchar_t *) wschr(colon + 1, + (int) percent_char)) == NULL) { + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 122, "%% missing from replacement macro reference")); + } + if (eq < percent) { + fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 123, "%% missing from replacement macro reference")); + } + + if (percent > (colon + 1)) { + tmp_len = percent - colon; + if(left_head) { + retmem(left_head); + } + left_head = ALLOC_WC(tmp_len); + (void) wsncpy(left_head, + colon + 1, + percent - colon - 1); + left_head[percent-colon-1] = (int) nul_char; + left_head_len = percent-colon-1; + } else { + left_head = NULL; + left_head_len = 0; + } + + if (eq > percent+1) { + tmp_len = eq - percent; + if(left_tail) { + retmem(left_tail); + } + left_tail = ALLOC_WC(tmp_len); + (void) wsncpy(left_tail, + percent + 1, + eq - percent - 1); + left_tail[eq-percent-1] = (int) nul_char; + left_tail_len = eq-percent-1; + } else { + left_tail = NULL; + left_tail_len = 0; + } + + if ((percent = (wchar_t *) wschr(++eq, + (int) percent_char)) == NULL) { + + right_hand[0] = ALLOC_WC(wslen(eq) + 1); + right_hand[1] = NULL; + (void) wscpy(right_hand[0], eq); + } else { + i = 0; + do { + right_hand[i] = ALLOC_WC(percent-eq+1); + (void) wsncpy(right_hand[i], + eq, + percent - eq); + right_hand[i][percent-eq] = + (int) nul_char; + if (i++ >= VSIZEOF(right_hand)) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 124, "Too many %% in pattern")); + } + eq = percent + 1; + if (eq[0] == (int) nul_char) { + MBSTOWCS(wcs_buffer, ""); + right_hand[i] = (wchar_t *) wsdup(wcs_buffer); + i++; + break; + } + } while ((percent = (wchar_t *) wschr(eq, (int) percent_char)) != NULL); + if (eq[0] != (int) nul_char) { + right_hand[i] = ALLOC_WC(wslen(eq) + 1); + (void) wscpy(right_hand[i], eq); + i++; + } + right_hand[i] = NULL; + } + replacement = pattern_replace; + } + } + if (name == NULL) { + /* + * No translations found. + * Use the whole string as the macro name. + */ + name = GETNAME(string.buffer.start, + string.text.p - string.buffer.start); + } + if (string.free_after_use) { + retmem(string.buffer.start); + } + if (name == make) { + make_word_mentioned = true; + } + if (name == query) { + query_mentioned = true; + } + if ((name == host_arch) || (name == target_arch)) { + if (!init_arch_done) { + init_arch_done = true; + init_arch_macros(); + } + } + if ((name == host_mach) || (name == target_mach)) { + if (!init_mach_done) { + init_mach_done = true; + init_mach_macros(); + } + } + /* Get the macro value. */ + macro = get_prop(name->prop, macro_prop); +#ifdef NSE + if (nse_watch_vars && nse && macro != NULL) { + if (macro->body.macro.imported) { + nse_shell_var_used= name; + } + if (macro->body.macro.value != NULL){ + if (nse_backquotes(macro->body.macro.value->string)) { + nse_backquote_seen= name; + } + } + } +#endif + if ((macro != NULL) && macro->body.macro.is_conditional) { + conditional_macro_used = true; + /* + * Add this conditional macro to the beginning of the + * global list. + */ + add_macro_to_global_list(name); + if (makefile_type == reading_makefile) { + warning_mksh(catgets(libmksdmsi18n_catd, 1, 164, "Conditional macro `%s' referenced in file `%ws', line %d"), + name->string_mb, file_being_read, line_number); + } + } + /* Macro name read and parsed. Expand the value. */ + if ((macro == NULL) || (macro->body.macro.value == NULL)) { + /* If the value is empty, we just get out of here. */ + goto exit; + } + if (replacement == sh_replace) { + /* If we should do a :sh transform, we expand the command + * and process it. + */ + INIT_STRING_FROM_STACK(string, buffer); + /* Expand the value into a local string buffer and run cmd. */ + expand_value_with_daemon(name, macro, &string, cmd); + sh_command2string(&string, destination); + } else if ((replacement != no_replace) || (extraction != no_extract)) { + /* + * If there were any transforms specified in the macro + * name, we deal with them here. + */ + INIT_STRING_FROM_STACK(string, buffer); + /* Expand the value into a local string buffer. */ + expand_value_with_daemon(name, macro, &string, cmd); + /* Scan the expanded string. */ + p = string.buffer.start; + while (*p != (int) nul_char) { + wchar_t chr; + + /* + * First skip over any white space and append + * that to the destination string. + */ + block_start = p; + while ((*p != (int) nul_char) && iswspace(*p)) { + p++; + } + append_string(block_start, + destination, + p - block_start); + /* Then find the end of the next word. */ + block_start = p; + while ((*p != (int) nul_char) && !iswspace(*p)) { + p++; + } + /* If we cant find another word we are done */ + if (block_start == p) { + break; + } + /* Then apply the transforms to the word */ + INIT_STRING_FROM_STACK(extracted, extracted_string); + switch (extraction) { + case dir_extract: + /* + * $(@D) type transform. Extract the + * path from the word. Deliver "." if + * none is found. + */ + if (p != NULL) { + chr = *p; + *p = (int) nul_char; + } + eq = (wchar_t *) wsrchr(block_start, (int) slash_char); + if (p != NULL) { + *p = chr; + } + if ((eq == NULL) || (eq > p)) { + MBSTOWCS(wcs_buffer, "."); + append_string(wcs_buffer, &extracted, 1); + } else { + append_string(block_start, + &extracted, + eq - block_start); + } + break; + case file_extract: + /* + * $(@F) type transform. Remove the path + * from the word if any. + */ + if (p != NULL) { + chr = *p; + *p = (int) nul_char; + } + eq = (wchar_t *) wsrchr(block_start, (int) slash_char); + if (p != NULL) { + *p = chr; + } + if ((eq == NULL) || (eq > p)) { + append_string(block_start, + &extracted, + p - block_start); + } else { + append_string(eq + 1, + &extracted, + p - eq - 1); + } + break; + case no_extract: + append_string(block_start, + &extracted, + p - block_start); + break; + } + switch (replacement) { + case suffix_replace: + /* + * $(FOO:.o=.c) type transform. + * Maybe replace the tail of the word. + */ + if (((extracted.text.p - + extracted.buffer.start) >= + left_tail_len) && + IS_WEQUALN(extracted.text.p - left_tail_len, + left_tail, + left_tail_len)) { + append_string(extracted.buffer.start, + destination, + (extracted.text.p - + extracted.buffer.start) + - left_tail_len); + append_string(right_tail, + destination, + FIND_LENGTH); + } else { + append_string(extracted.buffer.start, + destination, + FIND_LENGTH); + } + break; + case pattern_replace: + /* $(X:a%b=c%d) type transform. */ + if (((extracted.text.p - + extracted.buffer.start) >= + left_head_len+left_tail_len) && + IS_WEQUALN(left_head, + extracted.buffer.start, + left_head_len) && + IS_WEQUALN(left_tail, + extracted.text.p - left_tail_len, + left_tail_len)) { + i = 0; + while (right_hand[i] != NULL) { + append_string(right_hand[i], + destination, + FIND_LENGTH); + i++; + if (right_hand[i] != NULL) { + append_string(extracted.buffer. + start + + left_head_len, + destination, + (extracted.text.p - extracted.buffer.start)-left_head_len-left_tail_len); + } + } + } else { + append_string(extracted.buffer.start, + destination, + FIND_LENGTH); + } + break; + case no_replace: + append_string(extracted.buffer.start, + destination, + FIND_LENGTH); + break; + case sh_replace: + break; + } + } + if (string.free_after_use) { + retmem(string.buffer.start); + } + } else { + /* + * This is for the case when the macro name did not + * specify transforms. + */ + if (!strncmp(name->string_mb, NOCATGETS("GET"), 3)) { + dollarget_seen = true; + } + dollarless_flag = false; + if (!strncmp(name->string_mb, "<", 1) && + dollarget_seen) { + dollarless_flag = true; + dollarget_seen = false; + } + expand_value_with_daemon(name, macro, destination, cmd); + } +exit: + if(left_tail) { + retmem(left_tail); + } + if(right_tail) { + retmem(right_tail); + } + if(left_head) { + retmem(left_head); + } + i = 0; + while (right_hand[i] != NULL) { + retmem(right_hand[i]); + i++; + } + *destination->text.p = (int) nul_char; + destination->text.end = destination->text.p; +} + +static void +add_macro_to_global_list(Name macro_to_add) +{ + Macro_list new_macro; + Macro_list macro_on_list; + char *name_on_list = (char*)NULL; + char *name_to_add = macro_to_add->string_mb; + char *value_on_list = (char*)NULL; + char *value_to_add = (char*)NULL; + + if (macro_to_add->prop->body.macro.value != NULL) { + value_to_add = macro_to_add->prop->body.macro.value->string_mb; + } else { + value_to_add = ""; + } + + /* + * Check if this macro is already on list, if so, do nothing + */ + for (macro_on_list = cond_macro_list; + macro_on_list != NULL; + macro_on_list = macro_on_list->next) { + + name_on_list = macro_on_list->macro_name; + value_on_list = macro_on_list->value; + + if (IS_EQUAL(name_on_list, name_to_add)) { + if (IS_EQUAL(value_on_list, value_to_add)) { + return; + } + } + } + new_macro = (Macro_list) malloc(sizeof(Macro_list_rec)); + new_macro->macro_name = strdup(name_to_add); + new_macro->value = strdup(value_to_add); + new_macro->next = cond_macro_list; + cond_macro_list = new_macro; +} + +/* + * init_arch_macros(void) + * + * Set the magic macros TARGET_ARCH, HOST_ARCH, + * + * Parameters: + * + * Global variables used: + * host_arch Property for magic macro HOST_ARCH + * target_arch Property for magic macro TARGET_ARCH + * + * Return value: + * The function does not return a value, but can + * call fatal() in case of error. + */ +static void +init_arch_macros(void) +{ + String_rec result_string; + wchar_t wc_buf[STRING_BUFFER_LENGTH]; + char mb_buf[STRING_BUFFER_LENGTH]; + FILE *pipe; + Name value; + int set_host, set_target; +#ifdef NSE + Property macro; +#endif +#if defined(linux) + const char *mach_command = NOCATGETS("/bin/uname -p"); +#else + const char *mach_command = NOCATGETS("/bin/mach"); +#endif + + set_host = (get_prop(host_arch->prop, macro_prop) == NULL); + set_target = (get_prop(target_arch->prop, macro_prop) == NULL); + + if (set_host || set_target) { + INIT_STRING_FROM_STACK(result_string, wc_buf); + append_char((int) hyphen_char, &result_string); + + if ((pipe = popen(mach_command, "r")) == NULL) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 185, "Execute of %s failed"), mach_command); + } + while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) { + MBSTOWCS(wcs_buffer, mb_buf); + append_string(wcs_buffer, &result_string, wslen(wcs_buffer)); + } + if (pclose(pipe) != 0) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 186, "Execute of %s failed"), mach_command); + } + + value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start)); + +#ifdef NSE + macro = setvar_daemon(host_arch, value, false, no_daemon, true, 0); + macro->body.macro.imported= true; + macro = setvar_daemon(target_arch, value, false, no_daemon, true, 0); + macro->body.macro.imported= true; +#else + if (set_host) { + (void) setvar_daemon(host_arch, value, false, no_daemon, true, 0); + } + if (set_target) { + (void) setvar_daemon(target_arch, value, false, no_daemon, true, 0); + } +#endif + } +} + +/* + * init_mach_macros(void) + * + * Set the magic macros TARGET_MACH, HOST_MACH, + * + * Parameters: + * + * Global variables used: + * host_mach Property for magic macro HOST_MACH + * target_mach Property for magic macro TARGET_MACH + * + * Return value: + * The function does not return a value, but can + * call fatal() in case of error. + */ +static void +init_mach_macros(void) +{ + String_rec result_string; + wchar_t wc_buf[STRING_BUFFER_LENGTH]; + char mb_buf[STRING_BUFFER_LENGTH]; + FILE *pipe; + Name value; + int set_host, set_target; + const char *arch_command = NOCATGETS("/bin/arch"); + + set_host = (get_prop(host_mach->prop, macro_prop) == NULL); + set_target = (get_prop(target_mach->prop, macro_prop) == NULL); + + if (set_host || set_target) { + INIT_STRING_FROM_STACK(result_string, wc_buf); + append_char((int) hyphen_char, &result_string); + + if ((pipe = popen(arch_command, "r")) == NULL) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 183, "Execute of %s failed"), arch_command); + } + while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) { + MBSTOWCS(wcs_buffer, mb_buf); + append_string(wcs_buffer, &result_string, wslen(wcs_buffer)); + } + if (pclose(pipe) != 0) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 184, "Execute of %s failed"), arch_command); + } + + value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start)); + + if (set_host) { + (void) setvar_daemon(host_mach, value, false, no_daemon, true, 0); + } + if (set_target) { + (void) setvar_daemon(target_mach, value, false, no_daemon, true, 0); + } + } +} + +/* + * expand_value_with_daemon(name, macro, destination, cmd) + * + * Checks for daemons and then maybe calls expand_value(). + * + * Parameters: + * name Name of the macro (Added by the NSE) + * macro The property block with the value to expand + * destination Where the result should be deposited + * cmd If we are evaluating a command line we + * turn \ quoting off + * + * Global variables used: + */ +static void +#ifdef NSE +expand_value_with_daemon(Name name, register Property macro, register String destination, Boolean cmd) +#else +expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd) +#endif +{ + register Chain chain; + +#ifdef NSE + if (reading_dependencies) { + /* + * Processing the dependencies themselves + */ + depvar_dep_macro_used(name); + } else { + /* + * Processing the rules for the targets + * the nse_watch_vars flags chokes off most + * checks. it is true only when processing + * the output from a recursive make run + * which is all we are interested in here. + */ + if (nse_watch_vars) { + depvar_rule_macro_used(name); + } + } +#endif + + switch (macro->body.macro.daemon) { + case no_daemon: + if (!svr4 && !posix) { + expand_value(macro->body.macro.value, destination, cmd); + } else { + if (dollarless_flag && tilde_rule) { + expand_value(dollarless_value, destination, cmd); + dollarless_flag = false; + tilde_rule = false; + } else { + expand_value(macro->body.macro.value, destination, cmd); + } + } + return; + case chain_daemon: + /* If this is a $? value we call the daemon to translate the */ + /* list of names to a string */ + for (chain = (Chain) macro->body.macro.value; + chain != NULL; + chain = chain->next) { + APPEND_NAME(chain->name, + destination, + (int) chain->name->hash.length); + if (chain->next != NULL) { + append_char((int) space_char, destination); + } + } + return; + } +} + +/* + * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value. + */ +char *sunpro_dependencies_buf = NULL; +char *sunpro_dependencies_oldbuf = NULL; +int sunpro_dependencies_buf_size = 0; + +/* + * setvar_daemon(name, value, append, daemon, strip_trailing_spaces) + * + * Set a macro value, possibly supplying a daemon to be used + * when referencing the value. + * + * Return value: + * The property block with the new value + * + * Parameters: + * name Name of the macro to set + * value The value to set + * append Should we reset or append to the current value? + * daemon Special treatment when reading the value + * strip_trailing_spaces from the end of value->string + * debug_level Indicates how much tracing we should do + * + * Global variables used: + * makefile_type Used to check if we should enforce read only + * path_name The Name "PATH", compared against + * virtual_root The Name "VIRTUAL_ROOT", compared against + * vpath_defined Set if the macro VPATH is set + * vpath_name The Name "VPATH", compared against + * envvar A list of environment vars with $ in value + */ +Property +setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level) +{ + register Property macro = maybe_append_prop(name, macro_prop); + register Property macro_apx = get_prop(name->prop, macro_append_prop); + int length = 0; + String_rec destination; + wchar_t buffer[STRING_BUFFER_LENGTH]; + register Chain chain; + Name val; + wchar_t *val_string = (wchar_t*)NULL; + Wstring wcb; + +#ifdef NSE + macro->body.macro.imported = false; +#endif + + if ((makefile_type != reading_nothing) && + macro->body.macro.read_only) { + return macro; + } + /* Strip spaces from the end of the value */ + if (daemon == no_daemon) { + if(value != NULL) { + wcb.init(value); + length = wcb.length(); + val_string = wcb.get_string(); + } + if ((length > 0) && iswspace(val_string[length-1])) { + INIT_STRING_FROM_STACK(destination, buffer); + buffer[0] = 0; + append_string(val_string, &destination, length); + if (strip_trailing_spaces) { + while ((length > 0) && + iswspace(destination.buffer.start[length-1])) { + destination.buffer.start[--length] = 0; + } + } + value = GETNAME(destination.buffer.start, FIND_LENGTH); + } + } + + if(macro_apx != NULL) { + val = macro_apx->body.macro_appendix.value; + } else { + val = macro->body.macro.value; + } + + if (append) { + /* + * If we are appending, we just tack the new value after + * the old one with a space in between. + */ + INIT_STRING_FROM_STACK(destination, buffer); + buffer[0] = 0; + if ((macro != NULL) && (val != NULL)) { + APPEND_NAME(val, + &destination, + (int) val->hash.length); + if (value != NULL) { + wcb.init(value); + if(wcb.length() > 0) { + MBTOWC(wcs_buffer, " "); + append_char(wcs_buffer[0], &destination); + } + } + } + if (value != NULL) { + APPEND_NAME(value, + &destination, + (int) value->hash.length); + } + value = GETNAME(destination.buffer.start, FIND_LENGTH); + wcb.init(value); + if (destination.free_after_use) { + retmem(destination.buffer.start); + } + } + + /* Debugging trace */ + if (debug_level > 1) { + if (value != NULL) { + switch (daemon) { + case chain_daemon: + (void) printf("%s =", name->string_mb); + for (chain = (Chain) value; + chain != NULL; + chain = chain->next) { + (void) printf(" %s", chain->name->string_mb); + } + (void) printf("\n"); + break; + case no_daemon: + (void) printf("%s= %s\n", + name->string_mb, + value->string_mb); + break; + } + } else { + (void) printf("%s =\n", name->string_mb); + } + } + /* Set the new values in the macro property block */ +/**/ + if(macro_apx != NULL) { + macro_apx->body.macro_appendix.value = value; + INIT_STRING_FROM_STACK(destination, buffer); + buffer[0] = 0; + if (value != NULL) { + APPEND_NAME(value, + &destination, + (int) value->hash.length); + if (macro_apx->body.macro_appendix.value_to_append != NULL) { + MBTOWC(wcs_buffer, " "); + append_char(wcs_buffer[0], &destination); + } + } + if (macro_apx->body.macro_appendix.value_to_append != NULL) { + APPEND_NAME(macro_apx->body.macro_appendix.value_to_append, + &destination, + (int) macro_apx->body.macro_appendix.value_to_append->hash.length); + } + value = GETNAME(destination.buffer.start, FIND_LENGTH); + if (destination.free_after_use) { + retmem(destination.buffer.start); + } + } +/**/ + macro->body.macro.value = value; + macro->body.macro.daemon = daemon; + /* + * If the user changes the VIRTUAL_ROOT, we need to flush + * the vroot package cache. + */ + if (name == path_name) { + flush_path_cache(); + } + if (name == virtual_root) { + flush_vroot_cache(); + } + /* If this sets the VPATH we remember that */ + if ((name == vpath_name) && + (value != NULL) && + (value->hash.length > 0)) { + vpath_defined = true; + } + /* + * For environment variables we also set the + * environment value each time. + */ + if (macro->body.macro.exported) { + static char *env; + +#ifdef DISTRIBUTED + if (!reading_environment && (value != NULL)) { +#else + if (!reading_environment && (value != NULL) && value->dollar) { +#endif + Envvar p; + + for (p = envvar; p != NULL; p = p->next) { + if (p->name == name) { + p->value = value; + p->already_put = false; + goto found_it; + } + } + p = ALLOC(Envvar); + p->name = name; + p->value = value; + p->next = envvar; + p->env_string = NULL; + p->already_put = false; + envvar = p; +found_it:; +#ifdef DISTRIBUTED + } + if (reading_environment || (value == NULL) || !value->dollar) { +#else + } else { +#endif + length = 2 + strlen(name->string_mb); + if (value != NULL) { + length += strlen(value->string_mb); + } + Property env_prop = maybe_append_prop(name, env_mem_prop); + /* + * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value. + */ + if (!strncmp(name->string_mb, NOCATGETS("SUNPRO_DEPENDENCIES"), 19)) { + if (length >= sunpro_dependencies_buf_size) { + sunpro_dependencies_buf_size=length*2; + if (sunpro_dependencies_buf_size < 4096) + sunpro_dependencies_buf_size = 4096; // Default minimum size + if (sunpro_dependencies_buf) + sunpro_dependencies_oldbuf = sunpro_dependencies_buf; + sunpro_dependencies_buf=getmem(sunpro_dependencies_buf_size); + } + env = sunpro_dependencies_buf; + } else { + env = getmem(length); + } + env_alloc_num++; + env_alloc_bytes += length; + (void) sprintf(env, + "%s=%s", + name->string_mb, + value == NULL ? + "" : value->string_mb); + (void) putenv(env); + env_prop->body.env_mem.value = env; + if (sunpro_dependencies_oldbuf) { + /* Return old buffer */ + retmem_mb(sunpro_dependencies_oldbuf); + sunpro_dependencies_oldbuf = NULL; + } + } + } + if (name == target_arch) { + Name ha = getvar(host_arch); + Name ta = getvar(target_arch); + Name vr = getvar(virtual_root); + int length; + wchar_t *new_value; + wchar_t *old_vr; + Boolean new_value_allocated = false; + + Wstring ha_str(ha); + Wstring ta_str(ta); + Wstring vr_str(vr); + + wchar_t * wcb_ha = ha_str.get_string(); + wchar_t * wcb_ta = ta_str.get_string(); + wchar_t * wcb_vr = vr_str.get_string(); + + length = 32 + + wslen(wcb_ha) + + wslen(wcb_ta) + + wslen(wcb_vr); + old_vr = wcb_vr; + MBSTOWCS(wcs_buffer, NOCATGETS("/usr/arch/")); + if (IS_WEQUALN(old_vr, + wcs_buffer, + wslen(wcs_buffer))) { + old_vr = (wchar_t *) wschr(old_vr, (int) colon_char) + 1; + } + if ( (ha == ta) || (wslen(wcb_ta) == 0) ) { + new_value = old_vr; + } else { + new_value = ALLOC_WC(length); + new_value_allocated = true; + WCSTOMBS(mbs_buffer, old_vr); +#if !defined(linux) + (void) wsprintf(new_value, + NOCATGETS("/usr/arch/%s/%s:%s"), + ha->string_mb + 1, + ta->string_mb + 1, + mbs_buffer); +#else + char * mbs_new_value = (char *)getmem(length); + (void) sprintf(mbs_new_value, + NOCATGETS("/usr/arch/%s/%s:%s"), + ha->string_mb + 1, + ta->string_mb + 1, + mbs_buffer); + MBSTOWCS(new_value, mbs_new_value); + retmem_mb(mbs_new_value); +#endif + } + if (new_value[0] != 0) { + (void) setvar_daemon(virtual_root, + GETNAME(new_value, FIND_LENGTH), + false, + no_daemon, + true, + debug_level); + } + if (new_value_allocated) { + retmem(new_value); + } + } + return macro; +} diff --git a/usr/src/make_src/Make/lib/mksh/src/misc.cc b/usr/src/make_src/Make/lib/mksh/src/misc.cc new file mode 100644 index 0000000..17a878b --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/misc.cc @@ -0,0 +1,1178 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)misc.cc 1.31 06/12/12 + */ + +#pragma ident "@(#)misc.cc 1.31 06/12/12" + +/* + * misc.cc + * + * This file contains various unclassified routines. Some main groups: + * getname + * Memory allocation + * String handling + * Property handling + * Error message handling + * Make internal state dumping + * main routine support + */ + +/* + * Included files + */ +#include <bsd/bsd.h> /* bsd_signal() */ +#include <mksh/i18n.h> /* get_char_semantics_value() */ +#include <mksh/misc.h> +#include <mksdmsi18n/mksdmsi18n.h> +#include <stdarg.h> /* va_list, va_start(), va_end() */ +#include <stdlib.h> /* mbstowcs() */ +#include <sys/signal.h> /* SIG_DFL */ +#include <sys/wait.h> /* wait() */ + +#ifdef SUN5_0 +#include <string.h> /* strerror() */ +#endif + +#if defined (HP_UX) || defined (linux) +#include <unistd.h> +#endif + +/* + * Defined macros + */ + +/* + * typedefs & structs + */ + +/* + * Static variables + */ +#ifdef SUN5_0 +extern "C" void (*sigivalue)(int) = SIG_DFL; +extern "C" void (*sigqvalue)(int) = SIG_DFL; +extern "C" void (*sigtvalue)(int) = SIG_DFL; +extern "C" void (*sighvalue)(int) = SIG_DFL; +#else +static void (*sigivalue)(int) = (void (*) (int)) SIG_DFL; +static void (*sigqvalue)(int) = (void (*) (int)) SIG_DFL; +static void (*sigtvalue)(int) = (void (*) (int)) SIG_DFL; +static void (*sighvalue)(int) = (void (*) (int)) SIG_DFL; +#endif + +long getname_bytes_count = 0; +long getname_names_count = 0; +long getname_struct_count = 0; + +long freename_bytes_count = 0; +long freename_names_count = 0; +long freename_struct_count = 0; + +long expandstring_count = 0; +long getwstring_count = 0; + +/* + * File table of contents + */ +static void expand_string(register String string, register int length); + +#define FATAL_ERROR_MSG_SIZE 200 + +/* + * getmem(size) + * + * malloc() version that checks the returned value. + * + * Return value: + * The memory chunk we allocated + * + * Parameters: + * size The size of the chunk we need + * + * Global variables used: + */ +char * +getmem(register int size) +{ + register char *result = (char *) malloc((unsigned) size); + if (result == NULL) { + char buf[FATAL_ERROR_MSG_SIZE]; + sprintf(buf, NOCATGETS("*** Error: malloc(%d) failed: %s\n"), size, strerror(errno)); + strcat(buf, catgets(libmksdmsi18n_catd, 1, 126, "mksh: Fatal error: Out of memory\n")); + fputs(buf, stderr); +#ifdef SUN5_0 + exit_status = 1; +#endif + exit(1); + } + return result; +} + +/* + * retmem(p) + * + * Cover funtion for free() to make it possible to insert advises. + * + * Parameters: + * p The memory block to free + * + * Global variables used: + */ +void +retmem(wchar_t *p) +{ + (void) free((char *) p); +} + +void +retmem_mb(caddr_t p) +{ + (void) free(p); +} + +/* + * getname_fn(name, len, dont_enter) + * + * Hash a name string to the corresponding nameblock. + * + * Return value: + * The Name block for the string + * + * Parameters: + * name The string we want to internalize + * len The length of that string + * dont_enter Don't enter the name if it does not exist + * + * Global variables used: + * funny The vector of semantic tags for characters + * hashtab The hashtable used for the nametable + */ +Name +getname_fn(wchar_t *name, register int len, register Boolean dont_enter, register Boolean * foundp) +{ + register int length; + register wchar_t *cap = name; + register Name np; + static Name_rec empty_Name; + char *tmp_mbs_buffer = NULL; + char *mbs_name = mbs_buffer; + + /* + * First figure out how long the string is. + * If the len argument is -1 we count the chars here. + */ + if (len == FIND_LENGTH) { + length = wslen(name); + } else { + length = len; + } + + Wstring ws; + ws.init(name, length); + if (length >= MAXPATHLEN) { + mbs_name = tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); + } + (void) wcstombs(mbs_name, ws.get_string(), (length * MB_LEN_MAX) + 1); + + /* Look for the string */ + if (dont_enter || (foundp != 0)) { + np = hashtab.lookup(mbs_name); + if (foundp != 0) { + *foundp = (np != 0) ? true : false; + } + if ((np != 0) || dont_enter) { + if(tmp_mbs_buffer != NULL) { + retmem_mb(tmp_mbs_buffer); + } + return np; + } else { + np = ALLOC(Name); + } + } else { + Boolean found; + np = hashtab.insert(mbs_name, found); + if (found) { + if(tmp_mbs_buffer != NULL) { + retmem_mb(tmp_mbs_buffer); + } + return np; + } + } + getname_struct_count += sizeof(struct _Name); + *np = empty_Name; + + np->string_mb = strdup(mbs_name); + if(tmp_mbs_buffer != NULL) { + retmem_mb(tmp_mbs_buffer); + mbs_name = tmp_mbs_buffer = NULL; + } + getname_bytes_count += strlen(np->string_mb) + 1; + /* Fill in the new Name */ + np->stat.time = file_no_time; + np->hash.length = length; + /* Scan the namestring to classify it */ + for (cap = name, len = 0; --length >= 0;) { + len |= get_char_semantics_value(*cap++); + } + np->dollar = BOOLEAN((len & (int) dollar_sem) != 0); + np->meta = BOOLEAN((len & (int) meta_sem) != 0); + np->percent = BOOLEAN((len & (int) percent_sem) != 0); + np->wildcard = BOOLEAN((len & (int) wildcard_sem) != 0); + np->colon = BOOLEAN((len & (int) colon_sem) != 0); + np->parenleft = BOOLEAN((len & (int) parenleft_sem) != 0); + getname_names_count++; + return np; +} + +void +store_name(Name name) +{ + hashtab.insert(name); +} + +void +free_name(Name name) +{ + freename_names_count++; + freename_struct_count += sizeof(struct _Name); + freename_bytes_count += strlen(name->string_mb) + 1; + retmem_mb(name->string_mb); + for (Property next, p = name->prop; p != NULL; p = next) { + next = p->next; + free(p); + } + free(name); +} + +/* + * enable_interrupt(handler) + * + * This routine sets a new interrupt handler for the signals make + * wants to deal with. + * + * Parameters: + * handler The function installed as interrupt handler + * + * Static variables used: + * sigivalue The original signal handler + * sigqvalue The original signal handler + * sigtvalue The original signal handler + * sighvalue The original signal handler + */ +void +enable_interrupt(register void (*handler) (int)) +{ +#ifdef SUN5_0 + if (sigivalue != SIG_IGN) { +#else + if (sigivalue != (void (*) (int)) SIG_IGN) { +#endif + (void) bsd_signal(SIGINT, (SIG_PF) handler); + } +#ifdef SUN5_0 + if (sigqvalue != SIG_IGN) { +#else + if (sigqvalue != (void (*) (int)) SIG_IGN) { +#endif + (void) bsd_signal(SIGQUIT, (SIG_PF) handler); + } +#ifdef SUN5_0 + if (sigtvalue != SIG_IGN) { +#else + if (sigtvalue != (void (*) (int)) SIG_IGN) { +#endif + (void) bsd_signal(SIGTERM, (SIG_PF) handler); + } +#ifdef SUN5_0 + if (sighvalue != SIG_IGN) { +#else + if (sighvalue != (void (*) (int)) SIG_IGN) { +#endif + (void) bsd_signal(SIGHUP, (SIG_PF) handler); + } +} + +/* + * setup_char_semantics() + * + * Load the vector char_semantics[] with lexical markers + * + * Parameters: + * + * Global variables used: + * char_semantics The vector of character semantics that we set + */ +void +setup_char_semantics(void) +{ + char *s; + wchar_t wc_buffer[1]; + int entry; + + if (svr4) { + s = "@-"; + } else { + s = "=@-?!+"; + } + for (s; MBTOWC(wc_buffer, s); s++) { + entry = get_char_semantics_entry(*wc_buffer); + char_semantics[entry] |= (int) command_prefix_sem; + } + char_semantics[dollar_char_entry] |= (int) dollar_sem; + for (s = "#|=^();&<>*?[]:$`'\"\\\n"; MBTOWC(wc_buffer, s); s++) { + entry = get_char_semantics_entry(*wc_buffer); + char_semantics[entry] |= (int) meta_sem; + } + char_semantics[percent_char_entry] |= (int) percent_sem; + for (s = "@*<%?^"; MBTOWC(wc_buffer, s); s++) { + entry = get_char_semantics_entry(*wc_buffer); + char_semantics[entry] |= (int) special_macro_sem; + } + for (s = "?[*"; MBTOWC(wc_buffer, s); s++) { + entry = get_char_semantics_entry(*wc_buffer); + char_semantics[entry] |= (int) wildcard_sem; + } + char_semantics[colon_char_entry] |= (int) colon_sem; + char_semantics[parenleft_char_entry] |= (int) parenleft_sem; +} + +/* + * errmsg(errnum) + * + * Return the error message for a system call error + * + * Return value: + * An error message string + * + * Parameters: + * errnum The number of the error we want to describe + * + * Global variables used: + * sys_errlist A vector of error messages + * sys_nerr The size of sys_errlist + */ +char * +errmsg(int errnum) +{ +#ifdef linux + return strerror(errnum); +#else // linux + + extern int sys_nerr; +#ifdef SUN4_x + extern char *sys_errlist[]; +#endif + char *errbuf; + + if ((errnum < 0) || (errnum > sys_nerr)) { + errbuf = getmem(6+1+11+1); + (void) sprintf(errbuf, catgets(libmksdmsi18n_catd, 1, 127, "Error %d"), errnum); + return errbuf; + } else { +#ifdef SUN4_x + return(sys_errlist[errnum]); +#endif +#ifdef SUN5_0 + return strerror(errnum); +#endif + + } +#endif // linux +} + +static char static_buf[MAXPATHLEN*3]; + +/* + * fatal_mksh(format, args...) + * + * Print a message and die + * + * Parameters: + * format printf type format string + * args Arguments to match the format + */ +/*VARARGS*/ +void +fatal_mksh(char * message, ...) +{ + va_list args; + char *buf = static_buf; + char *mksh_fat_err = catgets(libmksdmsi18n_catd, 1, 128, "mksh: Fatal error: "); + char *cur_wrk_dir = catgets(libmksdmsi18n_catd, 1, 129, "Current working directory: "); + int mksh_fat_err_len = strlen(mksh_fat_err); + + va_start(args, message); + (void) fflush(stdout); + (void) strcpy(buf, mksh_fat_err); + size_t buf_len = vsnprintf(static_buf + mksh_fat_err_len, + sizeof(static_buf) - mksh_fat_err_len, + message, args) + + mksh_fat_err_len + + strlen(cur_wrk_dir) + + strlen(get_current_path_mksh()) + + 3; // "\n\n" + va_end(args); + if (buf_len >= sizeof(static_buf)) { + buf = getmem(buf_len); + (void) strcpy(buf, mksh_fat_err); + va_start(args, message); + (void) vsprintf(buf + mksh_fat_err_len, message, args); + va_end(args); + } + (void) strcat(buf, "\n"); +/* + if (report_pwd) { + */ + if (1) { + (void) strcat(buf, cur_wrk_dir); + (void) strcat(buf, get_current_path_mksh()); + (void) strcat(buf, "\n"); + } + (void) fputs(buf, stderr); + (void) fflush(stderr); + if (buf != static_buf) { + retmem_mb(buf); + } +#ifdef SUN5_0 + exit_status = 1; +#endif + exit(1); +} + +/* + * fatal_reader_mksh(format, args...) + * + * Parameters: + * format printf style format string + * args arguments to match the format + */ +/*VARARGS*/ +void +fatal_reader_mksh(char * pattern, ...) +{ + va_list args; + char message[1000]; + + va_start(args, pattern); +/* + if (file_being_read != NULL) { + WCSTOMBS(mbs_buffer, file_being_read); + if (line_number != 0) { + (void) sprintf(message, + catgets(libmksdmsi18n_catd, 1, 130, "%s, line %d: %s"), + mbs_buffer, + line_number, + pattern); + } else { + (void) sprintf(message, + "%s: %s", + mbs_buffer, + pattern); + } + pattern = message; + } + */ + + (void) fflush(stdout); + (void) fprintf(stderr, catgets(libmksdmsi18n_catd, 1, 131, "mksh: Fatal error in reader: ")); + (void) vfprintf(stderr, pattern, args); + (void) fprintf(stderr, "\n"); + va_end(args); + +/* + if (temp_file_name != NULL) { + (void) fprintf(stderr, + catgets(libmksdmsi18n_catd, 1, 132, "mksh: Temp-file %s not removed\n"), + temp_file_name->string_mb); + temp_file_name = NULL; + } + */ + +/* + if (report_pwd) { + */ + if (1) { + (void) fprintf(stderr, + catgets(libmksdmsi18n_catd, 1, 133, "Current working directory %s\n"), + get_current_path_mksh()); + } + (void) fflush(stderr); +#ifdef SUN5_0 + exit_status = 1; +#endif + exit(1); +} + +/* + * warning_mksh(format, args...) + * + * Print a message and continue. + * + * Parameters: + * format printf type format string + * args Arguments to match the format + */ +/*VARARGS*/ +void +warning_mksh(char * message, ...) +{ + va_list args; + + va_start(args, message); + (void) fflush(stdout); + (void) fprintf(stderr, catgets(libmksdmsi18n_catd, 1, 134, "mksh: Warning: ")); + (void) vfprintf(stderr, message, args); + (void) fprintf(stderr, "\n"); + va_end(args); +/* + if (report_pwd) { + */ + if (1) { + (void) fprintf(stderr, + catgets(libmksdmsi18n_catd, 1, 135, "Current working directory %s\n"), + get_current_path_mksh()); + } + (void) fflush(stderr); +} + +/* + * get_current_path_mksh() + * + * Stuff current_path with the current path if it isnt there already. + * + * Parameters: + * + * Global variables used: + */ +char * +get_current_path_mksh(void) +{ + char pwd[(MAXPATHLEN * MB_LEN_MAX)]; + static char *current_path; + + if (current_path == NULL) { +#if defined(SUN5_0) || defined(HP_UX) || defined(linux) + getcwd(pwd, sizeof(pwd)); +#else + (void) getwd(pwd); +#endif + if (pwd[0] == (int) nul_char) { + pwd[0] = (int) slash_char; + pwd[1] = (int) nul_char; + } + current_path = strdup(pwd); + } + return current_path; +} + +/* + * append_prop(target, type) + * + * Create a new property and append it to the property list of a Name. + * + * Return value: + * A new property block for the target + * + * Parameters: + * target The target that wants a new property + * type The type of property being requested + * + * Global variables used: + */ +Property +append_prop(register Name target, register Property_id type) +{ + register Property *insert = &target->prop; + register Property prop = *insert; + register int size; + + switch (type) { + case conditional_prop: + size = sizeof (struct Conditional); + break; + case line_prop: + size = sizeof (struct Line); + break; + case macro_prop: + size = sizeof (struct _Macro); + break; + case makefile_prop: + size = sizeof (struct Makefile); + break; + case member_prop: + size = sizeof (struct Member); + break; + case recursive_prop: + size = sizeof (struct Recursive); + break; + case sccs_prop: + size = sizeof (struct Sccs); + break; + case suffix_prop: + size = sizeof (struct Suffix); + break; + case target_prop: + size = sizeof (struct Target); + break; + case time_prop: + size = sizeof (struct STime); + break; + case vpath_alias_prop: + size = sizeof (struct Vpath_alias); + break; + case long_member_name_prop: + size = sizeof (struct Long_member_name); + break; + case macro_append_prop: + size = sizeof (struct _Macro_appendix); + break; + case env_mem_prop: + size = sizeof (struct _Env_mem); + break; + default: + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 136, "Internal error. Unknown prop type %d"), type); + } + for (; prop != NULL; insert = &prop->next, prop = *insert); + size += PROPERTY_HEAD_SIZE; + *insert = prop = (Property) getmem(size); + memset((char *) prop, 0, size); + prop->type = type; + prop->next = NULL; + return prop; +} + +/* + * maybe_append_prop(target, type) + * + * Append a property to the Name if none of this type exists + * else return the one already there + * + * Return value: + * A property of the requested type for the target + * + * Parameters: + * target The target that wants a new property + * type The type of property being requested + * + * Global variables used: + */ +Property +maybe_append_prop(register Name target, register Property_id type) +{ + register Property prop; + + if ((prop = get_prop(target->prop, type)) != NULL) { + return prop; + } + return append_prop(target, type); +} + +/* + * get_prop(start, type) + * + * Scan the property list of a Name to find the next property + * of a given type. + * + * Return value: + * The first property of the type, if any left + * + * Parameters: + * start The first property block to check for type + * type The type of property block we need + * + * Global variables used: + */ +Property +get_prop(register Property start, register Property_id type) +{ + for (; start != NULL; start = start->next) { + if (start->type == type) { + return start; + } + } + return NULL; +} + +/* + * append_string(from, to, length) + * + * Append a C string to a make string expanding it if nessecary + * + * Parameters: + * from The source (C style) string + * to The destination (make style) string + * length The length of the from string + * + * Global variables used: + */ +void +append_string(register wchar_t *from, register String to, register int length) +{ + if (length == FIND_LENGTH) { + length = wslen(from); + } + if (to->buffer.start == NULL) { + expand_string(to, 32 + length); + } + if (to->buffer.end - to->text.p <= length) { + expand_string(to, + (to->buffer.end - to->buffer.start) * 2 + + length); + } + if (length > 0) { + (void) wsncpy(to->text.p, from, length); + to->text.p += length; + } + *(to->text.p) = (int) nul_char; +} + +wchar_t * get_wstring(char *from) { + if(from == NULL) { + return NULL; + } + getwstring_count++; + wchar_t * wcbuf = ALLOC_WC(strlen(from) + 1); + mbstowcs(wcbuf, from, strlen(from)+1); + return wcbuf; +} + +void +append_string(register char *from, register String to, register int length) +{ + if (length == FIND_LENGTH) { + length = strlen(from); + } + if (to->buffer.start == NULL) { + expand_string(to, 32 + length); + } + if (to->buffer.end - to->text.p <= length) { + expand_string(to, + (to->buffer.end - to->buffer.start) * 2 + + length); + } + if (length > 0) { + (void) mbstowcs(to->text.p, from, length); + to->text.p += length; + } + *(to->text.p) = (int) nul_char; +} + +/* + * expand_string(string, length) + * + * Allocate more memory for strings that run out of space. + * + * Parameters: + * string The make style string we want to expand + * length The new length we need + * + * Global variables used: + */ +static void +expand_string(register String string, register int length) +{ + register wchar_t *p; + + if (string->buffer.start == NULL) { + /* For strings that have no memory allocated */ + string->buffer.start = + string->text.p = + string->text.end = + ALLOC_WC(length); + string->buffer.end = string->buffer.start + length; + string->text.p[0] = (int) nul_char; + string->free_after_use = true; + expandstring_count++; + return; + } + if (string->buffer.end - string->buffer.start >= length) { + /* If we really don't need more memory. */ + return; + } + /* + * Get more memory, copy the string and free the old buffer if + * it is was malloc()'ed. + */ + expandstring_count++; + p = ALLOC_WC(length); + (void) wscpy(p, string->buffer.start); + string->text.p = p + (string->text.p - string->buffer.start); + string->text.end = p + (string->text.end - string->buffer.start); + string->buffer.end = p + length; + if (string->free_after_use) { + retmem(string->buffer.start); + } + string->buffer.start = p; + string->free_after_use = true; +} + +/* + * append_char(from, to) + * + * Append one char to a make string expanding it if nessecary + * + * Parameters: + * from Single character to append to string + * to The destination (make style) string + * + * Global variables used: + */ +void +append_char(wchar_t from, register String to) +{ + if (to->buffer.start == NULL) { + expand_string(to, 32); + } + if (to->buffer.end - to->text.p <= 2) { + expand_string(to, to->buffer.end - to->buffer.start + 32); + } + *(to->text.p)++ = from; + *(to->text.p) = (int) nul_char; +} + +/* + * handle_interrupt_mksh() + * + * This is where C-C traps are caught. + */ +void +handle_interrupt_mksh(int) +{ + (void) fflush(stdout); + /* Make sure the processes running under us terminate first. */ + if (childPid > 0) { + kill(childPid, SIGTERM); + childPid = -1; + } +#if defined(SUN5_0) || defined(HP_UX) || defined(linux) + while (wait((int *) NULL) != -1); +#if defined(SUN5_0) + exit_status = 2; +#endif +#else + while (wait((union wait *) NULL) != -1); +#endif + exit(2); +} + +/* + * setup_interrupt() + * + * This routine saves the original interrupt handler pointers + * + * Parameters: + * + * Static variables used: + * sigivalue The original signal handler + * sigqvalue The original signal handler + * sigtvalue The original signal handler + * sighvalue The original signal handler + */ +void +setup_interrupt(register void (*handler) (int)) +{ +#ifdef SUN5_0 + sigivalue = bsd_signal(SIGINT, SIG_IGN); + sigqvalue = bsd_signal(SIGQUIT, SIG_IGN); + sigtvalue = bsd_signal(SIGTERM, SIG_IGN); + sighvalue = bsd_signal(SIGHUP, SIG_IGN); +#else + sigivalue = (void (*) (int)) bsd_signal(SIGINT, SIG_IGN); + sigqvalue = (void (*) (int)) bsd_signal(SIGQUIT, SIG_IGN); + sigtvalue = (void (*) (int)) bsd_signal(SIGTERM, SIG_IGN); + sighvalue = (void (*) (int)) bsd_signal(SIGHUP, SIG_IGN); +#endif + enable_interrupt(handler); +} + + +void +mbstowcs_with_check(wchar_t *pwcs, const char *s, size_t n) +{ + if(mbstowcs(pwcs, s, n) == -1) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 143, "The string `%s' is not valid in current locale"), s); + } +} + + + +Wstring::Wstring() +{ + INIT_STRING_FROM_STACK(string, string_buf); +} + +Wstring::Wstring(struct _Name * name) +{ + INIT_STRING_FROM_STACK(string, string_buf); + append_string(name->string_mb, &string, name->hash.length); +} + +Wstring::~Wstring() +{ + if(string.free_after_use) { + retmem(string.buffer.start); + } +} + +void +Wstring::init(struct _Name * name) +{ + if(string.free_after_use) { + retmem(string.buffer.start); + } + INIT_STRING_FROM_STACK(string, string_buf); + append_string(name->string_mb, &string, name->hash.length); +} + +void +Wstring::init(wchar_t * name, unsigned length) +{ + INIT_STRING_FROM_STACK(string, string_buf); + append_string(name, &string, length); + string.buffer.start[length] = 0; +} + +Boolean +Wstring::equaln(wchar_t * str, unsigned length) +{ + return (Boolean)IS_WEQUALN(string.buffer.start, str, length); +} + +Boolean +Wstring::equaln(Wstring * str, unsigned length) +{ + return (Boolean)IS_WEQUALN(string.buffer.start, str->string.buffer.start, length); +} + +Boolean +Wstring::equal(wchar_t * str, unsigned off, unsigned length) +{ + return (Boolean)IS_WEQUALN(string.buffer.start + off, str, length); +} + +Boolean +Wstring::equal(wchar_t * str, unsigned off) +{ + return (Boolean)IS_WEQUAL(string.buffer.start + off, str); +} + +Boolean +Wstring::equal(wchar_t * str) +{ + return equal(str, 0); +} + +Boolean +Wstring::equal(Wstring * str, unsigned off, unsigned length) +{ + return (Boolean)IS_WEQUALN(string.buffer.start + off, str->string.buffer.start, length); +} + +Boolean +Wstring::equal(Wstring * str) +{ + return equal(str, 0); +} + +Boolean +Wstring::equal(Wstring * str, unsigned off) +{ + return (Boolean)IS_WEQUAL(string.buffer.start + off, str->string.buffer.start); +} + +void +Wstring::append_to_str(struct _String * str, unsigned off, unsigned length) +{ + append_string(string.buffer.start + off, str, length); +} + +Name +Name_set::lookup(const char *key) +{ + for (entry *node = root; node != 0;) { + int res = strcmp(key, node->name->string_mb); + if (res < 0) { + node = node->left; + } else if (res > 0) { + node = node->right; + } else { + return node->name; + } + } + return 0; +} + +Name +Name_set::insert(const char *key, Boolean &found) +{ + Name name = 0; + + if (root != 0) { + for (entry *node = root; name == 0;) { + int res = strcmp(key, node->name->string_mb); + if (res < 0) { + if (node->left != 0) { + node = node->left; + } else { + found = false; + name = ALLOC(Name); + + node->left = new entry(name, node); + rebalance(node); + } + } else if (res > 0) { + if (node->right != 0) { + node = node->right; + } else { + found = false; + name = ALLOC(Name); + + node->right = new entry(name, node); + rebalance(node); + } + } else { + found = true; + name = node->name; + } + } + } else { + found = false; + name = ALLOC(Name); + + root = new entry(name, 0); + } + return name; +} + +void +Name_set::insert(Name name) { + if (root != 0) { + for (entry *node = root;;) { + int res = strcmp(name->string_mb, node->name->string_mb); + if (res < 0) { + if (node->left != 0) { + node = node->left; + } else { + node->left = new entry(name, node); + rebalance(node); + break; + } + } else if (res > 0) { + if (node->right != 0) { + node = node->right; + } else { + node->right = new entry(name, node); + rebalance(node); + break; + } + } else { + // should be an error: inserting already existing name + break; + } + } + } else { + root = new entry(name, 0); + } +} + +void +Name_set::rebalance(Name_set::entry *node) { + for (; node != 0; node = node->parent) { + entry *right = node->right; + entry *left = node->left; + + unsigned rdepth = (right != 0) ? right->depth : 0; + unsigned ldepth = (left != 0) ? left->depth : 0; + + if (ldepth > rdepth + 1) { + if ((node->left = left->right) != 0) { + left->right->parent = node; + } + if ((left->parent = node->parent) != 0) { + if (node == node->parent->right) { + node->parent->right = left; + } else { + node->parent->left = left; + } + } else { + root = left; + } + left->right = node; + node->parent = left; + + node->setup_depth(); + node = left; + } else if (rdepth > ldepth + 1) { + if ((node->right = right->left) != 0) { + right->left->parent = node; + } + if ((right->parent = node->parent) != 0) { + if (node == node->parent->right) { + node->parent->right = right; + } else { + node->parent->left = right; + } + } else { + root = right; + } + right->left = node; + node->parent = right; + + node->setup_depth(); + node = right; + } + node->setup_depth(); + } +} + +Name_set::iterator +Name_set::begin() const { + for (entry *node = root; node != 0; node = node->left) { + if (node->left == 0) { + return iterator(node); + } + } + return iterator(); +} + +Name_set::iterator& +Name_set::iterator::operator++() { + if (node != 0) { + if (node->right != 0) { + node = node->right; + while (node->left != 0) { + node = node->left; + } + } else { + while ((node->parent != 0) && (node->parent->right == node)) { + node = node->parent; + } + node = node->parent; + } + } + return *this; +} diff --git a/usr/src/make_src/Make/lib/mksh/src/mksh.cc b/usr/src/make_src/Make/lib/mksh/src/mksh.cc new file mode 100644 index 0000000..98c9601 --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/mksh.cc @@ -0,0 +1,286 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)mksh.cc 1.22 06/12/12 + */ + +#pragma ident "@(#)mksh.cc 1.22 06/12/12" + +/* + * mksh.cc + * + * Execute the command(s) of one Make or DMake rule + */ + +/* + * Included files + */ +#if defined(TEAMWARE_MAKE_CMN) || defined(MAKETOOL) /* tolik */ +# include <avo/util.h> +#endif + +#include <mksh/dosys.h> /* redirect_io() */ +#include <mksh/misc.h> /* retmem() */ +#include <mksh/mksh.h> +#include <mksdmsi18n/mksdmsi18n.h> +#include <errno.h> +#include <signal.h> + +#ifdef HP_UX + extern void (*sigset(int, void (*)(__harg)))(__harg); +#endif + +/* + * Workaround for NFS bug. Sometimes, when running 'chdir' on a remote + * dmake server, it fails with "Stale NFS file handle" error. + * The second attempt seems to work. + */ +int +my_chdir(char * dir) { + int res = chdir(dir); + if (res != 0 && (errno == ESTALE || errno == EAGAIN)) { + /* Stale NFS file handle. Try again */ + res = chdir(dir); + } + return res; +} + + +/* + * File table of contents + */ +static void change_sunpro_dependencies_value(char *oldpath, char *newpath); +static void init_mksh_globals(char *shell); +static void set_env_vars(char *env_list[]); + +#if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */ +/* + * Execute the command(s) of one Make or DMake rule + */ +int +do_job(Avo_DmakeCommand *cmd_list[], char *env_list[], char *stdout_file, char *stderr_file, char *cwd, char *cnwd, int ignore, int silent, pathpt vroot_path, char *shell, int nice_prio) +{ + Boolean always_exec_flag; + char *cmd; + Avo_DmakeCommand **cmd_list_p; + Name command; + Boolean do_not_exec_flag; + Boolean ignore_flag; + int length; + Boolean make_refd_flag; + Boolean meta_flag; + char pathname[MAXPATHLEN]; + Doname result; + Boolean silent_flag; + wchar_t *tmp_wcs_buffer; + + if ((childPid = fork()) < 0) { /* error */ + ; + } else if (childPid > 0) { /* parent */ + ; + } else { /* child, mksh */ + (void) sigset(SIGCHLD, SIG_DFL); + enable_interrupt(handle_interrupt_mksh); + /* set environment variables */ + set_env_vars(env_list); + /* redirect stdout and stderr to temp files */ + dup2(1, 2); // Because fatal_mksh() prints error messages into + // stderr but dmake uses stderr for XDR communications + // and stdout for errors messages. + redirect_io(stdout_file, stderr_file); + /* try cd'ing to cwd */ + if (my_chdir(cwd) != 0) { + /* try the netpath machine:pathname */ + if (!avo_netpath_to_path(cnwd, pathname)) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 137, "`cd %s' failed, and conversion of %s to automounter pathname also failed: %s"), cwd, cnwd, strerror(errno)); + } else if (my_chdir(pathname) != 0) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 138, "`cd %s' and `cd %s' both failed: %s"), cwd, pathname, strerror(errno)); + } + /* + * change the value of SUNPRO_DEPENDENCIES + * to the new path. + */ + change_sunpro_dependencies_value(cwd, pathname); + } + init_mksh_globals(shell); + for (cmd_list_p = cmd_list; + *cmd_list_p != (Avo_DmakeCommand *) NULL; + cmd_list_p++) { + if ((*cmd_list_p)->ignore()) { + ignore_flag = true; + } else { + ignore_flag = false; + } + if ((*cmd_list_p)->silent()) { + silent_flag = true; + } else { + silent_flag = false; + } +/* + if ((*cmd_list_p)->always_exec()) { + always_exec_flag = true; + } else { + always_exec_flag = false; + } + */ + always_exec_flag = false; + if ((*cmd_list_p)->meta()) { + meta_flag = true; + } else { + meta_flag = false; + } + if ((*cmd_list_p)->make_refd()) { + make_refd_flag = true; + } else { + make_refd_flag = false; + } + if ((*cmd_list_p)->do_not_exec()) { + do_not_exec_flag = true; + } else { + do_not_exec_flag = false; + } + do_not_exec_rule = do_not_exec_flag; + cmd = (*cmd_list_p)->getCmd(); + if ((length = strlen(cmd)) >= MAXPATHLEN) { + tmp_wcs_buffer = ALLOC_WC(length + 1); + (void) mbstowcs(tmp_wcs_buffer, cmd, length + 1); + command = GETNAME(tmp_wcs_buffer, FIND_LENGTH); + retmem(tmp_wcs_buffer); + } else { + MBSTOWCS(wcs_buffer, cmd); + command = GETNAME(wcs_buffer, FIND_LENGTH); + } + if ((command->hash.length > 0) && + (!silent_flag || do_not_exec_flag)) { + (void) printf("%s\n", command->string_mb); + } + result = dosys_mksh(command, + ignore_flag, + make_refd_flag, + false, /* bugs #4085164 & #4990057 */ + /* BOOLEAN(silent_flag && ignore_flag), */ + always_exec_flag, + (Name) NULL, + false, + NULL, + NULL, + vroot_path, + nice_prio); + if (result == build_failed) { + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in do_job(), and dosys_mksh() returned result of build_failed.")); +#endif + + if (silent_flag) { + (void) printf(catgets(libmksdmsi18n_catd, 1, 139, "The following command caused the error:\n%s\n"), + command->string_mb); + } + if (!ignore_flag && !ignore) { + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in do_job(), and dosys_mksh() returned result of build_failed, exiting 1.")); +#endif + + exit(1); + } + } + } + +#ifdef PRINT_EXIT_STATUS + warning_mksh(NOCATGETS("I'm in do_job(), exiting 0.")); +#endif + + exit(0); + } + return childPid; +} +#endif /* TEAMWARE_MAKE_CMN */ + +static void +set_env_vars(char *env_list[]) +{ + char **env_list_p; + + for (env_list_p = env_list; + *env_list_p != (char *) NULL; + env_list_p++) { + putenv(*env_list_p); + } +} + +static void +init_mksh_globals(char *shell) +{ +/* + MBSTOWCS(wcs_buffer, NOCATGETS("SHELL")); + shell_name = GETNAME(wcs_buffer, FIND_LENGTH); + MBSTOWCS(wcs_buffer, shell); + (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false); + */ + char * dmake_shell; + if ((dmake_shell = getenv(NOCATGETS("DMAKE_SHELL"))) == NULL) { + dmake_shell = shell; + } + MBSTOWCS(wcs_buffer, dmake_shell); + shell_name = GETNAME(wcs_buffer, FIND_LENGTH); +} + +/* + * Change the pathname in the value of the SUNPRO_DEPENDENCIES env variable + * from oldpath to newpath. + */ +static void +change_sunpro_dependencies_value(char *oldpath, char *newpath) +{ + char buf[MAXPATHLEN]; + static char *env; + int length; + int oldpathlen; + char *sp_dep_value; + + /* check if SUNPRO_DEPENDENCIES is set in the environment */ + if ((sp_dep_value = getenv(NOCATGETS("SUNPRO_DEPENDENCIES"))) != NULL) { + oldpathlen = strlen(oldpath); + /* check if oldpath is indeed in the value of SUNPRO_DEPENDENCIES */ + if (strncmp(oldpath, sp_dep_value, oldpathlen) == 0) { + (void) sprintf(buf, + "%s%s", + newpath, + sp_dep_value + oldpathlen); + length = 2 + + strlen(NOCATGETS("SUNPRO_DEPENDENCIES")) + + strlen(buf); + env = getmem(length); + (void) sprintf(env, + "%s=%s", + NOCATGETS("SUNPRO_DEPENDENCIES"), + buf); + (void) putenv(env); + } + } +} + + diff --git a/usr/src/make_src/Make/lib/mksh/src/read.cc b/usr/src/make_src/Make/lib/mksh/src/read.cc new file mode 100644 index 0000000..53cd524 --- /dev/null +++ b/usr/src/make_src/Make/lib/mksh/src/read.cc @@ -0,0 +1,174 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)read.cc 1.11 06/12/12 + */ + +#pragma ident "@(#)read.cc 1.11 06/12/12" + +/* + * read.c + * + * This file contains the makefile reader. + */ + +/* + * Included files + */ +#include <mksh/misc.h> /* retmem() */ +#include <mksh/read.h> +#include <mksdmsi18n/mksdmsi18n.h> +#include <sys/uio.h> /* read() */ +#include <unistd.h> /* close(), unlink(), read() */ + +#define STRING_LEN_TO_CONVERT (8*1024) + +/* + * get_next_block_fn(source) + * + * Will get the next block of text to read either + * by popping one source bVSIZEOFlock of the stack of Sources + * or by reading some more from the makefile. + * + * Return value: + * The new source block to read from + * + * Parameters: + * source The old source block + * + * Global variables used: + * file_being_read The name of the current file, error msg + */ +Boolean make_state_locked; +Source +get_next_block_fn(register Source source) +{ + register off_t to_read; + register int length; + register size_t num_wc_chars; + char ch_save; + char *ptr; + + if (source == NULL) { + return NULL; + } + if ((source->fd < 0) || + ((source->bytes_left_in_file <= 0) && + (source->inp_buf_ptr >= source->inp_buf_end))) { + /* We can't read from the makefile, so pop the source block */ + if (source->fd > 2) { + (void) close(source->fd); + if (make_state_lockfile != NULL) { + (void) unlink(make_state_lockfile); + retmem_mb(make_state_lockfile); + make_state_lockfile = NULL; + make_state_locked = false; + } + } + if (source->string.free_after_use && + (source->string.buffer.start != NULL)) { + retmem(source->string.buffer.start); + source->string.buffer.start = NULL; + } + if (source->inp_buf != NULL) { + retmem_mb(source->inp_buf); + source->inp_buf = NULL; + } + source = source->previous; + if (source != NULL) { + source->error_converting = false; + } + return source; + } + if (source->bytes_left_in_file > 0) { + /* + * Read the whole makefile. + * Hopefully the kernel managed to prefetch the stuff. + */ + to_read = source->bytes_left_in_file; + source->inp_buf_ptr = source->inp_buf = getmem(to_read + 1); + source->inp_buf_end = source->inp_buf + to_read; + length = read(source->fd, source->inp_buf, (unsigned int) to_read); + if (length != to_read) { + WCSTOMBS(mbs_buffer, file_being_read); + if (length == 0) { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 140, "Error reading `%s': Premature EOF"), + mbs_buffer); + } else { + fatal_mksh(catgets(libmksdmsi18n_catd, 1, 141, "Error reading `%s': %s"), + mbs_buffer, + errmsg(errno)); + } + } + *source->inp_buf_end = nul_char; + source->bytes_left_in_file = 0; + } + /* + * Try to convert the next piece. + */ + ptr = source->inp_buf_ptr + STRING_LEN_TO_CONVERT; + if (ptr > source->inp_buf_end) { + ptr = source->inp_buf_end; + } + for (num_wc_chars = 0; ptr > source->inp_buf_ptr; ptr--) { + ch_save = *ptr; + *ptr = nul_char; + num_wc_chars = mbstowcs(source->string.text.end, + source->inp_buf_ptr, + STRING_LEN_TO_CONVERT); + *ptr = ch_save; + if (num_wc_chars != (size_t)-1) { + break; + } + } + + if ((int) num_wc_chars == (size_t)-1) { + source->error_converting = true; + return source; + } + + source->error_converting = false; + source->inp_buf_ptr = ptr; + source->string.text.end += num_wc_chars; + *source->string.text.end = 0; + + if (source->inp_buf_ptr >= source->inp_buf_end) { + if (*(source->string.text.end - 1) != (int) newline_char) { + WCSTOMBS(mbs_buffer, file_being_read); + warning_mksh(catgets(libmksdmsi18n_catd, 1, 142, "newline is not last character in file %s"), + mbs_buffer); + *source->string.text.end++ = (int) newline_char; + *source->string.text.end = (int) nul_char; + *source->string.buffer.end++; + } + if (source->inp_buf != NULL) { + retmem_mb(source->inp_buf); + source->inp_buf = NULL; + } + } + return source; +} + + |