diff options
author | wlemb <wlemb> | 2002-02-11 10:45:48 +0000 |
---|---|---|
committer | wlemb <wlemb> | 2002-02-11 10:45:48 +0000 |
commit | d68f82e908248fd7dcb7726ee9393f6b87299dae (patch) | |
tree | 197725372d2c48ee3c5c45c758e0b83eac03a4a3 /src | |
parent | 6751b7b886769f82724f2bec16479abf73d7523f (diff) | |
download | groff-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.c | 236 | ||||
-rw-r--r-- | src/preproc/grn/hdb.cc | 4 | ||||
-rw-r--r-- | src/roff/grog/grog.pl | 12 | ||||
-rw-r--r-- | src/roff/grog/grog.sh | 9 |
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" |