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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <error.h>
include <syserr.h>
include "tty.h"
task mkttydata = t_mkttydata
.help mkttydata
.nf -------------------------------------------------------------------------
MKTTYDATA -- System Manager's program to compile the TERMCAP entries for a
list of terminals. Output is an SPP format include file to be used in TTYLOAD
to statically declare and initialize the TERMCAP entries for the named
devices, eliminating the need to scan the TERMCAP file for those devices.
Compilation of selected termcap entries to speed up accesses to the
termcap database for frequently referenced terminals. We read and preprocess
the entries for the named terminals from the termcap file, producing the source
code for the TTYLOAD procedure as output. The termcap entry for each device
is included in the source for TTYLOAD as a static data structure. TTYLOAD is
subsequently compiled and placed in the library with the other TTY routines.
At run time, TTYODES first tries to load the termcap database entry using
TTYLOAD, and if that fails it goes and reads the termcap file.
N.B.: The TTY interface may be used for any termcap format file, regardless
of whether or not the database describes terminals.
.endhelp ---------------------------------------------------------------------
# Tunable parameters.
define MAX_DEVICES 25 # initial max termcap entries
define INC_DEVICES 25 # increment if overflow occurs
define SZ_SBUF 4096 # initial size of string buffer
define INC_SZSBUF 2048 # increment if overflow occurs
define NI_PERLINE 5 # number of datastmt ints per line
define NC_PERLINE 8 # number of datastmt chars per line
# Device descriptor structure (contains the extracted termcap entries).
# There are no upper limits on the number of devices or upon the sizes of
# any of the substructures.
define LEN_TCSTRUCT 8
define TC_NDEVICES Memi[$1] # number of termcap entries
define TC_MAXDEVICES Memi[$1+1] # initial max termcap entries
define TC_DEVNAME_P Memi[$1+2] # pointer to devname index array
define TC_CAPLIST_P Memi[$1+3] # pointer to caplist index array
define TC_SBUF Memi[$1+4] # pointer to string buffer
define TC_SZSBUF Memi[$1+5] # current size of string buffer
define TC_NEXTCH Memi[$1+6] # offset of next avail char in sbuf
define TC_TCFNAME Memi[$1+7] # name of termcap file
define TC_DEVNAME Memi[TC_DEVNAME_P($1)+$2-1]
define TC_CAPLIST Memi[TC_CAPLIST_P($1)+$2-1]
# MKTTYDATA -- Given the name of a termcap format file and a list of device
# names, call TTYOPEN to fetch the termcap entry of the device.
# Move the entry for the device into the dev structure and continue until
# the entries for all devices have been read. Write out the source code for
# the data structures of these devices. This output file is "included"
# when TTYLOAD is later compiled, cacheing the termcap entries for the
# named devices in memory.
procedure t_mkttydata()
bool verbose
int devlist, fd, ndev, buflen
pointer sp, termcap_file, output_file, devname, tc, tty
bool clgetb()
int clpopnu(), clgfil(), tc_putstr(), open(), tc_dummy_ttyload()
pointer ttyopen()
extern tc_dummy_ttyload()
errchk open, tc_write_data_declarations, clgfil, tc_putstr, malloc, realloc
begin
call smark (sp)
call salloc (termcap_file, SZ_FNAME, TY_CHAR)
call salloc (output_file, SZ_FNAME, TY_CHAR)
call salloc (devname, SZ_FNAME, TY_CHAR)
call salloc (tc, LEN_TCSTRUCT, TY_STRUCT)
# Open the list of devices to be compiled into the cache. CLGFIL is
# useful for reading the list even though the list elements are not
# filenames, because it can expand comma a delimited list passed as
# a string as well as read from a list file. The list is not sorted
# so that the caller can order the devices in the order in which they
# will most frequently be referenced (though really it matters little).
# Get the names of the input and output files.
devlist = clpopnu ("devlist")
call clgstr ("termcap_file", Memc[termcap_file], SZ_FNAME)
call clgstr ("output_file", Memc[output_file], SZ_FNAME)
verbose = clgetb ("verbose")
# Initialize the TC descriptor structure. Allocate the variable sized
# buffers.
ndev = 0
buflen = MAX_DEVICES
TC_NDEVICES(tc) = 0
TC_MAXDEVICES(tc) = MAX_DEVICES
TC_SZSBUF(tc) = SZ_SBUF
TC_NEXTCH(tc) = 0
iferr {
call malloc (TC_DEVNAME_P(tc), buflen, TY_INT)
call malloc (TC_CAPLIST_P(tc), buflen, TY_INT)
call malloc (TC_SBUF(tc), SZ_SBUF, TY_CHAR)
} then
call erract (EA_FATAL)
# Store the name of the termcap file in the descriptor. The descriptor
# is only valid if TTYLOAD is called with the exact same filename.
TC_TCFNAME(tc) = tc_putstr (tc, Memc[termcap_file])
# Fetch the termcap entry for each device in the list. This is not
# done very efficiently, but it does not matter since this program
# is infrequently run. Accumulate the entries in the TC structure.
while (clgfil (devlist, Memc[devname], SZ_FNAME) != EOF) {
# Fetch entry from termcap file.
iferr (tty = ttyopen (Memc[termcap_file], Memc[devname],
tc_dummy_ttyload)) {
call erract (EA_WARN)
next
} else if (verbose) {
call eprintf ("%4d %s: %d chars\n")
call pargi (ndev + 1)
call pargstr (Memc[devname])
call pargi (T_CAPLEN(tty))
}
ndev = ndev + 1
TC_NDEVICES(tc) = ndev
# Make room for more devices if necessary.
if (ndev > TC_MAXDEVICES(tc)) {
TC_MAXDEVICES(tc) = TC_MAXDEVICES(tc) + INC_DEVICES
buflen = TC_MAXDEVICES(tc)
iferr {
call realloc (TC_DEVNAME_P(tc), buflen, TY_INT)
call realloc (TC_CAPLIST_P(tc), buflen, TY_INT)
} then
call erract (EA_FATAL)
}
# Add entry to descriptor.
TC_DEVNAME(tc,ndev) = tc_putstr (tc, Memc[devname])
TC_CAPLIST(tc,ndev) = tc_putstr (tc, T_CAPLIST(tty))
call ttyclose (tty)
}
call clpcls (devlist)
# Write the output file (an SPP "include" file) containing data
# declarations for the data structures in the TC structure.
iferr (call delete (Memc[output_file]))
;
fd = open (Memc[output_file], NEW_FILE, TEXT_FILE)
call tc_write_data_declarations (fd, tc, Memc[termcap_file])
call close (fd)
call mfree (TC_DEVNAME_P(tc), TY_INT)
call mfree (TC_CAPLIST_P(tc), TY_INT)
call mfree (TC_SBUF(tc), TY_CHAR)
call sfree (sp)
end
# TC_PUTSTR -- Put a string (incl EOS) in the string buffer at nextch.
# If there is not enough space in the buffer, reallocate a larger buffer.
# Return the index of the string in the string buffer.
int procedure tc_putstr (tc, str)
pointer tc
char str[ARB]
int nextch, nchars, strlen()
errchk realloc
begin
# Null strings are not stored and cause a null index to be returned.
nchars = strlen (str)
if (nchars == 0)
return (0)
nextch = TC_NEXTCH(tc)
if (nextch + nchars + 1 > TC_SZSBUF(tc)) {
TC_SZSBUF(tc) = TC_SZSBUF(tc) + INC_SZSBUF
call realloc (TC_SBUF(tc), TC_SZSBUF(tc), TY_CHAR)
}
call strcpy (str, Memc[TC_SBUF(tc) + nextch], ARB)
TC_NEXTCH(tc) = nextch + nchars + 1
return (nextch)
end
# TC_WRITE_DATA_DECLARATIONS -- Write the SPP data declarations required to
# declare and initialize the following data structures:
#
# int ndevices # number of devices in cache
# int devname[] # 0-indexed offset into sbuf of device name
# int devcaps[] # 0-indexed offset into sbuf of termcap entry
# char sbuf[] # string buffer
procedure tc_write_data_declarations (fd, tc, termcap_file)
int fd # output file
pointer tc # TC descriptor
char termcap_file[ARB] # name of source file
int ndevices, dev
pointer sbuf
int strlen()
begin
ndevices = TC_NDEVICES(tc)
sbuf = TC_SBUF(tc)
# Write a comments section naming the devices represented by the
# data declarations which follow.
call fprintf (fd,
"# TERMCAP data declarations for %d devices from '%s'\n")
call pargi (TC_NDEVICES(tc))
call pargstr (termcap_file)
do dev = 1, ndevices {
call fprintf (fd, "#%15s (size %d+1 chars)\n")
call pargstr (Memc[sbuf+TC_DEVNAME(tc,dev)])
call pargi (strlen (Memc[sbuf+TC_CAPLIST(tc,dev)]))
}
# Output the object declarations.
call fprintf (fd, "\n")
call fprintf (fd, "int\ttermcap_filename, ndevices, i\n")
call fprintf (fd, "int\tdevname[%d], devcaps[%d]\n")
call pargi (ndevices)
call pargi (ndevices)
# Do not add 1 char for the EOS; SPP compiler automatically does so.
call fprintf (fd, "char\tsbuf[%d]\n")
call pargi (TC_NEXTCH(tc))
# Output the data initialization declarations.
call fprintf (fd, "\n")
call fprintf (fd, "data\tndevices /%d/\n")
call pargi (ndevices)
call fprintf (fd, "data\ttermcap_filename /%d/\n")
call pargi (TC_TCFNAME(tc) + 1)
call tc_init_datai (fd, "devname", Memi[TC_DEVNAME_P(tc)], ndevices)
call tc_init_datai (fd, "devcaps", Memi[TC_CAPLIST_P(tc)], ndevices)
call fprintf (fd, "\n")
call tc_init_datac (fd, "sbuf", Memc[TC_SBUF(tc)], TC_NEXTCH(tc)+1)
end
# TC_INIT_DATAI -- Write a series of data statements to initialize an
# integer array. A single large statement is not used due to variation
# in the permissible number of continuation statements permitted by
# different compilers.
procedure tc_init_datai (fd, varname, array, npix)
int fd # output file
char varname[ARB] # name of variable to be initialized
int array[npix] # array values
int npix
int i, j, i1, i2
begin
for (j=1; j <= npix; j = j + NI_PERLINE) {
i1 = j
i2 = min (j + NI_PERLINE - 1, npix)
# Begin new data statement.
call fprintf (fd, "data\t(%s(i),i=%2d,%2d)\t/")
call pargstr (varname)
call pargi (i1)
call pargi (i2)
# Output data values. NOTE: the TC_SBUF offsets are zero-indexed
# offsets into Mem, but the SBUF array in the include file is a
# static Fortran array which requires 1-indexed offsets, so we
# add one before writing out the offsets.
for (i=i1; i <= i2; i=i+1) {
if (i > i1)
call fprintf (fd, ", ")
call fprintf (fd, "%d")
call pargi (array[i] + 1)
}
# Terminate statement.
call fprintf (fd, "/\n")
}
end
# TC_INIT_DATAC -- Write a series of data statements to initialize a
# char array. A single large statement is not used due to variation
# in the permissible number of continuation statements permitted by
# different compilers.
procedure tc_init_datac (fd, varname, str, nchars)
int fd # output file
char varname[ARB] # name of variable to be initialized
char str[nchars] # array values
int nchars
int i, j, i1, i2
begin
for (j=1; j <= nchars; j = j + NC_PERLINE) {
i1 = j
i2 = min (j + NC_PERLINE - 1, nchars)
# Begin new data statement.
call fprintf (fd, "data\t(%s(i),i=%2d,%2d)\t/")
call pargstr (varname)
call pargi (i1)
call pargi (i2)
# Output data values.
for (i=i1; i <= i2; i=i+1) {
if (i > i1)
call fprintf (fd, ", ")
call fprintf (fd, "%3d")
call pargc (str[i])
}
# Terminate statement.
call fprintf (fd, "/\n")
}
end
# TC_DUMMY_TTYLOAD -- Since we are rebuilding a TTYLOAD, we cannot pass
# a real one to TTYOPEN. This dummy procedure returns 0 to TTYOPEN for
# all devices, forcing TTYOPEN to open and scan the termcap file to fetch
# the termcap entry for a device.
int procedure tc_dummy_ttyload (termcap_file, devname, outstr, maxch)
char termcap_file[ARB]
char devname[ARB]
char outstr[maxch]
int maxch
begin
outstr[1] = EOS
return (0)
end
|