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 nroff driving table format */
     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' || *s == '\0'))
     47 			break;
     48 		if (*s != '\\')
     49 			*t++ = *s++;
     50 		else {
     51 			s++;	/* skip \\ */
     52 			if (isdigit((uchar)s[0]) && isdigit((uchar)s[1]) && isdigit((uchar)s[2])) {
     53 				*t++ = (s[0]-'0')<<6 | (s[1]-'0')<<3 | s[2]-'0';
     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 alphabetic character is itself */
     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-graphics */
    105 			chtemp[n].num = ch[0];
    106 		} else if (ch[0] == '\\' && ch[1] == '0') {
    107 			n = strtol(ch+1, 0, 0);	/* \0octal or \0xhex */
    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, devname WARN;
    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, Notype));
    217 		else if (is("twrest")) t.twrest = strdupl(parse(opt, Notype));
    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, Notype));
    224 		else if (is("iton")) t.iton = strdupl(parse(opt, Notype));
    225 		else if (is("itoff")) t.itoff = strdupl(parse(opt, Notype));
    226 		else if (is("ploton")) t.ploton = strdupl(parse(opt, Notype));
    227 		else if (is("plotoff")) t.plotoff = strdupl(parse(opt, Notype));
    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, Notype));
    231 		else if (is("left")) t.left = strdupl(parse(opt, Notype));
    232 		else
    233 			ERROR "bad tab.%s file, %s %s", devname, cmd, opt WARN;
    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.bdoff); break;
    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 & 0377)) {
    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 == BDFONT || xfont == BIFONT))
    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 really understood */
    382 /* fprintf(stderr, "big char %d, name %s\n", k, chname(k)); /* */
    383 			oputs(chname(k)+1);	/* BUG: should separate Troffchar and MBchar... */
    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 separate Troffchar and MBchar... */
    387 		} else if (t.tfont.wp[k].str[0] == MBchar) {	/* parse() puts this on */
    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 by default */
    394 			while (*codep != 0) {
    395 				if (*codep & 0200) {
    396 					codep = plot(codep);
    397 					oput(' ');
    398 				} else {
    399 					if (*codep == '%')	/* escape */
    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 turns it off */
    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)) <= esc) {
    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 }