|
|
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.