diff options
Diffstat (limited to 'usr/src/tools')
| -rw-r--r-- | usr/src/tools/Makefile | 11 | ||||
| -rw-r--r-- | usr/src/tools/Makefile.tools | 4 | ||||
| -rw-r--r-- | usr/src/tools/chk4ubin/Makefile | 1 | ||||
| -rw-r--r-- | usr/src/tools/ctf/dwarf/Makefile.com | 3 | ||||
| -rw-r--r-- | usr/src/tools/cw/cw.1onbld | 9 | ||||
| -rw-r--r-- | usr/src/tools/cw/cw.c | 32 | ||||
| -rw-r--r-- | usr/src/tools/findunref/exception_list.open | 1 | ||||
| -rw-r--r-- | usr/src/tools/make/bin/Makefile | 1 | ||||
| -rw-r--r-- | usr/src/tools/make/lib/makestate/Makefile.com | 1 | ||||
| -rw-r--r-- | usr/src/tools/sgs/Makefile | 39 | ||||
| -rw-r--r-- | usr/src/tools/sgs/Makefile.com | 18 | ||||
| -rw-r--r-- | usr/src/tools/sgs/include/Makefile | 68 | ||||
| -rw-r--r-- | usr/src/tools/sgs/ld/Makefile | 41 | ||||
| -rw-r--r-- | usr/src/tools/sgs/libconv/Makefile | 43 | ||||
| -rw-r--r-- | usr/src/tools/sgs/libelf/Makefile | 48 | ||||
| -rw-r--r-- | usr/src/tools/sgs/libld/Makefile | 56 | ||||
| -rw-r--r-- | usr/src/tools/sgs/liblddbg/Makefile | 51 | ||||
| -rw-r--r-- | usr/src/tools/sgs/sgsmsg/Makefile | 79 | ||||
| -rw-r--r-- | usr/src/tools/sgs/sgsmsg/sgsmsg.1onbld | 426 | ||||
| -rw-r--r-- | usr/src/tools/sgs/sgsmsg/sgsmsg.c | 1237 |
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); +} |
