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
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <chars.h>
include <ctype.h>
include "tty.h"
.help ttysubi
.nf ___________________________________________________________________________
TTYSUBI -- Argument substitution on a control string.
Process a capability string containing arguments. Examples of such
capability strings are cursor motion to [x,y], and set scrolling region to
[line1,line2]. Note that arguments in the termcap database are zero-indexed
by default, while the TTYSUBI arguments are one-indexed. The control string
given as input has already been processed to reduce all escape sequences to
single characters.
Various output formats are supported (some of these are completely off the
wall, very special case, but that's how termcap does it):
%d print decimal integer, zero origin.
%2 like %2d.
%3 like %3d.
%. put binary value of x,y arg as a character
%+x like %., but add value of char X first
%% print a single %.
The following format codes affect the arguments, but do not directly cause
any output:
%>xy if next arg value > char x add char y.
%r reverses order of arguments.
%i increments arg values by one, for 1 origin.
%n exlusive-or args with 0140B. (DM2500)
%B BCD next arg, (16*(x/10))+(mod(x,10).
%D Reverse coding (x-2*(mod(x,16))). (Delta Data)
We have generalized the termcap formats somewhat to permit a greater range
of %n formats (%1-%4), as well as %o and %x formats, in case a terminal
comes along which likes octal or hex numbers.
The %. format causes special problems. If the terminal requires coordinates
in binary in the range zero or one to 40B, we can expect problems trying to
push such chars through the OS driver and any other software (networks, etc.),
since system software likes to map control characters on output. To get around
this we have defined a set of reserved codes which are not to be generated.
This set is defined in tty.h, and includes newline, tab, etc. When asked to
output one of these chars, we output a char with a somewhat larger value
and return the delta to our caller, which does whatever is appropriate to
complete the function.
.endhelp ______________________________________________________________________
int procedure ttysubi (ctrlstr, outstr, maxch, coords, ncoords)
char ctrlstr[ARB] # control string containing % formats
char outstr[ARB] # receives processed string
int maxch
int coords[ncoords] # on input, coords; on output, deltas
int ncoords
bool reverse # reverse deltas on output
int revstart # first arg/coord reversed
int args[MAX_COORDS] # processed values of arguments
int argnum # arg being processed
int nargs # number of args (min(MAX_COORDS,ncoords))
char driver_chars[NDCHARS]
char ch, format_char
int i, ip, op, field_width, left, right, temp
int stridx(), strlen(), xor()
data driver_chars /DRIVER_CHARS/
errchk sprintf, pargi
begin
# Make a local copy of the arguments to make reversal etc. easy.
# Also switch to zero-indexing internally, since the termcap entry
# is zero-indexed.
nargs = min (MAX_COORDS, ncoords)
do i = 1, nargs {
args[i] = coords[i] - 1 # make zero-indexed
coords[i] = 0 # init delta
}
argnum = 1 # output x first by default
reverse = false
op = 1
for (ip=1; ctrlstr[ip] != EOS && op <= maxch; ip=ip+1) {
ch = ctrlstr[ip]
# If normal char, we do not get past this if statement.
if (ch != '%') {
outstr[op] = ch
op = op + 1
next
} else {
ip = ip + 1 # fetch format-type char
ch = ctrlstr[ip]
}
# Get here only if processing a %x format specification.
switch (ch) {
case '%': # %% --> %
outstr[op] = ch
op = op + 1
case 'd', 'o', 'x', '1', '2', '3', '4':
# Output next argument according to the format given.
if (IS_DIGIT(ch)) {
field_width = TO_INTEG(ch)
format_char = 'd'
} else {
field_width = 0
format_char = ch
}
call sprintf (outstr[op], maxch-op+1, "%0*.0*")
call pargi (field_width)
call pargc (format_char)
call pargi (args[argnum])
argnum = min (nargs, argnum + 1)
op = op + strlen (outstr[op])
case '.', '+':
# Binary output format. Coordinate output in binary is a
# problem because the OS driver may see a tab, newline, or
# whatever and map it into something else. If the value of
# args[argnum] corresponds to a special control character,
# we increment it until we have an acceptable value, leaving
# it up to our caller to do the rest.
if (ch == '+') {
ip = ip + 1
args[argnum] = args[argnum] + ctrlstr[ip]
}
repeat {
ch = char (args[argnum])
if (stridx (ch, driver_chars) > 0) {
args[argnum] = args[argnum] + 1
coords[argnum] = coords[argnum] + 1
} else
break
}
outstr[op] = args[argnum]
op = op + 1
argnum = min (nargs, argnum + 1)
# The remaining cases are used to change the values of the
# remaining arguments, and do not cause any output.
case '>': # %>xy
if (args[argnum] > ctrlstr[ip+1])
args[argnum] = args[argnum] + ctrlstr[ip+2]
ip = ip + 2
case 'r': # swap remaining args
do left = argnum, (nargs - argnum + 1) / 2 {
right = nargs - (left - argnum)
temp = args[left]
args[left] = args[right]
args[right] = temp
}
reverse = !reverse
revstart = argnum
case 'i': # increment by one
do i = argnum, nargs
args[i] = args[i] + 1
case 'n': # exclusive or with 140B
do i = argnum, nargs
args[i] = xor (args[i], 140B)
case 'B': # BCD encode next arg
temp = args[argnum]
args[argnum] = 16 * (temp / 10) + mod (temp, 10)
case 'D': # Reverse code next arg
temp = args[argnum]
args[argnum] = temp - 2 * mod (temp, 16)
}
}
# If the input coordinates were reversed, we must reverse the
# correction deltas, too.
if (reverse)
do left = revstart, (nargs - revstart + 1) / 2 {
right = nargs - (left - revstart)
temp = coords[left]
coords[left] = coords[right]
coords[right] = temp
}
outstr[op] = EOS
return (op - 1)
end
|