From 075e75fbeb2096f4faf6816fd8aaf064eff27161 Mon Sep 17 00:00:00 2001 Message-Id: From: Steffen Nurpmeso Date: Wed, 16 Jul 2014 15:27:27 +0200 Subject: [PATCH 01/20] contrib/gideal/Makefile.sub: fix Bernd (Public Domain) --- contrib/gideal/Makefile.sub | 56 +++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/contrib/gideal/Makefile.sub b/contrib/gideal/Makefile.sub index b59a757..2d25731 100644 --- a/contrib/gideal/Makefile.sub +++ b/contrib/gideal/Makefile.sub @@ -32,9 +32,6 @@ MAN7=ideal.n MOSTLYCLEANADD=gideal $(MAN1) $(MAN7) -# not all make programs have $(RM) predefined. -RM=rm -f - all: gideal gideal: gideal.pl @@ -46,21 +43,23 @@ gideal: gideal.pl $(srcdir)/gideal.pl >$@; \ chmod +x $@ -.PHONY: install_data -install_data: gideal +install_data: install_always $(make_install_examples) +install_always: gideal -test -d $(DESTDIR)$(bindir) || $(mkinstalldirs) $(DESTDIR)$(bindir) - $(RM) $(DESTDIR)$(bindir)/gideal + rm -f $(DESTDIR)$(bindir)/gideal $(INSTALL_SCRIPT) gideal $(DESTDIR)$(bindir)/gideal - -test -d $(DESTDIR)$(datasubdir) \ - || $(mkinstalldirs) $(DESTDIR)$(datasubdir) - -test -d $(DESTDIR)$(datasubdir)/ideal \ - || $(mkinstalldirs) $(DESTDIR)$(datasubdir)/ideal - -test -d $(DESTDIR)$(datasubdir)/ideal/libfiles \ - || $(mkinstalldirs) $(DESTDIR)$(datasubdir)/ideal/libfiles - $(RM) $(DESTDIR)$(datasubdir)/ideal/libfiles/* + +install_examples: install_always + -test -d $(DESTDIR)$(exampledir) \ + || $(mkinstalldirs) $(DESTDIR)$(exampledir) + -test -d $(DESTDIR)$(exampledir)/ideal \ + || $(mkinstalldirs) $(DESTDIR)$(exampledir)/ideal + -test -d $(DESTDIR)$(exampledir)/ideal/libfiles \ + || $(mkinstalldirs) $(DESTDIR)$(exampledir)/ideal/libfiles + rm -f $(DESTDIR)$(exampledir)/ideal/libfiles/* for i in $(srcdir)/libfiles/*; do \ n=`echo $$i | sed 's|$(srcdir)/libfiles/||g'`; \ - $(INSTALL_DATA) $$i $(DESTDIR)$(datasubdir)/ideal/libfiles/$$n; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(exampledir)/ideal/libfiles/$$n; \ done -test -d $(DESTDIR)$(exampledir) \ || $(mkinstalldirs) $(DESTDIR)$(exampledir) @@ -68,28 +67,19 @@ install_data: gideal || $(mkinstalldirs) $(DESTDIR)$(exampledir)/ideal -test -d $(DESTDIR)$(exampledir)/ideal/files \ || $(mkinstalldirs) $(DESTDIR)$(exampledir)/ideal/files - $(RM) $(DESTDIR)$(exampledir)/ideal/files/* + rm -f $(DESTDIR)$(exampledir)/ideal/files/* for i in $(srcdir)/files/*; do \ n=`echo $$i | sed 's|$(srcdir)/files/||g'`; \ $(INSTALL_DATA) $$i $(DESTDIR)$(exampledir)/ideal/files/$$n; \ done +uninstall_sub: uninstall_always $(make_uninstall_examples) +uninstall_always: + rm -f $(DESTDIR)$(bindir)/gideal -.PHONY: uninstall_sub -uninstall_sub: - $(RM) $(DESTDIR)$(bindir)/gideal - -rmdir $(DESTDIR)$(bindir) - $(RM) $(DESTDIR)$(datasubdir)/ideal/files/* - -rmdir $(DESTDIR)$(datasubdir)/ideal/files - $(RM) $(DESTDIR)$(datasubdir)/ideal/libfiles/* - -rmdir $(DESTDIR)$(datasubdir)/ideal/libfiles - -rmdir $(DESTDIR)$(datasubdir)/ideal - - -######################################################################## -# Emacs settings -######################################################################## -# -# Local Variables: -# mode: makefile -# End: +uninstall_examples: uninstall_always + rm -f $(DESTDIR)$(exampledir)/ideal/files/* + -rmdir $(DESTDIR)$(exampledir)/ideal/files + rm -f $(DESTDIR)$(exampledir)/ideal/libfiles/* + -rmdir $(DESTDIR)$(exampledir)/ideal/libfiles + -rmdir $(DESTDIR)$(exampledir)/ideal -- 2.0.0 From 61e9cd271622a7ad0e7577434973297fe07a6bf6 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 16:14:56 +0200 Subject: [PATCH 02/20] src/include/lib.h: add some infrastructure (Public Domain) --- src/include/lib.h | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/include/lib.h b/src/include/lib.h index 7f05f2d..3928277 100644 --- a/src/include/lib.h +++ b/src/include/lib.h @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-2000, 2001, 2002, 2003, 2005, 2006, 2009 +/* Copyright (C) 1989-2000, 2001, 2002, 2003, 2005, 2006, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -17,6 +17,8 @@ for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#ifndef _LIB_H +#define _LIB_H #ifdef HAVE_CONFIG_H #include @@ -175,3 +177,36 @@ const double PI = 3.14159265358979323846; #define ad_delete(size) delete [] #define a_delete delete [] #endif /* !ARRAY_DELETE_NEEDS_SIZE */ + +#ifdef HAVE_CC_INTTYPES_H +# include +#endif +#if !defined UINT8_MAX && !defined uint8_t +# undef int8_t +typedef unsigned char uint8_t; +typedef signed char int8_t; +#endif +#if !defined UINT32_MAX && !defined uint32_t +# undef int32_t +# if INT_MAX == 2147483647 +typedef unsigned int uint32_t; +typedef signed int int32_t; +# else +typedef unsigned long int uint32_t; +typedef signed long int int32_t; +# endif +#endif + +#ifndef NELEM +# define NELEM(X) (sizeof(X) / sizeof((X)[0])) +#endif + +#define CLASS_DISABLE_COPY(C) private: C(C const &); C &operator=(C const &) + +#ifndef NDEBUG +# define INJECT(X) X +#else +# define INJECT(X) +#endif + +#endif /* _LIB_H */ -- 2.0.0 From d154f86f67c567fdf982ee5b86784d292f705bb5 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 22:52:26 +0200 Subject: [PATCH 03/20] Encapsulate searchpath:: FILE*'s in new class file_case (Public Domain) --- src/devices/grops/ps.cpp | 23 ++-- src/devices/grops/psrm.cpp | 113 +++++++++---------- src/include/file_case.h | 100 +++++++++++++++++ src/include/font.h | 16 +-- src/include/searchpath.h | 16 +-- src/libs/libgroff/Makefile.sub | 3 +- src/libs/libgroff/file_case.cpp | 77 +++++++++++++ src/libs/libgroff/font.cpp | 48 ++++----- src/libs/libgroff/fontfile.cpp | 15 +-- src/libs/libgroff/searchpath.cpp | 179 ++++++++++++------------------ src/preproc/eqn/main.cpp | 14 +-- src/preproc/grn/main.cpp | 16 +-- src/preproc/html/pre-html.cpp | 22 ++-- src/preproc/soelim/soelim.cpp | 39 +++---- src/roff/troff/env.cpp | 52 ++++----- src/roff/troff/input.cpp | 227 ++++++++++++++++++--------------------- src/roff/troff/node.cpp | 20 ++-- 17 files changed, 553 insertions(+), 427 deletions(-) create mode 100644 src/include/file_case.h create mode 100644 src/libs/libgroff/file_case.cpp diff --git a/src/devices/grops/ps.cpp b/src/devices/grops/ps.cpp index ab1b080..b4306a8 100644 --- a/src/devices/grops/ps.cpp +++ b/src/devices/grops/ps.cpp @@ -1,6 +1,6 @@ // -*- C++ -*- /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2009 + 2006, 2007, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -26,6 +26,7 @@ along with this program. If not, see . */ */ #include "driver.h" +#include "file_case.h" #include "stringclass.h" #include "cset.h" #include "nonposix.h" @@ -784,28 +785,27 @@ void ps_printer::define_encoding(const char *encoding, int encoding_index) int i; for (i = 0; i < 256; i++) vec[i] = 0; - char *path; - FILE *fp = font::open_file(encoding, &path); - if (fp == 0) + + file_case *fcp = font::open_file(encoding); + if (fcp == NULL) fatal("can't open encoding file `%1'", encoding); - int lineno = 1; + const int BUFFER_SIZE = 512; char buf[BUFFER_SIZE]; - while (fgets(buf, BUFFER_SIZE, fp) != 0) { + for (int lineno = 1; fgets(buf, BUFFER_SIZE, fcp->file()) != NULL; ++lineno) { char *p = buf; while (csspace(*p)) p++; if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) { char *q = strtok(0, WS); - int n = 0; // pacify compiler + int n = 0; // pacify compiler if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256) - fatal_with_file_and_line(path, lineno, "bad second field"); + fatal_with_file_and_line(fcp->path(), lineno, "bad second field"); vec[n] = new char[strlen(p) + 1]; strcpy(vec[n], p); } - lineno++; } - a_delete path; + out.put_literal_symbol(make_encoding_name(encoding_index)) .put_delimiter('['); for (i = 0; i < 256; i++) { @@ -818,7 +818,8 @@ void ps_printer::define_encoding(const char *encoding, int encoding_index) } out.put_delimiter(']') .put_symbol("def"); - fclose(fp); + + delete fcp; } void ps_printer::reencode_font(ps_font *f) diff --git a/src/devices/grops/psrm.cpp b/src/devices/grops/psrm.cpp index a3787cb..fae2176 100644 --- a/src/devices/grops/psrm.cpp +++ b/src/devices/grops/psrm.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000-2004, 2009, 2013 +/* Copyright (C) 1989-1992, 2000-2004, 2009, 2013, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "driver.h" +#include "file_case.h" #include "stringclass.h" #include "cset.h" @@ -306,7 +307,6 @@ void resource_manager::output_prolog(ps_output &out) { FILE *outfp = out.get_file(); out.end_line(); - char *path; if (!getenv("GROPS_PROLOGUE")) { string e = "GROPS_PROLOGUE"; e += '='; @@ -316,16 +316,18 @@ void resource_manager::output_prolog(ps_output &out) fatal("putenv failed"); } char *prologue = getenv("GROPS_PROLOGUE"); - FILE *fp = font::open_file(prologue, &path); - if (!fp) + + file_case *fcp = font::open_file(prologue); + if (fcp == NULL) fatal("can't find `%1'", prologue); + fputs("%%BeginResource: ", outfp); procset_resource->print_type_and_name(outfp); putc('\n', outfp); - process_file(-1, fp, path, outfp); - fclose(fp); - a_delete path; + process_file(-1, fcp->file(), fcp->path(), outfp); fputs("%%EndResource\n", outfp); + + delete fcp; } void resource_manager::import_file(const char *filename, ps_output &out) @@ -348,65 +350,54 @@ void resource_manager::supply_resource(resource *r, int rank, FILE *outfp, r->flags |= resource::BUSY; if (rank > r->rank) r->rank = rank; - char *path = 0; // pacify compiler - FILE *fp = 0; - if (r->filename != 0) { + + file_case *fcp = NULL; + if (r->filename != NULL) { if (r->type == RESOURCE_FONT) { - fp = font::open_file(r->filename, &path); - if (!fp) { - error("can't find `%1'", r->filename); - a_delete r->filename; - r->filename = 0; - } + if ((fcp = font::open_file(r->filename)) == NULL) + error("can't find `%1'", r->filename); + } else { + if ((fcp = include_search_path.open_file_cautious(r->filename)) == NULL) + error("can't open `%1': %2", r->filename, strerror(errno)); } - else { - errno = 0; - fp = include_search_path.open_file_cautious(r->filename); - if (!fp) { - error("can't open `%1': %2", r->filename, strerror(errno)); - a_delete r->filename; - r->filename = 0; - } - else - path = r->filename; + if (fcp == NULL) { + a_delete r->filename; + r->filename = NULL; } } - if (fp) { + + if (fcp != NULL) { if (outfp) { if (r->type == RESOURCE_FILE && is_document) { - fputs("%%BeginDocument: ", outfp); - print_ps_string(r->name, outfp); - putc('\n', outfp); - } - else { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); + fputs("%%BeginDocument: ", outfp); + print_ps_string(r->name, outfp); + putc('\n', outfp); + } else { + fputs("%%BeginResource: ", outfp); + r->print_type_and_name(outfp); + putc('\n', outfp); } } - process_file(rank, fp, path, outfp); - fclose(fp); - if (r->type == RESOURCE_FONT) - a_delete path; + process_file(rank, fcp->file(), fcp->path(), outfp); + delete fcp; + if (outfp) { if (r->type == RESOURCE_FILE && is_document) - fputs("%%EndDocument\n", outfp); + fputs("%%EndDocument\n", outfp); else - fputs("%%EndResource\n", outfp); + fputs("%%EndResource\n", outfp); } r->flags |= resource::SUPPLIED; - } - else { + } else { if (outfp) { if (r->type == RESOURCE_FILE && is_document) { - fputs("%%IncludeDocument: ", outfp); - print_ps_string(r->name, outfp); - putc('\n', outfp); - } - else { - fputs("%%IncludeResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); + fputs("%%IncludeDocument: ", outfp); + print_ps_string(r->name, outfp); + putc('\n', outfp); + } else { + fputs("%%IncludeResource: ", outfp); + r->print_type_and_name(outfp); + putc('\n', outfp); } } r->flags |= resource::NEEDED; @@ -1075,24 +1066,22 @@ void resource_manager::process_file(int rank, FILE *fp, const char *filename, void resource_manager::read_download_file() { - char *path = 0; - FILE *fp = font::open_file("download", &path); - if (!fp) + file_case *fcp = font::open_file("download"); + if (fcp == NULL) fatal("can't find `download'"); + char buf[512]; - int lineno = 0; - while (fgets(buf, sizeof(buf), fp)) { - lineno++; + for (int lineno = 1; fgets(buf, sizeof(buf), fcp->file()) != NULL; ++lineno) { char *p = strtok(buf, " \t\r\n"); - if (p == 0 || *p == '#') + if (p == NULL || *p == '#') continue; char *q = strtok(0, " \t\r\n"); - if (!q) - fatal_with_file_and_line(path, lineno, "missing filename"); + if (q == NULL) + fatal_with_file_and_line(fcp->path(), lineno, "missing filename"); lookup_font(p)->filename = strsave(q); } - a_delete path; - fclose(fp); + + delete fcp; } // XXX Can we share some code with ps_output::put_string()? diff --git a/src/include/file_case.h b/src/include/file_case.h new file mode 100644 index 0000000..a52d121 --- /dev/null +++ b/src/include/file_case.h @@ -0,0 +1,100 @@ +/*@ file_case: input file encapsulator + * Copyright (C) 2014 Free Software Foundation, Inc. + * Written by Steffen Nurpmeso (address@hidden) for groff (Public Domain) + * + * This file is part of groff. + * + * groff is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * groff is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ +#ifndef _FILE_CASE_H +#define _FILE_CASE_H + +#include "lib.h" + +#include +#include + +class file_case +{ + char const *_path; + FILE *_file; + uint32_t _flags; +public: + // Flags for ctor / muxer() + enum { + fc_none = 0, + fc_dont_close = 1<<0, // Don't close the file, if any + fc_pipe = 1<<1, // _file is not seekable + fc_const_path = 1<<2, // Don't dup path, and don't a_delete it + fc_take_path = 1<<3, // Don't dup path, but a_delete it + _fc_freebit = 4, + fc_mask = (1<<_fc_freebit) - 1 + }; + + // Flags only for muxer() + enum { + mux_need_seek = 1<<(_fc_freebit+0), // File must be seekable + mux_need_binary = 1<<(_fc_freebit+1), // Need binary I/O + mux_default = fc_none, + mux_mask = ~fc_mask + }; + + file_case(FILE *fp, char const *path, uint32_t flags=fc_none); + ~file_case(void); + + bool close(void); + char const * path(void) const; + FILE * file(void) const; + bool is_pipe(void) const; + + // Factory muxer; note that fc_take_path will be honoured even on failure + static file_case * muxer(char const *path, uint32_t flags=mux_default); + + CLASS_DISABLE_COPY(file_case); +}; + +inline +file_case::file_case(FILE *fp, char const *path, uint32_t flags) +: + _path(path), _file(fp), _flags(flags) +{ + assert(!(flags & (fc_const_path | fc_take_path)) || + !(flags & fc_const_path) != !(flags & fc_take_path)); + assert(!(flags & ~fc_mask)); +} + +inline +file_case::~file_case(void) +{ + if (_file != NULL) + close(); +} + +inline char const * +file_case::path(void) const +{ + return _path; +} + +inline FILE * +file_case::file(void) const +{ + return _file; +} + +inline bool +file_case::is_pipe(void) const +{ + return ((_flags & fc_pipe) != 0); +} +#endif /* _FILE_CASE_H */ diff --git a/src/include/font.h b/src/include/font.h index 75d2ef1..2088c87 100644 --- a/src/include/font.h +++ b/src/include/font.h @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004, 2006, 2009, 2010 +/* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004, 2006, 2009, 2010, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -18,6 +18,8 @@ for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "file_case.h" + // A function of this type can be registered to define the semantics of // arbitrary commands in a font DESC file. typedef void (*FONT_COMMAND_HANDLER)(const char *, // command @@ -215,13 +217,11 @@ public: static void command_line_font_dir(const char *); // Prepend given // path (arg1) to the list of directories in which // to look up fonts. - static FILE *open_file(const char *, char **); // Open a font file - // with the given name (arg1), searching along the - // current font path. If arg2 points to a string - // pointer, set it to the found file name (this - // depends on the device also). Return the opened - // file. If not found, arg2 is unchanged, and NULL - // is returned. + + // Open a font file with the given name, searching along the current font + // path. Return the opened file or NULL. + static file_case * open_file(const char *name, + uint32_t flags=file_case::mux_default); static int load_desc(); // Open the DESC file (depending on the // device) and initialize some static variables with // info from there. diff --git a/src/include/searchpath.h b/src/include/searchpath.h index 5f2334c..43d4773 100644 --- a/src/include/searchpath.h +++ b/src/include/searchpath.h @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2003, 2009 +/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2003, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -18,14 +18,18 @@ for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "file_case.h" + class search_path { char *dirs; unsigned init_len; public: - search_path(const char *envvar, const char *standard, - int add_home, int add_current); + search_path(const char *envvar, const char *standard, int add_home, + int add_current); ~search_path(); - void command_line_dir(const char *); - FILE *open_file(const char *, char **); - FILE *open_file_cautious(const char *, char ** = 0, const char * = 0); + + void command_line_dir(char const *); + file_case * open_file(char const *name, uint32_t f=file_case::mux_default); + file_case * open_file_cautious(char const *name, + uint32_t f=file_case::mux_default); }; diff --git a/src/libs/libgroff/Makefile.sub b/src/libs/libgroff/Makefile.sub index 80fd87c..ae5a5b5 100644 --- a/src/libs/libgroff/Makefile.sub +++ b/src/libs/libgroff/Makefile.sub @@ -12,6 +12,7 @@ OBJS=\ errarg.$(OBJEXT) \ error.$(OBJEXT) \ fatal.$(OBJEXT) \ + file_case.$(OBJEXT) \ filename.$(OBJEXT) \ font.$(OBJEXT) \ fontfile.$(OBJEXT) \ @@ -62,7 +63,7 @@ CCSRCS=\ $(srcdir)/errarg.cpp \ $(srcdir)/error.cpp \ $(srcdir)/fatal.cpp \ - $(srcdir)/filename.cpp \ + $(srcdir)/file_case.cpp \ $(srcdir)/font.cpp \ $(srcdir)/fontfile.cpp \ $(srcdir)/geometry.cpp \ diff --git a/src/libs/libgroff/file_case.cpp b/src/libs/libgroff/file_case.cpp new file mode 100644 index 0000000..51bc2f2 --- /dev/null +++ b/src/libs/libgroff/file_case.cpp @@ -0,0 +1,77 @@ +/*@ file_case: input file encapsulator + * Copyright (C) 2014 Free Software Foundation, Inc. + * Written by Steffen Nurpmeso (address@hidden) for groff (Public Domain) + * + * This file is part of groff. + * + * groff is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * groff is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include "lib.h" + +#include +#include +#include + +#include "file_case.h" + +bool +file_case::close(void) +{ + assert(_file != NULL); + + if (!(_flags & fc_const_path)) + a_delete _path; + + bool rv; + if (_flags & fc_dont_close) + rv = true; + else + rv = (fclose(_file) == 0); + +#ifndef NDEBUG + _file = NULL; + _path = NULL; + _flags = fc_none; +#endif + return rv; +} + +/*static*/ file_case * +file_case::muxer(char const *path, uint32_t flags) +{ + assert(!(flags & (fc_dont_close | fc_pipe))); + assert(!(flags & (fc_const_path | fc_take_path)) || + !(flags & fc_const_path) != !(flags & fc_take_path)); + + if (!(flags & (fc_const_path | fc_take_path))) { + path = strsave(path); + flags |= fc_take_path; + } + + errno = 0; + FILE *fp = fopen(path, ((flags & mux_need_binary) ? "rb" : "r")); + int save_err = errno; + + flags &= ~mux_mask; + file_case *fcp; + if (fp != NULL) + fcp = new file_case(fp, path, flags); + else { + if (!(flags & fc_const_path)) + a_delete path; + errno = save_err; + fcp = NULL; + } + return fcp; +} diff --git a/src/libs/libgroff/font.cpp b/src/libs/libgroff/font.cpp index fe23fdd..b5a1990 100644 --- a/src/libs/libgroff/font.cpp +++ b/src/libs/libgroff/font.cpp @@ -1,6 +1,6 @@ // -*- C++ -*- /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2008, 2009, 2010 + 2006, 2008, 2009, 2010, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -29,7 +29,9 @@ along with this program. If not, see . */ #include "errarg.h" #include "error.h" #include "cset.h" +#include "file_case.h" #include "font.h" +#include "searchpath.h" #include "unicode.h" #include "paper.h" @@ -68,38 +70,36 @@ struct font_widths_cache { /* text_file */ struct text_file { - FILE *fp; - char *path; + file_case *fcp; int lineno; int size; int skip_comments; int silent; char *buf; - text_file(FILE *fp, char *p); + text_file(file_case *fcp); ~text_file(); int next(); - void error(const char *format, + void error(const char *format, const errarg &arg1 = empty_errarg, const errarg &arg2 = empty_errarg, const errarg &arg3 = empty_errarg); }; -text_file::text_file(FILE *p, char *s) -: fp(p), path(s), lineno(0), size(0), skip_comments(1), silent(0), buf(0) +text_file::text_file(file_case *fcp) +: fcp(fcp), lineno(0), size(0), skip_comments(1), silent(0), buf(0) { } text_file::~text_file() { a_delete buf; - a_delete path; - if (fp) - fclose(fp); + if (fcp != NULL) + delete fcp; } int text_file::next() { - if (fp == 0) + if (fcp == NULL) return 0; if (buf == 0) { buf = new char[128]; @@ -108,7 +108,7 @@ int text_file::next() for (;;) { int i = 0; for (;;) { - int c = getc(fp); + int c = getc(fcp->file()); if (c == EOF) break; if (invalid_input_char(c)) @@ -139,13 +139,13 @@ int text_file::next() return 0; } -void text_file::error(const char *format, +void text_file::error(const char *format, const errarg &arg1, const errarg &arg2, const errarg &arg3) { if (!silent) - error_with_file_and_line(path, lineno, format, arg1, arg2, arg3); + error_with_file_and_line(fcp->path(), lineno, format, arg1, arg2, arg3); } int glyph_to_unicode(glyph *g) @@ -769,16 +769,15 @@ int font::load(int *not_found, int head_only) error("`DESC' is not a valid font file name"); return 0; } - char *path; - FILE *fp; - if ((fp = open_file(name, &path)) == NULL) { + file_case *fcp; + if ((fcp = open_file(name)) == NULL) { if (not_found) *not_found = 1; else error("can't find font file `%1'", name); return 0; } - text_file t(fp, path); + text_file t(fcp); t.skip_comments = 1; t.silent = head_only; char *p; @@ -844,7 +843,8 @@ int font::load(int *not_found, int head_only) else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) { char *command = p; p = strtok(0, "\n"); - handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno); + handle_unknown_font_command(command, trim_arg(p), t.fcp->path(), + t.lineno); } else break; @@ -1033,13 +1033,12 @@ static struct { int font::load_desc() { int nfonts = 0; - FILE *fp; - char *path; - if ((fp = open_file("DESC", &path)) == 0) { + file_case *fcp; + if ((fcp = open_file("DESC")) == NULL) { error("can't find `DESC' file"); return 0; } - text_file t(fp, path); + text_file t(fcp); t.skip_comments = 1; res = 0; while (t.next()) { @@ -1215,7 +1214,8 @@ int font::load_desc() else if (unknown_desc_command_handler) { char *command = p; p = strtok(0, "\n"); - (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno); + (*unknown_desc_command_handler)(command, trim_arg(p), t.fcp->path(), + t.lineno); } } if (res == 0) { diff --git a/src/libs/libgroff/fontfile.cpp b/src/libs/libgroff/fontfile.cpp index 543f406..a731cf8 100644 --- a/src/libs/libgroff/fontfile.cpp +++ b/src/libs/libgroff/fontfile.cpp @@ -1,6 +1,6 @@ // -*- C++ -*- /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2004, 2006, - 2009 + 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -24,6 +24,7 @@ along with this program. If not, see . */ #include #include #include +#include "file_case.h" #include "font.h" #include "searchpath.h" #include "device.h" @@ -60,11 +61,11 @@ void font::command_line_font_dir(const char *dir) font_path.command_line_dir(dir); } -FILE *font::open_file(const char *nm, char **pathp) +file_case *font::open_file(const char *name, uint32_t flags) { - char *filename = new char[strlen(nm) + strlen(device) + 5]; - sprintf(filename, "dev%s/%s", device, nm); - FILE *fp = font_path.open_file(filename, pathp); - a_delete filename; - return fp; + assert(!(flags & ~file_case::mux_mask)); + + char *filename = new char[strlen(name) + strlen(device) + 5]; + sprintf(filename, "dev%s/%s", device, name); + return font_path.open_file(filename, flags | file_case::fc_take_path); } diff --git a/src/libs/libgroff/searchpath.cpp b/src/libs/libgroff/searchpath.cpp index 105dfdf..b0520d6 100644 --- a/src/libs/libgroff/searchpath.cpp +++ b/src/libs/libgroff/searchpath.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003, 2005, 2009 +/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003, 2005, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -24,6 +24,7 @@ along with this program. If not, see . */ #include #include +#include "file_case.h" #include "searchpath.h" #include "nonposix.h" @@ -33,6 +34,51 @@ along with this program. If not, see . */ # define relocate(path) strsave(path) #endif +static file_case * _try_iter(char const *dirs, char const *name, + uint32_t flags); + +static file_case * +_try_iter(char const *dirs, char const *name, uint32_t flags) +{ + file_case *fcp; + bool delname = ((flags & fcp->fc_take_path) != 0); + flags = (flags & ~(fcp->fc_const_path)) | fcp->fc_take_path; + unsigned namelen = strlen(name); + char const *p = dirs; + + for (;;) { + char *end = strchr(p, PATH_SEP_CHAR); + if (end == NULL) + end = strchr(p, '\0'); + int need_slash = (end > p && strchr(DIR_SEPS, end[-1]) == NULL); + char *origpath = new char[(end - p) + need_slash + namelen + 1]; + memcpy(origpath, p, end - p); + if (need_slash) + origpath[end - p] = '/'; + strcpy(origpath + (end - p) + need_slash, name); +#if 0 + fprintf(stderr, "origpath `%s'\n", origpath); +#endif + char *path = relocate(origpath); + a_delete origpath; +#if 0 + fprintf(stderr, "trying `%s'\n", path); +#endif + if ((fcp = file_case::muxer(path, flags)) != NULL) + goto jleave; + if (errno != ENOENT) + goto jleave; + if (*end == '\0') + break; + p = end + 1; + } + errno = ENOENT; +jleave: + if (delname) + a_delete name; + return fcp; +} + search_path::search_path(const char *envvar, const char *standard, int add_home, int add_current) { @@ -93,115 +139,32 @@ void search_path::command_line_dir(const char *s) a_delete old; } -FILE *search_path::open_file(const char *name, char **pathp) +file_case *search_path::open_file(char const *name, uint32_t flags) { - assert(name != 0); - if (IS_ABSOLUTE(name) || *dirs == '\0') { - FILE *fp = fopen(name, "r"); - if (fp) { - if (pathp) - *pathp = strsave(name); - return fp; - } - else - return 0; - } - unsigned namelen = strlen(name); - char *p = dirs; - for (;;) { - char *end = strchr(p, PATH_SEP_CHAR); - if (!end) - end = strchr(p, '\0'); - int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; - char *origpath = new char[(end - p) + need_slash + namelen + 1]; - memcpy(origpath, p, end - p); - if (need_slash) - origpath[end - p] = '/'; - strcpy(origpath + (end - p) + need_slash, name); -#if 0 - fprintf(stderr, "origpath `%s'\n", origpath); -#endif - char *path = relocate(origpath); - a_delete origpath; -#if 0 - fprintf(stderr, "trying `%s'\n", path); -#endif - FILE *fp = fopen(path, "r"); - if (fp) { - if (pathp) - *pathp = path; - else - a_delete path; - return fp; - } - a_delete path; - if (*end == '\0') - break; - p = end + 1; - } - return 0; + assert(name != NULL); + + file_case *fcp; + if (IS_ABSOLUTE(name) || *dirs == '\0') + fcp = file_case::muxer(name, flags); + else + fcp = _try_iter(dirs, name, flags); + return fcp; } -FILE *search_path::open_file_cautious(const char *name, char **pathp, - const char *mode) +file_case *search_path::open_file_cautious(char const *name, uint32_t flags) { - if (!mode) - mode = "r"; - bool reading = (strchr(mode, 'r') != 0); - if (name == 0 || strcmp(name, "-") == 0) { - if (pathp) - *pathp = strsave(reading ? "stdin" : "stdout"); - return (reading ? stdin : stdout); - } - if (!reading || IS_ABSOLUTE(name) || *dirs == '\0') { - FILE *fp = fopen(name, mode); - if (fp) { - if (pathp) - *pathp = strsave(name); - return fp; - } - else - return 0; - } - unsigned namelen = strlen(name); - char *p = dirs; - for (;;) { - char *end = strchr(p, PATH_SEP_CHAR); - if (!end) - end = strchr(p, '\0'); - int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; - char *origpath = new char[(end - p) + need_slash + namelen + 1]; - memcpy(origpath, p, end - p); - if (need_slash) - origpath[end - p] = '/'; - strcpy(origpath + (end - p) + need_slash, name); -#if 0 - fprintf(stderr, "origpath `%s'\n", origpath); -#endif - char *path = relocate(origpath); - a_delete origpath; -#if 0 - fprintf(stderr, "trying `%s'\n", path); -#endif - FILE *fp = fopen(path, mode); - if (fp) { - if (pathp) - *pathp = path; - else - a_delete path; - return fp; - } - int err = errno; - a_delete path; - if (err != ENOENT) - { - errno = err; - return 0; - } - if (*end == '\0') - break; - p = end + 1; - } - errno = ENOENT; - return 0; + assert(name != NULL); + + file_case *fcp; + if (name == NULL || strcmp(name, "-") == 0) { + flags &= ~(fcp->fc_take_path); + flags |= fcp->fc_dont_close | fcp->fc_const_path; + if (flags & fcp->mux_need_binary) + SET_BINARY(fileno(stdin)); + fcp = new file_case(stdin, "stdin", flags); + } else if (IS_ABSOLUTE(name) || *dirs == '\0') + fcp = file_case::muxer(name, flags); + else + fcp = _try_iter(dirs, name, flags); + return fcp; } diff --git a/src/preproc/eqn/main.cpp b/src/preproc/eqn/main.cpp index 167fb4e..672bc50 100644 --- a/src/preproc/eqn/main.cpp +++ b/src/preproc/eqn/main.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000-2002, 2005, 2007, 2009, 2011 +/* Copyright (C) 1989-1992, 2000-2002, 2005, 2007, 2009, 2011, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -21,6 +21,7 @@ along with this program. If not, see . */ #include "eqn.h" #include "stringclass.h" #include "device.h" +#include "file_case.h" #include "searchpath.h" #include "macropath.h" #include "htmlhint.h" @@ -390,12 +391,11 @@ int main(int argc, char **argv) device); } if (load_startup_file) { - char *path; - FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path); - if (fp) { - do_file(fp, path); - fclose(fp); - a_delete path; + file_case *fcp; + if ((fcp = config_macro_path.open_file(STARTUP_FILE, fcp->fc_const_path) + ) != NULL) { + do_file(fcp->file(), fcp->path()); + delete fcp; } } if (optind >= argc) diff --git a/src/preproc/grn/main.cpp b/src/preproc/grn/main.cpp index 55fc27a..b5bcc79 100644 --- a/src/preproc/grn/main.cpp +++ b/src/preproc/grn/main.cpp @@ -74,6 +74,7 @@ #include "gprint.h" #include "device.h" +#include "file_case.h" #include "font.h" #include "searchpath.h" #include "macropath.h" @@ -514,7 +515,6 @@ void conv(register FILE *fp, int baseline) { - register FILE *gfp = NULL; /* input file pointer */ register int done = 0; /* flag to remember if finished */ register ELT *e; /* current element pointer */ ELT *PICTURE; /* whole picture data base pointer */ @@ -546,13 +546,13 @@ conv(register FILE *fp, error("at line %1: no picture filename.\n", baseline); return; } - char *path; - gfp = macro_path.open_file(gremlinfile, &path); - if (!gfp) - return; - PICTURE = DBRead(gfp); /* read picture file */ - fclose(gfp); - a_delete path; + { + file_case *fcp; + if ((fcp = macro_path.open_file(gremlinfile, fcp->fc_const_path)) == NULL) + return; + PICTURE = DBRead(fcp->file()); /* read picture file */ + delete fcp; + } if (DBNullelt(PICTURE)) return; /* If a request is made to make the */ /* picture fit into a specific area, */ diff --git a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp index fae164c..8c115ec 100644 --- a/src/preproc/html/pre-html.cpp +++ b/src/preproc/html/pre-html.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 2000-2004, 2007-2009, 2012 +/* Copyright (C) 2000-2004, 2007-2009, 2012, 2014 * Free Software Foundation, Inc. * Written by Gaius Mulley (address@hidden). * @@ -31,6 +31,7 @@ #include #include "errarg.h" #include "error.h" +#include "file_case.h" #include "stringclass.h" #include "posix.h" #include "defs.h" @@ -293,22 +294,19 @@ int get_line(FILE *f) static unsigned int get_resolution(void) { - char *pathp; - FILE *f; unsigned int res; - f = font_path.open_file("devps/DESC", &pathp); - a_delete pathp; - if (f == 0) + file_case *fcp; + if ((fcp = font_path.open_file("devps/DESC", fcp->fc_const_path)) == NULL) fatal("can't open devps/DESC"); - while (get_line(f)) { + while (get_line(fcp->file())) { int n = sscanf(linebuf, "res %u", &res); - if (n >= 1) { - fclose(f); - return res; - } + if (n >= 1) + goto jleave; } fatal("can't find `res' keyword in devps/DESC"); - return 0; +jleave: + delete fcp; + return res; } /* diff --git a/src/preproc/soelim/soelim.cpp b/src/preproc/soelim/soelim.cpp index 57732fd..0c0654d 100644 --- a/src/preproc/soelim/soelim.cpp +++ b/src/preproc/soelim/soelim.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001, 2003, 2004, 2005, 2009 +/* Copyright (C) 1989-1992, 2000, 2001, 2003, 2004, 2005, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -26,6 +26,7 @@ along with this program. If not, see . */ #include #include "errarg.h" #include "error.h" +#include "file_case.h" #include "stringclass.h" #include "nonposix.h" #include "searchpath.h" @@ -151,23 +152,20 @@ void do_so(const char *line) int do_file(const char *filename) { - char *file_name_in_path = 0; - FILE *fp = include_search_path.open_file_cautious(filename, - &file_name_in_path); - int err = errno; - string whole_filename(file_name_in_path ? file_name_in_path : filename); - whole_filename += '\0'; - a_delete file_name_in_path; - if (fp == 0) { - error("can't open `%1': %2", whole_filename.contents(), strerror(err)); - return 0; + int rv = 0; + enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START; + + file_case *fcp; + if ((fcp = include_search_path.open_file_cautious(filename)) == NULL) { + error("can't open `%1': %2", filename, strerror(errno)); + goto jleave; } - current_filename = whole_filename.contents(); + + current_filename = fcp->path(); current_lineno = 1; set_location(); - enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START; for (;;) { - int c = getc(fp); + int c = getc(fcp->file()); if (c == EOF) break; switch (state) { @@ -225,7 +223,7 @@ int do_file(const char *filename) case HAD_so: if (c == ' ' || c == '\n' || compatible_flag) { string line; - for (; c != EOF && c != '\n'; c = getc(fp)) + for (; c != EOF && c != '\n'; c = getc(fcp->file())) line += c; current_lineno++; line += '\n'; @@ -257,7 +255,7 @@ int do_file(const char *filename) case HAD_lf: if (c == ' ' || c == '\n' || compatible_flag) { string line; - for (; c != EOF && c != '\n'; c = getc(fp)) + for (; c != EOF && c != '\n'; c = getc(fcp->file())) line += c; current_lineno++; line += '\n'; @@ -276,6 +274,7 @@ int do_file(const char *filename) assert(0); } } + switch (state) { case HAD_DOT: fputs(".\n", stdout); @@ -298,8 +297,10 @@ int do_file(const char *filename) case START: break; } - if (fp != stdin) - fclose(fp); + + delete fcp; current_filename = 0; - return 1; + rv = 1; +jleave: + return rv; } diff --git a/src/roff/troff/env.cpp b/src/roff/troff/env.cpp index 6d722f5..f8d2ce3 100644 --- a/src/roff/troff/env.cpp +++ b/src/roff/troff/env.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000-2006, 2009, 2011 +/* Copyright (C) 1989-1992, 2000-2006, 2009, 2011, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -24,6 +24,7 @@ along with this program. If not, see . */ #include "stringclass.h" #include "mtsm.h" #include "env.h" +#include "file_case.h" #include "request.h" #include "node.h" #include "token.h" @@ -3827,42 +3828,42 @@ void hyphen_trie::read_patterns_file(const char *name, int append, { if (!append) clear(); + char buf[WORD_MAX]; for (int i = 0; i < WORD_MAX; i++) buf[i] = 0; int num[WORD_MAX+1]; - errno = 0; - char *path = 0; - FILE *fp = mac_path->open_file(name, &path); - if (fp == 0) { - error("can't find hyphenation patterns file `%1'", name); - return; - } - int c = hpf_getc(fp); int have_patterns = 0; // we've seen \patterns int final_pattern = 0; // 1 if we have a trailing closing brace int have_hyphenation = 0; // we've seen \hyphenation int final_hyphenation = 0; // 1 if we have a trailing closing brace int have_keyword = 0; // we've seen either \patterns or \hyphenation int traditional = 0; // don't handle \patterns - for (;;) { + int c; + file_case *fcp; + if ((fcp = mac_path->open_file(name, fcp->fc_const_path)) == NULL) { + error("can't find hyphenation patterns file `%1'", name); + goto jleave; + } + + for (c = hpf_getc(fcp->file());;) { for (;;) { if (c == '%') { // skip comments do { - c = getc(fp); + c = getc(fcp->file()); } while (c != EOF && c != '\n'); } if (c == EOF || !csspace(c)) break; - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); } if (c == EOF) { if (have_keyword || traditional) // we are done break; else { // rescan file in `traditional' mode - rewind(fp); + rewind(fcp->file()); traditional = 1; - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); continue; } } @@ -3876,14 +3877,14 @@ void hyphen_trie::read_patterns_file(const char *name, int append, buf[i++] = c; num[i] = 0; } - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); } while (i < WORD_MAX && c != EOF && !csspace(c) && c != '%' && c != '{' && c != '}'); } if (!traditional) { if (i >= 9 && !strncmp(buf + i - 9, "\\patterns", 9)) { while (csspace(c)) - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); if (c == '{') { if (have_patterns || have_hyphenation) error("\\patterns not allowed inside of %1 group", @@ -3892,13 +3893,13 @@ void hyphen_trie::read_patterns_file(const char *name, int append, have_patterns = 1; have_keyword = 1; } - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); continue; } } else if (i >= 12 && !strncmp(buf + i - 12, "\\hyphenation", 12)) { while (csspace(c)) - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); if (c == '{') { if (have_patterns || have_hyphenation) error("\\hyphenation not allowed inside of %1 group", @@ -3907,7 +3908,7 @@ void hyphen_trie::read_patterns_file(const char *name, int append, have_hyphenation = 1; have_keyword = 1; } - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); continue; } } @@ -3928,19 +3929,19 @@ void hyphen_trie::read_patterns_file(const char *name, int append, if (i > 0) final_hyphenation = 1; } - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); } else if (c == '{') { if (have_patterns || have_hyphenation) error("`{' not allowed within %1 group", have_patterns ? "\\patterns" : "\\hyphenation"); - c = hpf_getc(fp); // skipped if not starting \patterns - // or \hyphenation + c = hpf_getc(fcp->file()); // skipped if not starting \patterns + // or \hyphenation } } else { if (c == '{' || c == '}') - c = hpf_getc(fp); + c = hpf_getc(fcp->file()); } if (i > 0) { if (have_patterns || final_pattern || traditional) { @@ -3955,8 +3956,9 @@ void hyphen_trie::read_patterns_file(const char *name, int append, } } } - fclose(fp); - a_delete path; + + delete fcp; +jleave: return; } diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp index b71f27e..932eecb 100644 --- a/src/roff/troff/input.cpp +++ b/src/roff/troff/input.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000-2011 +/* Copyright (C) 1989-1992, 2000-2011, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -26,6 +26,7 @@ along with this program. If not, see . */ #include "stringclass.h" #include "mtsm.h" #include "env.h" +#include "file_case.h" #include "request.h" #include "node.h" #include "token.h" @@ -229,7 +230,7 @@ private: virtual int get_location(int, const char **, int *) { return 0; } virtual void backtrace() {} virtual int set_location(const char *, int) { return 0; } - virtual int next_file(FILE *, const char *) { return 0; } + virtual int next_file(file_case *, const char *) { return 0; } virtual void shift(int) {} virtual int is_boundary() {return 0; } virtual int is_file() { return 0; } @@ -274,53 +275,48 @@ public: }; class file_iterator : public input_iterator { - FILE *fp; + file_case *_fcp; int lineno; const char *filename; - int popened; int newline_flag; int seen_escape; enum { BUF_SIZE = 512 }; unsigned char buf[BUF_SIZE]; void close(); public: - file_iterator(FILE *, const char *, int = 0); + file_iterator(file_case *, const char *); ~file_iterator(); int fill(node **); int peek(); int get_location(int, const char **, int *); void backtrace(); int set_location(const char *, int); - int next_file(FILE *, const char *); + int next_file(file_case *, const char *); int is_file(); }; -file_iterator::file_iterator(FILE *f, const char *fn, int po) -: fp(f), lineno(1), filename(fn), popened(po), - newline_flag(0), seen_escape(0) +file_iterator::file_iterator(file_case *fcp, const char *fn) +: _fcp(fcp), lineno(1), filename(fn), newline_flag(0), seen_escape(0) { if ((font::use_charnames_in_special) && (fn != 0)) { if (!the_output) init_output(); - the_output->put_filename(fn, po); + the_output->put_filename(fn, _fcp->is_pipe()); } } file_iterator::~file_iterator() { - close(); + if (_fcp != NULL) + delete _fcp; } void file_iterator::close() { - if (fp == stdin) - clearerr(stdin); -#ifndef POPEN_MISSING - else if (popened) - pclose(fp); -#endif /* not POPEN_MISSING */ - else - fclose(fp); + if (_fcp != NULL) { + delete _fcp; + _fcp = NULL; + } } int file_iterator::is_file() @@ -328,15 +324,14 @@ int file_iterator::is_file() return 1; } -int file_iterator::next_file(FILE *f, const char *s) +int file_iterator::next_file(file_case *fcp, const char *s) { close(); + _fcp = fcp; filename = s; - fp = f; lineno = 1; newline_flag = 0; seen_escape = 0; - popened = 0; ptr = 0; eptr = 0; return 1; @@ -351,7 +346,7 @@ int file_iterator::fill(node **) ptr = p; unsigned char *e = p + BUF_SIZE; while (p < e) { - int c = getc(fp); + int c = getc(_fcp->file()); if (c == EOF) break; if (invalid_input_char(c)) @@ -378,13 +373,13 @@ int file_iterator::fill(node **) int file_iterator::peek() { - int c = getc(fp); + int c = getc(_fcp->file()); while (invalid_input_char(c)) { warning(WARN_INPUT, "invalid input character code %1", int(c)); - c = getc(fp); + c = getc(_fcp->file()); } if (c != EOF) - ungetc(c, fp); + ungetc(c, _fcp->file()); return c; } @@ -402,7 +397,7 @@ int file_iterator::get_location(int /*allow_macro*/, void file_iterator::backtrace() { errprint("%1:%2: backtrace: %3 `%1'\n", filename, lineno, - popened ? "process" : "file"); + _fcp->is_pipe() ? "process" : "file"); } int file_iterator::set_location(const char *f, int ln) @@ -434,7 +429,7 @@ public: static int set_location(const char *, int); static void backtrace(); static void backtrace_all(); - static void next_file(FILE *, const char *); + static void next_file(file_case *, const char *); static void end_file(); static void shift(int n); static void add_boundary(); @@ -719,15 +714,15 @@ int input_stack::set_location(const char *filename, int lineno) return 0; } -void input_stack::next_file(FILE *fp, const char *s) +void input_stack::next_file(file_case *fcp, const char *s) { input_iterator **pp; for (pp = ⊤ *pp != &nil_iterator; pp = &(*pp)->next) - if ((*pp)->next_file(fp, s)) + if ((*pp)->next_file(fcp, s)) return; if (++level > limit && limit > 0) fatal("input stack limit exceeded"); - *pp = new file_iterator(fp, s); + *pp = new file_iterator(fcp, s); (*pp)->next = &nil_iterator; } @@ -807,12 +802,13 @@ void next_file() if (nm.is_null()) input_stack::end_file(); else { - errno = 0; - FILE *fp = include_search_path.open_file_cautious(nm.contents()); - if (!fp) + file_case *fcp = include_search_path.open_file_cautious(nm.contents(), + fcp->fc_const_path); + if (fcp != NULL) { + input_stack::next_file(fcp, nm.contents()); + delete fcp; + } else error("can't open `%1': %2", nm.contents(), strerror(errno)); - else - input_stack::next_file(fp, nm.contents()); } tok.next(); } @@ -5940,10 +5936,9 @@ void source() else { while (!tok.newline() && !tok.eof()) tok.next(); - errno = 0; - FILE *fp = include_search_path.open_file_cautious(nm.contents()); - if (fp) - input_stack::push(new file_iterator(fp, nm.contents())); + file_case *fcp = include_search_path.open_file_cautious(nm.contents()); + if (fcp != NULL) + input_stack::push(new file_iterator(fcp, nm.contents())); else error("can't open `%1': %2", nm.contents(), strerror(errno)); tok.next(); @@ -5989,11 +5984,14 @@ void pipe_source() buf[buf_used] = '\0'; errno = 0; FILE *fp = popen(buf, POPEN_RT); - if (fp) - input_stack::push(new file_iterator(fp, symbol(buf).contents(), 1)); - else - error("can't open pipe to process `%1': %2", buf, strerror(errno)); - a_delete buf; + if (fp != NULL) + input_stack::push(new file_iterator( + new file_case(fp, buf, file_case::fc_pipe | file_case::fc_take_path), + symbol(buf).contents())); + else { + error("can't open pipe to process `%1': %2", buf, strerror(errno)); + a_delete buf; + } } tok.next(); #endif /* not POPEN_MISSING */ @@ -6184,16 +6182,14 @@ void ps_bbox_request() else { while (!tok.newline() && !tok.eof()) tok.next(); - errno = 0; // PS files might contain non-printable characters, such as ^Z // and CRs not followed by an LF, so open them in binary mode. - FILE *fp = include_search_path.open_file_cautious(nm.contents(), - 0, FOPEN_RB); - if (fp) { - do_ps_file(fp, nm.contents()); - fclose(fp); - } - else + file_case *fcp = include_search_path.open_file_cautious(nm.contents(), + fcp->mux_need_seek | fcp->mux_need_binary); + if (fcp != NULL) { + do_ps_file(fcp->file(), nm.contents()); + delete fcp; + } else error("can't open `%1': %2", nm.contents(), strerror(errno)); tok.next(); } @@ -7324,26 +7320,26 @@ void transparent_file() if (break_flag) curenv->do_break(); if (!filename.is_null()) { - errno = 0; - FILE *fp = include_search_path.open_file_cautious(filename.contents()); - if (!fp) + file_case *fcp = include_search_path + .open_file_cautious(filename.contents()); + if (fcp == NULL) error("can't open `%1': %2", filename.contents(), strerror(errno)); else { int bol = 1; for (;;) { - int c = getc(fp); - if (c == EOF) - break; - if (invalid_input_char(c)) - warning(WARN_INPUT, "invalid input character code %1", int(c)); - else { - curdiv->transparent_output(c); - bol = c == '\n'; - } + int c = getc(fcp->file()); + if (c == EOF) + break; + if (invalid_input_char(c)) + warning(WARN_INPUT, "invalid input character code %1", int(c)); + else { + curdiv->transparent_output(c); + bol = c == '\n'; + } } if (!bol) - curdiv->transparent_output('\n'); - fclose(fp); + curdiv->transparent_output('\n'); + delete fcp; } } tok.next(); @@ -7421,46 +7417,41 @@ static void parse_output_page_list(char *p) } } -static FILE *open_mac_file(const char *mac, char **path) +static file_case *open_mac_file(const char *mac) { // Try first FOOBAR.tmac, then tmac.FOOBAR - char *s1 = new char[strlen(mac)+strlen(MACRO_POSTFIX)+1]; - strcpy(s1, mac); - strcat(s1, MACRO_POSTFIX); - FILE *fp = mac_path->open_file(s1, path); - a_delete s1; - if (!fp) { - char *s2 = new char[strlen(mac)+strlen(MACRO_PREFIX)+1]; - strcpy(s2, MACRO_PREFIX); - strcat(s2, mac); - fp = mac_path->open_file(s2, path); - a_delete s2; + char *s = new char[strlen(mac) + strlen(MACRO_POSTFIX) +1]; + strcpy(s, mac); + strcat(s, MACRO_POSTFIX); + + file_case *fcp; + if ((fcp = mac_path->open_file(s, fcp->fc_take_path)) == NULL) { + s = new char[strlen(mac) + strlen(MACRO_PREFIX) +1]; + strcpy(s, MACRO_PREFIX); + strcat(s, mac); + fcp = mac_path->open_file(s, fcp->fc_take_path); } - return fp; + return fcp; } static void process_macro_file(const char *mac) { - char *path; - FILE *fp = open_mac_file(mac, &path); - if (!fp) + file_case *fcp = open_mac_file(mac); + if (fcp == NULL) fatal("can't find macro file %1", mac); - const char *s = symbol(path).contents(); - a_delete path; - input_stack::push(new file_iterator(fp, s)); + const char *s = symbol(fcp->path()).contents(); + input_stack::push(new file_iterator(fcp, s)); tok.next(); process_input_stack(); } static void process_startup_file(const char *filename) { - char *path; search_path *orig_mac_path = mac_path; mac_path = &config_macro_path; - FILE *fp = mac_path->open_file(filename, &path); - if (fp) { - input_stack::push(new file_iterator(fp, symbol(path).contents())); - a_delete path; + file_case *fcp; + if ((fcp = mac_path->open_file(filename)) != NULL) { + input_stack::push(new file_iterator(fcp, symbol(fcp->path()).contents())); tok.next(); process_input_stack(); } @@ -7475,35 +7466,33 @@ void macro_source() else { while (!tok.newline() && !tok.eof()) tok.next(); - char *path; - FILE *fp = mac_path->open_file(nm.contents(), &path); // .mso doesn't (and cannot) go through open_mac_file, so we // need to do it here manually: If we have tmac.FOOBAR, try // FOOBAR.tmac and vice versa - if (!fp) { + file_case *fcp; + if ((fcp = mac_path->open_file(nm.contents())) == NULL) { const char *fn = nm.contents(); + if (strncasecmp(fn, MACRO_PREFIX, sizeof(MACRO_PREFIX) - 1) == 0) { - char *s = new char[strlen(fn) + sizeof(MACRO_POSTFIX)]; - strcpy(s, fn + sizeof(MACRO_PREFIX) - 1); - strcat(s, MACRO_POSTFIX); - fp = mac_path->open_file(s, &path); - a_delete s; + char *s = new char[strlen(fn) + sizeof(MACRO_POSTFIX)]; + strcpy(s, fn + sizeof(MACRO_PREFIX) - 1); + strcat(s, MACRO_POSTFIX); + fcp = mac_path->open_file(s, fcp->fc_take_path); } - if (!fp) { - if (strncasecmp(fn + strlen(fn) - sizeof(MACRO_POSTFIX) + 1, - MACRO_POSTFIX, sizeof(MACRO_POSTFIX) - 1) == 0) { - char *s = new char[strlen(fn) + sizeof(MACRO_PREFIX)]; - strcpy(s, MACRO_PREFIX); - strncat(s, fn, strlen(fn) - sizeof(MACRO_POSTFIX) + 1); - fp = mac_path->open_file(s, &path); - a_delete s; - } + + if (fcp == NULL) { + if (strncasecmp(fn + strlen(fn) - sizeof(MACRO_POSTFIX) + 1, + MACRO_POSTFIX, sizeof(MACRO_POSTFIX) - 1) == 0) { + char *s = new char[strlen(fn) + sizeof(MACRO_PREFIX)]; + strcpy(s, MACRO_PREFIX); + strncat(s, fn, strlen(fn) - sizeof(MACRO_POSTFIX) + 1); + fcp = mac_path->open_file(s, fcp->fc_take_path); + } } } - if (fp) { - input_stack::push(new file_iterator(fp, symbol(path).contents())); - a_delete path; - } + + if (fcp != NULL) + input_stack::push(new file_iterator(fcp, symbol(fcp->path()).contents())); else warning(WARN_FILE, "can't find macro file `%1'", nm.contents()); tok.next(); @@ -7512,18 +7501,16 @@ void macro_source() static void process_input_file(const char *name) { - FILE *fp; + file_case *fcp; if (strcmp(name, "-") == 0) { clearerr(stdin); - fp = stdin; - } - else { - errno = 0; - fp = include_search_path.open_file_cautious(name); - if (!fp) + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path); + } else { + if ((fcp = include_search_path.open_file_cautious(name)) == NULL) fatal("can't open `%1': %2", name, strerror(errno)); } - input_stack::push(new file_iterator(fp, name)); + input_stack::push(new file_iterator(fcp, name)); tok.next(); process_input_stack(); } diff --git a/src/roff/troff/node.cpp b/src/roff/troff/node.cpp index 311a5cd..9b27f12 100644 --- a/src/roff/troff/node.cpp +++ b/src/roff/troff/node.cpp @@ -1,6 +1,6 @@ // -*- C++ -*- /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2008, 2009, 2010 + 2006, 2008, 2009, 2010, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -32,6 +32,7 @@ extern int debug_state; #include "stringclass.h" #include "mtsm.h" #include "env.h" +#include "file_case.h" #include "request.h" #include "node.h" #include "token.h" @@ -1551,16 +1552,17 @@ void troff_output_file::really_copy_file(hunits x, vunits y, moveto(x, y); flush_tbuf(); do_motion(); - errno = 0; - FILE *ifp = include_search_path.open_file_cautious(filename); - if (ifp == 0) - error("can't open `%1': %2", filename, strerror(errno)); - else { + + file_case *fcp = include_search_path.open_file_cautious(filename, + fcp->fc_const_path); + if (fcp != NULL) { int c; - while ((c = getc(ifp)) != EOF) + while ((c = getc(fcp->file())) != EOF) put(char(c)); - fclose(ifp); - } + delete fcp; + } else + error("can't open `%1': %2", filename, strerror(errno)); + force_motion = 1; current_size = 0; current_tfont = 0; -- 2.0.0 From ea111b9221aff011f2f57aad2da74f8f1936026e Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Fri, 25 Jul 2014 15:53:27 +0200 Subject: [PATCH 04/20] Add GROFF_UNPACK_CHECK m4++ / --with-unpack=XY (Public Domain) --- Makefile.in | 14 ++++++++++++++ configure.ac | 1 + m4/groff.m4 | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index 0abc86e..d76c57d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -406,6 +406,10 @@ address@hidden@ # -DGHOSTSCRIPT=gs the name (and directory if required) of the # ghostscript program # +# -DHAVE_UNPACK_BZ2 if unpacking via bzip2(1) is supported +# -DHAVE_UNPACK_GZ if unpacking via gzip(1) is supported +# -DHAVE_UNPACK_XZ if unpacking via xz(1) is supported +# address@hidden@ # Include @@ -469,6 +473,12 @@ address@hidden@ # Sed script to deal with OS dependencies in sh scripts. SH_DEPS_SED_SCRIPT=$(top_builddir)/arch/misc/shdeps.sed +# Unpacker support address@hidden@ address@hidden@ address@hidden@ address@hidden@ + # The program to create directory hierarchies. mkinstalldirs= $(SHELL) $(top_srcdir)/mkinstalldirs @@ -501,6 +511,10 @@ MDEFINES=\ "EXEEXT=$(EXEEXT)" \ "GLIBC21=$(GLIBC21)" \ "GREP=$(GREP)" \ + "HAVE_UNPACK=$(HAVE_UNPACK)" \ + "HAVE_UNPACK_BZ2=$(HAVE_UNPACK_BZ2)" \ + "HAVE_UNPACK_GZ=$(HAVE_UNPACK_GZ)" \ + "HAVE_UNPACK_XZ=$(HAVE_UNPACK_XZ)" \ "HOST=$(HOST)" \ "INSTALL_DATA=$(INSTALL_DATA)" \ "INSTALL_INFO=$(INSTALL_INFO)" \ diff --git a/configure.ac b/configure.ac index a11f879..b918d6e 100644 --- a/configure.ac +++ b/configure.ac @@ -65,6 +65,7 @@ GROFF_GROFFERDIR_OPTION GROFF_GROFFERDIR_DEFAULT GROFF_GLILYPONDDIR_DEFAULT GROFF_GROGDIR_DEFAULT +GROFF_UNPACK_CHECK GROFF_PERL GROFF_PRINT AC_PROG_EGREP diff --git a/m4/groff.m4 b/m4/groff.m4 index 6021c22..ffc2f3c 100644 --- a/m4/groff.m4 +++ b/m4/groff.m4 @@ -71,14 +71,64 @@ AC_DEFUN([GROFF_PERL], AC_MSG_ERROR([perl version is too old], 1))]) +# It is possible to directly use compressed files +AC_DEFUN([GROFF_UNPACK_CHECK], + [AC_ARG_WITH([unpack], + [AS_HELP_STRING([--with-unpack[[=TYPE]]], + [choose wether support for unpacking of compressed files is desirable. + TYPE can be `yes' or `no', or a comma-separated list of one or + multiple of `bz2', `gz' and `xz', to restrict what can be unpacked])], + [unpack="$withval"], + [unpack=yes]) + test "x$unpack" = xno && unpack='' + + if test "x$unpack" = xyes; then + HAVE_UNPACK=1 + HAVE_UNPACK_BZ2=1 + HAVE_UNPACK_GZ=1 + HAVE_UNPACK_XZ=1 + else + # Don't use case/esac, verify input. + HAVE_UNPACK=0 + HAVE_UNPACK_BZ2=0 + HAVE_UNPACK_GZ=0 + HAVE_UNPACK_XZ=0 + OFS=$IFS + IFS=',' + set -- $unpack + IFS=$OFS + for i + do + test "x$i" = xbz2 && { HAVE_UNPACK=1; HAVE_UNPACK_BZ2=1; continue; } + test "x$i" = xgz && { HAVE_UNPACK=1; HAVE_UNPACK_GZ=1; continue; } + test "x$i" = xxz && { HAVE_UNPACK=1; HAVE_UNPACK_XZ=1; continue; } + AC_MSG_WARN([Invalid `--with-unpack' argument:] $i) + done + fi + + AC_SUBST([HAVE_UNPACK]) + test $HAVE_UNPACK -eq 1 && + AC_DEFINE([HAVE_UNPACK], [1], [Define if you have any unpacker support.]) + AC_SUBST([HAVE_UNPACK_BZ2]) + test $HAVE_UNPACK_BZ2 -eq 1 && + AC_DEFINE([HAVE_UNPACK_BZ2], [1], [Define if you have bzip2 support.]) + AC_SUBST([HAVE_UNPACK_GZ]) + test $HAVE_UNPACK_GZ -eq 1 && + AC_DEFINE([HAVE_UNPACK_GZ], [1], [Define if you have gzip support.]) + AC_SUBST([HAVE_UNPACK_XZ]) + test $HAVE_UNPACK_XZ && + AC_DEFINE([HAVE_UNPACK_XZ], [1], [Define if you have xz support.]) +]) + + # It is possible to fine-tune generation of documenation. AC_DEFUN([GROFF_DOC_CHECK], [AC_ARG_WITH([doc], [AS_HELP_STRING([--with-doc[[=TYPE]]], - [choose which manuals (beside man pages) are desirable. \ - TYPE can be `yes' or `no', or a comma-separated list of \ - one or multiple of `html', `info', `other', `pdf', and \ + [choose which manuals (beside man pages) are desirable. + TYPE can be `yes' or `no', or a comma-separated list of + one or multiple of `html', `info', `other', `pdf', and `examples', to restrict what is produced])], [doc="$withval"], [doc=yes]) -- 2.0.0 From 6ed7720614630f1f70a229ed150fd3975e0bc138 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 22:04:38 +0200 Subject: [PATCH 05/20] file_case: support transparent file decompression (Public Domain).. Since now file decompression can optionally be supported for all files which get opened via file_case{,::muxer()} this changeset in effect adds support for GNU troff(1) installations where each file is compressed. (It depends on file_case::_mux_unpack_default if this is actually true -- it is mux_unpack now, but changing it to ::mux_no_unpack will reduce compression support to those facilities which *explicitly* specify mux_unpack, which this changeset only uses for the `.so' request.) Inspired by a commit from Matthew Dillon (dillon AT apollo DOT backplane DOT com) of DragonFly BSD ([84d7c06], 2014-05-20). --- src/devices/gropdf/Makefile.sub | 4 + src/devices/gropdf/gropdf.pl | 56 ++++++--- src/include/file_case.h | 7 +- src/libs/libgroff/file_case.cpp | 243 ++++++++++++++++++++++++++++++++++++++-- src/roff/troff/input.cpp | 3 +- 5 files changed, 283 insertions(+), 30 deletions(-) diff --git a/src/devices/gropdf/Makefile.sub b/src/devices/gropdf/Makefile.sub index c587dc5..57c3c70 100644 --- a/src/devices/gropdf/Makefile.sub +++ b/src/devices/gropdf/Makefile.sub @@ -39,6 +39,10 @@ gropdf: gropdf.pl $(SH_DEPS_SED_SCRIPT) -e "s|@VERSION@|$(version)$(revision)|" \ -e "s|@PERL@|$(PERL)|" \ -e "s|@GROFF_FONT_DIR@|$(fontpath)|" \ + -e "s|@HAVE_UNPACK@|$(HAVE_UNPACK)|" \ + -e "s|@HAVE_UNPACK_BZ2@|$(HAVE_UNPACK_BZ2)|" \ + -e "s|@HAVE_UNPACK_GZ@|$(HAVE_UNPACK_GZ)|" \ + -e "s|@HAVE_UNPACK_XZ@|$(HAVE_UNPACK_XZ)|" \ -e "s|@RT_SEP@|$(RT_SEP)|" $(srcdir)/gropdf.pl >$@ chmod +x $@ diff --git a/src/devices/gropdf/gropdf.pl b/src/devices/gropdf/gropdf.pl index f18bac8..1b6d256 100644 --- a/src/devices/gropdf/gropdf.pl +++ b/src/devices/gropdf/gropdf.pl @@ -3,7 +3,7 @@ # gropdf : PDF post processor for groff # Last update : 15 Apr 2013 # -# Copyright (C) 2011-2013 +# Copyright (C) 2011-2014 # Free Software Foundation, Inc. # Written by Deri James # @@ -547,21 +547,45 @@ sub LoadDownload sub OpenFile { - my $f=shift; - my $dirs=shift; - my $fnm=shift; - - if (substr($fnm,0,1) eq '/' or substr($fnm,1,1) eq ':') # dos - { - return if -r "$fnm" and open($$f,"<$fnm"); - } - - my (@dirs)=split($cfg{RT_SEP},$dirs); - - foreach my $dir (@dirs) - { - last if -r "$dir/$devnm/$fnm" and open($$f,"<$dir/$devnm/$fnm"); - } + sub __open { + my $fh = shift; + my $p = shift; + + if ($p =~ /.*\.(gz|bz2|xz)$/) { + if (@HAVE_UNPACK@) { + return open($$fh, "bzip2 -cdf $p|") + if @HAVE_UNPACK_BZ2@ && $1 eq 'bz2' && -r $p; + return open($$fh, "gzip -cdf $p|") + if @HAVE_UNPACK_GZ@ && $1 eq 'gz' && -r $p; + return open($$fh, "xz -cdf $p|") + if @HAVE_UNPACK_XZ@ && $1 eq 'xz' && -r $p; + } + } else { + return open($$fh, "$p") if -r $p; + if (@HAVE_UNPACK@) { + return open($$fh, "bzip2 -cdf $p.bz2|") + if @HAVE_UNPACK_BZ2@ && -r "$p.bz2"; + return open($$fh, "gzip -cdf $p.gz|") + if @HAVE_UNPACK_GZ@ && -r "$p.gz"; + return open($$fh, "xz -cdf $p.xz|") + if @HAVE_UNPACK_XZ@ && -r "$p.xz"; + } + } + return undef; + } + + my $f = shift; + my $dirs = shift; + my $fnm = shift; + + if (substr($fnm,0,1) eq '/' || substr($fnm,1,1) eq ':') { # dos + return if __open($f, $fnm); + } + + my (@dirs) = split($cfg{RT_SEP},$dirs); + foreach my $dir (@dirs) { + return if __open($f, "$dir/$devnm/$fnm"); + } } sub LoadDesc diff --git a/src/include/file_case.h b/src/include/file_case.h index a52d121..7ea3f86 100644 --- a/src/include/file_case.h +++ b/src/include/file_case.h @@ -45,8 +45,13 @@ public: enum { mux_need_seek = 1<<(_fc_freebit+0), // File must be seekable mux_need_binary = 1<<(_fc_freebit+1), // Need binary I/O + mux_unpack = 1<<(_fc_freebit+2), // Do auto-check for FILE{.gz,.bz2..} + mux_no_unpack = 1<<(_fc_freebit+3), // Do NOT auto-check + mux_mask = ~fc_mask, mux_default = fc_none, - mux_mask = ~fc_mask + // Defines the global default strategy for dealing with packed files in case + // none of the above has been given explicitly by a callee + _mux_unpack_default = mux_unpack }; file_case(FILE *fp, char const *path, uint32_t flags=fc_none); diff --git a/src/libs/libgroff/file_case.cpp b/src/libs/libgroff/file_case.cpp index 51bc2f2..5fdbd1f 100644 --- a/src/libs/libgroff/file_case.cpp +++ b/src/libs/libgroff/file_case.cpp @@ -23,8 +23,190 @@ #include #include +#include "errarg.h" +#include "error.h" +#include "posix.h" +#include "nonposix.h" + #include "file_case.h" +// Support decompression XXX configure should say `no popen() - no unpacking' +#ifdef POPEN_MISSING +# undef HAVE_UNPACK +#endif + +struct args { + FILE *a_fp; + char const *a_path; + size_t a_path_len; + char const *a_mode; // Mode for fopen(3), if used + uint32_t a_flags; + int32_t a_errno; +}; + +#ifdef HAVE_UNPACK +struct zproc { + uint8_t zp_popen; + uint8_t zp_ext_len; // Extension including `.' () + uint8_t zp_cmd_len; + char zp_ext[5]; + char zp_cmd[16]; +}; + +static zproc const _zprocs[] = { +# define __X(C,E) {true, sizeof(E) -1, sizeof(C) -1, E, C} +# ifdef HAVE_UNPACK_BZ2 + __X("bzip2 -cdf", ".bz2"), +# endif +# ifdef HAVE_UNPACK_GZ + __X("gzip -cdf", ".gz"), +# endif +# ifdef HAVE_UNPACK_XZ + __X("xz -cdf", ".xz") +# endif +# undef __X +}; +#endif // HAVE_UNPACK + +#ifdef HAVE_UNPACK +// Check wether path was explicitly specified with a packer extension. +// This returns a ternary: false only if we knew the extension, applied the +// zproc and that failed to perform, true otherwise (ap->a_fp is 2nd indicator) +static bool _is_ext(args *ap); + +// Plain file didn't exist, iterate over the supported packer extensions +// and see if a matching file exists instead; NULL if not / on error. +// Note that ap->a_errno is ENOENT on entry and only overwritten if we run +// a zproc and that fails XXX ENOENT is blindly used in codebase, but not ISO C +static bool _try_all_ext(args *ap); + +// Create a FILE* according to zp, return NULL on error +static args * __run_zproc(args *ap, zproc const *zp); + +// Callee needs seek()ing, unpack into temporary file, return NULL on error +static args * __unpack(args *ap); +#endif // HAVE_UNPACK + +#ifdef HAVE_UNPACK +static bool +_is_ext(args *ap) +{ + for (zproc const *zp = _zprocs; zp < _zprocs + NELEM(_zprocs); ++zp) { + size_t el = zp->zp_ext_len; + + if (ap->a_path_len <= el) + continue; + if (memcmp(ap->a_path + ap->a_path_len - el, zp->zp_ext, el)) + continue; + + ap = __run_zproc(ap, zp); + break; + } + return (ap != NULL); +} + +static bool +_try_all_ext(args *ap) +{ + for (zproc const *zp = _zprocs; zp < _zprocs + NELEM(_zprocs); ++zp) { + char *np = new char[zp->zp_cmd_len +1+ ap->a_path_len + zp->zp_ext_len +1]; + + memcpy(np, ap->a_path, ap->a_path_len); + + struct ::stat sb; + memcpy(np + ap->a_path_len, zp->zp_ext, zp->zp_ext_len +1); + if (stat(np, &sb)) { + a_delete np; + continue; + } + + // That's our zproc, let it make the deal + char const *pb_save = ap->a_path; + size_t pl_save = ap->a_path_len; + ap->a_path = np; + ap->a_path_len = pl_save + zp->zp_ext_len; + if ((ap = __run_zproc(ap, zp)) != NULL) { + ap->a_path = pb_save; + ap->a_path_len = pl_save; + } + a_delete np; + goto jleave; + } + ap = NULL; +jleave: + return (ap != NULL); +} + +static args * +__run_zproc(args *ap, zproc const *zp) +{ + char *np = new char[zp->zp_cmd_len + 1 + ap->a_path_len +1]; + + size_t l; + memcpy(np, zp->zp_cmd, l = zp->zp_cmd_len); + np[l++] = ' '; + memcpy(np + l, ap->a_path, ap->a_path_len +1); + + if ((ap->a_fp = popen(np, "r")) == NULL) { + ap->a_errno = errno; + ap = NULL; + } else if (ap->a_flags & file_case::mux_need_seek) + ap = __unpack(ap); + else + ap->a_flags |= file_case::fc_pipe; + + a_delete np; + return ap; +} + +static args * +__unpack(args *ap) +{ + size_t const buf_len = (BUFSIZ + 0) > 1 << 15 ? BUFSIZ : 1 << 15; + uint8_t *buf = new uint8_t[buf_len]; + + // xtmpfile uses binary mode and fatal()s on error + FILE *decomp = xtmpfile(NULL, "groff_unpack"), *decomp_save = decomp; + for (;;) { + size_t oc = fread(buf, sizeof *buf, buf_len, ap->a_fp); + if (oc == 0) { + if (!feof(ap->a_fp)) { + ap->a_errno = errno; + decomp = NULL; + } + break; + } + + if (decomp != NULL) { + for (uint8_t *target = buf; oc > 0;) { + size_t i = fwrite(target, sizeof *buf, oc, decomp); + if (i == 0) + break; + oc -= i; + target += i; + } + if (oc > 0) { + ap->a_errno = errno; + decomp = NULL; + } + } + } + if (pclose(ap->a_fp) != 0) + error("decompressor pipe pclose(3) didn't exit cleanly"); + + if (decomp != NULL) + rewind(ap->a_fp = decomp); + else { + fclose(decomp_save); + ap->a_fp = NULL; + ap = NULL; + } + + a_delete buf; + return ap; +} +#endif // HAVE_UNPACK + bool file_case::close(void) { @@ -36,6 +218,10 @@ file_case::close(void) bool rv; if (_flags & fc_dont_close) rv = true; +#ifdef HAVE_UNPACK + else if (_flags & fc_pipe) + rv = (pclose(_file) == 0); +#endif else rv = (fclose(_file) == 0); @@ -53,25 +239,58 @@ file_case::muxer(char const *path, uint32_t flags) assert(!(flags & (fc_dont_close | fc_pipe))); assert(!(flags & (fc_const_path | fc_take_path)) || !(flags & fc_const_path) != !(flags & fc_take_path)); + assert(!(flags & (mux_unpack | mux_no_unpack)) || + !(flags & mux_unpack) != !(flags & mux_no_unpack)); if (!(flags & (fc_const_path | fc_take_path))) { path = strsave(path); flags |= fc_take_path; } + if (!(flags & (mux_unpack | mux_no_unpack))) + flags |= _mux_unpack_default; - errno = 0; - FILE *fp = fopen(path, ((flags & mux_need_binary) ? "rb" : "r")); - int save_err = errno; - - flags &= ~mux_mask; file_case *fcp; - if (fp != NULL) - fcp = new file_case(fp, path, flags); - else { - if (!(flags & fc_const_path)) - a_delete path; - errno = save_err; - fcp = NULL; + args a; + a.a_fp = NULL; + a.a_path_len = strlen(a.a_path = path); + a.a_mode = (flags & mux_need_binary) ? "rb" : "r"; + a.a_flags = flags; + a.a_errno = 0; + + // If we support unpacking then check wether the path already includes + // a packer's extension, i.e., explicitly. Anyway unpack then, despite flags +#ifdef HAVE_UNPACK + if (!_is_ext(&a)) { + assert(a.a_fp == NULL); + goto jerror; } + if (a.a_fp != NULL) + goto jnew; +#endif + + // Try a plain open + errno = 0; + if ((a.a_fp = fopen(a.a_path, a.a_mode)) != NULL) { +#ifdef HAVE_UNPACK +jnew: +#endif + assert(a.a_fp != NULL); + fcp = new file_case(a.a_fp, path, a.a_flags & ~mux_mask); // XXX real path? + goto jleave; + } + a.a_errno = errno; + + // Then auto-expand the given path if so desired +#ifdef HAVE_UNPACK + if (a.a_errno == ENOENT && (a.a_flags & mux_unpack) && _try_all_ext(&a)) + goto jnew; + +jerror: +#endif + if (!(a.a_flags & fc_const_path)) + a_delete a.a_path; + errno = a.a_errno; + fcp = NULL; +jleave: return fcp; } diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp index 932eecb..9458682 100644 --- a/src/roff/troff/input.cpp +++ b/src/roff/troff/input.cpp @@ -5936,7 +5936,8 @@ void source() else { while (!tok.newline() && !tok.eof()) tok.next(); - file_case *fcp = include_search_path.open_file_cautious(nm.contents()); + file_case *fcp = include_search_path.open_file_cautious(nm.contents(), + fcp->mux_unpack); if (fcp != NULL) input_stack::push(new file_iterator(fcp, nm.contents())); else -- 2.0.0 From f605d82bb09f5ee04b470b81e8038f4cf09b2094 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 23:12:55 +0200 Subject: [PATCH 06/20] file_case: add read interface, extend abstraction (Public Domain).. Encapsulate I/O reads under the file_case surface in order to implement a decompression layer that doesn't use external unpack programs but instead directly uses and links against the libraries which implement the decompression algorithms. Add new file_case::mux_need_stdio (and ::fc_have_stdio) flags which henceforth will be required in order to access the .file() a.k.a STD I/O FILE* of an object, for those rare cases (only the grn(1) gremlin preprocessor) where the file_case user needs a FILE* for extended operations which we don't support in file_case, e.g. fscanf(3). --- src/devices/grops/ps.cpp | 2 +- src/devices/grops/ps.h | 42 +++++++------- src/devices/grops/psrm.cpp | 118 +++++++++++++++++++-------------------- src/include/file_case.h | 27 +++++++-- src/libs/libgroff/file_case.cpp | 54 ++++++++++++++++++ src/libs/libgroff/font.cpp | 2 +- src/libs/libgroff/searchpath.cpp | 2 +- src/preproc/eqn/main.cpp | 56 ++++++++++--------- src/preproc/grn/main.cpp | 7 ++- src/preproc/html/pre-html.cpp | 12 ++-- src/preproc/soelim/soelim.cpp | 6 +- src/roff/troff/env.cpp | 42 +++++++------- src/roff/troff/input.cpp | 34 +++++------ src/roff/troff/node.cpp | 2 +- 14 files changed, 241 insertions(+), 165 deletions(-) diff --git a/src/devices/grops/ps.cpp b/src/devices/grops/ps.cpp index b4306a8..c34b7cd 100644 --- a/src/devices/grops/ps.cpp +++ b/src/devices/grops/ps.cpp @@ -792,7 +792,7 @@ void ps_printer::define_encoding(const char *encoding, int encoding_index) const int BUFFER_SIZE = 512; char buf[BUFFER_SIZE]; - for (int lineno = 1; fgets(buf, BUFFER_SIZE, fcp->file()) != NULL; ++lineno) { + for (int lineno = 1; fcp->get_line(buf, BUFFER_SIZE) != NULL; ++lineno) { char *p = buf; while (csspace(*p)) p++; diff --git a/src/devices/grops/ps.h b/src/devices/grops/ps.h index 9e592ae..15d5b3e 100644 --- a/src/devices/grops/ps.h +++ b/src/devices/grops/ps.h @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2002, 2003, 2009, 2013 +/* Copyright (C) 1989-1992, 2002, 2003, 2009, 2013, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -87,30 +87,30 @@ private: unsigned revision = 0); resource *lookup_font(const char *name); void read_download_file(); - void supply_resource(resource *r, int rank, FILE *outfp, - int is_document = 0); - void process_file(int rank, FILE *fp, const char *filename, FILE *outfp); + void supply_resource(resource *r, int rank, FILE *ofp, int is_document = 0); + void process_file(int rank, file_case *fcp, FILE *ofp); resource *read_file_arg(const char **); resource *read_procset_arg(const char **); resource *read_font_arg(const char **); resource *read_resource_arg(const char **); - void print_resources_comment(unsigned flag, FILE *outfp); - void print_extensions_comment(FILE *outfp); - void print_language_level_comment(FILE *outfp); - int do_begin_resource(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_include_resource(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_begin_document(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_include_document(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_begin_procset(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_include_procset(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_begin_font(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_include_font(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_begin_file(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_include_file(const char *ptr, int rank, FILE *fp, FILE *outfp); - int change_to_end_resource(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_begin_preview(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_begin_data(const char *ptr, int rank, FILE *fp, FILE *outfp); - int do_begin_binary(const char *ptr, int rank, FILE *fp, FILE *outfp); + void print_resources_comment(unsigned flag, FILE *ofp); + void print_extensions_comment(FILE *ofp); + void print_language_level_comment(FILE *ofp); + int do_begin_resource(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_include_resource(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_begin_document(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_include_document(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_begin_procset(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_include_procset(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_begin_font(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_include_font(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_begin_file(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_include_file(const char *ptr, int rank, file_case *fp, FILE *ofp); + int change_to_end_resource(const char *ptr, int rank, file_case *fp, + FILE *ofp); + int do_begin_preview(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_begin_data(const char *ptr, int rank, file_case *fcp, FILE *ofp); + int do_begin_binary(const char *ptr, int rank, file_case *fcp, FILE *ofp); }; extern unsigned broken_flags; diff --git a/src/devices/grops/psrm.cpp b/src/devices/grops/psrm.cpp index fae2176..e02a1f8 100644 --- a/src/devices/grops/psrm.cpp +++ b/src/devices/grops/psrm.cpp @@ -324,7 +324,7 @@ void resource_manager::output_prolog(ps_output &out) fputs("%%BeginResource: ", outfp); procset_resource->print_type_and_name(outfp); putc('\n', outfp); - process_file(-1, fcp->file(), fcp->path(), outfp); + process_file(-1, fcp, outfp); fputs("%%EndResource\n", outfp); delete fcp; @@ -378,7 +378,7 @@ void resource_manager::supply_resource(resource *r, int rank, FILE *outfp, putc('\n', outfp); } } - process_file(rank, fcp->file(), fcp->path(), outfp); + process_file(rank, fcp, outfp); delete fcp; if (outfp) { @@ -407,10 +407,10 @@ void resource_manager::supply_resource(resource *r, int rank, FILE *outfp, #define PS_MAGIC "%!PS-Adobe-" -static int ps_get_line(string &buf, FILE *fp) +static int ps_get_line(string &buf, file_case *fcp) { buf.clear(); - int c = getc(fp); + int c = fcp->get_c(); if (c == EOF) return 0; current_lineno++; @@ -418,14 +418,14 @@ static int ps_get_line(string &buf, FILE *fp) if (!valid_input_table[c]) error("invalid input character code %1", int(c)); buf += c; - c = getc(fp); + c = fcp->get_c(); } buf += '\n'; buf += '\0'; if (c == '\r') { - c = getc(fp); + c = fcp->get_c(); if (c != EOF && c != '\n') - ungetc(c, fp); + fcp->unget_c(c); } return 1; } @@ -591,8 +591,8 @@ static const char *matches_comment(string &buf, const char *comment) // Return 1 if the line should be copied out. -int resource_manager::do_begin_resource(const char *ptr, int, FILE *, - FILE *) +int resource_manager::do_begin_resource(const char *ptr, int, file_case *, + FILE *) { resource *r = read_resource_arg(&ptr); if (r) @@ -600,8 +600,8 @@ int resource_manager::do_begin_resource(const char *ptr, int, FILE *, return 1; } -int resource_manager::do_include_resource(const char *ptr, int rank, FILE *, - FILE *outfp) +int resource_manager::do_include_resource(const char *ptr, int rank, + file_case *, FILE *outfp) { resource *r = read_resource_arg(&ptr); if (r) { @@ -617,8 +617,8 @@ int resource_manager::do_include_resource(const char *ptr, int rank, FILE *, return 0; } -int resource_manager::do_begin_document(const char *ptr, int, FILE *, - FILE *) +int resource_manager::do_begin_document(const char *ptr, int, file_case *, + FILE *) { resource *r = read_file_arg(&ptr); if (r) @@ -626,8 +626,8 @@ int resource_manager::do_begin_document(const char *ptr, int, FILE *, return 1; } -int resource_manager::do_include_document(const char *ptr, int rank, FILE *, - FILE *outfp) +int resource_manager::do_include_document(const char *ptr, int rank, + file_case *, FILE *outfp) { resource *r = read_file_arg(&ptr); if (r) @@ -635,8 +635,8 @@ int resource_manager::do_include_document(const char *ptr, int rank, FILE *, return 0; } -int resource_manager::do_begin_procset(const char *ptr, int, FILE *, - FILE *outfp) +int resource_manager::do_begin_procset(const char *ptr, int, file_case *, + FILE *outfp) { resource *r = read_procset_arg(&ptr); if (r) { @@ -650,8 +650,8 @@ int resource_manager::do_begin_procset(const char *ptr, int, FILE *, return 0; } -int resource_manager::do_include_procset(const char *ptr, int rank, FILE *, - FILE *outfp) +int resource_manager::do_include_procset(const char *ptr, int rank, + file_case *, FILE *outfp) { resource *r = read_procset_arg(&ptr); if (r) @@ -659,8 +659,8 @@ int resource_manager::do_include_procset(const char *ptr, int rank, FILE *, return 0; } -int resource_manager::do_begin_file(const char *ptr, int, FILE *, - FILE *outfp) +int resource_manager::do_begin_file(const char *ptr, int, file_case *, + FILE *outfp) { resource *r = read_file_arg(&ptr); if (r) { @@ -674,8 +674,8 @@ int resource_manager::do_begin_file(const char *ptr, int, FILE *, return 0; } -int resource_manager::do_include_file(const char *ptr, int rank, FILE *, - FILE *outfp) +int resource_manager::do_include_file(const char *ptr, int rank, file_case *, + FILE *outfp) { resource *r = read_file_arg(&ptr); if (r) @@ -683,8 +683,8 @@ int resource_manager::do_include_file(const char *ptr, int rank, FILE *, return 0; } -int resource_manager::do_begin_font(const char *ptr, int, FILE *, - FILE *outfp) +int resource_manager::do_begin_font(const char *ptr, int, file_case *, + FILE *outfp) { resource *r = read_font_arg(&ptr); if (r) { @@ -698,8 +698,8 @@ int resource_manager::do_begin_font(const char *ptr, int, FILE *, return 0; } -int resource_manager::do_include_font(const char *ptr, int rank, FILE *, - FILE *outfp) +int resource_manager::do_include_font(const char *ptr, int rank, file_case *, + FILE *outfp) { resource *r = read_font_arg(&ptr); if (r) { @@ -711,19 +711,20 @@ int resource_manager::do_include_font(const char *ptr, int rank, FILE *, return 0; } -int resource_manager::change_to_end_resource(const char *, int, FILE *, - FILE *outfp) +int resource_manager::change_to_end_resource(const char *, int, file_case *, + FILE *outfp) { if (outfp) fputs("%%EndResource\n", outfp); return 0; } -int resource_manager::do_begin_preview(const char *, int, FILE *fp, FILE *) +int resource_manager::do_begin_preview(const char *, int, file_case *fcp, + FILE *) { string buf; do { - if (!ps_get_line(buf, fp)) { + if (!ps_get_line(buf, fcp)) { error("end of file in preview section"); break; } @@ -748,17 +749,17 @@ int read_one_of(const char **ptr, const char **s, int n) return -1; } -void skip_possible_newline(FILE *fp, FILE *outfp) +void skip_possible_newline(file_case *fcp, FILE *outfp) { - int c = getc(fp); + int c = fcp->get_c(); if (c == '\r') { current_lineno++; if (outfp) putc(c, outfp); - int cc = getc(fp); + int cc = fcp->get_c(); if (cc != '\n') { if (cc != EOF) - ungetc(cc, fp); + fcp->unget_c(cc); } else { if (outfp) @@ -771,11 +772,11 @@ void skip_possible_newline(FILE *fp, FILE *outfp) putc(c, outfp); } else if (c != EOF) - ungetc(c, fp); + fcp->unget_c(c); } -int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, - FILE *outfp) +int resource_manager::do_begin_data(const char *ptr, int, file_case *fcp, + FILE *outfp) { while (white_space(*ptr)) ptr++; @@ -817,7 +818,7 @@ int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, unsigned bytecount = 0; unsigned linecount = 0; do { - int c = getc(fp); + int c = fcp->get_c(); if (c == EOF) { error("end of file within data section"); return 0; @@ -826,13 +827,13 @@ int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, putc(c, outfp); bytecount++; if (c == '\r') { - int cc = getc(fp); + int cc = fcp->get_c(); if (cc != '\n') { linecount++; current_lineno++; } if (cc != EOF) - ungetc(cc, fp); + fcp->unget_c(cc); } else if (c == '\n') { linecount++; @@ -840,9 +841,9 @@ int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, } } while ((unit == Bytes ? bytecount : linecount) < numberof); } - skip_possible_newline(fp, outfp); + skip_possible_newline(fcp, outfp); string buf; - if (!ps_get_line(buf, fp)) { + if (!ps_get_line(buf, fcp)) { error("missing %%%%EndData line"); return 0; } @@ -853,8 +854,8 @@ int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, return 0; } -int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp, - FILE *outfp) +int resource_manager::do_begin_binary(const char *ptr, int, file_case *fcp, + FILE *outfp) { if (!outfp) return 0; @@ -864,7 +865,7 @@ int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp, if (outfp) fprintf(outfp, "%%%%BeginData: %u Binary Bytes\n", count); while (count != 0) { - int c = getc(fp); + int c = fcp->get_c(); if (c == EOF) { error("end of file within binary section"); return 0; @@ -873,18 +874,18 @@ int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp, putc(c, outfp); --count; if (c == '\r') { - int cc = getc(fp); + int cc = fcp->get_c(); if (cc != '\n') current_lineno++; if (cc != EOF) - ungetc(cc, fp); + fcp->unget_c(cc); } else if (c == '\n') current_lineno++; } - skip_possible_newline(fp, outfp); + skip_possible_newline(fcp, outfp); string buf; - if (!ps_get_line(buf, fp)) { + if (!ps_get_line(buf, fcp)) { error("missing %%%%EndBinary line"); return 0; } @@ -933,8 +934,7 @@ static unsigned parse_extensions(const char *ptr) // BeginResource: file should be postponed till we have seen // the first line of the file. -void resource_manager::process_file(int rank, FILE *fp, const char *filename, - FILE *outfp) +void resource_manager::process_file(int rank, file_case *fcp, FILE *outfp) { // If none of these comments appear in the header section, and we are // just analyzing the file (ie outfp is 0), then we can return immediately. @@ -953,7 +953,7 @@ void resource_manager::process_file(int rank, FILE *fp, const char *filename, / sizeof(header_comment_table[0]); struct comment_info { const char *name; - int (resource_manager::*proc)(const char *, int, FILE *, FILE *); + int (resource_manager::*proc)(const char *, int, file_case *, FILE *); }; static comment_info comment_table[] = { @@ -979,9 +979,9 @@ void resource_manager::process_file(int rank, FILE *fp, const char *filename, string buf; int saved_lineno = current_lineno; const char *saved_filename = current_filename; - current_filename = filename; + current_filename = fcp->path(); current_lineno = 0; - if (!ps_get_line(buf, fp)) { + if (!ps_get_line(buf, fcp)) { current_filename = saved_filename; current_lineno = saved_lineno; return; @@ -993,7 +993,7 @@ void resource_manager::process_file(int rank, FILE *fp, const char *filename, if (!(broken_flags & STRIP_PERCENT_BANG) || buf[0] != '%' || buf[1] != '!') fputs(buf.contents(), outfp); - } while (ps_get_line(buf, fp)); + } while (ps_get_line(buf, fcp)); } } else { @@ -1004,7 +1004,7 @@ void resource_manager::process_file(int rank, FILE *fp, const char *filename, int had_extensions_comment = 0; int had_language_level_comment = 0; for (;;) { - if (!ps_get_line(buf, fp)) + if (!ps_get_line(buf, fcp)) break; int copy_this_line = 1; if (buf[0] == '%') { @@ -1014,7 +1014,7 @@ void resource_manager::process_file(int rank, FILE *fp, const char *filename, for (i = 0; i < NCOMMENTS; i++) if ((ptr = matches_comment(buf, comment_table[i].name))) { copy_this_line - = (this->*(comment_table[i].proc))(ptr, rank, fp, outfp); + = (this->*(comment_table[i].proc))(ptr, rank, fcp, outfp); break; } if (i >= NCOMMENTS && in_header) { @@ -1071,7 +1071,7 @@ void resource_manager::read_download_file() fatal("can't find `download'"); char buf[512]; - for (int lineno = 1; fgets(buf, sizeof(buf), fcp->file()) != NULL; ++lineno) { + for (int lineno = 1; fcp->get_line(buf, sizeof(buf)) != NULL; ++lineno) { char *p = strtok(buf, " \t\r\n"); if (p == NULL || *p == '#') continue; diff --git a/src/include/file_case.h b/src/include/file_case.h index 7ea3f86..07f21d7 100644 --- a/src/include/file_case.h +++ b/src/include/file_case.h @@ -27,8 +27,10 @@ class file_case { char const *_path; - FILE *_file; + FILE *_file; // fc_have_stdio + void *_layer; // E.g., gzFile uint32_t _flags; + uint8_t _dummy[4]; public: // Flags for ctor / muxer() enum { @@ -37,7 +39,8 @@ public: fc_pipe = 1<<1, // _file is not seekable fc_const_path = 1<<2, // Don't dup path, and don't a_delete it fc_take_path = 1<<3, // Don't dup path, but a_delete it - _fc_freebit = 4, + fc_have_stdio = 1<<4, // .file() may be used + _fc_freebit = 5, fc_mask = (1<<_fc_freebit) - 1 }; @@ -47,6 +50,7 @@ public: mux_need_binary = 1<<(_fc_freebit+1), // Need binary I/O mux_unpack = 1<<(_fc_freebit+2), // Do auto-check for FILE{.gz,.bz2..} mux_no_unpack = 1<<(_fc_freebit+3), // Do NOT auto-check + mux_need_stdio = 1<<(_fc_freebit+4), // Only then may .file() be used mux_mask = ~fc_mask, mux_default = fc_none, // Defines the global default strategy for dealing with packed files in case @@ -54,6 +58,12 @@ public: _mux_unpack_default = mux_unpack }; + enum seek_whence { + seek_set, + seek_cur, + seek_end + }; + file_case(FILE *fp, char const *path, uint32_t flags=fc_none); ~file_case(void); @@ -62,6 +72,14 @@ public: FILE * file(void) const; bool is_pipe(void) const; + bool is_eof(void) const; + int get_c(void); + int unget_c(int c); + char * get_line(char *buf, size_t buf_size); + size_t get_buf(void *buf, size_t buf_size); + void rewind(void); + int seek(long offset, seek_whence whence=seek_set); + // Factory muxer; note that fc_take_path will be honoured even on failure static file_case * muxer(char const *path, uint32_t flags=mux_default); @@ -71,7 +89,7 @@ public: inline file_case::file_case(FILE *fp, char const *path, uint32_t flags) : - _path(path), _file(fp), _flags(flags) + _path(path), _file(fp), _layer(NULL), _flags(flags) { assert(!(flags & (fc_const_path | fc_take_path)) || !(flags & fc_const_path) != !(flags & fc_take_path)); @@ -81,7 +99,7 @@ file_case::file_case(FILE *fp, char const *path, uint32_t flags) inline file_case::~file_case(void) { - if (_file != NULL) + if (_file != NULL || _layer != NULL) // xxx (uintptr_t)a|(uintptr_t)b close(); } @@ -94,6 +112,7 @@ file_case::path(void) const inline FILE * file_case::file(void) const { + assert(_flags & fc_have_stdio); return _file; } diff --git a/src/libs/libgroff/file_case.cpp b/src/libs/libgroff/file_case.cpp index 5fdbd1f..362098b 100644 --- a/src/libs/libgroff/file_case.cpp +++ b/src/libs/libgroff/file_case.cpp @@ -30,6 +30,14 @@ #include "file_case.h" +#undef getc +#undef _getc +#ifdef HAVE_DECL_GETC_UNLOCKED +# define _getc getc_unlocked +#else +# define _getc fgetc +#endif + // Support decompression XXX configure should say `no popen() - no unpacking' #ifdef POPEN_MISSING # undef HAVE_UNPACK @@ -233,6 +241,51 @@ file_case::close(void) return rv; } +bool +file_case::is_eof(void) const +{ + return (feof(_file) != 0); +} + +int +file_case::get_c(void) +{ + return _getc(_file); +} + +int +file_case::unget_c(int c) +{ + return ungetc(c, _file); +} + +char * +file_case::get_line(char *buf, size_t buf_size) +{ + buf = fgets(buf, (int)buf_size, _file); + return buf; +} + +size_t +file_case::get_buf(void *buf, size_t buf_size) +{ + return fread(buf, 1, buf_size, _file); +} + +void +file_case::rewind(void) +{ + ::rewind(_file); +} + +int +file_case::seek(long offset, seek_whence whence) +{ + int w = (whence == seek_set ? SEEK_SET : + (whence == seek_cur ? SEEK_CUR : SEEK_END)); + return fseek(_file, offset, w); +} + /*static*/ file_case * file_case::muxer(char const *path, uint32_t flags) { @@ -271,6 +324,7 @@ file_case::muxer(char const *path, uint32_t flags) // Try a plain open errno = 0; if ((a.a_fp = fopen(a.a_path, a.a_mode)) != NULL) { + a.a_flags |= fc_have_stdio; #ifdef HAVE_UNPACK jnew: #endif diff --git a/src/libs/libgroff/font.cpp b/src/libs/libgroff/font.cpp index b5a1990..e5908a5 100644 --- a/src/libs/libgroff/font.cpp +++ b/src/libs/libgroff/font.cpp @@ -108,7 +108,7 @@ int text_file::next() for (;;) { int i = 0; for (;;) { - int c = getc(fcp->file()); + int c = fcp->get_c(); if (c == EOF) break; if (invalid_input_char(c)) diff --git a/src/libs/libgroff/searchpath.cpp b/src/libs/libgroff/searchpath.cpp index b0520d6..4a0561d 100644 --- a/src/libs/libgroff/searchpath.cpp +++ b/src/libs/libgroff/searchpath.cpp @@ -158,7 +158,7 @@ file_case *search_path::open_file_cautious(char const *name, uint32_t flags) file_case *fcp; if (name == NULL || strcmp(name, "-") == 0) { flags &= ~(fcp->fc_take_path); - flags |= fcp->fc_dont_close | fcp->fc_const_path; + flags |= fcp->fc_dont_close | fcp->fc_const_path | fcp->fc_have_stdio; if (flags & fcp->mux_need_binary) SET_BINARY(fileno(stdin)); fcp = new file_case(stdin, "stdin", flags); diff --git a/src/preproc/eqn/main.cpp b/src/preproc/eqn/main.cpp index 672bc50..b2a3ba1 100644 --- a/src/preproc/eqn/main.cpp +++ b/src/preproc/eqn/main.cpp @@ -34,7 +34,7 @@ extern int yyparse(); extern "C" const char *Version_string; static char *delim_search (char *, int); -static int inline_equation (FILE *, string &, string &); +static int inline_equation (file_case *, string &, string &); char start_delim = '\0'; char end_delim = '\0'; @@ -48,11 +48,11 @@ int html = 0; int xhtml = 0; eqnmode_t output_format; -int read_line(FILE *fp, string *p) +int read_line(file_case *fcp, string *p) { p->clear(); int c = -1; - while ((c = getc(fp)) != EOF) { + while ((c = fcp->get_c()) != EOF) { if (!invalid_input_char(c)) *p += char(c); else @@ -64,7 +64,7 @@ int read_line(FILE *fp, string *p) return p->length() > 0; } -void do_file(FILE *fp, const char *filename) +void do_file(file_case *fcp, const char *filename) { string linebuf; string str; @@ -72,7 +72,7 @@ void do_file(FILE *fp, const char *filename) printf(".lf 1 %s\n", filename); current_filename = filename; current_lineno = 0; - while (read_line(fp, &linebuf)) { + while (read_line(fcp, &linebuf)) { if (linebuf.length() >= 4 && linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f' && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) { @@ -91,7 +91,7 @@ void do_file(FILE *fp, const char *filename) int start_lineno = current_lineno + 1; str.clear(); for (;;) { - if (!read_line(fp, &linebuf)) + if (!read_line(fcp, &linebuf)) fatal("end of file before .EN"); if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') { if (linebuf[2] == 'N' @@ -125,7 +125,7 @@ void do_file(FILE *fp, const char *filename) put_string(linebuf, stdout); } else if (start_delim != '\0' && linebuf.search(start_delim) >= 0 - && inline_equation(fp, linebuf, str)) + && inline_equation(fcp, linebuf, str)) ; else put_string(linebuf, stdout); @@ -136,7 +136,7 @@ void do_file(FILE *fp, const char *filename) // Handle an inline equation. Return 1 if it was an inline equation, // otherwise. -static int inline_equation(FILE *fp, string &linebuf, string &str) +static int inline_equation(file_case *fcp, string &linebuf, string &str) { linebuf += '\0'; char *ptr = &linebuf[0]; @@ -171,7 +171,7 @@ static int inline_equation(FILE *fp, string &linebuf, string &str) break; } str += ptr; - if (!read_line(fp, &linebuf)) + if (!read_line(fcp, &linebuf)) fatal("unterminated `%1' at line %2, looking for `%3'", start_delim, start_lineno, end_delim); linebuf += '\0'; @@ -390,30 +390,32 @@ int main(int argc, char **argv) ".tm warning: (it is advisable to invoke groff via: groff -Thtml -e)\n", device); } + + file_case *fcp; if (load_startup_file) { - file_case *fcp; if ((fcp = config_macro_path.open_file(STARTUP_FILE, fcp->fc_const_path) ) != NULL) { - do_file(fcp->file(), fcp->path()); + do_file(fcp, fcp->path()); delete fcp; } } - if (optind >= argc) - do_file(stdin, "-"); - else - for (int i = optind; i < argc; i++) - if (strcmp(argv[i], "-") == 0) - do_file(stdin, "-"); - else { - errno = 0; - FILE *fp = fopen(argv[i], "r"); - if (!fp) - fatal("can't open `%1': %2", argv[i], strerror(errno)); - else { - do_file(fp, argv[i]); - fclose(fp); - } - } + int i = optind; + if (i >= argc) + goto jstdin; + for (; i < argc; ++i) { + if (!strcmp(argv[i], "-")) { +jstdin: + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); + do_file(fcp, "-"); + } else { + fcp = file_case::muxer(argv[i]); + if (fcp == NULL) + fatal("can't open `%1': %2", argv[i], strerror(errno)); + do_file(fcp, argv[i]); + } + delete fcp; + } if (ferror(stdout) || fflush(stdout) < 0) fatal("output error"); return 0; diff --git a/src/preproc/grn/main.cpp b/src/preproc/grn/main.cpp index b5bcc79..ee17002 100644 --- a/src/preproc/grn/main.cpp +++ b/src/preproc/grn/main.cpp @@ -547,10 +547,11 @@ conv(register FILE *fp, return; } { - file_case *fcp; - if ((fcp = macro_path.open_file(gremlinfile, fcp->fc_const_path)) == NULL) + file_case *fcp = macro_path.open_file(gremlinfile, + fcp->fc_const_path | fcp->mux_need_stdio); /* TODO _need_stdio! */ + if (fcp == NULL) return; - PICTURE = DBRead(fcp->file()); /* read picture file */ + PICTURE = DBRead(fcp->file()); /* read picture file TODO _need_stdio! */ delete fcp; } if (DBNullelt(PICTURE)) diff --git a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp index 8c115ec..bbc2331 100644 --- a/src/preproc/html/pre-html.cpp +++ b/src/preproc/html/pre-html.cpp @@ -248,9 +248,9 @@ void sys_fatal(const char *s) * global line buffer. */ -int get_line(FILE *f) +int get_line(file_case *fcp) { - if (f == 0) + if (fcp == NULL) return 0; if (linebuf == 0) { linebuf = new char[128]; @@ -259,16 +259,16 @@ int get_line(FILE *f) int i = 0; // skip leading whitespace for (;;) { - int c = getc(f); + int c = fcp->get_c(); if (c == EOF) return 0; if (c != ' ' && c != '\t') { - ungetc(c, f); + fcp->unget_c(c); break; } } for (;;) { - int c = getc(f); + int c = fcp->get_c(); if (c == EOF) break; if (i + 1 >= linebufsize) { @@ -298,7 +298,7 @@ static unsigned int get_resolution(void) file_case *fcp; if ((fcp = font_path.open_file("devps/DESC", fcp->fc_const_path)) == NULL) fatal("can't open devps/DESC"); - while (get_line(fcp->file())) { + while (get_line(fcp)) { int n = sscanf(linebuf, "res %u", &res); if (n >= 1) goto jleave; diff --git a/src/preproc/soelim/soelim.cpp b/src/preproc/soelim/soelim.cpp index 0c0654d..da8a675 100644 --- a/src/preproc/soelim/soelim.cpp +++ b/src/preproc/soelim/soelim.cpp @@ -165,7 +165,7 @@ int do_file(const char *filename) current_lineno = 1; set_location(); for (;;) { - int c = getc(fcp->file()); + int c = fcp->get_c(); if (c == EOF) break; switch (state) { @@ -223,7 +223,7 @@ int do_file(const char *filename) case HAD_so: if (c == ' ' || c == '\n' || compatible_flag) { string line; - for (; c != EOF && c != '\n'; c = getc(fcp->file())) + for (; c != EOF && c != '\n'; c = fcp->get_c()) line += c; current_lineno++; line += '\n'; @@ -255,7 +255,7 @@ int do_file(const char *filename) case HAD_lf: if (c == ' ' || c == '\n' || compatible_flag) { string line; - for (; c != EOF && c != '\n'; c = getc(fcp->file())) + for (; c != EOF && c != '\n'; c = fcp->get_c()) line += c; current_lineno++; line += '\n'; diff --git a/src/roff/troff/env.cpp b/src/roff/troff/env.cpp index f8d2ce3..66ec813 100644 --- a/src/roff/troff/env.cpp +++ b/src/roff/troff/env.cpp @@ -3522,7 +3522,7 @@ class hyphen_trie : private trie { void do_delete(void *v); void insert_pattern(const char *pat, int patlen, int *num); void insert_hyphenation(dictionary *ex, const char *pat, int patlen); - int hpf_getc(FILE *f); + int hpf_getc(file_case *fcp); public: hyphen_trie() {} ~hyphen_trie() {} @@ -3784,18 +3784,18 @@ void hyphen_trie::do_delete(void *v) */ -int hyphen_trie::hpf_getc(FILE *f) +int hyphen_trie::hpf_getc(file_case *fcp) { - int c = getc(f); + int c = fcp->get_c(); int c1; int cc = 0; if (c != '^') return c; - c = getc(f); + c = fcp->get_c(); if (c != '^') goto fail; - c = getc(f); - c1 = getc(f); + c = fcp->get_c(); + c1 = fcp->get_c(); if (((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) && ((c1 >= '0' && c1 <= '9') || (c1 >= 'a' && c1 <= 'f'))) { if (c >= '0' && c <= '9') @@ -3809,7 +3809,7 @@ int hyphen_trie::hpf_getc(FILE *f) cc = c * 16 + c1; } else { - ungetc(c1, f); + fcp->unget_c(c1); if (c >= 0 && c <= 63) cc = c + 64; else if (c >= 64 && c <= 127) @@ -3846,24 +3846,24 @@ void hyphen_trie::read_patterns_file(const char *name, int append, goto jleave; } - for (c = hpf_getc(fcp->file());;) { + for (c = hpf_getc(fcp);;) { for (;;) { if (c == '%') { // skip comments do { - c = getc(fcp->file()); + c = fcp->get_c(); } while (c != EOF && c != '\n'); } if (c == EOF || !csspace(c)) break; - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); } if (c == EOF) { if (have_keyword || traditional) // we are done break; else { // rescan file in `traditional' mode - rewind(fcp->file()); + fcp->rewind(); traditional = 1; - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); continue; } } @@ -3877,14 +3877,14 @@ void hyphen_trie::read_patterns_file(const char *name, int append, buf[i++] = c; num[i] = 0; } - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); } while (i < WORD_MAX && c != EOF && !csspace(c) && c != '%' && c != '{' && c != '}'); } if (!traditional) { if (i >= 9 && !strncmp(buf + i - 9, "\\patterns", 9)) { while (csspace(c)) - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); if (c == '{') { if (have_patterns || have_hyphenation) error("\\patterns not allowed inside of %1 group", @@ -3893,13 +3893,13 @@ void hyphen_trie::read_patterns_file(const char *name, int append, have_patterns = 1; have_keyword = 1; } - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); continue; } } else if (i >= 12 && !strncmp(buf + i - 12, "\\hyphenation", 12)) { while (csspace(c)) - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); if (c == '{') { if (have_patterns || have_hyphenation) error("\\hyphenation not allowed inside of %1 group", @@ -3908,7 +3908,7 @@ void hyphen_trie::read_patterns_file(const char *name, int append, have_hyphenation = 1; have_keyword = 1; } - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); continue; } } @@ -3929,19 +3929,19 @@ void hyphen_trie::read_patterns_file(const char *name, int append, if (i > 0) final_hyphenation = 1; } - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); } else if (c == '{') { if (have_patterns || have_hyphenation) error("`{' not allowed within %1 group", have_patterns ? "\\patterns" : "\\hyphenation"); - c = hpf_getc(fcp->file()); // skipped if not starting \patterns - // or \hyphenation + c = hpf_getc(fcp); // skipped if not starting \patterns + // or \hyphenation } } else { if (c == '{' || c == '}') - c = hpf_getc(fcp->file()); + c = hpf_getc(fcp); } if (i > 0) { if (have_patterns || final_pattern || traditional) { diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp index 9458682..fa2c8bd 100644 --- a/src/roff/troff/input.cpp +++ b/src/roff/troff/input.cpp @@ -346,7 +346,7 @@ int file_iterator::fill(node **) ptr = p; unsigned char *e = p + BUF_SIZE; while (p < e) { - int c = getc(_fcp->file()); + int c = _fcp->get_c(); if (c == EOF) break; if (invalid_input_char(c)) @@ -373,13 +373,13 @@ int file_iterator::fill(node **) int file_iterator::peek() { - int c = getc(_fcp->file()); + int c = _fcp->get_c(); while (invalid_input_char(c)) { warning(WARN_INPUT, "invalid input character code %1", int(c)); - c = getc(_fcp->file()); + c = _fcp->get_c(); } if (c != EOF) - ungetc(c, _fcp->file()); + _fcp->unget_c(c); return c; } @@ -6047,9 +6047,9 @@ int parse_bounding_box(char *p, bounding_box *bb) #define PS_LINE_MAX 255 cset white_space("\n\r \t"); -int ps_get_line(char *buf, FILE *fp, const char* filename) +int ps_get_line(char *buf, file_case *fcp, const char* filename) { - int c = getc(fp); + int c = fcp->get_c(); if (c == EOF) { buf[0] = '\0'; return 0; @@ -6066,14 +6066,14 @@ int ps_get_line(char *buf, FILE *fp, const char* filename) error("PostScript file `%1' is non-conforming " "because length of line exceeds 255", filename); } - c = getc(fp); + c = fcp->get_c(); } buf[i++] = '\n'; buf[i] = '\0'; if (c == '\r') { - c = getc(fp); + c = fcp->get_c(); if (c != EOF && c != '\n') - ungetc(c, fp); + fcp->unget_c(c); } return 1; } @@ -6086,14 +6086,14 @@ inline void assign_registers(int llx, int lly, int urx, int ury) ury_reg_contents = ury; } -void do_ps_file(FILE *fp, const char* filename) +void do_ps_file(file_case *fcp, const char* filename) { bounding_box bb; int bb_at_end = 0; char buf[PS_LINE_MAX]; llx_reg_contents = lly_reg_contents = urx_reg_contents = ury_reg_contents = 0; - if (!ps_get_line(buf, fp, filename)) { + if (!ps_get_line(buf, fcp, filename)) { error("`%1' is empty", filename); return; } @@ -6102,7 +6102,7 @@ void do_ps_file(FILE *fp, const char* filename) filename); return; } - while (ps_get_line(buf, fp, filename) != 0) { + while (ps_get_line(buf, fcp, filename) != 0) { // in header comments, `%X' (`X' any printable character except // whitespace) is possible too if (buf[0] == '%') { @@ -6137,12 +6137,12 @@ void do_ps_file(FILE *fp, const char* filename) for (offset = 512; !last_try; offset *= 2) { int had_trailer = 0; int got_bb = 0; - if (offset > 32768 || fseek(fp, -offset, 2) == -1) { + if (offset > 32768 || fcp->seek(-offset, fcp->seek_end) == -1) { last_try = 1; - if (fseek(fp, 0L, 0) == -1) + if (fcp->seek(0L, fcp->seek_set) == -1) break; } - while (ps_get_line(buf, fp, filename) != 0) { + while (ps_get_line(buf, fcp, filename) != 0) { if (buf[0] == '%' && buf[1] == '%') { if (!had_trailer) { if (strncmp(buf + 2, "Trailer", 7) == 0) @@ -6188,7 +6188,7 @@ void ps_bbox_request() file_case *fcp = include_search_path.open_file_cautious(nm.contents(), fcp->mux_need_seek | fcp->mux_need_binary); if (fcp != NULL) { - do_ps_file(fcp->file(), nm.contents()); + do_ps_file(fcp, nm.contents()); delete fcp; } else error("can't open `%1': %2", nm.contents(), strerror(errno)); @@ -7328,7 +7328,7 @@ void transparent_file() else { int bol = 1; for (;;) { - int c = getc(fcp->file()); + int c = fcp->get_c(); if (c == EOF) break; if (invalid_input_char(c)) diff --git a/src/roff/troff/node.cpp b/src/roff/troff/node.cpp index 9b27f12..2f2306f 100644 --- a/src/roff/troff/node.cpp +++ b/src/roff/troff/node.cpp @@ -1557,7 +1557,7 @@ void troff_output_file::really_copy_file(hunits x, vunits y, fcp->fc_const_path); if (fcp != NULL) { int c; - while ((c = getc(fcp->file())) != EOF) + while ((c = fcp->get_c()) != EOF) put(char(c)); delete fcp; } else -- 2.0.0 From 5c2bf98e6843b43242ee99d8a13577c8059b6e90 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Fri, 25 Jul 2014 15:53:31 +0200 Subject: [PATCH 07/20] Add GROFF_ZLIB_CHECK m4++ / --with-zlib=DIR (Public Domain) --- configure.ac | 1 + m4/groff.m4 | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/configure.ac b/configure.ac index b918d6e..619f579 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,7 @@ GROFF_GROFFERDIR_DEFAULT GROFF_GLILYPONDDIR_DEFAULT GROFF_GROGDIR_DEFAULT GROFF_UNPACK_CHECK +GROFF_ZLIB_CHECK GROFF_PERL GROFF_PRINT AC_PROG_EGREP diff --git a/m4/groff.m4 b/m4/groff.m4 index ffc2f3c..7078bde 100644 --- a/m4/groff.m4 +++ b/m4/groff.m4 @@ -121,6 +121,41 @@ AC_DEFUN([GROFF_UNPACK_CHECK], ]) +# Check for zlib +AC_DEFUN([GROFF_ZLIB_CHECK], + [user=0 + AC_ARG_WITH([zlib], + [AS_HELP_STRING([--with-zlib[[=DIR]]], + [choose wether support of `gz' decompression through the zlib library + is desirable (requires --with-unpack to include `gz')])], + [user=1; ZLIB="$withval"], + [ZLIB=yes]) + + if test $HAVE_UNPACK_GZ -ne 1; then + if test $user -ne 0 && test "x$ZLIB" != xno; then + AC_MSG_ERROR([--with-zlib needs --with-unpack= (to include `gz')]) + fi + else + DIR=/usr/local + test -f "$DIR/include/zlib.h" || DIR=/usr + if test "x$ZLIB" != xyes; then + DIR=$ZLIB + CPPFLAGS="-I$DIR/include $CPPFLAGS" + LDFLAGS="-L$DIR/lib $LDFLAGS" + fi + AC_CHECK_HEADER([zlib.h], [ZLIB=1], + [AC_MSG_ERROR([Cannot find zlib.h; either specify a valid zlib + installation with --with-zlib=DIR or disable zlib usage with + --without-zlib])]) + AC_CHECK_LIB([z], [gzopen], [LIBS="-lz $LIBS"], + [AC_MSG_ERROR([cannot link against -lz; either specify a valid zlib + installation with --with-zlib=DIR or disable zlib usage with + --without-zlib])]) + AC_DEFINE([HAVE_ZLIB], [1], [Define if you have the zlib library.]) + fi +]) + + # It is possible to fine-tune generation of documenation. AC_DEFUN([GROFF_DOC_CHECK], -- 2.0.0 From f6ad3b78d17ee6a7d2d066fe93b47617f3235af7 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 22:24:24 +0200 Subject: [PATCH 08/20] file_case: implement direct HAVE_ZLIB layer (Public Domain) --- src/libs/libgroff/file_case.cpp | 182 ++++++++++++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 36 deletions(-) diff --git a/src/libs/libgroff/file_case.cpp b/src/libs/libgroff/file_case.cpp index 362098b..f47c4f2 100644 --- a/src/libs/libgroff/file_case.cpp +++ b/src/libs/libgroff/file_case.cpp @@ -23,6 +23,10 @@ #include #include +#ifdef HAVE_ZLIB +# include +#endif + #include "errarg.h" #include "error.h" #include "posix.h" @@ -43,8 +47,23 @@ # undef HAVE_UNPACK #endif +// (Enclosed by HAVE_UNPACK) Directly support decompression library layer? +// XXX We yet only support a zlib _LAYER, which is why we directly address zlib +// XXX functions instead of furtherly abstracting into a struct iolayer or sth. +// XXX If we would, that can only have read_buf() and close() and we should +// XXX deal with buffer handling entirely ourselfs, in which case even the +// XXX popen(3) code path could be enwrapped into struct iolayer; i.e., then +// XXX the entire public read interface could internally be driven by iolayer +#ifndef HAVE_ZLIB +# define HAVE_ZLIB 0 +#endif +#if HAVE_ZLIB +# define _LAYER +#endif + struct args { FILE *a_fp; + void *a_layer; char const *a_path; size_t a_path_len; char const *a_mode; // Mode for fopen(3), if used @@ -57,20 +76,21 @@ struct zproc { uint8_t zp_popen; uint8_t zp_ext_len; // Extension including `.' () uint8_t zp_cmd_len; + uint8_t zp_layer; // Uses I/O layer (zlib) char zp_ext[5]; - char zp_cmd[16]; + char zp_cmd[15]; }; static zproc const _zprocs[] = { -# define __X(C,E) {true, sizeof(E) -1, sizeof(C) -1, E, C} +# define __X(L,C,E) {true, sizeof(E) -1, sizeof(C) -1, L, E, C} # ifdef HAVE_UNPACK_BZ2 - __X("bzip2 -cdf", ".bz2"), + __X(0, "bzip2 -cdf", ".bz2"), # endif # ifdef HAVE_UNPACK_GZ - __X("gzip -cdf", ".gz"), + __X(HAVE_ZLIB, "gzip -cdf", ".gz"), # endif # ifdef HAVE_UNPACK_XZ - __X("xz -cdf", ".xz") + __X(0, "xz -cdf", ".xz") # endif # undef __X }; @@ -91,7 +111,7 @@ static bool _try_all_ext(args *ap); // Create a FILE* according to zp, return NULL on error static args * __run_zproc(args *ap, zproc const *zp); -// Callee needs seek()ing, unpack into temporary file, return NULL on error +// Callee needs seek()ing or STD I/O, unpack into temporary file, NULL on error static args * __unpack(args *ap); #endif // HAVE_UNPACK @@ -148,22 +168,36 @@ jleave: static args * __run_zproc(args *ap, zproc const *zp) { - char *np = new char[zp->zp_cmd_len + 1 + ap->a_path_len +1]; +# ifdef _LAYER + if (zp->zp_layer) { + if ((ap->a_layer = gzopen(ap->a_path, "rb")) == NULL) { + ap->a_errno = errno; + ap = NULL; + } else if (ap->a_flags & + (file_case::mux_need_seek | file_case::mux_need_stdio)) + ap = __unpack(ap); + } else { +# endif + char *np = new char[zp->zp_cmd_len + 1 + ap->a_path_len +1]; - size_t l; - memcpy(np, zp->zp_cmd, l = zp->zp_cmd_len); - np[l++] = ' '; - memcpy(np + l, ap->a_path, ap->a_path_len +1); + size_t l; + memcpy(np, zp->zp_cmd, l = zp->zp_cmd_len); + np[l++] = ' '; + memcpy(np + l, ap->a_path, ap->a_path_len +1); - if ((ap->a_fp = popen(np, "r")) == NULL) { - ap->a_errno = errno; - ap = NULL; - } else if (ap->a_flags & file_case::mux_need_seek) - ap = __unpack(ap); - else - ap->a_flags |= file_case::fc_pipe; + if ((ap->a_fp = popen(np, "r")) == NULL) { + ap->a_errno = errno; + ap = NULL; + } else if (ap->a_flags & file_case::mux_need_seek) + ap = __unpack(ap); + else + ap->a_flags |= file_case::fc_pipe | file_case::fc_have_stdio; + + a_delete np; +# ifdef _LAYER + } +# endif - a_delete np; return ap; } @@ -176,8 +210,21 @@ __unpack(args *ap) // xtmpfile uses binary mode and fatal()s on error FILE *decomp = xtmpfile(NULL, "groff_unpack"), *decomp_save = decomp; for (;;) { - size_t oc = fread(buf, sizeof *buf, buf_len, ap->a_fp); - if (oc == 0) { + size_t oc; + +# ifdef _LAYER + if (ap->a_layer != NULL) { + int i = gzread((gzFile)ap->a_layer, buf, buf_len); + if (i == -1) { + ap->a_errno = errno; + decomp = NULL; + break; + } else if (i == 0) + break; + oc = (size_t)i; + } else +# endif + if ((oc = fread(buf, sizeof *buf, buf_len, ap->a_fp)) == 0) { if (!feof(ap->a_fp)) { ap->a_errno = errno; decomp = NULL; @@ -199,12 +246,21 @@ __unpack(args *ap) } } } + +# ifdef _LAYER + if (ap->a_layer != NULL) { + if (gzclose((gzFile)ap->a_layer) != Z_OK) + error("decompressor gzclose(3) failed"); + ap->a_layer = NULL; + } else +# endif if (pclose(ap->a_fp) != 0) error("decompressor pipe pclose(3) didn't exit cleanly"); - if (decomp != NULL) + if (decomp != NULL) { + ap->a_flags |= file_case::fc_have_stdio; rewind(ap->a_fp = decomp); - else { + } else { fclose(decomp_save); ap->a_fp = NULL; ap = NULL; @@ -218,7 +274,8 @@ __unpack(args *ap) bool file_case::close(void) { - assert(_file != NULL); + assert((_file != NULL && _layer == NULL) || + (_file == NULL && _layer != NULL)); if (!(_flags & fc_const_path)) a_delete _path; @@ -226,6 +283,10 @@ file_case::close(void) bool rv; if (_flags & fc_dont_close) rv = true; +#ifdef _LAYER + else if (_layer != NULL) + rv = (gzclose((gzFile)_layer) == Z_OK); +#endif #ifdef HAVE_UNPACK else if (_flags & fc_pipe) rv = (pclose(_file) == 0); @@ -234,8 +295,9 @@ file_case::close(void) rv = (fclose(_file) == 0); #ifndef NDEBUG - _file = NULL; _path = NULL; + _file = NULL; + _layer = NULL; _flags = fc_none; #endif return rv; @@ -244,46 +306,91 @@ file_case::close(void) bool file_case::is_eof(void) const { - return (feof(_file) != 0); + bool rv; +#ifdef _LAYER + if (_layer != NULL) + rv = (gzeof((gzFile)_layer) != 0); + else +#endif + rv = (feof(_file) != 0); + return rv; } int file_case::get_c(void) { - return _getc(_file); + int rv; +#ifdef _LAYER + if (_layer != NULL) + rv = gzgetc((gzFile)_layer); + else +#endif + rv = _getc(_file); + return rv; } int file_case::unget_c(int c) { - return ungetc(c, _file); + int rv; +#ifdef _LAYER + if (_layer != NULL) + rv = gzungetc(c, (gzFile)_layer); + else +#endif + rv = ungetc(c, _file); + return rv; } char * file_case::get_line(char *buf, size_t buf_size) { - buf = fgets(buf, (int)buf_size, _file); +#ifdef _LAYER + if (_layer != NULL) + buf = gzgets((gzFile)_layer, buf, (int)buf_size); + else +#endif + buf = fgets(buf, (int)buf_size, _file); return buf; } size_t file_case::get_buf(void *buf, size_t buf_size) { - return fread(buf, 1, buf_size, _file); + size_t rv; +#ifdef _LAYER + if (_layer != NULL) { + int i = gzread((gzFile)_layer, buf, (unsigned int)buf_size); + rv = (i <= 0) ? 0 : (size_t)i; + } else +#endif + rv = fread(buf, 1, buf_size, _file); + return rv; } void file_case::rewind(void) { - ::rewind(_file); +#ifdef _LAYER + if (_layer != NULL) + gzrewind((gzFile)_layer); + else +#endif + ::rewind(_file); } int file_case::seek(long offset, seek_whence whence) { - int w = (whence == seek_set ? SEEK_SET : + int x = (whence == seek_set ? SEEK_SET : (whence == seek_cur ? SEEK_CUR : SEEK_END)); - return fseek(_file, offset, w); +#ifdef _LAYER + if (_layer != NULL) + x = gzseek((gzFile)_layer, (z_off_t)offset, x); + else +#endif + x = fseek(_file, offset, x); + return x; } /*static*/ file_case * @@ -305,6 +412,7 @@ file_case::muxer(char const *path, uint32_t flags) file_case *fcp; args a; a.a_fp = NULL; + a.a_layer = NULL; a.a_path_len = strlen(a.a_path = path); a.a_mode = (flags & mux_need_binary) ? "rb" : "r"; a.a_flags = flags; @@ -314,10 +422,10 @@ file_case::muxer(char const *path, uint32_t flags) // a packer's extension, i.e., explicitly. Anyway unpack then, despite flags #ifdef HAVE_UNPACK if (!_is_ext(&a)) { - assert(a.a_fp == NULL); + assert(a.a_fp == NULL && a.a_layer == NULL); goto jerror; } - if (a.a_fp != NULL) + if (a.a_fp != NULL || a.a_layer != NULL) goto jnew; #endif @@ -328,8 +436,10 @@ file_case::muxer(char const *path, uint32_t flags) #ifdef HAVE_UNPACK jnew: #endif - assert(a.a_fp != NULL); + assert((a.a_fp != NULL && a.a_layer == NULL) || + (a.a_fp == NULL && a.a_layer != NULL)); fcp = new file_case(a.a_fp, path, a.a_flags & ~mux_mask); // XXX real path? + fcp->_layer = a.a_layer; goto jleave; } a.a_errno = errno; -- 2.0.0 From 3f3f721712242f86137494bf3d66861a063accdc Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 16:22:57 +0200 Subject: [PATCH 09/20] CXX peace: src/preproc/eqn/pile.cpp (Public Domain) --- src/preproc/eqn/pile.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/preproc/eqn/pile.cpp b/src/preproc/eqn/pile.cpp index 79982d0..e35f6a9 100644 --- a/src/preproc/eqn/pile.cpp +++ b/src/preproc/eqn/pile.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2004, 2007, 2009, 2013 +/* Copyright (C) 1989-1992, 2004, 2007, 2009, 2013, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -106,11 +106,12 @@ void pile_box::output() case RIGHT_ALIGN: av = "right"; break; + default: + assert(0); + // FALLTHRU (pacify compiler) case CENTER_ALIGN: av = "center"; break; - default: - assert(0); } printf("", av); for (int i = 0; i < col.len; i++) { @@ -249,11 +250,12 @@ void matrix_box::output() case RIGHT_ALIGN: av = "right"; break; + default: + assert(0); + // FALLTHRU (pacify compiler) case CENTER_ALIGN: av = "center"; break; - default: - assert(0); } printf("", av); p[j]->p[i]->output(); -- 2.0.0 From d73d2159ee80afe7b14ecbb4d1f3b51e6038ec53 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 14:38:13 +0200 Subject: [PATCH 10/20] CXX peace: src/roff/troff/input.cpp (Public Domain) --- src/roff/troff/input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp index fa2c8bd..e914413 100644 --- a/src/roff/troff/input.cpp +++ b/src/roff/troff/input.cpp @@ -3256,7 +3256,7 @@ macro::macro() } macro::macro(const macro &m) -: filename(m.filename), lineno(m.lineno), len(m.len), +: request_or_macro(), filename(m.filename), lineno(m.lineno), len(m.len), empty_macro(m.empty_macro), is_a_diversion(m.is_a_diversion), is_a_string(m.is_a_string), p(m.p) { -- 2.0.0 From 2668aebb375cb0e236ad41776f63386a75172eb3 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 14:39:17 +0200 Subject: [PATCH 11/20] CXX peace: src/preproc/grn/hgraph.cpp (Public Domain) --- src/preproc/grn/hgraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preproc/grn/hgraph.cpp b/src/preproc/grn/hgraph.cpp index 0120895..2a05b1f 100644 --- a/src/preproc/grn/hgraph.cpp +++ b/src/preproc/grn/hgraph.cpp @@ -597,7 +597,7 @@ HGArc(register int cx, resolution = (1.0 + groff_hypot(xs, ys) / res) * PointsPerInterval; /* mask = (1 << (int) log10(resolution + 1.0)) - 1; */ (void) frexp(resolution, &m); /* A bit more elegant than log10 */ - for (mask = 1; mask < m; mask = mask << 1); + for (mask = 1; mask < m; mask <<= 1) {;} mask -= 1; epsilon = 1.0 / resolution; -- 2.0.0 From 1226fbbc01136cf9753baad83d70cb01eae34b34 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 17:50:02 +0200 Subject: [PATCH 12/20] Preproc: use file_case::muxer() for ARGV: eqn/ (Public Domain) --- src/preproc/eqn/lex.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/preproc/eqn/lex.cpp b/src/preproc/eqn/lex.cpp index 899ecae..0ac8f0d 100644 --- a/src/preproc/eqn/lex.cpp +++ b/src/preproc/eqn/lex.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000-2003, 2005, 2007-2009, 2013 +/* Copyright (C) 1989-1992, 2000-2003, 2005, 2007-2009, 2013, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -22,6 +22,7 @@ along with this program. If not, see . */ #include "eqn_tab.h" #include "stringclass.h" #include "ptable.h" +#include "file_case.h" // declarations to avoid friend name injection problems @@ -333,14 +334,14 @@ public: }; class file_input : public input { - FILE *fp; + file_case *_fcp; char *filename; int lineno; string line; const char *ptr; int read_line(); public: - file_input(FILE *, const char *, input *); + file_input(file_case *, const char *, input *); ~file_input(); int get(); int peek(); @@ -394,17 +395,16 @@ int input::get_location(char **, int *) return 0; } -file_input::file_input(FILE *f, const char *fn, input *p) -: input(p), lineno(0), ptr("") +file_input::file_input(file_case *fcp, const char *fn, input *p) +: input(p), _fcp(fcp), lineno(0), ptr("") { - fp = f; filename = strsave(fn); } file_input::~file_input() { a_delete filename; - fclose(fp); + delete _fcp; } int file_input::read_line() @@ -413,7 +413,7 @@ int file_input::read_line() line.clear(); lineno++; for (;;) { - int c = getc(fp); + int c = _fcp->get_c(); if (c == EOF) break; else if (invalid_input_char(c)) @@ -925,13 +925,12 @@ void do_include() } token_buffer += '\0'; const char *filename = token_buffer.contents(); - errno = 0; - FILE *fp = fopen(filename, "r"); - if (fp == 0) { + file_case *fcp = file_case::muxer(filename); + if (fcp == NULL) { lex_error("can't open included file `%1'", filename); return; } - current_input = new file_input(fp, filename, current_input); + current_input = new file_input(fcp, filename, current_input); } void ignore_definition() -- 2.0.0 From 34099883bc674832ebfa6e29346503a64a031dd8 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 22:04:46 +0200 Subject: [PATCH 13/20] Preproc: use file_case::muxer() for ARGV: grn/ (Public Domain) --- src/preproc/grn/main.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/preproc/grn/main.cpp b/src/preproc/grn/main.cpp index ee17002..f5e3b8a 100644 --- a/src/preproc/grn/main.cpp +++ b/src/preproc/grn/main.cpp @@ -231,8 +231,8 @@ int compatibility_flag = FALSE; /* TRUE if in compatibility mode */ void getres(); -int doinput(FILE *fp); -void conv(register FILE *fp, int baseline); +int doinput(file_case *fcp); +void conv(file_case *fcp, int baseline); void savestate(); int has_polygon(register ELT *elist); void interpret(char *line); @@ -284,7 +284,6 @@ main(int argc, { setlocale(LC_NUMERIC, "C"); program_name = argv[0]; - register FILE *fp; register int k; register char c; int gfil = 0; @@ -354,22 +353,26 @@ main(int argc, } for (k = 0; k < gfil; k++) { + file_case *fcp; if (file[k] != NULL) { - if ((fp = fopen(file[k], "r")) == NULL) - fatal("can't open %1", file[k]); + if ((fcp = file_case::muxer(file[k])) == NULL) + fatal("can't open %1", file[k]); } else - fp = stdin; + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); - while (doinput(fp)) { + while (doinput(fcp)) { if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') { if (compatibility_flag || *c4 == '\n' || *c4 == ' ' || *c4 == '\0') - conv(fp, linenum); + conv(fcp, linenum); else fputs(inputline, stdout); } else fputs(inputline, stdout); } + + delete fcp; } return 0; @@ -445,9 +448,9 @@ getres() *----------------------------------------------------------------------------*/ int -doinput(FILE *fp) +doinput(file_case *fcp) { - if (fgets(inputline, MAXINLINE, fp) == NULL) + if (fcp->get_line(inputline, MAXINLINE) == NULL) return 0; if (strchr(inputline, '\n')) /* ++ only if it's a complete line */ linenum++; @@ -512,7 +515,7 @@ initpic() *----------------------------------------------------------------------------*/ void -conv(register FILE *fp, +conv(file_case *fcp, int baseline) { register int done = 0; /* flag to remember if finished */ @@ -530,7 +533,7 @@ conv(register FILE *fp, strcpy(GScommand, inputline); /* save `.GS' line for later */ do { - done = !doinput(fp); /* test for EOF */ + done = !doinput(fcp); /* test for EOF */ flyback = (*c3 == 'F'); /* and .GE or .GF */ compat = (compatibility_flag || *c4 == '\n' || *c4 == ' ' || *c4 == '\0'); -- 2.0.0 From 906e29b3ab9e18e71a768fdcf058ef62ba82de71 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 22:04:48 +0200 Subject: [PATCH 14/20] Preproc: use file_case::muxer() for ARGV: html/ (Public Domain) --- src/preproc/html/pre-html.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp index bbc2331..d5a5e49 100644 --- a/src/preproc/html/pre-html.cpp +++ b/src/preproc/html/pre-html.cpp @@ -416,7 +416,7 @@ class char_buffer { public: char_buffer(); ~char_buffer(); - int read_file(FILE *fp); + int read_file(file_case *fcp); int do_html(int argc, char *argv[]); int do_image(int argc, char *argv[]); void emit_troff_output(int device_format_selector); @@ -457,10 +457,10 @@ char_buffer::~char_buffer() * char_blocks. */ -int char_buffer::read_file(FILE *fp) +int char_buffer::read_file(file_case *fcp) { int n; - while (!feof(fp)) { + while (!fcp->is_eof()) { if (tail == NULL) { tail = new char_block; head = tail; @@ -473,14 +473,17 @@ int char_buffer::read_file(FILE *fp) } // at this point we have a tail which is ready for the next SIZE // bytes of the file - n = fread(tail->buffer, sizeof(char), char_block::SIZE-tail->used, fp); - if (n <= 0) - // error - return 0; - else + n = fcp->get_buf(tail->buffer, char_block::SIZE - tail->used); + if (n != 0) tail->used += n * sizeof(char); + else { + n = fcp->is_eof(); + goto jleave; + } } - return 1; + n = 1; +jleave: + return n; } /* @@ -1809,25 +1812,25 @@ int main(int argc, char **argv) static int do_file(const char *filename) { - FILE *fp; + file_case *fcp; current_filename = filename; if (strcmp(filename, "-") == 0) - fp = stdin; + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); else { - fp = fopen(filename, "r"); - if (fp == 0) { + fcp = file_case::muxer(filename); + if (fcp == NULL) { error("can't open `%1': %2", filename, strerror(errno)); return 0; } } - if (inputFile.read_file(fp)) { + if (inputFile.read_file(fcp)) { // XXX } - if (fp != stdin) - fclose(fp); + delete fcp; current_filename = NULL; return 1; } -- 2.0.0 From deff27cf7941a3a5f295735f25ba4d503ebeba1a Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 22:04:51 +0200 Subject: [PATCH 15/20] Preproc: use file_case::muxer() for ARGV: pic/ (Public Domain) --- src/preproc/pic/lex.cpp | 44 +++++++++--------- src/preproc/pic/main.cpp | 118 +++++++++++++++++++++++------------------------ src/preproc/pic/pic.h | 8 ++-- 3 files changed, 85 insertions(+), 85 deletions(-) diff --git a/src/preproc/pic/lex.cpp b/src/preproc/pic/lex.cpp index 73ef9a1..9c6df58 100644 --- a/src/preproc/pic/lex.cpp +++ b/src/preproc/pic/lex.cpp @@ -1,6 +1,6 @@ // -*- C++ -*- /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002, 2003, 2004, 2006, - 2007, 2009 + 2007, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -75,14 +75,14 @@ int input::get_location(const char **, int *) return 0; } -file_input::file_input(FILE *f, const char *fn) -: fp(f), filename(fn), lineno(0), ptr("") +file_input::file_input(file_case *fcp, const char *fn) +: _fcp(fcp), filename(fn), lineno(0), ptr("") { } file_input::~file_input() { - fclose(fp); + delete _fcp; } int file_input::read_line() @@ -91,7 +91,7 @@ int file_input::read_line() line.clear(); lineno++; for (;;) { - int c = getc(fp); + int c = _fcp->get_c(); if (c == EOF) break; else if (invalid_input_char(c)) @@ -1459,13 +1459,12 @@ void do_for(char *var, double from, double to, int by_is_multiplicative, void do_copy(const char *filename) { - errno = 0; - FILE *fp = fopen(filename, "r"); - if (fp == 0) { + file_case *fcp = file_case::muxer(filename); + if (fcp == NULL) { lex_error("can't open `%1': %2", filename, strerror(errno)); return; } - input_stack::push(new file_input(fp, filename)); + input_stack::push(new file_input(fcp, filename)); } class copy_thru_input : public input { @@ -1651,32 +1650,32 @@ int copy_thru_input::get_line() class simple_file_input : public input { const char *filename; int lineno; - FILE *fp; + file_case *_fcp; public: - simple_file_input(FILE *, const char *); + simple_file_input(file_case *, const char *); ~simple_file_input(); int get(); int peek(); int get_location(const char **, int *); }; -simple_file_input::simple_file_input(FILE *p, const char *s) -: filename(s), lineno(1), fp(p) +simple_file_input::simple_file_input(file_case *fcp, const char *s) +: filename(s), lineno(1), _fcp(fcp) { } simple_file_input::~simple_file_input() { // don't delete the filename - fclose(fp); + delete _fcp; } int simple_file_input::get() { - int c = getc(fp); + int c = _fcp->get_c(); while (invalid_input_char(c)) { error("invalid input character code %1", c); - c = getc(fp); + c = _fcp->get_c(); } if (c == '\n') lineno++; @@ -1685,13 +1684,13 @@ int simple_file_input::get() int simple_file_input::peek() { - int c = getc(fp); + int c = _fcp->get_c(); while (invalid_input_char(c)) { error("invalid input character code %1", c); - c = getc(fp); + c = _fcp->get_c(); } if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); return c; } @@ -1705,13 +1704,12 @@ int simple_file_input::get_location(const char **fnp, int *lnp) void copy_file_thru(const char *filename, const char *body, const char *until) { - errno = 0; - FILE *fp = fopen(filename, "r"); - if (fp == 0) { + file_case *fcp = file_case::muxer(filename); + if (fcp == NULL) { lex_error("can't open `%1': %2", filename, strerror(errno)); return; } - input *in = new copy_file_thru_input(new simple_file_input(fp, filename), + input *in = new copy_file_thru_input(new simple_file_input(fcp, filename), body, until); input_stack::push(in); } diff --git a/src/preproc/pic/main.cpp b/src/preproc/pic/main.cpp index f242da0..8173c5e 100644 --- a/src/preproc/pic/main.cpp +++ b/src/preproc/pic/main.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001, 2002, 2003, 2006, 2009, 2012 +/* Copyright (C) 1989-1992, 2000, 2001, 2002, 2003, 2006, 2009, 2012, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -18,6 +18,8 @@ for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "file_case.h" + #include "pic.h" extern int yyparse(); @@ -43,19 +45,19 @@ static int had_parse_error = 0; void do_file(const char *filename); class top_input : public input { - FILE *fp; + file_case *_fcp; int bol; int eof; int push_back[3]; int start_lineno; public: - top_input(FILE *); + top_input(file_case *); int get(); int peek(); int get_location(const char **, int *); }; -top_input::top_input(FILE *p) : fp(p), bol(1), eof(0) +top_input::top_input(file_case *fcp) : _fcp(fcp), bol(1), eof(0) { push_back[0] = push_back[1] = push_back[2] = EOF; start_lineno = current_lineno; @@ -80,20 +82,20 @@ int top_input::get() push_back[0] = EOF; return c; } - int c = getc(fp); + int c = _fcp->get_c(); while (invalid_input_char(c)) { error("invalid input character code %1", int(c)); - c = getc(fp); + c = _fcp->get_c(); bol = 0; } if (bol && c == '.') { - c = getc(fp); + c = _fcp->get_c(); if (c == 'P') { - c = getc(fp); + c = _fcp->get_c(); if (c == 'F' || c == 'E') { - int d = getc(fp); + int d = _fcp->get_c(); if (d != EOF) - ungetc(d, fp); + _fcp->unget_c(d); if (d == EOF || d == ' ' || d == '\n' || compatible_flag) { eof = 1; flyback_flag = c == 'F'; @@ -104,9 +106,9 @@ int top_input::get() return '.'; } if (c == 'S') { - c = getc(fp); - if (c != EOF) - ungetc(c, fp); + c = _fcp->get_c(); + if (c != EOF) + _fcp->unget_c(c); if (c == EOF || c == ' ' || c == '\n' || compatible_flag) { error("nested .PS"); eof = 1; @@ -117,13 +119,13 @@ int top_input::get() return '.'; } if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); push_back[0] = 'P'; return '.'; } else { if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); return '.'; } } @@ -152,20 +154,20 @@ int top_input::peek() return push_back[1]; if (push_back[0] != EOF) return push_back[0]; - int c = getc(fp); + int c = _fcp->get_c(); while (invalid_input_char(c)) { error("invalid input character code %1", int(c)); - c = getc(fp); + c = _fcp->get_c(); bol = 0; } if (bol && c == '.') { - c = getc(fp); + c = _fcp->get_c(); if (c == 'P') { - c = getc(fp); + c = _fcp->get_c(); if (c == 'F' || c == 'E') { - int d = getc(fp); + int d = _fcp->get_c(); if (d != EOF) - ungetc(d, fp); + _fcp->unget_c(d); if (d == EOF || d == ' ' || d == '\n' || compatible_flag) { eof = 1; flyback_flag = c == 'F'; @@ -177,9 +179,9 @@ int top_input::peek() return '.'; } if (c == 'S') { - c = getc(fp); + c = _fcp->get_c(); if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); if (c == EOF || c == ' ' || c == '\n' || compatible_flag) { error("nested .PS"); eof = 1; @@ -191,20 +193,20 @@ int top_input::peek() return '.'; } if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); push_back[0] = 'P'; push_back[1] = '.'; return '.'; } else { if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); push_back[0] = '.'; return '.'; } } if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); if (c == '\n') return '\n'; return c; @@ -217,25 +219,25 @@ int top_input::get_location(const char **filenamep, int *linenop) return 1; } -void do_picture(FILE *fp) +void do_picture(file_case *fcp) { flyback_flag = 0; int c; a_delete graphname; graphname = strsave("graph"); // default picture name in TeX mode - while ((c = getc(fp)) == ' ') + while ((c = fcp->get_c()) == ' ') ; if (c == '<') { string filename; - while ((c = getc(fp)) == ' ') + while ((c = fcp->get_c()) == ' ') ; while (c != EOF && c != ' ' && c != '\n') { filename += char(c); - c = getc(fp); + c = fcp->get_c(); } if (c == ' ') { do { - c = getc(fp); + c = fcp->get_c(); } while (c != EOF && c != '\n'); } if (c == '\n') @@ -262,7 +264,7 @@ void do_picture(FILE *fp) break; } start_line += c; - c = getc(fp); + c = fcp->get_c(); } if (c == EOF) return; @@ -280,7 +282,7 @@ void do_picture(FILE *fp) } out->set_desired_width_height(wid, ht); out->set_args(start_line.contents()); - lex_init(new top_input(fp)); + lex_init(new top_input(fcp)); if (yyparse()) { had_parse_error = 1; lex_error("giving up on this picture"); @@ -289,7 +291,7 @@ void do_picture(FILE *fp) lex_cleanup(); // skip the rest of the .PF/.PE line - while ((c = getc(fp)) != EOF && c != '\n') + while ((c = fcp->get_c()) != EOF && c != '\n') ; if (c == '\n') current_lineno++; @@ -299,26 +301,24 @@ void do_picture(FILE *fp) void do_file(const char *filename) { - FILE *fp; + file_case *fcp; if (strcmp(filename, "-") == 0) - fp = stdin; - else { - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) { - delete out; - fatal("can't open `%1': %2", filename, strerror(errno)); - } + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); + else if ((fcp = file_case::muxer(filename)) == NULL) { + delete out; + fatal("can't open `%1': %2", filename, strerror(errno)); } + out->set_location(filename, 1); current_filename = filename; current_lineno = 1; enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START; for (;;) { - int c = getc(fp); + int c = fcp->get_c(); while (invalid_input_char(c)) { error("invalid input character code %1", int(c)); - c = getc(fp); + c = fcp->get_c(); } if (c == EOF) break; @@ -376,8 +376,8 @@ void do_file(const char *filename) break; case HAD_PS: if (c == ' ' || c == '\n' || compatible_flag) { - ungetc(c, fp); - do_picture(fp); + fcp->unget_c(c); + do_picture(fcp); state = START; } else { @@ -410,7 +410,7 @@ void do_file(const char *filename) current_lineno++; break; } - c = getc(fp); + c = fcp->get_c(); } line += '\0'; interpret_lf_args(line.contents()); @@ -449,28 +449,28 @@ void do_file(const char *filename) fputs(".lf\n", stdout); break; } - if (fp != stdin) - fclose(fp); + + delete fcp; } #ifdef FIG_SUPPORT void do_whole_file(const char *filename) { // Do not set current_filename. - FILE *fp; + file_case *fcp; if (strcmp(filename, "-") == 0) - fp = stdin; - else { - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) - fatal("can't open `%1': %2", filename, strerror(errno)); - } - lex_init(new file_input(fp, filename)); + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); + else if ((fcp = file_case::muxer(filename)) == NULL) + fatal("can't open `%1': %2", filename, strerror(errno)); + + lex_init(new file_input(fcp, filename)); if (yyparse()) had_parse_error = 1; parse_cleanup(); lex_cleanup(); + + delete fcp; } #endif diff --git a/src/preproc/pic/pic.h b/src/preproc/pic/pic.h index b32b7d6..1ca726f 100644 --- a/src/preproc/pic/pic.h +++ b/src/preproc/pic/pic.h @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003, 2005, 2009 +/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003, 2005, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -24,6 +24,8 @@ along with this program. If not, see . */ #include #include +#include "file_case.h" + #ifdef NEED_DECLARATION_RAND #undef rand extern "C" { @@ -78,14 +80,14 @@ public: }; class file_input : public input { - FILE *fp; + file_case *_fcp; const char *filename; int lineno; string line; const char *ptr; int read_line(); public: - file_input(FILE *, const char *); + file_input(file_case *, const char *); ~file_input(); int get(); int peek(); -- 2.0.0 From b62209ee131f879259575150b389a32a54f86565 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 23:39:34 +0200 Subject: [PATCH 16/20] Preproc: use file_case::muxer() for ARGV: preconv/ (Public Domain) --- src/preproc/preconv/preconv.cpp | 77 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/src/preproc/preconv/preconv.cpp b/src/preproc/preconv/preconv.cpp index d09fc1c..ed770c3 100644 --- a/src/preproc/preconv/preconv.cpp +++ b/src/preproc/preconv/preconv.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 2005, 2006, 2008, 2009 +/* Copyright (C) 2005, 2006, 2008, 2009, 2014 Free Software Foundation, Inc. Written by Werner Lemberg (address@hidden) @@ -25,6 +25,7 @@ along with this program. If not, see . */ #include #include "errarg.h" #include "error.h" +#include "file_case.h" #include "localcharset.h" #include "nonposix.h" #include "stringclass.h" @@ -419,14 +420,14 @@ unicode_entity(int u) // Conversion from ISO-8859-1 (aka Latin-1) to Unicode. void -conversion_latin1(FILE *fp, const string &data) +conversion_latin1(file_case *fcp, const string &data) { int len = data.length(); const unsigned char *ptr = (const unsigned char *)data.contents(); for (int i = 0; i < len; i++) unicode_entity(ptr[i]); int c = -1; - while ((c = getc(fp)) != EOF) + while ((c = fcp->get_c()) != EOF) unicode_entity(c); } @@ -435,7 +436,7 @@ conversion_latin1(FILE *fp, const string &data) // moved to the troff program. struct utf8 { - FILE *fp; + file_case *_fcp; unsigned char s[6]; enum { FIRST = 0, @@ -448,14 +449,14 @@ struct utf8 { int expected_bytes; int invalid_warning; int incomplete_warning; - utf8(FILE *); + utf8(file_case *); ~utf8(); void add(unsigned char); void invalid(); void incomplete(); }; -utf8::utf8(FILE *f) : fp(f), byte(FIRST), expected_bytes(1), +utf8::utf8(file_case *fcp) : _fcp(fcp), byte(FIRST), expected_bytes(1), invalid_warning(1), incomplete_warning(1) { // empty @@ -591,22 +592,22 @@ utf8::incomplete() // Conversion from UTF-8 to Unicode. void -conversion_utf8(FILE *fp, const string &data) +conversion_utf8(file_case *fcp, const string &data) { - utf8 u(fp); + utf8 u(fcp); int len = data.length(); const unsigned char *ptr = (const unsigned char *)data.contents(); for (int i = 0; i < len; i++) u.add(ptr[i]); int c = -1; - while ((c = getc(fp)) != EOF) + while ((c = fcp->get_c()) != EOF) u.add(c); return; } // Conversion from cp1047 (EBCDIC) to UTF-8. void -conversion_cp1047(FILE *fp, const string &data) +conversion_cp1047(file_case *fcp, const string &data) { static unsigned char cp1047[] = { 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, // 0x00 @@ -647,14 +648,14 @@ conversion_cp1047(FILE *fp, const string &data) for (int i = 0; i < len; i++) unicode_entity(cp1047[ptr[i]]); int c = -1; - while ((c = getc(fp)) != EOF) + while ((c = fcp->get_c()) != EOF) unicode_entity(cp1047[c]); } // Locale-sensible conversion. #if HAVE_ICONV void -conversion_iconv(FILE *fp, const string &data, char *enc) +conversion_iconv(file_case *fcp, const string &data, char *enc) { iconv_t handle = iconv_open(UNICODE, enc); if (handle == (iconv_t)-1) { @@ -701,7 +702,7 @@ conversion_iconv(FILE *fp, const string &data, char *enc) // Handle `fp' and switch to `inbuf'. size_t read_bytes; char *read_start = inbuf + inbytes_left; - while ((read_bytes = fread(read_start, 1, BUFSIZ - inbytes_left, fp)) > 0) { + while ((read_bytes = fcp->get_buf(read_start, BUFSIZ - inbytes_left)) > 0) { inptr = inbuf; inbytes_left += read_bytes; while (inbytes_left > 0) { @@ -756,7 +757,7 @@ conversion_iconv(FILE *fp, const string &data, char *enc) // Return encoding if a BOM is found, NULL otherwise. // --------------------------------------------------------- const char * -get_BOM(FILE *fp, string &BOM, string &data) +get_BOM(file_case *fcp, string &BOM, string &data) { // The BOM is U+FEFF. We have thus the following possible // representations. @@ -780,7 +781,7 @@ get_BOM(FILE *fp, string &BOM, string &data) const char *retval = NULL; int len; for (len = 0; len < 4; len++) { - int c = getc(fp); + int c = fcp->get_c(); if (c == EOF) break; BOM_string[len] = char(c); @@ -810,7 +811,7 @@ get_BOM(FILE *fp, string &BOM, string &data) // (which is stored unmodified in `data'). // --------------------------------------------------------- char * -get_tag_lines(FILE *fp, string &data) +get_tag_lines(file_case *fcp, string &data) { int newline_count = 0; int c, prev = -1; @@ -827,7 +828,7 @@ get_tag_lines(FILE *fp, string &data) return NULL; int emit_warning = 1; for (int lines = newline_count; lines < 2; lines++) { - while ((c = getc(fp)) != EOF) { + while ((c = fcp->get_c()) != EOF) { if (c == '\0' && debug_flag && emit_warning) { fprintf(stderr, " null byte(s) found in input stream --\n" @@ -840,9 +841,9 @@ get_tag_lines(FILE *fp, string &data) } // Handle CR, LF, and CRLF as line separators. if (c == '\r') { - c = getc(fp); + c = fcp->get_c(); if (c != EOF && c != '\n') - ungetc(c, fp); + fcp->unget_c(c); else data += char(c); } @@ -965,9 +966,9 @@ get_variable_value_pair(char *d1, char **variable, char **value) // XXX Add support for tag at the end of buffer. // --------------------------------------------------------- char * -check_coding_tag(FILE *fp, string &data) +check_coding_tag(file_case *fcp, string &data) { - char *inbuf = get_tag_lines(fp, data); + char *inbuf = get_tag_lines(fcp, data); char *lineend; for (char *p = inbuf; is_comment_line(p); p = lineend + 1) { if ((lineend = strchr(p, '\n')) == NULL) @@ -1005,24 +1006,22 @@ check_coding_tag(FILE *fp, string &data) int do_file(const char *filename) { - FILE *fp; + file_case *fcp; string BOM, data; + if (debug_flag) + fprintf(stderr, "file `%s':\n", filename); if (strcmp(filename, "-")) { - if (debug_flag) - fprintf(stderr, "file `%s':\n", filename); - fp = fopen(filename, FOPEN_RB); - if (!fp) { + if ((fcp = file_case::muxer(filename, fcp->mux_need_binary)) == NULL) { error("can't open `%1': %2", filename, strerror(errno)); return 0; } - } - else { - if (debug_flag) - fprintf(stderr, "standard input:\n"); + } else { SET_BINARY(fileno(stdin)); - fp = stdin; + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); } - const char *BOM_encoding = get_BOM(fp, BOM, data); + + const char *BOM_encoding = get_BOM(fcp, BOM, data); // Determine the encoding. char *encoding; if (user_encoding[0]) { @@ -1043,7 +1042,7 @@ do_file(const char *filename) } else { // `check_coding_tag' returns a pointer to a static array (or NULL). - char *file_encoding = check_coding_tag(fp, data); + char *file_encoding = check_coding_tag(fcp, data); if (!file_encoding) { if (debug_flag) fprintf(stderr, " no file encoding\n"); @@ -1071,21 +1070,21 @@ do_file(const char *filename) int success = 1; // Call converter (converters write to stdout). if (!strcasecmp(encoding, "ISO-8859-1")) - conversion_latin1(fp, BOM + data); + conversion_latin1(fcp, BOM + data); else if (!strcasecmp(encoding, "UTF-8")) - conversion_utf8(fp, data); + conversion_utf8(fcp, data); else if (!strcasecmp(encoding, "cp1047")) - conversion_cp1047(fp, BOM + data); + conversion_cp1047(fcp, BOM + data); else { #if HAVE_ICONV - conversion_iconv(fp, BOM + data, encoding); + conversion_iconv(fcp, BOM + data, encoding); #else error("encoding system `%1' not supported", encoding); success = 0; #endif /* HAVE_ICONV */ } - if (fp != stdin) - fclose(fp); + + delete fcp; return success; } -- 2.0.0 From 09565d1eca8b0bd5b2d9630d2e8e20463ff89b51 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sun, 27 Jul 2014 01:01:28 +0200 Subject: [PATCH 17/20] Preproc: use file_case::muxer() for ARGV: refer/ (Public Domain) --- src/preproc/refer/command.cpp | 32 ++++++++++++------------ src/preproc/refer/refer.cpp | 57 ++++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/preproc/refer/command.cpp b/src/preproc/refer/command.cpp index 33bc9c2..cd10c26 100644 --- a/src/preproc/refer/command.cpp +++ b/src/preproc/refer/command.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2004, 2006, 2009 +/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2004, 2006, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -21,6 +21,7 @@ along with this program. If not, see . */ #include "refer.h" #include "refid.h" #include "search.h" +#include "file_case.h" #include "command.h" cset cs_field_name = csalpha; @@ -147,35 +148,35 @@ int input_stack::peek_char() void input_stack::push_file(const char *fn) { - FILE *fp; + file_case *fcp; if (strcmp(fn, "-") == 0) { - fp = stdin; + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); fn = ""; - } - else { - errno = 0; - fp = fopen(fn, "r"); - if (fp == 0) { + } else { + fcp = file_case::muxer(fn); + if (fcp == NULL) { error("can't open `%1': %2", fn, strerror(errno)); return; } } + string buf; int bol = 1; int lineno = 1; for (;;) { - int c = getc(fp); + int c = fcp->get_c(); if (bol && c == '.') { // replace lines beginning with .R1 or .R2 with a blank line - c = getc(fp); + c = fcp->get_c(); if (c == 'R') { - c = getc(fp); + c = fcp->get_c(); if (c == '1' || c == '2') { int cc = c; - c = getc(fp); + c = fcp->get_c(); if (compatible_flag || c == ' ' || c == '\n' || c == EOF) { while (c != '\n' && c != EOF) - c = getc(fp); + c = fcp->get_c(); } else { buf += '.'; @@ -206,8 +207,9 @@ void input_stack::push_file(const char *fn) bol = 0; } } - if (fp != stdin) - fclose(fp); + + delete fcp; + if (buf.length() > 0 && buf[buf.length() - 1] != '\n') buf += '\n'; input_item *it = new input_item(buf, fn); diff --git a/src/preproc/refer/refer.cpp b/src/preproc/refer/refer.cpp index 292d0e7..2395bb8 100644 --- a/src/preproc/refer/refer.cpp +++ b/src/preproc/refer/refer.cpp @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001, 2002, 2004, 2006, 2009 +/* Copyright (C) 1989-1992, 2000, 2001, 2002, 2004, 2006, 2009, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -23,6 +23,7 @@ along with this program. If not, see . */ #include "ref.h" #include "token.h" #include "search.h" +#include "file_case.h" #include "command.h" extern "C" const char *Version_string; @@ -421,18 +422,13 @@ static int is_list(const string &str) static void do_file(const char *filename) { - FILE *fp; - if (strcmp(filename, "-") == 0) { - fp = stdin; - } - else { - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) { - error("can't open `%1': %2", filename, strerror(errno)); - return; - } + file_case *fcp; + if ((fcp = file_case::muxer(filename)) == NULL) { + assert(strcmp(filename, "-")); + error("can't open `%1': %2", filename, strerror(errno)); + return; } + current_filename = filename; fprintf(outfp, ".lf 1 %s\n", filename); string line; @@ -440,7 +436,7 @@ static void do_file(const char *filename) for (;;) { line.clear(); for (;;) { - int c = getc(fp); + int c = fcp->get_c(); if (c == EOF) { if (line.length() > 0) line += '\n'; @@ -465,7 +461,7 @@ static void do_file(const char *filename) string post; string pre(line.contents() + 2, line.length() - 3); for (;;) { - int c = getc(fp); + int c = fcp->get_c(); if (c == EOF) { error_with_file_and_line(current_filename, start_lineno, "missing `.]' line"); @@ -474,9 +470,9 @@ static void do_file(const char *filename) if (start_of_line) current_lineno++; if (start_of_line && c == '.') { - int d = getc(fp); + int d = fcp->get_c(); if (d == ']') { - while ((d = getc(fp)) != '\n' && d != EOF) { + while ((d = fcp->get_c()) != '\n' && d != EOF) { if (invalid_input_char(d)) error("invalid input character code %1", d); else @@ -485,7 +481,7 @@ static void do_file(const char *filename) break; } if (d != EOF) - ungetc(d, fp); + fcp->unget_c(d); } if (invalid_input_char(c)) error("invalid input character code %1", c); @@ -548,21 +544,20 @@ static void do_file(const char *filename) int start_of_line = 1; int start_lineno = current_lineno; for (;;) { - int c = getc(fp); + int c = fcp->get_c(); if (c != EOF && start_of_line) current_lineno++; if (start_of_line && c == '.') { - c = getc(fp); - if (c == 'R') { - c = getc(fp); - if (c == '2') { - c = getc(fp); - if (compatible_flag || c == ' ' || c == '\n' || c == EOF) { - while (c != EOF && c != '\n') - c = getc(fp); - break; - } - else { + c = fcp->get_c(); + if (c == 'R') { + c = fcp->get_c(); + if (c == '2') { + c = fcp->get_c(); + if (compatible_flag || c == ' ' || c == '\n' || c == EOF) { + while (c != EOF && c != '\n') + c = fcp->get_c(); + break; + } else { line += '.'; line += 'R'; line += '2'; @@ -603,8 +598,8 @@ static void do_file(const char *filename) } need_syncing = 0; output_pending_line(); - if (fp != stdin) - fclose(fp); + + delete fcp; } class label_processing_state { -- 2.0.0 From 69ea78919fbe3141022b1891ef89d056a11bd462 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sat, 26 Jul 2014 22:04:57 +0200 Subject: [PATCH 18/20] Preproc: use file_case::muxer() for ARGV: tbl/ (Public Domain) --- src/preproc/tbl/main.cpp | 100 ++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/src/preproc/tbl/main.cpp b/src/preproc/tbl/main.cpp index 8732db9..38195de 100644 --- a/src/preproc/tbl/main.cpp +++ b/src/preproc/tbl/main.cpp @@ -1,6 +1,6 @@ // -*- C++ -*- /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005, - 2007, 2008, 2009, 2010 + 2007, 2008, 2009, 2010, 2014 Free Software Foundation, Inc. Written by James Clark (address@hidden) @@ -19,6 +19,8 @@ for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "file_case.h" + #include "table.h" #define MAX_POINT_SIZE 99 @@ -29,21 +31,21 @@ extern "C" const char *Version_string; int compatible_flag = 0; class table_input { - FILE *fp; + file_case *_fcp; enum { START, MIDDLE, REREAD_T, REREAD_TE, REREAD_E, LEADER_1, LEADER_2, LEADER_3, LEADER_4, END, ERROR } state; string unget_stack; public: - table_input(FILE *); + table_input(file_case *); int get(); int ended() { return unget_stack.empty() && state == END; } void unget(char); }; -table_input::table_input(FILE *p) -: fp(p), state(START) +table_input::table_input(file_case *fcp) +: _fcp(fcp), state(START) { } @@ -69,17 +71,17 @@ int table_input::get() for (;;) { switch (state) { case START: - if ((c = getc(fp)) == '.') { - if ((c = getc(fp)) == 'T') { - if ((c = getc(fp)) == 'E') { + if ((c = _fcp->get_c()) == '.') { + if ((c = _fcp->get_c()) == 'T') { + if ((c = _fcp->get_c()) == 'E') { if (compatible_flag) { state = END; return EOF; } else { - c = getc(fp); + c = _fcp->get_c(); if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); if (c == EOF || c == ' ' || c == '\n') { state = END; return EOF; @@ -90,14 +92,14 @@ int table_input::get() } else { if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); state = REREAD_T; return '.'; } } else { if (c != EOF) - ungetc(c, fp); + _fcp->unget_c(c); state = MIDDLE; return '.'; } @@ -121,18 +123,18 @@ int table_input::get() break; case MIDDLE: // handle line continuation and uninterpreted leader character - if ((c = getc(fp)) == '\\') { - c = getc(fp); - if (c == '\n') - c = getc(fp); // perhaps state ought to be START now + if ((c = _fcp->get_c()) == '\\') { + c = _fcp->get_c(); + if (c == '\n') + c = _fcp->get_c(); // perhaps state ought to be START now else if (c == 'a' && compatible_flag) { state = LEADER_1; return '\\'; } else { - if (c != EOF) - ungetc(c, fp); - c = '\\'; + if (c != EOF) + _fcp->unget_c(c); + c = '\\'; } } if (c == EOF) { @@ -178,15 +180,15 @@ int table_input::get() } } -void process_input_file(FILE *); +void process_input_file(file_case *); void process_table(table_input &in); -void process_input_file(FILE *fp) +void process_input_file(file_case *fcp) { enum { START, MIDDLE, HAD_DOT, HAD_T, HAD_TS, HAD_l, HAD_lf } state; state = START; int c; - while ((c = getc(fp)) != EOF) + while ((c = fcp->get_c()) != EOF) switch (state) { case START: if (c == '.') @@ -248,17 +250,17 @@ void process_input_file(FILE *fp) return; } putchar(c); - c = getc(fp); + c = fcp->get_c(); } putchar('\n'); current_lineno++; { - table_input input(fp); + table_input input(fcp); process_table(input); set_troff_location(current_filename, current_lineno); if (input.ended()) { fputs(".TE", stdout); - while ((c = getc(fp)) != '\n') { + while ((c = fcp->get_c()) != '\n') { if (c == EOF) { putchar('\n'); return; @@ -301,7 +303,7 @@ void process_input_file(FILE *fp) current_lineno++; break; } - c = getc(fp); + c = fcp->get_c(); } line += '\0'; interpret_lf_args(line.contents()); @@ -339,8 +341,6 @@ void process_input_file(FILE *fp) fputs(".TS\n", stdout); break; } - if (fp != stdin) - fclose(fp); } struct options { @@ -1602,33 +1602,27 @@ int main(int argc, char **argv) printf(".if !\\n(.g .ab GNU tbl requires GNU troff.\n" ".if !dTS .ds TS\n" ".if !dTE .ds TE\n"); - if (argc > optind) { - for (int i = optind; i < argc; i++) - if (argv[i][0] == '-' && argv[i][1] == '\0') { - current_filename = "-"; - current_lineno = 1; - printf(".lf 1 -\n"); - process_input_file(stdin); - } - else { - errno = 0; - FILE *fp = fopen(argv[i], "r"); - if (fp == 0) - fatal("can't open `%1': %2", argv[i], strerror(errno)); - else { - current_lineno = 1; - current_filename = argv[i]; - printf(".lf 1 %s\n", current_filename); - process_input_file(fp); - } - } - } - else { - current_filename = "-"; + + file_case *fcp; + int i = optind; + if (i >= argc) + goto jstdin; + for (; i < argc; ++i) { + if (!strcmp(argv[i], "-")) { +jstdin: + fcp = new file_case(stdin, "stdin", + fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); + current_filename = "-"; + } else if ((fcp = file_case::muxer(current_filename = argv[i])) == NULL) + fatal("can't open `%1': %2", argv[i], strerror(errno)); + current_lineno = 1; - printf(".lf 1 -\n"); - process_input_file(stdin); + printf(".lf 1 %s\n", current_filename); + process_input_file(fcp); + + delete fcp; } + if (ferror(stdout) || fflush(stdout) < 0) fatal("output error"); return 0; -- 2.0.0 From a3daa945f1c9bc7ad7e7762f0122440000820e62 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sun, 27 Jul 2014 00:14:32 +0200 Subject: [PATCH 19/20] file_case: add support for "-" a.k.a. stdin (Public Domain) --- src/include/file_case.h | 4 +++- src/libs/libgroff/file_case.cpp | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/include/file_case.h b/src/include/file_case.h index 07f21d7..ab64e2e 100644 --- a/src/include/file_case.h +++ b/src/include/file_case.h @@ -51,6 +51,7 @@ public: mux_unpack = 1<<(_fc_freebit+2), // Do auto-check for FILE{.gz,.bz2..} mux_no_unpack = 1<<(_fc_freebit+3), // Do NOT auto-check mux_need_stdio = 1<<(_fc_freebit+4), // Only then may .file() be used + _mux_freebit = _fc_freebit + 5, mux_mask = ~fc_mask, mux_default = fc_none, // Defines the global default strategy for dealing with packed files in case @@ -81,7 +82,8 @@ public: int seek(long offset, seek_whence whence=seek_set); // Factory muxer; note that fc_take_path will be honoured even on failure - static file_case * muxer(char const *path, uint32_t flags=mux_default); + // If path is NULL or "-" we'll go for stdin + static file_case * muxer(char const *path=NULL, uint32_t flags=mux_default); CLASS_DISABLE_COPY(file_case); }; diff --git a/src/libs/libgroff/file_case.cpp b/src/libs/libgroff/file_case.cpp index f47c4f2..0b85a79 100644 --- a/src/libs/libgroff/file_case.cpp +++ b/src/libs/libgroff/file_case.cpp @@ -396,13 +396,19 @@ file_case::seek(long offset, seek_whence whence) /*static*/ file_case * file_case::muxer(char const *path, uint32_t flags) { + enum {tmpbit = 1<<(_mux_freebit+0)}; + assert(!(flags & (fc_dont_close | fc_pipe))); assert(!(flags & (fc_const_path | fc_take_path)) || !(flags & fc_const_path) != !(flags & fc_take_path)); assert(!(flags & (mux_unpack | mux_no_unpack)) || !(flags & mux_unpack) != !(flags & mux_no_unpack)); - if (!(flags & (fc_const_path | fc_take_path))) { + if (path == NULL || (path[0] == '-' && path[1] == '\0')) { + path = "-"; + flags &= ~fc_take_path; + flags |= fc_const_path | tmpbit; + } else if (!(flags & (fc_const_path | fc_take_path))) { path = strsave(path); flags |= fc_take_path; } @@ -418,6 +424,16 @@ file_case::muxer(char const *path, uint32_t flags) a.a_flags = flags; a.a_errno = 0; + // Shorthand: support "-" to mean stdin + if (flags & tmpbit) { + clearerr(stdin); + if (flags & mux_need_binary) + SET_BINARY(fileno(stdin)); + a.a_fp = stdin; + a.a_flags |= fc_dont_close | fc_const_path | fc_have_stdio; + goto jnew; + } + // If we support unpacking then check wether the path already includes // a packer's extension, i.e., explicitly. Anyway unpack then, despite flags #ifdef HAVE_UNPACK @@ -433,12 +449,10 @@ file_case::muxer(char const *path, uint32_t flags) errno = 0; if ((a.a_fp = fopen(a.a_path, a.a_mode)) != NULL) { a.a_flags |= fc_have_stdio; -#ifdef HAVE_UNPACK jnew: -#endif assert((a.a_fp != NULL && a.a_layer == NULL) || (a.a_fp == NULL && a.a_layer != NULL)); - fcp = new file_case(a.a_fp, path, a.a_flags & ~mux_mask); // XXX real path? + fcp = new file_case(a.a_fp, path, a.a_flags & fc_mask); // XXX real path? fcp->_layer = a.a_layer; goto jleave; } -- 2.0.0 From 66f424fcf8ec2929112e74bd7d415847547c14be Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Steffen Nurpmeso Date: Sun, 27 Jul 2014 00:20:27 +0200 Subject: [PATCH 20/20] Many: use stdin support of file_case::muxer() (Public Domain) --- src/libs/libgroff/searchpath.cpp | 13 +++++-------- src/preproc/eqn/main.cpp | 27 +++++++++++---------------- src/preproc/grn/main.cpp | 10 ++++------ src/preproc/html/pre-html.cpp | 14 +++++--------- src/preproc/pic/main.cpp | 13 +++++-------- src/preproc/preconv/preconv.cpp | 17 ++++++----------- src/preproc/refer/command.cpp | 18 +++++++----------- src/preproc/tbl/main.cpp | 17 ++++++----------- src/roff/troff/input.cpp | 10 +++------- 9 files changed, 52 insertions(+), 87 deletions(-) diff --git a/src/libs/libgroff/searchpath.cpp b/src/libs/libgroff/searchpath.cpp index 4a0561d..d84b1f7 100644 --- a/src/libs/libgroff/searchpath.cpp +++ b/src/libs/libgroff/searchpath.cpp @@ -153,16 +153,13 @@ file_case *search_path::open_file(char const *name, uint32_t flags) file_case *search_path::open_file_cautious(char const *name, uint32_t flags) { - assert(name != NULL); - file_case *fcp; if (name == NULL || strcmp(name, "-") == 0) { - flags &= ~(fcp->fc_take_path); - flags |= fcp->fc_dont_close | fcp->fc_const_path | fcp->fc_have_stdio; - if (flags & fcp->mux_need_binary) - SET_BINARY(fileno(stdin)); - fcp = new file_case(stdin, "stdin", flags); - } else if (IS_ABSOLUTE(name) || *dirs == '\0') + name = NULL; + goto jmuxer; + } + if (IS_ABSOLUTE(name) || *dirs == '\0') +jmuxer: fcp = file_case::muxer(name, flags); else fcp = _try_iter(dirs, name, flags); diff --git a/src/preproc/eqn/main.cpp b/src/preproc/eqn/main.cpp index b2a3ba1..12b22a6 100644 --- a/src/preproc/eqn/main.cpp +++ b/src/preproc/eqn/main.cpp @@ -399,23 +399,18 @@ int main(int argc, char **argv) delete fcp; } } - int i = optind; - if (i >= argc) - goto jstdin; - for (; i < argc; ++i) { - if (!strcmp(argv[i], "-")) { -jstdin: - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); - do_file(fcp, "-"); - } else { - fcp = file_case::muxer(argv[i]); - if (fcp == NULL) - fatal("can't open `%1': %2", argv[i], strerror(errno)); - do_file(fcp, argv[i]); - } + + do /*while (optind < argc)*/ { + char const *name = argv[optind++]; + fcp = file_case::muxer(name); + if (name == NULL) + name = "-"; + if (fcp == NULL) + fatal("can't open `%1': %2", name, strerror(errno)); + do_file(fcp, name); delete fcp; - } + } while (optind < argc); + if (ferror(stdout) || fflush(stdout) < 0) fatal("output error"); return 0; diff --git a/src/preproc/grn/main.cpp b/src/preproc/grn/main.cpp index f5e3b8a..c61642f 100644 --- a/src/preproc/grn/main.cpp +++ b/src/preproc/grn/main.cpp @@ -354,12 +354,10 @@ main(int argc, for (k = 0; k < gfil; k++) { file_case *fcp; - if (file[k] != NULL) { - if ((fcp = file_case::muxer(file[k])) == NULL) - fatal("can't open %1", file[k]); - } else - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); + if ((fcp = file_case::muxer(file[k])) == NULL) { + assert(file[k] != NULL); + fatal("can't open %1", file[k]); + } while (doinput(fcp)) { if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') { diff --git a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp index d5a5e49..f4482a6 100644 --- a/src/preproc/html/pre-html.cpp +++ b/src/preproc/html/pre-html.cpp @@ -1815,15 +1815,11 @@ static int do_file(const char *filename) file_case *fcp; current_filename = filename; - if (strcmp(filename, "-") == 0) - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); - else { - fcp = file_case::muxer(filename); - if (fcp == NULL) { - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } + fcp = file_case::muxer(filename); + if (fcp == NULL) { + assert(strcmp(filename, "-")); + error("can't open `%1': %2", filename, strerror(errno)); + return 0; } if (inputFile.read_file(fcp)) { diff --git a/src/preproc/pic/main.cpp b/src/preproc/pic/main.cpp index 8173c5e..988744e 100644 --- a/src/preproc/pic/main.cpp +++ b/src/preproc/pic/main.cpp @@ -302,10 +302,8 @@ void do_picture(file_case *fcp) void do_file(const char *filename) { file_case *fcp; - if (strcmp(filename, "-") == 0) - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); - else if ((fcp = file_case::muxer(filename)) == NULL) { + if ((fcp = file_case::muxer(filename)) == NULL) { + assert(strcmp(filename, "-")); delete out; fatal("can't open `%1': %2", filename, strerror(errno)); } @@ -458,11 +456,10 @@ void do_whole_file(const char *filename) { // Do not set current_filename. file_case *fcp; - if (strcmp(filename, "-") == 0) - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); - else if ((fcp = file_case::muxer(filename)) == NULL) + if ((fcp = file_case::muxer(filename)) == NULL) { + assert(strcmp(filename, "-")); fatal("can't open `%1': %2", filename, strerror(errno)); + } lex_init(new file_input(fcp, filename)); if (yyparse()) diff --git a/src/preproc/preconv/preconv.cpp b/src/preproc/preconv/preconv.cpp index ed770c3..c087af0 100644 --- a/src/preproc/preconv/preconv.cpp +++ b/src/preproc/preconv/preconv.cpp @@ -1006,21 +1006,16 @@ check_coding_tag(file_case *fcp, string &data) int do_file(const char *filename) { - file_case *fcp; - string BOM, data; if (debug_flag) fprintf(stderr, "file `%s':\n", filename); - if (strcmp(filename, "-")) { - if ((fcp = file_case::muxer(filename, fcp->mux_need_binary)) == NULL) { - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } - } else { - SET_BINARY(fileno(stdin)); - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); + file_case *fcp; + if ((fcp = file_case::muxer(filename, fcp->mux_need_binary)) == NULL) { + assert(strcmp(filename, "-")); + error("can't open `%1': %2", filename, strerror(errno)); + return 0; } + string BOM, data; const char *BOM_encoding = get_BOM(fcp, BOM, data); // Determine the encoding. char *encoding; diff --git a/src/preproc/refer/command.cpp b/src/preproc/refer/command.cpp index cd10c26..ba52a57 100644 --- a/src/preproc/refer/command.cpp +++ b/src/preproc/refer/command.cpp @@ -148,18 +148,14 @@ int input_stack::peek_char() void input_stack::push_file(const char *fn) { - file_case *fcp; - if (strcmp(fn, "-") == 0) { - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); - fn = ""; - } else { - fcp = file_case::muxer(fn); - if (fcp == NULL) { - error("can't open `%1': %2", fn, strerror(errno)); - return; - } + file_case *fcp = file_case::muxer(fn); + if (fcp == NULL) { + assert(strcmp(fn, "-")); + error("can't open `%1': %2", fn, strerror(errno)); + return; } + if (fn[0] == '-' && fn[1] == '\0') + fn = ""; string buf; int bol = 1; diff --git a/src/preproc/tbl/main.cpp b/src/preproc/tbl/main.cpp index 38195de..345f266 100644 --- a/src/preproc/tbl/main.cpp +++ b/src/preproc/tbl/main.cpp @@ -1604,24 +1604,19 @@ int main(int argc, char **argv) ".if !dTE .ds TE\n"); file_case *fcp; - int i = optind; - if (i >= argc) - goto jstdin; - for (; i < argc; ++i) { - if (!strcmp(argv[i], "-")) { -jstdin: - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path /*| fcp->fc_have_stdio*/); + do /*while (optind < argc)*/ { + if ((current_filename = argv[optind++]) == NULL) current_filename = "-"; - } else if ((fcp = file_case::muxer(current_filename = argv[i])) == NULL) - fatal("can't open `%1': %2", argv[i], strerror(errno)); + fcp = file_case::muxer(current_filename); + if (fcp == NULL) + fatal("can't open `%1': %2", current_filename, strerror(errno)); current_lineno = 1; printf(".lf 1 %s\n", current_filename); process_input_file(fcp); delete fcp; - } + } while (optind < argc); if (ferror(stdout) || fflush(stdout) < 0) fatal("output error"); diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp index e914413..16ca390 100644 --- a/src/roff/troff/input.cpp +++ b/src/roff/troff/input.cpp @@ -7503,13 +7503,9 @@ void macro_source() static void process_input_file(const char *name) { file_case *fcp; - if (strcmp(name, "-") == 0) { - clearerr(stdin); - fcp = new file_case(stdin, "stdin", - fcp->fc_dont_close | fcp->fc_const_path); - } else { - if ((fcp = include_search_path.open_file_cautious(name)) == NULL) - fatal("can't open `%1': %2", name, strerror(errno)); + if ((fcp = include_search_path.open_file_cautious(name)) == NULL) { + assert(strcmp(name, "-")); + fatal("can't open `%1': %2", name, strerror(errno)); } input_stack::push(new file_iterator(fcp, name)); tok.next(); -- 2.0.0