aboutsummaryrefslogtreecommitdiff
path: root/pkg/tbtables/tbzlin.x
blob: 7ab68e94f5204793c8a1258001f6d8d6da07a7d4 (plain) (blame)
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