| n10.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| n10.c (11599B) | |
| --- | |
| 1 /* | |
| 2 n10.c | |
| 3 | |
| 4 Device interfaces | |
| 5 */ | |
| 6 | |
| 7 #include <u.h> | |
| 8 #include "tdef.h" | |
| 9 #include "ext.h" | |
| 10 #include "fns.h" | |
| 11 #include <ctype.h> | |
| 12 | |
| 13 Term t; /* terminal characteristics */ | |
| 14 | |
| 15 int dtab; | |
| 16 int plotmode; | |
| 17 int esct; | |
| 18 | |
| 19 enum { Notype = 0, Type = 1 }; | |
| 20 | |
| 21 static char *parse(char *s, int typeit) /* convert \0, etc to nro… | |
| 22 { /* typeit => add a type id to the front for later use */ | |
| 23 static char buf[100], *t, *obuf; | |
| 24 int quote = 0; | |
| 25 wchar_t wc; | |
| 26 | |
| 27 obuf = typeit == Type ? buf : buf+1; | |
| 28 #ifdef UNICODE | |
| 29 if (mbtowc(&wc, s, strlen(s)) > 1) { /* it's multibyte, */ | |
| 30 buf[0] = MBchar; | |
| 31 strcpy(buf+1, s); | |
| 32 return obuf; | |
| 33 } /* so just hand it back */ | |
| 34 #endif /*UNICODE*/ | |
| 35 buf[0] = Troffchar; | |
| 36 t = buf + 1; | |
| 37 if (*s == '"') { | |
| 38 s++; | |
| 39 quote = 1; | |
| 40 } | |
| 41 for (;;) { | |
| 42 if (quote && *s == '"') { | |
| 43 s++; | |
| 44 break; | |
| 45 } | |
| 46 if (!quote && (*s == ' ' || *s == '\t' || *s == '\n' || … | |
| 47 break; | |
| 48 if (*s != '\\') | |
| 49 *t++ = *s++; | |
| 50 else { | |
| 51 s++; /* skip \\ */ | |
| 52 if (isdigit((uchar)s[0]) && isdigit((uchar)s[1])… | |
| 53 *t++ = (s[0]-'0')<<6 | (s[1]-'0')<<3 | s… | |
| 54 s += 2; | |
| 55 } else if (isdigit((uchar)s[0])) { | |
| 56 *t++ = *s - '0'; | |
| 57 } else if (*s == 'b') { | |
| 58 *t++ = '\b'; | |
| 59 } else if (*s == 'n') { | |
| 60 *t++ = '\n'; | |
| 61 } else if (*s == 'r') { | |
| 62 *t++ = '\r'; | |
| 63 } else if (*s == 't') { | |
| 64 *t++ = '\t'; | |
| 65 } else { | |
| 66 *t++ = *s; | |
| 67 } | |
| 68 s++; | |
| 69 } | |
| 70 } | |
| 71 *t = '\0'; | |
| 72 return obuf; | |
| 73 } | |
| 74 | |
| 75 | |
| 76 static int getnrfont(FILE *fp) /* read the nroff description file… | |
| 77 { | |
| 78 Chwid chtemp[NCHARS]; | |
| 79 static Chwid chinit; | |
| 80 int i, nw, n, wid, code, type; | |
| 81 char buf[100], ch[100], s1[100], s2[100]; | |
| 82 wchar_t wc; | |
| 83 | |
| 84 code = 0; | |
| 85 chinit.wid = 1; | |
| 86 chinit.str = ""; | |
| 87 for (i = 0; i < ALPHABET; i++) { | |
| 88 chtemp[i] = chinit; /* zero out to begin with */ | |
| 89 chtemp[i].num = chtemp[i].code = i; /* every alph… | |
| 90 chtemp[i].wid = 1; /* default ascii widths */ | |
| 91 } | |
| 92 skipline(fp); | |
| 93 nw = ALPHABET; | |
| 94 while (fgets(buf, sizeof buf, fp) != NULL) { | |
| 95 sscanf(buf, "%s %s %[^\n]", ch, s1, s2); | |
| 96 if (!eq(s1, "\"")) { /* genuine new character */ | |
| 97 sscanf(s1, "%d", &wid); | |
| 98 } /* else it's a synonym for prev character, */ | |
| 99 /* so leave previous values intact */ | |
| 100 | |
| 101 /* decide what kind of alphabet it might come from */ | |
| 102 | |
| 103 if (strlen(ch) == 1) { /* it's ascii */ | |
| 104 n = ch[0]; /* origin includes non-graphic… | |
| 105 chtemp[n].num = ch[0]; | |
| 106 } else if (ch[0] == '\\' && ch[1] == '0') { | |
| 107 n = strtol(ch+1, 0, 0); /* \0octal or \0x… | |
| 108 chtemp[n].num = n; | |
| 109 #ifdef UNICODE | |
| 110 } else if (mbtowc(&wc, ch, strlen(ch)) > 1) { | |
| 111 chtemp[nw].num = chadd(ch, MBchar, Install); | |
| 112 n = nw; | |
| 113 nw++; | |
| 114 #endif /*UNICODE*/ | |
| 115 } else { | |
| 116 if (strcmp(ch, "---") == 0) { /* no name */ | |
| 117 sprintf(ch, "%d", code); | |
| 118 type = Number; | |
| 119 } else | |
| 120 type = Troffchar; | |
| 121 /* BUG in here somewhere when same character occurs twice in table */ | |
| 122 chtemp[nw].num = chadd(ch, type, Install); | |
| 123 n = nw; | |
| 124 nw++; | |
| 125 } | |
| 126 chtemp[n].wid = wid; | |
| 127 chtemp[n].str = strdupl(parse(s2, Type)); | |
| 128 } | |
| 129 t.tfont.nchars = nw; | |
| 130 t.tfont.wp = (Chwid *) malloc(nw * sizeof(Chwid)); | |
| 131 if (t.tfont.wp == NULL) | |
| 132 return -1; | |
| 133 for (i = 0; i < nw; i++) | |
| 134 t.tfont.wp[i] = chtemp[i]; | |
| 135 return 1; | |
| 136 } | |
| 137 | |
| 138 | |
| 139 void n_ptinit(void) | |
| 140 { | |
| 141 int i; | |
| 142 char *p; | |
| 143 char opt[50], cmd[100]; | |
| 144 FILE *fp; | |
| 145 | |
| 146 hmot = n_hmot; | |
| 147 makem = n_makem; | |
| 148 setabs = n_setabs; | |
| 149 setch = n_setch; | |
| 150 sethl = n_sethl; | |
| 151 setht = n_setht; | |
| 152 setslant = n_setslant; | |
| 153 vmot = n_vmot; | |
| 154 xlss = n_xlss; | |
| 155 findft = n_findft; | |
| 156 width = n_width; | |
| 157 mchbits = n_mchbits; | |
| 158 ptlead = n_ptlead; | |
| 159 ptout = n_ptout; | |
| 160 ptpause = n_ptpause; | |
| 161 setfont = n_setfont; | |
| 162 setps = n_setps; | |
| 163 setwd = n_setwd; | |
| 164 | |
| 165 if ((p = getenv("NROFFTERM")) != 0) | |
| 166 strcpy(devname, p); | |
| 167 if (termtab[0] == 0) | |
| 168 strcpy(termtab,DWBntermdir); | |
| 169 if (fontdir[0] == 0) | |
| 170 strcpy(fontdir, ""); | |
| 171 if (devname[0] == 0) | |
| 172 strcpy(devname, NDEVNAME); | |
| 173 pl = 11*INCH; | |
| 174 po = PO; | |
| 175 hyf = 0; | |
| 176 ascii = 1; | |
| 177 lg = 0; | |
| 178 fontlab[1] = 'R'; | |
| 179 fontlab[2] = 'I'; | |
| 180 fontlab[3] = 'B'; | |
| 181 fontlab[4] = PAIR('B','I'); | |
| 182 fontlab[5] = 'D'; | |
| 183 bdtab[3] = 3; | |
| 184 bdtab[4] = 3; | |
| 185 | |
| 186 /* hyphalg = 0; /* for testing */ | |
| 187 | |
| 188 strcat(termtab, devname); | |
| 189 if ((fp = fopen(unsharp(termtab), "r")) == NULL) { | |
| 190 ERROR "cannot open %s", termtab WARN; | |
| 191 exit(-1); | |
| 192 } | |
| 193 | |
| 194 | |
| 195 /* this loop isn't robust about input format errors. */ | |
| 196 /* it assumes name, name-value pairs..., charset */ | |
| 197 /* god help us if we get out of sync. */ | |
| 198 | |
| 199 fscanf(fp, "%s", cmd); /* should be device name... */ | |
| 200 if (!is(devname) && trace) | |
| 201 ERROR "wrong terminal name: saw %s, wanted %s", cmd, dev… | |
| 202 for (;;) { | |
| 203 fscanf(fp, "%s", cmd); | |
| 204 if (is("charset")) | |
| 205 break; | |
| 206 fscanf(fp, " %[^\n]", opt); | |
| 207 if (is("bset")) t.bset = atoi(opt); | |
| 208 else if (is("breset")) t.breset = atoi(opt); | |
| 209 else if (is("Hor")) t.Hor = atoi(opt); | |
| 210 else if (is("Vert")) t.Vert = atoi(opt); | |
| 211 else if (is("Newline")) t.Newline = atoi(opt); | |
| 212 else if (is("Char")) t.Char = atoi(opt); | |
| 213 else if (is("Em")) t.Em = atoi(opt); | |
| 214 else if (is("Halfline")) t.Halfline = atoi(opt); | |
| 215 else if (is("Adj")) t.Adj = atoi(opt); | |
| 216 else if (is("twinit")) t.twinit = strdupl(parse(opt, Not… | |
| 217 else if (is("twrest")) t.twrest = strdupl(parse(opt, Not… | |
| 218 else if (is("twnl")) t.twnl = strdupl(parse(opt, Notype)… | |
| 219 else if (is("hlr")) t.hlr = strdupl(parse(opt, Notype)); | |
| 220 else if (is("hlf")) t.hlf = strdupl(parse(opt, Notype)); | |
| 221 else if (is("flr")) t.flr = strdupl(parse(opt, Notype)); | |
| 222 else if (is("bdon")) t.bdon = strdupl(parse(opt, Notype)… | |
| 223 else if (is("bdoff")) t.bdoff = strdupl(parse(opt, Notyp… | |
| 224 else if (is("iton")) t.iton = strdupl(parse(opt, Notype)… | |
| 225 else if (is("itoff")) t.itoff = strdupl(parse(opt, Notyp… | |
| 226 else if (is("ploton")) t.ploton = strdupl(parse(opt, Not… | |
| 227 else if (is("plotoff")) t.plotoff = strdupl(parse(opt, N… | |
| 228 else if (is("up")) t.up = strdupl(parse(opt, Notype)); | |
| 229 else if (is("down")) t.down = strdupl(parse(opt, Notype)… | |
| 230 else if (is("right")) t.right = strdupl(parse(opt, Notyp… | |
| 231 else if (is("left")) t.left = strdupl(parse(opt, Notype)… | |
| 232 else | |
| 233 ERROR "bad tab.%s file, %s %s", devname, cmd, op… | |
| 234 } | |
| 235 | |
| 236 getnrfont(fp); | |
| 237 fclose(fp); | |
| 238 | |
| 239 sps = EM; | |
| 240 ics = EM * 2; | |
| 241 dtab = 8 * t.Em; | |
| 242 for (i = 0; i < 16; i++) | |
| 243 tabtab[i] = dtab * (i + 1); | |
| 244 pl = 11 * INCH; | |
| 245 po = PO; | |
| 246 spacesz = SS; | |
| 247 lss = lss1 = VS; | |
| 248 ll = ll1 = lt = lt1 = LL; | |
| 249 smnt = nfonts = 5; /* R I B BI S */ | |
| 250 n_specnames(); /* install names like "hyphen", etc. */ | |
| 251 if (eqflg) | |
| 252 t.Adj = t.Hor; | |
| 253 } | |
| 254 | |
| 255 | |
| 256 void n_specnames(void) | |
| 257 { | |
| 258 | |
| 259 int i; | |
| 260 | |
| 261 for (i = 0; spnames[i].n; i++) | |
| 262 *spnames[i].n = chadd(spnames[i].v, Troffchar, Install); | |
| 263 if (c_isalnum == 0) | |
| 264 c_isalnum = NROFFCHARS; | |
| 265 } | |
| 266 | |
| 267 void twdone(void) | |
| 268 { | |
| 269 if (!TROFF && t.twrest) { | |
| 270 obufp = obuf; | |
| 271 oputs(t.twrest); | |
| 272 flusho(); | |
| 273 if (pipeflg) { | |
| 274 pclose(ptid); | |
| 275 } | |
| 276 restore_tty(); | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 | |
| 281 void n_ptout(Tchar i) | |
| 282 { | |
| 283 *olinep++ = i; | |
| 284 if (olinep >= &oline[LNSIZE]) | |
| 285 olinep--; | |
| 286 if (cbits(i) != '\n') | |
| 287 return; | |
| 288 olinep--; | |
| 289 lead += dip->blss + lss - t.Newline; | |
| 290 dip->blss = 0; | |
| 291 esct = esc = 0; | |
| 292 if (olinep > oline) { | |
| 293 move(); | |
| 294 ptout1(); | |
| 295 oputs(t.twnl); | |
| 296 } else { | |
| 297 lead += t.Newline; | |
| 298 move(); | |
| 299 } | |
| 300 lead += dip->alss; | |
| 301 dip->alss = 0; | |
| 302 olinep = oline; | |
| 303 } | |
| 304 | |
| 305 | |
| 306 void ptout1(void) | |
| 307 { | |
| 308 int k; | |
| 309 char *codep; | |
| 310 int w, j, phyw; | |
| 311 Tchar *q, i; | |
| 312 static int oxfont = FT; /* start off in roman */ | |
| 313 | |
| 314 for (q = oline; q < olinep; q++) { | |
| 315 i = *q; | |
| 316 if (ismot(i)) { | |
| 317 j = absmot(i); | |
| 318 if (isnmot(i)) | |
| 319 j = -j; | |
| 320 if (isvmot(i)) | |
| 321 lead += j; | |
| 322 else | |
| 323 esc += j; | |
| 324 continue; | |
| 325 } | |
| 326 if ((k = cbits(i)) <= ' ') { | |
| 327 switch (k) { | |
| 328 case ' ': /*space*/ | |
| 329 esc += t.Char; | |
| 330 break; | |
| 331 case '\033': | |
| 332 case '\007': | |
| 333 case '\016': | |
| 334 case '\017': | |
| 335 oput(k); | |
| 336 break; | |
| 337 } | |
| 338 continue; | |
| 339 } | |
| 340 phyw = w = t.Char * t.tfont.wp[k].wid; | |
| 341 if (iszbit(i)) | |
| 342 w = 0; | |
| 343 if (esc || lead) | |
| 344 move(); | |
| 345 esct += w; | |
| 346 xfont = fbits(i); | |
| 347 if (xfont != oxfont) { | |
| 348 switch (oxfont) { | |
| 349 case ULFONT: oputs(t.itoff); break; | |
| 350 case BDFONT: oputs(t.bdoff); break; | |
| 351 case BIFONT: oputs(t.itoff); oputs(t.bdof… | |
| 352 } | |
| 353 switch (xfont) { | |
| 354 case ULFONT: | |
| 355 if (*t.iton & 0377) oputs(t.iton); break; | |
| 356 case BDFONT: | |
| 357 if (*t.bdon & 0377) oputs(t.bdon); break; | |
| 358 case BIFONT: | |
| 359 if (*t.bdon & 0377) oputs(t.bdon); | |
| 360 if (*t.iton & 0377) oputs(t.iton); | |
| 361 break; | |
| 362 } | |
| 363 oxfont = xfont; | |
| 364 } | |
| 365 if ((xfont == ulfont || xfont == BIFONT) && !(*t.iton & … | |
| 366 for (j = w / t.Char; j > 0; j--) | |
| 367 oput('_'); | |
| 368 for (j = w / t.Char; j > 0; j--) | |
| 369 oput('\b'); | |
| 370 } | |
| 371 if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) || xfont ==… | |
| 372 j++; | |
| 373 else | |
| 374 j = 1; /* number of overstrikes for bold … | |
| 375 if (k < ALPHABET) { /* ordinary ascii */ | |
| 376 oput(k); | |
| 377 while (--j > 0) { | |
| 378 oput('\b'); | |
| 379 oput(k); | |
| 380 } | |
| 381 } else if (k >= t.tfont.nchars) { /* BUG -- not r… | |
| 382 /* fprintf(stderr, "big char %d, name %s\n", k, chname(k)); /* */ | |
| 383 oputs(chname(k)+1); /* BUG: should separa… | |
| 384 } else if (t.tfont.wp[k].str == 0) { | |
| 385 /* fprintf(stderr, "nostr char %d, name %s\n", k, chname(k)); /* */ | |
| 386 oputs(chname(k)+1); /* BUG: should separa… | |
| 387 } else if (t.tfont.wp[k].str[0] == MBchar) { /* p… | |
| 388 /* fprintf(stderr, "MBstr char %d, name %s\n", k, chname(k)); /* */ | |
| 389 oputs(t.tfont.wp[k].str+1); | |
| 390 } else { | |
| 391 int oj = j; | |
| 392 /* fprintf(stderr, "str char %d, name %s\n", k, chname(k)); /* */ | |
| 393 codep = t.tfont.wp[k].str+1; /* Troffchar… | |
| 394 while (*codep != 0) { | |
| 395 if (*codep & 0200) { | |
| 396 codep = plot(codep); | |
| 397 oput(' '); | |
| 398 } else { | |
| 399 if (*codep == '%') /* esc… | |
| 400 codep++; | |
| 401 oput(*codep); | |
| 402 if (*codep == '\033') | |
| 403 oput(*++codep); | |
| 404 else if (*codep != '\b') | |
| 405 for (j = oj; --j > 0; ) { | |
| 406 oput('\b'); | |
| 407 oput(*codep); | |
| 408 } | |
| 409 codep++; | |
| 410 } | |
| 411 } | |
| 412 } | |
| 413 if (!w) | |
| 414 for (j = phyw / t.Char; j > 0; j--) | |
| 415 oput('\b'); | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 | |
| 420 char *plot(char *x) | |
| 421 { | |
| 422 int i; | |
| 423 char *j, *k; | |
| 424 | |
| 425 oputs(t.ploton); | |
| 426 k = x; | |
| 427 if ((*k & 0377) == 0200) | |
| 428 k++; | |
| 429 for (; *k; k++) { | |
| 430 if (*k == '%') { /* quote char within plot mode */ | |
| 431 oput(*++k); | |
| 432 } else if (*k & 0200) { | |
| 433 if (*k & 0100) { | |
| 434 if (*k & 040) | |
| 435 j = t.up; | |
| 436 else | |
| 437 j = t.down; | |
| 438 } else { | |
| 439 if (*k & 040) | |
| 440 j = t.left; | |
| 441 else | |
| 442 j = t.right; | |
| 443 } | |
| 444 if ((i = *k & 037) == 0) { /* 2nd 0200 tu… | |
| 445 ++k; | |
| 446 break; | |
| 447 } | |
| 448 while (i--) | |
| 449 oputs(j); | |
| 450 } else | |
| 451 oput(*k); | |
| 452 } | |
| 453 oputs(t.plotoff); | |
| 454 return(k); | |
| 455 } | |
| 456 | |
| 457 | |
| 458 void move(void) | |
| 459 { | |
| 460 int k; | |
| 461 char *i, *j; | |
| 462 char *p, *q; | |
| 463 int iesct, dt; | |
| 464 | |
| 465 iesct = esct; | |
| 466 if (esct += esc) | |
| 467 i = "\0"; | |
| 468 else | |
| 469 i = "\n\0"; | |
| 470 j = t.hlf; | |
| 471 p = t.right; | |
| 472 q = t.down; | |
| 473 if (lead) { | |
| 474 if (lead < 0) { | |
| 475 lead = -lead; | |
| 476 i = t.flr; | |
| 477 /* if(!esct)i = t.flr; else i = "\0";*/ | |
| 478 j = t.hlr; | |
| 479 q = t.up; | |
| 480 } | |
| 481 if (*i & 0377) { | |
| 482 k = lead / t.Newline; | |
| 483 lead = lead % t.Newline; | |
| 484 while (k--) | |
| 485 oputs(i); | |
| 486 } | |
| 487 if (*j & 0377) { | |
| 488 k = lead / t.Halfline; | |
| 489 lead = lead % t.Halfline; | |
| 490 while (k--) | |
| 491 oputs(j); | |
| 492 } else { /* no half-line forward, not at line begining */ | |
| 493 k = lead / t.Newline; | |
| 494 lead = lead % t.Newline; | |
| 495 if (k > 0) | |
| 496 esc = esct; | |
| 497 i = "\n"; | |
| 498 while (k--) | |
| 499 oputs(i); | |
| 500 } | |
| 501 } | |
| 502 if (esc) { | |
| 503 if (esc < 0) { | |
| 504 esc = -esc; | |
| 505 j = "\b"; | |
| 506 p = t.left; | |
| 507 } else { | |
| 508 j = " "; | |
| 509 if (hflg) | |
| 510 while ((dt = dtab - (iesct % dtab)) <= e… | |
| 511 if (dt % t.Em) | |
| 512 break; | |
| 513 oput(TAB); | |
| 514 esc -= dt; | |
| 515 iesct += dt; | |
| 516 } | |
| 517 } | |
| 518 k = esc / t.Em; | |
| 519 esc = esc % t.Em; | |
| 520 while (k--) | |
| 521 oputs(j); | |
| 522 } | |
| 523 if ((*t.ploton & 0377) && (esc || lead)) { | |
| 524 oputs(t.ploton); | |
| 525 esc /= t.Hor; | |
| 526 lead /= t.Vert; | |
| 527 while (esc--) | |
| 528 oputs(p); | |
| 529 while (lead--) | |
| 530 oputs(q); | |
| 531 oputs(t.plotoff); | |
| 532 } | |
| 533 esc = lead = 0; | |
| 534 } | |
| 535 | |
| 536 | |
| 537 void n_ptlead(void) | |
| 538 { | |
| 539 move(); | |
| 540 } | |
| 541 | |
| 542 | |
| 543 void n_ptpause(void ) | |
| 544 { | |
| 545 char junk; | |
| 546 | |
| 547 flusho(); | |
| 548 read(2, &junk, 1); | |
| 549 } |