aboutsummaryrefslogtreecommitdiff
path: root/sys/tty/ttysubi.x
blob: 870dce592f68914baac131612faed4af661c3241 (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
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