diff options
Diffstat (limited to 'text-utils')
34 files changed, 10216 insertions, 0 deletions
diff --git a/text-utils/LICENSE.pg b/text-utils/LICENSE.pg new file mode 100644 index 0000000..e805a31 --- /dev/null +++ b/text-utils/LICENSE.pg @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2000-2001 Gunnar Ritter. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. [deleted] + * 4. Neither the name of Gunnar Ritter nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/text-utils/Makefile.am b/text-utils/Makefile.am new file mode 100644 index 0000000..dec895b --- /dev/null +++ b/text-utils/Makefile.am @@ -0,0 +1,33 @@ +include $(top_srcdir)/config/include-Makefile.am + +EXTRA_DIST = README.clear README.col + +usrbin_exec_PROGRAMS = col colcrt colrm column hexdump rev line tailf + +hexdump_SOURCES = hexdump.c conv.c display.c hexsyntax.c odsyntax.c parse.c \ + hexdump.h + +dist_man_MANS = col.1 colcrt.1 colrm.1 column.1 hexdump.1 rev.1 line.1 tailf.1 + +if HAVE_NCURSES +bin_PROGRAMS = more +usrbin_exec_PROGRAMS += ul pg +if HAVE_TINFO +more_LDADD = -ltinfo +pg_LDADD = -ltinfo @NCURSES_LIBS@ +ul_LDADD = -ltinfo +else +more_LDADD = @NCURSES_LIBS@ +pg_LDADD = @NCURSES_LIBS@ +ul_LDADD = @NCURSES_LIBS@ +endif +dist_man_MANS += ul.1 more.1 pg.1 +else +if HAVE_TERMCAP +bin_PROGRAMS = more +more_LDADD = -ltermcap +dist_man_MANS += more.1 +endif +endif + +EXTRA_DIST += README.pg LICENSE.pg diff --git a/text-utils/Makefile.in b/text-utils/Makefile.in new file mode 100644 index 0000000..892c8d6 --- /dev/null +++ b/text-utils/Makefile.in @@ -0,0 +1,802 @@ +# Makefile.in generated by automake 1.11 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = $(am__dist_noinst_DATA_DIST) $(dist_man_MANS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/config/include-Makefile.am +usrbin_exec_PROGRAMS = col$(EXEEXT) colcrt$(EXEEXT) colrm$(EXEEXT) \ + column$(EXEEXT) hexdump$(EXEEXT) rev$(EXEEXT) line$(EXEEXT) \ + tailf$(EXEEXT) $(am__EXEEXT_1) +@HAVE_NCURSES_FALSE@@HAVE_TERMCAP_TRUE@bin_PROGRAMS = more$(EXEEXT) +@HAVE_NCURSES_TRUE@bin_PROGRAMS = more$(EXEEXT) +@HAVE_NCURSES_TRUE@am__append_1 = ul pg +@HAVE_NCURSES_TRUE@am__append_2 = ul.1 more.1 pg.1 +@HAVE_NCURSES_FALSE@@HAVE_TERMCAP_TRUE@am__append_3 = more.1 +subdir = text-utils +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/tls.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(usrbin_execdir)" \ + "$(DESTDIR)$(man1dir)" +@HAVE_NCURSES_TRUE@am__EXEEXT_1 = ul$(EXEEXT) pg$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(usrbin_exec_PROGRAMS) +col_SOURCES = col.c +col_OBJECTS = col.$(OBJEXT) +col_LDADD = $(LDADD) +colcrt_SOURCES = colcrt.c +colcrt_OBJECTS = colcrt.$(OBJEXT) +colcrt_LDADD = $(LDADD) +colrm_SOURCES = colrm.c +colrm_OBJECTS = colrm.$(OBJEXT) +colrm_LDADD = $(LDADD) +column_SOURCES = column.c +column_OBJECTS = column.$(OBJEXT) +column_LDADD = $(LDADD) +am_hexdump_OBJECTS = hexdump.$(OBJEXT) conv.$(OBJEXT) \ + display.$(OBJEXT) hexsyntax.$(OBJEXT) odsyntax.$(OBJEXT) \ + parse.$(OBJEXT) +hexdump_OBJECTS = $(am_hexdump_OBJECTS) +hexdump_LDADD = $(LDADD) +line_SOURCES = line.c +line_OBJECTS = line.$(OBJEXT) +line_LDADD = $(LDADD) +more_SOURCES = more.c +more_OBJECTS = more.$(OBJEXT) +more_DEPENDENCIES = +pg_SOURCES = pg.c +pg_OBJECTS = pg.$(OBJEXT) +pg_DEPENDENCIES = +rev_SOURCES = rev.c +rev_OBJECTS = rev.$(OBJEXT) +rev_LDADD = $(LDADD) +tailf_SOURCES = tailf.c +tailf_OBJECTS = tailf.$(OBJEXT) +tailf_LDADD = $(LDADD) +ul_SOURCES = ul.c +ul_OBJECTS = ul.$(OBJEXT) +ul_DEPENDENCIES = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = col.c colcrt.c colrm.c column.c $(hexdump_SOURCES) line.c \ + more.c pg.c rev.c tailf.c ul.c +DIST_SOURCES = col.c colcrt.c colrm.c column.c $(hexdump_SOURCES) \ + line.c more.c pg.c rev.c tailf.c ul.c +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man_MANS) +am__dist_noinst_DATA_DIST = col.1 colcrt.1 colrm.1 column.1 hexdump.1 \ + rev.1 line.1 tailf.1 ul.1 more.1 pg.1 +DATA = $(dist_noinst_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLKID = @BLKID@ +BLKID_CFLAGS = @BLKID_CFLAGS@ +BLKID_LIBS = @BLKID_LIBS@ +BLKID_LIBS_STATIC = @BLKID_LIBS_STATIC@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBBLKID_VERSION = @LIBBLKID_VERSION@ +LIBBLKID_VERSION_INFO = @LIBBLKID_VERSION_INFO@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUUID_VERSION = @LIBUUID_VERSION@ +LIBUUID_VERSION_INFO = @LIBUUID_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +NCURSES_LIBS = @NCURSES_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SELINUX_LIBS = @SELINUX_LIBS@ +SELINUX_LIBS_STATIC = @SELINUX_LIBS_STATIC@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SUID_CFLAGS = @SUID_CFLAGS@ +SUID_LDFLAGS = @SUID_LDFLAGS@ +USE_NLS = @USE_NLS@ +UUID_CFLAGS = @UUID_CFLAGS@ +UUID_LIBS = @UUID_LIBS@ +VERSION = @VERSION@ +VOLID = @VOLID@ +XGETTEXT = @XGETTEXT@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libdirname = @libdirname@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +usrbin_execdir = @usrbin_execdir@ +usrlib_execdir = @usrlib_execdir@ +usrsbin_execdir = @usrsbin_execdir@ +AM_CPPFLAGS = -include $(top_builddir)/config.h -I$(top_srcdir)/include \ + -DLOCALEDIR=\"$(localedir)\" + +AM_CFLAGS = -fsigned-char +AM_LDFLAGS = + +# Automake (at least up to 1.10) mishandles dist_man_MANS inside conditionals. +# Unlike with other dist primaries, the files are not distributed if the +# conditional is false. +# Work the bug around until it is fixed: +dist_noinst_DATA = $(dist_man_MANS) + +# Paths to in-tree libraries (use ul_ prefix to avoid possible collisions) +# +# blkid +ul_libblkid_srcdir = $(top_srcdir)/shlibs/blkid/src +ul_libblkid_builddir = $(top_builddir)/shlibs/blkid/src +ul_libblkid_la = $(top_builddir)/shlibs/blkid/src/libblkid.la + +# uuid +ul_libuuid_srcdir = $(top_srcdir)/shlibs/uuid/src +ul_libuuid_builddir = $(top_builddir)/shlibs/uuid/src +ul_libuuid_la = $(top_builddir)/shlibs/uuid/src/libuuid.la +EXTRA_DIST = README.clear README.col README.pg LICENSE.pg +hexdump_SOURCES = hexdump.c conv.c display.c hexsyntax.c odsyntax.c parse.c \ + hexdump.h + +dist_man_MANS = col.1 colcrt.1 colrm.1 column.1 hexdump.1 rev.1 line.1 \ + tailf.1 $(am__append_2) $(am__append_3) +@HAVE_NCURSES_FALSE@@HAVE_TERMCAP_TRUE@more_LDADD = -ltermcap +@HAVE_NCURSES_TRUE@@HAVE_TINFO_FALSE@more_LDADD = @NCURSES_LIBS@ +@HAVE_NCURSES_TRUE@@HAVE_TINFO_TRUE@more_LDADD = -ltinfo +@HAVE_NCURSES_TRUE@@HAVE_TINFO_FALSE@pg_LDADD = @NCURSES_LIBS@ +@HAVE_NCURSES_TRUE@@HAVE_TINFO_TRUE@pg_LDADD = -ltinfo @NCURSES_LIBS@ +@HAVE_NCURSES_TRUE@@HAVE_TINFO_FALSE@ul_LDADD = @NCURSES_LIBS@ +@HAVE_NCURSES_TRUE@@HAVE_TINFO_TRUE@ul_LDADD = -ltinfo +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/config/include-Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign text-utils/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign text-utils/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-usrbin_execPROGRAMS: $(usrbin_exec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(usrbin_execdir)" || $(MKDIR_P) "$(DESTDIR)$(usrbin_execdir)" + @list='$(usrbin_exec_PROGRAMS)'; test -n "$(usrbin_execdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(usrbin_execdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(usrbin_execdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-usrbin_execPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(usrbin_exec_PROGRAMS)'; test -n "$(usrbin_execdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(usrbin_execdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(usrbin_execdir)" && rm -f $$files + +clean-usrbin_execPROGRAMS: + @list='$(usrbin_exec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +col$(EXEEXT): $(col_OBJECTS) $(col_DEPENDENCIES) + @rm -f col$(EXEEXT) + $(LINK) $(col_OBJECTS) $(col_LDADD) $(LIBS) +colcrt$(EXEEXT): $(colcrt_OBJECTS) $(colcrt_DEPENDENCIES) + @rm -f colcrt$(EXEEXT) + $(LINK) $(colcrt_OBJECTS) $(colcrt_LDADD) $(LIBS) +colrm$(EXEEXT): $(colrm_OBJECTS) $(colrm_DEPENDENCIES) + @rm -f colrm$(EXEEXT) + $(LINK) $(colrm_OBJECTS) $(colrm_LDADD) $(LIBS) +column$(EXEEXT): $(column_OBJECTS) $(column_DEPENDENCIES) + @rm -f column$(EXEEXT) + $(LINK) $(column_OBJECTS) $(column_LDADD) $(LIBS) +hexdump$(EXEEXT): $(hexdump_OBJECTS) $(hexdump_DEPENDENCIES) + @rm -f hexdump$(EXEEXT) + $(LINK) $(hexdump_OBJECTS) $(hexdump_LDADD) $(LIBS) +line$(EXEEXT): $(line_OBJECTS) $(line_DEPENDENCIES) + @rm -f line$(EXEEXT) + $(LINK) $(line_OBJECTS) $(line_LDADD) $(LIBS) +more$(EXEEXT): $(more_OBJECTS) $(more_DEPENDENCIES) + @rm -f more$(EXEEXT) + $(LINK) $(more_OBJECTS) $(more_LDADD) $(LIBS) +pg$(EXEEXT): $(pg_OBJECTS) $(pg_DEPENDENCIES) + @rm -f pg$(EXEEXT) + $(LINK) $(pg_OBJECTS) $(pg_LDADD) $(LIBS) +rev$(EXEEXT): $(rev_OBJECTS) $(rev_DEPENDENCIES) + @rm -f rev$(EXEEXT) + $(LINK) $(rev_OBJECTS) $(rev_LDADD) $(LIBS) +tailf$(EXEEXT): $(tailf_OBJECTS) $(tailf_DEPENDENCIES) + @rm -f tailf$(EXEEXT) + $(LINK) $(tailf_OBJECTS) $(tailf_LDADD) $(LIBS) +ul$(EXEEXT): $(ul_OBJECTS) $(ul_DEPENDENCIES) + @rm -f ul$(EXEEXT) + $(LINK) $(ul_OBJECTS) $(ul_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/col.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/colcrt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/colrm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/column.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/display.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hexdump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hexsyntax.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/line.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/more.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odsyntax.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rev.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tailf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ul.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(dist_man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list=''; test -n "$(man1dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(usrbin_execdir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-usrbin_execPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-usrbin_execPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-man \ + uninstall-usrbin_execPROGRAMS + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-usrbin_execPROGRAMS ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-man1 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip install-usrbin_execPROGRAMS installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-man uninstall-man1 uninstall-usrbin_execPROGRAMS + + +$(ul_libblkid_la): + $(MAKE) -C $(ul_libblkid_builddir) + +$(ul_libuuid_la): + $(MAKE) -C $(ul_libuuid_builddir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/text-utils/README.clear b/text-utils/README.clear new file mode 100644 index 0000000..7684132 --- /dev/null +++ b/text-utils/README.clear @@ -0,0 +1,7 @@ +RedHat and SuSE take the program clear from ncurses. + A 20KB program equivalent to "tput clear". + +Slackware uses the script. + +So, both versions will behave identically, and +Slackware saves 20 KB. diff --git a/text-utils/README.col b/text-utils/README.col new file mode 100644 index 0000000..2a7dd6c --- /dev/null +++ b/text-utils/README.col @@ -0,0 +1,48 @@ +# @(#)README 5.1 (Berkeley) 5/22/90 + +col - filter out reverse line feeds. + +Options are: + -b do not print any backspaces (last character written is printed) + -f allow half line feeds in output, by default characters between + lines are pushed to the line below + -x do not compress spaces into tabs. + -l num keep (at least) num lines in memory, 128 are kept by default + +In the 32V source code to col(1) the default behavior was to NOT compress +spaces into tabs. There was a -h option which caused it to compress spaces +into tabs. There was no -x flag. + +The 32V documentation, however, was consistent with the SVID (actually, V7 +at the time) and documented a -x flag (as defined above) while making no +mention of a -h flag. Just before 4.3BSD went out, CSRG updated the manual +page to reflect the way the code worked. Suspecting that this was probably +the wrong way to go, this version adopts the SVID defaults, and no longer +documents the -h option. + +The S5 -p flag is not supported because it isn't clear what it does (looks +like a kludge introduced for a particular printer). + +Known differences between AT&T's col and this one (# is delimiter): + Input AT&T col this col + #\nabc\E7def\n# # def\nabc\r# # def\nabc\n# + #a# ## #a\n# + - last line always ends with at least one \n (or \E9) + #1234567 8\n# #1234567\t8\n# #1234567 8\n# + - single space not expanded to tab + -f #a\E8b\n# #ab\n# # b\E9\ra\n# + - can back up past first line (as far as you want) so you + *can* have a super script on the first line + #\E9_\ba\E8\nb\n# #\n_\bb\ba\n# #\n_\ba\bb\n# + - always print last character written to a position, + AT&T col claims to do this but doesn't. + +If a character is to be placed on a line that has been flushed, a warning +is produced (the AT&T col is silent). The -l flag (not in AT&T col) can +be used to increase the number of lines buffered to avoid the problem. + +General algorithm: a limited number of lines are buffered in a linked +list. When a printable character is read, it is put in the buffer of +the current line along with the column it's supposed to be in. When +a line is flushed, the characters in the line are sorted according to +column and then printed. diff --git a/text-utils/README.pg b/text-utils/README.pg new file mode 100644 index 0000000..df92b85 --- /dev/null +++ b/text-utils/README.pg @@ -0,0 +1,23 @@ +README for the "pg" utility for Linux. + +The "pg" utility is the historic System V equivalent to BSD's "more". This +is a free clone of it, and it is intended to conform to the SVID 4 as well +as the SUSv2 specification of this command. + +Contrasting to the System V implementation, this one filters backspace +formatting sequences while searching, so you can comfortably search in nroff +output like manual pages. + +This code uses routines as defined by SUSv2, so a glibc version of 2.1 or +higher is required on Linux. A curses implementation (like ncurses) must +be present as well. + +If large files > 2GB are supported by the kernel and the C library, pg is +able to handle them. + +Please send comments, bug-reports and especially bug-fixes to +<g-r@bigfoot.de> . + +Gunnar Ritter +Freiburg i. Br. +Germany diff --git a/text-utils/col.1 b/text-utils/col.1 new file mode 100644 index 0000000..86afba3 --- /dev/null +++ b/text-utils/col.1 @@ -0,0 +1,141 @@ +.\" Copyright (c) 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Michael Rendell. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)col.1 6.8 (Berkeley) 6/17/91 +.\" +.Dd June 17, 1991 +.Dt COL 1 +.Os +.Sh NAME +.Nm col +.Nd filter reverse line feeds from input +.Sh SYNOPSIS +.Nm col +.Op Fl bfpx +.Op Fl l Ar num +.Sh DESCRIPTION +.Nm Col +filters out reverse (and half reverse) line feeds so the output is +in the correct order with only forward and half forward line +feeds, and replaces white-space characters with tabs where possible. +This can be useful in processing the output of +.Xr nroff 1 +and +.Xr tbl 1 . +.Pp +.Nm Col +reads from standard input and writes to standard output. +.Pp +The options are as follows: +.Bl -tag -width "-lnum" +.It Fl b +Do not output any backspaces, printing only the last character +written to each column position. +.It Fl f +Forward half line feeds are permitted (``fine'' mode). +Normally characters printed on a half line boundary are printed +on the following line. +.It Fl p +Force unknown control sequences to be passed through unchanged. +Normally, +.Nm col +will filter out any control sequences from the input other than those +recognized and interpreted by itself, which are listed below. +.It Fl x +Output multiple spaces instead of tabs. +.It Fl l Ns Ar num +Buffer at least +.Ar num +lines in memory. +By default, 128 lines are buffered. +.El +.Pp +The control sequences for carriage motion that +.Nm col +understands and their decimal values are listed in the following +table: +.Pp +.Bl -tag -width "carriage return" -compact +.It ESC\-7 +reverse line feed (escape then 7) +.It ESC\-8 +half reverse line feed (escape then 8) +.It ESC\-9 +half forward line feed (escape then 9) +.It backspace +moves back one column (8); ignored in the first column +.It carriage return +(13) +.It newline +forward line feed (10); also does carriage return +.It shift in +shift to normal character set (15) +.It shift out +shift to alternate character set (14) +.It space +moves forward one column (32) +.It tab +moves forward to next tab stop (9) +.It vertical tab +reverse line feed (11) +.El +.Pp +All unrecognized control characters and escape sequences are +discarded. +.Pp +.Nm Col +keeps track of the character set as characters are read and makes +sure the character set is correct when they are output. +.Pp +If the input attempts to back up to the last flushed line, +.Nm col +will display a warning message. +.Sh SEE ALSO +.Xr expand 1 , +.Xr nroff 1 , +.Xr tbl 1 +.Sh STANDARDS +The +.Nm col +utility conforms to the Single UNIX Specification, Version 2. The +.Fl l +option is an extension to the standard. +.Sh HISTORY +A +.Nm col +command +appeared in Version 6 AT&T UNIX. +.Sh AVAILABILITY +The col command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/col.c b/text-utils/col.c new file mode 100644 index 0000000..3b81a89 --- /dev/null +++ b/text-utils/col.c @@ -0,0 +1,559 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Rendell of the Memorial University of Newfoundland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Wed Jun 22 22:15:41 1994, faith@cs.unc.edu: Added internationalization + * patches from Andries.Brouwer@cwi.nl + * Wed Sep 14 22:31:17 1994: patches from Carl Christofferson + * (cchris@connected.com) + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * added Native Language Support + * 1999-09-19 Bruno Haible <haible@clisp.cons.org> + * modified to work correctly in multi-byte locales + * + */ + +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "nls.h" + +#include "widechar.h" + +#define BS '\b' /* backspace */ +#define TAB '\t' /* tab */ +#define SPACE ' ' /* space */ +#define NL '\n' /* newline */ +#define CR '\r' /* carriage return */ +#define ESC '\033' /* escape */ +#define SI '\017' /* shift in to normal character set */ +#define SO '\016' /* shift out to alternate character set */ +#define VT '\013' /* vertical tab (aka reverse line feed) */ +#define RLF '\007' /* ESC-07 reverse line feed */ +#define RHLF '\010' /* ESC-010 reverse half-line feed */ +#define FHLF '\011' /* ESC-011 forward half-line feed */ + +/* build up at least this many lines before flushing them out */ +#define BUFFER_MARGIN 32 + +typedef char CSET; + +typedef struct char_str { +#define CS_NORMAL 1 +#define CS_ALTERNATE 2 + short c_column; /* column character is in */ + CSET c_set; /* character set (currently only 2) */ + wchar_t c_char; /* character in question */ + int c_width; /* character width */ +} CHAR; + +typedef struct line_str LINE; +struct line_str { + CHAR *l_line; /* characters on the line */ + LINE *l_prev; /* previous line */ + LINE *l_next; /* next line */ + int l_lsize; /* allocated sizeof l_line */ + int l_line_len; /* strlen(l_line) */ + int l_needs_sort; /* set if chars went in out of order */ + int l_max_col; /* max column in the line */ +}; + +void usage(void); +void wrerr(void); +void warn(int); +void free_line(LINE *l); +void flush_line(LINE *l); +void flush_lines(int); +void flush_blanks(void); +void *xmalloc(void *p, size_t size); +LINE *alloc_line(void); + +CSET last_set; /* char_set of last char printed */ +LINE *lines; +int compress_spaces; /* if doing space -> tab conversion */ +int fine; /* if `fine' resolution (half lines) */ +int max_bufd_lines; /* max # lines to keep in memory */ +int nblank_lines; /* # blanks after last flushed line */ +int no_backspaces; /* if not to output any backspaces */ +int pass_unknown_seqs; /* whether to pass unknown control sequences */ + +#define PUTC(ch) \ + if (putwchar(ch) == WEOF) \ + wrerr(); + +int main(int argc, char **argv) +{ + register wint_t ch; + CHAR *c; + CSET cur_set; /* current character set */ + LINE *l; /* current line */ + int extra_lines; /* # of lines above first line */ + int cur_col; /* current column */ + int cur_line; /* line number of current position */ + int max_line; /* max value of cur_line */ + int this_line; /* line l points to */ + int nflushd_lines; /* number of lines that were flushed */ + int adjust, opt, warned; + int ret = 0; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + max_bufd_lines = 128; + compress_spaces = 1; /* compress spaces into tabs */ + pass_unknown_seqs = 0; /* remove unknown escape sequences */ + while ((opt = getopt(argc, argv, "bfhl:px")) != -1) + switch (opt) { + case 'b': /* do not output backspaces */ + no_backspaces = 1; + break; + case 'f': /* allow half forward line feeds */ + fine = 1; + break; + case 'h': /* compress spaces into tabs */ + compress_spaces = 1; + break; + case 'l': /* buffered line count */ + if ((max_bufd_lines = atoi(optarg)) <= 0) { + (void)fprintf(stderr, + _("col: bad -l argument %s.\n"), optarg); + exit(1); + } + break; + case 'p': + pass_unknown_seqs = 1; + break; + case 'x': /* do not compress spaces into tabs */ + compress_spaces = 0; + break; + case '?': + default: + usage(); + } + + if (optind != argc) + usage(); + + /* this value is in half lines */ + max_bufd_lines *= 2; + + adjust = cur_col = extra_lines = warned = 0; + cur_line = max_line = nflushd_lines = this_line = 0; + cur_set = last_set = CS_NORMAL; + lines = l = alloc_line(); + + while (feof(stdin)==0) { + errno = 0; + if ((ch = getwchar()) == WEOF) { + if (errno==EILSEQ) { + perror("col"); + ret = 1; + } + break; + } + if (!iswgraph(ch)) { + switch (ch) { + case BS: /* can't go back further */ + if (cur_col == 0) + continue; + --cur_col; + continue; + case CR: + cur_col = 0; + continue; + case ESC: /* just ignore EOF */ + switch(getwchar()) { + case RLF: + cur_line -= 2; + break; + case RHLF: + cur_line--; + break; + case FHLF: + cur_line++; + if (cur_line > max_line) + max_line = cur_line; + } + continue; + case NL: + cur_line += 2; + if (cur_line > max_line) + max_line = cur_line; + cur_col = 0; + continue; + case SPACE: + ++cur_col; + continue; + case SI: + cur_set = CS_NORMAL; + continue; + case SO: + cur_set = CS_ALTERNATE; + continue; + case TAB: /* adjust column */ + cur_col |= 7; + ++cur_col; + continue; + case VT: + cur_line -= 2; + continue; + } + if (iswspace(ch)) { + if (wcwidth(ch) > 0) + cur_col += wcwidth(ch); + continue; + } + if (!pass_unknown_seqs) + continue; + } + + /* Must stuff ch in a line - are we at the right one? */ + if (cur_line != this_line - adjust) { + LINE *lnew; + int nmove; + + adjust = 0; + nmove = cur_line - this_line; + if (!fine) { + /* round up to next line */ + if (cur_line & 1) { + adjust = 1; + nmove++; + } + } + if (nmove < 0) { + for (; nmove < 0 && l->l_prev; nmove++) + l = l->l_prev; + if (nmove) { + if (nflushd_lines == 0) { + /* + * Allow backup past first + * line if nothing has been + * flushed yet. + */ + for (; nmove < 0; nmove++) { + lnew = alloc_line(); + l->l_prev = lnew; + lnew->l_next = l; + l = lines = lnew; + extra_lines++; + } + } else { + if (!warned++) + warn(cur_line); + cur_line -= nmove; + } + } + } else { + /* may need to allocate here */ + for (; nmove > 0 && l->l_next; nmove--) + l = l->l_next; + for (; nmove > 0; nmove--) { + lnew = alloc_line(); + lnew->l_prev = l; + l->l_next = lnew; + l = lnew; + } + } + this_line = cur_line + adjust; + nmove = this_line - nflushd_lines; + if (nmove >= max_bufd_lines + BUFFER_MARGIN) { + nflushd_lines += nmove - max_bufd_lines; + flush_lines(nmove - max_bufd_lines); + } + } + /* grow line's buffer? */ + if (l->l_line_len + 1 >= l->l_lsize) { + int need; + + need = l->l_lsize ? l->l_lsize * 2 : 90; + l->l_line = (CHAR *)xmalloc((void *) l->l_line, + (unsigned) need * sizeof(CHAR)); + l->l_lsize = need; + } + c = &l->l_line[l->l_line_len++]; + c->c_char = ch; + c->c_set = cur_set; + c->c_column = cur_col; + c->c_width = wcwidth(ch); + /* + * If things are put in out of order, they will need sorting + * when it is flushed. + */ + if (cur_col < l->l_max_col) + l->l_needs_sort = 1; + else + l->l_max_col = cur_col; + if (c->c_width > 0) + cur_col += c->c_width; + } + /* goto the last line that had a character on it */ + for (; l->l_next; l = l->l_next) + this_line++; + flush_lines(this_line - nflushd_lines + extra_lines + 1); + + /* make sure we leave things in a sane state */ + if (last_set != CS_NORMAL) + PUTC('\017'); + + /* flush out the last few blank lines */ + nblank_lines = max_line - this_line; + if (max_line & 1) + nblank_lines++; + else if (!nblank_lines) + /* missing a \n on the last line? */ + nblank_lines = 2; + flush_blanks(); + if (ferror(stdout) || fclose(stdout)) + return 1; + return ret; +} + +void flush_lines(int nflush) +{ + LINE *l; + + while (--nflush >= 0) { + l = lines; + lines = l->l_next; + if (l->l_line) { + flush_blanks(); + flush_line(l); + } + nblank_lines++; + if (l->l_line) + (void)free((void *)l->l_line); + free_line(l); + } + if (lines) + lines->l_prev = NULL; +} + +/* + * Print a number of newline/half newlines. If fine flag is set, nblank_lines + * is the number of half line feeds, otherwise it is the number of whole line + * feeds. + */ +void flush_blanks() +{ + int half, i, nb; + + half = 0; + nb = nblank_lines; + if (nb & 1) { + if (fine) + half = 1; + else + nb++; + } + nb /= 2; + for (i = nb; --i >= 0;) + PUTC('\n'); + if (half) { + PUTC('\033'); + PUTC('9'); + if (!nb) + PUTC('\r'); + } + nblank_lines = 0; +} + +/* + * Write a line to stdout taking care of space to tab conversion (-h flag) + * and character set shifts. + */ +void flush_line(LINE *l) +{ + CHAR *c, *endc; + int nchars, last_col, this_col; + + last_col = 0; + nchars = l->l_line_len; + + if (l->l_needs_sort) { + static CHAR *sorted; + static int count_size, *count, i, save, sorted_size, tot; + + /* + * Do an O(n) sort on l->l_line by column being careful to + * preserve the order of characters in the same column. + */ + if (l->l_lsize > sorted_size) { + sorted_size = l->l_lsize; + sorted = (CHAR *)xmalloc((void *)sorted, + (unsigned)sizeof(CHAR) * sorted_size); + } + if (l->l_max_col >= count_size) { + count_size = l->l_max_col + 1; + count = (int *)xmalloc((void *)count, + (unsigned)sizeof(int) * count_size); + } + memset(count, 0, sizeof(int) * l->l_max_col + 1); + for (i = nchars, c = l->l_line; --i >= 0; c++) + count[c->c_column]++; + + /* + * calculate running total (shifted down by 1) to use as + * indices into new line. + */ + for (tot = 0, i = 0; i <= l->l_max_col; i++) { + save = count[i]; + count[i] = tot; + tot += save; + } + + for (i = nchars, c = l->l_line; --i >= 0; c++) + sorted[count[c->c_column]++] = *c; + c = sorted; + } else + c = l->l_line; + while (nchars > 0) { + this_col = c->c_column; + endc = c; + do { + ++endc; + } while (--nchars > 0 && this_col == endc->c_column); + + /* if -b only print last character */ + if (no_backspaces) { + c = endc - 1; + if (nchars > 0 && + this_col + c->c_width > endc->c_column) + continue; + } + + if (this_col > last_col) { + int nspace = this_col - last_col; + + if (compress_spaces && nspace > 1) { + int ntabs; + + ntabs = this_col / 8 - last_col / 8; + if (ntabs > 0) { + nspace = this_col & 7; + while (--ntabs >= 0) + PUTC('\t'); + } + } + while (--nspace >= 0) + PUTC(' '); + last_col = this_col; + } + + for (;;) { + if (c->c_set != last_set) { + switch (c->c_set) { + case CS_NORMAL: + PUTC('\017'); + break; + case CS_ALTERNATE: + PUTC('\016'); + } + last_set = c->c_set; + } + PUTC(c->c_char); + if ((c+1) < endc) { + int i; + for (i=0; i < c->c_width; i++) + PUTC('\b'); + } + if (++c >= endc) + break; + } + last_col += (c-1)->c_width; + } +} + +#define NALLOC 64 + +static LINE *line_freelist; + +LINE * +alloc_line() +{ + LINE *l; + int i; + + if (!line_freelist) { + l = (LINE *)xmalloc((void *)NULL, sizeof(LINE) * NALLOC); + line_freelist = l; + for (i = 1; i < NALLOC; i++, l++) + l->l_next = l + 1; + l->l_next = NULL; + } + l = line_freelist; + line_freelist = l->l_next; + + memset(l, 0, sizeof(LINE)); + return(l); +} + +void free_line(LINE *l) +{ + l->l_next = line_freelist; + line_freelist = l; +} + +void * +xmalloc(void *p, size_t size) +{ + if (!(p = (void *)realloc(p, size))) { + (void)fprintf(stderr, "col: %s.\n", strerror(ENOMEM)); + exit(1); + } + return(p); +} + +void usage() +{ + (void)fprintf(stderr, _("usage: col [-bfpx] [-l nline]\n")); + exit(1); +} + +void wrerr() +{ + (void)fprintf(stderr, _("col: write error.\n")); + exit(1); +} + +void warn(int line) +{ + (void)fprintf(stderr, + _("col: warning: can't back up %s.\n"), line < 0 ? + _("past first line") : _("-- line already flushed")); +} diff --git a/text-utils/colcrt.1 b/text-utils/colcrt.1 new file mode 100644 index 0000000..f0eceb5 --- /dev/null +++ b/text-utils/colcrt.1 @@ -0,0 +1,111 @@ +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)colcrt.1 8.1 (Berkeley) 6/30/93 +.\" +.Dd June 30, 1993 +.Dt COLCRT 1 +.Os BSD 3 +.Sh NAME +.Nm colcrt +.Nd filter nroff output for CRT previewing +.Sh SYNOPSIS +.Nm colcrt +.Op Fl +.Op Fl \&2 +.Op Ar +.Sh DESCRIPTION +.Nm Colcrt +provides virtual half-line and reverse line feed sequences +for terminals without such capability, and on which overstriking +is destructive. +Half-line characters and underlining (changed to dashing `\-') +are placed on new lines in between the normal output lines. +.Pp +Available options: +.Bl -tag -width Ds +.It Fl +Suppress all underlining. +This option is especially useful for previewing +.Em allboxed +tables from +.Xr tbl 1 . +.It Fl 2 +Causes all half-lines to be printed, effectively double spacing the output. +Normally, a minimal space output format is used which will suppress empty +lines. +The program never suppresses two consecutive empty lines, however. +The +.Fl 2 +option is useful for sending output to the line printer when the output +contains superscripts and subscripts which would otherwise be invisible. +.El +.Sh EXAMPLES +A typical use of +.Nm colcrt +would be +.Bd -literal +tbl exum2.n \&| nroff \-ms \&| colcrt \- \&| more +.Ed +.Sh SEE ALSO +.Xr nroff 1 , +.Xr troff 1 , +.Xr col 1 , +.Xr more 1 , +.Xr ul 1 +.Sh BUGS +Should fold underlines onto blanks even with the +.Ql Fl +option so that +a true underline character would show. +.Pp +Can't back up more than 102 lines. +.Pp +General overstriking is lost; +as a special case +.Ql \&| +overstruck with +.Ql \- +or underline becomes +.Ql \&+ . +.Pp +Lines are trimmed to 132 characters. +.Pp +Some provision should be made for processing superscripts and subscripts +in documents which are already double-spaced. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . +.Sh AVAILABILITY +The colcrt command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/colcrt.c b/text-utils/colcrt.c new file mode 100644 index 0000000..6f79665 --- /dev/null +++ b/text-utils/colcrt.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * added Native Language Support + * 1999-09-19 Bruno Haible <haible@clisp.cons.org> + * modified to work correctly in multi-byte locales + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> /* for close() */ +#include <string.h> +#include "nls.h" + +#include "widechar.h" + +int plus(wchar_t c, wchar_t d); +void move(int l, int m); +void pflush(int ol); + +/* + * colcrt - replaces col for crts with new nroff esp. when using tbl. + * Bill Joy UCB July 14, 1977 + * + * This filter uses a screen buffer, 267 half-lines by 132 columns. + * It interprets the up and down sequences generated by the new + * nroff when used with tbl and by \u \d and \r. + * General overstriking doesn't work correctly. + * Underlining is split onto multiple lines, etc. + * + * Option - suppresses all underlining. + * Option -2 forces printing of all half lines. + */ + +wchar_t page[267][132]; + +int outline = 1; +int outcol; + +char suppresul; +char printall; + +char *progname; +void colcrt(FILE *f); + +int +main(int argc, char **argv) { + FILE *f; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + argc--; + progname = *argv++; + while (argc > 0 && argv[0][0] == '-') { + switch (argv[0][1]) { + case 0: + suppresul = 1; + break; + case '2': + printall = 1; + break; + default: + printf(_("usage: %s [ - ] [ -2 ] [ file ... ]\n"), progname); + fflush(stdout); + exit(1); + } + argc--; + argv++; + } + f = stdin; + do { + if (argc > 0) { + if (!(f = fopen(argv[0], "r"))) { + fflush(stdout); + perror(argv[0]); + exit (1); + } + argc--; + argv++; + } + colcrt(f); + if (f != stdin) + fclose(f); + } while (argc > 0); + fflush(stdout); + if (ferror(stdout) || fclose(stdout)) + return 1; + return 0; +} + +void +colcrt(FILE *f) { + wint_t c; + wchar_t *cp, *dp; + int i, w; + + for (;;) { + c = getwc(f); + if (c == WEOF) { + pflush(outline); + fflush(stdout); + break; + } + switch (c) { + case '\n': + if (outline >= 265) + pflush(62); + outline += 2; + outcol = 0; + continue; + case '\016': + case '\017': + continue; + case 033: + c = getwc(f); + switch (c) { + case '9': + if (outline >= 266) + pflush(62); + outline++; + continue; + case '8': + if (outline >= 1) + outline--; + continue; + case '7': + outline -= 2; + if (outline < 0) + outline = 0; + continue; + default: + continue; + } + case '\b': + if (outcol) + outcol--; + continue; + case '\t': + outcol += 8; + outcol &= ~7; + outcol--; + c = ' '; + default: + w = wcwidth(c); + if (outcol + w > 132) { + outcol++; + continue; + } + cp = &page[outline][outcol]; + outcol += w; + if (c == '_') { + if (suppresul) + continue; + cp += 132; + c = '-'; + } + if (*cp == 0) { + /* trick! */ + for (i=0; i<w; i++) + cp[i] = c; + dp = cp - (outcol-w); + for (cp--; cp >= dp && *cp == 0; cp--) + *cp = ' '; + } else { + if (plus(c, *cp) || plus(*cp, c)) + *cp = '+'; + else if (*cp == ' ' || *cp == 0) { + for (i=1; i<w; i++) + if (cp[i] != ' ' && cp[i] != 0) + continue; + for (i=0; i<w; i++) + cp[i] = c; + } + } + continue; + } + } +} + +int plus(wchar_t c, wchar_t d) +{ + + return (c == '|' && (d == '-' || d == '_')); +} + +int first; + +void pflush(int ol) +{ + register int i; + register wchar_t *cp; + char lastomit; + int l, w; + + l = ol; + lastomit = 0; + if (l > 266) + l = 266; + else + l |= 1; + for (i = first | 1; i < l; i++) { + move(i, i - 1); + move(i, i + 1); + } + for (i = first; i < l; i++) { + cp = page[i]; + if (printall == 0 && lastomit == 0 && *cp == 0) { + lastomit = 1; + continue; + } + lastomit = 0; + while (*cp) { + if ((w = wcwidth(*cp)) > 0) { + putwchar(*cp); + cp += w; + } else + cp++; + } + putwchar('\n'); + } + memmove(page, page[ol], (267 - ol) * 132 * sizeof(wchar_t)); + memset(page[267- ol], '\0', ol * 132 * sizeof(wchar_t)); + outline -= ol; + outcol = 0; + first = 1; +} + +void move(int l, int m) +{ + register wchar_t *cp, *dp; + + for (cp = page[l], dp = page[m]; *cp; cp++, dp++) { + switch (*cp) { + case '|': + if (*dp != ' ' && *dp != '|' && *dp != 0) + return; + break; + case ' ': + break; + default: + return; + } + } + if (*cp == 0) { + for (cp = page[l], dp = page[m]; *cp; cp++, dp++) + if (*cp == '|') + *dp = '|'; + else if (*dp == 0) + *dp = ' '; + page[l][0] = 0; + } +} diff --git a/text-utils/colrm.1 b/text-utils/colrm.1 new file mode 100644 index 0000000..d02167a --- /dev/null +++ b/text-utils/colrm.1 @@ -0,0 +1,66 @@ +.\" Copyright (c) 1980, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)colrm.1 6.6 (Berkeley) 3/14/91 +.\" +.Dd March 14, 1991 +.Dt COLRM 1 +.Os BSD 3 +.Sh NAME +.Nm colrm +.Nd remove columns from a file +.Sh SYNOPSIS +.Nm colrm +.Op Ar startcol Op Ar endcol +.Sh DESCRIPTION +.Nm Colrm +removes selected columns from a file. Input is taken from standard input. +Output is sent to standard output. +.Pp +If called with one parameter the columns +of each line will be removed starting with the specified column. +If called with two parameters the columns from the first column +to the last column will be removed. +.Pp +Column numbering starts with column 1. +.Sh SEE ALSO +.Xr awk 1 , +.Xr column 1 , +.Xr expand 1 , +.Xr paste 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . +.Sh AVAILABILITY +The colrm command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/colrm.c b/text-utils/colrm.c new file mode 100644 index 0000000..e8b1ea4 --- /dev/null +++ b/text-utils/colrm.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * added Native Language Support + * 1999-09-19 Bruno Haible <haible@clisp.cons.org> + * modified to work correctly in multi-byte locales + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "nls.h" +#include "widechar.h" + +/* +COLRM removes unwanted columns from a file + Jeff Schriebman UC Berkeley 11-74 +*/ + +int +main(int argc, char **argv) +{ + register int ct, first, last; + register wint_t c; + int i, w; + int padding; + + setlocale(LC_ALL, ""); + + first = 0; + last = 0; + if (argc > 1) + first = atoi(*++argv); + if (argc > 2) + last = atoi(*++argv); + +start: + ct = 0; +loop1: + c = getwc(stdin); + if (c == WEOF) + goto fin; + if (c == '\t') + w = ((ct + 8) & ~7) - ct; + else if (c == '\b') + w = (ct ? ct - 1 : 0) - ct; + else { + w = wcwidth(c); + if (w < 0) + w = 0; + } + ct += w; + if (c == '\n') { + putwc(c, stdout); + goto start; + } + if (!first || ct < first) { + putwc(c, stdout); + goto loop1; + } + for (i = ct-w+1; i < first; i++) + putwc(' ', stdout); + +/* Loop getting rid of characters */ + while (!last || ct < last) { + c = getwc(stdin); + if (c == WEOF) + goto fin; + if (c == '\n') { + putwc(c, stdout); + goto start; + } + if (c == '\t') + ct = (ct + 8) & ~7; + else if (c == '\b') + ct = ct ? ct - 1 : 0; + else { + w = wcwidth(c); + if (w < 0) + w = 0; + ct += w; + } + } + + padding = 0; + +/* Output last of the line */ + for (;;) { + c = getwc(stdin); + if (c == WEOF) + break; + if (c == '\n') { + putwc(c, stdout); + goto start; + } + if (padding == 0 && last < ct) { + for (i = last; i <ct; i++) + putwc(' ', stdout); + padding = 1; + } + putwc(c, stdout); + } +fin: + fflush(stdout); + if (ferror(stdout) || fclose(stdout)) + return 1; + return 0; +} diff --git a/text-utils/column.1 b/text-utils/column.1 new file mode 100644 index 0000000..1da59cc --- /dev/null +++ b/text-utils/column.1 @@ -0,0 +1,102 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)column.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Os +.Dt COLUMN 1 +.Sh NAME +.Nm column +.Nd columnate lists +.Sh SYNOPSIS +.Nm column +.Op Fl tx +.Op Fl c Ar columns +.Op Fl s Ar sep +.Op Ar +.Sh DESCRIPTION +The +.Nm column +utility formats its input into multiple columns. +Rows are filled before columns. +Input is taken from +.Ar file +operands, or, by default, from the standard input. +Empty lines are ignored. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl c +Output is formatted for a display +.Ar columns +wide. +.It Fl s +Specify a set of characters to be used to delimit columns for the +.Fl t +option. +.It Fl t +Determine the number of columns the input contains and create a table. +Columns are delimited with whitespace, by default, or with the characters +supplied using the +.Fl s +option. +Useful for pretty-printing displays. +.It Fl x +Fill columns before filling rows. +.El +.Pp +.Nm Column +exits 0 on success, >0 if an error occurred. +.Sh ENVIRONMENT +.Bl -tag -width COLUMNS +.It Ev COLUMNS +The environment variable +.Ev COLUMNS +is used to determine the size of +the screen if no other information is available. +.El +.Sh EXAMPLES +.Dl (printf \&"PERM LINKS OWNER GROUP SIZE MONTH DAY HH:MM/YEAR\ NAME\en\&"\ \&\e +.Dl \&; ls -l \&| sed 1d) \&| column -t +.Sh SEE ALSO +.Xr colrm 1 , +.Xr ls 1 , +.Xr paste 1 , +.Xr sort 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 Reno . +.Sh AVAILABILITY +The column command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/column.c b/text-utils/column.c new file mode 100644 index 0000000..f5d41a2 --- /dev/null +++ b/text-utils/column.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * added Native Language Support + * 1999-09-19 Bruno Haible <haible@clisp.cons.org> + * modified to work correctly in multi-byte locales + */ + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include "nls.h" + +#include "widechar.h" + +#ifdef HAVE_WIDECHAR +#define wcs_width(s) wcswidth(s,wcslen(s)) +static wchar_t *mbs_to_wcs(const char *); +#else +#define wcs_width(s) strlen(s) +#define mbs_to_wcs(s) strdup(s) +static char *mtsafe_strtok(char *, const char *, char **); +#define wcstok mtsafe_strtok +#endif + +static void c_columnate __P((void)); +static void *emalloc __P((int)); +static void input __P((FILE *)); +static void maketbl __P((void)); +static void print __P((void)); +static void r_columnate __P((void)); +static void usage __P((void)); + +int termwidth = 80; /* default terminal width */ + +int entries; /* number of records */ +int eval; /* exit value */ +int maxlength; /* longest record */ +wchar_t **list; /* array of pointers to records */ +wchar_t default_separator[] = { '\t', ' ', 0 }; +wchar_t *separator = default_separator; /* field separator for table option */ + +int +main(int argc, char **argv) +{ + struct winsize win; + FILE *fp; + int ch, tflag, xflag; + char *p; + + extern char *__progname; + __progname = argv[0]; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { + if ((p = getenv("COLUMNS")) != NULL) + termwidth = atoi(p); + } else + termwidth = win.ws_col; + + tflag = xflag = 0; + while ((ch = getopt(argc, argv, "c:s:tx")) != -1) + switch(ch) { + case 'c': + termwidth = atoi(optarg); + break; + case 's': + separator = mbs_to_wcs(optarg); + break; + case 't': + tflag = 1; + break; + case 'x': + xflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!*argv) + input(stdin); + else for (; *argv; ++argv) + if ((fp = fopen(*argv, "r")) != NULL) { + input(fp); + (void)fclose(fp); + } else { + warn("%s", *argv); + eval = 1; + } + + if (!entries) + exit(eval); + + if (tflag) + maketbl(); + else if (maxlength >= termwidth) + print(); + else if (xflag) + c_columnate(); + else + r_columnate(); + if (ferror(stdout) || fclose(stdout)) + eval = 1; + exit(eval); +} + +#define TAB 8 +static void +c_columnate() +{ + int chcnt, col, cnt, endcol, numcols; + wchar_t **lp; + + maxlength = (maxlength + TAB) & ~(TAB - 1); + numcols = termwidth / maxlength; + endcol = maxlength; + for (chcnt = col = 0, lp = list;; ++lp) { + fputws(*lp, stdout); + chcnt += wcs_width(*lp); + if (!--entries) + break; + if (++col == numcols) { + chcnt = col = 0; + endcol = maxlength; + putwchar('\n'); + } else { + while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { + putwchar('\t'); + chcnt = cnt; + } + endcol += maxlength; + } + } + if (chcnt) + putwchar('\n'); +} + +static void +r_columnate() +{ + int base, chcnt, cnt, col, endcol, numcols, numrows, row; + + maxlength = (maxlength + TAB) & ~(TAB - 1); + numcols = termwidth / maxlength; + if (!numcols) + numcols = 1; + numrows = entries / numcols; + if (entries % numcols) + ++numrows; + + for (row = 0; row < numrows; ++row) { + endcol = maxlength; + for (base = row, chcnt = col = 0; col < numcols; ++col) { + fputws(list[base], stdout); + chcnt += wcs_width(list[base]); + if ((base += numrows) >= entries) + break; + while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { + putwchar('\t'); + chcnt = cnt; + } + endcol += maxlength; + } + putwchar('\n'); + } +} + +static void +print() +{ + int cnt; + wchar_t **lp; + + for (cnt = entries, lp = list; cnt--; ++lp) { + fputws(*lp, stdout); + putwchar('\n'); + } +} + +typedef struct _tbl { + wchar_t **list; + int cols, *len; +} TBL; +#define DEFCOLS 25 + +static void +maketbl() +{ + TBL *t; + int coloff, cnt, i; + wchar_t *p, **lp; + int *lens, maxcols; + TBL *tbl; + wchar_t **cols; + wchar_t *wcstok_state; + + t = tbl = emalloc(entries * sizeof(TBL)); + cols = emalloc((maxcols = DEFCOLS) * sizeof(wchar_t *)); + lens = emalloc(maxcols * sizeof(int)); + for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { + for (coloff = 0, p = *lp; + (cols[coloff] = wcstok(p, separator, &wcstok_state)) != NULL; + p = NULL) + if (++coloff == maxcols) { + if (!(cols = realloc(cols, ((u_int)maxcols + DEFCOLS) + * sizeof(wchar_t *))) || + !(lens = realloc(lens, ((u_int)maxcols + DEFCOLS) + * sizeof(int)))) + err(1, NULL); + memset((char *)lens + maxcols * sizeof(int), + 0, DEFCOLS * sizeof(int)); + maxcols += DEFCOLS; + } + t->list = emalloc(coloff * sizeof(wchar_t *)); + t->len = emalloc(coloff * sizeof(int)); + for (t->cols = coloff; --coloff >= 0;) { + t->list[coloff] = cols[coloff]; + t->len[coloff] = wcs_width(cols[coloff]); + if (t->len[coloff] > lens[coloff]) + lens[coloff] = t->len[coloff]; + } + } + for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) { + for (coloff = 0; coloff < t->cols - 1; ++coloff) { + fputws(t->list[coloff], stdout); + for (i = lens[coloff] - t->len[coloff] + 2; i > 0; i--) + putwchar(' '); + } + fputws(t->list[coloff], stdout); + putwchar('\n'); + } +} + +#define DEFNUM 1000 +#define MAXLINELEN (LINE_MAX + 1) + +static void +input(fp) + FILE *fp; +{ + static int maxentry; + int len; + wchar_t *p, buf[MAXLINELEN]; + + if (!list) + list = emalloc((maxentry = DEFNUM) * sizeof(wchar_t *)); + while (fgetws(buf, MAXLINELEN, fp)) { + for (p = buf; *p && iswspace(*p); ++p); + if (!*p) + continue; + if (!(p = wcschr(p, '\n'))) { + warnx(_("line too long")); + eval = 1; + continue; + } + *p = '\0'; + len = wcs_width(buf); /* len = p - buf; */ + if (maxlength < len) + maxlength = len; + if (entries == maxentry) { + maxentry += DEFNUM; + if (!(list = realloc(list, + (u_int)maxentry * sizeof(wchar_t *)))) + err(1, NULL); + } + list[entries++] = wcsdup(buf); + } +} + +#ifdef HAVE_WIDECHAR +static wchar_t *mbs_to_wcs(const char *s) +{ + size_t n; + wchar_t *wcs; + + n = mbstowcs((wchar_t *)0, s, 0); + if (n < 0) + return NULL; + wcs = malloc((n + 1) * sizeof(wchar_t)); + if (!wcs) + return NULL; + if (mbstowcs(wcs, s, n + 1) < 0) + return NULL; + return wcs; +} +#endif + +#ifndef HAVE_WIDECHAR +static char *mtsafe_strtok(char *str, const char *delim, char **ptr) +{ + if (str == NULL) { + str = *ptr; + if (str == NULL) + return NULL; + } + str += strspn(str, delim); + if (*str == '\0') { + *ptr = NULL; + return NULL; + } else { + char *token_end = strpbrk(str, delim); + if (token_end) { + *token_end = '\0'; + *ptr = token_end + 1; + } else + *ptr = NULL; + return str; + } +} +#endif + +static void * +emalloc(size) + int size; +{ + char *p; + + if (!(p = malloc(size))) + err(1, NULL); + memset(p, 0, size); + return (p); +} + +static void +usage() +{ + + (void)fprintf(stderr, + _("usage: column [-tx] [-c columns] [file ...]\n")); + exit(1); +} diff --git a/text-utils/conv.c b/text-utils/conv.c new file mode 100644 index 0000000..8e0efa1 --- /dev/null +++ b/text-utils/conv.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include "hexdump.h" + +void +conv_c(PR *pr, u_char *p) +{ + char buf[10]; + char const *str; + + switch(*p) { + case '\0': + str = "\\0"; + goto strpr; + /* case '\a': */ + case '\007': + if (deprecated) /* od didn't know about \a */ + break; + str = "\\a"; + goto strpr; + case '\b': + str = "\\b"; + goto strpr; + case '\f': + str = "\\f"; + goto strpr; + case '\n': + str = "\\n"; + goto strpr; + case '\r': + str = "\\r"; + goto strpr; + case '\t': + str = "\\t"; + goto strpr; + case '\v': + if (deprecated) + break; + str = "\\v"; + goto strpr; + default: + break; + } + if (isprint(*p)) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, *p); + } else { + (void)sprintf(buf, "%03o", (int)*p); + str = buf; +strpr: *pr->cchar = 's'; + (void)printf(pr->fmt, str); + } +} + +void +conv_u(PR *pr, u_char *p) +{ + static const char *list[] = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs", "ht", "lf", "vt", "ff", "cr", "so", "si", + "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us", + }; + + /* od used nl, not lf */ + if (*p <= 0x1f) { + *pr->cchar = 's'; + if (deprecated && *p == 0x0a) + (void)printf(pr->fmt, "nl"); + else + (void)printf(pr->fmt, list[*p]); + } else if (*p == 0x7f) { + *pr->cchar = 's'; + (void)printf(pr->fmt, "del"); + } else if (deprecated && *p == 0x20) { /* od replaced space with sp */ + *pr->cchar = 's'; + (void)printf(pr->fmt, " sp"); + } else if (isprint(*p)) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, *p); + } else { + *pr->cchar = 'x'; + (void)printf(pr->fmt, (int)*p); + } +} diff --git a/text-utils/display.c b/text-utils/display.c new file mode 100644 index 0000000..91857c2 --- /dev/null +++ b/text-utils/display.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hexdump.h" + +static void doskip(const char *, int); +static u_char *get(void); + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +enum _vflag vflag = FIRST; + +static off_t address; /* address/offset in stream */ +static off_t eaddress; /* end address */ + +static inline void +print(PR *pr, u_char *bp) { + + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (quad_t)address); + break; + case F_BPAD: + (void)printf(pr->fmt, ""); + break; + case F_C: + conv_c(pr, bp); + break; + case F_CHAR: + (void)printf(pr->fmt, *bp); + break; + case F_DBL: + { + double dval; + float fval; + switch(pr->bcnt) { + case 4: + memmove(&fval, bp, sizeof(fval)); + (void)printf(pr->fmt, fval); + break; + case 8: + memmove(&dval, bp, sizeof(dval)); + (void)printf(pr->fmt, dval); + break; + } + break; + } + case F_INT: + { + short sval; /* int16_t */ + int ival; /* int32_t */ + long long Lval; /* int64_t, quad_t */ + + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (quad_t)*bp); + break; + case 2: + memmove(&sval, bp, sizeof(sval)); + (void)printf(pr->fmt, (quad_t)sval); + break; + case 4: + memmove(&ival, bp, sizeof(ival)); + (void)printf(pr->fmt, (quad_t)ival); + break; + case 8: + memmove(&Lval, bp, sizeof(Lval)); + (void)printf(pr->fmt, (quad_t)Lval); + break; + } + break; + } + case F_P: + (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); + break; + case F_STR: + (void)printf(pr->fmt, (char *)bp); + break; + case F_TEXT: + (void)printf("%s", pr->fmt); + break; + case F_U: + conv_u(pr, bp); + break; + case F_UINT: + { + unsigned short sval; /* u_int16_t */ + unsigned int ival; /* u_int32_t */ + unsigned long long Lval;/* u_int64_t, u_quad_t */ + + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (u_quad_t)*bp); + break; + case 2: + memmove(&sval, bp, sizeof(sval)); + (void)printf(pr->fmt, (u_quad_t)sval); + break; + case 4: + memmove(&ival, bp, sizeof(ival)); + (void)printf(pr->fmt, (u_quad_t)ival); + break; + case 8: + memmove(&Lval, bp, sizeof(Lval)); + (void)printf(pr->fmt, (u_quad_t)Lval); + break; + } + break; + } + } +} + +static void bpad(PR *pr) +{ + static const char *spec = " -0+#"; + char *p1, *p2; + + /* + * remove all conversion flags; '-' is the only one valid + * with %s, and it's not useful here. + */ + pr->flags = F_BPAD; + pr->cchar[0] = 's'; + pr->cchar[1] = 0; + for (p1 = pr->fmt; *p1 != '%'; ++p1); + for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1); + while ((*p2++ = *p1++) != 0) ; +} + +void display(void) +{ + register FS *fs; + register FU *fu; + register PR *pr; + register int cnt; + register u_char *bp; + off_t saveaddress; + u_char savech = 0, *savebp; + + while ((bp = get()) != NULL) + for (fs = fshead, savebp = bp, saveaddress = address; fs; + fs = fs->nextfs, bp = savebp, address = saveaddress) + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->flags&F_IGNORE) + break; + for (cnt = fu->reps; cnt; --cnt) + for (pr = fu->nextpr; pr; address += pr->bcnt, + bp += pr->bcnt, pr = pr->nextpr) { + if (eaddress && address >= eaddress && + !(pr->flags&(F_TEXT|F_BPAD))) + bpad(pr); + if (cnt == 1 && pr->nospace) { + savech = *pr->nospace; + *pr->nospace = '\0'; + } + print(pr, bp); + if (cnt == 1 && pr->nospace) + *pr->nospace = savech; + } + } + if (endfu) { + /* + * if eaddress not set, error or file size was multiple of + * blocksize, and no partial block ever found. + */ + if (!eaddress) { + if (!address) + return; + eaddress = address; + } + for (pr = endfu->nextpr; pr; pr = pr->nextpr) + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (quad_t)eaddress); + break; + case F_TEXT: + (void)printf("%s", pr->fmt); + break; + } + } +} + +static char **_argv; + +static u_char * +get(void) +{ + static int ateof = 1; + static u_char *curp, *savp; + int n; + int need, nread; + u_char *tmpp; + + if (!curp) { + curp = emalloc(blocksize); + savp = emalloc(blocksize); + } else { + tmpp = curp; + curp = savp; + savp = tmpp; + address += blocksize; + } + for (need = blocksize, nread = 0;;) { + /* + * if read the right number of bytes, or at EOF for one file, + * and no other files are available, zero-pad the rest of the + * block and set the end flag. + */ + if (!length || (ateof && !next(NULL))) { + if (need == blocksize) + return(NULL); + if (!need && vflag != ALL && + !memcmp(curp, savp, nread)) { + if (vflag != DUP) + (void)printf("*\n"); + return(NULL); + } + if (need > 0) + memset((char *)curp + nread, 0, need); + eaddress = address + nread; + return(curp); + } + n = fread((char *)curp + nread, sizeof(u_char), + length == -1 ? need : MIN(length, need), stdin); + if (!n) { + if (ferror(stdin)) + (void)fprintf(stderr, "hexdump: %s: %s\n", + _argv[-1], strerror(errno)); + ateof = 1; + continue; + } + ateof = 0; + if (length != -1) + length -= n; + if (!(need -= n)) { + if (vflag == ALL || vflag == FIRST || + memcmp(curp, savp, blocksize)) { + if (vflag == DUP || vflag == FIRST) + vflag = WAIT; + return(curp); + } + if (vflag == WAIT) + (void)printf("*\n"); + vflag = DUP; + address += blocksize; + need = blocksize; + nread = 0; + } + else + nread += n; + } +} + +int next(char **argv) +{ + static int done; + int statok; + + if (argv) { + _argv = argv; + return(1); + } + for (;;) { + if (*_argv) { + if (!(freopen(*_argv, "r", stdin))) { + (void)fprintf(stderr, "hexdump: %s: %s\n", + *_argv, strerror(errno)); + exitval = 1; + ++_argv; + continue; + } + statok = done = 1; + } else { + if (done++) + return(0); + statok = 0; + } + if (skip) + doskip(statok ? *_argv : "stdin", statok); + if (*_argv) + ++_argv; + if (!skip) + return(1); + } + /* NOTREACHED */ +} + +static void +doskip(const char *fname, int statok) +{ + struct stat sbuf; + + if (statok) { + if (fstat(fileno(stdin), &sbuf)) { + (void)fprintf(stderr, "hexdump: %s: %s.\n", + fname, strerror(errno)); + exit(1); + } + if (S_ISREG(sbuf.st_mode) && skip >= sbuf.st_size) { + /* If size valid and skip >= size */ + skip -= sbuf.st_size; + address += sbuf.st_size; + return; + } + } + /* sbuf may be undefined here - do not test it */ + if (fseek(stdin, skip, SEEK_SET)) { + (void)fprintf(stderr, "hexdump: %s: %s.\n", + fname, strerror(errno)); + exit(1); + } + address += skip; + skip = 0; +} + +void * +emalloc(int sz) { + void *p; + + if (!(p = malloc((u_int)sz))) + nomem(); + memset(p, 0, sz); + return(p); +} + +void nomem() { + (void)fprintf(stderr, "hexdump: %s.\n", strerror(errno)); + exit(1); +} diff --git a/text-utils/hexdump.1 b/text-utils/hexdump.1 new file mode 100644 index 0000000..24cb8c3 --- /dev/null +++ b/text-utils/hexdump.1 @@ -0,0 +1,342 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)hexdump.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt HEXDUMP 1 +.Os +.Sh NAME +.Nm hexdump +.Nd ascii, decimal, hexadecimal, octal dump +.Sh SYNOPSIS +.Nm +.Op Fl bcCdovx +.Bk -words +.Op Fl e Ar format_string +.Ek +.Bk -words +.Op Fl f Ar format_file +.Ek +.Bk -words +.Op Fl n Ar length +.Ek +.Bk -words +.Op Fl s Ar skip +.Ek +.Ar file ... +.Sh DESCRIPTION +The hexdump utility is a filter which displays the specified files, or +the standard input, if no files are specified, in a user specified +format. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl b +.Em One-byte octal display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, three column, zero-filled, bytes of input data, +in octal, per line. +.It Fl c +.Em One-byte character display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, three column, space-filled, characters of input +data per line. +.It Fl C +.Em Canonical hex+ASCII display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, two column, hexadecimal bytes, followed by the +same sixteen bytes in %_p format enclosed in ``|'' characters. +.It Fl d +.Em Two-byte decimal display . +Display the input offset in hexadecimal, followed by eight +space-separated, five column, zero-filled, two-byte units +of input data, in unsigned decimal, per line. +.It Fl e Ar format_string +Specify a format string to be used for displaying data. +.It Fl f Ar format_file +Specify a file that contains one or more newline separated format strings. +Empty lines and lines whose first non-blank character is a hash mark +.Pf ( Cm \&# ) +are ignored. +.It Fl n Ar length +Interpret only +.Ar length +bytes of input. +.It Fl o +.Em Two-byte octal display . +Display the input offset in hexadecimal, followed by eight +space-separated, six column, zero-filled, two byte quantities of +input data, in octal, per line. +.It Fl s Ar offset +Skip +.Ar offset +bytes from the beginning of the input. +By default, +.Ar offset +is interpreted as a decimal number. +With a leading +.Cm 0x +or +.Cm 0X , +.Ar offset +is interpreted as a hexadecimal number, +otherwise, with a leading +.Cm 0 , +.Ar offset +is interpreted as an octal number. +Appending the character +.Cm b , +.Cm k , +or +.Cm m +to +.Ar offset +causes it to be interpreted as a multiple of +.Li 512 , +.Li 1024 , +or +.Li 1048576 , +respectively. +.It Fl v +The +.Fl v +option causes hexdump to display all input data. +Without the +.Fl v +option, any number of groups of output lines, which would be +identical to the immediately preceding group of output lines (except +for the input offsets), are replaced with a line comprised of a +single asterisk. +.It Fl x +.Em Two-byte hexadecimal display . +Display the input offset in hexadecimal, followed by eight, space +separated, four column, zero-filled, two-byte quantities of input +data, in hexadecimal, per line. +.El +.Pp +For each input file, +.Nm +sequentially copies the input to standard output, transforming the +data according to the format strings specified by the +.Fl e +and +.Fl f +options, in the order that they were specified. +.Ss Formats +A format string contains any number of format units, separated by +whitespace. +A format unit contains up to three items: an iteration count, a byte +count, and a format. +.Pp +The iteration count is an optional positive integer, which defaults to +one. +Each format is applied iteration count times. +.Pp +The byte count is an optional positive integer. +If specified it defines the number of bytes to be interpreted by +each iteration of the format. +.Pp +If an iteration count and/or a byte count is specified, a single slash +must be placed after the iteration count and/or before the byte count +to disambiguate them. +Any whitespace before or after the slash is ignored. +.Pp +The format is required and must be surrounded by double quote +(" ") marks. +It is interpreted as a fprintf-style format string (see +.Xr fprintf 3 ) , +with the +following exceptions: +.Bl -bullet -offset indent +.It +An asterisk (*) may not be used as a field width or precision. +.It +A byte count or field precision +.Em is +required for each ``s'' conversion +character (unlike the +.Xr fprintf 3 +default which prints the entire string if the precision is unspecified). +.It +The conversion characters ``h'', ``l'', ``n'', ``p'' and ``q'' are +not supported. +.It +The single character escape sequences +described in the C standard are supported: +.Bd -ragged -offset indent -compact +.Bl -column <alert_character> +.It NUL \e0 +.It <alert character> \ea +.It <backspace> \eb +.It <form-feed> \ef +.It <newline> \en +.It <carriage return> \er +.It <tab> \et +.It <vertical tab> \ev +.El +.Ed +.El +.Pp +Hexdump also supports the following additional conversion strings: +.Bl -tag -width Fl +.It Cm \&_a Ns Op Cm dox +Display the input offset, cumulative across input files, of the +next byte to be displayed. +The appended characters +.Cm d , +.Cm o , +and +.Cm x +specify the display base +as decimal, octal or hexadecimal respectively. +.It Cm \&_A Ns Op Cm dox +Identical to the +.Cm \&_a +conversion string except that it is only performed +once, when all of the input data has been processed. +.It Cm \&_c +Output characters in the default character set. +Nonprinting characters are displayed in three character, zero-padded +octal, except for those representable by standard escape notation +(see above), +which are displayed as two character strings. +.It Cm _p +Output characters in the default character set. +Nonprinting characters are displayed as a single +.Dq Cm \&. . +.It Cm _u +Output US ASCII characters, with the exception that control characters are +displayed using the following, lower-case, names. +Characters greater than 0xff, hexadecimal, are displayed as hexadecimal +strings. +.Bl -column \&000_nu \&001_so \&002_st \&003_et \&004_eo +.It \&000\ nul\t001\ soh\t002\ stx\t003\ etx\t004\ eot\t005\ enq +.It \&006\ ack\t007\ bel\t008\ bs\t009\ ht\t00A\ lf\t00B\ vt +.It \&00C\ ff\t00D\ cr\t00E\ so\t00F\ si\t010\ dle\t011\ dc1 +.It \&012\ dc2\t013\ dc3\t014\ dc4\t015\ nak\t016\ syn\t017\ etb +.It \&018\ can\t019\ em\t01A\ sub\t01B\ esc\t01C\ fs\t01D\ gs +.It \&01E\ rs\t01F\ us\t0FF\ del +.El +.El +.Pp +The default and supported byte counts for the conversion characters +are as follows: +.Bl -tag -width "Xc,_Xc,_Xc,_Xc,_Xc,_Xc" -offset indent +.It Li \&%_c , \&%_p , \&%_u , \&%c +One byte counts only. +.It Xo +.Li \&%d , \&%i , \&%o , +.Li \&%u , \&%X , \&%x +.Xc +Four byte default, one, two and four byte counts supported. +.It Xo +.Li \&%E , \&%e , \&%f , +.Li \&%G , \&%g +.Xc +Eight byte default, four byte counts supported. +.El +.Pp +The amount of data interpreted by each format string is the sum of the +data required by each format unit, which is the iteration count times the +byte count, or the iteration count times the number of bytes required by +the format if the byte count is not specified. +.Pp +The input is manipulated in ``blocks'', where a block is defined as the +largest amount of data specified by any format string. +Format strings interpreting less than an input block's worth of data, +whose last format unit both interprets some number of bytes and does +not have a specified iteration count, have the iteration count +incremented until the entire input block has been processed or there +is not enough data remaining in the block to satisfy the format string. +.Pp +If, either as a result of user specification or hexdump modifying +the iteration count as described above, an iteration count is +greater than one, no trailing whitespace characters are output +during the last iteration. +.Pp +It is an error to specify a byte count as well as multiple conversion +characters or strings unless all but one of the conversion characters +or strings is +.Cm \&_a +or +.Cm \&_A . +.Pp +If, as a result of the specification of the +.Fl n +option or end-of-file being reached, input data only partially +satisfies a format string, the input block is zero-padded sufficiently +to display all available data (i.e. any format units overlapping the +end of data will display some number of the zero bytes). +.Pp +Further output by such format strings is replaced by an equivalent +number of spaces. +An equivalent number of spaces is defined as the number of spaces +output by an +.Cm s +conversion character with the same field width +and precision as the original conversion character or conversion +string but with any +.Dq Li \&+ , +.Dq \&\ \& , +.Dq Li \&# +conversion flag characters +removed, and referencing a NULL string. +.Pp +If no format strings are specified, the default display is equivalent +to specifying the +.Fl x +option. +.Pp +.Nm +exits 0 on success and >0 if an error occurred. +.Sh EXAMPLES +Display the input in perusal format: +.Bd -literal -offset indent +"%06.6_ao " 12/1 "%3_u " +"\et\et" "%_p " +"\en" +.Ed +.Pp +Implement the \-x option: +.Bd -literal -offset indent +"%07.7_Ax\en" +"%07.7_ax " 8/2 "%04x " "\en" +.Ed +.Sh STANDARDS +The +.Nm +utility is expected to be +.St -p1003.2 +compatible. +.Sh AVAILABILITY +The hexdump command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/hexdump.c b/text-utils/hexdump.c new file mode 100644 index 0000000..68bb76e --- /dev/null +++ b/text-utils/hexdump.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include "hexdump.h" +#include "nls.h" + +FS *fshead; /* head of format strings */ +int blocksize; /* data block size */ +int exitval; /* final exit value */ +int length = -1; /* max bytes to read */ + +int main(int argc, char **argv) +{ + FS *tfs; + char *p; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + if (!(p = strrchr(argv[0], 'o')) || strcmp(p, "od")) + newsyntax(argc, &argv); + else + oldsyntax(argc, &argv); + + /* figure out the data block size */ + for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) { + tfs->bcnt = size(tfs); + if (blocksize < tfs->bcnt) + blocksize = tfs->bcnt; + } + /* rewrite the rules, do syntax checking */ + for (tfs = fshead; tfs; tfs = tfs->nextfs) + rewrite(tfs); + + (void)next(argv); + display(); + return exitval; +} diff --git a/text-utils/hexdump.h b/text-utils/hexdump.h new file mode 100644 index 0000000..f9e963b --- /dev/null +++ b/text-utils/hexdump.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)hexdump.h 5.4 (Berkeley) 6/1/90 + */ + +typedef struct _pr { + struct _pr *nextpr; /* next print unit */ +#define F_ADDRESS 0x001 /* print offset */ +#define F_BPAD 0x002 /* blank pad */ +#define F_C 0x004 /* %_c */ +#define F_CHAR 0x008 /* %c */ +#define F_DBL 0x010 /* %[EefGf] */ +#define F_INT 0x020 /* %[di] */ +#define F_P 0x040 /* %_p */ +#define F_STR 0x080 /* %s */ +#define F_U 0x100 /* %_u */ +#define F_UINT 0x200 /* %[ouXx] */ +#define F_TEXT 0x400 /* no conversions */ + u_int flags; /* flag values */ + int bcnt; /* byte count */ + char *cchar; /* conversion character */ + char *fmt; /* printf format */ + char *nospace; /* no whitespace version */ +} PR; + +typedef struct _fu { + struct _fu *nextfu; /* next format unit */ + struct _pr *nextpr; /* next print unit */ +#define F_IGNORE 0x01 /* %_A */ +#define F_SETREP 0x02 /* rep count set, not default */ + u_int flags; /* flag values */ + int reps; /* repetition count */ + int bcnt; /* byte count */ + char *fmt; /* format string */ +} FU; + +typedef struct _fs { /* format strings */ + struct _fs *nextfs; /* linked list of format strings */ + struct _fu *nextfu; /* linked list of format units */ + int bcnt; +} FS; + +extern FU *endfu; +extern FS *fshead; /* head of format strings list */ +extern int blocksize; /* data block size */ +extern int deprecated; /* od compatibility */ +extern int exitval; /* final exit value */ +extern int length; /* max bytes to read */ +extern off_t skip; /* bytes to skip */ + +enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */ +extern enum _vflag vflag; + +void *emalloc(int); +int size(FS *); +void add(const char *); +void rewrite(FS *); +void addfile(char *); +void display(void); +void nomem(void); +void usage(void); +void conv_c(PR *, u_char *); +void conv_u(PR *, u_char *); +int next(char **); +void oldsyntax(int, char ***); +void newsyntax(int, char ***); diff --git a/text-utils/hexsyntax.c b/text-utils/hexsyntax.c new file mode 100644 index 0000000..f05043c --- /dev/null +++ b/text-utils/hexsyntax.c @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + */ + +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include "hexdump.h" +#include "nls.h" + +off_t skip; /* bytes to skip */ + +void +newsyntax(int argc, char ***argvp) +{ + int ch; + char *p, **argv; + + argv = *argvp; + while ((ch = getopt(argc, argv, "bcCde:f:n:os:vx")) != -1) + switch (ch) { + case 'b': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 16/1 \"%03o \" \"\\n\""); + break; + case 'c': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\""); + break; + case 'C': + add("\"%08.8_Ax\n\""); + add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" "); + add("\" |\" 16/1 \"%_p\" \"|\\n\""); + break; + case 'd': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %05u \" \"\\n\""); + break; + case 'e': + add(optarg); + break; + case 'f': + addfile(optarg); + break; + case 'n': + if ((length = atoi(optarg)) < 0) { + fprintf(stderr, + _("hexdump: bad length value.\n")); + exit(1); + } + break; + case 'o': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %06o \" \"\\n\""); + break; + case 's': + if ((skip = strtol(optarg, &p, 0)) < 0) { + fprintf(stderr, + _("hexdump: bad skip value.\n")); + exit(1); + } + switch(*p) { + case 'b': + skip *= 512; + break; + case 'k': + skip *= 1024; + break; + case 'm': + skip *= 1048576; + break; + } + break; + case 'v': + vflag = ALL; + break; + case 'x': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %04x \" \"\\n\""); + break; + case '?': + usage(); + } + + if (!fshead) { + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\""); + } + + *argvp += optind; +} + +void +usage() +{ + fprintf(stderr, +_("hexdump: [-bcCdovx] [-e fmt] [-f fmt_file] [-n length] [-s skip] [file ...]\n")); + exit(1); +} diff --git a/text-utils/line.1 b/text-utils/line.1 new file mode 100644 index 0000000..93081ea --- /dev/null +++ b/text-utils/line.1 @@ -0,0 +1,17 @@ +.\" This page is in the public domain +.TH LINE 1 "2002-07-07" "" "User Commands" +.SH NAME +line \- read one line +.SH SYNOPSIS +.B line +.SH DESCRIPTION +The utility +.I line +copies one line (up to a newline) from standard input to standard output. +It always prints at least a newline and returns an exit status of 1 +on EOF or read error. +.SH "SEE ALSO" +.BR read (1) +.SH AVAILABILITY +The line command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/line.c b/text-utils/line.c new file mode 100644 index 0000000..d4bb86d --- /dev/null +++ b/text-utils/line.c @@ -0,0 +1,38 @@ +/* + * line - read one line + * + * Gunnar Ritter, Freiburg i. Br., Germany, December 2000. + * + * Public Domain. + */ + +#ident "@(#)line.c 1.7 (gritter) 7/5/02" + +#include <stdio.h> +#include <unistd.h> + +static int status; /* exit status */ + +static void +doline(int fd) +{ + char c; + + for (;;) { + if (read(fd, &c, 1) <= 0) { + status = 1; + break; + } + if (c == '\n') + break; + putchar(c); + } + putchar('\n'); +} + +int +main(int argc, char **argv) +{ + doline(0); + return status; +} diff --git a/text-utils/more.1 b/text-utils/more.1 new file mode 100644 index 0000000..a049d13 --- /dev/null +++ b/text-utils/more.1 @@ -0,0 +1,205 @@ +.\" Copyright (c) 1988, 1990 The Regents of the University of California. +.\" Copyright (c) 1988 Mark Nudleman +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)more.1 5.15 (Berkeley) 7/29/91 +.\" +.\" Revised: Fri Dec 25 15:27:27 1992 by root +.\" 25Dec92: Extensive changes made by Rik Faith (faith@cs.unc.edu) to +.\" conform with the more 5.19 currently in use by the Linux community. +.\" +.\" .Dd July 29, 1991 (Modified December 25, 1992) +.Dd December 25, 1992 +.Dt MORE 1 +.Os "Linux 0.98" +.Sh NAME +.Nm more +.Nd file perusal filter for crt viewing +.Sh SYNOPSIS +.Nm more +.Op Fl dlfpcsu +.Op Fl num +.Op +/\fIpattern\fP +.Op +\fIlinenum\fP +.Op Ar +.Sh DESCRIPTION +.Nm More +is a filter for paging through text one screenful at a time. This version +is especially primitive. Users should realize that +.Xr less 1 +provides +.Xr more 1 +emulation and extensive enhancements. +.Sh OPTIONS +Command line options are described below. +Options are also taken from the environment variable +.Ev MORE +(make sure to precede them with a dash (``-'')) but command +line options will override them. +.Bl -tag -width flag +.It Fl num +This option specifies an integer which is the screen size (in lines). +.It Fl d +.Nm more +will prompt the user with the message "[Press space to continue, 'q' to +quit.]" and will display "[Press 'h' for instructions.]" instead of ringing +the bell when an illegal key is pressed. +.It Fl l +.Nm more +usually treats +.Ic \&^L +(form feed) as a special character, and will pause after any line that +contains a form feed. The +.Fl l +option will prevent this behavior. +.It Fl f +Causes +.Nm more +to count logical, rather than screen lines (i.e., long lines are not +folded). +.It Fl p +Do not scroll. Instead, clear the whole screen and then display the text. +.It Fl c +Do not scroll. Instead, paint each screen from the top, clearing the +remainder of each line as it is displayed. +.It Fl s +Squeeze multiple blank lines into one. +.It Fl u +Suppress underlining. +.It Ic +/ +The +.Ic +/ +option specifies a string that will be searched for before +each file is displayed. +.It Ic +num +Start at line number +.Ic num . +.El +.Sh COMMANDS +Interactive commands for +.Nm more +are based on +.Xr vi 1 . +Some commands may be preceded by a decimal number, called k in the +descriptions below. +In the following descriptions, ^X means control-X. +.Pp +.Bl -tag -width Ic +.It Ic h No or Ic ? +Help: display a summary of these commands. +If you forget all the other commands, remember this one. +.It Ic SPACE +Display next k lines of text. Defaults to current screen size. +.It Ic z +Display next k lines of text. Defaults to current screen size. Argument +becomes new default. +.It Ic RETURN +Display next k lines of text. Defaults to 1. Argument becomes new +default. +.It Ic d No or Ic \&^D +Scroll k lines. Default is current scroll size, initially 11. Argument +becomes new default. +.It Xo +.Ic q +.No or +.Ic Q +.No or +.Ic INTERRUPT +.Xc +Exit. +.It Ic s +Skip forward k lines of text. Defaults to 1. +.It Ic f +Skip forward k screenfuls of text. Defaults to 1. +.It Ic b No or Ic \&^B +Skip backwards k screenfuls of text. Defaults to 1. +Only works with files, not pipes. +.It Ic ' +Go to place where previous search started. +.It Ic = +Display current line number. +.It Ic \&/ Ns Ar pattern +Search for kth occurrence of regular expression. Defaults to 1. +.It Ic n +Search for kth occurrence of last r.e. Defaults to 1. +.It Ic !<cmd> No or Ic :!<cmd> +Execute <cmd> in a subshell +.It Ic v +Start up an editor at current line. +The editor is taken from the environment variable VISUAL if defined, +or EDITOR if VISUAL is not defined, +or defaults to "vi" if neither VISUAL nor EDITOR is defined. +.It Ic \&^L +Redraw screen +.It Ic :n +Go to kth next file. Defaults to 1. +.It Ic :p +Go to kth previous file. Defaults to 1. +.It Ic :f +Display current file name and line number +.It Ic \&. +Repeat previous command +.El +.Sh ENVIRONMENT +.Nm More +utilizes the following environment variables, if they exist: +.Bl -tag -width Fl +.It Ev MORE +This variable may be set with favored options to +.Nm more . +.It Ev SHELL +Current shell in use (normally set by the shell at login time). +.It Ev TERM +Specifies terminal type, used by more to get the terminal +characteristics necessary to manipulate the screen. +.El +.Sh SEE ALSO +.Xr vi 1 , +.Xr less 1 +.Sh AUTHORS +Eric Shienbrood, UC Berkeley +.br +Modified by Geoff Peck, UCB to add underlining, single spacing +.br +Modified by John Foderaro, UCB to add -c and MORE environment variable +.Sh HISTORY +The +.Nm more +command appeared in +.Bx 3.0 . +This man page documents +.Nm more +version 5.19 (Berkeley 6/29/88), which is currently in use in the Linux +community. Documentation was produced using several other versions of the +man page, and extensive inspection of the source code. +.Sh AVAILABILITY +The more command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/more.c b/text-utils/more.c new file mode 100644 index 0000000..45a58e2 --- /dev/null +++ b/text-utils/more.c @@ -0,0 +1,2126 @@ +/* + * Copyright (C) 1980 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* +** more.c - General purpose tty output filter and file perusal program +** +** by Eric Shienbrood, UC Berkeley +** +** modified by Geoff Peck, UCB to add underlining, single spacing +** modified by John Foderaro, UCB to add -c and MORE environment variable +** modified by Erik Troan <ewt@redhat.com> to be more posix and so compile +** on linux/axp. +** modified by Kars de Jong <jongk@cs.utwente.nl> to use terminfo instead +** of termcap. + 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + - added Native Language Support + 1999-03-19 Arnaldo Carvalho de Melo <acme@conectiva.com.br> + - more nls translatable strings + 1999-05-09 aeb - applied a RedHat patch (setjmp->sigsetjmp); without it + a second ^Z would fail. + 1999-05-09 aeb - undone Kars' work, so that more works without + libcurses (and hence can be in /bin with libcurses being in /usr/lib + which may not be mounted). However, when termcap is not present curses + can still be used. +*/ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> /* for alloca() */ +#include <stdarg.h> /* for va_start() etc */ +#include <sys/param.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <fcntl.h> +#include <termios.h> +#include <setjmp.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/wait.h> +#include "xstrncpy.h" +#include "nls.h" +#include "widechar.h" + +#define _REGEX_RE_COMP +#include <regex.h> +#undef _REGEX_RE_COMP + +#define VI "vi" /* found on the user's path */ + +#define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) +#define Ftell(f) file_pos +#define Fseek(f,off) (file_pos=off,fseek(f,off,0)) +#define Getc(f) (++file_pos, getc(f)) +#define Ungetc(c,f) (--file_pos, ungetc(c,f)) +#define putcerr(c) fputc(c, stderr) +#define putserr(s) fputs(s, stderr) +#define putsout(s) fputs(s, stdout) + +#define stty(fd,argp) tcsetattr(fd,TCSANOW,argp) + +/* some function declarations */ +void initterm(void); +void kill_line(void); +void doclear(void); +void cleareol(void); +void clreos(void); +void home(void); +void error (char *mess); +void do_shell (char *filename); +int colon (char *filename, int cmd, int nlines); +int expand (char **outbuf, char *inbuf); +void argscan(char *s,char *argv0); +void rdline (register FILE *f); +void copy_file(register FILE *f); +void search(char buf[], FILE *file, register int n); +void skipf (register int nskip); +void skiplns(register int n, register FILE *f); +void screen (register FILE *f, register int num_lines); +int command (char *filename, register FILE *f); +void erasep (register int col); +void show (register char ch); +void set_tty(void); +void reset_tty(void); +void ttyin (char buf[], register int nmax, char pchar); +int number(char *cmd); +int readch (void); +int get_line(register FILE *f, int *length); +void prbuf (register char *s, register int n); +void execute (char *filename, char *cmd, ...); +FILE *checkf (char *, int *); + +#define TBUFSIZ 1024 +#define LINSIZ 256 +#define ctrl(letter) (letter & 077) +#define RUBOUT '\177' +#define ESC '\033' +#define QUIT '\034' + +struct termios otty, savetty0; +long file_pos, file_size; +int fnum, no_intty, no_tty, slow_tty; +int dum_opt, dlines; +void onquit(int), onsusp(int), chgwinsz(int), end_it(int); +int nscroll = 11; /* Number of lines scrolled by 'd' */ +int fold_opt = 1; /* Fold long lines */ +int stop_opt = 1; /* Stop after form feeds */ +int ssp_opt = 0; /* Suppress white space */ +int ul_opt = 1; /* Underline as best we can */ +int promptlen; +int Currline; /* Line we are currently at */ +int startup = 1; +int firstf = 1; +int notell = 1; +int docrterase = 0; +int docrtkill = 0; +int bad_so; /* True if overwriting does not turn off standout */ +int inwait, Pause, errors; +int within; /* true if we are within a file, + false if we are between files */ +int hard, dumb, noscroll, hardtabs, clreol, eatnl; +int catch_susp; /* We should catch the SIGTSTP signal */ +char **fnames; /* The list of file names */ +int nfiles; /* Number of files left to process */ +char *shell; /* The name of the shell to use */ +int shellp; /* A previous shell command exists */ +sigjmp_buf restore; +char Line[LINSIZ+2]; /* Line buffer */ +int Lpp = 24; /* lines per page */ +char *Clear; /* clear screen */ +char *eraseln; /* erase line */ +char *Senter, *Sexit;/* enter and exit standout mode */ +char *ULenter, *ULexit; /* enter and exit underline mode */ +char *chUL; /* underline character */ +char *chBS; /* backspace character */ +char *Home; /* go to home */ +char *cursorm; /* cursor movement */ +char cursorhome[40]; /* contains cursor movement to home */ +char *EodClr; /* clear rest of screen */ +int Mcol = 80; /* number of columns */ +int Wrap = 1; /* set if automargins */ +int soglitch; /* terminal has standout mode glitch */ +int ulglitch; /* terminal has underline mode glitch */ +int pstate = 0; /* current UL state */ +static int magic(FILE *, char *); +struct { + long chrctr, line; +} context, screen_start; +extern char PC; /* pad character */ + +#ifdef HAVE_NCURSES_H +# include <ncurses.h> +#elif defined(HAVE_NCURSES_NCURSES_H) +# include <ncurses/ncurses.h> +#endif + +#if defined(HAVE_NCURSES_H) || defined(HAVE_NCURSES_NCURSES_H) +# include <term.h> /* include after <curses.h> */ + +static void +my_putstring(char *s) { + tputs (s, 1, putchar); /* putp(s); */ +} + +static void +my_setupterm(char *term, int fildes, int *errret) { + setupterm(term, fildes, errret); +} + +static int +my_tgetnum(char *s, char *ss) { + return tigetnum(ss); +} + +static int +my_tgetflag(char *s, char *ss) { + return tigetflag(ss); +} + +static char * +my_tgetstr(char *s, char *ss) { + return tigetstr(ss); +} + +static char * +my_tgoto(char *cap, int col, int row) { + return tparm(cap, col, row); +} + +#elif defined(HAVE_LIBTERMCAP) /* !ncurses */ + +#include <termcap.h> + +char termbuffer[4096]; +char tcbuffer[4096]; +char *strbuf = termbuffer; + +static void +my_putstring(char *s) { + tputs (s, 1, putchar); +} + +static void +my_setupterm(char *term, int fildes, int *errret) { + *errret = tgetent(tcbuffer, term); +} + +static int +my_tgetnum(char *s, char *ss) { + return tgetnum(s); +} + +static int +my_tgetflag(char *s, char *ss) { + return tgetflag(s); +} + +static char * +my_tgetstr(char *s, char *ss) { + return tgetstr(s, &strbuf); +} + +static char * +my_tgoto(char *cap, int col, int row) { + return tgoto(cap, col, row); +} + +#endif /* HAVE_LIBTERMCAP */ + +static void +idummy(int *kk) {} + +static void +Fdummy(FILE **ff) {} + +static void +usage(char *s) { + char *p = strrchr(s, '/'); + fprintf(stderr, + _("usage: %s [-dflpcsu] [+linenum | +/pattern] name1 name2 ...\n"), + p ? p + 1 : s); +} + +int main(int argc, char **argv) { + FILE *f; + char *s; + char *p; + int ch; + int left; + int prnames = 0; + int initopt = 0; + int srchopt = 0; + int clearit = 0; + int initline = 0; + char initbuf[80]; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + /* avoid gcc complaints about register variables that + may be clobbered by a longjmp, by forcing our variables here + to be non-register */ + Fdummy(&f); idummy(&left); idummy(&prnames); + idummy(&initopt); idummy(&srchopt); idummy(&initline); + + nfiles = argc; + fnames = argv; + setlocale(LC_ALL, ""); + initterm (); + nscroll = Lpp/2 - 1; + if (nscroll <= 0) + nscroll = 1; + if((s = getenv("MORE")) != NULL) argscan(s,argv[0]); + while (--nfiles > 0) { + if ((ch = (*++fnames)[0]) == '-') { + argscan(*fnames+1,argv[0]); + } + else if (ch == '+') { + s = *fnames; + if (*++s == '/') { + srchopt++; + for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) + *p++ = *s++; + *p = '\0'; + } + else { + initopt++; + for (initline = 0; *s != '\0'; s++) + if (isdigit (*s)) + initline = initline*10 + *s -'0'; + --initline; + } + } + else break; + } + /* allow clreol only if Home and eraseln and EodClr strings are + * defined, and in that case, make sure we are in noscroll mode + */ + if (clreol) { + if((Home == NULL) || (*Home == '\0') || + (eraseln == NULL) || (*eraseln == '\0') || + (EodClr == NULL) || (*EodClr == '\0') ) + clreol = 0; + else noscroll = 1; + } + if (dlines == 0) + dlines = Lpp - 1; /* was: Lpp - (noscroll ? 1 : 2) */ + left = dlines; + if (nfiles > 1) + prnames++; + if (!no_intty && nfiles == 0) { + usage(argv[0]); + exit(1); + } + else + f = stdin; + if (!no_tty) { + signal(SIGQUIT, onquit); + signal(SIGINT, end_it); +#ifdef SIGWINCH + signal(SIGWINCH, chgwinsz); +#endif + if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { + signal(SIGTSTP, onsusp); + catch_susp++; + } + stty (fileno(stderr), &otty); + } + if (no_intty) { + if (no_tty) + copy_file (stdin); + else { + if ((ch = Getc (f)) == '\f') + doclear(); + else { + Ungetc (ch, f); + if (noscroll && (ch != EOF)) { + if (clreol) + home (); + else + doclear (); + } + } + if (srchopt) + { + search (initbuf, stdin, 1); + if (noscroll) + left--; + } + else if (initopt) + skiplns (initline, stdin); + screen (stdin, left); + } + no_intty = 0; + prnames++; + firstf = 0; + } + + while (fnum < nfiles) { + if ((f = checkf (fnames[fnum], &clearit)) != NULL) { + context.line = context.chrctr = 0; + Currline = 0; + if (firstf) sigsetjmp (restore, 1); + if (firstf) { + firstf = 0; + if (srchopt) { + search (initbuf, f, 1); + if (noscroll) + left--; + } + else if (initopt) + skiplns (initline, f); + } + else if (fnum < nfiles && !no_tty) { + sigsetjmp (restore, 1); + left = command (fnames[fnum], f); + } + if (left != 0) { + if ((noscroll || clearit) && (file_size != LONG_MAX)) { + if (clreol) + home (); + else + doclear (); + } + if (prnames) { + if (bad_so) + erasep (0); + if (clreol) + cleareol (); + putsout("::::::::::::::"); + if (promptlen > 14) + erasep (14); + putchar('\n'); + if(clreol) cleareol(); + puts(fnames[fnum]); + if(clreol) cleareol(); + puts("::::::::::::::"); + if (left > Lpp - 4) + left = Lpp - 4; + } + if (no_tty) + copy_file (f); + else { + within++; + screen(f, left); + within = 0; + } + } + sigsetjmp (restore, 1); + fflush(stdout); + fclose(f); + screen_start.line = screen_start.chrctr = 0L; + context.line = context.chrctr = 0L; + } + fnum++; + firstf = 0; + } + reset_tty (); + exit(0); +} + +void argscan(char *s, char *argv0) { + int seen_num = 0; + + while (*s != '\0') { + switch (*s) { + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': + if (!seen_num) { + dlines = 0; + seen_num = 1; + } + dlines = dlines*10 + *s - '0'; + break; + case 'd': + dum_opt = 1; + break; + case 'l': + stop_opt = 0; + break; + case 'f': + fold_opt = 0; + break; + case 'p': + noscroll++; + break; + case 'c': + clreol++; + break; + case 's': + ssp_opt = 1; + break; + case 'u': + ul_opt = 0; + break; + case '-': case ' ': case '\t': + break; + default: + fprintf(stderr, + _("%s: unknown option \"-%c\"\n"), argv0, *s); + usage(argv0); + exit(1); + break; + } + s++; + } +} + + +/* +** Check whether the file named by fs is an ASCII file which the user may +** access. If it is, return the opened file. Otherwise return NULL. +*/ + +FILE * +checkf (fs, clearfirst) + register char *fs; + int *clearfirst; +{ + struct stat stbuf; + register FILE *f; + int c; + + if (stat (fs, &stbuf) == -1) { + (void)fflush(stdout); + if (clreol) + cleareol (); + perror(fs); + return((FILE *)NULL); + } + if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { + printf(_("\n*** %s: directory ***\n\n"), fs); + return((FILE *)NULL); + } + if ((f = Fopen(fs, "r")) == NULL) { + (void)fflush(stdout); + perror(fs); + return((FILE *)NULL); + } + if (magic(f, fs)) + return((FILE *)NULL); + fcntl(fileno(f), F_SETFD, FD_CLOEXEC ); + c = Getc(f); + *clearfirst = (c == '\f'); + Ungetc (c, f); + if ((file_size = stbuf.st_size) == 0) + file_size = LONG_MAX; + return(f); +} + +/* + * magic -- + * check for file magic numbers. This code would best be shared with + * the file(1) program or, perhaps, more should not try to be so smart. + */ +static int +magic(f, fs) + FILE *f; + char *fs; +{ + signed char twobytes[2]; + + /* don't try to look ahead if the input is unseekable */ + if (fseek(f, 0L, SEEK_SET)) + return 0; + + if (fread(twobytes, 2, 1, f) == 1) { + switch(twobytes[0] + (twobytes[1]<<8)) { + case 0407: /* a.out obj */ + case 0410: /* a.out exec */ + case 0413: /* a.out demand exec */ + case 0405: + case 0411: + case 0177545: + case 0x457f: /* simple ELF detection */ + printf(_("\n******** %s: Not a text file ********\n\n"), fs); + (void)fclose(f); + return 1; + } + } + (void)fseek(f, 0L, SEEK_SET); /* rewind() not necessary */ + return 0; +} + +/* +** Print out the contents of the file f, one screenful at a time. +*/ + +#define STOP -10 + +void screen (register FILE *f, register int num_lines) +{ + register int c; + register int nchars; + int length; /* length of current line */ + static int prev_len = 1; /* length of previous line */ + + for (;;) { + while (num_lines > 0 && !Pause) { + if ((nchars = get_line (f, &length)) == EOF) + { + if (clreol) + clreos(); + return; + } + if (ssp_opt && length == 0 && prev_len == 0) + continue; + prev_len = length; + if (bad_so || ((Senter && *Senter == ' ') && (promptlen > 0))) + erasep (0); + /* must clear before drawing line since tabs on some terminals + * do not erase what they tab over. + */ + if (clreol) + cleareol (); + prbuf (Line, length); + if (nchars < promptlen) + erasep (nchars); /* erasep () sets promptlen to 0 */ + else promptlen = 0; + /* is this needed? + * if (clreol) + * cleareol(); * must clear again in case we wrapped * + */ + if (nchars < Mcol || !fold_opt) + prbuf("\n", 1); /* will turn off UL if necessary */ + if (nchars == STOP) + break; + num_lines--; + } + if (pstate) { + my_putstring (ULexit); + pstate = 0; + } + fflush(stdout); + if ((c = Getc(f)) == EOF) + { + if (clreol) + clreos (); + return; + } + + if (Pause && clreol) + clreos (); + Ungetc (c, f); + sigsetjmp (restore, 1); + Pause = 0; startup = 0; + if ((num_lines = command (NULL, f)) == 0) + return; + if (hard && promptlen > 0) + erasep (0); + if (noscroll && num_lines >= dlines) + { + if (clreol) + home(); + else + doclear (); + } + screen_start.line = Currline; + screen_start.chrctr = Ftell (f); + } +} + +/* +** Come here if a quit signal is received +*/ + +void onquit(int dummy) { + signal(SIGQUIT, SIG_IGN); + if (!inwait) { + putchar ('\n'); + if (!startup) { + signal(SIGQUIT, onquit); + siglongjmp (restore, 1); + } + else + Pause++; + } + else if (!dum_opt && notell) { + promptlen += fprintf(stderr, _("[Use q or Q to quit]")); + notell = 0; + } + signal(SIGQUIT, onquit); +} + +/* +** Come here if a signal for a window size change is received +*/ + +#ifdef SIGWINCH +void chgwinsz(int dummy) { + struct winsize win; + + (void) signal(SIGWINCH, SIG_IGN); + if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { + if (win.ws_row != 0) { + Lpp = win.ws_row; + nscroll = Lpp/2 - 1; + if (nscroll <= 0) + nscroll = 1; + dlines = Lpp - 1; /* was: Lpp - (noscroll ? 1 : 2) */ + } + if (win.ws_col != 0) + Mcol = win.ws_col; + } + (void) signal(SIGWINCH, chgwinsz); +} +#endif + +/* +** Clean up terminal state and exit. Also come here if interrupt signal received +*/ + +void end_it (int dummy) { + reset_tty (); + if (clreol) { + putchar ('\r'); + clreos (); + fflush (stdout); + } + else if (!clreol && (promptlen > 0)) { + kill_line (); + fflush (stdout); + } + else + putcerr('\n'); + _exit(0); +} + +void copy_file(register FILE *f) { + register int c; + + while ((c = getc(f)) != EOF) + putchar(c); +} + +#define ringbell() putcerr('\007') + +/* See whether the last component of the path name "path" is equal to the +** string "string" +*/ + +static int tailequ (char *path, register char *string) +{ + register char *tail; + + tail = path + strlen(path); + while (--tail >= path) + if (*tail == '/') + break; + ++tail; + while (*tail++ == *string++) + if (*tail == '\0') + return(1); + return(0); +} + +static void prompt (char *filename) +{ + if (clreol) + cleareol (); + else if (promptlen > 0) + kill_line (); + if (!hard) { + promptlen = 0; + if (Senter && Sexit) { + my_putstring (Senter); + promptlen += (2 * soglitch); + } + if (clreol) + cleareol (); + promptlen += printf(_("--More--")); + if (filename != NULL) { + promptlen += printf(_("(Next file: %s)"), filename); + } else if (!no_intty) { + promptlen += printf("(%d%%)", (int) ((file_pos * 100) / file_size)); + } + if (dum_opt) { + promptlen += printf(_("[Press space to continue, 'q' to quit.]")); + } + if (Senter && Sexit) + my_putstring (Sexit); + if (clreol) + clreos (); + fflush(stdout); + } + else + ringbell(); + inwait++; +} + +/* + * Get a logical line + */ + +int get_line(register FILE *f, int *length) +{ + int c; + char *p; + int column; + static int colflg; + +#ifdef HAVE_WIDECHAR + int i; + wchar_t wc; + int wc_width; + mbstate_t state, state_bak; /* Current status of the stream. */ + char mbc[MB_LEN_MAX]; /* Buffer for one multibyte char. */ + size_t mblength; /* Byte length of multibyte char. */ + size_t mbc_pos = 0; /* Postion of the MBC. */ + int use_mbc_buffer_flag = 0; /* If 1, mbc has data. */ + int break_flag = 0; /* If 1, exit while(). */ + long file_pos_bak = Ftell (f); + + memset (&state, '\0', sizeof (mbstate_t)); +#endif + + p = Line; + column = 0; + c = Getc (f); + if (colflg && c == '\n') { + Currline++; + c = Getc (f); + } + while (p < &Line[LINSIZ - 1]) { +#ifdef HAVE_WIDECHAR + if (fold_opt && use_mbc_buffer_flag && MB_CUR_MAX > 1) { + use_mbc_buffer_flag = 0; + state_bak = state; + mbc[mbc_pos++] = c; +process_mbc: + mblength = mbrtowc (&wc, mbc, mbc_pos, &state); + + switch (mblength) { + case (size_t)-2: /* Incomplete multibyte character. */ + use_mbc_buffer_flag = 1; + state = state_bak; + break; + + case (size_t)-1: /* Invalid as a multibyte character. */ + *p++ = mbc[0]; + state = state_bak; + column++; + file_pos_bak++; + + if (column >= Mcol) { + Fseek (f, file_pos_bak); + } else { + memmove (mbc, mbc + 1, --mbc_pos); + if (mbc_pos > 0) { + mbc[mbc_pos] = '\0'; + goto process_mbc; + } + } + break; + + default: + wc_width = wcwidth (wc); + + if (column + wc_width > Mcol) { + Fseek (f, file_pos_bak); + break_flag = 1; + } else { + for (i = 0; i < mbc_pos; i++) + *p++ = mbc[i]; + if (wc_width > 0) + column += wc_width; + } + } + + if (break_flag || column >= Mcol) + break; + + c = Getc (f); + continue; + } +#endif + if (c == EOF) { + if (p > Line) { + *p = '\0'; + *length = p - Line; + return (column); + } + *length = p - Line; + return (EOF); + } + if (c == '\n') { + Currline++; + break; + } + + *p++ = c; +#if 0 + if (c == '\033') { /* ESC */ + c = Getc(f); + while (c > ' ' && c < '0' && p < &Line[LINSIZ - 1]) { + *p++ = c; + c = Getc(f); + } + if (c >= '0' && c < '\177' && p < &Line[LINSIZ - 1]) { + *p++ = c; + c = Getc(f); + continue; + } + } +#endif + if (c == '\t') { + if (!hardtabs || (column < promptlen && !hard)) { + if (hardtabs && eraseln && !dumb) { + column = 1 + (column | 7); + my_putstring (eraseln); + promptlen = 0; + } + else { + for (--p; p < &Line[LINSIZ - 1];) { + *p++ = ' '; + if ((++column & 7) == 0) + break; + } + if (column >= promptlen) promptlen = 0; + } + } else + column = 1 + (column | 7); + } else if (c == '\b' && column > 0) { + column--; + } else if (c == '\r') { + int next = Getc(f); + if (next == '\n') { + p--; + Currline++; + break; + } + Ungetc(next,f); + column = 0; + } else if (c == '\f' && stop_opt) { + p[-1] = '^'; + *p++ = 'L'; + column += 2; + Pause++; + } else if (c == EOF) { + *length = p - Line; + return (column); + } else { +#ifdef HAVE_WIDECHAR + if (fold_opt && MB_CUR_MAX > 1) { + memset (mbc, '\0', MB_LEN_MAX); + mbc_pos = 0; + mbc[mbc_pos++] = c; + state_bak = state; + + mblength = mbrtowc (&wc, mbc, mbc_pos, &state); + + /* The value of mblength is always less than 2 here. */ + switch (mblength) { + case (size_t)-2: + p--; + file_pos_bak = Ftell (f) - 1; + state = state_bak; + use_mbc_buffer_flag = 1; + break; + + case (size_t)-1: + state = state_bak; + column++; + break; + + default: + wc_width = wcwidth (wc); + if (wc_width > 0) + column += wc_width; + } + } else +#endif + { + if (isprint(c)) + column++; + } + } + + if (column >= Mcol && fold_opt) + break; + c = Getc (f); + } + if (column >= Mcol && Mcol > 0) { + if (!Wrap) { + *p++ = '\n'; + } + } + colflg = column == Mcol && fold_opt; + if (colflg && eatnl && Wrap) { + *p++ = '\n'; /* simulate normal wrap */ + } + *length = p - Line; + *p = 0; + return (column); +} + +/* +** Erase the rest of the prompt, assuming we are starting at column col. +*/ + +void erasep (register int col) +{ + + if (promptlen == 0) + return; + if (hard) { + putchar ('\n'); + } + else { + if (col == 0) + putchar ('\r'); + if (!dumb && eraseln) + my_putstring (eraseln); + else + for (col = promptlen - col; col > 0; col--) + putchar (' '); + } + promptlen = 0; +} + +/* +** Erase the current line entirely +*/ + +void kill_line() +{ + erasep(0); + if (!eraseln || dumb) + putchar('\r'); +} + +/* + * force clear to end of line + */ +void cleareol() +{ + my_putstring(eraseln); +} + +void clreos() +{ + my_putstring(EodClr); +} + +/* Print a buffer of n characters */ + +void prbuf (register char *s, register int n) +{ + register char c; /* next output character */ + register int state; /* next output char's UL state */ +#define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) + + while (--n >= 0) + if (!ul_opt) + putchar (*s++); + else { + if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { + s++; + continue; + } + if ((state = wouldul(s, n)) != 0) { + c = (*s == '_')? s[2] : *s ; + n -= 2; + s += 3; + } else + c = *s++; + if (state != pstate) { + if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) + state = 1; + else + my_putstring(state ? ULenter : ULexit); + } + if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) +#ifdef HAVE_WIDECHAR + { + wchar_t wc; + size_t mblength; + mbstate_t state; + memset (&state, '\0', sizeof (mbstate_t)); + s--; n++; + mblength = mbrtowc (&wc, s, n, &state); + if (mblength == (size_t) -2 || mblength == (size_t) -1) + mblength = 1; + while (mblength--) + putchar (*s++); + n += mblength; + } +#else + putchar(c); +#endif /* HAVE_WIDECHAR */ + if (state && *chUL) { + putsout(chBS); + my_putstring(chUL); + } + pstate = state; + } +} + +/* +** Clear the screen +*/ +void +doclear() +{ + if (Clear && !hard) { + my_putstring(Clear); + + /* Put out carriage return so that system doesn't + ** get confused by escape sequences when expanding tabs + */ + putchar ('\r'); + promptlen = 0; + } +} + +/* + * Go to home position + */ +void +home() +{ + my_putstring(Home); +} + +static int lastcmd, lastarg, lastp; +static int lastcolon; +char shell_line[1000]; + +/* +** Read a command and do it. A command consists of an optional integer +** argument followed by the command character. Return the number of lines +** to display in the next screenful. If there is nothing more to display +** in the current file, zero is returned. +*/ + +int command (char *filename, register FILE *f) +{ + register int nlines; + register int retval = 0; + register int c; + char colonch; + int done; + char comchar, cmdbuf[80]; + +#define ret(val) retval=val;done++;break + + done = 0; + if (!errors) + prompt (filename); + else + errors = 0; + for (;;) { + nlines = number (&comchar); + lastp = colonch = 0; + if (comchar == '.') { /* Repeat last command */ + lastp++; + comchar = lastcmd; + nlines = lastarg; + if (lastcmd == ':') + colonch = lastcolon; + } + lastcmd = comchar; + lastarg = nlines; + if ((cc_t) comchar == otty.c_cc[VERASE]) { + kill_line (); + prompt (filename); + continue; + } + switch (comchar) { + case ':': + retval = colon (filename, colonch, nlines); + if (retval >= 0) + done++; + break; + case 'b': + case ctrl('B'): + { + register int initline; + + if (no_intty) { + ringbell(); + return (-1); + } + + if (nlines == 0) nlines++; + + putchar ('\r'); + erasep (0); + putchar('\n'); + if (clreol) + cleareol (); + if (nlines != 1) + printf(_("...back %d pages"), nlines); + else + putsout(_("...back 1 page")); + if (clreol) + cleareol (); + putchar('\n'); + + initline = Currline - dlines * (nlines + 1); + if (! noscroll) + --initline; + if (initline < 0) initline = 0; + Fseek(f, 0L); + Currline = 0; /* skiplns() will make Currline correct */ + skiplns(initline, f); + if (! noscroll) { + ret(dlines + 1); + } + else { + ret(dlines); + } + } + case ' ': + case 'z': + if (nlines == 0) nlines = dlines; + else if (comchar == 'z') dlines = nlines; + ret (nlines); + case 'd': + case ctrl('D'): + if (nlines != 0) nscroll = nlines; + ret (nscroll); + case 'q': + case 'Q': + end_it (0); + case 's': + case 'f': + case ctrl('F'): + if (nlines == 0) nlines++; + if (comchar == 'f') + nlines *= dlines; + putchar ('\r'); + erasep (0); + putchar('\n'); + if (clreol) + cleareol (); + if (nlines == 1) + putsout(_("...skipping one line")); + else + printf(_("...skipping %d lines"), nlines); + + if (clreol) + cleareol (); + putchar('\n'); + + while (nlines > 0) { + while ((c = Getc (f)) != '\n') + if (c == EOF) { + retval = 0; + done++; + goto endsw; + } + Currline++; + nlines--; + } + ret (dlines); + case '\n': + if (nlines != 0) + dlines = nlines; + else + nlines = 1; + ret (nlines); + case '\f': + if (!no_intty) { + doclear (); + Fseek (f, screen_start.chrctr); + Currline = screen_start.line; + ret (dlines); + } + else { + ringbell(); + break; + } + case '\'': + if (!no_intty) { + kill_line (); + putsout(_("\n***Back***\n\n")); + Fseek (f, context.chrctr); + Currline = context.line; + ret (dlines); + } + else { + ringbell(); + break; + } + case '=': + kill_line (); + promptlen = printf("%d", Currline); + fflush (stdout); + break; + case 'n': + lastp++; + case '/': + if (nlines == 0) nlines++; + kill_line (); + putchar('/'); + promptlen = 1; + fflush (stdout); + if (lastp) { + putcerr('\r'); + search (NULL, f, nlines); /* Use previous r.e. */ + } + else { + ttyin (cmdbuf, sizeof(cmdbuf)-2, '/'); + putcerr('\r'); + search (cmdbuf, f, nlines); + } + ret (dlines-1); + case '!': + do_shell (filename); + break; + case '?': + case 'h': + if (noscroll) doclear(); + putsout(_("\n" +"Most commands optionally preceded by integer argument k. " +"Defaults in brackets.\n" +"Star (*) indicates argument becomes new default.\n")); + puts("---------------------------------------" + "----------------------------------------"); + putsout(_( +"<space> Display next k lines of text [current screen size]\n" +"z Display next k lines of text [current screen size]*\n" +"<return> Display next k lines of text [1]*\n" +"d or ctrl-D Scroll k lines [current scroll size, initially 11]*\n" +"q or Q or <interrupt> Exit from more\n" +"s Skip forward k lines of text [1]\n" +"f Skip forward k screenfuls of text [1]\n" +"b or ctrl-B Skip backwards k screenfuls of text [1]\n" +"' Go to place where previous search started\n" +"= Display current line number\n" +"/<regular expression> Search for kth occurrence of regular expression [1]\n" +"n Search for kth occurrence of last r.e [1]\n" +"!<cmd> or :!<cmd> Execute <cmd> in a subshell\n" +"v Start up /usr/bin/vi at current line\n" +"ctrl-L Redraw screen\n" +":n Go to kth next file [1]\n" +":p Go to kth previous file [1]\n" +":f Display current file name and line number\n" +". Repeat previous command\n")); + puts("---------------------------------------" + "----------------------------------------"); + prompt(filename); + break; + case 'v': /* This case should go right before default */ + if (!no_intty) { + /* + * Earlier: call vi +n file. This also works for emacs. + * POSIX: call vi -c n file (when editor is vi or ex). + */ + char *editor, *p; + int n = (Currline - dlines <= 0 ? 1 : + Currline - (dlines + 1) / 2); + int split = 0; + + editor = getenv("VISUAL"); + if (editor == NULL || *editor == '\0') + editor = getenv("EDITOR"); + if (editor == NULL || *editor == '\0') + editor = VI; + + p = strrchr(editor, '/'); + if (p) + p++; + else + p = editor; + if (!strcmp(p, "vi") || !strcmp(p, "ex")) { + sprintf(cmdbuf, "-c %d", n); + split = 1; + } else { + sprintf(cmdbuf, "+%d", n); + } + + kill_line(); + printf("%s %s %s", editor, cmdbuf, fnames[fnum]); + if (split) { + cmdbuf[2] = 0; + execute(filename, editor, editor, cmdbuf, + cmdbuf+3, fnames[fnum], (char *)0); + } else + execute(filename, editor, editor, + cmdbuf, fnames[fnum], (char *)0); + break; + } + /* fall through */ + default: + if (dum_opt) { + kill_line (); + if (Senter && Sexit) { + my_putstring (Senter); + promptlen = printf(_("[Press 'h' for instructions.]")) + + 2 * soglitch; + my_putstring (Sexit); + } + else + promptlen = printf(_("[Press 'h' for instructions.]")); + fflush (stdout); + } + else + ringbell(); + break; + } + if (done) break; + } + putchar ('\r'); +endsw: + inwait = 0; + notell++; + return (retval); +} + +static char ch; + +/* + * Execute a colon-prefixed command. + * Returns <0 if not a command that should cause + * more of the file to be printed. + */ + +int colon (char *filename, int cmd, int nlines) { + if (cmd == 0) + ch = readch (); + else + ch = cmd; + lastcolon = ch; + switch (ch) { + case 'f': + kill_line (); + if (!no_intty) + promptlen = printf(_("\"%s\" line %d"), fnames[fnum], Currline); + else + promptlen = printf(_("[Not a file] line %d"), Currline); + fflush (stdout); + return (-1); + case 'n': + if (nlines == 0) { + if (fnum >= nfiles - 1) + end_it (0); + nlines++; + } + putchar ('\r'); + erasep (0); + skipf (nlines); + return (0); + case 'p': + if (no_intty) { + ringbell(); + return (-1); + } + putchar ('\r'); + erasep (0); + if (nlines == 0) + nlines++; + skipf (-nlines); + return (0); + case '!': + do_shell (filename); + return (-1); + case 'q': + case 'Q': + end_it (0); + default: + ringbell(); + return (-1); + } +} + +/* +** Read a decimal number from the terminal. Set cmd to the non-digit which +** terminates the number. +*/ + +int number(char *cmd) +{ + register int i; + + i = 0; ch = otty.c_cc[VKILL]; + for (;;) { + ch = readch (); + if (isdigit(ch)) + i = i*10 + ch - '0'; + else if ((cc_t) ch == otty.c_cc[VKILL]) + i = 0; + else { + *cmd = ch; + break; + } + } + return (i); +} + +void do_shell (char *filename) +{ + char cmdbuf[200]; + int rc; + char *expanded; + + kill_line (); + putchar('!'); + fflush (stdout); + promptlen = 1; + if (lastp) + putsout(shell_line); + else { + ttyin (cmdbuf, sizeof(cmdbuf)-2, '!'); + expanded = 0; + rc = expand (&expanded, cmdbuf); + if (expanded) { + if (strlen(expanded) < sizeof(shell_line)) + strcpy(shell_line, expanded); + else + rc = -1; + free(expanded); + } + if (rc < 0) { + putserr(_(" Overflow\n")); + prompt (filename); + return; + } else if (rc > 0) { + kill_line (); + promptlen = printf("!%s", shell_line); + } + } + fflush (stdout); + putcerr('\n'); + promptlen = 0; + shellp = 1; + execute (filename, shell, shell, "-c", shell_line, 0); +} + +/* +** Search for nth ocurrence of regular expression contained in buf in the file +*/ + +void search(char buf[], FILE *file, register int n) +{ + long startline = Ftell (file); + register long line1 = startline; + register long line2 = startline; + register long line3 = startline; + register int lncount; + int saveln, rv; + char *s; + + context.line = saveln = Currline; + context.chrctr = startline; + lncount = 0; + if ((s = re_comp (buf)) != 0) + error (s); + while (!feof (file)) { + line3 = line2; + line2 = line1; + line1 = Ftell (file); + rdline (file); + lncount++; + if ((rv = re_exec (Line)) == 1) { + if (--n == 0) { + if (lncount > 3 || (lncount > 1 && no_intty)) + { + putchar('\n'); + if (clreol) + cleareol (); + putsout(_("...skipping\n")); + } + if (!no_intty) { + Currline -= (lncount >= 3 ? 3 : lncount); + Fseek (file, line3); + if (noscroll) { + if (clreol) { + home (); + cleareol (); + } + else + doclear (); + } + } + else { + kill_line (); + if (noscroll) { + if (clreol) { + home (); + cleareol (); + } + else + doclear (); + } + puts(Line); + } + break; + } + } else if (rv == -1) + error (_("Regular expression botch")); + } + if (feof (file)) { + if (!no_intty) { + Currline = saveln; + Fseek (file, startline); + } + else { + putsout(_("\nPattern not found\n")); + end_it (0); + } + error (_("Pattern not found")); + } +} + +/*VARARGS2*/ +void execute (char *filename, char *cmd, ...) +{ + int id; + int n; + va_list argp; + char * arg; + char ** args; + int argcount; + + fflush (stdout); + reset_tty (); + for (n = 10; (id = fork ()) < 0 && n > 0; n--) + sleep (5); + if (id == 0) { + if (!isatty(0)) { + close(0); + open("/dev/tty", 0); + } + + va_start(argp, cmd); + arg = va_arg(argp, char *); + argcount = 0; + while (arg) { + argcount++; + arg = va_arg(argp, char *); + } + va_end(argp); + + args = alloca(sizeof(char *) * (argcount + 1)); + args[argcount] = NULL; + + va_start(argp, cmd); + arg = va_arg(argp, char *); + argcount = 0; + while (arg) { + args[argcount] = arg; + argcount++; + arg = va_arg(argp, char *); + } + va_end(argp); + + execvp (cmd, args); + putserr(_("exec failed\n")); + exit (1); + } + if (id > 0) { + signal (SIGINT, SIG_IGN); + signal (SIGQUIT, SIG_IGN); + if (catch_susp) + signal(SIGTSTP, SIG_DFL); + while (wait(0) > 0); + signal (SIGINT, end_it); + signal (SIGQUIT, onquit); + if (catch_susp) + signal(SIGTSTP, onsusp); + } else + putserr(_("can't fork\n")); + set_tty (); + puts("------------------------"); + prompt (filename); +} +/* +** Skip n lines in the file f +*/ + +void skiplns (register int n, register FILE *f) +{ + register int c; + + while (n > 0) { + while ((c = Getc (f)) != '\n') + if (c == EOF) + return; + n--; + Currline++; + } +} + +/* +** Skip nskip files in the file list (from the command line). Nskip may be +** negative. +*/ + +void skipf (register int nskip) +{ + if (nskip == 0) return; + if (nskip > 0) { + if (fnum + nskip > nfiles - 1) + nskip = nfiles - fnum - 1; + } + else if (within) + ++fnum; + fnum += nskip; + if (fnum < 0) + fnum = 0; + puts(_("\n...Skipping ")); + if (clreol) + cleareol (); + if (nskip > 0) + putsout(_("...Skipping to file ")); + else + putsout(_("...Skipping back to file ")); + puts(fnames[fnum]); + if (clreol) + cleareol (); + putchar('\n'); + --fnum; +} + +/*----------------------------- Terminal I/O -------------------------------*/ + +void initterm() +{ + int ret; + char *padstr; + char *term; + struct winsize win; + +#ifdef do_SIGTTOU +retry: +#endif + no_tty = tcgetattr(fileno(stdout), &otty); + if (!no_tty) { + docrterase = (otty.c_cc[VERASE] != 255); + docrtkill = (otty.c_cc[VKILL] != 255); +#ifdef do_SIGTTOU + { + int tgrp; + /* + * Wait until we're in the foreground before we save the + * the terminal modes. + */ + if ((tgrp = tcgetpgrp(fileno(stdout))) < 0) { + perror("tcgetpgrp"); + exit(1); + } + if (tgrp != getpgrp(0)) { + kill(0, SIGTTOU); + goto retry; + } + } +#endif + if ((term = getenv("TERM")) == 0) { + dumb++; ul_opt = 0; + } + my_setupterm(term, 1, &ret); + if (ret <= 0) { + dumb++; ul_opt = 0; + } + else { +#ifdef TIOCGWINSZ + if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { +#endif + Lpp = my_tgetnum("li","lines"); + Mcol = my_tgetnum("co","cols"); +#ifdef TIOCGWINSZ + } else { + if ((Lpp = win.ws_row) == 0) + Lpp = my_tgetnum("li","lines"); + if ((Mcol = win.ws_col) == 0) + Mcol = my_tgetnum("co","cols"); + } +#endif + if ((Lpp <= 0) || my_tgetflag("hc","hc")) { + hard++; /* Hard copy terminal */ + Lpp = 24; + } + + if (my_tgetflag("xn","xenl")) + eatnl++; /* Eat newline at last column + 1; dec, concept */ + if (Mcol <= 0) + Mcol = 80; + + if (tailequ (fnames[0], "page")) + noscroll++; + Wrap = my_tgetflag("am","am"); + bad_so = my_tgetflag ("xs","xhp"); + eraseln = my_tgetstr("ce","el"); + Clear = my_tgetstr("cl","clear"); + Senter = my_tgetstr("so","smso"); + Sexit = my_tgetstr("se","rmso"); + if ((soglitch = my_tgetnum("sg","xmc")) < 0) + soglitch = 0; + + /* + * Set up for underlining: some terminals don't need it; + * others have start/stop sequences, still others have an + * underline char sequence which is assumed to move the + * cursor forward one character. If underline sequence + * isn't available, settle for standout sequence. + */ + + if (my_tgetflag("ul","ul") || my_tgetflag("os","os")) + ul_opt = 0; + if ((chUL = my_tgetstr("uc","uc")) == NULL ) + chUL = ""; + if (((ULenter = my_tgetstr("us","smul")) == NULL || + (ULexit = my_tgetstr("ue","rmul")) == NULL) && !*chUL) { + if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { + ULenter = ""; + ULexit = ""; + } else + ulglitch = soglitch; + } else { + ulglitch = 0; + } + + if ((padstr = my_tgetstr("pc","pad")) != NULL) + PC = *padstr; + Home = my_tgetstr("ho","home"); + if (Home == 0 || *Home == '\0') { + if ((cursorm = my_tgetstr("cm","cup")) != NULL) { + const char *t = (const char *)my_tgoto(cursorm, 0, 0); + xstrncpy(cursorhome, t, sizeof(cursorhome)); + Home = cursorhome; + } + } + EodClr = my_tgetstr("cd","ed"); + if ((chBS = my_tgetstr("le","cub1")) == NULL) + chBS = "\b"; + + } + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; + } + no_intty = tcgetattr(fileno(stdin), &otty); + tcgetattr(fileno(stderr), &otty); + savetty0 = otty; + slow_tty = cfgetispeed(&otty) < B1200; + hardtabs = (otty.c_oflag & TABDLY) != XTABS; + if (!no_tty) { + otty.c_lflag &= ~(ICANON|ECHO); + otty.c_cc[VMIN] = 1; + otty.c_cc[VTIME] = 0; + } +} + +int readch () { + unsigned char c; + + errno = 0; + if (read (fileno(stderr), &c, 1) <= 0) { + if (errno != EINTR) + end_it(0); + else + c = otty.c_cc[VKILL]; + } + return (c); +} + +static char *BS = "\b"; +static char *BSB = "\b \b"; +static char *CARAT = "^"; +#define ERASEONECOLUMN \ + if (docrterase) \ + putserr(BSB); \ + else \ + putserr(BS); + +void ttyin (char buf[], register int nmax, char pchar) { + char *sp; + int c; + int slash = 0; + int maxlen; + + sp = buf; + maxlen = 0; + while (sp - buf < nmax) { + if (promptlen > maxlen) maxlen = promptlen; + c = readch (); + if (c == '\\') { + slash++; + } + else if (((cc_t) c == otty.c_cc[VERASE]) && !slash) { + if (sp > buf) { +#ifdef HAVE_WIDECHAR + if (MB_CUR_MAX > 1) + { + wchar_t wc; + size_t pos = 0, mblength; + mbstate_t state, state_bak; + + memset (&state, '\0', sizeof (mbstate_t)); + + while (1) { + state_bak = state; + mblength = mbrtowc (&wc, buf + pos, sp - buf, &state); + + state = (mblength == (size_t)-2 + || mblength == (size_t)-1) ? state_bak : state; + mblength = (mblength == (size_t)-2 + || mblength == (size_t)-1 + || mblength == 0) ? 1 : mblength; + + if (buf + pos + mblength >= sp) + break; + + pos += mblength; + } + + if (mblength == 1) { + ERASEONECOLUMN + } + else { + int wc_width; + wc_width = wcwidth (wc); + wc_width = (wc_width < 1) ? 1 : wc_width; + while (wc_width--) { + ERASEONECOLUMN + } + } + + while (mblength--) { + --promptlen; + --sp; + } + } + else +#endif + { + --promptlen; + ERASEONECOLUMN + --sp; + } + + if ((*sp < ' ' && *sp != '\n') || *sp == RUBOUT) { + --promptlen; + ERASEONECOLUMN + } + continue; + } + else { + if (!eraseln) promptlen = maxlen; + siglongjmp (restore, 1); + } + } + else if (((cc_t) c == otty.c_cc[VKILL]) && !slash) { + if (hard) { + show (c); + putchar ('\n'); + putchar (pchar); + } + else { + putchar ('\r'); + putchar (pchar); + if (eraseln) + erasep (1); + else if (docrtkill) + while (promptlen-- > 1) + putserr(BSB); + promptlen = 1; + } + sp = buf; + fflush (stdout); + continue; + } + if (slash && ((cc_t) c == otty.c_cc[VKILL] + || (cc_t) c == otty.c_cc[VERASE])) { + ERASEONECOLUMN + --sp; + } + if (c != '\\') + slash = 0; + *sp++ = c; + if ((c < ' ' && c != '\n' && c != ESC) || c == RUBOUT) { + c += (c == RUBOUT) ? -0100 : 0100; + putserr(CARAT); + promptlen++; + } + if (c != '\n' && c != ESC) { + putcerr(c); + promptlen++; + } + else + break; + } + *--sp = '\0'; + if (!eraseln) promptlen = maxlen; + if (sp - buf >= nmax - 1) + error (_("Line too long")); +} + +/* return: 0 - unchanged, 1 - changed, -1 - overflow (unchanged) */ +int expand (char **outbuf, char *inbuf) { + char *inpstr; + char *outstr; + char c; + char *temp; + int changed = 0; + int tempsz, xtra, offset; + + xtra = strlen (fnames[fnum]) + strlen (shell_line) + 1; + tempsz = 200 + xtra; + temp = malloc(tempsz); + if (!temp) { + error (_("Out of memory")); + return -1; + } + inpstr = inbuf; + outstr = temp; + while ((c = *inpstr++) != '\0'){ + offset = outstr-temp; + if (tempsz-offset-1 < xtra) { + tempsz += 200 + xtra; + temp = realloc(temp, tempsz); + if (!temp) { + error (_("Out of memory")); + return -1; + } + outstr = temp + offset; + } + switch (c) { + case '%': + if (!no_intty) { + strcpy (outstr, fnames[fnum]); + outstr += strlen (fnames[fnum]); + changed++; + } else + *outstr++ = c; + break; + case '!': + if (!shellp) + error (_("No previous command to substitute for")); + strcpy (outstr, shell_line); + outstr += strlen (shell_line); + changed++; + break; + case '\\': + if (*inpstr == '%' || *inpstr == '!') { + *outstr++ = *inpstr++; + break; + } + default: + *outstr++ = c; + } + } + *outstr++ = '\0'; + *outbuf = temp; + return (changed); +} + +void show (char c) { + if ((c < ' ' && c != '\n' && c != ESC) || c == RUBOUT) { + c += (c == RUBOUT) ? -0100 : 0100; + putserr(CARAT); + promptlen++; + } + putcerr(c); + promptlen++; +} + +void error (char *mess) +{ + if (clreol) + cleareol (); + else + kill_line (); + promptlen += strlen (mess); + if (Senter && Sexit) { + my_putstring (Senter); + putsout(mess); + my_putstring (Sexit); + } + else + putsout(mess); + fflush(stdout); + errors++; + siglongjmp (restore, 1); +} + + +void set_tty () { + otty.c_lflag &= ~(ICANON|ECHO); + otty.c_cc[VMIN] = 1; /* read at least 1 char */ + otty.c_cc[VTIME] = 0; /* no timeout */ + stty(fileno(stderr), &otty); +} + +static int +ourputch(int c) { + return putc(c, stdout); +} + +void +reset_tty () { + if (no_tty) + return; + if (pstate) { + tputs(ULexit, 1, ourputch); /* putchar - if that isnt a macro */ + fflush(stdout); + pstate = 0; + } + otty.c_lflag |= ICANON|ECHO; + otty.c_cc[VMIN] = savetty0.c_cc[VMIN]; + otty.c_cc[VTIME] = savetty0.c_cc[VTIME]; + stty(fileno(stderr), &savetty0); +} + +void rdline (register FILE *f) +{ + register int c; + register char *p; + + p = Line; + while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) + *p++ = c; + if (c == '\n') + Currline++; + *p = '\0'; +} + +/* Come here when we get a suspend signal from the terminal */ + +void onsusp (int dummy) { + sigset_t signals, oldmask; + + /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ + signal(SIGTTOU, SIG_IGN); + reset_tty (); + fflush (stdout); + signal(SIGTTOU, SIG_DFL); + /* Send the TSTP signal to suspend our process group */ + signal(SIGTSTP, SIG_DFL); + + /* unblock SIGTSTP or we won't be able to suspend ourself */ + sigemptyset(&signals); + sigaddset(&signals, SIGTSTP); + sigprocmask(SIG_UNBLOCK, &signals, &oldmask); + + kill (0, SIGTSTP); + /* Pause for station break */ + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + + /* We're back */ + signal (SIGTSTP, onsusp); + set_tty (); + if (inwait) + siglongjmp (restore, 1); +} diff --git a/text-utils/odsyntax.c b/text-utils/odsyntax.c new file mode 100644 index 0000000..e7711f9 --- /dev/null +++ b/text-utils/odsyntax.c @@ -0,0 +1,265 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> /* for isdigit() */ +#include <unistd.h> /* for getopt() */ +#include "hexdump.h" +#include "nls.h" + +static void odoffset(int, char ***); +static void odprecede(void); + +int deprecated; + +void +oldsyntax(int argc, char ***argvp) +{ + int ch; + char **argv; + + deprecated = 1; + argv = *argvp; + while ((ch = getopt(argc, argv, "aBbcDdeFfHhIiLlOoPpswvXx")) != -1) + switch (ch) { + case 'a': + odprecede(); + add("16/1 \"%3_u \" \"\\n\""); + break; + case 'B': + case 'o': + odprecede(); + add("8/2 \" %06o \" \"\\n\""); + break; + case 'b': + odprecede(); + add("16/1 \"%03o \" \"\\n\""); + break; + case 'c': + odprecede(); + add("16/1 \"%3_c \" \"\\n\""); + break; + case 'd': + odprecede(); + add("8/2 \" %05u \" \"\\n\""); + break; + case 'D': + odprecede(); + add("4/4 \" %010u \" \"\\n\""); + break; + case 'e': /* undocumented in od */ + case 'F': + odprecede(); + add("2/8 \" %21.14e \" \"\\n\""); + break; + + case 'f': + odprecede(); + add("4/4 \" %14.7e \" \"\\n\""); + break; + case 'H': + case 'X': + odprecede(); + add("4/4 \" %08x \" \"\\n\""); + break; + case 'h': + case 'x': + odprecede(); + add("8/2 \" %04x \" \"\\n\""); + break; + case 'I': + case 'L': + case 'l': + odprecede(); + add("4/4 \" %11d \" \"\\n\""); + break; + case 'i': + odprecede(); + add("8/2 \" %6d \" \"\\n\""); + break; + case 'O': + odprecede(); + add("4/4 \" %011o \" \"\\n\""); + break; + case 'v': + vflag = ALL; + break; + case 'P': + case 'p': + case 's': + case 'w': + case '?': + default: + fprintf(stderr, + _("od: od(1) has been deprecated for hexdump(1).\n")); + if (ch != '?') + fprintf(stderr, +_("od: hexdump(1) compatibility doesn't support the -%c option%s\n"), + ch, ch == 's' ? _("; see strings(1).") : "."); + usage(); + } + + if (!fshead) { + add("\"%07.7_Ao\n\""); + add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\""); + } + + argc -= optind; + *argvp += optind; + + if (argc) + odoffset(argc, argvp); +} + +#define ishexdigit(c) \ + ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) + +static void +odoffset(int argc, char ***argvp) +{ + char *num, *p; + int base; + char *end; + + /* + * The offset syntax of od(1) was genuinely bizarre. First, if + * it started with a plus it had to be an offset. Otherwise, if + * there were at least two arguments, a number or lower-case 'x' + * followed by a number makes it an offset. By default it was + * octal; if it started with 'x' or '0x' it was hex. If it ended + * in a '.', it was decimal. If a 'b' or 'B' was appended, it + * multiplied the number by 512 or 1024 byte units. There was + * no way to assign a block count to a hex offset. + * + * We assume it's a file if the offset is bad. + */ + p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; + if (!p) + return; + + if (*p != '+' && (argc < 2 || + (!isdigit((unsigned char)p[0]) && + (p[0] != 'x' || !ishexdigit(p[1]))))) + return; + + base = 0; + /* + * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and + * set base. + */ + if (p[0] == '+') + ++p; + if (p[0] == 'x' && ishexdigit(p[1])) { + ++p; + base = 16; + } else if (p[0] == '0' && p[1] == 'x') { + p += 2; + base = 16; + } + + /* skip over the number */ + if (base == 16) + for (num = p; ishexdigit(*p); ++p); + else + for (num = p; isdigit((unsigned char)*p); ++p); + + /* check for no number */ + if (num == p) + return; + + /* if terminates with a '.', base is decimal */ + if (*p == '.') { + if (base) + return; + base = 10; + } + + skip = strtol(num, &end, base ? base : 8); + + /* if end isn't the same as p, we got a non-octal digit */ + if (end != p) { + skip = 0; + return; + } + + if (*p) { + if (*p == 'B') { + skip *= 1024; + p++; + } else if (*p == 'b') { + skip *= 512; + p++; + } + } + + if (*p) { + skip = 0; + return; + } + + /* + * If the offset uses a non-octal base, the base of + * the offset is changed as well. This isn't pretty, + * but it's easy. + */ +#define TYPE_OFFSET 7 + if (base == 16) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; + } else if (base == 10) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; + } + + /* Terminate file list. */ + (*argvp)[1] = NULL; +} + +static void +odprecede(void) +{ + static int first = 1; + + if (first) { + first = 0; + add("\"%07.7_Ao\n\""); + add("\"%07.7_ao \""); + } else + add("\" \""); +} diff --git a/text-utils/parse.c b/text-utils/parse.c new file mode 100644 index 0000000..8164c60 --- /dev/null +++ b/text-utils/parse.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include "hexdump.h" +#include "nls.h" + +static void escape(char *p1); +static void badcnt(const char *s); +static void badsfmt(void); +static void badfmt(const char *fmt); +static void badconv(const char *ch); + +FU *endfu; /* format at end-of-data */ + +void addfile(char *name) +{ + char *p; + FILE *fp; + int ch; + char buf[2048 + 1]; + + if ((fp = fopen(name, "r")) == NULL) { + (void)fprintf(stderr, _("hexdump: can't read %s.\n"), name); + exit(1); + } + while (fgets(buf, sizeof(buf), fp)) { + if ((p = strchr(buf, '\n')) == NULL) { + (void)fprintf(stderr, _("hexdump: line too long.\n")); + while ((ch = getchar()) != '\n' && ch != EOF); + continue; + } + *p = '\0'; + for (p = buf; *p && isspace((unsigned char)*p); ++p); + if (!*p || *p == '#') + continue; + add(p); + } + (void)fclose(fp); +} + +void add(const char *fmt) +{ + const char *p; + static FS **nextfs; + FS *tfs; + FU *tfu, **nextfu; + const char *savep; + + /* Start new linked list of format units. */ + tfs = emalloc(sizeof(FS)); + if (!fshead) + fshead = tfs; + else + *nextfs = tfs; + nextfs = &tfs->nextfs; + nextfu = &tfs->nextfu; + + /* Take the format string and break it up into format units. */ + for (p = fmt;;) { + /* Skip leading white space. */ + for (; isspace((unsigned char)*p); ++p); + if (!*p) + break; + + /* Allocate a new format unit and link it in. */ + tfu = emalloc(sizeof(FU)); + *nextfu = tfu; + nextfu = &tfu->nextfu; + tfu->reps = 1; + + /* If leading digit, repetition count. */ + if (isdigit((unsigned char)*p)) { + for (savep = p; isdigit((unsigned char)*p); ++p); + if (!isspace((unsigned char)*p) && *p != '/') + badfmt(fmt); + /* may overwrite either white space or slash */ + tfu->reps = atoi(savep); + tfu->flags = F_SETREP; + /* skip trailing white space */ + for (++p; isspace((unsigned char)*p); ++p); + } + + /* Skip slash and trailing white space. */ + if (*p == '/') + while (isspace((unsigned char)*++p)); + + /* byte count */ + if (isdigit((unsigned char)*p)) { + for (savep = p; isdigit((unsigned char)*p); ++p); + if (!isspace((unsigned char)*p)) + badfmt(fmt); + tfu->bcnt = atoi(savep); + /* skip trailing white space */ + for (++p; isspace((unsigned char)*p); ++p); + } + + /* format */ + if (*p != '"') + badfmt(fmt); + for (savep = ++p; *p != '"';) + if (*p++ == 0) + badfmt(fmt); + if (!(tfu->fmt = malloc(p - savep + 1))) + nomem(); + (void) strncpy(tfu->fmt, savep, p - savep); + tfu->fmt[p - savep] = '\0'; + escape(tfu->fmt); + p++; + } +} + +static const char *spec = ".#-+ 0123456789"; + +int size(FS *fs) +{ + FU *fu; + int bcnt, cursize; + char *fmt; + int prec; + + /* figure out the data block size needed for each format unit */ + for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->bcnt) { + cursize += fu->bcnt * fu->reps; + continue; + } + for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { + if (*fmt != '%') + continue; + /* + * skip any special chars -- save precision in + * case it's a %s format. + */ + while (strchr(spec + 1, *++fmt)); + if (*fmt == '.' && isdigit((unsigned char)*++fmt)) { + prec = atoi(fmt); + while (isdigit((unsigned char)*++fmt)); + } + switch(*fmt) { + case 'c': + bcnt += 1; + break; + case 'd': case 'i': case 'o': case 'u': + case 'x': case 'X': + bcnt += 4; + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + bcnt += 8; + break; + case 's': + bcnt += prec; + break; + case '_': + switch(*++fmt) { + case 'c': case 'p': case 'u': + bcnt += 1; + break; + } + } + } + cursize += bcnt * fu->reps; + } + return(cursize); +} + +void rewrite(FS *fs) +{ + enum { NOTOKAY, USEBCNT, USEPREC } sokay; + PR *pr, **nextpr; + FU *fu; + char *p1, *p2; + char savech, *fmtp, cs[3]; + int nconv, prec; + + nextpr = NULL; + prec = 0; + + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + /* + * Break each format unit into print units; each + * conversion character gets its own. + */ + for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { + pr = emalloc(sizeof(PR)); + if (!fu->nextpr) + fu->nextpr = pr; + else + *nextpr = pr; + + /* Skip preceding text and up to the next % sign. */ + for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); + + /* Only text in the string. */ + if (!*p1) { + pr->fmt = fmtp; + pr->flags = F_TEXT; + break; + } + + /* + * Get precision for %s -- if have a byte count, don't + * need it. + */ + if (fu->bcnt) { + sokay = USEBCNT; + /* skip to conversion character */ + for (++p1; strchr(spec, *p1); ++p1); + } else { + /* skip any special chars, field width */ + while (strchr(spec + 1, *++p1)); + if (*p1 == '.' && + isdigit((unsigned char)*++p1)) { + sokay = USEPREC; + prec = atoi(p1); + while (isdigit((unsigned char)*++p1)); + } else + sokay = NOTOKAY; + } + + p2 = p1 + 1; /* Set end pointer. */ + cs[0] = *p1; /* Set conversion string. */ + cs[1] = 0; + + /* + * Figure out the byte count for each conversion; + * rewrite the format as necessary, set up blank- + * padding for end of data. + */ + switch(cs[0]) { + case 'c': + pr->flags = F_CHAR; + switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 'd': case 'i': + pr->flags = F_INT; + goto isint; + case 'o': case 'u': case 'x': case 'X': + pr->flags = F_UINT; +isint: cs[2] = '\0'; + cs[1] = cs[0]; + cs[0] = 'q'; + switch(fu->bcnt) { + case 0: case 4: + pr->bcnt = 4; + break; + case 1: + pr->bcnt = 1; + break; + case 2: + pr->bcnt = 2; + break; + case 8: + pr->bcnt = 8; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + pr->flags = F_DBL; + switch(fu->bcnt) { + case 0: case 8: + pr->bcnt = 8; + break; + case 4: + pr->bcnt = 4; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 's': + pr->flags = F_STR; + switch(sokay) { + case NOTOKAY: + badsfmt(); + case USEBCNT: + pr->bcnt = fu->bcnt; + break; + case USEPREC: + pr->bcnt = prec; + break; + } + break; + case '_': + ++p2; + switch(p1[1]) { + case 'A': + endfu = fu; + fu->flags |= F_IGNORE; + /* FALLTHROUGH */ + case 'a': + pr->flags = F_ADDRESS; + ++p2; + switch(p1[2]) { + case 'd': case 'o': case'x': + cs[0] = 'q'; + cs[1] = p1[2]; + cs[2] = '\0'; + break; + default: + p1[3] = '\0'; + badconv(p1); + } + break; + case 'c': + pr->flags = F_C; + /* cs[0] = 'c'; set in conv_c */ + goto isint2; + case 'p': + pr->flags = F_P; + cs[0] = 'c'; + goto isint2; + case 'u': + pr->flags = F_U; + /* cs[0] = 'c'; set in conv_u */ +isint2: switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[2] = '\0'; + badcnt(p1); + } + break; + default: + p1[2] = '\0'; + badconv(p1); + } + break; + default: + p1[1] = '\0'; + badconv(p1); + } + + /* + * Copy to PR format string, set conversion character + * pointer, update original. + */ + savech = *p2; + p1[0] = '\0'; + pr->fmt = emalloc(strlen(fmtp) + strlen(cs) + 1); + (void)strcpy(pr->fmt, fmtp); + (void)strcat(pr->fmt, cs); + *p2 = savech; + pr->cchar = pr->fmt + (p1 - fmtp); + fmtp = p2; + + /* Only one conversion character if byte count */ + if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) { + (void)fprintf(stderr, + _("hexdump: byte count with multiple conversion characters.\n")); + exit(1); + } + } + /* + * If format unit byte count not specified, figure it out + * so can adjust rep count later. + */ + if (!fu->bcnt) + for (pr = fu->nextpr; pr; pr = pr->nextpr) + fu->bcnt += pr->bcnt; + } + /* + * If the format string interprets any data at all, and it's + * not the same as the blocksize, and its last format unit + * interprets any data at all, and has no iteration count, + * repeat it as necessary. + * + * If rep count is greater than 1, no trailing whitespace + * gets output from the last iteration of the format unit. + */ + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + if (!fu->nextfu && fs->bcnt < blocksize && + !(fu->flags&F_SETREP) && fu->bcnt) + fu->reps += (blocksize - fs->bcnt) / fu->bcnt; + if (fu->reps > 1) { + for (pr = fu->nextpr;; pr = pr->nextpr) + if (!pr->nextpr) + break; + for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) + p2 = isspace((unsigned char)*p1) ? p1 : NULL; + if (p2) + pr->nospace = p2; + } + } +} + + +static void escape(char *p1) +{ + char *p2; + + /* alphabetic escape sequences have to be done in place */ + for (p2 = p1;; ++p1, ++p2) { + if (!*p1) { + *p2 = *p1; + break; + } + if (*p1 == '\\') + switch(*++p1) { + case 'a': + /* *p2 = '\a'; */ + *p2 = '\007'; + break; + case 'b': + *p2 = '\b'; + break; + case 'f': + *p2 = '\f'; + break; + case 'n': + *p2 = '\n'; + break; + case 'r': + *p2 = '\r'; + break; + case 't': + *p2 = '\t'; + break; + case 'v': + *p2 = '\v'; + break; + default: + *p2 = *p1; + break; + } + } +} + +static void badcnt(const char *s) +{ + (void)fprintf(stderr, + _("hexdump: bad byte count for conversion character %s.\n"), s); + exit(1); +} + +static void badsfmt(void) +{ + (void)fprintf(stderr, + _("hexdump: %%s requires a precision or a byte count.\n")); + exit(1); +} + +static void badfmt(const char *fmt) +{ + (void)fprintf(stderr, _("hexdump: bad format {%s}\n"), fmt); + exit(1); +} + +static void badconv(const char *ch) +{ + (void)fprintf(stderr, _("hexdump: bad conversion character %%%s.\n"), ch); + exit(1); +} diff --git a/text-utils/pg.1 b/text-utils/pg.1 new file mode 100644 index 0000000..b1891ca --- /dev/null +++ b/text-utils/pg.1 @@ -0,0 +1,237 @@ +.\" @(#)pg.1 1.7 (gritter) 4/25/01 +.TH PG 1 "2001-04-25" "Gunnar Ritter" "User Commands" +.SH NAME +pg \- browse pagewise through text files +.SH SYNOPSIS +.B pg +.RB [ \-\fInumber\fP ] +.RB [ \-p +.IR string ] +.RB [ \-cefnrs ] +.RB [ +\fIline\fP ] +.RB [ +/\fIpattern\fP/ ] +.RI [ file ...] +.SH DESCRIPTION +.I Pg +displays a text file on a +.SM CRT +one screenful at once. +After each page, a prompt is displayed. The user may then either press the +newline key to view the next page or one of the keys described below. +.PP +If no filename is given on the command line, +.I pg +reads from standard input. +If the standard output is not a terminal, +.I pg +acts like +.IR cat (1) +but precedes each file with its name if there is more than one. +.PP +If input comes from a pipe, +.I pg +stores the data in a buffer file while reading +to make navigation possible. +.SH OPTIONS +.I Pg +accepts the following options: +.TP +.BI \- number +The number of lines per page. Usually, this is the number of +.SM CRT +lines +minus one. +.TP +.B \-c +Clear the screen before a page is displayed +if the terminfo entry for the terminal provides this capability. +.TP +.B \-e +.I pg +will not pause and display +.SM (EOF) +at the end of a file. +.TP +.B \-f +.I pg +does not split long lines. +.TP +.B \-n +Without this option, commands must be terminated by a newline character. With +this option, +.I pg +advances once a command letter is entered. +.TP +.BI \-p \ string +Instead of the prompt +.I " :" +, +.I string +is displayed. +If +.I string +contains +.I %d +, its first occurrence is replaced by the number of the current page. +.TP +.B \-r +Disallow the shell escape. +.TP +.B \-s +Print messages in +.I standout +mode +if the terminfo entry for the terminal provides this capability. +.TP +.BI + number +Start at the given line. +.TP +.BI +/ pattern / +Start at the line containing the Basic Regular Expression +.I pattern +given. +.SH USAGE +The following commands may be entered at the prompt. Commands preceded by +.I i +in this document accept a number as argument, positive or negative. +If this argument starts with +.I + +or +.I \-, +it is interpreted relative to the current position in the input file, +otherwise relative to the beginning. +.TP +.IB i <newline> +Display the next or the indicated page. +.TP +\fIi\fR\fBd\fR or \fB^D\fR +Display the next halfpage. If +.I i +is given, it is always interpreted relative to the current position. +.TP +.IB i l +Display the next or the indicated line. +.TP +.IB i f +Skip a page forward. +.I i +must be a positive number and is always interpreted relative +to the current position. +.TP +\fIi\fR\fBw\fR or \fIi\fR\fBz\fR +Behave as +.I <newline> +except that +.I i +becomes the new page size. +.TP +.BR . " or " ^L +Redraw the screen. +.TP +.B $ +Advance to the last line of the input file. +.TP +.IB i / pattern / +Search forward until the first or the \fIi\fR-th +occurrence of the Basic Regular Expression +.I pattern +is found. The search starts +after the current page and stops at the end of the file. No wrap-around is +performed. +.I i +must be a positive number. +.TP +\fIi\fR\fB?\fR\fIpattern\fR\fB?\fR or \fIi\fR\fB^\fR\fIpattern\fR\fB^\fR +Search backward until the first or the \fIi\fR-th +occurrence of the Basic Regular Expression +.I pattern +is found. The search starts +before the current page and stops at the beginning of the file. +No wrap-around is performed. +.I i +must be a positive number. +.PP +The search commands accept an added letter. If +.B t +is given, the line containing the pattern is displayed at the top of the +screen, which is the default. +.B m +selects the middle and +.B b +the bottom of the screen. +The selected position is used in following searches, too. +.TP +.IB i n +Advance to the next file or +.I i +files forward. +.TP +.IB i p +Reread the previous file or +.I i +files backward. +.TP +.BI s \ filename +Save the current file to the given +.I filename. +.TP +.B h +Display a command summary. +.TP +.BI ! command +Execute +.I command +using the shell. +.TP +.BR q " or " Q +Quit. +.PP +If the user presses the interrupt or quit key while +.I pg +reads from the +input file or writes on the terminal, +.I pg +will immediately display the prompt. +In all other situations these keys will terminate +.I pg. +.SH "ENVIRONMENT VARIABLES" +The following environment variables +affect the behaviour of +.I pg: +.TP +.B COLUMNS +Overrides the system-supplied number of columns if set. +.TP +.BR LANG ,\ LC_ALL ,\ LC_COLLATE ,\ LC_CTYPE ,\ LC_MESSAGES +See +.IR locale (7). +.TP +.B LINES +Overrides the system-supplied number of lines if set. +.TP +.B SHELL +Used by the +.B ! +command. +.TP +.B TERM +Determines the terminal type. +.SH "SEE ALSO" +.BR cat (1), +.BR more (1), +.BR sh (1), +.BR terminfo (5), +.BR locale (7), +.BR regex (7), +.BR term (7) +.SH NOTES +.I pg +expects the terminal tabulators to set on eight positions. +.PP +Files that include +.SM NUL +characters cannot be displayed by +.IR pg . +.SH AVAILABILITY +The pg command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/pg.c b/text-utils/pg.c new file mode 100644 index 0000000..b2c4d87 --- /dev/null +++ b/text-utils/pg.c @@ -0,0 +1,1768 @@ +/* + * pg - A clone of the System V CRT paging utility. + * + * Copyright (c) 2000-2001 Gunnar Ritter. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. [deleted] + * 4. Neither the name of Gunnar Ritter nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Sccsid @(#)pg.c 1.44 (gritter) 2/8/02 - modified for util-linux */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#ifndef TIOCGWINSZ +#include <sys/ioctl.h> +#endif +#include <sys/termios.h> +#include <fcntl.h> +#include <regex.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <setjmp.h> +#include <libgen.h> + +#ifdef HAVE_NCURSES_H +#include <ncurses.h> +#elif defined(HAVE_NCURSES_NCURSES_H) +#include <ncurses/ncurses.h> +#endif + +#include <term.h> + +#include "nls.h" +#include "widechar.h" + +#define READBUF LINE_MAX /* size of input buffer */ +#define CMDBUF 255 /* size of command buffer */ +#define TABSIZE 8 /* spaces consumed by tab character */ + +/* + * Avoid the message "`var' might be clobbered by `longjmp' or `vfork'" + */ +#define CLOBBGRD(a) (void)(&(a)); + +#define cuc(c) ((c) & 0377) + +enum { FORWARD = 1, BACKWARD = 2 }; /* search direction */ +enum { TOP, MIDDLE, BOTTOM }; /* position of matching line */ + +/* + * States for syntax-aware command line editor. + */ +enum { + COUNT, + SIGN, + CMD_FIN, + SEARCH, + SEARCH_FIN, + ADDON_FIN, + STRING, + INVALID +}; + +/* + * Current command + */ +struct { + char cmdline[CMDBUF]; + size_t cmdlen; + int count; + int key; + char pattern[CMDBUF]; + char addon; +} cmd; + +/* + * Position of file arguments on argv[] to main() + */ +struct { + int first; + int current; + int last; +} files; + +void (*oldint)(int); /* old SIGINT handler */ +void (*oldquit)(int); /* old SIGQUIT handler */ +void (*oldterm)(int); /* old SIGTERM handler */ +char *tty; /* result of ttyname(1) */ +char *progname; /* program name */ +unsigned ontty; /* whether running on tty device */ +unsigned exitstatus; /* exit status */ +int pagelen = 23; /* lines on a single screen page */ +int ttycols = 79; /* screen columns (starting at 0) */ +struct termios otio; /* old termios settings */ +int tinfostat = -1; /* terminfo routines initialized */ +int searchdisplay = TOP; /* matching line position */ +regex_t re; /* regular expression to search for */ +int remembered; /* have a remembered search string */ +int cflag; /* clear screen before each page */ +int eflag; /* suppress (EOF) */ +int fflag; /* do not split lines */ +int nflag; /* no newline for commands required */ +int rflag; /* "restricted" pg */ +int sflag; /* use standout mode */ +char *pstring = ":"; /* prompt string */ +char *searchfor; /* search pattern from argv[] */ +int havepagelen; /* page length is manually defined */ +long startline; /* start line from argv[] */ +int nextfile = 1; /* files to advance */ +jmp_buf jmpenv; /* jump from signal handlers */ +int canjump; /* jmpenv is valid */ +wchar_t wbuf[READBUF]; /* used in several widechar routines */ + +const char *copyright = +"@(#)pg 1.44 2/8/02. Copyright (c) 2000-2001 Gunnar Ritter. "; +const char *helpscreen = N_("All rights reserved.\n\ +-------------------------------------------------------\n\ + h this screen\n\ + q or Q quit program\n\ + <newline> next page\n\ + f skip a page forward\n\ + d or ^D next halfpage\n\ + l next line\n\ + $ last page\n\ + /regex/ search forward for regex\n\ + ?regex? or ^regex^ search backward for regex\n\ + . or ^L redraw screen\n\ + w or z set page size and go to next page\n\ + s filename save current file to filename\n\ + !command shell escape\n\ + p go to previous file\n\ + n go to next file\n\ +\n\ +Many commands accept preceding numbers, for example:\n\ ++1<newline> (next page); -1<newline> (previous page); 1<newline> (first page).\n\ +\n\ +See pg(1) for more information.\n\ +-------------------------------------------------------\n"); + +#ifndef HAVE_FSEEKO + static int fseeko(FILE *f, off_t off, int whence) { + return fseek(f, (long) off, whence); + } + static off_t ftello(FILE *f) { + return (off_t) ftell(f); + } +#endif + +#ifdef USE_SIGSET /* never defined */ +/* sigset and sigrelse are obsolete - use when POSIX stuff is unavailable */ +#define my_sigset sigset +#define my_sigrelse sigrelse +#else +static int my_sigrelse(int sig) { + sigset_t sigs; + + if (sigemptyset(&sigs) || sigaddset(&sigs, sig)) + return -1; + return sigprocmask(SIG_UNBLOCK, &sigs, NULL); +} +typedef void (*my_sighandler_t)(int); +static my_sighandler_t my_sigset(int sig, my_sighandler_t disp) { + struct sigaction act, oact; + + act.sa_handler = disp; + if (sigemptyset(&act.sa_mask)) + return SIG_ERR; + act.sa_flags = 0; + if (sigaction(sig, &act, &oact)) + return SIG_ERR; + if (my_sigrelse(sig)) + return SIG_ERR; + return oact.sa_handler; +} +#endif + +/* + * Quit pg. + */ +static void +quit(int status) +{ + exit(status < 0100 ? status : 077); +} + +/* + * Memory allocator including check. + */ +static char * +smalloc(size_t s) +{ + char *m = (char *)malloc(s); + if (m == NULL) { + const char *p = _("Out of memory\n"); + write(2, p, strlen(p)); + quit(++exitstatus); + } + return m; +} + +/* + * Usage message and similar routines. + */ +static void +usage(void) +{ + fprintf(stderr, _("%s: Usage: %s [-number] [-p string] [-cefnrs] " + "[+line] [+/pattern/] [files]\n"), + progname, progname); + quit(2); +} + +static void +needarg(char *s) +{ + fprintf(stderr, _("%s: option requires an argument -- %s\n"), + progname, s); + usage(); +} + +static void +invopt(char *s) +{ + fprintf(stderr, _("%s: illegal option -- %s\n"), progname, s); + usage(); +} + +#ifdef HAVE_WIDECHAR +/* + * A mbstowcs()-alike function that transparently handles invalid sequences. + */ +static size_t +xmbstowcs(wchar_t *pwcs, const char *s, size_t nwcs) +{ + size_t n = nwcs; + int c; + + mbtowc(pwcs, NULL, MB_CUR_MAX); + while (*s && n) { + if ((c = mbtowc(pwcs, s, MB_CUR_MAX)) < 0) { + s++; + *pwcs = L'?'; + } else + s += c; + pwcs++; + n--; + } + if (n) + *pwcs = L'\0'; + mbtowc(pwcs, NULL, MB_CUR_MAX); + return nwcs - n; +} +#endif + +/* + * Helper function for tputs(). + */ +static int +outcap(int i) +{ + char c = i; + return write(1, &c, 1); +} + +/* + * Write messages to terminal. + */ +static void +mesg(char *message) +{ + if (ontty == 0) + return; + if (*message != '\n' && sflag) + vidputs(A_STANDOUT, outcap); + write(1, message, strlen(message)); + if (*message != '\n' && sflag) + vidputs(A_NORMAL, outcap); +} + +/* + * Get the window size. + */ +static void +getwinsize(void) +{ + static int initialized, envlines, envcols, deflines, defcols; +#ifdef TIOCGWINSZ + struct winsize winsz; + int badioctl; +#endif + char *p; + + if (initialized == 0) { + if ((p = getenv("LINES")) != NULL && *p != '\0') + if ((envlines = atoi(p)) < 0) + envlines = 0; + if ((p = getenv("COLUMNS")) != NULL && *p != '\0') + if ((envcols = atoi(p)) < 0) + envcols = 0; + /* terminfo values. */ + if (tinfostat != 1 || columns == 0) + defcols = 24; + else + defcols = columns; + if (tinfostat != 1 || lines == 0) + deflines = 80; + else + deflines = lines; + initialized = 1; + } +#ifdef TIOCGWINSZ + badioctl = ioctl(1, TIOCGWINSZ, &winsz); +#endif + if (envcols) + ttycols = envcols - 1; +#ifdef TIOCGWINSZ + else if (!badioctl) + ttycols = winsz.ws_col - 1; +#endif + else + ttycols = defcols - 1; + if (havepagelen == 0) { + if (envlines) + pagelen = envlines - 1; +#ifdef TIOCGWINSZ + else if (!badioctl) + pagelen = winsz.ws_row - 1; +#endif + else + pagelen = deflines - 1; + } +} + +/* + * Message if skipping parts of files. + */ +static void +skip(int direction) +{ + if (direction > 0) + mesg(_("...skipping forward\n")); + else + mesg(_("...skipping backward\n")); +} + +/* + * Signal handler while reading from input file. + */ +static void +sighandler(int signum) +{ + if (canjump && (signum == SIGINT || signum == SIGQUIT)) + longjmp(jmpenv, signum); + tcsetattr(1, TCSADRAIN, &otio); + quit(exitstatus); +} + +/* + * Check whether the requested file was specified on the command line. + */ +static int +checkf(void) +{ + if (files.current + nextfile >= files.last) { + mesg(_("No next file")); + return 1; + } + if (files.current + nextfile < files.first) { + mesg(_("No previous file")); + return 1; + } + return 0; +} + +#ifdef HAVE_WIDECHAR +/* + * Return the last character that will fit on the line at col columns + * in case MB_CUR_MAX > 1. + */ +static char * +endline_for_mb(unsigned col, char *s) +{ + unsigned pos = 0; + wchar_t *p = wbuf; + wchar_t *end; + size_t wl; + char *t = s; + + if ((wl = xmbstowcs(wbuf, t, sizeof wbuf - 1)) == (size_t)-1) + return s + 1; + wbuf[wl] = L'\0'; + while (*p != L'\0') { + switch (*p) { + /* + * Cursor left. + */ + case L'\b': + if (pos > 0) + pos--; + break; + /* + * No cursor movement. + */ + case L'\a': + break; + /* + * Special. + */ + case L'\r': + pos = 0; + break; + case L'\n': + end = p + 1; + goto ended; + /* + * Cursor right. + */ + case L'\t': + pos += TABSIZE - (pos % TABSIZE); + break; + default: + pos += wcwidth(*p); + } + if (pos > col) { + if (*p == L'\t') + p++; + else if (pos > col + 1) + /* + * wcwidth() found a character that + * has multiple columns. What happens + * now? Assume the terminal will print + * the entire character onto the next + * row. + */ + p--; + if (*++p == L'\n') + p++; + end = p; + goto ended; + } + p++; + } + end = p; + ended: + *end = L'\0'; + p = wbuf; + if ((pos = wcstombs(NULL, p, READBUF)) == -1) + return s + 1; + return s + pos; +} +#endif + +/* + * Return the last character that will fit on the line at col columns. + */ +static char * +endline(unsigned col, char *s) +{ + unsigned pos = 0; + char *t = s; + +#ifdef HAVE_WIDECHAR + if (MB_CUR_MAX > 1) + return endline_for_mb(col, s); +#endif + + while (*s != '\0') { + switch (*s) { + /* + * Cursor left. + */ + case '\b': + if (pos > 0) + pos--; + break; + /* + * No cursor movement. + */ + case '\a': + break; + /* + * Special. + */ + case '\r': + pos = 0; + break; + case '\n': + t = s + 1; + goto cend; + /* + * Cursor right. + */ + case '\t': + pos += TABSIZE - (pos % TABSIZE); + break; + default: + pos++; + } + if (pos > col) { + if (*s == '\t') + s++; + if (*++s == '\n') + s++; + t = s; + goto cend; + } + s++; + } + t = s; + cend: + return t; +} + +/* + * Clear the current line on the terminal's screen. + */ +static void +cline(void) +{ + char *buf = (char *)smalloc(ttycols + 2); + memset(buf, ' ', ttycols + 2); + buf[0] = '\r'; + buf[ttycols + 1] = '\r'; + write(1, buf, ttycols + 2); + free(buf); +} + +/* + * Evaluate a command character's semantics. + */ +static int +getstate(int c) +{ + switch (c) { + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '0': + case '\0': + return COUNT; + case '-': case '+': + return SIGN; + case 'l': case 'd': case '\004': case 'f': case 'z': + case '.': case '\014': case '$': case 'n': case 'p': + case 'w': case 'h': case 'q': case 'Q': + return CMD_FIN; + case '/': case '?': case '^': + return SEARCH; + case 's': case '!': + return STRING; + case 'm': case 'b': case 't': + return ADDON_FIN; + default: +#ifdef PG_BELL + if (bell) + tputs(bell, 1, outcap); +#endif /* PG_BELL */ + return INVALID; + } +} + +/* + * Get the count and ignore last character of string. + */ +static int +getcount(char *cmdstr) +{ + char *buf; + char *p; + int i; + + if (*cmdstr == '\0') + return 1; + buf = (char *)smalloc(strlen(cmdstr) + 1); + strcpy(buf, cmdstr); + if (cmd.key != '\0') { + if (cmd.key == '/' || cmd.key == '?' || cmd.key == '^') { + if ((p = strchr(buf, cmd.key)) != NULL) + *p = '\0'; + } else + *(buf + strlen(buf) - 1) = '\0'; + } + if (*buf == '\0') + return 1; + if (buf[0] == '-' && buf[1] == '\0') { + i = -1; + } else { + if (*buf == '+') + i = atoi(buf + 1); + else + i = atoi(buf); + } + free(buf); + return i; +} + +/* + * Read what the user writes at the prompt. This is tricky because + * we check for valid input. + */ +static void +prompt(long long pageno) +{ + struct termios tio; + char key; + int state = COUNT; + int escape = 0; + char b[LINE_MAX], *p; + + if (pageno != -1) { + if ((p = strstr(pstring, "%d")) == NULL) { + mesg(pstring); + } else { + strcpy(b, pstring); + sprintf(b + (p - pstring), "%lld", pageno); + strcat(b, p + 2); + mesg(b); + } + } + cmd.key = cmd.addon = cmd.cmdline[0] = '\0'; + cmd.cmdlen = 0; + tcgetattr(1, &tio); + tio.c_lflag &= ~(ICANON | ECHO); + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr(1, TCSADRAIN, &tio); + tcflush(1, TCIFLUSH); + for (;;) { + switch (read(1, &key, 1)) { + case 0: quit(0); + /*NOTREACHED*/ + case -1: quit(1); + } + if (key == tio.c_cc[VERASE]) { + if (cmd.cmdlen) { + write(1, "\b \b", 3); + cmd.cmdline[--cmd.cmdlen] = '\0'; + switch (state) { + case ADDON_FIN: + state = SEARCH_FIN; + cmd.addon = '\0'; + break; + case CMD_FIN: + cmd.key = '\0'; + state = COUNT; + break; + case SEARCH_FIN: + state = SEARCH; + /*FALLTHRU*/ + case SEARCH: + if (cmd.cmdline[cmd.cmdlen - 1] + == '\\') { + escape = 1; + while(cmd.cmdline[cmd.cmdlen + - escape - 1] + == '\\') escape++; + escape %= 2; + } + else { + escape = 0; + if (strchr(cmd.cmdline, cmd.key) + == NULL) { + cmd.key = '\0'; + state = COUNT; + } + } + break; + } + } + if (cmd.cmdlen == 0) { + state = COUNT; + cmd.key = '\0'; + } + continue; + } + if (key == tio.c_cc[VKILL]) { + cline(); + cmd.cmdlen = 0; + cmd.cmdline[0] = '\0'; + state = COUNT; + cmd.key = '\0'; + continue; + } + if (key == '\n' || (nflag && state == COUNT && key == ' ')) + break; + if (cmd.cmdlen >= CMDBUF - 1) + continue; + switch (state) { + case STRING: + break; + case SEARCH: + if (!escape) { + if (key == cmd.key) + state = SEARCH_FIN; + if (key == '\\') + escape = 1; + } else + escape = 0; + break; + case SEARCH_FIN: + if (getstate(key) != ADDON_FIN) + continue; + state = ADDON_FIN; + cmd.addon = key; + switch (key) { + case 't': + searchdisplay = TOP; + break; + case 'm': + searchdisplay = MIDDLE; + break; + case 'b': + searchdisplay = BOTTOM; + break; + } + break; + case CMD_FIN: + case ADDON_FIN: + continue; + default: + state = getstate(key); + switch (state) { + case SIGN: + if (cmd.cmdlen != 0) { + state = INVALID; + continue; + } + state = COUNT; + /*FALLTHRU*/ + case COUNT: + break; + case ADDON_FIN: + case INVALID: + continue; + default: + cmd.key = key; + } + } + write(1, &key, 1); + cmd.cmdline[cmd.cmdlen++] = key; + cmd.cmdline[cmd.cmdlen] = '\0'; + if (nflag && state == CMD_FIN) + goto endprompt; + } +endprompt: + tcsetattr(1, TCSADRAIN, &otio); + cline(); + cmd.count = getcount(cmd.cmdline); +} + +#ifdef HAVE_WIDECHAR +/* + * Remove backspace formatting, for searches + * in case MB_CUR_MAX > 1. + */ +static char * +colb_for_mb(char *s) +{ + char *p = s; + wchar_t *wp, *wq; + size_t l = strlen(s), wl; + unsigned i; + + if ((wl = xmbstowcs(wbuf, p, sizeof wbuf)) == (size_t)-1) + return s; + for (wp = wbuf, wq = wbuf, i = 0; *wp != L'\0' && i < wl; + wp++, wq++) { + if (*wp == L'\b') { + if (wq != wbuf) + wq -= 2; + else + wq--; + } else + *wq = *wp; + } + *wq = L'\0'; + wp = wbuf; + wcstombs(s, wp, l + 1); + + return s; +} +#endif + +/* + * Remove backspace formatting, for searches. + */ +static char * +colb(char *s) +{ + char *p = s, *q; + +#ifdef HAVE_WIDECHAR + if (MB_CUR_MAX > 1) + return colb_for_mb(s); +#endif + + for (q = s; *p != '\0'; p++, q++) { + if (*p == '\b') { + if (q != s) + q -= 2; + else + q--; + } else + *q = *p; + } + *q = '\0'; + + return s; +} + +#ifdef HAVE_WIDECHAR +/* + * Convert nonprintable characters to spaces + * in case MB_CUR_MAX > 1. + */ +static void +makeprint_for_mb(char *s, size_t l) +{ + char *t = s; + wchar_t *wp = wbuf; + size_t wl; + + if ((wl = xmbstowcs(wbuf, t, sizeof wbuf)) == (size_t)-1) + return; + while (wl--) { + if (!iswprint(*wp) && *wp != L'\n' && *wp != L'\r' + && *wp != L'\b' && *wp != L'\t') + *wp = L'?'; + wp++; + } + wp = wbuf; + wcstombs(s, wp, l); +} +#endif + +/* + * Convert nonprintable characters to spaces. + */ +static void +makeprint(char *s, size_t l) +{ +#ifdef HAVE_WIDECHAR + if (MB_CUR_MAX > 1) + return makeprint_for_mb(s, l); +#endif + + while (l--) { + if (!isprint(cuc(*s)) && *s != '\n' && *s != '\r' + && *s != '\b' && *s != '\t') + *s = '?'; + s++; + } +} + +/* + * Strip backslash characters from the given string. + */ +static void +striprs(char *s) +{ + char *p = s; + + do { + if (*s == '\\') { + s++; + } + *p++ = *s; + } while (*s++ != '\0'); +} + +/* + * Extract the search pattern off the command line. + */ +static char * +makepat(void) +{ + char *p; + + if (cmd.addon == '\0') + p = cmd.cmdline + strlen(cmd.cmdline) - 1; + else + p = cmd.cmdline + strlen(cmd.cmdline) - 2; + if (*p == cmd.key) + *p = '\0'; + else + *(p + 1) = '\0'; + if ((p = strchr(cmd.cmdline, cmd.key)) != NULL) { + p++; + striprs(p); + } + return p; +} + +/* + * Process errors that occurred in temporary file operations. + */ +static void +tmperr(FILE *f, char *ftype) +{ + if (ferror(f)) + fprintf(stderr, _("%s: Read error from %s file\n"), + progname, ftype); + else if (feof(f)) + /* + * Most likely '\0' in input. + */ + fprintf(stderr, _("%s: Unexpected EOF in %s file\n"), + progname, ftype); + else + fprintf(stderr, _("%s: Unknown error in %s file\n"), + progname, ftype); + quit(++exitstatus); +} + +/* + * perror()-like, but showing the program's name. + */ +static void +pgerror(int eno, char *string) +{ + fprintf(stderr, "%s: %s: %s\n", progname, string, strerror(eno)); +} + +/* + * Read the file and respond to user input. + * Beware: long and ugly. + */ +static void +pgfile(FILE *f, char *name) +{ + off_t pos, oldpos, fpos; + off_t line = 0, fline = 0, bline = 0, oldline = 0, eofline = 0; + int dline = 0; + /* + * These are the line counters: + * line the line desired to display + * fline the current line of the input file + * bline the current line of the file buffer + * oldline the line before a search was started + * eofline the last line of the file if it is already reached + * dline the line on the display + */ + int search = 0; + unsigned searchcount = 0; + /* + * Advance to EOF immediately. + */ + int seekeof = 0; + /* + * EOF has been reached by `line'. + */ + int eof = 0; + /* + * f and fbuf refer to the same file. + */ + int nobuf = 0; + int sig; + int rerror; + size_t sz; + char b[READBUF + 1]; + char *p; + /* + * fbuf an exact copy of the input file as it gets read + * find index table for input, one entry per line + * save for the s command, to save to a file + */ + FILE *fbuf, *find, *save; + + /* silence compiler - it may warn about longjmp() */ + CLOBBGRD(line); + CLOBBGRD(fline); + CLOBBGRD(bline); + CLOBBGRD(oldline); + CLOBBGRD(eofline); + CLOBBGRD(dline); + CLOBBGRD(ttycols); + CLOBBGRD(search); + CLOBBGRD(searchcount); + CLOBBGRD(seekeof); + CLOBBGRD(eof); + CLOBBGRD(fpos); + CLOBBGRD(nobuf); + CLOBBGRD(fbuf); + + if (ontty == 0) { + /* + * Just copy stdin to stdout. + */ + while ((sz = fread(b, sizeof *b, READBUF, f)) != 0) + write(1, b, sz); + if (ferror(f)) { + pgerror(errno, name); + exitstatus++; + } + return; + } + if ((fpos = fseeko(f, (off_t)0, SEEK_SET)) == -1) + fbuf = tmpfile(); + else { + fbuf = f; + nobuf = 1; + } + find = tmpfile(); + if (fbuf == NULL || find == NULL) { + fprintf(stderr, _("%s: Cannot create tempfile\n"), progname); + quit(++exitstatus); + } + if (searchfor) { + search = FORWARD; + oldline = 0; + searchcount = 1; + rerror = regcomp(&re, searchfor, REG_NOSUB | REG_NEWLINE); + if (rerror != 0) { + mesg(_("RE error: ")); + regerror(rerror, &re, b, READBUF); + mesg(b); + goto newcmd; + } + remembered = 1; + } + + for (line = startline; ; ) { + /* + * Get a line from input file or buffer. + */ + if (line < bline) { + fseeko(find, line * sizeof pos, SEEK_SET); + if (fread(&pos, sizeof pos, 1, find) == 0) + tmperr(find, "index"); + fseeko(find, (off_t)0, SEEK_END); + fseeko(fbuf, pos, SEEK_SET); + if (fgets(b, READBUF, fbuf) == NULL) + tmperr(fbuf, "buffer"); + } else if (eofline == 0) { + fseeko(find, (off_t)0, SEEK_END); + do { + if (!nobuf) + fseeko(fbuf, (off_t)0, SEEK_END); + pos = ftello(fbuf); + if ((sig = setjmp(jmpenv)) != 0) { + /* + * We got a signal. + */ + canjump = 0; + my_sigrelse(sig); + fseeko(fbuf, pos, SEEK_SET); + *b = '\0'; + dline = pagelen; + break; + } else { + if (nobuf) + fseeko(f, fpos, SEEK_SET); + canjump = 1; + p = fgets(b, READBUF, f); + if (nobuf) + if ((fpos = ftello(f)) == -1) + pgerror(errno, name); + canjump = 0; + } + if (p == NULL || *b == '\0') { + if (ferror(f)) + pgerror(errno, name); + eofline = fline; + eof = 1; + break; + } else { + if (!nobuf) + fputs(b, fbuf); + fwrite(&pos, sizeof pos, 1, find); + if (!fflag) { + oldpos = pos; + p = b; + while (*(p = endline(ttycols, + p)) + != '\0') { + pos = oldpos + (p - b); + fwrite(&pos, + sizeof pos, + 1, find); + fline++; + bline++; + } + } + fline++; + } + } while (line > bline++); + } else { + /* + * eofline != 0 + */ + eof = 1; + } + if (search == FORWARD && remembered == 1) { + if (eof) { + line = oldline; + search = searchcount = 0; + mesg(_("Pattern not found")); + eof = 0; + goto newcmd; + } + line++; + colb(b); + if (regexec(&re, b, 0, NULL, 0) == 0) { + searchcount--; + } + if (searchcount == 0) { + search = dline = 0; + switch (searchdisplay) { + case TOP: + line -= 1; + break; + case MIDDLE: + line -= pagelen / 2 + 1; + break; + case BOTTOM: + line -= pagelen; + break; + } + skip(1); + } + continue; + } else if (eof) { /* + * We are not searching. + */ + line = bline; + } else if (*b != '\0') { + if (cflag && clear_screen) { + switch (dline) { + case 0: + tputs(clear_screen, 1, outcap); + dline = 0; + } + } + line++; + if (eofline && line == eofline) + eof = 1; + dline++; + if ((sig = setjmp(jmpenv)) != 0) { + /* + * We got a signal. + */ + canjump = 0; + my_sigrelse(sig); + dline = pagelen; + } else { + p = endline(ttycols, b); + sz = p - b; + makeprint(b, sz); + canjump = 1; + write(1, b, sz); + canjump = 0; + } + } + if (dline >= pagelen || eof) { + /* + * Time for prompting! + */ + if (eof && seekeof) { + eof = seekeof = 0; + if (line >= pagelen) + line -= pagelen; + else + line = 0; + dline = -1; + continue; + } +newcmd: + if (eof) { + if (fline == 0 || eflag) + break; + mesg(_("(EOF)")); + } + prompt((line - 1) / pagelen + 1); + switch (cmd.key) { + case '/': + /* + * Search forward. + */ + search = FORWARD; + oldline = line; + searchcount = cmd.count; + p = makepat(); + if (p != NULL && *p) { + if (remembered == 1) + regfree(&re); + rerror = regcomp(&re, p, + REG_NOSUB | REG_NEWLINE); + if (rerror != 0) { + mesg(_("RE error: ")); + sz = regerror(rerror, &re, + b, READBUF); + mesg(b); + goto newcmd; + } + remembered = 1; + } else if (remembered == 0) { + mesg(_("No remembered search string")); + goto newcmd; + } + continue; + case '?': + case '^': + /* + * Search backward. + */ + search = BACKWARD; + oldline = line; + searchcount = cmd.count; + p = makepat(); + if (p != NULL && *p) { + if (remembered == 1) + regfree(&re); + rerror = regcomp(&re, p, + REG_NOSUB | REG_NEWLINE); + if (rerror != 0) { + mesg(_("RE error: ")); + regerror(rerror, &re, + b, READBUF); + mesg(b); + goto newcmd; + } + remembered = 1; + } else if (remembered == 0) { + mesg(_("No remembered search string")); + goto newcmd; + } + line -= pagelen; + if (line <= 0) + goto notfound_bw; + while (line) { + fseeko(find, --line * sizeof pos, + SEEK_SET); + if(fread(&pos, sizeof pos, 1,find)==0) + tmperr(find, "index"); + fseeko(find, (off_t)0, SEEK_END); + fseeko(fbuf, pos, SEEK_SET); + if (fgets(b, READBUF, fbuf) == NULL) + tmperr(fbuf, "buffer"); + colb(b); + if (regexec(&re, b, 0, NULL, 0) == 0) + searchcount--; + if (searchcount == 0) + goto found_bw; + } +notfound_bw: + line = oldline; + search = searchcount = 0; + mesg(_("Pattern not found")); + goto newcmd; +found_bw: + eof = search = dline = 0; + skip(-1); + switch (searchdisplay) { + case TOP: + /* line -= 1; */ + break; + case MIDDLE: + line -= pagelen / 2; + break; + case BOTTOM: + if (line != 0) + dline = -1; + line -= pagelen; + break; + } + if (line < 0) + line = 0; + continue; + case 's': + /* + * Save to file. + */ + p = cmd.cmdline; + while (*++p == ' '); + if (*p == '\0') + goto newcmd; + save = fopen(p, "wb"); + if (save == NULL) { + cmd.count = errno; + mesg(_("Cannot open ")); + mesg(p); + mesg(": "); + mesg(strerror(cmd.count)); + goto newcmd; + } + /* + * Advance to EOF. + */ + fseeko(find, (off_t)0, SEEK_END); + for (;;) { + if (!nobuf) + fseeko(fbuf,(off_t)0,SEEK_END); + pos = ftello(fbuf); + if (fgets(b, READBUF, f) == NULL) { + eofline = fline; + break; + } + if (!nobuf) + fputs(b, fbuf); + fwrite(&pos, sizeof pos, 1, find); + if (!fflag) { + oldpos = pos; + p = b; + while (*(p = endline(ttycols, + p)) + != '\0') { + pos = oldpos + (p - b); + fwrite(&pos, + sizeof pos, + 1, find); + fline++; + bline++; + } + } + fline++; + bline++; + } + fseeko(fbuf, (off_t)0, SEEK_SET); + while ((sz = fread(b, sizeof *b, READBUF, + fbuf)) != 0) { + /* + * No error check for compat. + */ + fwrite(b, sizeof *b, sz, save); + } + fclose(save); + fseeko(fbuf, (off_t)0, SEEK_END); + mesg(_("saved")); + goto newcmd; + case 'l': + /* + * Next line. + */ + if (*cmd.cmdline != 'l') + eof = 0; + if (cmd.count == 0) + cmd.count = 1; /* compat */ + if (isdigit(cuc(*cmd.cmdline))) { + line = cmd.count - 2; + dline = 0; + } else { + if (cmd.count != 1) { + line += cmd.count - 1 + - pagelen; + dline = -1; + skip(cmd.count); + } + /* + * Nothing to do if count==1. + */ + } + break; + case 'd': + /* + * Half screen forward. + */ + case '\004': /* ^D */ + if (*cmd.cmdline != cmd.key) + eof = 0; + if (cmd.count == 0) + cmd.count = 1; /* compat */ + line += (cmd.count * pagelen / 2) + - pagelen - 1; + dline = -1; + skip(cmd.count); + break; + case 'f': + /* + * Skip forward. + */ + if (cmd.count <= 0) + cmd.count = 1; /* compat */ + line += cmd.count * pagelen - 2; + if (eof) + line += 2; + if (*cmd.cmdline != 'f') + eof = 0; + else if (eof) + break; + if (eofline && line >= eofline) + line -= pagelen; + dline = -1; + skip(cmd.count); + break; + case '\0': + /* + * Just a number, or '-', or <newline>. + */ + if (cmd.count == 0) + cmd.count = 1; /* compat */ + if (isdigit(cuc(*cmd.cmdline))) + line = (cmd.count - 1) * pagelen - 2; + else + line += (cmd.count - 1) + * (pagelen - 1) - 2; + if (*cmd.cmdline != '\0') + eof = 0; + if (cmd.count != 1) { + skip(cmd.count); + dline = -1; + } else { + dline = 1; + line += 2; + } + break; + case '$': + /* + * Advance to EOF. + */ + if (!eof) + skip(1); + eof = 0; + line = LONG_MAX; + seekeof = 1; + dline = -1; + break; + case '.': + case '\014': /* ^L */ + /* + * Repaint screen. + */ + eof = 0; + if (line >= pagelen) + line -= pagelen; + else + line = 0; + dline = 0; + break; + case '!': + /* + * Shell escape. + */ + if (rflag) { + mesg(progname); + mesg(_(": !command not allowed in " + "rflag mode.\n")); + } else { + pid_t cpid; + + write(1, cmd.cmdline, + strlen(cmd.cmdline)); + write(1, "\n", 1); + my_sigset(SIGINT, SIG_IGN); + my_sigset(SIGQUIT, SIG_IGN); + switch (cpid = fork()) { + case 0: + p = getenv("SHELL"); + if (p == NULL) p = "/bin/sh"; + if (!nobuf) + fclose(fbuf); + fclose(find); + if (isatty(0) == 0) { + close(0); + open(tty, O_RDONLY); + } else { + fclose(f); + } + my_sigset(SIGINT, oldint); + my_sigset(SIGQUIT, oldquit); + my_sigset(SIGTERM, oldterm); + execl(p, p, "-c", + cmd.cmdline + 1, NULL); + pgerror(errno, p); + _exit(0177); + /*NOTREACHED*/ + case -1: + mesg(_("fork() failed, " + "try again later\n")); + break; + default: + while (wait(NULL) != cpid); + } + my_sigset(SIGINT, sighandler); + my_sigset(SIGQUIT, sighandler); + mesg("!\n"); + } + goto newcmd; + case 'h': + { + /* + * Help! + */ + const char *help = _(helpscreen); + write(1, copyright + 4, strlen(copyright + 4)); + write(1, help, strlen(help)); + goto newcmd; + } + case 'n': + /* + * Next file. + */ + if (cmd.count == 0) + cmd.count = 1; + nextfile = cmd.count; + if (checkf()) { + nextfile = 1; + goto newcmd; + } + eof = 1; + break; + case 'p': + /* + * Previous file. + */ + if (cmd.count == 0) + cmd.count = 1; + nextfile = 0 - cmd.count; + if (checkf()) { + nextfile = 1; + goto newcmd; + } + eof = 1; + break; + case 'q': + case 'Q': + /* + * Exit pg. + */ + quit(exitstatus); + /*NOTREACHED*/ + case 'w': + case 'z': + /* + * Set window size. + */ + if (cmd.count < 0) + cmd.count = 0; + if (*cmd.cmdline != cmd.key) + pagelen = ++cmd.count; + dline = 1; + break; + } + if (line <= 0) { + line = 0; + dline = 0; + } + if (cflag && dline == 1) { + dline = 0; + line--; + } + } + if (eof) + break; + } + fclose(find); + if (!nobuf) + fclose(fbuf); +} + +int +main(int argc, char **argv) +{ + int arg, i; + char *p; + FILE *input; + + progname = basename(argv[0]); + + setlocale(LC_MESSAGES, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + if (tcgetattr(1, &otio) == 0) { + ontty = 1; + oldint = my_sigset(SIGINT, sighandler); + oldquit = my_sigset(SIGQUIT, sighandler); + oldterm = my_sigset(SIGTERM, sighandler); + setlocale(LC_CTYPE, ""); + setlocale(LC_COLLATE, ""); + tty = ttyname(1); + setupterm(NULL, 1, &tinfostat); + getwinsize(); + helpscreen = _(helpscreen); + } + for (arg = 1; argv[arg]; arg++) { + if (*argv[arg] == '+') + continue; + if (*argv[arg] != '-' || argv[arg][1] == '\0') + break; + argc--; + for (i = 1; argv[arg][i]; i++) { + switch (argv[arg][i]) { + case '-': + if (i != 1 || argv[arg][i + 1]) + invopt(&argv[arg][i]); + goto endargs; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '0': + pagelen = atoi(argv[arg] + i); + havepagelen = 1; + goto nextarg; + case 'c': + cflag = 1; + break; + case 'e': + eflag = 1; + break; + case 'f': + fflag = 1; + break; + case 'n': + nflag = 1; + break; + case 'p': + if (argv[arg][i + 1]) { + pstring = &argv[arg][i + 1]; + } else if (argv[++arg]) { + --argc; + pstring = argv[arg]; + } else + needarg("-p"); + goto nextarg; + case 'r': + rflag = 1; + break; + case 's': + sflag = 1; + break; + default: + invopt(&argv[arg][i]); + } + } +nextarg: + ; + } +endargs: + for (arg = 1; argv[arg]; arg++) { + if (*argv[arg] == '-') { + if (argv[arg][1] == '-') { + arg++; + break; + } + if (argv[arg][1] == '\0') + break; + if (argv[arg][1] == 'p' && argv[arg][2] == '\0') + arg++; + continue; + } + if (*argv[arg] != '+') + break; + argc--; + switch (*(argv[arg] + 1)) { + case '\0': + needarg("+"); + /*NOTREACHED*/ + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '0': + startline = atoi(argv[arg] + 1); + break; + case '/': + searchfor = argv[arg] + 2; + if (*searchfor == '\0') + needarg("+/"); + p = searchfor + strlen(searchfor) - 1; + if (*p == '/') *p = '\0'; + if (*searchfor == '\0') + needarg("+/"); + break; + default: + invopt(argv[arg]); + } + } + if (argc == 1) { + pgfile(stdin, "stdin"); + } else { + files.first = arg; + files.last = arg + argc - 1; + for ( ; argv[arg]; arg += nextfile) { + nextfile = 1; + files.current = arg; + if (argc > 2) { + static int firsttime; + firsttime++; + if (firsttime > 1) { + mesg(_("(Next file: ")); + mesg(argv[arg]); + mesg(")"); +newfile: + if (ontty) { + prompt(-1); + switch(cmd.key) { + case 'n': + /* + * Next file. + */ + if (cmd.count == 0) + cmd.count = 1; + nextfile = cmd.count; + if (checkf()) { + nextfile = 1; + mesg(":"); + goto newfile; + } + continue; + case 'p': + /* + * Previous file. + */ + if (cmd.count == 0) + cmd.count = 1; + nextfile = 0 - cmd.count; + if (checkf()) { + nextfile = 1; + mesg(":"); + goto newfile; + } + continue; + case 'q': + case 'Q': + quit(exitstatus); + } + } else mesg("\n"); + } + } + if (strcmp(argv[arg], "-") == 0) + input = stdin; + else { + input = fopen(argv[arg], "r"); + if (input == NULL) { + pgerror(errno, argv[arg]); + exitstatus++; + continue; + } + } + if (ontty == 0 && argc > 2) { + /* + * Use the prefix as specified by SUSv2. + */ + write(1, "::::::::::::::\n", 15); + write(1, argv[arg], strlen(argv[arg])); + write(1, "\n::::::::::::::\n", 16); + } + pgfile(input, argv[arg]); + if (input != stdin) + fclose(input); + } + } + quit(exitstatus); + /*NOTREACHED*/ + return 0; +} diff --git a/text-utils/rev.1 b/text-utils/rev.1 new file mode 100644 index 0000000..6288616 --- /dev/null +++ b/text-utils/rev.1 @@ -0,0 +1,53 @@ +.\" Copyright (c) 1985, 1992 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)rev.1 6.3 (Berkeley) 3/21/92 +.\" Modified for Linux by Charles Hannum (mycroft@gnu.ai.mit.edu) +.\" and Brian Koehmstedt (bpk@gnu.ai.mit.edu) +.\" +.Dd March 21, 1992 +.Dt REV 1 +.Os +.Sh NAME +.Nm rev +.Nd reverse lines of a file or files +.Sh SYNOPSIS +.Nm rev +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm rev +utility copies the specified files to the standard output, reversing the +order of characters in every line. +If no files are specified, the standard input is read. +.Sh AVAILABILITY +The rev command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/rev.c b/text-utils/rev.c new file mode 100644 index 0000000..3ae38cf --- /dev/null +++ b/text-utils/rev.c @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 1987, 1992 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Modified for Linux by Charles Hannum (mycroft@gnu.ai.mit.edu) + * and Brian Koehmstedt (bpk@gnu.ai.mit.edu) + * + * Wed Sep 14 22:26:00 1994: Patch from bjdouma <bjdouma@xs4all.nl> to handle + * last line that has no newline correctly. + * 3-Jun-1998: Patched by Nicolai Langfeldt to work better on Linux: + * Handle any-length-lines. Code copied from util-linux' setpwnam.c + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * added Native Language Support + * 1999-09-19 Bruno Haible <haible@clisp.cons.org> + * modified to work correctly in multi-byte locales + * + */ + +#include <stdarg.h> +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <err.h> + +#include "nls.h" +#include "widechar.h" + +void usage(void); + +int +main(int argc, char *argv[]) +{ + register char *filename; + register wchar_t *t; + size_t buflen = 512; + wchar_t *p = malloc(buflen*sizeof(wchar_t)); + size_t len; + FILE *fp; + int ch, rval; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + while ((ch = getopt(argc, argv, "")) != -1) + switch(ch) { + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + fp = stdin; + filename = "stdin"; + rval = 0; + do { + if (*argv) { + if ((fp = fopen(*argv, "r")) == NULL) { + warn("cannot open %s", *argv ); + rval = 1; + ++argv; + continue; + } + filename = *argv++; + } + + while (fgetws(p, buflen, fp)) { + + len = wcslen(p); + + /* This is my hack from setpwnam.c -janl */ + while (p[len-1] != '\n' && !feof(fp)) { + /* Extend input buffer if it failed getting the whole line */ + + /* So now we double the buffer size */ + buflen *= 2; + + p = realloc(p, buflen*sizeof(wchar_t)); + if (p == NULL) + err(1, _("unable to allocate bufferspace")); + + /* And fill the rest of the buffer */ + if (fgetws(&p[len], buflen/2, fp) == NULL) break; + + len = wcslen(p); + + /* That was a lot of work for nothing. Gimme perl! */ + } + + t = p + len - 1 - (*(p+len-1)=='\r' || *(p+len-1)=='\n'); + for ( ; t >= p; --t) + if (*t != 0) + putwchar(*t); + putwchar('\n'); + } + fflush(fp); + if (ferror(fp)) { + warn("%s", filename); + rval = 1; + } + if (fclose(fp)) + rval = 1; + } while(*argv); + exit(rval); +} + +void +usage(void) +{ + (void)fprintf(stderr, _("usage: rev [file ...]\n")); + exit(1); +} diff --git a/text-utils/tailf.1 b/text-utils/tailf.1 new file mode 100644 index 0000000..294d9d6 --- /dev/null +++ b/text-utils/tailf.1 @@ -0,0 +1,61 @@ +.\" tailf.1 -- +.\" Created: Thu Jan 11 16:43:10 1996 by faith@acm.org +.\" Copyright 1996, 2003 Rickard E. Faith (faith@acm.org) +.\" +.\" Permission is granted to make and distribute verbatim copies of this +.\" manual provided the copyright notice and this permission notice are +.\" preserved on all copies. +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" manual under the conditions for verbatim copying, provided that the +.\" entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one. +.\" +.\" Since the Linux kernel and libraries are constantly changing, this +.\" manual page may be incorrect or out-of-date. The author(s) assume no +.\" responsibility for errors or omissions, or for damages resulting from +.\" the use of the information contained herein. The author(s) may not +.\" have taken the same level of care in the production of this manual, +.\" which is licensed free of charge, as they might when working +.\" professionally. +.\" +.\" Formatted or processed versions of this manual, if unaccompanied by +.\" the source, must acknowledge the copyright and authors of this work. +.\" +.TH TAILF 1 "13 February 2003" "" "Linux Programmer's Manual" +.SH NAME +tailf \- follow the growth of a log file +.SH SYNOPSIS +.B tailf +[\fIOPTION\fR] \fIfile\fR +.SH DESCRIPTION +.B tailf +will print out the last 10 lines of a file and then wait for the file to +grow. It is similar to +.B tail -f +but does not access the file when it is not growing. This has the side +effect of not updating the access time for the file, so a filesystem flush +does not occur periodically when no log activity is happening. +.PP +.B tailf +is extremely useful for monitoring log files on a laptop when logging is +infrequent and the user desires that the hard disk spin down to conserve +battery life. +.PP +Mandatory arguments to long options are mandatory for short options too. +.TP +\fB\-n\fR, \fB\-\-lines\fR=\fIN\fR, \fB\-N\fR +output the last +.I N +lines, instead of the last 10. +.SH AUTHOR +This program was originally written by Rik Faith (faith@acm.org) and may be freely +distributed under the terms of the X11/MIT License. There is ABSOLUTELY +NO WARRANTY for this program. + +The latest inotify based implementation was written by Karel Zak (kzak@redhat.com). +.SH "SEE ALSO" +.BR tail "(1), " less "(1)" +.SH AVAILABILITY +The tailf command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/tailf.c b/text-utils/tailf.c new file mode 100644 index 0000000..75998ce --- /dev/null +++ b/text-utils/tailf.c @@ -0,0 +1,227 @@ +/* tailf.c -- tail a log file and then follow it + * Created: Tue Jan 9 15:49:21 1996 by faith@acm.org + * Copyright 1996, 2003 Rickard E. Faith (faith@acm.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * less -F and tail -f cause a disk access every five seconds. This + * program avoids this problem by waiting for the file size to change. + * Hence, the file is not accessed, and the access time does not need to be + * flushed back to disk. This is sort of a "stealth" tail. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <malloc.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <err.h> +#ifdef HAVE_INOTIFY_INIT +#include <sys/inotify.h> +#endif +#include "nls.h" +#include "usleep.h" + +#define DEFAULT_LINES 10 + +static void +tailf(const char *filename, int lines) +{ + char *buf, *p; + int head = 0; + int tail = 0; + FILE *str; + int i; + + if (!(str = fopen(filename, "r"))) + err(EXIT_FAILURE, _("cannot open \"%s\" for read"), filename); + + buf = malloc(lines * BUFSIZ); + p = buf; + while (fgets(p, BUFSIZ, str)) { + if (++tail >= lines) { + tail = 0; + head = 1; + } + p = buf + (tail * BUFSIZ); + } + + if (head) { + for (i = tail; i < lines; i++) + fputs(buf + (i * BUFSIZ), stdout); + for (i = 0; i < tail; i++) + fputs(buf + (i * BUFSIZ), stdout); + } else { + for (i = head; i < tail; i++) + fputs(buf + (i * BUFSIZ), stdout); + } + + fflush(stdout); + free(buf); + fclose(str); +} + +static void +roll_file(const char *filename, off_t *size) +{ + char buf[BUFSIZ]; + int fd; + struct stat st; + + if (!(fd = open(filename, O_RDONLY))) + err(EXIT_FAILURE, _("cannot open \"%s\" for read"), filename); + + if (fstat(fd, &st) == -1) + err(EXIT_FAILURE, _("cannot stat \"%s\""), filename); + + if (st.st_size == *size) { + close(fd); + return; + } + + if (lseek(fd, *size, SEEK_SET) != (off_t)-1) { + ssize_t rc, wc; + + while ((rc = read(fd, buf, sizeof(buf))) > 0) { + wc = write(STDOUT_FILENO, buf, rc); + if (rc != wc) + warnx(_("incomplete write to \"%s\" (written %zd, expected %zd)\n"), + filename, wc, rc); + } + fflush(stdout); + } + close(fd); + *size = st.st_size; +} + +static void +watch_file(const char *filename, off_t *size) +{ + do { + roll_file(filename, size); + usleep(250000); + } while(1); +} + + +#ifdef HAVE_INOTIFY_INIT + +#define EVENTS (IN_MODIFY|IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT) +#define NEVENTS 4 + +static int +watch_file_inotify(const char *filename, off_t *size) +{ + char buf[ NEVENTS * sizeof(struct inotify_event) ]; + int fd, ffd, e; + ssize_t len; + + fd = inotify_init(); + if (fd == -1) + return 0; + + ffd = inotify_add_watch(fd, filename, EVENTS); + if (ffd == -1) { + if (errno == ENOSPC) + errx(EXIT_FAILURE, _("%s: cannot add inotify watch " + "(limit of inotify watches was reached)."), + filename); + + err(EXIT_FAILURE, _("%s: cannot add inotify watch."), filename); + } + + while (ffd >= 0) { + len = read(fd, buf, sizeof(buf)); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + if (len < 0) + err(EXIT_FAILURE, + _("%s: cannot read inotify events"), filename); + + for (e = 0; e < len; ) { + struct inotify_event *ev = (struct inotify_event *) &buf[e]; + + if (ev->mask & IN_MODIFY) + roll_file(filename, size); + else { + close(ffd); + ffd = -1; + break; + } + e += sizeof(struct inotify_event) + ev->len; + } + } + close(fd); + return 1; +} + +#endif /* HAVE_INOTIFY_INIT */ + +int main(int argc, char **argv) +{ + const char *filename; + int lines = DEFAULT_LINES; + struct stat st; + off_t size = 0; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + argc--; + argv++; + + for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { + if (!strcmp(*argv, "-n") || !strcmp(*argv, "--lines")) { + argc--; argv++; + if (argc > 0 && (lines = atoi(argv[0])) <= 0) + errx(EXIT_FAILURE, _("invalid number of lines")); + } + else if (isdigit(argv[0][1])) { + if ((lines = atoi(*argv + 1)) <= 0) + errx(EXIT_FAILURE, _("invalid number of lines")); + } + else + errx(EXIT_FAILURE, _("invalid option")); + } + + if (argc != 1) + errx(EXIT_FAILURE, _("usage: tailf [-n N | -N] logfile")); + + filename = argv[0]; + + if (stat(filename, &st) != 0) + err(EXIT_FAILURE, _("cannot stat \"%s\""), filename); + + size = st.st_size;; + tailf(filename, lines); + +#ifdef HAVE_INOTIFY_INIT + if (!watch_file_inotify(filename, &size)) +#endif + watch_file(filename, &size); + + return EXIT_SUCCESS; +} + diff --git a/text-utils/ul.1 b/text-utils/ul.1 new file mode 100644 index 0000000..cec6940 --- /dev/null +++ b/text-utils/ul.1 @@ -0,0 +1,110 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ul.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UL 1 +.Os BSD 4 +.Sh NAME +.Nm ul +.Nd do underlining +.Sh SYNOPSIS +.Nm ul +.Op Fl i +.Op Fl t Ar terminal +.Op Ar name Ar ... +.Sh DESCRIPTION +.Nm Ul +reads the named files (or standard input if none are given) +and translates occurrences of underscores to the sequence +which indicates underlining for the terminal in use, as specified +by the environment variable +.Ev TERM . +The +.Pa terminfo +database is read to determine the appropriate sequences for underlining. +If the terminal is incapable of underlining, but is capable of +a standout mode then that is used instead. +If the terminal can overstrike, +or handles underlining automatically, +.Nm ul +degenerates to +.Xr cat 1 . +If the terminal cannot underline, underlining is ignored. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl i +Underlining is indicated by a separate line containing appropriate +dashes `\-'; this is useful when you want to look at the underlining +which is present in an +.Xr nroff +output stream on a crt-terminal. +.It Fl t Ar terminal +Overrides the terminal type specified in the environment with +.Ar terminal . +.El +.Sh ENVIRONMENT +The following environment variable is used: +.Bl -tag -width TERM +.It Ev TERM +The +.Ev TERM +variable is used to relate a tty device +with its device capability description (see +.Xr terminfo 5 ) . +.Ev TERM +is set at login time, either by the default terminal type +specified in +.Pa /etc/ttys +or as set during the login process by the user in their +.Pa login +file (see +.Xr setenv 1 ) . +.El +.Sh SEE ALSO +.Xr man 1 , +.Xr nroff 1 , +.Xr colcrt 1 +.Sh BUGS +.Xr Nroff +usually outputs a series of backspaces and underlines intermixed +with the text to indicate underlining. No attempt is made to optimize +the backward motion. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . +.Sh AVAILABILITY +The ul command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/text-utils/ul.c b/text-utils/ul.c new file mode 100644 index 0000000..a1491b8 --- /dev/null +++ b/text-utils/ul.c @@ -0,0 +1,603 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * modified by Kars de Jong <jongk@cs.utwente.nl> + * to use terminfo instead of termcap. + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * added Native Language Support + * 1999-09-19 Bruno Haible <haible@clisp.cons.org> + * modified to work correctly in multi-byte locales + */ + +#include <stdio.h> +#include <unistd.h> /* for getopt(), isatty() */ +#include <string.h> /* for memset(), strcpy() */ +#include <term.h> /* for setupterm() */ +#include <stdlib.h> /* for getenv() */ +#include <limits.h> /* for INT_MAX */ +#include "nls.h" + +#include "widechar.h" + +#ifdef HAVE_WIDECHAR +static int put1wc(int c) /* Output an ASCII character as a wide character */ +{ + if (putwchar(c) == WEOF) + return EOF; + else + return c; +} +#define putwp(s) tputs(s,1,put1wc) +#else +#define putwp(s) putp(s) +#endif + +void filter(FILE *f); +void flushln(void); +void overstrike(void); +void iattr(void); +void initbuf(void); +void fwd(void); +void reverse(void); +void initinfo(void); +void outc(wint_t c, int width); +void setmode(int newmode); +static void setcol(int newcol); +static void needcol(int col); + +#define IESC '\033' +#define SO '\016' +#define SI '\017' +#define HFWD '9' +#define HREV '8' +#define FREV '7' + +#define NORMAL 000 +#define ALTSET 001 /* Reverse */ +#define SUPERSC 002 /* Dim */ +#define SUBSC 004 /* Dim | Ul */ +#define UNDERL 010 /* Ul */ +#define BOLD 020 /* Bold */ +#define INITBUF 512 + +int must_use_uc, must_overstrike; +char *CURS_UP, *CURS_RIGHT, *CURS_LEFT, + *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE, + *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES; + +struct CHAR { + char c_mode; + wchar_t c_char; + int c_width; +} ; + +struct CHAR *obuf; +int obuflen; /* Tracks number of elements in obuf. */ +int col, maxcol; +int mode; +int halfpos; +int upln; +int iflag; + +#define PRINT(s) if (s == NULL) /* void */; else putwp(s) + +int main(int argc, char **argv) +{ + int c, ret; + char *termtype; + FILE *f; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + termtype = getenv("TERM"); + if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) + termtype = "lpr"; + while ((c = getopt(argc, argv, "it:T:")) != -1) + switch(c) { + + case 't': + case 'T': /* for nroff compatibility */ + termtype = optarg; + break; + case 'i': + iflag = 1; + break; + + default: + fprintf(stderr, + _("usage: %s [ -i ] [ -tTerm ] file...\n"), + argv[0]); + exit(1); + } + setupterm(termtype, 1, &ret); + switch(ret) { + + case 1: + break; + + default: + fprintf(stderr,_("trouble reading terminfo")); + /* fall through to ... */ + + case 0: + /* No such terminal type - assume dumb */ + setupterm("dumb", 1, (int *)0); + break; + } + initinfo(); + if ( (tigetflag("os") && ENTER_BOLD==NULL ) || + (tigetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL)) + must_overstrike = 1; + initbuf(); + if (optind == argc) + filter(stdin); + else for (; optind<argc; optind++) { + f = fopen(argv[optind],"r"); + if (f == NULL) { + perror(argv[optind]); + exit(1); + } else + filter(f); + } + if (ferror(stdout) || fclose(stdout)) + return 1; + return 0; +} + +void filter(FILE *f) +{ + wint_t c; + int i, w; + + while ((c = getwc(f)) != WEOF) switch(c) { + + case '\b': + setcol(col - 1); + continue; + + case '\t': + setcol((col+8) & ~07); + continue; + + case '\r': + setcol(0); + continue; + + case SO: + mode |= ALTSET; + continue; + + case SI: + mode &= ~ALTSET; + continue; + + case IESC: + switch (c = getwc(f)) { + + case HREV: + if (halfpos == 0) { + mode |= SUPERSC; + halfpos--; + } else if (halfpos > 0) { + mode &= ~SUBSC; + halfpos--; + } else { + halfpos = 0; + reverse(); + } + continue; + + case HFWD: + if (halfpos == 0) { + mode |= SUBSC; + halfpos++; + } else if (halfpos < 0) { + mode &= ~SUPERSC; + halfpos++; + } else { + halfpos = 0; + fwd(); + } + continue; + + case FREV: + reverse(); + continue; + + default: + fprintf(stderr, + _("Unknown escape sequence in input: %o, %o\n"), + IESC, c); + exit(1); + } + continue; + + case '_': + if (obuf[col].c_char || obuf[col].c_width < 0) { + while(col > 0 && obuf[col].c_width < 0) + col--; + w = obuf[col].c_width; + for (i = 0; i < w; i++) + obuf[col++].c_mode |= UNDERL | mode; + setcol(col); + continue; + } + obuf[col].c_char = '_'; + obuf[col].c_width = 1; + /* fall through */ + case ' ': + setcol(col + 1); + continue; + + case '\n': + flushln(); + continue; + + case '\f': + flushln(); + putwchar('\f'); + continue; + + default: + if (!iswprint(c)) /* non printing */ + continue; + w = wcwidth(c); + needcol(col + w); + if (obuf[col].c_char == '\0') { + obuf[col].c_char = c; + for (i = 0; i < w; i++) + obuf[col+i].c_mode = mode; + obuf[col].c_width = w; + for (i = 1; i < w; i++) + obuf[col+i].c_width = -1; + } else if (obuf[col].c_char == '_') { + obuf[col].c_char = c; + for (i = 0; i < w; i++) + obuf[col+i].c_mode |= UNDERL|mode; + obuf[col].c_width = w; + for (i = 1; i < w; i++) + obuf[col+i].c_width = -1; + } else if (obuf[col].c_char == c) { + for (i = 0; i < w; i++) + obuf[col+i].c_mode |= BOLD|mode; + } else { + w = obuf[col].c_width; + for (i = 0; i < w; i++) + obuf[col+i].c_mode = mode; + } + setcol(col + w); + continue; + } + if (maxcol) + flushln(); +} + +void flushln(void) +{ + int lastmode; + int i; + int hadmodes = 0; + + lastmode = NORMAL; + for (i=0; i<maxcol; i++) { + if (obuf[i].c_mode != lastmode) { + hadmodes++; + setmode(obuf[i].c_mode); + lastmode = obuf[i].c_mode; + } + if (obuf[i].c_char == '\0') { + if (upln) { + PRINT(CURS_RIGHT); + } else + outc(' ', 1); + } else + outc(obuf[i].c_char, obuf[i].c_width); + if (obuf[i].c_width > 1) + i += obuf[i].c_width -1; + } + if (lastmode != NORMAL) { + setmode(0); + } + if (must_overstrike && hadmodes) + overstrike(); + putwchar('\n'); + if (iflag && hadmodes) + iattr(); + (void)fflush(stdout); + if (upln) + upln--; + initbuf(); +} + +/* + * For terminals that can overstrike, overstrike underlines and bolds. + * We don't do anything with halfline ups and downs, or Greek. + */ +void overstrike(void) +{ + register int i; +#ifdef __GNUC__ + register wchar_t *lbuf = __builtin_alloca((maxcol+1)*sizeof(wchar_t)); +#else + wchar_t lbuf[256]; +#endif + register wchar_t *cp = lbuf; + int hadbold=0; + + /* Set up overstrike buffer */ + for (i=0; i<maxcol; i++) + switch (obuf[i].c_mode) { + case NORMAL: + default: + *cp++ = ' '; + break; + case UNDERL: + *cp++ = '_'; + break; + case BOLD: + *cp++ = obuf[i].c_char; + if (obuf[i].c_width > 1) + i += obuf[i].c_width - 1; + hadbold=1; + break; + } + putwchar('\r'); + for (*cp=' '; *cp==' '; cp--) + *cp = 0; + for (cp=lbuf; *cp; cp++) + putwchar(*cp); + if (hadbold) { + putwchar('\r'); + for (cp=lbuf; *cp; cp++) + putwchar(*cp=='_' ? ' ' : *cp); + putwchar('\r'); + for (cp=lbuf; *cp; cp++) + putwchar(*cp=='_' ? ' ' : *cp); + } +} + +void iattr(void) +{ + register int i; +#ifdef __GNUC__ + register char *lbuf = __builtin_alloca((maxcol+1)*sizeof(char)); +#else + char lbuf[256]; +#endif + register char *cp = lbuf; + + for (i=0; i<maxcol; i++) + switch (obuf[i].c_mode) { + case NORMAL: *cp++ = ' '; break; + case ALTSET: *cp++ = 'g'; break; + case SUPERSC: *cp++ = '^'; break; + case SUBSC: *cp++ = 'v'; break; + case UNDERL: *cp++ = '_'; break; + case BOLD: *cp++ = '!'; break; + default: *cp++ = 'X'; break; + } + for (*cp=' '; *cp==' '; cp--) + *cp = 0; + for (cp=lbuf; *cp; cp++) + putwchar(*cp); + putwchar('\n'); +} + +void initbuf(void) +{ + if (obuf == NULL) { /* First time. */ + obuflen = INITBUF; + obuf = malloc(sizeof(struct CHAR) * obuflen); + if (obuf == NULL) { + fprintf(stderr, _("Unable to allocate buffer.\n")); + exit(1); + } + } + + /* assumes NORMAL == 0 */ + memset(obuf, 0, sizeof(struct CHAR) * obuflen); + setcol(0); + maxcol = 0; + mode &= ALTSET; +} + +void fwd(void) +{ + int oldcol, oldmax; + + oldcol = col; + oldmax = maxcol; + flushln(); + setcol(oldcol); + maxcol = oldmax; +} + +void reverse(void) +{ + upln++; + fwd(); + PRINT(CURS_UP); + PRINT(CURS_UP); + upln++; +} + +void initinfo(void) +{ + CURS_UP = tigetstr("cuu1"); + CURS_RIGHT = tigetstr("cuf1"); + CURS_LEFT = tigetstr("cub1"); + if (CURS_LEFT == NULL) + CURS_LEFT = "\b"; + + ENTER_STANDOUT = tigetstr("smso"); + EXIT_STANDOUT = tigetstr("rmso"); + ENTER_UNDERLINE = tigetstr("smul"); + EXIT_UNDERLINE = tigetstr("rmul"); + ENTER_DIM = tigetstr("dim"); + ENTER_BOLD = tigetstr("bold"); + ENTER_REVERSE = tigetstr("rev"); + EXIT_ATTRIBUTES = tigetstr("sgr0"); + + if (!ENTER_BOLD && ENTER_REVERSE) + ENTER_BOLD = ENTER_REVERSE; + if (!ENTER_BOLD && ENTER_STANDOUT) + ENTER_BOLD = ENTER_STANDOUT; + if (!ENTER_UNDERLINE && ENTER_STANDOUT) { + ENTER_UNDERLINE = ENTER_STANDOUT; + EXIT_UNDERLINE = EXIT_STANDOUT; + } + if (!ENTER_DIM && ENTER_STANDOUT) + ENTER_DIM = ENTER_STANDOUT; + if (!ENTER_REVERSE && ENTER_STANDOUT) + ENTER_REVERSE = ENTER_STANDOUT; + if (!EXIT_ATTRIBUTES && EXIT_STANDOUT) + EXIT_ATTRIBUTES = EXIT_STANDOUT; + + /* + * Note that we use REVERSE for the alternate character set, + * not the as/ae capabilities. This is because we are modelling + * the model 37 teletype (since that's what nroff outputs) and + * the typical as/ae is more of a graphics set, not the greek + * letters the 37 has. + */ + + UNDER_CHAR = tigetstr("uc"); + must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE); +} + +static int curmode = 0; + +void +outc(wint_t c, int width) { + int i; + + putwchar(c); + if (must_use_uc && (curmode&UNDERL)) { + for (i=0; i<width; i++) + PRINT(CURS_LEFT); + for (i=0; i<width; i++) + PRINT(UNDER_CHAR); + } +} + +void setmode(int newmode) +{ + if (!iflag) { + if (curmode != NORMAL && newmode != NORMAL) + setmode(NORMAL); + switch (newmode) { + case NORMAL: + switch(curmode) { + case NORMAL: + break; + case UNDERL: + PRINT(EXIT_UNDERLINE); + break; + default: + /* This includes standout */ + PRINT(EXIT_ATTRIBUTES); + break; + } + break; + case ALTSET: + PRINT(ENTER_REVERSE); + break; + case SUPERSC: + /* + * This only works on a few terminals. + * It should be fixed. + */ + PRINT(ENTER_UNDERLINE); + PRINT(ENTER_DIM); + break; + case SUBSC: + PRINT(ENTER_DIM); + break; + case UNDERL: + PRINT(ENTER_UNDERLINE); + break; + case BOLD: + PRINT(ENTER_BOLD); + break; + default: + /* + * We should have some provision here for multiple modes + * on at once. This will have to come later. + */ + PRINT(ENTER_STANDOUT); + break; + } + } + curmode = newmode; +} + +static void +setcol(int newcol) { + col = newcol; + + if (col < 0) + col = 0; + else if (col > maxcol) + needcol(col); +} + +static void +needcol(int col) { + maxcol = col; + + /* If col >= obuflen, expand obuf until obuflen > col. */ + while (col >= obuflen) { + /* Paranoid check for obuflen == INT_MAX. */ + if (obuflen == INT_MAX) { + fprintf(stderr, + _("Input line too long.\n")); + exit(1); + } + + /* Similar paranoia: double only up to INT_MAX. */ + obuflen = ((INT_MAX / 2) < obuflen) + ? INT_MAX + : obuflen * 2; + + /* Now we can try to expand obuf. */ + obuf = realloc(obuf, sizeof(struct CHAR) * obuflen); + if (obuf == NULL) { + fprintf(stderr, + _("Out of memory when growing buffer.\n")); + exit(1); + } + } +} |