summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorwlemb <wlemb>2002-02-11 10:45:48 +0000
committerwlemb <wlemb>2002-02-11 10:45:48 +0000
commitd68f82e908248fd7dcb7726ee9393f6b87299dae (patch)
tree197725372d2c48ee3c5c45c758e0b83eac03a4a3 /src
parent6751b7b886769f82724f2bec16479abf73d7523f (diff)
downloadgroff-d68f82e908248fd7dcb7726ee9393f6b87299dae.tar.gz
* src/libs/snprintf/snprintf.c: Updated to latest version
(2002-02-11). * src/roff/grog/grog.pl (process): Fix handling of `.['. We now test whether there is `.]' also. Don't check for spaces after `.['. * src/roff/grog/grog.sh: Do the same. * NEWS: Updated. * src/preproc/grn/hdb.cc (DBRead): Fix fscanf() fields.
Diffstat (limited to 'src')
-rw-r--r--src/libs/snprintf/snprintf.c236
-rw-r--r--src/preproc/grn/hdb.cc4
-rw-r--r--src/roff/grog/grog.pl12
-rw-r--r--src/roff/grog/grog.sh9
4 files changed, 178 insertions, 83 deletions
diff --git a/src/libs/snprintf/snprintf.c b/src/libs/snprintf/snprintf.c
index b12038b3..fc245f14 100644
--- a/src/libs/snprintf/snprintf.c
+++ b/src/libs/snprintf/snprintf.c
@@ -4,7 +4,7 @@
* AUTHOR
* Mark Martinec <mark.martinec@ijs.si>, April 1999.
*
- * Copyright 1999,2000,2001 Mark Martinec. All rights reserved.
+ * Copyright 1999-2002 Mark Martinec. All rights reserved.
*
* TERMS AND CONDITIONS
* This program is free software; it is dual licensed, the terms of the
@@ -30,7 +30,9 @@
* optimizations turned on, tell the compiler the code is strict ANSI
* if necessary to give it more freedom for optimizations);
* - return value semantics per ISO/IEC 9899:1999 ("ISO C99");
- * - written in standard ISO/ANSI C - requires an ANSI C compiler.
+ * - written in standard ISO/ANSI C - requires an ANSI C compiler;
+ * - works also with non-ASCII 8-bit character sets (e.g. EBCDIC)
+ * provided strings are '\0'-terminated.
*
* SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES
*
@@ -184,16 +186,27 @@
* - several comments rephrased and new ones added;
* - make compiler not complain about 'credits' defined but
* not used;
- * 2001-08-16 V2.3 Mark Martinec <mark.martinec@ijs.si>
+ * 2001-08 V2.3 Mark Martinec <mark.martinec@ijs.si>
+ * .. 2002-02 - writeback conversion specifier 'n' is now supported;
* - bump the size of a temporary buffer for simple
* numeric->string conversion from 32 to 48 characters
* in anticipation of 128-bit machines;
+ * - added #include <stddef.h> and <stdarg.h> to snprintf.h;
+ * - fixed one assert in test.c
+ * (thanks to Tuomo A Turunen for reporting this problem);
+ * - portability fix: use isdigit() provided with <ctype.h>
+ * and do not assume character set is ASCII - call strtoul()
+ * if needed to convert field width and precision;
+ * - check for broken or non-ANSI native sprintf (e.g. SunOS)
+ * which does not return string lenth, and work around it;
* - shouldn't happen, but just in case (applies to numeric
* conversions only): added assertion after a call to
* system's sprintf to make sure we detect a problem
- * as it happens (of very shortly after a buffer overflow
- * occured for some strange reason in system's sprintf,
- * but still);
+ * as it happens (or very shortly - but still - after a
+ * buffer overflow occured for some strange reason
+ * in system's sprintf);
+ * - cleanup: avoid comparing signed and unsigned values
+ * (ANSI c++ complaint); added a couple of 'const' qualifiers;
* - changed few comments, new references to some other
* implementations added to the README file;
* - it appears the Artistic License and its variant the Frontier
@@ -201,7 +214,7 @@
* this work to be included with GPL-licensed work. This was
* not my intention. The fact that this package is dual licensed
* comes to the rescue. Changed the credits[] string, and
- * TERMS AND CONDITIONS to explicitly say so and stress
+ * TERMS AND CONDITIONS to explicitly say so, stressing
* the fact that this work is dual licensed.
*/
@@ -259,14 +272,14 @@
* I don't know of any other standard and portable way of achieving the same.
* With some versions of gcc you may use __va_copy(). You might even get away
* with "ap2 = ap", in this case you must not call va_end(ap2) !
- * #define va_copy(ap2,ap) ap2 = ap
+ * #define va_copy(ap2,ap) __va_copy((ap2),(ap))
+ * #define va_copy(ap2,ap) (ap2) = (ap)
*/
/* #define NEED_ASPRINTF */
/* #define NEED_ASNPRINTF */
/* #define NEED_VASPRINTF */
/* #define NEED_VASNPRINTF */
-
/* Define the following macros if desired:
* SOLARIS_COMPATIBLE, SOLARIS_BUG_COMPATIBLE,
* HPUX_COMPATIBLE, HPUX_BUG_COMPATIBLE, LINUX_COMPATIBLE,
@@ -338,6 +351,7 @@
#endif
#include <sys/types.h>
+#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -345,11 +359,6 @@
#include <assert.h>
#include <errno.h>
-#ifdef isdigit
-#undef isdigit
-#endif
-#define isdigit(c) ((c) >= '0' && (c) <= '9')
-
/* For copying strings longer or equal to 'breakeven_point'
* it is more efficient to call memcpy() than to do it inline.
* The value depends mostly on the processor architecture,
@@ -362,10 +371,10 @@
* large values favour inline code (saves procedure call, more code).
*/
#if defined(__alpha__) || defined(__alpha)
-# define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc or egcs */
+# define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc */
#endif
#if defined(__i386__) || defined(__i386)
-# define breakeven_point 12 /* Intel Pentium/Linux - gcc 2.96 */
+# define breakeven_point 15 /* Intel Pentium/Linux - gcc 2.96 (12..30) */
#endif
#if defined(__hppa)
# define breakeven_point 10 /* HP-PA - gcc */
@@ -375,8 +384,8 @@
#endif
/* some other values of possible interest: */
-/* #define breakeven_point 8 */ /* VAX 4000 - vaxc */
-/* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */
+/* #define breakeven_point 8 */ /* VAX 4000 - vaxc */
+/* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */
#ifndef breakeven_point
# define breakeven_point 6 /* some reasonable one-size-fits-all value */
@@ -385,17 +394,58 @@
#define fast_memcpy(d,s,n) \
{ register size_t nn = (size_t)(n); \
if (nn >= breakeven_point) memcpy((d), (s), nn); \
- else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
+ else if (nn > 0) { /* call overhead is worth only for large strings*/ \
register char *dd; register const char *ss; \
for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
#define fast_memset(d,c,n) \
{ register size_t nn = (size_t)(n); \
if (nn >= breakeven_point) memset((d), (int)(c), nn); \
- else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
+ else if (nn > 0) { /* call overhead is worth only for large strings*/ \
register char *dd; register const int cc=(int)(c); \
for (dd=(d); nn>0; nn--) *dd++ = cc; } }
+/* The following isdigit() is not portable (e.g. may not work
+ * with non-ASCII character sets). Use the system-provided isdigit()
+ * if available, otherwise uncomment:
+ * #define isdigit(c) ((c) >= '0' && (c) <= '9')
+ */
+
+/* atosizet converts a span of decimal digits to a number of type size_t.
+ * It is a macro, similar to: (but not quite, p will be modified!)
+ * void atosizet(const char *p, const char **endp, size_t *result);
+ * endp will point to just beyond the digits substring.
+ * This is _not_ a general-purpose macro:
+ * - the first argument will be modified;
+ * - the first character must already be checked to be a digit!
+ * NOTE: size_t could be wider than unsigned int;
+ * but we treat numeric string like common implementations do!
+ * If character set is ASCII (checking with a quick and simple-minded test)
+ * we convert string to a number inline for speed, otherwise we call strtoul.
+ */
+#define atosizet(p, endp, result) \
+ if ((int)'0' == 48) { /* a compile-time constant expression, */ \
+ /* hoping the code from one branch */ \
+ /* will be optimized away */ \
+ /* looks like ASCII character set, let's hope it really is */ \
+ register unsigned int uj = (unsigned int)(*(p)++ - '0'); \
+ while (isdigit((int)(*(p)))) \
+ uj = 10*uj + (unsigned int)(*(p)++ - '0'); \
+ if ((endp) != NULL) *(endp) = (p); \
+ *(result) = (size_t) uj; \
+ } else { \
+ /* non-ASCII character set, play by the rules */ \
+ char *ep; /* NOTE: no 'const' to make strtoul happy! */ \
+ /* NOTE: clip (unsigned long) to (unsigned int) as is common !!! */ \
+ const unsigned int uj = (unsigned int) strtoul((p), &ep, 10); \
+ /* The following assignment is legal: the address of a non-const */ \
+ /* object can be assigned to a pointer to a const object, but */ \
+ /* that pointer cannot be used to alter the value of the object. */ \
+ if ((endp) != NULL) *(endp) = ep; \
+ /* if num too large the result will be ULONG_MAX and errno=ERANGE */ \
+ *(result) = (size_t) uj; \
+ } \
+
/* prototypes */
#if defined(NEED_ASPRINTF)
@@ -431,9 +481,9 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
/* declarations */
-static char credits[] = "\n\
+static const char credits[] = "\n\
@(#)snprintf.c, v2.3: Mark Martinec, <mark.martinec@ijs.si>\n\
-@(#)snprintf.c, v2.3: Copyright 1999,2000,2001 Mark Martinec. Dual licensed: Frontier Artistic License or GNU General Public License applies.\n\
+@(#)snprintf.c, v2.3: Copyright 1999-2002 Mark Martinec. Dual licensed: Frontier Artistic License or GNU General Public License applies.\n\
@(#)snprintf.c, v2.3: http://www.ijs.si/software/snprintf/\n";
#if defined(NEED_ASPRINTF)
@@ -475,7 +525,7 @@ int vasprintf(char **ptr, const char *fmt, va_list ap) {
*ptr = (char *) malloc(str_m = (size_t)str_l + 1);
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
else {
- int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
+ const int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
assert(str_l2 == str_l);
}
return str_l;
@@ -483,7 +533,7 @@ int vasprintf(char **ptr, const char *fmt, va_list ap) {
#endif
#if defined(NEED_ASNPRINTF)
-int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
+int asnprintf(char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
va_list ap;
int str_l;
@@ -511,7 +561,7 @@ int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
#endif
#if defined(NEED_VASNPRINTF)
-int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
+int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap) {
int str_l;
*ptr = NULL;
@@ -528,7 +578,7 @@ int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
*ptr = (char *) malloc(str_m);
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
else {
- int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
+ const int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
assert(str_l2 == str_l);
}
}
@@ -576,16 +626,21 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
if (!p) p = "";
while (*p) {
if (*p != '%') {
- /* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */
- /* but the following code achieves better performance for cases
- * where format string is long and contains few conversions */
- const char *q = strchr(p+1,'%');
- size_t n = !q ? strlen(p) : (q-p);
- if (str_l < str_m) {
- size_t avail = str_m-str_l;
- fast_memcpy(str+str_l, p, (n>avail?avail:n));
+ if (0) { /* compile time decision between two equivalent alternatives */
+ /* this is simple but slow */
+ if (str_l < str_m) str[str_l] = *p;
+ p++; str_l++;
+ } else {
+ /* this usually achieves much better performance for cases
+ * where format string is long and contains few conversions */
+ const char *const q = strchr(p+1,'%');
+ const size_t n = !q ? strlen(p) : (q-p);
+ if (str_l < str_m) {
+ const size_t avail = str_m-str_l;
+ fast_memcpy(str+str_l, p, (n>avail?avail:n));
+ }
+ p += n; str_l += n;
}
- p += n; str_l += n;
} else {
const char *starting_p;
size_t min_field_width = 0, precision = 0;
@@ -640,22 +695,18 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
/* parse field width */
if (*p == '*') {
- int j;
- p++; j = va_arg(ap, int);
+ const int j = va_arg(ap, int);
+ p++;
if (j >= 0) min_field_width = j;
else { min_field_width = -j; justify_left = 1; }
} else if (isdigit((int)(*p))) {
- /* size_t could be wider than unsigned int;
- make sure we treat argument like common implementations do */
- unsigned int uj = *p++ - '0';
- while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
- min_field_width = uj;
+ atosizet(p, &p, &min_field_width);
}
/* parse precision */
if (*p == '.') {
p++; precision_specified = 1;
if (*p == '*') {
- int j = va_arg(ap, int);
+ const int j = va_arg(ap, int);
p++;
if (j >= 0) precision = j;
else {
@@ -668,11 +719,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
*/
}
} else if (isdigit((int)(*p))) {
- /* size_t could be wider than unsigned int;
- make sure we treat argument like common implementations do */
- unsigned int uj = *p++ - '0';
- while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
- precision = uj;
+ atosizet(p, &p, &precision);
}
}
/* parse 'h', 'l' and 'll' length modifiers */
@@ -713,7 +760,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
case '%':
str_arg = p; break;
case 'c': {
- int j = va_arg(ap, int);
+ const int j = va_arg(ap, int);
uchar_arg = (unsigned char) j; /* standard demands unsigned char */
str_arg = (const char *) &uchar_arg;
break;
@@ -727,7 +774,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
else if (precision == 0) str_arg_l = 0;
else {
/* memchr on HP does not like n > 2^31 !!! */
- const char *q = memchr(str_arg, '\0',
+ const char *const q = (const char *) memchr(str_arg, '\0',
precision <= 0x7fffffff ? precision : 0x7fffffff);
str_arg_l = !q ? precision : (q-str_arg);
}
@@ -872,12 +919,20 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
/* When zero value is formatted with an explicit precision 0,
the resulting formatted string is empty (d, i, u, o, x, X, p). */
} else {
+ static int sprintf_return_value_is_ansi_compliant = -1; /* unknown */
char f[5]; int f_l = 0, sprintf_l = 0;
f[f_l++] = '%'; /* construct a simple format string for sprintf */
if (!length_modifier) { }
else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
else f[f_l++] = length_modifier;
f[f_l++] = fmt_spec; f[f_l++] = '\0';
+ if (sprintf_return_value_is_ansi_compliant < 0) { /* not yet known */
+ /* let's do a little run-time experiment (only once) to see if the
+ * native sprintf returns a string length as required by ANSI, or has
+ * some other ideas like the old SunOS which returns buffer address */
+ sprintf_return_value_is_ansi_compliant =
+ (sprintf(tmp+str_arg_l, "%d", 19) == 2);
+ }
if (fmt_spec == 'p') sprintf_l=sprintf(tmp+str_arg_l, f, ptr_arg);
else if (fmt_spec == 'd') { /* signed */
switch (length_modifier) {
@@ -898,9 +953,12 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
#endif
}
}
- assert(sprintf_l >= 0); /* should not happen */
- assert(sprintf_l+str_arg_l < sizeof(tmp)); /*better safe than sorry*/
- str_arg_l += sprintf_l;
+ if (!sprintf_return_value_is_ansi_compliant) { /* broken sprintf? */
+ tmp[sizeof(tmp)-1] = '\0'; sprintf_l = strlen(tmp+str_arg_l);
+ }
+ assert(sprintf_l >= 0); /* should not happen; problem in sprintf? */
+ assert(sprintf_l+str_arg_l < sizeof(tmp)); /*better late then never*/
+ str_arg_l += sprintf_l;
/* include the optional minus sign and possible "0x"
in the region before the zero padding insertion point */
if (zero_padding_insertion_ind < str_arg_l &&
@@ -914,7 +972,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
zero_padding_insertion_ind += 2;
}
}
- { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
+ { const size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
if (alternate_form && fmt_spec == 'o'
#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */
&& (str_arg_l > 0)
@@ -939,11 +997,29 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
}
/* zero padding to specified minimal field width? */
if (!justify_left && zero_padding) {
- int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
+ const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) number_of_zeros_to_pad += n;
}
break;
}
+ case 'n': {
+ void *const ptr = va_arg(ap, void *);
+ if (ptr != NULL) {
+ /* same problem of size_t -> int type conversion as with the
+ * snprintf return value - see comment at the end of this procedure */
+ switch (length_modifier) {
+ case '\0': *( int *const)ptr = str_l; break;
+ case 'h': *(short int *const)ptr = str_l; break;
+ case 'l': *(long int *const)ptr = str_l; break;
+#ifdef SNPRINTF_LONGLONG_SUPPORT
+ case '2': *(long long int *const)ptr = str_l; break;
+#endif
+ }
+ }
+ /* no argument converted */
+ min_field_width = number_of_zeros_to_pad = str_arg_l = 0;
+ break;
+ }
default: /* unrecognized conversion specifier, keep format string as-is*/
zero_padding = 0; /* turn zero padding off for non-numeric convers. */
#ifndef DIGITAL_UNIX_COMPATIBLE
@@ -967,11 +1043,12 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
/* insert padding to the left as requested by min_field_width;
this does not include the zero padding in case of numerical conversions*/
if (!justify_left) { /* left padding with blank or zero */
- int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
+ const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) {
if (str_l < str_m) {
- size_t avail = str_m-str_l;
- fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
+ const size_t avail = str_m-str_l;
+ fast_memset(str+str_l, (zero_padding?'0':' '),
+ ((unsigned int)n > avail ? avail : (unsigned int)n));
}
str_l += n;
}
@@ -984,43 +1061,48 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
zero_padding_insertion_ind = 0;
} else {
/* insert first part of numerics (sign or '0x') before zero padding */
- int n = zero_padding_insertion_ind;
- if (n > 0) {
- if (str_l < str_m) {
- size_t avail = str_m-str_l;
- fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
+ { const int n = zero_padding_insertion_ind;
+ if (n > 0) {
+ if (str_l < str_m) {
+ const size_t avail = str_m-str_l;
+ fast_memcpy(str+str_l, str_arg,
+ ((unsigned int)n > avail ? avail : (unsigned int)n));
+ }
+ str_l += n;
}
- str_l += n;
}
/* insert zero padding as requested by the precision or min field width */
- n = number_of_zeros_to_pad;
- if (n > 0) {
- if (str_l < str_m) {
- size_t avail = str_m-str_l;
- fast_memset(str+str_l, '0', (n>avail?avail:n));
+ { const int n = number_of_zeros_to_pad;
+ if (n > 0) {
+ if (str_l < str_m) {
+ const size_t avail = str_m-str_l;
+ fast_memset(str+str_l, '0',
+ ((unsigned int)n > avail ? avail : (unsigned int)n));
+ }
+ str_l += n;
}
- str_l += n;
}
}
/* insert formatted string
* (or as-is conversion specifier for unknown conversions) */
- { int n = str_arg_l - zero_padding_insertion_ind;
+ { const int n = str_arg_l - zero_padding_insertion_ind;
if (n > 0) {
if (str_l < str_m) {
- size_t avail = str_m-str_l;
+ const size_t avail = str_m-str_l;
fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
- (n>avail?avail:n));
+ ((unsigned int)n > avail ? avail : (unsigned int)n));
}
str_l += n;
}
}
/* insert right padding */
if (justify_left) { /* right blank padding to the field width */
- int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
+ const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) {
if (str_l < str_m) {
- size_t avail = str_m-str_l;
- fast_memset(str+str_l, ' ', (n>avail?avail:n));
+ const size_t avail = str_m-str_l;
+ fast_memset(str+str_l, ' ',
+ ((unsigned int)n > avail ? avail : (unsigned int)n));
}
str_l += n;
}
@@ -1040,7 +1122,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
*
* The value of str_l should be returned, but str_l is of unsigned type
* size_t, and snprintf is int, possibly leading to an undetected
- * integer overflow, resulting in a negative return value, which is illegal.
+ * integer overflow, resulting in a negative return value, which is invalid.
* Both XSH5 and ISO C99 (at least the draft) are silent on this issue.
* Should errno be set to EOVERFLOW and EOF returned in this case???
*/
diff --git a/src/preproc/grn/hdb.cc b/src/preproc/grn/hdb.cc
index 05788ebf..8bbc6b5a 100644
--- a/src/preproc/grn/hdb.cc
+++ b/src/preproc/grn/hdb.cc
@@ -90,7 +90,7 @@ DBRead(register FILE *file)
SUNFILE = FALSE;
elist = DBInit();
- (void) fscanf(file, "%" MAXSTRING_S "s%*s\n", string);
+ (void) fscanf(file, "%" MAXSTRING_S "s%*[^\n]\n", string);
if (strcmp(string, "gremlinfile")) {
if (strcmp(string, "sungremlinfile")) {
error("`%1' is not a gremlin file", gremlinfile);
@@ -107,7 +107,7 @@ DBRead(register FILE *file)
/* if (fscanf(file,"%" MAXSTRING_S "s\n", string) == EOF) */
/* I changed the scanf format because the element */
/* can have two words (e.g. CURVE SPLINE) */
- if (fscanf(file, "\n%" MAXSTRING_S "[^\n]%*s\n", string) == EOF) {
+ if (fscanf(file, "\n%" MAXSTRING_S "[^\n]%*[^\n]\n", string) == EOF) {
error("`%1', error in file format", gremlinfile);
return (elist);
}
diff --git a/src/roff/grog/grog.pl b/src/roff/grog/grog.pl
index a61106c1..fd252b6d 100644
--- a/src/roff/grog/grog.pl
+++ b/src/roff/grog/grog.pl
@@ -81,10 +81,18 @@ sub process {
}
}
}
- elsif (/^\.R1$sp/ || /^\.\[$sp/) {
+ elsif (/^\.R1$sp/) {
$refer++;
$soelim++ if $level;
}
+ elsif (/^\.\[/) {
+ $refer_open++;
+ $soelim++ if $level;
+ }
+ elsif (/^\.\]/) {
+ $refer_close++;
+ $soelim++ if $level;
+ }
elsif (/^\.[PLI]P$sp/) {
$PP++;
}
@@ -166,6 +174,8 @@ sub help {
exit 0;
}
+refer = $refer || ($refer_open && $refer_close);
+
if ($pic || $tbl || $eqn || $grn || $grap || $refer) {
$s = "-";
$s .= "s" if $soelim;
diff --git a/src/roff/grog/grog.sh b/src/roff/grog/grog.sh
index ae269af5..20ea863e 100644
--- a/src/roff/grog/grog.sh
+++ b/src/roff/grog/grog.sh
@@ -29,19 +29,21 @@ do
esac
done
-egrep -h "^\.(P|PS|[PLI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|.* Oo|Oc|.* Oc|TS|EQ|TH|SH|so|\[|R1|GS|G1|PH|SA)$sp" $* \
+egrep -h "^\.(\[|\])|((P|PS|[PLI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|.* Oo|Oc|.* Oc|TS|EQ|TH|SH|so|\[|R1|GS|G1|PH|SA)$sp)" $* \
| sed -e '/^\.so/s/^.*$/.SO_START\
&\
.SO_END/' \
| $soelim \
-| egrep '^\.(P|PS|[PLI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|.* Oo|Oc|.* Oc|TS|EQ|TH|SH|\[|R1|GS|G1|PH|SA|SO_START|SO_END)' \
+| egrep '^\.(P|PS|[PLI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|.* Oo|Oc|.* Oc|TS|EQ|TH|SH|\[|\]|R1|GS|G1|PH|SA|SO_START|SO_END)' \
| awk '
/^\.SO_START$/ { so = 1 }
/^\.SO_END$/ { so = 0 }
/^\.TS/ { tbl++; if (so > 0) soelim++ }
/^\.PS([ 0-9.<].*)?$/ { pic++; if (so > 0) soelim++ }
/^\.EQ/ { eqn++; if (so > 0) soelim++ }
-/^\.(R1|\[)/ { refer++; if (so > 0) soelim++ }
+/^\.R1)/ { refer++; if (so > 0) soelim++ }
+/^\.\[/ {refer_start++; if (so > 0) soelim++ }
+/^\.\]/ {refer_end++; if (so > 0) soelim++ }
/^\.GS/ { grn++; if (so > 0) soelim++ }
/^\.G1/ { grap++; pic++; if (so > 0) soelim++ }
/^\.TH/ { TH++ }
@@ -74,6 +76,7 @@ END {
if (files ~ /^-/)
files = "-- " files
printf "groff"
+ refer = refer || (refer_start && refer_end)
if (pic > 0 || tbl > 0 || grn > 0 || grap > 0 || eqn > 0 || refer > 0) {
printf " -"
if (soelim > 0) printf "s"