an old saddle

This commit is contained in:
rsc 2005-01-04 21:24:19 +00:00
parent 24c02865d8
commit 020c80587a
7 changed files with 1559 additions and 0 deletions

372
src/cmd/proof/font.c Normal file
View file

@ -0,0 +1,372 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <bio.h>
#include "proof.h"
char fname[NFONT][20]; /* font names */
char lastload[NFONT][20]; /* last file name prefix loaded for this font */
Font *fonttab[NFONT][NSIZE]; /* pointers to fonts */
int fmap[NFONT]; /* what map to use with this font */
static void loadfont(int, int);
static void fontlookup(int, char *);
static void buildxheight(Biobuf*);
static void buildmap(Biobuf*);
static void buildtroff(char *);
static void addmap(int, char *, int);
static char *map(Rune*, int);
static void scanstr(char *, char *, char **);
int specfont; /* somehow, number of special font */
#define NMAP 5
#define QUICK 2048 /* char values less than this are quick to look up */
#define eq(s,t) strcmp((char *) s, (char *) t) == 0
int curmap = -1; /* what map are we working on */
typedef struct Link Link;
struct Link /* link names together */
{
uchar *name;
int val;
Link *next;
};
typedef struct Map Map;
struct Map /* holds a mapping from uchar name to index */
{
double xheight;
Rune quick[QUICK]; /* low values get special treatment */
Link *slow; /* other stuff goes into a link list */
};
Map charmap[5];
typedef struct Fontmap Fontmap;
struct Fontmap /* mapping from troff name to filename */
{
char *troffname;
char *prefix;
int map; /* which charmap to use for this font */
char *fallback; /* font to look in if can't find char here */
};
Fontmap fontmap[100];
int pos2fontmap[NFONT]; /* indexed by troff font position, gives Fontmap */
int nfontmap = 0; /* how many are there */
void
dochar(Rune r[])
{
char *s, *fb;
Font *f;
Point p;
int fontno, fm, i;
char buf[10];
fontno = curfont;
if((s = map(r, curfont)) == 0){ /* not on current font */
if ((s = map(r, specfont)) != 0) /* on special font */
fontno = specfont;
else{
/* look for fallback */
fm = pos2fontmap[curfont];
fb = fontmap[fm].fallback;
if(fb){
/* see if fallback is mounted */
for(i = 0; i < NFONT; i++){
if(eq(fb, fontmap[pos2fontmap[i]].troffname)){
s = map(r, i);
if(s){
fontno = i;
goto found;
}
}
}
}
/* no such char; use name itself on defont */
/* this is not a general solution */
p.x = hpos/DIV + xyoffset.x + offset.x;
p.y = vpos/DIV + xyoffset.y + offset.y;
p.y -= font->ascent;
sprint(buf, "%S", r);
string(screen, p, display->black, ZP, font, buf);
return;
}
}
found:
p.x = hpos/DIV + xyoffset.x + offset.x;
p.y = vpos/DIV + xyoffset.y + offset.y;
while ((f = fonttab[fontno][cursize]) == 0)
loadfont(fontno, cursize);
p.y -= f->ascent;
dprint(2, "putting %S at %d,%d font %d, size %d\n", r, p.x, p.y, fontno, cursize);
string(screen, p, display->black, ZP, f, s);
}
static int drawlog2[] = {
0, 0,
1, 1,
2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5
};
static void
loadfont(int n, int s)
{
char file[100];
int i, fd, t, deep;
static char *try[3] = {"", "times/R.", "pelm/"};
Subfont *f;
Font *ff;
try[0] = fname[n];
dprint(2, "loadfont %d %d\n", n, s);
for (t = 0; t < 3; t++){
i = s * mag * charmap[fmap[n]].xheight/0.72; /* a pixel is 0.72 points */
if (i < MINSIZE)
i = MINSIZE;
dprint(2, "size %d, i %d, mag %g\n", s, i, mag);
for(; i >= MINSIZE; i--){
/* if .font file exists, take that */
sprint(file, "%s/%s%d.font", libfont, try[t], i);
ff = openfont(display, file);
if(ff != 0){
fonttab[n][s] = ff;
dprint(2, "using %s for font %d %d\n", file, n, s);
return;
}
/* else look for a subfont file */
for (deep = drawlog2[screen->depth]; deep >= 0; deep--){
sprint(file, "%s/%s%d.%d", libfont, try[t], i, deep);
dprint(2, "trying %s for %d\n", file, i);
if ((fd = open(file, 0)) >= 0){
f = readsubfont(display, file, fd, 0);
if (f == 0) {
fprint(2, "can't rdsubfontfile %s: %r\n", file);
exits("rdsubfont");
}
close(fd);
ff = mkfont(f, 0);
if(ff == 0){
fprint(2, "can't mkfont %s: %r\n", file);
exits("rdsubfont");
}
fonttab[n][s] = ff;
dprint(2, "using %s for font %d %d\n", file, n, s);
return;
}
}
}
}
fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n], s);
exits("no font");
}
void
loadfontname(int n, char *s)
{
int i;
Font *f, *g = 0;
if (strcmp(s, fname[n]) == 0)
return;
if(fname[n] && fname[n][0]){
if(lastload[n] && strcmp(lastload[n], fname[n]) == 0)
return;
strcpy(lastload[n], fname[n]);
}
fontlookup(n, s);
for (i = 0; i < NSIZE; i++)
if (f = fonttab[n][i]){
if (f != g) {
freefont(f);
g = f;
}
fonttab[n][i] = 0;
}
}
void
allfree(void)
{
int i;
for (i=0; i<NFONT; i++)
loadfontname(i, "??");
}
void
readmapfile(char *file)
{
Biobuf *fp;
char *p, cmd[100];
if ((fp=Bopen(file, OREAD)) == 0){
fprint(2, "proof: can't open map file %s\n", file);
exits("urk");
}
while((p=Brdline(fp, '\n')) != 0) {
p[Blinelen(fp)-1] = 0;
scanstr(p, cmd, 0);
if(p[0]=='\0' || eq(cmd, "#")) /* skip comments, empty */
continue;
else if(eq(cmd, "xheight"))
buildxheight(fp);
else if(eq(cmd, "map"))
buildmap(fp);
else if(eq(cmd, "special"))
buildtroff(p);
else if(eq(cmd, "troff"))
buildtroff(p);
else
fprint(2, "weird map line %s\n", p);
}
Bterm(fp);
}
static void
buildxheight(Biobuf *fp) /* map goes from char name to value to print via *string() */
{
char *line;
line = Brdline(fp, '\n');
if(line == 0){
fprint(2, "proof: bad map file\n");
exits("map");
}
charmap[curmap].xheight = atof(line);
}
static void
buildmap(Biobuf *fp) /* map goes from char name to value to print via *string() */
{
uchar *p, *line, ch[100];
int val;
Rune r;
curmap++;
if(curmap >= NMAP){
fprint(2, "proof: out of char maps; recompile\n");
exits("charmap");
}
while ((line = Brdline(fp, '\n'))!= 0){
if (line[0] == '\n')
return;
line[Blinelen(fp)-1] = 0;
scanstr((char *) line, (char *) ch, (char **)(void*)&p);
if (ch[0] == '\0') {
fprint(2, "bad map file line '%s'\n", (char*)line);
continue;
}
val = strtol((char *) p, 0, 10);
dprint(2, "buildmap %s (%x %x) %s %d\n", (char*)ch, ch[0], ch[1], (char*)p, val);
chartorune(&r, (char*)ch);
if(utflen((char*)ch)==1 && r<QUICK)
charmap[curmap].quick[r] = val;
else
addmap(curmap, strdup((char *) ch), val); /* put somewhere else */
}
}
static void
addmap(int n, char *s, int val) /* stick a new link on */
{
Link *p = (Link *) malloc(sizeof(Link));
Link *prev = charmap[n].slow;
if(p == 0)
exits("out of memory in addmap");
p->name = (uchar *) s;
p->val = val;
p->next = prev;
charmap[n].slow = p;
}
static void
buildtroff(char *buf) /* map troff names into bitmap filenames */
{ /* e.g., R -> times/R., I -> times/I., etc. */
char *p, cmd[100], name[200], prefix[400], fallback[100];
scanstr(buf, cmd, &p);
scanstr(p, name, &p);
scanstr(p, prefix, &p);
while(*p!=0 && isspace(*p))
p++;
if(*p != 0){
scanstr(p, fallback, &p);
fontmap[nfontmap].fallback = strdup(fallback);
}else
fontmap[nfontmap].fallback = 0;
fontmap[nfontmap].troffname = strdup(name);
fontmap[nfontmap].prefix = strdup(prefix);
fontmap[nfontmap].map = curmap;
dprint(2, "troff name %s is bitmap %s map %d in slot %d fallback %s\n", name, prefix, curmap, nfontmap, fontmap[nfontmap].fallback? fontmap[nfontmap].fallback : "<null>");
nfontmap++;
}
static void
fontlookup(int n, char *s) /* map troff name of s into position n */
{
int i;
for(i = 0; i < nfontmap; i++)
if (eq(s, fontmap[i].troffname)) {
strcpy(fname[n], fontmap[i].prefix);
fmap[n] = fontmap[i].map;
pos2fontmap[n] = i;
if (eq(s, "S"))
specfont = n;
dprint(2, "font %d %s is %s\n", n, s, fname[n]);
return;
}
/* god help us if this font isn't there */
}
static char *
map(Rune rp[], int font) /* figure out mapping for char in this font */
{
static char s[100];
char c[10];
Link *p;
Rune r;
if(rp[1]==0 && rp[0]<QUICK) /* fast lookup */
r = charmap[fmap[font]].quick[rp[0]];
else { /* high-valued or compound character name */
sprint(c, "%S", rp);
r = 0;
for (p = charmap[fmap[font]].slow; p; p = p->next)
if(eq(c, p->name)){
r = p->val;
break;
}
}
if(r == 0){ /* not there */
dprint(2, "didn't find %S font# %d\n", rp, font);
return 0;
}
dprint(2, "map %S to %s font# %d\n", rp, s, font);
s[runetochar(s, &r)] = 0;
return s;
}
static void
scanstr(char *s, char *ans, char **ep)
{
for (; isspace((uchar) *s); s++)
;
for (; *s!=0 && !isspace((uchar) *s); )
*ans++ = *s++;
*ans = 0;
if (ep)
*ep = s;
}

579
src/cmd/proof/htroff.c Normal file
View file

@ -0,0 +1,579 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <cursor.h>
#include <event.h>
#include <bio.h>
#include "proof.h"
int res;
int hpos;
int vpos;
int DIV = 11;
Point offset;
Point xyoffset = { 0,0 };
Rectangle view[MAXVIEW];
Rectangle bound[MAXVIEW]; /* extreme points */
int nview = 1;
int lastp; /* last page number we were on */
#define NPAGENUMS 200
struct pagenum {
int num;
long adr;
} pagenums[NPAGENUMS];
int npagenums;
int curfont, cursize;
char *getcmdstr(void);
static void initpage(void);
static void view_setup(int);
static Point scale(Point);
static void clearview(Rectangle);
static int addpage(int);
static void spline(Image *, int, Point *);
static int skipto(int, int);
static void wiggly(int);
static void devcntrl(void);
static void eatline(void);
static int getn(void);
static int botpage(int);
static void getstr(char *);
/*
static void getutf(char *);
*/
#define Do screen->r.min
#define Dc screen->r.max
/* declarations and definitions of font stuff are in font.c and main.c */
static void
initpage(void)
{
int i;
view_setup(nview);
for (i = 0; i < nview-1; i++)
draw(screen, view[i], screen, nil, view[i+1].min);
clearview(view[nview-1]);
offset = view[nview-1].min;
vpos = 0;
}
static void
view_setup(int n)
{
int i, j, v, dx, dy, r, c;
switch (n) {
case 1: r = 1; c = 1; break;
case 2: r = 1; c = 2; break;
case 3: r = 1; c = 3; break;
case 4: r = 2; c = 2; break;
case 5: case 6: r = 2; c = 3; break;
case 7: case 8: case 9: r = 3; c = 3; break;
default: r = (n+2)/3; c = 3; break; /* finking out */
}
dx = (Dc.x - Do.x) / c;
dy = (Dc.y - Do.y) / r;
v = 0;
for (i = 0; i < r && v < n; i++)
for (j = 0; j < c && v < n; j++) {
view[v] = screen->r;
view[v].min.x = Do.x + j * dx;
view[v].max.x = Do.x + (j+1) * dx;
view[v].min.y = Do.y + i * dy;
view[v].max.y = Do.y + (i+1) * dy;
v++;
}
}
static void
clearview(Rectangle r)
{
draw(screen, r, display->white, nil, r.min);
}
int resized;
void eresized(int new)
{
/* this is called if we are resized */
if(new && getwindow(display, Refnone) < 0)
drawerror(display, "can't reattach to window");
initpage();
resized = 1;
}
static Point
scale(Point p)
{
p.x /= DIV;
p.y /= DIV;
return addpt(xyoffset, addpt(offset,p));
}
static int
addpage(int n)
{
int i;
for (i = 0; i < npagenums; i++)
if (n == pagenums[i].num)
return i;
if (npagenums < NPAGENUMS-1) {
pagenums[npagenums].num = n;
pagenums[npagenums].adr = offsetc();
npagenums++;
}
return npagenums;
}
void
readpage(void)
{
int c, i, a, alpha, phi;
static int first = 0;
int m, n, gonow = 1;
Rune r[32], t;
Point p,q,qq;
offset = screen->clipr.min;
esetcursor(&deadmouse);
while (gonow)
{
c = getc();
switch (c)
{
case -1:
esetcursor(0);
if (botpage(lastp+1)) {
initpage();
break;
}
exits(0);
case 'p': /* new page */
lastp = getn();
addpage(lastp);
if (first++ > 0) {
esetcursor(0);
botpage(lastp);
esetcursor(&deadmouse);
}
initpage();
break;
case '\n': /* when input is text */
case ' ':
case 0: /* occasional noise creeps in */
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* two motion digits plus a character */
hpos += (c-'0')*10 + getc()-'0';
/* FALLS THROUGH */
case 'c': /* single ascii character */
r[0] = getrune();
r[1] = 0;
dochar(r);
break;
case 'C':
for(i=0; ; i++){
t = getrune();
if(isspace(t))
break;
r[i] = t;
}
r[i] = 0;
dochar(r);
break;
case 'N':
r[0] = getn();
r[1] = 0;
dochar(r);
break;
case 'D': /* draw function */
switch (getc())
{
case 'l': /* draw a line */
n = getn();
m = getn();
p = Pt(hpos,vpos);
q = addpt(p, Pt(n,m));
hpos += n;
vpos += m;
line(screen, scale(p), scale(q), 0, 0, 0, display->black, ZP);
break;
case 'c': /* circle */
/*nop*/
m = getn()/2;
p = Pt(hpos+m,vpos);
hpos += 2*m;
ellipse(screen, scale(p), m/DIV, m/DIV, 0, display->black, ZP);
/* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,ONES,Mode*/
break;
case 'e': /* ellipse */
/*nop*/
m = getn()/2;
n = getn()/2;
p = Pt(hpos+m,vpos);
hpos += 2*m;
ellipse(screen, scale(p), m/DIV, n/DIV, 0, display->black, ZP);
break;
case 'a': /* arc */
p = scale(Pt(hpos,vpos));
n = getn();
m = getn();
hpos += n;
vpos += m;
q = scale(Pt(hpos,vpos));
n = getn();
m = getn();
hpos += n;
vpos += m;
qq = scale(Pt(hpos,vpos));
/*
* tricky: convert from 3-point clockwise to
* center, angle1, delta-angle counterclockwise.
*/
a = hypot(qq.x-q.x, qq.y-q.y);
phi = atan2(q.y-p.y, p.x-q.x)*180./PI;
alpha = atan2(q.y-qq.y, qq.x-q.x)*180./PI - phi;
if(alpha < 0)
alpha += 360;
arc(screen, q, a, a, 0, display->black, ZP, phi, alpha);
break;
case '~': /* wiggly line */
wiggly(0);
break;
default:
break;
}
eatline();
break;
case 's':
n = getn(); /* ignore fractional sizes */
if (cursize == n)
break;
cursize = n;
if (cursize >= NFONT)
cursize = NFONT-1;
break;
case 'f':
curfont = getn();
break;
case 'H': /* absolute horizontal motion */
hpos = getn();
break;
case 'h': /* relative horizontal motion */
hpos += getn();
break;
case 'w': /* word space */
break;
case 'V':
vpos = getn();
break;
case 'v':
vpos += getn();
break;
case '#': /* comment */
case 'n': /* end of line */
eatline();
break;
case 'x': /* device control */
devcntrl();
break;
default:
fprint(2, "unknown input character %o %c at offset %lud\n", c, c, offsetc());
exits("bad char");
}
}
esetcursor(0);
}
static void
spline(Image *b, int n, Point *pp)
{
long w, t1, t2, t3, fac=1000;
int i, j, steps=10;
Point p, q;
for (i = n; i > 0; i--)
pp[i] = pp[i-1];
pp[n+1] = pp[n];
n += 2;
p = pp[0];
for(i = 0; i < n-2; i++)
{
for(j = 0; j < steps; j++)
{
w = fac * j / steps;
t1 = w * w / (2 * fac);
w = w - fac/2;
t2 = 3*fac/4 - w * w / fac;
w = w - fac/2;
t3 = w * w / (2*fac);
q.x = (t1*pp[i+2].x + t2*pp[i+1].x +
t3*pp[i].x + fac/2) / fac;
q.y = (t1*pp[i+2].y + t2*pp[i+1].y +
t3*pp[i].y + fac/2) / fac;
line(b, p, q, 0, 0, 0, display->black, ZP);
p = q;
}
}
}
/* Have to parse skipped pages, to find out what fonts are loaded. */
static int
skipto(int gotop, int curp)
{
char *p;
int i;
if (gotop == curp)
return 1;
for (i = 0; i < npagenums; i++)
if (pagenums[i].num == gotop) {
if (seekc(pagenums[i].adr) == Beof) {
fprint(2, "can't rewind input\n");
return 0;
}
return 1;
}
if (gotop <= curp) {
restart:
if (seekc(0) == Beof) {
fprint(2, "can't rewind input\n");
return 0;
}
}
for(;;){
p = rdlinec();
if (p == 0) {
if(gotop>curp){
gotop = curp;
goto restart;
}
return 0;
} else if (*p == 'p') {
lastp = curp = atoi(p+1);
addpage(lastp); /* maybe 1 too high */
if (curp>=gotop)
return 1;
}
}
}
static void
wiggly(int skip)
{
Point p[300];
int c,i,n;
for (n = 1; (c = getc()) != '\n' && c>=0; n++) {
ungetc();
p[n].x = getn();
p[n].y = getn();
}
p[0] = Pt(hpos, vpos);
for (i = 1; i < n; i++)
p[i] = addpt(p[i],p[i-1]);
hpos = p[n-1].x;
vpos = p[n-1].y;
for (i = 0; i < n; i++)
p[i] = scale(p[i]);
if (!skip)
spline(screen,n,p);
}
static void
devcntrl(void) /* interpret device control functions */
{
char str[80];
int n;
getstr(str);
switch (str[0]) { /* crude for now */
case 'i': /* initialize */
break;
case 'T': /* device name */
getstr(devname);
break;
case 't': /* trailer */
break;
case 'p': /* pause -- can restart */
break;
case 's': /* stop */
break;
case 'r': /* resolution assumed when prepared */
res=getn();
DIV = floor(.5 + res/(100.0*mag));
if (DIV < 1)
DIV = 1;
mag = res/(100.0*DIV); /* adjust mag according to DIV coarseness */
break;
case 'f': /* font used */
n = getn();
getstr(str);
loadfontname(n, str);
break;
/* these don't belong here... */
case 'H': /* char height */
break;
case 'S': /* slant */
break;
case 'X':
break;
}
eatline();
}
int
isspace(int c)
{
return c==' ' || c=='\t' || c=='\n';
}
static void
getstr(char *is)
{
uchar *s = (uchar *) is;
for (*s = getc(); isspace(*s); *s = getc())
;
for (; !isspace(*s); *++s = getc())
;
ungetc();
*s = 0;
}
#if 0
static void
getutf(char *s) /* get next utf char, as bytes */
{
int c, i;
for (i=0;;) {
c = getc();
if (c < 0)
return;
s[i++] = c;
if (fullrune(s, i)) {
s[i] = 0;
return;
}
}
}
#endif
static void
eatline(void)
{
int c;
while ((c=getc()) != '\n' && c >= 0)
;
}
static int
getn(void)
{
int n, c, sign;
while (c = getc())
if (!isspace(c))
break;
if(c == '-'){
sign = -1;
c = getc();
}else
sign = 1;
for (n = 0; '0'<=c && c<='9'; c = getc())
n = n*10 + c - '0';
while (c == ' ')
c = getc();
ungetc();
return(n*sign);
}
static int
botpage(int np) /* called at bottom of page np-1 == top of page np */
{
char *p;
int n;
while (p = getcmdstr()) {
if (*p == '\0')
return 0;
if (*p == 'q')
exits(p);
if (*p == 'c') /* nop */
continue;
if (*p == 'm') {
mag = atof(p+1);
if (mag <= .1 || mag >= 10)
mag = DEFMAG;
allfree(); /* zap fonts */
DIV = floor(.5 + res/(100.0*mag));
if (DIV < 1)
DIV = 1;
mag = res/(100.0*DIV);
return skipto(np-1, np); /* reprint the page */
}
if (*p == 'x') {
xyoffset.x += atoi(p+1)*100;
skipto(np-1, np);
return 1;
}
if (*p == 'y') {
xyoffset.y += atoi(p+1)*100;
skipto(np-1, np);
return 1;
}
if (*p == '/') { /* divide into n pieces */
nview = atoi(p+1);
if (nview < 1)
nview = 1;
else if (nview > MAXVIEW)
nview = MAXVIEW;
return skipto(np-1, np);
}
if (*p == 'p') {
if (p[1] == '\0'){ /* bare 'p' */
if(skipto(np-1, np))
return 1;
continue;
}
p++;
}
if ('0'<=*p && *p<='9') {
n = atoi(p);
if(skipto(n, np))
return 1;
continue;
}
if (*p == '-' || *p == '+') {
n = atoi(p);
if (n == 0)
n = *p == '-' ? -1 : 1;
if(skipto(np - 1 + n, np))
return 1;
continue;
}
if (*p == 'd') {
dbg = 1 - dbg;
continue;
}
fprint(2, "illegal; try q, 17, +2, -1, p, m.7, /2, x1, y-.5 or return\n");
}
return 0;
}

226
src/cmd/proof/main.c Normal file
View file

@ -0,0 +1,226 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <bio.h>
#include "proof.h"
Rectangle rpage = { 0, 0, 850, 1150 };
char devname[64];
double mag = DEFMAG;
int dbg = 0;
char *track = 0;
Biobuf bin;
char *libfont = "#9/font";
char *mapfile = "MAP";
char *mapname = "MAP";
void
usage(void)
{
fprint(2, "usage: proof [-m mag] [-/ nview] [-x xoff] [-y yoff] [-M mapfile] [-F fontdir] [-dt] file...\n");
exits("usage");
}
double
getnum(char *s)
{
if(s == nil)
usage();
return atof(s);
}
char*
getstr(char *s)
{
if(s == nil)
usage();
return s;
}
void
main(int argc, char *argv[])
{
char c;
int dotrack = 0;
libfont = unsharp(libfont);
ARGBEGIN{
case 'm': /* magnification */
mag = getnum(ARGF());
if (mag < 0.1 || mag > 10){
fprint(2, "ridiculous mag argument ignored\n");
mag = DEFMAG;
}
break;
case '/':
nview = getnum(ARGF());
if (nview < 1 || nview > MAXVIEW)
nview = 1;
break;
case 'x':
xyoffset.x += getnum(ARGF()) * 100;
break;
case 'y':
xyoffset.y += getnum(ARGF()) * 100;
break;
case 'M': /* change MAP file */
mapname = EARGF(usage());
break;
case 'F': /* change /lib/font/bit directory */
libfont = EARGF(usage());
break;
case 'd':
dbg = 1;
break;
case 't':
dotrack = 1;
break;
default:
usage();
}ARGEND
if (argc > 0) {
close(0);
if (open(argv[0], 0) != 0) {
sysfatal("can't open %s: %r\n", argv[0]);
exits("open failure");
}
if(dotrack)
track = argv[0];
}
Binit(&bin, 0, OREAD);
mapfile = smprint("%s/%s", libfont, mapname);
readmapfile(mapfile);
for (c = 0; c < NFONT; c++)
loadfontname(c, "??");
mapscreen();
clearscreen();
readpage();
}
/*
* Input buffer to allow us to back up
*/
#define SIZE 100000 /* 8-10 pages, typically */
char bufc[SIZE];
char *inc = bufc; /* where next input character goes */
char *outc = bufc; /* next character to be read from buffer */
int off; /* position of outc in total input stream */
void
addc(int c)
{
*inc++ = c;
if(inc == &bufc[SIZE])
inc = &bufc[0];
}
int
getc(void)
{
int c;
if(outc == inc){
c = Bgetc(&bin);
if(c == Beof)
return Beof;
addc(c);
}
off++;
c = *outc++;
if(outc == &bufc[SIZE])
outc = &bufc[0];
return c;
}
int
getrune(void)
{
int c, n;
Rune r;
char buf[UTFmax];
for(n=0; !fullrune(buf, n); n++){
c = getc();
if(c == Beof)
return Beof;
buf[n] = c;
}
chartorune(&r, buf);
return r;
}
int
nbuf(void) /* return number of buffered characters */
{
int ini, outi;
ini = inc-bufc;
outi = outc-bufc;
if(ini < outi)
ini += SIZE;
return ini-outi;
}
ulong
seekc(ulong o)
{
ulong avail;
long delta;
delta = off-o;
if(delta < 0)
return Beof;
avail = SIZE-nbuf();
if(delta < avail){
off = o;
outc -= delta;
if(outc < &bufc[0])
outc += SIZE;
return off;
}
return Beof;
}
void
ungetc(void)
{
if(off == 0)
return;
if(nbuf() == SIZE){
fprint(2, "backup buffer overflow\n");
return;
}
if(outc == &bufc[0])
outc = &bufc[SIZE];
--outc;
--off;
}
ulong
offsetc(void)
{
return off;
}
char*
rdlinec(void)
{
static char buf[2048];
int c, i;
for(i=0; i<sizeof buf; ){
c = getc();
if(c == Beof)
break;
buf[i++] = c;
if(c == '\n')
break;
}
if(i == 0)
return nil;
return buf;
}

14
src/cmd/proof/mkfile Normal file
View file

@ -0,0 +1,14 @@
<$PLAN9/src/mkhdr
TARG=proof
OFILES=main.$O\
font.$O\
htroff.$O\
screen.$O\
HFILES=proof.h
<$PLAN9/src/mkone
$O.pout: $OFILES
$LD -o $O.pout -p $OFILES

5
src/cmd/proof/portdate Normal file
View file

@ -0,0 +1,5 @@
font.c 2004/1225
htroff.c 2004/1225
main.c 2004/1225
proof.h 2004/1225
screen.c 2004/1225

48
src/cmd/proof/proof.h Normal file
View file

@ -0,0 +1,48 @@
#include <cursor.h>
#undef isspace
#define NPAGES 500
#define NFONT 33
#define NSIZE 40
#define MINSIZE 4
#define DEFMAG (10.0/11.0) /* was (10.0/11.0), then 1 */
#define MAXVIEW 40
#define ONES ~0
extern char devname[];
extern double mag;
extern int nview;
extern int hpos, vpos, curfont, cursize;
extern int DIV, res;
extern int Mode;
extern Point offset; /* for small pages within big page */
extern Point xyoffset; /* for explicit x,y move */
extern Cursor deadmouse;
extern char *libfont;
void mapscreen(void);
void clearscreen(void);
char *getcmdstr(void);
void readmapfile(char *);
void dochar(Rune*);
void bufput(void);
void loadfontname(int, char *);
void allfree(void);
void readpage(void);
int isspace(int);
extern int getc(void);
extern int getrune(void);
extern void ungetc(void);
extern ulong offsetc(void);
extern ulong seekc(ulong);
extern char* rdlinec(void);
#define dprint if (dbg) fprint
extern int dbg;
extern int resized;

315
src/cmd/proof/screen.c Normal file
View file

@ -0,0 +1,315 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <cursor.h>
#include <event.h>
#include <bio.h>
#include "proof.h"
static int checkmouse(void);
/* static int buttondown(void); */
static char *getmousestr(void);
static char *getkbdstr(int);
extern Cursor blot;
extern char *track;
Mouse mouse;
void
mapscreen(void)
{
if(initdraw(0, 0, "proof") < 0){
fprint(2, "proof: initdraw failed: %r\n");
exits("initdraw");
}
einit(Ekeyboard|Emouse);
}
void
clearscreen(void)
{
draw(screen, screen->r, display->black, nil, ZP);
}
void
screenprint(char *fmt, ...)
{
char buf[100];
Point p;
va_list args;
va_start(args, fmt);
vseprint(buf, &buf[sizeof buf], fmt, args);
va_end(args);
p = Pt(screen->clipr.min.x+40, screen->clipr.max.y-40);
string(screen, p, display->black, ZP, font, buf);
}
#define Viewkey 0xb2
#define etimer(x, y) 0
char *
getcmdstr(void)
{
Event ev;
int e;
static ulong timekey = 0;
ulong tracktm = 0;
Dir *dir;
if(track){
if(timekey == 0)
timekey = etimer(0, 5000);
dir = dirstat(track);
if(dir != nil){
tracktm = dir->mtime;
free(dir);
}
}
for (;;) {
e = event(&ev);
if(resized){
resized = 0;
return "p";
}
if ((e & Emouse) && ev.mouse.buttons) {
mouse = ev.mouse;
return getmousestr();
} else if (e & Ekeyboard)
return getkbdstr(ev.kbdc); /* sadly, no way to unget */
else if (e & timekey) {
if((dir = dirstat(track)) != nil){
if(tracktm < dir->mtime){
free(dir);
return "q";
}
free(dir);
}
}
}
return nil;
}
static char *
getkbdstr(int c0)
{
static char buf[100];
char *p;
int c;
if (c0 == '\n')
return "";
buf[0] = c0;
buf[1] = 0;
screenprint("%s", buf);
for (p = buf+1; (c = ekbd()) != '\n' && c != '\r' && c != -1 && c != Viewkey; ) {
if (c == '\b' && p > buf) {
*--p = ' ';
} else {
*p++ = c;
*p = 0;
}
screenprint("%s", buf);
}
*p = 0;
return buf;
}
#define button3(b) ((b) & 4)
#define button2(b) ((b) & 2)
#define button1(b) ((b) & 1)
#define button23(b) ((b) & 6)
#define button123(b) ((b) & 7)
#define butcvt(b) (1 << ((b) - 1))
#if 0
static int buttondown(void) /* report state of buttons, if any */
{
if (!ecanmouse()) /* no event pending */
return 0;
mouse = emouse(); /* something, but it could be motion */
return mouse.buttons & 7;
}
#endif
int waitdown(void) /* wait until some button is down */
{
while (!(mouse.buttons & 7))
mouse = emouse();
return mouse.buttons & 7;
}
int waitup(void)
{
while (mouse.buttons & 7)
mouse = emouse();
return mouse.buttons & 7;
}
char *m3[] = { "next", "prev", "page n", "again", "bigger", "smaller", "pan", "quit?", 0 };
char *m2[] = { 0 };
enum { Next = 0, Prev, Page, Again, Bigger, Smaller, Pan, Quit };
Menu mbut3 = { m3, 0, 0 };
Menu mbut2 = { m2, 0, 0 };
int last_hit;
int last_but;
char *pan(void)
{
Point dd, xy, lastxy, min, max;
esetcursor(&blot);
waitdown();
xy = mouse.xy;
do{
lastxy = mouse.xy;
mouse = emouse();
dd = subpt(mouse.xy, lastxy);
min = addpt(screen->clipr.min, dd);
max = addpt(screen->clipr.max, dd);
draw(screen, rectaddpt(screen->r, subpt(mouse.xy, lastxy)),
screen, nil, screen->r.min);
if(mouse.xy.x < lastxy.x) /* moved left, clear right */
draw(screen, Rect(max.x, screen->r.min.y, screen->r.max.x, screen->r.max.y),
display->white, nil, ZP);
else /* moved right, clear left*/
draw(screen, Rect(screen->r.min.x, screen->r.min.y, min.x, screen->r.max.y),
display->white, nil, ZP);
if(mouse.xy.y < lastxy.y) /* moved up, clear down */
draw(screen, Rect(screen->r.min.x, max.y, screen->r.max.x, screen->r.max.y),
display->white, nil, ZP);
else /* moved down, clear up */
draw(screen, Rect(screen->r.min.x, screen->r.min.y, screen->r.max.x, min.y),
display->white, nil, ZP);
flushimage(display, 1);
}while(mouse.buttons);
xyoffset = addpt(xyoffset, subpt(mouse.xy, xy));
esetcursor(0);
return "p";
}
static char *getmousestr(void)
{
static char buf[20];
checkmouse();
if (last_but == 1)
return "p"; /* repaint after panning */
if (last_but == 2) {
return "c";
} else if (last_but == 3) {
switch (last_hit) {
case Next:
return "";
case Prev:
return "-1";
case Page:
screenprint("page? ");
return "c";
case Again:
return "p";
case Bigger:
sprint(buf, "m%g", mag * 1.1);
return buf;
case Smaller:
sprint(buf, "m%g", mag / 1.1);
return buf;
case Pan:
return pan();
case Quit:
return "q";
default:
return "c";
}
} else { /* button 1 or bail out */
return "c";
}
}
static int
checkmouse(void) /* return button touched if any */
{
int c, b;
char *p;
extern int confirm(int);
b = waitdown();
last_but = 0;
last_hit = -1;
c = 0;
if (button3(b)) {
last_hit = emenuhit(3, &mouse, &mbut3);
last_but = 3;
} else if (button2(b)) {
last_hit = emenuhit(2, &mouse, &mbut2);
last_but = 2;
} else { /* button1() */
pan();
last_but = 1;
}
waitup();
if (last_but == 3 && last_hit >= 0) {
p = m3[last_hit];
c = p[strlen(p) - 1];
}
if (c == '?' && !confirm(last_but))
last_hit = -1;
return last_but;
}
Cursor deadmouse = {
{ 0, 0}, /* offset */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41,
0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0,
0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41,
0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0,
0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
};
Cursor blot ={
{ 0, 0 },
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }
};
Cursor skull ={
{ 0, 0 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
};
int
confirm(int but) /* ask for confirmation if menu item ends with '?' */
{
int c;
static int but_cvt[8] = { 0, 1, 2, 0, 3, 0, 0, 0 };
esetcursor(&skull);
c = waitdown();
waitup();
esetcursor(0);
return but == but_cvt[c];
}