summaryrefslogtreecommitdiff
path: root/usr/src/tools
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2019-09-09 11:26:45 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2019-09-09 11:26:45 +0000
commitb36aca9fee0db2b4336b9f6ee7835a8f3fbfe9c9 (patch)
tree029c95d18101ff3839ddd942d4ed90ff16fd8fe7 /usr/src/tools
parent1cc204b97b9317e681958da0e91abeb27bcc6f82 (diff)
parent793ac993be490bb7c16673e5f2588c6d18672894 (diff)
downloadillumos-joyent-b36aca9fee0db2b4336b9f6ee7835a8f3fbfe9c9.tar.gz
[illumos-gate merge]
commit 793ac993be490bb7c16673e5f2588c6d18672894 11654 libipmi/Makefile.com has an invalid and unused variable substitution commit d8109ce4330e1b8ad6c29f9fccacec969066bb9d 11653 tools/make/bin/Makefile has an invalid and unused variable substitution commit bdf3516c67ac96d42da6a8adc5bf9a0a5b72b060 11652 Remove unused archive library rules from cmd/sgs commit 2b1ff28bbd88f04a83e6ca2d284eb7be0959c43c 11647 6026 regressed after 5980 commit 21ec5af72097881ccdcd81ebfd26e1c85b609ad6 11662 nss_ldap: group members are not comma separated commit aa5636e518a7c706134caf5072a16f9f85f7497a 11633 SPARC NULL pointer errors in libprtdiag_psr commit 3f8c0768c028803de6022c542bbd9e9e6f08289f 11632 SPARC NULL pointer error in libtsalarm commit 53bfe442a2e3c2938be0ac7b2b05d096689c2ea6 11631 SPARC NULL pointer error in libds commit 9cb0a1d4446fe891a01d01e07b2e27f0177c84cd 11630 remove checks for 64-bit capable hardware commit 95bfa623bf6336d9476ba272ebda6e2c2a305e6f 10852 libficl-sys: implement loader emulator commands with linker set commit 90ce8b937724b0472efa92ca9911002383cf25a2 10851 want sys/linker_set.h commit bfa93d3911fd4856c353c9b190c18cdb98fc36b4 11610 PCI ID ambiguity leads to driver induced mayhem 11611 pchtemp driver should use new IPD 9 aliases commit 96fc3fdf646c403f7896ecd3e9657d0474025bba 11617 esc fails with /usr/bin/cpp present commit 5711d3938643272e5ca2aaf5d868e612e7bc97b6 11640 add zpool ashift property tunable commit 2c54ade085d70dd5a2914f0fa5cf7fe208cd36a6 11603 smbadm has wrong exit code while listing SMB group properties commit 69b1fd3f24d0ee2e682883606201c61f52085805 11461 should use a native link-editor during the build 11463 SUNWonld has passed its use-by date 11464 cmd/sgs/tools should contain tools, not common code 11465 sgsmsg should be built with the rest of the build tools commit d58ceae2ed78dc65ab682a0281ce523d6c4116fe 11646 fbt entry probes incorrectly placed due to -fshrink-wrap Conflicts: usr/src/uts/Makefile.uts
Diffstat (limited to 'usr/src/tools')
-rw-r--r--usr/src/tools/Makefile11
-rw-r--r--usr/src/tools/Makefile.tools4
-rw-r--r--usr/src/tools/chk4ubin/Makefile1
-rw-r--r--usr/src/tools/ctf/dwarf/Makefile.com3
-rw-r--r--usr/src/tools/cw/cw.1onbld9
-rw-r--r--usr/src/tools/cw/cw.c32
-rw-r--r--usr/src/tools/findunref/exception_list.open1
-rw-r--r--usr/src/tools/make/bin/Makefile1
-rw-r--r--usr/src/tools/make/lib/makestate/Makefile.com1
-rw-r--r--usr/src/tools/sgs/Makefile39
-rw-r--r--usr/src/tools/sgs/Makefile.com18
-rw-r--r--usr/src/tools/sgs/include/Makefile68
-rw-r--r--usr/src/tools/sgs/ld/Makefile41
-rw-r--r--usr/src/tools/sgs/libconv/Makefile43
-rw-r--r--usr/src/tools/sgs/libelf/Makefile48
-rw-r--r--usr/src/tools/sgs/libld/Makefile56
-rw-r--r--usr/src/tools/sgs/liblddbg/Makefile51
-rw-r--r--usr/src/tools/sgs/sgsmsg/Makefile79
-rw-r--r--usr/src/tools/sgs/sgsmsg/sgsmsg.1onbld426
-rw-r--r--usr/src/tools/sgs/sgsmsg/sgsmsg.c1237
20 files changed, 2151 insertions, 18 deletions
diff --git a/usr/src/tools/Makefile b/usr/src/tools/Makefile
index 68a4c34ff5..60c74fb342 100644
--- a/usr/src/tools/Makefile
+++ b/usr/src/tools/Makefile
@@ -61,12 +61,19 @@ COMMON_SUBDIRS= \
onbld \
protocmp \
protolist \
- scripts
+ scripts \
+ sgs
#
# special versions of commands for use only in build
#
UNSHIPPED_SUBDIRS = \
+ $(SGSMSG) \
+ $(SGSLIBCONV) \
+ $(SGSLIBELF) \
+ $(SGSLIBLDDBG) \
+ $(SGSLIBLD) \
+ $(SGSLD) \
localedef \
man \
mandoc \
@@ -86,6 +93,8 @@ i386_SUBDIRS= \
mbh_patch \
btxld
+$(INTEL_BLD)sgs: aw
+
SUBDIRS= \
$($(MACH)_SUBDIRS) \
$(COMMON_SUBDIRS) \
diff --git a/usr/src/tools/Makefile.tools b/usr/src/tools/Makefile.tools
index cd38795b01..867c55b2f4 100644
--- a/usr/src/tools/Makefile.tools
+++ b/usr/src/tools/Makefile.tools
@@ -55,6 +55,10 @@ LDLIBS=
LDFLAGS= $(MAPFILE.NES:%=-M%) $(MAPFILE.NED:%=-M%) \
$(MAPFILE.PGA:%=-M%)
+# Unset CW_LINKER so we run the default. We don't set LD here to avoid taking
+# the journey through LD_ALTEXEC unnecessarily.
+CW_LINKER=
+
ROOTONBLDPROG= $(PROG:%=$(ROOTONBLDBIN)/%)
ROOTONBLDMACHPROG= $(PROG:%=$(ROOTONBLDBINMACH)/%)
ROOTONBLDSHFILES= $(SHFILES:%=$(ROOTONBLDBIN)/%)
diff --git a/usr/src/tools/chk4ubin/Makefile b/usr/src/tools/chk4ubin/Makefile
index a251d49ca7..5da362350e 100644
--- a/usr/src/tools/chk4ubin/Makefile
+++ b/usr/src/tools/chk4ubin/Makefile
@@ -28,6 +28,7 @@ include ../Makefile.tools
PROG = chk4ubin
+DYNFLAGS += '-R$$ORIGIN/../../lib/$(MACH)'
LDLIBS += -lelf
LINTFLAGS += -ux
diff --git a/usr/src/tools/ctf/dwarf/Makefile.com b/usr/src/tools/ctf/dwarf/Makefile.com
index 67ffd64a62..52aedda3a7 100644
--- a/usr/src/tools/ctf/dwarf/Makefile.com
+++ b/usr/src/tools/ctf/dwarf/Makefile.com
@@ -68,7 +68,7 @@ OBJECTS=dwarf_abbrev.o \
pro_weaks.o
include $(SRC)/lib/Makefile.lib
-
+include $(SRC)/tools/Makefile.tools
FILEMODE = 0755
SRCDIR = $(SRC)/lib/libdwarf/common/
@@ -81,6 +81,7 @@ CERRWARN += -_gcc=-Wno-implicit-function-declaration
# libdwarf not clean
SMATCH=off
+DYNFLAGS += '-R$$ORIGIN/../../lib/$(MACH)'
LDLIBS = -lelf -lc
.KEEP_STATE:
diff --git a/usr/src/tools/cw/cw.1onbld b/usr/src/tools/cw/cw.1onbld
index 62800bb727..465c4b590d 100644
--- a/usr/src/tools/cw/cw.1onbld
+++ b/usr/src/tools/cw/cw.1onbld
@@ -36,6 +36,7 @@
.Op Fl -noecho
.Fl -primary Ar compiler
.Op Fl -shadow Ar compiler ...
+.Op Fl -linker Ar linker
.Fl -
.Ar compiler args ...
.Sh DESCRIPTION
@@ -77,6 +78,11 @@ and pre-processing, and whos objects we deliver).
.It Fl -shadow Ar compiler
Specify a shadow compiler, which builds sources for the sake of checking code
quality and compatibility, but has its output discarded.
+.It Fl -linker Ar linker
+Specify a link-editor to use in place of
+.Pa /usr/bin/ld .
+.Xr ld 1
+itself arranges for this to be executed by any subprocesses.
.It Fl -noecho
Do not echo the actual command line of any compilers invoked.
.It Fl -versions
@@ -210,7 +216,8 @@ exit status.
.Sh SEE ALSO
.Xr cc 1 ,
.Xr CC 1 ,
-.Xr gcc 1
+.Xr gcc 1 ,
+.Xr ld 1
.Sh BUGS
The translations provided for gcc are not always exact and in some cases
reflect local policy rather than actual equivalence.
diff --git a/usr/src/tools/cw/cw.c b/usr/src/tools/cw/cw.c
index 3763e8298e..31ba40cb85 100644
--- a/usr/src/tools/cw/cw.c
+++ b/usr/src/tools/cw/cw.c
@@ -39,7 +39,7 @@
*/
/* If you modify this file, you must increment CW_VERSION */
-#define CW_VERSION "4.0"
+#define CW_VERSION "5.0"
/*
* -# Verbose mode
@@ -306,6 +306,7 @@ typedef struct {
typedef struct cw_ictx {
struct cw_ictx *i_next;
cw_compiler_t *i_compiler;
+ char *i_linker;
struct aelist *i_ae;
uint32_t i_flags;
int i_oldargc;
@@ -423,7 +424,7 @@ newae(struct aelist *ael, const char *arg)
{
struct ae *ae;
- if ((ae = calloc(sizeof (*ae), 1)) == NULL)
+ if ((ae = calloc(1, sizeof (*ae))) == NULL)
nomem();
ae->ae_arg = strdup(arg);
if (ael->ael_tail == NULL)
@@ -437,9 +438,9 @@ newae(struct aelist *ael, const char *arg)
static cw_ictx_t *
newictx(void)
{
- cw_ictx_t *ctx = calloc(sizeof (cw_ictx_t), 1);
+ cw_ictx_t *ctx = calloc(1, sizeof (cw_ictx_t));
if (ctx)
- if ((ctx->i_ae = calloc(sizeof (struct aelist), 1)) == NULL) {
+ if ((ctx->i_ae = calloc(1, sizeof (struct aelist))) == NULL) {
free(ctx);
return (NULL);
}
@@ -495,7 +496,7 @@ Xsmode(struct aelist *h)
}
static void
-usage()
+usage(void)
{
extern char *__progname;
(void) fprintf(stderr,
@@ -1209,14 +1210,6 @@ do_gcc(cw_ictx_t *ctx)
/* Just ignore -YS,... for now */
if (strncmp(arg, "S,", 2) == 0)
break;
- if (strncmp(arg, "l,", 2) == 0) {
- char *s = strdup(arg);
- s[0] = '-';
- s[1] = 'B';
- newae(ctx->i_ae, s);
- free(s);
- break;
- }
if (strncmp(arg, "I,", 2) == 0) {
char *s = strdup(arg);
s[0] = '-';
@@ -1468,6 +1461,14 @@ prepctx(cw_ictx_t *ctx)
(void) fflush(stdout);
}
+ /*
+ * If LD_ALTEXEC is already set, the expectation would be that that
+ * link-editor is run, as such we need to leave it the environment
+ * alone and let that happen.
+ */
+ if ((ctx->i_linker != NULL) && (getenv("LD_ALTEXEC") == NULL))
+ setenv("LD_ALTEXEC", ctx->i_linker, 1);
+
if (!(ctx->i_flags & CW_F_XLATE))
return;
@@ -1727,6 +1728,7 @@ main(int argc, char **argv)
static struct option longopts[] = {
{ "compiler", no_argument, NULL, 'c' },
+ { "linker", required_argument, NULL, 'l' },
{ "noecho", no_argument, NULL, 'n' },
{ "primary", required_argument, NULL, 'p' },
{ "shadow", required_argument, NULL, 's' },
@@ -1746,6 +1748,10 @@ main(int argc, char **argv)
case 'C':
Cflg = B_TRUE;
break;
+ case 'l':
+ if ((main_ctx->i_linker = strdup(optarg)) == NULL)
+ nomem();
+ break;
case 'n':
nflg = B_TRUE;
break;
diff --git a/usr/src/tools/findunref/exception_list.open b/usr/src/tools/findunref/exception_list.open
index a1c421cceb..6c432c78c1 100644
--- a/usr/src/tools/findunref/exception_list.open
+++ b/usr/src/tools/findunref/exception_list.open
@@ -143,7 +143,6 @@
# Ignore internal packages, scripts, and tools that are intentionally not
# built or used during a nightly.
#
-./usr/src/cmd/sgs/packages
./usr/src/cmd/sgs/rtld.4.x
./usr/src/prototypes
./usr/src/cmd/pools/poold/com/sun/solaris/*/*/package.html
diff --git a/usr/src/tools/make/bin/Makefile b/usr/src/tools/make/bin/Makefile
index 28c51177bd..fcbcb3c7d1 100644
--- a/usr/src/tools/make/bin/Makefile
+++ b/usr/src/tools/make/bin/Makefile
@@ -30,7 +30,6 @@ OBJS= ar.o \
read2.o \
rep.o \
state.o
-SRCS=$(OBJS:%.o:$(CMDDIR)/%.cc)
include ../../Makefile.tools
include ../Makefile.com
diff --git a/usr/src/tools/make/lib/makestate/Makefile.com b/usr/src/tools/make/lib/makestate/Makefile.com
index 1bf0d1d89a..338cdf7a27 100644
--- a/usr/src/tools/make/lib/makestate/Makefile.com
+++ b/usr/src/tools/make/lib/makestate/Makefile.com
@@ -18,6 +18,7 @@ VERS = .1
OBJECTS = ld_file.o lock.o
include $(SRC)/lib/Makefile.lib
+include $(SRC)/tools/Makefile.tools
include ../../../Makefile.com
LIBS = $(DYNLIB)
diff --git a/usr/src/tools/sgs/Makefile b/usr/src/tools/sgs/Makefile
new file mode 100644
index 0000000000..cd407f0709
--- /dev/null
+++ b/usr/src/tools/sgs/Makefile
@@ -0,0 +1,39 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2019, Richard Lowe.
+
+SUBDIRS = \
+ include \
+ ld \
+ libconv \
+ libelf \
+ libld \
+ liblddbg \
+ sgsmsg
+
+all := TARGET= install
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+
+ld: sgsmsg include libconv libelf libld
+libconv: sgsmsg include
+libelf: sgsmsg include
+libld: sgsmsg libelf libconv liblddbg include
+liblddbg: sgsmsg libconv include
+
+all install clean clobber: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/tools/sgs/Makefile.com b/usr/src/tools/sgs/Makefile.com
new file mode 100644
index 0000000000..e3be3840f7
--- /dev/null
+++ b/usr/src/tools/sgs/Makefile.com
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2019, Richard Lowe.
+
+include $(SRC)/cmd/sgs/Makefile.com
+
+NATIVE_CPPFLAGS = -I. -I$(SRCDIR) -I$(SRCDIR)/common \
+ -I$(SGSHOME)/include -I$(SGSHOME)/include/$(MACH) \
+ -I../include $(CPPFLAGS.native) -I$(ELFCAP) -DNATIVE_BUILD
diff --git a/usr/src/tools/sgs/include/Makefile b/usr/src/tools/sgs/include/Makefile
new file mode 100644
index 0000000000..e97e7564b3
--- /dev/null
+++ b/usr/src/tools/sgs/include/Makefile
@@ -0,0 +1,68 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2019, Richard Lowe.
+
+include ../../../Makefile.master
+
+#
+# To build a proper 'tools' version of the link-editor is not possible, as
+# we'll always depend on the ELF-related headers from the workspace, not the
+# system.
+#
+# We pull in the minimum amount of headers using an explicit list of "ELF-y"
+# headers to populate this directory, which we then search while building.
+#
+# This may not be enough on all occasions, judgement must be used to decide
+# between providing extra headers, and wrapping problematic code in conditions
+# on NATIVE_BUILD for a period of time.
+#
+
+ROOTHDRS= dlfcn.h \
+ gelf.h \
+ libelf.h \
+ proc_service.h \
+ rtld_db.h \
+ link.h
+
+SYSHDRS= sys/elf.h \
+ sys/elf_386.h \
+ sys/elf_SPARC.h \
+ sys/elf_notes.h \
+ sys/elf_amd64.h \
+ sys/elftypes.h \
+ sys/auxv.h \
+ sys/auxv_SPARC.h \
+ sys/auxv_386.h \
+ sys/avl.h \
+ sys/link.h \
+ sys/machelf.h \
+ sys/note.h \
+ sys/systeminfo.h
+
+sys:
+ $(MKDIR) -p sys
+
+%: $(SRC)/head/%
+ $(INS.file)
+
+sys/%: sys $(SRC)/uts/common/sys/%
+ $(INS.file)
+
+all install: $(SYSHDRS) $(ROOTHDRS)
+
+clean:
+
+clobber: clean
+ $(RM) $(SYSHDRS) $(ROOTHDRS)
+
+
+
diff --git a/usr/src/tools/sgs/ld/Makefile b/usr/src/tools/sgs/ld/Makefile
new file mode 100644
index 0000000000..fc802dea0e
--- /dev/null
+++ b/usr/src/tools/sgs/ld/Makefile
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 (c) 1996 by Sun Microsystems, Inc.
+# All rights reserved.
+
+include ../Makefile.com
+include ../../Makefile.tools
+include $(SGSHOME)/ld/Makefile.com
+
+LDLIBS = -L../libconv -L$(ROOTONBLDLIBMACH) -lld -lelf -lconv
+CPPFLAGS = $(NATIVE_CPPFLAGS)
+CFLAGS = $(NATIVE_CFLAGS)
+MAPFILES = $(SRCDIR)/common/mapfile-intf
+CW_LINKER =
+VAR_LD_LLDFLAGS= '-R$$ORIGIN/../../lib/$(MACH)'
+VAR_LD_LLDFLAGS64 = '-R$$ORIGIN/../../../lib/$(MACH64)'
+
+install: $(ROOTONBLDMACHPROG)
+
+.KEEP_STATE:
+
+include $(SGSHOME)/ld/Makefile.targ
diff --git a/usr/src/tools/sgs/libconv/Makefile b/usr/src/tools/sgs/libconv/Makefile
new file mode 100644
index 0000000000..a4423c8304
--- /dev/null
+++ b/usr/src/tools/sgs/libconv/Makefile
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+#
+
+include ../Makefile.com
+include $(SGSHOME)/libconv/Makefile.com
+
+CPPFLAGS = $(NATIVE_CPPFLAGS) -I$(SRC)/lib/libc/inc -I$(ELFCAP) \
+ -I$(SRC)/common/sgsrtcid \
+ -I$(SRC)/lib/libdemangle/common
+CFLAGS = $(NATIVE_CFLAGS)
+CW_LINKER =
+
+.PARALLEL: $(PICS)
+.KEEP_STATE:
+
+install all: $(LIBRARY)
+
+include $(SGSHOME)/libconv/Makefile.targ
+
diff --git a/usr/src/tools/sgs/libelf/Makefile b/usr/src/tools/sgs/libelf/Makefile
new file mode 100644
index 0000000000..2ee8dfeb48
--- /dev/null
+++ b/usr/src/tools/sgs/libelf/Makefile
@@ -0,0 +1,48 @@
+#
+# 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 (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.tools
+include $(SGSHOME)/libelf/Makefile.com
+
+CONVLIBDIR = -L../libconv
+CPPFLAGS = $(NATIVE_CPPFLAGS)
+CFLAGS = $(NATIVE_CFLAGS)
+SGSMSGTARG += $(SGSMSG32)
+CW_LINKER =
+
+.KEEP_STATE:
+
+install: all $(ROOTONBLDLIBMACH)/$(DYNLIB) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+
+$(ROOTONBLDLIBMACH)/$(DYNLIB): $(PICS) $(ROOTONBLDLIBMACH)
+ $(BUILD.SO)
+ $(POST_PROCESS_SO)
+
+$(ROOTONBLDLIBMACH)/$(LIBLINKS): $(ROOTONBLDLIBMACH)/$(DYNLIB)
+ @$(RM) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+ $(SYMLINK) $(DYNLIB) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+
+include $(SGSHOME)/libelf/Makefile.targ
diff --git a/usr/src/tools/sgs/libld/Makefile b/usr/src/tools/sgs/libld/Makefile
new file mode 100644
index 0000000000..bc5ebb73e8
--- /dev/null
+++ b/usr/src/tools/sgs/libld/Makefile
@@ -0,0 +1,56 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+include ../../Makefile.tools
+include $(SGSHOME)/libld/Makefile.com
+
+.KEEP_STATE:
+
+CW_LINKER =
+
+CPPFLAGS = $(NATIVE_CPPFLAGS) -DUSE_LIBLD_MALLOC -I$(SRC)/lib/libc/inc \
+ -I$(SRC)/uts/common/krtld -I$(SRC)/uts/sparc \
+ $(VAR_LIBLD_CPPFLAGS)
+LDLIBS += -L$(ROOTONBLDLIBMACH) -L../libconv -lconv -llddbg -lelf -lc
+
+DYNFLAGS += $(VERSREF) '-R$$ORIGIN'
+CFLAGS = $(NATIVE_CFLAGS)
+
+all: $(DYNLIB) $(LIBLINKS)
+
+install: all $(ROOTONBLDLIBMACH)/$(DYNLIB) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+
+$(ROOTONBLDLIBMACH)/$(DYNLIB): $(PICS) $(ROOTONBLDLIBMACH)
+ $(BUILD.SO)
+ $(POST_PROCESS_SO)
+
+$(ROOTONBLDLIBMACH)/$(LIBLINKS): $(ROOTONBLDLIBMACH)/$(DYNLIB)
+ @$(RM) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+ $(SYMLINK) $(DYNLIB) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+
+include $(SGSHOME)/libld/Makefile.targ
diff --git a/usr/src/tools/sgs/liblddbg/Makefile b/usr/src/tools/sgs/liblddbg/Makefile
new file mode 100644
index 0000000000..f2bdd55c81
--- /dev/null
+++ b/usr/src/tools/sgs/liblddbg/Makefile
@@ -0,0 +1,51 @@
+#
+# 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.
+#
+
+include ../Makefile.com
+include ../../Makefile.tools
+include $(SGSHOME)/liblddbg/Makefile.com
+
+.KEEP_STATE:
+
+CPPFLAGS = $(NATIVE_CPPFLAGS) -I$(SRC)/lib/libc/inc
+CFLAGS = $(NATIVE_CFLAGS)
+DYNFLAGS += -L../libconv
+SGSMSGTARG += $(SGSMSG32)
+CW_LINKER=
+
+all: $(DYNLIB) $(LIBLINKS)
+
+install: all $(ROOTONBLDLIBMACH)/$(DYNLIB) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+
+$(ROOTONBLDLIBMACH)/$(DYNLIB): $(PICS) $(ROOTONBLDLIBMACH)
+ $(BUILD.SO)
+ $(POST_PROCESS_SO)
+
+$(ROOTONBLDLIBMACH)/$(LIBLINKS): $(ROOTONBLDLIBMACH)/$(DYNLIB)
+ @$(RM) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+ $(SYMLINK) $(DYNLIB) $(ROOTONBLDLIBMACH)/$(LIBLINKS)
+
+include $(SGSHOME)/liblddbg/Makefile.targ
diff --git a/usr/src/tools/sgs/sgsmsg/Makefile b/usr/src/tools/sgs/sgsmsg/Makefile
new file mode 100644
index 0000000000..e808245030
--- /dev/null
+++ b/usr/src/tools/sgs/sgsmsg/Makefile
@@ -0,0 +1,79 @@
+#
+# 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 (c) 2018, Joyent, Inc.
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+
+#
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Makefile to support tools used for linker development:
+#
+# o sgsmsg creates message headers/arrays/catalogs (a native tool).
+#
+# Note, these tools are not part of the product.
+#
+
+include ../Makefile.com
+include ../../Makefile.tools
+include $(SRC)/cmd/Makefile.cmd
+
+
+PROG= sgsmsg
+
+MAN1ONBLDFILES = sgsmsg.1onbld
+$(ROOTONBLDMAN1ONBLDFILES) := FILEMODE= 644
+
+OBJS= assfail.o \
+ avl.o \
+ findprime.o \
+ sgsmsg.o \
+ string_table.o
+
+FILEMODE= 0755
+
+CPPFLAGS = $(NATIVE_CPPFLAGS)
+CFLAGS = $(NATIVE_CFLAGS)
+CW_LINKER =
+
+# not linted
+SMATCH= off
+
+all: $(PROG)
+
+install: $(ROOTONBLDMACHPROG) $(ROOTONBLDMAN1ONBLDFILES)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+
+%.o: $(SGSCOMMON)/%.c
+ $(NATIVECC) $(DEBUG) $(NATIVE_CFLAGS) $(CPPFLAGS) -c $<
+
+avl.o: $(SRC)/common/avl/avl.c
+ $(NATIVECC) $(DEBUG) $(NATIVE_CFLAGS) $(CPPFLAGS) -c \
+ $(SRC)/common/avl/avl.c
+
+clean:
+ $(RM) $(OBJS)
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/tools/sgs/sgsmsg/sgsmsg.1onbld b/usr/src/tools/sgs/sgsmsg/sgsmsg.1onbld
new file mode 100644
index 0000000000..abd8d3b318
--- /dev/null
+++ b/usr/src/tools/sgs/sgsmsg/sgsmsg.1onbld
@@ -0,0 +1,426 @@
+.\" Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+.\" Use is subject to license terms.
+.\"
+.\" CDDL HEADER START
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License, Version 1.0 only
+.\" (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
+.\"
+.if n .tr \--
+.TH sgsmsg 1ONBLD "Jun 2, 1999"
+.SH NAME
+sgsmsg \- generate message strings for SGS subsystem.
+.SH SYNOPSIS
+.B sgsmsg
+[
+.B \-cl
+] [
+.BI \-d\0 "data"
+] [
+.BI \-h\0 "defs"
+] [
+.BI \-i\0 "ident"
+]
+.if n .ti +5n
+[
+.BI \-m\0 "messages"
+] [
+.BI \-n\0 "name"
+]
+.I file \.\.\.
+.SH AVAILABILITY
+SUNWonld
+.SH DESCRIPTION
+\f3sgsmsg\f1 generates several message files from an input string definition
+\f2file\f1. \f3sgsmsg\f1 provides a flexible, centralized, mechanism
+of collecting character strings within a code group such as an executable or
+shared object. All character strings are captured into a single data array
+within the \f2data\f1 file.
+The data array is similar to that produced by
+.BR xstr (1)),
+and helps reduce the relocation overhead incurred by string pointers.
+.LP
+Indexes into the data array are generated as
+definitions within the \f2defs\f1 file. The code group can reference each
+character string via predefined macros.
+.LP
+The character strings may also be translated into an internationalized
+format and captured in the
+\f2messages\f1 file. By default these message strings are suitable for
+.BR gettext (3I)
+manipulation. The \f3\-c\f1 option provides for these message strings to be
+translated into a form suitable for
+.BR catgets (3C)
+manipulation.
+.SH OPERANDS
+One of more input \f2file\f1s contains a definition for each character
+string used by a particular code group. The interpretation of a
+definition is determined by the first character of each line within
+the input \f2file\f1:
+.LP
+.PD 0
+.RS +4
+.IP \(bu 3
+Entries that begin with a \f3#\fI, \f3$\f1 or a newline are treated as
+comments and are copied (as is) to the \f2messages\f1 file.
+.IP \(bu 3
+Entries that begin with a \f3@\f1 are translated and will be written to
+one or more of the output files. Two translations are possible dependent upon
+whether one or more tokens follow the \f3@\f1 character.
+.RE
+.PD
+.sp
+.LP
+An \f4@\f1 character followed by a single token is interpreted as one of
+two reserved message output
+\f2indicators\f1, or a message \f2identifier\f1. The reserved output
+indicator \f4_START_\f1 enables output to the \f2messages\f1 file (note that
+the occurrence of any \f4@\f1 token will also enable message output).
+The reserved output indicator \f4_END_\f1 disables output to the
+\f2messages\f1 file. These two indicators provides a means of isolating
+only those character strings that require translation into the \f2messages\f1
+file.
+.LP
+Besides the reserved output indicators, an \f4@\f1 character followed by a
+single token is taken to be a
+message \f2identifier\f1. This identifier will be translated into a
+\f2domain\f1 name for
+.BR gettext (3I)
+output, or a \f2setid\f1 for
+.BR catgets (3C)
+output. This translated value is determine by substituting the message
+\f2identifier\f1 token
+for the associated definition from in the \f2ident\f1 file. Note that
+a message \f2identifier\f1 is required for
+.BR catgets (3C)
+use but is optional for
+.BR gettext (3I).
+.LP
+An \f4@\f1 character followed by multiple tokens is taken to be a
+string \f2definition\f1 followed by a quoted character string. Character
+strings can be continued over multiple lines by ending the preceding
+line with a backslash - all initial whitespace on the continuation line will
+is ignored. Character strings can contain the escape sequences
+.B \en
+for newline,
+.B \et
+for tab,
+.B \ev
+for vertical tab,
+.B \eb
+for backspace,
+.B \er
+for carriage return,
+.B \ef
+for formfeed,
+.B \e\e
+for backslash, and
+\e"
+for double quote.
+.LP
+The character string is copied to the \f2data\f1 array
+and an index into this array is generated as the \f2definition\f1 within
+the string
+\f2defs\f1 file. The character string is also translated to the appropriate
+message format and written to the \f2messages\f1 file.
+.SH OPTIONS
+.TP 12
+.B \-c
+By default, strings generated in the \f2messages\f1 file are suitable for
+.BR msgfmt (1)
+processing, which provides for message extraction via
+.BR gettext (3I).
+This option causes the formatting of the message strings to be suitable for
+.BR gencat (1)
+processing, which provides for message extraction via
+.BR catgets (3C).
+.TP
+.BI \-d\0 data
+Specify a \f2data\f1 file is to be created.
+This file contains a single data array, by default named (\f2__name\f1[]),
+containing all the strings
+defined in the string definition \f2file\f1.
+.TP
+.BI \-h\0 defs
+Specify a \f2defs\f1 file is to be created.
+This file contains definitions for each character string contained in
+the data array within the \f2data\f1 file. These definitions represent
+offsets in the data array for each string. Reference to individual strings
+should use one of the two defined macros \f4MSG_INTL\f1 (which specifies
+a user defined message extraction function), or \f4MSG_ORIG\f1
+(which specifies a direct access to the \f2__name\f1[] array).
+.TP
+.BI \-i\0 ident
+Specify an \f2ident\f1 file from which to interpret a message identifier
+token.
+.TP
+.B \-l
+Indicate that the \f2data\f1 array be defined local (\f2static\f1). This
+is useful for establishing individual string arrays on a per-object basis.
+.TP
+.BI \-m\0 messages
+Specify a \f2messages\f1 file is to be created. This
+contain message strings suitable for delivery to a localization group.
+.TP
+.BI \-n\0 name
+Specify an alternative interface \f2name\f1. This name is used to label
+the message data array (\f2__name\f1[]) and the user defined message
+extraction function (const char * \f2_name\f1(int)) which will interface
+with this array.
+.SH EXAMPLES
+The following examples provide a simplified guide to using the \f3sgsmsg\fP
+command, including sample input files and generated output files.
+.LP
+The following \f2ident\f1 file provides message \f2identifiers\f1 for
+the link-editor utilities
+.BR ld (1),
+.BR libld.so.2 ,
+and
+.BR liblddbg.so.3 .
+These identifiers are referenced from the input string definition files
+of the respective code groups:
+.if n .ta 1.8i 2.2i
+.if t .ta 1.6i 2.2i
+.RS
+.nf
+.ft 3
+
+% cat sgs.ident
+.ft 1
+.if t .sp 0.35
+.if n .sp
+# mesgid setid domain
+.if t .sp 0.35
+.if n .sp
+MSG_ID_LD 1 SUNW_OST_SGS
+MSG_ID_LIBLD 2 SUNW_OST_SGS
+MSG_ID_LIBLDDBG 3 SUNW_OST_SGS
+
+.fi
+.RE
+.if t .bp
+.LP
+The following string definition \f2file\f1 defines a small number of
+strings used by
+.BR libld.so.2 :
+.ta 2.2i
+.RS
+.nf
+.ft 3
+
+% cat libld.msg
+.ft 1
+.if t .sp 0.35
+.if n .sp
+@ _START_
+.if t .sp 0.35
+.if n .sp
+# Message file for cmd/sgs/libld.
+.if t .sp 0.35
+.if n .sp
+@ MSG_ID_LIBLD
+
+# System call messages
+.if t .sp 0.35
+.if n .sp
+@ MSG_SYS_OPEN "file %s: cannot open file: %s"
+@ MSG_SYS_MMAP "file %s: cannot mmap file: %s"
+
+# Symbol processing errors
+.if t .sp 0.35
+.if n .sp
+@ MSG_SYM_DIFFTYPE "symbol `%s' has differing types:"
+@ MSG_SYM_DIFFATTR "symbol `%s' has differing %s:\\n\\
+ \ \\t(file %s value=0x%x; file %s value=0x%x);"
+.if t .sp 0.35
+.if n .sp
+@ _END_
+
+# The following strings represent reserved names. Reference to
+# these strings is via the MSG_ORIG() macro, and thus no
+# translations are required.
+.if t .sp 0.35
+.if n .sp
+@ MSG_STR_EMPTY ""
+@ MSG_PTH_DEVZERO "/dev/zero"
+@ MSG_SUNW_OST_SGS "SUNW_OST_SGS"
+
+.fi
+.RE
+.LP
+Using the above input files, the following string and message data files can be
+generated:
+.if t .ta 0.5i 2.2i
+.if n .ta 0.5i 0.8i 3.0i
+.RS
+.nf
+.ft 3
+
+% sgsmsg\ \ \-i sgs.ident\ \ \-m\ messages\ \ \-d\ msg.c\ \ \-h\ msg.h \\
+\ \ \ \ \-n\ libld_msg\ \ libld.msg
+% cat msg.c
+.ft 1
+.if t .sp 0.35
+.if n .sp
+const char __libld_msg[] = { 0x00,
+ 0x66, 0x69, 0x6c, 0x65, 0x20, 0x25, 0x73, 0x3a, \.\.\.\.
+ 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, \.\.\.\.
+ \.\.\.\.
+ 0x00
+};
+
+.if t .bp
+.ft 3
+% cat msg.h
+.ft 1
+.if t .sp 0.35
+.if n .sp
+extern const char __libld_msg[];
+.if t .sp 0.35
+.if n .sp
+#define MSG_ORIG(x) &__libld_msg[x]
+.if t .sp 0.35
+.if n .sp
+extern const char * _libld_msg(int);
+.if t .sp 0.35
+.if n .sp
+#define MSG_INTL(x) _libld_msg(x)
+.if t .sp 0.35
+.if n .sp
+#define MSG_SYS_OPEN 1
+#define MSG_SYS_MMAP 31
+#define MSG_SYM_DIFFTYPE 61
+#define MSG_SYM_DIFFATTR 94
+#define MSG_STR_EMPTY 167
+#define MSG_PTH_DEVZERO 168
+#define MSG_SUNW_OST_SGS 178
+
+.ft 3
+% cat messages
+.ft 1
+.if t .sp 0.35
+.if n .sp
+# Message file for cmd/sgs/libld.
+.if t .sp 0.35
+.if n .sp
+domain "SUNW_OST_SGS"
+.if t .sp 0.35
+.if n .sp
+# System call messages
+.if t .sp 0.35
+.if n .sp
+msgid "file %s: cannot open file: %s"
+msgstr ""
+msgid "file %s: cannot mmap file: %s"
+msgstr ""
+.if t .sp 0.35
+.if n .sp
+# Symbol processing errors
+.if t .sp 0.35
+.if n .sp
+msgid "symbol `%s' has differing types:"
+msgstr ""
+msgid "symbol `%s' has differing %s:\\n\\t(file %s value=0x%x; file %s value=0x%x);"
+msgstr ""
+
+.fi
+.RE
+.LP
+References to the string data from the code group
+should use one of the two defined macros
+depending upon whether an original or localized string is required.
+For example, the simple
+.BR open (2)
+of a file would use the original string, however its associated
+error message should be localized:
+.if n .ta 0.75i
+.if t .ta 0.5i 2.2i
+.RS
+.nf
+.ft 3
+
+const char * file = MSG_ORIG(MSG_PTH_DEVZERO);
+.if t .sp 0.35
+.if n .sp
+if ((fd = open(file, O_RDWR, 0)) == -1) {
+ int err = errno;
+ (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), file,
+ strerror(err));
+ return (1);
+}
+
+.fi
+.RE
+.if t .bp
+.LP
+The \f3MSG_INTL\f1 definition provides for a user defined message
+extraction function
+that allows the greatest flexibility in providing an objects localization.
+Normally this interface is quite simple. For a code group that resides
+in a shared object the following interface can be provided by the user:
+.RS
+.nf
+.ft 3
+
+extern char * _dgettext(const char *, const char *);
+.if t .sp 0.35
+.if n .sp
+const char *
+_libld_msg(int mid)
+{
+ return (_dgettext(MSG_ORIG(MSG_SUNW_OST_SGS),
+ MSG_ORIG(mid)));
+}
+
+.fi
+.RE
+.LP
+For a code group that resides in an executable the following interface,
+and initialization can be provided by the user:
+.RS
+.nf
+.ft 3
+
+#include <locale.h>
+
+int
+main(int argc, char ** argv)
+{
+ \&\.\.\.\.\.\.
+ (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
+ (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
+ \&\.\.\.\.\.\.
+}
+
+const char *
+_ld_msg(int mid)
+{
+ return (gettext(MSG_ORIG(mid)));
+}
+.RE
+.sp
+.SH "EXIT STATUS"
+A non-zero error return indicates a processing error.
+.PD
+.SH "SEE ALSO"
+.BR gencat (1),
+.BR ld (1),
+.BR msgfmt (1),
+.BR catgets (3C),
+.BR gettext (3C).
+.if n .tr \-\-
diff --git a/usr/src/tools/sgs/sgsmsg/sgsmsg.c b/usr/src/tools/sgs/sgsmsg/sgsmsg.c
new file mode 100644
index 0000000000..203a7569a5
--- /dev/null
+++ b/usr/src/tools/sgs/sgsmsg/sgsmsg.c
@@ -0,0 +1,1237 @@
+/*
+ * 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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * sgsmsg generates several message files from an input template file. Messages
+ * are constructed for use with gettext(3i) - the default - or catgets(3c). The
+ * files generate are:
+ *
+ * msg.h a header file containing definitions for each message. The -h
+ * option triggers the creation of these definitions and specifies
+ * the name to use.
+ *
+ * msg.c a data array of message strings. The msg.h definitions are
+ * offsets into this array. The -d option triggers the creation of
+ * these definitions and specifies the name to use.
+ *
+ * messages a message file suitable for catgets(3c) or gettext(3i) use. The
+ * -m option triggers this output and specifies the filename to be
+ * used.
+ *
+ * The template file is processed based on the first character of each line:
+ *
+ * # or $ entries are copied (as is) to the message file (messages).
+ *
+ * @ token(s) entries are translated. Two translations are possible dependent
+ * on whether one or more tokens are supplied:
+ *
+ * A single token is interpreted as one of two reserved message
+ * output indicators, or a message identifier. The reserved output
+ * indicator _START_ enables output to the message file - Note that
+ * the occurance of any other @ token will also enable message
+ * output. The reserved output indicator _END_ disables output to
+ * the message file. The use of these two indicators provides for
+ * only those message strings that require translation to be output
+ * to the message file.
+ *
+ * Besides the reserved output indicators, a single token is taken
+ * to be a message identifier which will be subsituted for a
+ * `setid' for catgets(3c) output, or a `domain' name for
+ * gettext(3i) output. This value is determine by substituting the
+ * token for the associated definition found in the message
+ * identifier file (specified with the -i option).
+ *
+ * Multiple tokens are taken to be a message definition followed by
+ * the associated message string. The message string is copied to
+ * the data array being built in msg.c. The index into this array
+ * becomes the `message' identifier created in the msg.h file.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include <sgs.h>
+#include <_string_table.h>
+
+/*
+ * Define any error message strings.
+ */
+static const char
+ * Errmsg_malt = "sgsmsg: file %s: line %d: malformed input "
+ "at line\n",
+ * Errmsg_nmem = "sgsmsg: memory allocation failed: %s\n",
+ * Errmsg_opne = "sgsmsg: file %s: open failed: %s\n",
+ * Errmsg_wrte = "sgsmsg: file %s: write failed: %s\n",
+ * Errmsg_read = "sgsmsg: file %s: read failed %s\n",
+ * Errmsg_stnw = "sgsmsg: st_new(): failed: %s\n",
+ * Errmsg_stin = "sgsmsg: Str_tbl insert failed: %s\n",
+ * Errmsg_mnfn = "sgsmsg: message not found in Str_tbl: %s\n",
+ * Errmsg_use = "usage: sgsmsg [-clv] [-d mesgdata] [-h mesgdefs] "
+ "[-m messages] [-n name] [-i mesgident] file ...\n";
+
+/*
+ * Define all output filenames and associated descriptors.
+ */
+static FILE *fddefs, *fddata, *fdmsgs, *fdmids, *fddesc;
+static char *fldefs, *fldata, *flmsgs, *flmids, *fldesc;
+static FILE *fdlint;
+static char fllint[MAXPATHLEN];
+
+static uint_t vflag; /* verbose flag */
+static Str_tbl *stp; /* string table */
+
+/*
+ * Define any default strings.
+ */
+static const char
+ *nmlint = "/tmp/sgsmsg.lint",
+ *interface = "sgs_msg",
+ *start = "_START_",
+ *end = "_END_";
+
+/*
+ * Define any default flags and data items.
+ */
+static int cflag = 0, lflag = 0, prtmsgs = 0, line, ptr = 1, msgid = 0;
+static char *mesgid = 0, *setid = 0, *domain = 0;
+
+typedef struct msg_string {
+ char *ms_defn;
+ char *ms_message;
+ struct msg_string *ms_next;
+} msg_string;
+
+static msg_string *msg_head;
+static msg_string *msg_tail;
+
+/*
+ * message_append() is responsible for both inserting strings into
+ * the master Str_tbl as well as maintaining a list of the
+ * DEFINITIONS associated with each string.
+ *
+ * The list of strings is traversed at the end once the full
+ * Str_tbl has been constructed - and string offsets can be
+ * assigned.
+ */
+static void
+message_append(const char *defn, const char *message)
+{
+ msg_string *msg;
+ if ((msg = calloc(sizeof (msg_string), 1)) == 0) {
+ (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * Initialize the string table.
+ */
+ if ((stp == 0) && ((stp = st_new(FLG_STNEW_COMPRESS)) == NULL)) {
+ (void) fprintf(stderr, Errmsg_stnw, strerror(errno));
+ exit(1);
+ }
+
+
+ if ((msg->ms_defn = strdup(defn)) == 0) {
+ (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
+ exit(1);
+ }
+ if ((msg->ms_message = strdup(message)) == 0) {
+ (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
+ exit(1);
+ }
+
+ if (st_insert(stp, msg->ms_message) == -1) {
+ (void) fprintf(stderr, Errmsg_stin,
+ message);
+ exit(1);
+ }
+
+ if (msg_head == 0) {
+ msg_head = msg_tail = msg;
+ return;
+ }
+ msg_tail->ms_next = msg;
+ msg_tail = msg;
+}
+
+/*
+ * Initialize a setid value. Given a setid definition determine its numeric
+ * value from the specified message identifier file (specified with the -i
+ * option). Return a pointer to the numeric string.
+ */
+static int
+getmesgid(char *id)
+{
+ char *buffer, *token, *_mesgid = 0, *_setid = 0, *_domain = 0;
+
+ /*
+ * If we're being asked to interpret a message id but the user didn't
+ * provide the required message identifier file (-i option) we're in
+ * trouble.
+ */
+ if (flmids == 0) {
+ (void) fprintf(stderr, "sgsmsg: file %s: line %d: mesgid %s: "
+ "unable to process mesgid\n\t"
+ "no message identifier file specified "
+ "(see -i option)\n", fldesc, line, id);
+ return (1);
+ }
+
+ if ((buffer = malloc(LINE_MAX)) == 0) {
+ (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Read the message identifier file and locate the required mesgid.
+ */
+ rewind(fdmids);
+ while (fgets(buffer, LINE_MAX, fdmids) != NULL) {
+ if ((token = strstr(buffer, id)) == NULL)
+ continue;
+
+ /*
+ * Establish individual strings for the mesgid, setid and domain
+ * values.
+ */
+ _mesgid = token;
+ while (!(isspace(*token)))
+ token++;
+ *token++ = 0;
+
+ while (isspace(*token))
+ token++;
+ _setid = token;
+ while (!(isspace(*token)))
+ token++;
+ *token++ = 0;
+
+ while (isspace(*token))
+ token++;
+ _domain = token;
+ while (!(isspace(*token)))
+ token++;
+ *token = 0;
+ break;
+ }
+
+ /*
+ * Did we find a match?
+ */
+ if ((_mesgid == 0) || (_setid == 0) || (_domain == 0)) {
+ (void) fprintf(stderr, "sgsmsg: file %s: line %d: mesgid %s: "
+ "unable to process mesgid\n\t"
+ "identifier does not exist in file %s\n",
+ fldesc, line, id, flmids);
+ return (1);
+ }
+
+ /*
+ * Have we been here before?
+ */
+ if (mesgid) {
+ if (cflag == 1) {
+ /*
+ * If we're being asked to process more than one mesgid
+ * warn the user that only one mesgid can be used for
+ * the catgets(3c) call.
+ */
+ (void) fprintf(stderr, "sgsmsg: file %s: line %d: "
+ "setid %s: warning: multiple mesgids "
+ "encountered\n\t"
+ "last setting used in messaging code\n",
+ fldesc, line, id);
+ }
+ }
+
+ mesgid = _mesgid;
+ setid = _setid;
+ domain = _domain;
+
+ /*
+ * Generate the message file output (insure output flag is enabled).
+ */
+ if (prtmsgs != -1)
+ prtmsgs = 1;
+ if (fdmsgs && (prtmsgs == 1)) {
+ if (cflag == 1) {
+ if (fprintf(fdmsgs, "$quote \"\n$set %s\n",
+ setid) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ } else {
+ if (fprintf(fdmsgs, "domain\t\"%s\"\n", domain) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ }
+ }
+
+ /*
+ * For catgets(3c) output generate a setid definition in the message
+ * definition file.
+ */
+ if (fddefs && (cflag == 1) &&
+ (fprintf(fddefs, "#define\t%s\t%s\n\n", mesgid, setid) < 0)) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Dump contents of String Table to standard out
+ */
+static void
+dump_stringtab(Str_tbl *stp)
+{
+ uint_t cnt;
+
+ if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) {
+ (void) printf("string table full size: %ld: uncompressed\n",
+ stp->st_fullstrsize);
+ return;
+ }
+
+ (void) printf("string table full size: %ld compressed down to: %ld\n\n",
+ stp->st_fullstrsize, stp->st_strsize);
+ (void) printf("string table compression information [%d buckets]:\n",
+ stp->st_hbckcnt);
+
+ for (cnt = 0; cnt < stp->st_hbckcnt; cnt++) {
+ Str_hash *sthash = stp->st_hashbcks[cnt];
+
+ if (sthash == 0)
+ continue;
+
+ (void) printf(" bucket: [%d]\n", cnt);
+
+ while (sthash) {
+ size_t stroff = sthash->hi_mstr->sm_strlen -
+ sthash->hi_strlen;
+
+ if (stroff == 0) {
+ (void) printf(" [%ld]: '%s' <master>\n",
+ sthash->hi_refcnt, sthash->hi_mstr->sm_str);
+ } else {
+ (void) printf(" [%ld]: '%s' <suffix of: "
+ "'%s'>\n", sthash->hi_refcnt,
+ &sthash->hi_mstr->sm_str[stroff],
+ sthash->hi_mstr->sm_str);
+ }
+ sthash = sthash->hi_next;
+ }
+ }
+}
+
+/*
+ * Initialize the message definition header file stream.
+ */
+static int
+init_defs(void)
+{
+ static char guard[FILENAME_MAX + 6];
+ char *optr;
+ const char *iptr, *_ptr;
+
+ /*
+ * Establish a header guard name using the files basename.
+ */
+ for (iptr = 0, _ptr = fldefs; _ptr && (*_ptr != '\0'); _ptr++) {
+ if (*_ptr == '/')
+ iptr = _ptr + 1;
+ }
+ if (iptr == 0)
+ iptr = fldefs;
+
+ optr = guard;
+ for (*optr++ = '_'; iptr && (*iptr != '\0'); iptr++, optr++) {
+ if (*iptr == '.') {
+ *optr++ = '_';
+ *optr++ = 'D';
+ *optr++ = 'O';
+ *optr++ = 'T';
+ *optr = '_';
+ } else
+ *optr = toupper(*iptr);
+ }
+
+ if (fprintf(fddefs, "#ifndef\t%s\n#define\t%s\n\n", guard, guard) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ if (fprintf(fddefs, "#include <sgsmsg.h>\t/* Msg typedef */\n\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ if (fprintf(fddefs, "#ifndef\t__lint\n\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ /*
+ * The MSG_SGS_ARRAY_NAME macro supplies a generic way to
+ * reference the string table regardless of its name.
+ */
+ if (fprintf(fddefs, "#define\tMSG_SGS_LOCAL_ARRAY\t__%s\n\n",
+ interface) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ /*
+ * If the associated data array is global define a prototype.
+ * Define a macro to access the array elements.
+ */
+ if (lflag == 0) {
+ if (fprintf(fddefs, "extern\tconst char\t__%s[];\n\n",
+ interface) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs,
+ strerror(errno));
+ return (1);
+ }
+ }
+ if (fprintf(fddefs,
+ "#define\tMSG_ORIG_STRTAB(_x, _s)\t&_s[_x]\n\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+ if (fprintf(fddefs,
+ "#define\tMSG_ORIG(x)\tMSG_ORIG_STRTAB(x, __%s)\n\n",
+ interface) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Generate a prototype to access the associated data array.
+ */
+ if (fprintf(fddefs, "extern\tconst char *\t_%s(Msg);\n\n",
+ interface) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+ if (fprintf(fddefs, "#define\tMSG_INTL(x)\t_%s(x)\n\n",
+ interface) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Finish the message definition header file.
+ */
+static int
+fini_defs(void)
+{
+ if (fprintf(fddefs, "\n#else\t/* __lint */\n\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ if (fprintf(fddefs, "extern\tconst char *\t_%s(Msg);\n\n",
+ interface) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ if (fprintf(fddefs, "#ifndef MSG_SGS_LOCAL_ARRAY\n"
+ "#define\tMSG_SGS_LOCAL_ARRAY\t\"\"\n#endif\n\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ if (lflag == 0) {
+ if (fprintf(fddefs, "extern\tconst char\t__%s[];\n\n",
+ interface) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs,
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (fprintf(fddefs,
+ "#define MSG_ORIG_STRTAB(_x, _s)\t_x\n"
+ "#define MSG_ORIG(x)\tx\n#define MSG_INTL(x)\tx\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Provide a way to get the array and function declarations above
+ * without also getting the actual messages. This is useful in
+ * our lintsup.c files that include more than one message header.
+ * lintsup doesn't need the actual messages, and this prevents
+ * macro name collisions.
+ */
+ if (fprintf(fddefs, "\n#ifndef LINTSUP_SUPPRESS_STRINGS\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Copy the temporary lint defs file into the new header.
+ */
+ if (fdlint) {
+ long size;
+ char *buf;
+
+ size = ftell(fdlint);
+ (void) rewind(fdlint);
+
+ if ((buf = malloc(size)) == 0) {
+ (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
+ return (1);
+ }
+ if (fread(buf, size, 1, fdlint) == 0) {
+ (void) fprintf(stderr, Errmsg_read, fllint,
+ strerror(errno));
+ return (1);
+ }
+ if (fwrite(buf, size, 1, fddefs) == 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs,
+ strerror(errno));
+ return (1);
+ }
+ (void) free(buf);
+ }
+
+ if (fprintf(fddefs, "\n#endif\t/* LINTSUP_SUPPRESS_STRINGS */\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ if (fprintf(fddefs, "\n#endif\t/* __lint */\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ if (fprintf(fddefs, "\n#endif\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * The entire messaging file has been scanned - and all strings have been
+ * inserted into the string_table. We can now walk the message queue
+ * and create the '#define <DEFN>' for each string - with the strings
+ * assigned offset into the string_table.
+ */
+static int
+output_defs(void)
+{
+ msg_string *msg;
+ size_t stbufsize;
+ char *stbuf;
+
+ stbufsize = st_getstrtab_sz(stp);
+ if ((stbuf = malloc(stbufsize)) == 0) {
+ (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
+ exit(1);
+ }
+ (void) st_setstrbuf(stp, stbuf, stbufsize);
+ for (msg = msg_head; msg; msg = msg->ms_next) {
+ size_t stoff;
+ if ((st_setstring(stp, msg->ms_message, &stoff)) == -1) {
+ (void) fprintf(stderr, Errmsg_mnfn, msg->ms_message);
+ return (1);
+ }
+ if (fprintf(fddefs, "\n#define\t%s\t%ld\n",
+ msg->ms_defn, stoff) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fldefs, strerror(errno));
+ return (1);
+ }
+ if (fddefs && fprintf(fddefs, "#define\t%s_SIZE\t%d\n",
+ msg->ms_defn, strlen(msg->ms_message)) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fldefs, strerror(errno));
+ return (1);
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * Finish off the data structure definition.
+ */
+static int
+output_data(void)
+{
+ size_t stbufsize;
+ size_t ndx;
+ size_t column = 1;
+ const char *stbuf;
+ const char *fmtstr;
+
+ stbufsize = st_getstrtab_sz(stp);
+ stbuf = st_getstrbuf(stp);
+
+ assert(stbuf);
+
+ /*
+ * Determine from the local flag whether the data declaration should
+ * be static.
+ */
+ if (lflag)
+ fmtstr = (const char *)"static const";
+ else
+ fmtstr = (const char *)"const";
+
+ if (fprintf(fddata, "\n%s char __%s[%ld] __attribute__((unused)) = { ",
+ fmtstr, interface, stbufsize) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldata, strerror(errno));
+ return (1);
+ }
+
+ for (ndx = 0; ndx < (stbufsize - 1); ndx++) {
+ if (column == 1) {
+ if (fddata && fprintf(fddata,
+ "\n/* %4ld */ 0x%.2x,", ndx,
+ (unsigned char)stbuf[ndx]) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fldata, strerror(errno));
+ return (1);
+ }
+ } else {
+ if (fddata && fprintf(fddata, " 0x%.2x,",
+ (unsigned char)stbuf[ndx]) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fldata, strerror(errno));
+ return (1);
+ }
+ }
+
+ if (column++ == 10)
+ column = 1;
+ }
+
+ if (column == 1)
+ fmtstr = "\n\t0x%.2x };\n";
+ else
+ fmtstr = " 0x%.2x };\n";
+
+ if (fprintf(fddata, fmtstr, (unsigned char)stbuf[stbufsize - 1]) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, fldata, strerror(errno));
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+file()
+{
+ char buffer[LINE_MAX], * token;
+ uint_t bufsize;
+ char *token_buffer;
+ int escape = 0;
+ int len = 0;
+
+ if ((token_buffer = malloc(LINE_MAX)) == 0) {
+ (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
+ return (1);
+ }
+ bufsize = LINE_MAX;
+
+ line = 1;
+
+ while ((token = fgets(buffer, LINE_MAX, fddesc)) != NULL) {
+ char defn[PATH_MAX], * _defn, * str;
+
+ switch (*token) {
+ case '#':
+ case '$':
+ if (escape) {
+ (void) fprintf(stderr, Errmsg_malt, fldesc,
+ line);
+ return (1);
+ }
+
+ /*
+ * If a msgid has been output a msgstr must follow
+ * before we digest the new token. A msgid is only set
+ * if fdmsgs is in use.
+ */
+ if (msgid) {
+ msgid = 0;
+ if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ flmsgs, strerror(errno));
+ return (1);
+ }
+ }
+
+ /*
+ * Pass lines directly through to the output message
+ * file.
+ */
+ if (fdmsgs && (prtmsgs == 1)) {
+ char comment;
+
+ if (cflag == 0)
+ comment = '#';
+ else
+ comment = '$';
+
+ if (fprintf(fdmsgs, "%c%s", comment,
+ ++token) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ flmsgs, strerror(errno));
+ return (1);
+ }
+ }
+ break;
+
+ case '@':
+ if (escape) {
+ (void) fprintf(stderr, Errmsg_malt, fldesc,
+ line);
+ return (1);
+ }
+
+ /*
+ * If a msgid has been output a msgstr must follow
+ * before we digest the new token.
+ */
+ if (msgid) {
+ msgid = 0;
+ if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ flmsgs, strerror(errno));
+ return (1);
+ }
+ }
+
+ /*
+ * Determine whether we have one or more tokens.
+ */
+ token++;
+ while (isspace(*token)) /* rid any whitespace */
+ token++;
+ _defn = token; /* definition start */
+ while (!(isspace(*token)))
+ token++;
+ *token++ = 0;
+
+ while (isspace(*token)) /* rid any whitespace */
+ token++;
+
+ /*
+ * Determine whether the single token is one of the
+ * reserved message output delimiters otherwise
+ * translate it as a message identifier.
+ */
+ if (*token == 0) {
+ if (strcmp(_defn, start) == 0)
+ prtmsgs = 1;
+ else if (strcmp(_defn, end) == 0)
+ prtmsgs = -1;
+ else if (getmesgid(_defn) == 1)
+ return (1);
+ break;
+ }
+
+ /*
+ * Multiple tokens are translated by taking the first
+ * token as the message definition, and the rest of the
+ * line as the message itself. A message line ending
+ * with an escape ('\') is expected to be continued on
+ * the next line.
+ */
+ if (prtmsgs != -1)
+ prtmsgs = 1;
+ if (fdmsgs && (prtmsgs == 1)) {
+ /*
+ * For catgets(3c) make sure a message
+ * identifier has been established (this is
+ * normally a domain for gettext(3i), but for
+ * sgsmsg use this could be argued as being
+ * redundent). Also make sure that the message
+ * definitions haven't exceeeded the maximum
+ * value allowed by gencat(1) before generating
+ * any message file entries.
+ */
+ if (cflag == 1) {
+ if (setid == 0) {
+ (void) fprintf(stderr, "file "
+ "%s: no message identifier "
+ "has been established\n",
+ fldesc);
+ return (1);
+ }
+ if (ptr > NL_MSGMAX) {
+ (void) fprintf(stderr, "file "
+ "%s: message definition "
+ "(%d) exceeds allowable "
+ "limit (NL_MSGMAX)\n",
+ fldesc, ptr);
+ return (1);
+ }
+ }
+
+ /*
+ * For catgets(3c) write the definition and the
+ * message string to the message file. For
+ * gettext(3i) write the message string as a
+ * mesgid - indicate a mesgid has been output
+ * so that a msgstr can follow.
+ */
+ if (cflag == 1) {
+ if (fprintf(fdmsgs, "%d\t%s", ptr,
+ token) < 0) {
+ (void) fprintf(stderr,
+ Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ } else {
+ if (fprintf(fdmsgs, "msgid\t\"") < 0) {
+ (void) fprintf(stderr,
+ Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ msgid = 1;
+ }
+ }
+
+ /*
+ * The message itself is a quoted string as this makes
+ * embedding spaces at the start (or the end) of the
+ * string very easy.
+ */
+ if (*token != '"') {
+ (void) fprintf(stderr, Errmsg_malt, fldesc,
+ line);
+ return (1);
+ }
+
+ (void) strcpy(defn, _defn);
+
+ /*
+ * Write the tag to the lint definitions.
+ */
+ if (fdlint) {
+ if (fprintf(fdlint, "\n#define\t%s\t",
+ _defn) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fllint, strerror(errno));
+ return (1);
+ }
+ }
+
+ len = 0;
+
+ /*
+ * Write each character of the message string to the
+ * data array. Translate any escaped characters - use
+ * the same specially recognized characters as defined
+ * by gencat(1).
+ */
+message:
+ if (*token == '"') {
+ if (fdlint &&
+ (fprintf(fdlint, "%c", *token) < 0)) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fllint, strerror(errno));
+ return (1);
+ }
+ token++;
+ }
+ while (*token) {
+ char _token;
+
+ if ((*token == '\\') && (escape == 0)) {
+ escape = 1;
+ if (fdlint && (*(token + 1) != '\n') &&
+ fprintf(fdlint, "%c", *token) < 0) {
+ (void) fprintf(stderr,
+ Errmsg_wrte, fllint,
+ strerror(errno));
+ return (1);
+ }
+ token++;
+ continue;
+ }
+ if (escape) {
+ if (*token == 'n')
+ _token = '\n';
+ else if (*token == 't')
+ _token = '\t';
+ else if (*token == 'v')
+ _token = '\v';
+ else if (*token == 'b')
+ _token = '\b';
+ else if (*token == 'f')
+ _token = '\f';
+ else if (*token == '\\')
+ _token = '\\';
+ else if (*token == '"')
+ _token = '"';
+ else if (*token == '\n')
+ break;
+ else
+ _token = *token;
+
+ if (fdmsgs && (prtmsgs == 1) &&
+ (fprintf(fdmsgs, "\\") < 0)) {
+ (void) fprintf(stderr,
+ Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ } else {
+ /*
+ * If this is the trailing quote then
+ * thats the last of the message string.
+ * Eat up any remaining white space and
+ * unless an escape character is found
+ * terminate the data string with a 0.
+ */
+ /* BEGIN CSTYLED */
+ if (*token == '"') {
+ if (fdlint && (fprintf(fdlint,
+ "%c", *token) < 0)) {
+ (void) fprintf(stderr,
+ Errmsg_wrte, fllint,
+ strerror(errno));
+ return (1);
+ }
+
+ if (fdmsgs && (prtmsgs == 1) &&
+ (fprintf(fdmsgs, "%c",
+ *token) < 0)) {
+ (void) fprintf(stderr,
+ Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+
+ while (*++token) {
+ if (*token == '\n')
+ break;
+ }
+ _token = '\0';
+ } else
+ _token = *token;
+ /* END CSTYLED */
+ }
+
+ if (fdmsgs && (prtmsgs == 1) &&
+ (fprintf(fdmsgs, "%c", *token) < 0)) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ flmsgs, strerror(errno));
+ return (1);
+ }
+
+ if (fdlint && fprintf(fdlint,
+ "%c", *token) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fllint, strerror(errno));
+ return (1);
+ }
+
+ if (len >= bufsize) {
+ bufsize += LINE_MAX;
+ if ((token_buffer = realloc(
+ token_buffer, bufsize)) == 0) {
+ (void) fprintf(stderr,
+ Errmsg_nmem,
+ strerror(errno));
+ return (1);
+ }
+ }
+ token_buffer[len] = _token;
+ ptr++, token++, len++;
+ escape = 0;
+
+ if (_token == '\0')
+ break;
+ }
+
+ /*
+ * After the complete message string has been processed
+ * (including its continuation beyond one line), create
+ * a string size definition.
+ */
+ if (escape == 0) {
+ const char *form = "#define\t%s_SIZE\t%d\n";
+
+ token_buffer[len] = '\0';
+
+ message_append(defn, token_buffer);
+
+ if (fdlint && fprintf(fdlint, form, defn,
+ (len - 1)) < 0) {
+ (void) fprintf(stderr, Errmsg_wrte,
+ fllint, strerror(errno));
+ return (1);
+ }
+ }
+ break;
+
+ default:
+ /*
+ * Empty lines are passed through to the message file.
+ */
+ while (isspace(*token))
+ token++;
+
+ if (*token == 0) {
+ if (msgid || (fdmsgs && (prtmsgs == 1))) {
+ /*
+ * If a msgid has been output a msgstr
+ * must follow before we digest the new
+ * token.
+ */
+ if (msgid) {
+ msgid = 0;
+ str = "msgstr\t\"\"\n\n";
+ } else
+ str = "\n";
+
+ if (fprintf(fdmsgs, str) < 0) {
+ (void) fprintf(stderr,
+ Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ }
+ break;
+ }
+
+ /*
+ * If an escape is in effect then any tokens are taken
+ * to be message continuations.
+ */
+ if (escape) {
+ escape = 0;
+ goto message;
+ }
+
+ (void) fprintf(stderr, "file %s: line %d: invalid "
+ "input does not start with #, $ or @\n", fldesc,
+ line);
+ return (1);
+ }
+ line++;
+ }
+
+ free(token_buffer);
+
+ return (0);
+}
+
+int
+main(int argc, char ** argv)
+{
+ opterr = 0;
+ while ((line = getopt(argc, argv, "cd:h:lm:n:i:v")) != EOF) {
+ switch (line) {
+ case 'c': /* catgets instead of gettext */
+ cflag = 1;
+ break;
+ case 'd': /* new message data filename */
+ fldata = optarg; /* (msg.c is default) */
+ break;
+ case 'h': /* new message defs filename */
+ fldefs = optarg; /* (msg.h is default) */
+ break;
+ case 'i': /* input message ids from */
+ flmids = optarg; /* from this file */
+ break;
+ case 'l': /* define message data arrays */
+ lflag = 1; /* to be local (static) */
+ break;
+ case 'm': /* generate message database */
+ flmsgs = optarg; /* to this file */
+ break;
+ case 'n': /* new data array and func */
+ interface = optarg; /* name (msg is default) */
+ break;
+ case 'v':
+ vflag = 1; /* set verbose flag */
+ break;
+ case '?':
+ (void) fprintf(stderr, Errmsg_use, argv[0]);
+ exit(1);
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Validate the we have been given at least one input file.
+ */
+ if ((argc - optind) < 1) {
+ (void) fprintf(stderr, Errmsg_use);
+ exit(1);
+ }
+
+ /*
+ * Open all the required output files.
+ */
+ if (fldefs) {
+ if ((fddefs = fopen(fldefs, "w+")) == NULL) {
+ (void) fprintf(stderr, Errmsg_opne, fldefs,
+ strerror(errno));
+ return (1);
+ }
+ }
+ if (fldata) {
+ if (fldefs && (strcmp(fldefs, fldata) == 0))
+ fddata = fddefs;
+ else if ((fddata = fopen(fldata, "w+")) == NULL) {
+ (void) fprintf(stderr, Errmsg_opne, fldata,
+ strerror(errno));
+ return (1);
+ }
+ }
+ if (fddefs && fddata) {
+ (void) sprintf(fllint, "%s.%d.XXXXXX", nmlint, (int)getpid());
+ if ((mkstemp(fllint) == -1) ||
+ ((fdlint = fopen(fllint, "w+")) == NULL)) {
+ (void) fprintf(stderr, Errmsg_opne, fllint,
+ strerror(errno));
+ return (1);
+ }
+ }
+ if (flmsgs) {
+ if ((fdmsgs = fopen(flmsgs, "w+")) == NULL) {
+ (void) fprintf(stderr, Errmsg_opne, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ }
+ if (flmids) {
+ if ((fdmids = fopen(flmids, "r")) == NULL) {
+ (void) fprintf(stderr, Errmsg_opne, flmids,
+ strerror(errno));
+ return (1);
+ }
+ }
+
+
+ /*
+ * Initialize the message definition and message data streams.
+ */
+ if (fddefs) {
+ if (init_defs())
+ return (1);
+ }
+
+ /*
+ * Read the input message file, and for each line process accordingly.
+ */
+ for (; optind < argc; optind++) {
+ int err;
+
+ fldesc = argv[optind];
+
+ if ((fddesc = fopen(fldesc, "r")) == NULL) {
+ (void) fprintf(stderr, Errmsg_opne, fldesc,
+ strerror(errno));
+ return (1);
+ }
+ err = file();
+ (void) fclose(fddesc);
+
+ if (err != 0)
+ return (1);
+ }
+
+ /*
+ * If a msgid has been output a msgstr must follow before we end the
+ * file.
+ */
+ if (msgid) {
+ msgid = 0;
+ if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
+ (void) fprintf(stderr, Errmsg_wrte, flmsgs,
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (fdmids)
+ (void) fclose(fdmids);
+ if (fdmsgs)
+ (void) fclose(fdmsgs);
+
+ if (fddefs) {
+ if (output_defs())
+ return (1);
+ }
+
+ /*
+ * Finish off any generated data and header file.
+ */
+ if (fldata) {
+ if (output_data())
+ return (1);
+ }
+ if (fddefs) {
+ if (fini_defs())
+ return (1);
+ }
+
+ if (vflag)
+ dump_stringtab(stp);
+
+ /*
+ * Close up everything and go home.
+ */
+ if (fddata)
+ (void) fclose(fddata);
+ if (fddefs && (fddefs != fddata))
+ (void) fclose(fddefs);
+ if (fddefs && fddata) {
+ (void) fclose(fdlint);
+ (void) unlink(fllint);
+ }
+
+ if (stp)
+ st_destroy(stp);
+
+ return (0);
+}