1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <ctype.h>
include <printf.h>
.help
.nf _________________________________________________________________________
Process a format descriptor, setting the variables "decpl", "fill_char",
"format_char", and "width" in the fmtio common. Called from PARG_
to determine the format specification for printing a variable.
Format: "%[w[.d]]C[n]", where W is the field width, D the number of decimal
places or precision, C the format type character, and N the radix numeral,
for format type FMT_RADIX only. A negative field width signifies left
justification. A leading zero in the W field sets the fill character to the
numeral zero (when right justifying). Default values will be supplied if
any of the fields are omitted. The minimum format is "%C".
If any of the fields (wdCn) have the value GET_FIELD (= "*") the value of
the field will be taken from the next PARG_ call, rather than from the
format string. This makes it easy to vary the format specification at run
time. For example, "%10.*g" would print a number in G-floating format,
with a constant field width of 10, and with the number of digits of precision
being given by a PARGI call at execution time (followed by a PARG_ call to
pass the value to be printed).
.endhelp ____________________________________________________________________
# The following macro marks the position in the FPRFMT procedure (saves the
# code for the needed field), and returns the not done status to PARG_.
# A subsequent call to a PARG_ (with the value of the field we are waiting for
# as argument) causes FPRFMT to be reentered at the point where we left off.
define (waitfor, if (ival_already_used) { fmt_state = $1; return (NOT_DONE_YET) } ; $1 ival_already_used = true)
#define (waitfor, if (ival_already_used) {
# fmt_state = $1
# return (NOT_DONE_YET)
# }
# $1 ival_already_used = true)
# FPRFMT -- Process a %W.Dn format specification. ALL_DONE is returned when
# the format specification has been fully processed, else NOT_DONE_YET is
# returned, indicating that an additional PARG call is required to complete
# the format (which therefore contained one or more "*" specifiers).
int procedure fprfmt (ival)
int ival # argument value (from parg_)
bool ival_already_used # wait for next parg
int ctoi(), stridx()
char ch, chrlwr()
include "fmt.com"
begin
# This routine functions as a coroutine. If one of the fields in
# the format spec is to be given in a pargi call, an early return
# is taken. The routine is later reentered with the value of the
# needed field, and execution continues at the point it left off.
# (Sorry, I could not think of a simpler way to do it...)
switch (fmt_state) { # return from "waitfor"
case FMT_START: # initial state
ival_already_used = false
case GET_WIDTH_1: # "%*.dC"
goto GET_WIDTH_1
case GET_WIDTH_2: # "%-0*.dC"
goto GET_WIDTH_2
case GET_DECPL: # "%w.*C"
goto GET_DECPL
case GET_FMTCHAR: # "%w.d*"
goto GET_FMTCHAR
case GET_RADIX: # "%w.dr*"
goto GET_RADIX
case GET_OPERAND: # used ival for format
goto GET_OPERAND
}
# It is not an error if there is no format string.
if (format[ip] == EOS || format[ip] != START_OF_FORMAT) {
width = USE_DEFAULT
decpl = USE_DEFAULT
format_char = USE_DEFAULT
fill_char = ' '
left_justify = NO
fmt_state = FMT_START
return (ALL_DONE)
} else
ip = ip + 1 # eat the "%"
if (format[ip] == GET_FIELD) { # "%*.dC"
ip = ip + 1
waitfor (GET_WIDTH_1) # go get field width...
if (ival < 0) # ...and come back here
left_justify = YES
else
left_justify = NO
fill_char = ' '
width = abs (ival)
} else { # "%-0*.dC"
if (format[ip] == '-') { # left or right justify
left_justify = YES
ip = ip + 1
} else
left_justify = NO
fill_char = ' ' # zero or blank fill
if (format[ip] == '0') {
if (IS_DIGIT (format[ip+1]) || format[ip+1] == GET_FIELD) {
fill_char = '0'
ip = ip + 1
} else
fill_char = ' '
}
if (format[ip] == GET_FIELD) {
ip = ip + 1
waitfor (GET_WIDTH_2) # go get field width...
if (ival < 0) # ... and come back here
left_justify = YES
else
left_justify = NO
width = abs (ival)
} else if (ctoi (format, ip, width) <= 0) # "%N.dC"
width = USE_DEFAULT
}
if (width == 0) # make as big as needed
width = USE_DEFAULT
if (format[ip] == '.') { # get decpl field
ip = ip + 1
if (format[ip] == GET_FIELD) { # "%w.*C"
ip = ip + 1
waitfor (GET_DECPL)
decpl = ival
} else if (ctoi (format, ip, decpl) <= 0) # "%w.NC"
decpl = USE_DEFAULT
} else
decpl = USE_DEFAULT
if (format[ip] == GET_FIELD) { # "%w.d*"
ip = ip + 1
waitfor (GET_FMTCHAR)
format_char = ival
} else {
format_char = format[ip] # "%w.dC"
ip = ip + 1
}
ch = format_char
if (stridx (ch, "bcdefghHmMorstuwxz") <= 0) {
call putline (STDERR, "Warning: Unknown format type char\n")
call fmt_err ("", format, ip-1)
format_char = USE_DEFAULT
} else if (format_char == FMT_RADIX) { # get radix
ch = chrlwr (format[ip])
ip = ip + 1
if (ch == GET_FIELD) { # "%w.dr*"
waitfor (GET_RADIX)
radix = ival
} else if (IS_DIGIT (ch)) {
radix = TO_INTEG (ch)
} else if (IS_LOWER (ch)) {
radix = ch - 'a' + 10
} else {
radix = DECIMAL
ip = ip - 1
}
} else if (format_char == FMT_WHITESPACE || format_char == FMT_TOCOLUMN)
ival_already_used = false # no operand
waitfor (GET_OPERAND) # used ival for format,
fmt_state = FMT_START # need to get another
return (ALL_DONE)
end
|