diff options
Diffstat (limited to 'pkg/tbtables/tbbwrd.x')
-rw-r--r-- | pkg/tbtables/tbbwrd.x | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/pkg/tbtables/tbbwrd.x b/pkg/tbtables/tbbwrd.x new file mode 100644 index 00000000..024fe242 --- /dev/null +++ b/pkg/tbtables/tbbwrd.x @@ -0,0 +1,219 @@ +include <ctype.h> # for IS_DIGIT + +define LEFT_MARGIN 0 # extra space at left of first column + +# tbbwrd -- read a word from the input buffer +# This routine extracts the next word from the input buffer, returning +# the word itself and the number of characters that it contains. +# The function value is the number of char converted, as returned by +# ctowrd. If the value is a string (i.e. not numeric), then trailing +# blanks will be truncated. If the value is a single blank, however, +# that blank will not be deleted. +# +# If the word is numeric, PREC is the number of digits of precision +# in the word; for HH:MM:SS.d or HH:MM.d format PREC is the number of +# digits after the decimal point. The idea is that the values of WIDTH +# and PREC returned by this routine can go directly into a format code. +# +# The format code FCODE and precision PREC are really only used if the +# data type is double. + +# Phil Hodge, 3-Mar-1992 Subroutine created. +# Phil Hodge, 7-Aug-1992 Include checks on string beginning with number; +# add fcode to the calling sequence. +# Phil Hodge, 10-Sep-1992 Set datatype to double if word is INDEF. +# Phil Hodge, 7-Jun-1994 Set type to char if more than one decimal point. +# Phil Hodge, 27-Jul-1994 Change LEFT_MARGIN from 3 to 0 (no longer needed). + +int procedure tbbwrd (buf, ip, word, maxch, width, prec, datatype, fcode) + +char buf[ARB] # i: buffer containing line from file +int ip # io: starting location in buffer +char word[ARB] # o: word extracted from buffer +int maxch # i: max size of word +int width # o: width of column +int prec # o: digits of precision in this word +int datatype # o: TY_DOUBLE, TY_INT, or TY_CHAR +int fcode # o: format code for print format +#-- +char cval # one character in the word +int ip_start # ip before calling ctowrd +int word_width # width of extracted word (value of ctowrd) +int i # loop index +int num_colon # number of ':' found in word +bool quote # true if value begins with ' or " +bool exponent # true if there's an exponent in the word +bool dec_point # true if there's a decimal point in the word +int ctowrd(), strlen(), strncmp() +bool streq() + +define chartype_ 91 +define finished_ 93 + +begin + ip_start = ip + datatype = 0 + fcode = 's' + + word_width = ctowrd (buf, ip, word, maxch) + if (word_width < 1) + return (0) + + # These may be updated later. + width = word_width + prec = width + + # Check whether column begins with a quote, indicating that it's + # a string, even if the word itself is numeric, e.g. "3.14159". + quote = false + do i = ip_start, ip { + if (buf[i] != ' ') { + if (buf[i] == '"' || buf[i] == '\'') + quote = true + break + } + } + + # Get a first estimate of the data type. We may change this later. + if (quote) { + datatype = TY_CHAR + + } else if (IS_DIGIT(word[1])) { + datatype = TY_DOUBLE + + } else if (word[1] == '-' || word[1] == '+' || word[1] == '.') { + if (IS_DIGIT(word[2])) + datatype = TY_DOUBLE + else + datatype = TY_CHAR + + } else if (word[1] == 'I') { + if (streq (word, "INDEFI")) { + datatype = TY_INT + width = 6 + fcode = 'd' + goto finished_ + } else if (strncmp (word, "INDEF", 5) == 0) { + datatype = TY_DOUBLE + width = 5 + prec = 5 + fcode = 'g' + goto finished_ + } else { + datatype = TY_CHAR + } + + } else { + datatype = TY_CHAR + } + + if (quote) { + # The value is enclosed in quotes; don't include them in the width. + width = word_width - 2 + + # Trim trailing blanks. width is unchanged. + do i = strlen (word), 1, -1 { + if (word[i] != ' ') { + word[i+1] = EOS + break + } + } + } + + if (datatype != TY_CHAR) { + # So far, the word appears to be a number. Check each character, + # and change the type if we find that it's not numeric. + + num_colon = 0 # initial values + exponent = false + dec_point = false + prec = 0 # incremented in loop + do i = 1, maxch { + cval = word[i] + if (IS_DIGIT(cval)) { + if (!exponent) + prec = prec + 1 # count it + } else if (cval == '.') { + # There can't be two decimal points, or even one in + # an exponent. + if (dec_point || exponent) { + datatype = TY_CHAR + goto chartype_ + } + dec_point = true + if (num_colon > 0) + prec = 0 + } else if (cval == '+' || cval == '-') { + # A sign must be the first character or in an exponent. + if (i > 1 && !exponent) { + datatype = TY_CHAR + goto chartype_ + } + } else if (cval == ':') { + num_colon = num_colon + 1 + if (exponent || num_colon > 2) { + datatype = TY_CHAR + goto chartype_ + } + } else if (cval == 'E' || cval == 'e' || + cval == 'D' || cval == 'd') { + # There can't be more than one exponent in a number. + if (exponent) { + datatype = TY_CHAR + goto chartype_ + } exponent = true # it looks like an exponent + } else if (cval == EOS) { + break + } else { + datatype = TY_CHAR # not numeric + goto chartype_ + } + } + prec = max (prec, 1) + + # We need this test for HMS format because there might have been + # no decimal point in the value (e.g. 3:17:42), so the digits + # would have been counted in the precision and not reset to zero + # by a decimal point. We could in principle have prec=0, but + # that prints incorrect values due to truncation. + if (num_colon > 0 && !dec_point) + prec = 1 # should be zero for HH:MM:SS + + # Now make sure the field width is sufficient, and set format code. + if (num_colon == 2) { # HH:MM:SS.d + width = prec + 10 + fcode = 'h' + } else if (num_colon == 1) { # HH:MM.d + width = prec + 7 + fcode = 'm' + } else if (exponent) { + width = prec + 6 + fcode = 'g' + } else if (dec_point) { + width = prec + 2 + fcode = 'g' + } else { # no decimal point, colon, or exponent + width = prec + 1 + datatype = TY_INT # reset datatype to int + fcode = 'd' + } + + } + +chartype_ + if (datatype == TY_CHAR && !quote) { + # It's a string, but we don't need to check for trailing blanks + # because the string is not enclosed in quotes. + width = word_width + } + +finished_ + # If this is the first column and the value is left-justified, + # add a little extra space. + if (ip_start == 1) { + if (buf[1] != ' ' && buf[1] != '\t') + width = width + LEFT_MARGIN + } + + return (word_width) +end |