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
181
182
183
184
185
186
187
188
189
190
|
include <chars.h>
include <ctype.h>
include "tbltext.h"
# tbzlin -- get next line from text file
# This routine calls getlline (get long line) to get a line from a text file.
# The line_type indicates what type of line (comment, data, etc) was read.
# If the input line is data rather than a comment, the returned line will
# be terminated by EOS rather than by '\n'. If the line is a comment, the
# entire line (including newline) is returned. In the case of in-line
# comments, if there are non-whitespace characters preceding the '#' they
# will be returned, and the '#' will be replaced by EOS. A '#' which is
# enclosed in quotes (single or double) or preceded by '\' will not be
# counted as a comment character. A newline terminates the string regardless
# of what precedes or follows it; a newline within a string is an error,
# though. The function value is the number of characters preceding the EOS,
# or EOF is returned when the end of file is reached.
#
# The buffer is scanned to be sure it contains a '\n'. If not, we haven't
# read the entire line (i.e. it's longer than maxch); we regard that as
# a serious error.
#
# Phil Hodge, 6-Feb-1992 Function created.
# Phil Hodge, 19-Jan-1995 Allow continuation lines.
# Phil Hodge, 26-Dec-1995 Errchk getlline.
# Phil Hodge, 21-Apr-1999 Change error message if newline not found;
# allow last line of file to not have a newline.
# Phil Hodge, 7-Jun-1999 Change last argument from comment flag (bool)
# to line type (int); add line, and increment.
int procedure tbzlin (fd, buf, maxch, line, line_type)
int fd # i: fd for the file
char buf[ARB] # o: buffer for the line that was read
int maxch # i: size of line buffer
int line # io: incremented each time a line is read from file
int line_type # o: type of line returned in buf
#--
pointer sp
pointer scratch
char ch # a character from the string which was read
int ip # counter for a character in the string
int nchar # number of char read by getlline
bool done # loop-termination flag
bool at_end # true when we reach the end of the line ('\n')
bool odd_squotes # true if current character is within quoted string
bool odd_dquotes # true if current char is within double quoted string
int getlline(), strlen(), strncmp()
errchk getlline
begin
line_type = COMMENT_LINE # default
nchar = getlline (fd, buf, maxch)
if (nchar == EOF)
return (EOF) # end of file reached
line = line + 1
# Check for special cases.
done = false
if (strncmp (buf, "#k ", 3) == 0 ||
strncmp (buf, "#K ", 3) == 0) {
line_type = KEYWORD_LINE
done = true
} else if ((strncmp (buf, "#c ", 3) == 0 ||
strncmp (buf, "#C ", 3) == 0) && nchar > 4) {
# the test on nchar is because a column name must be specified
line_type = COLDEF_LINE
done = true
}
if (done) {
if (buf[nchar] == NEWLINE) {
buf[nchar] = EOS
nchar = nchar - 1
}
return (nchar)
}
# Blank up through maxch? Treat it as a comment.
ip = 1
while (IS_WHITE(buf[ip]) && ip < maxch) # skip whitespace
ip = ip + 1
if (ip >= maxch)
line_type = COMMENT_LINE
else if (buf[ip] == NEWLINE || buf[ip] == '#' || buf[ip] == EOS)
line_type = COMMENT_LINE
else
line_type = DATA_LINE
# If there's no newline, and if this is not the last line of the
# file, we haven't read the entire line (i.e. it's longer than the
# buffer size).
# Also check whether the newline has been escaped, in which case
# we need to read further lines and concatenate them.
done = false
while (!done) {
ip = strlen (buf)
if (buf[ip] != NEWLINE) {
# The last line of the file need not have a newline.
call smark (sp)
call salloc (scratch, 2*SZ_LINE, TY_CHAR)
nchar = getlline (fd, Memc[scratch], 2*SZ_LINE)
if (nchar != EOF) {
call error (1,
"Unknown table type, or line too long for text file.")
}
call sfree (sp)
break
}
done = true # may be reset below
if (ip > 1) {
if (buf[ip-1] == ESCAPE) { # newline is escaped
done = false
# Read another line, clobbering the '\' and newline.
ip = ip - 1 # now points to the '\'
nchar = getlline (fd, buf[ip], maxch-ip)
line = line + 1
if (line_type == COMMENT_LINE) {
# Remove comment character from continuation line.
while (IS_WHITE(buf[ip]) && ip < maxch)
ip = ip + 1
if (buf[ip] == '#')
buf[ip] = ' '
}
}
}
}
if (line_type != COMMENT_LINE) {
# The current line is not a comment or blank;
# replace '\n' or '#' by EOS.
# Skip leading whitespace and check whether the first character
# begins a quoted string.
ip = 1
while (IS_WHITE(buf[ip]) && ip < maxch)
ip = ip + 1
if (buf[ip] == SQUOTE)
odd_squotes = true
else
odd_squotes = false
if (buf[ip] == DQUOTE)
odd_dquotes = true
else
odd_dquotes = false
ip = ip + 1
at_end = false
while ( !at_end ) {
ch = buf[ip]
# Check for end of buffer or newline or in-line comment.
if (ch == NEWLINE) {
buf[ip] = EOS
at_end = true
} else if (ch == SQUOTE) {
# Toggle flag for in/out of quoted string.
odd_squotes = !odd_squotes
ip = ip + 1
} else if (ch == DQUOTE) {
odd_dquotes = !odd_dquotes
ip = ip + 1
} else if (ch == '#') {
# '#' is not a comment if it's in a quoted string
if (odd_squotes || odd_dquotes) {
ip = ip + 1
# ... or if it's escaped.
} else if (buf[ip-1] == ESCAPE) {
ip = ip + 1
} else { # it's an in-line comment
buf[ip] = EOS
at_end = true
}
} else if (ch == EOS) {
at_end = true
} else if (ip >= maxch) { # end of buffer reached
at_end = true # (can't get here)
buf[maxch+1] = EOS
} else {
ip = ip + 1
}
}
if (odd_squotes || odd_dquotes)
call error (1, "tbzlin: newline within string")
nchar = ip - 1
}
return (nchar)
end
|