|
|
1.1 root 1: static char sccsid[] = "@(#)tparm.c 1.1 (1.9 3/4/83)";
2: /* Copyright (c) 1979 Regents of the University of California */
3:
4: #include "curses.h"
5: #include "term.h"
6:
7: #ifdef NONSTANDARD
8: #include "ns_curses.h"
9: #endif
10:
11: #define CTRL(c) ('c' & 037)
12: /* #define _err(msg) 0 */
13: static char *_err();
14: char *_branchto();
15:
16: /*
17: * Routine to perform parameter substitution.
18: * instring is a string containing printf type escapes.
19: * The whole thing uses a stack, much like an HP 35.
20: * The following escapes are defined for substituting row/column:
21: *
22: * %d print pop() as in printf
23: * %[0]2d print pop() like %[0]2d
24: * %[0]3d print pop() like %[0]3d
25: * %c print pop() like %c
26: * %s print pop() like %s
27: * %l pop() a string and push its length.
28: *
29: * %p[1-0] push ith parm
30: * %P[a-z] set variable
31: * %g[a-z] get variable
32: * %'c' char constant c
33: * %{nn} integer constant nn
34: *
35: * %+ %- %* %/ %m arithmetic (%m is mod): push(pop() op pop())
36: * %& %| %^ bit operations: push(pop() op pop())
37: * %= %> %< logical operations: push(pop() op pop())
38: * %! %~ unary operations push(op pop())
39: * %b unary BCD conversion
40: * %d unary Delta Data conversion
41: *
42: * %? expr %t thenpart %e elsepart %;
43: * if-then-else, %e elsepart is optional.
44: * else-if's are possible ala Algol 68:
45: * %? c1 %t %e c2 %t %e c3 %t %e c4 %t %e %;
46: *
47: * all other characters are ``self-inserting''. %% gets % output.
48: */
49:
50: /* #define tparmdebug */
51: #ifdef tparmdebug
52: char *tparm();
53: #include <stdio.h>
54: #define DEBUG
55: FILE *outf;
56: main()
57: {
58: int so, ul, rev, bl, dim, bold, blank, prot, alt;
59: setupterm(getenv("TERM"), 1, 0);
60: outf = stdout;
61: for (;;) {
62: printf("so, ul, rev, bl, dim, bold, blank, prot, alt: ");
63: scanf("%d %d %d %d %d %d %d %d %d",
64: &so, &ul, &rev, &bl, &dim, &bold, &blank, &prot, &alt);
65: printf("-->%s<--\n", tparm(set_attributes,
66: so, ul, rev, bl, dim, bold, blank, prot, alt));
67: }
68: }
69:
70: _prstr(result)
71: char *result;
72: {
73: register char *cp;
74:
75: for (cp=result; *cp; cp++)
76: if (*cp >= ' ' && *cp <= '~')
77: putchar(*cp);
78: else
79: printf("\\%o", *cp&0377);
80: }
81: #endif
82:
83: #define push(i) (stack[++top] = (i))
84: #define pop() (stack[top--])
85:
86: /* VARARGS */
87: char *
88: tparm(instring, p1, p2, p3, p4, p5, p6, p7, p8, p9)
89: char *instring;
90: int p1, p2, p3, p4, p5, p6, p7, p8 ,p9;
91: {
92: static char result[32];
93: static char added[10];
94: int vars[26];
95: int stack[10], top = 0;
96: register char *cp = instring;
97: register char *outp = result;
98: register int c;
99: register int op;
100: int sign;
101: int onrow = 0;
102: int leadzero = 0; /* not having leading zero is unimplemented */
103: char *xp;
104:
105: if (instring == 0)
106: return _err("null arg");
107: added[0] = 0;
108: #ifdef tparmdebug
109: printf("'");
110: _prstr(instring);
111: printf("'\n");
112: #endif
113:
114: while (c = *cp++) {
115: #ifdef tparmdebug
116: printf("loop, c %c%c%c, top %d @ %d, 2nd %d, out '",
117: c, *cp, *(cp+1), stack[top], top, stack[top-1]);
118: _prstr(result); printf("'\n");
119: #endif
120: if (c != '%') {
121: *outp++ = c;
122: continue;
123: }
124: op = stack[top];
125: if (*cp == '0') {
126: leadzero = 1;
127: cp++;
128: }
129: switch (c = *cp++) {
130:
131: /* PRINTING CASES */
132: case 'd':
133: if (op < 10)
134: goto one;
135: if (op < 100)
136: goto two;
137: /* fall into... */
138:
139: case '3':
140: three:
141: if (c == '3' && *cp++ != 'd')
142: return _err("bad char after %3");
143: *outp++ = (op / 100) | '0';
144: op %= 100;
145: /* fall into... */
146:
147: case '2':
148: if (op >= 100)
149: goto three;
150: if (c == '2' && *cp++ != 'd')
151: return _err("bad char after %2");
152: two:
153: *outp++ = op / 10 | '0';
154: one:
155: *outp++ = op % 10 | '0';
156: (void) pop();
157: continue;
158:
159: case 'c':
160: /*
161: * This code is worth scratching your head at for a
162: * while. The idea is that various weird things can
163: * happen to nulls, EOT's, tabs, and newlines by the
164: * tty driver, arpanet, and so on, so we don't send
165: * them if we can help it. So we instead alter the
166: * place being addessed and then move the cursor
167: * locally using UP or RIGHT.
168: *
169: * This is a kludge, clearly. It loses if the
170: * parameterized string isn't addressing the cursor
171: * (but hopefully that is all that %c terminals do
172: * with parms). Also, since tab and newline happen
173: * to be next to each other in ASCII, if tab were
174: * included a loop would be needed. Finally, note
175: * that lots of other processing is done here, so
176: * this hack won't always work (e.g. the Ann Arbor
177: * 4080, which uses %B and then %c.)
178: */
179: switch (op) {
180: /*
181: * Null. Problem is that our output is, by
182: * convention, null terminated.
183: */
184: case 0:
185: op = 0200; /* Parity should be ignored */
186: break;
187: /*
188: * Control D. Problem is that certain very
189: * ancient hardware hangs up on this, so the
190: * current (!) UNIX tty driver doesn't xmit
191: * control D's.
192: */
193: case CTRL(d):
194: /*
195: * Newline. Problem is that UNIX will expand
196: * this to CRLF.
197: */
198: case '\n':
199: xp = onrow ? cursor_down : cursor_right;
200: if (onrow && xp && op < lines-1 && cursor_up) {
201: op += 2;
202: xp = cursor_up;
203: }
204: if (xp && instring == cursor_address) {
205: strcat(added, xp);
206: op--;
207: }
208: break;
209: /*
210: * Tab used to be in this group too,
211: * because UNIX might expand it to blanks.
212: * We now require that this tab mode be turned
213: * off by any program using this routine,
214: * or using termcap in general, since some
215: * terminals use tab for other stuff, like
216: * nondestructive space. (Filters like ul
217: * or vcrt will lose, since they can't stty.)
218: * Tab was taken out to get the Ann Arbor
219: * 4080 to work.
220: */
221: }
222:
223: *outp++ = op;
224: (void) pop();
225: break;
226:
227: case 'l':
228: xp = (char *) pop();
229: push(strlen(xp));
230: break;
231:
232: case 's':
233: xp = (char *) pop();
234: while (*xp)
235: *outp++ = *xp++;
236: break;
237:
238: case '%':
239: *outp++ = c;
240: break;
241:
242: /*
243: * %i: shorthand for increment first two parms.
244: * Useful for terminals that start numbering from
245: * one instead of zero (like ANSI terminals).
246: */
247: case 'i':
248: p1++; p2++;
249: break;
250:
251: /* %pi: push the ith parameter */
252: case 'p':
253: switch (c = *cp++) {
254: case '1': push(p1); break;
255: case '2': push(p2); break;
256: case '3': push(p3); break;
257: case '4': push(p4); break;
258: case '5': push(p5); break;
259: case '6': push(p6); break;
260: case '7': push(p7); break;
261: case '8': push(p8); break;
262: case '9': push(p9); break;
263: default: return _err("bad parm number");
264: }
265: onrow = (c == '1');
266: break;
267:
268: /* %Pi: pop from stack into variable i (a-z) */
269: case 'P':
270: vars[*cp++ - 'a'] = pop();
271: break;
272:
273: /* %gi: push variable i (a-z) */
274: case 'g':
275: push(vars[*cp++ - 'a']);
276: break;
277:
278: /* %'c' : character constant */
279: case '\'':
280: push(*cp++);
281: if (*cp++ != '\'')
282: return _err("missing closing quote");
283: break;
284:
285: /* %{nn} : integer constant. */
286: case '{':
287: op = 0; sign = 1;
288: if (*cp == '-') {
289: sign = -1;
290: cp++;
291: } else if (*cp == '+')
292: cp++;
293: while ((c = *cp++) >= '0' && c <= '9') {
294: op = 10*op + c - '0';
295: }
296: if (c != '}')
297: return _err("missing closing brace");
298: push(sign * op);
299: break;
300:
301: /* binary operators */
302: case '+': c=pop(); op=pop(); push(op + c); break;
303: case '-': c=pop(); op=pop(); push(op - c); break;
304: case '*': c=pop(); op=pop(); push(op * c); break;
305: case '/': c=pop(); op=pop(); push(op / c); break;
306: case 'm': c=pop(); op=pop(); push(op % c); break; /* %m: mod */
307: case '&': c=pop(); op=pop(); push(op & c); break;
308: case '|': c=pop(); op=pop(); push(op | c); break;
309: case '^': c=pop(); op=pop(); push(op ^ c); break;
310: case '=': c=pop(); op=pop(); push(op = c); break;
311: case '>': c=pop(); op=pop(); push(op > c); break;
312: case '<': c=pop(); op=pop(); push(op < c); break;
313:
314: /* Unary operators. */
315: case '!': stack[top] = !stack[top]; break;
316: case '~': stack[top] = ~stack[top]; break;
317: /* Sorry, no unary minus, because minus is binary. */
318:
319: /*
320: * If-then-else. Implemented by a low level hack of
321: * skipping forward until the match is found, counting
322: * nested if-then-elses.
323: */
324: case '?': /* IF - just a marker */
325: break;
326:
327: case 't': /* THEN - branch if false */
328: if (!pop())
329: cp = _branchto(cp, 'e');
330: break;
331:
332: case 'e': /* ELSE - branch to ENDIF */
333: cp = _branchto(cp, ';');
334: break;
335:
336: case ';': /* ENDIF - just a marker */
337: break;
338:
339: default:
340: return _err("bad % sequence");
341: }
342: }
343: #ifdef tparmdebug
344: printf("part a: '");
345: _prstr(result);
346: printf("', len %d, part b: '", outp-result);
347: _prstr(added);
348: printf("'\n");
349: #endif
350: strcpy(outp, added);
351: return (result);
352: }
353:
354: static
355: char *
356: _err(msg)
357: char *msg;
358: {
359: #ifdef tparmdebug
360: write(2,"tparm: ", 7);
361: write(2, msg, strlen(msg));
362: write(2, "\r\n", 2);
363: #endif
364: return 0;
365: }
366:
367: char *
368: _branchto(cp, to)
369: register char *cp;
370: char to;
371: {
372: register int level = 0;
373: register char c;
374:
375: while (c = *cp++) {
376: if (c == '%') {
377: if ((c = *cp++) == to || c == ';') {
378: if (level == 0) {
379: return cp;
380: }
381: }
382: if (c == '?')
383: level++;
384: if (c == ';')
385: level--;
386: }
387: }
388: return _err("no matching ENDIF");
389: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.