xref: /inferno-os/appl/lib/strokes/readstrokes.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Readstrokes;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth#
4*37da2899SCharles.Forsyth# read structures from stroke classifier files
5*37da2899SCharles.Forsyth#
6*37da2899SCharles.Forsyth
7*37da2899SCharles.Forsythinclude "sys.m";
8*37da2899SCharles.Forsyth	sys: Sys;
9*37da2899SCharles.Forsyth
10*37da2899SCharles.Forsythinclude "bufio.m";
11*37da2899SCharles.Forsyth	bufio: Bufio;
12*37da2899SCharles.Forsyth	Iobuf: import bufio;
13*37da2899SCharles.Forsyth
14*37da2899SCharles.Forsythinclude "strokes.m";
15*37da2899SCharles.Forsyth	strokes: Strokes;
16*37da2899SCharles.Forsyth	Classifier, Penpoint, Stroke, Region: import strokes;
17*37da2899SCharles.Forsyth	buildstrokes: Buildstrokes;
18*37da2899SCharles.Forsyth
19*37da2899SCharles.Forsythinit(s: Strokes)
20*37da2899SCharles.Forsyth{
21*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
22*37da2899SCharles.Forsyth	bufio = load Bufio Bufio->PATH;
23*37da2899SCharles.Forsyth	strokes = s;
24*37da2899SCharles.Forsyth}
25*37da2899SCharles.Forsyth
26*37da2899SCharles.Forsythgetint(fp: ref Iobuf): (int, int)
27*37da2899SCharles.Forsyth{
28*37da2899SCharles.Forsyth	while((c := fp.getc()) == ' ' || c == '\t' || c == '\n')
29*37da2899SCharles.Forsyth		;
30*37da2899SCharles.Forsyth	if(c < 0)
31*37da2899SCharles.Forsyth		return (c, 0);
32*37da2899SCharles.Forsyth	sign := 1;
33*37da2899SCharles.Forsyth	if(c == '-')
34*37da2899SCharles.Forsyth		sign = -1;
35*37da2899SCharles.Forsyth	else if(c == '+')
36*37da2899SCharles.Forsyth		;
37*37da2899SCharles.Forsyth	else
38*37da2899SCharles.Forsyth		fp.ungetc();
39*37da2899SCharles.Forsyth	rc := 0;
40*37da2899SCharles.Forsyth	n := 0;
41*37da2899SCharles.Forsyth	while((c = fp.getc()) >= '0' && c <= '9'){
42*37da2899SCharles.Forsyth		n = n*10 + (c-'0');
43*37da2899SCharles.Forsyth		rc = 1;
44*37da2899SCharles.Forsyth	}
45*37da2899SCharles.Forsyth	return (rc, n*sign);
46*37da2899SCharles.Forsyth}
47*37da2899SCharles.Forsyth
48*37da2899SCharles.Forsythgetstr(fp: ref Iobuf): (int, string)
49*37da2899SCharles.Forsyth{
50*37da2899SCharles.Forsyth	while((c := fp.getc()) == ' ' || c == '\t' || c == '\n')
51*37da2899SCharles.Forsyth		;
52*37da2899SCharles.Forsyth	if(c < 0)
53*37da2899SCharles.Forsyth		return (c, nil);
54*37da2899SCharles.Forsyth	fp.ungetc();
55*37da2899SCharles.Forsyth	s := "";
56*37da2899SCharles.Forsyth	while((c = fp.getc()) != ' ' && c != '\t' && c != '\n')
57*37da2899SCharles.Forsyth		s[len s] = c;
58*37da2899SCharles.Forsyth	return (0, s);
59*37da2899SCharles.Forsyth}
60*37da2899SCharles.Forsyth
61*37da2899SCharles.Forsythgetpoint(fp: ref Iobuf): (int, Penpoint)
62*37da2899SCharles.Forsyth{
63*37da2899SCharles.Forsyth	(okx, x) := getint(fp);
64*37da2899SCharles.Forsyth	(oky, y) := getint(fp);
65*37da2899SCharles.Forsyth	if(okx <= 0 || oky <= 0)
66*37da2899SCharles.Forsyth		return (-1, (0,0,0));
67*37da2899SCharles.Forsyth	return (0, (x,y,0));
68*37da2899SCharles.Forsyth}
69*37da2899SCharles.Forsyth
70*37da2899SCharles.Forsythgetpoints(fp: ref Iobuf): ref Stroke
71*37da2899SCharles.Forsyth{
72*37da2899SCharles.Forsyth	(ok, npts) := getint(fp);
73*37da2899SCharles.Forsyth	if(ok <= 0 || npts < 0 || npts > 4000)
74*37da2899SCharles.Forsyth		return nil;
75*37da2899SCharles.Forsyth	pts := array[npts] of Penpoint;
76*37da2899SCharles.Forsyth	for(i := 0; i < npts; i++){
77*37da2899SCharles.Forsyth		(ok, pts[i]) = getpoint(fp);
78*37da2899SCharles.Forsyth		if(ok < 0)
79*37da2899SCharles.Forsyth			return nil;
80*37da2899SCharles.Forsyth	}
81*37da2899SCharles.Forsyth	return ref Stroke(npts, pts, 0, 0);
82*37da2899SCharles.Forsyth}
83*37da2899SCharles.Forsyth
84*37da2899SCharles.Forsythread_classifier_points(fp: ref Iobuf, nclass: int): (int, array of string, array of list of ref Stroke)
85*37da2899SCharles.Forsyth{
86*37da2899SCharles.Forsyth	names := array[nclass] of string;
87*37da2899SCharles.Forsyth	examples := array[nclass] of list of ref Stroke;
88*37da2899SCharles.Forsyth	for(k := 0; k < nclass; k++){
89*37da2899SCharles.Forsyth		# read class name and number of examples
90*37da2899SCharles.Forsyth		(ok, nex) := getint(fp);
91*37da2899SCharles.Forsyth		if(ok <= 0)
92*37da2899SCharles.Forsyth			return (-1, nil, nil);
93*37da2899SCharles.Forsyth		(ok, names[k]) = getstr(fp);
94*37da2899SCharles.Forsyth		if(ok < 0)
95*37da2899SCharles.Forsyth			return (ok, nil, nil);
96*37da2899SCharles.Forsyth
97*37da2899SCharles.Forsyth		# read examples
98*37da2899SCharles.Forsyth		for(i := 0; i < nex; i++){
99*37da2899SCharles.Forsyth			pts := getpoints(fp);
100*37da2899SCharles.Forsyth			if(pts == nil)
101*37da2899SCharles.Forsyth				return (-1, nil, nil);
102*37da2899SCharles.Forsyth			examples[k] = pts :: examples[k];
103*37da2899SCharles.Forsyth		}
104*37da2899SCharles.Forsyth	}
105*37da2899SCharles.Forsyth	return (0, names, examples);
106*37da2899SCharles.Forsyth}
107*37da2899SCharles.Forsyth
108*37da2899SCharles.Forsyth#
109*37da2899SCharles.Forsyth# read a classifier, using its digest if that exists
110*37da2899SCharles.Forsyth#
111*37da2899SCharles.Forsythread_classifier(file: string, build: int, needex: int): (string, ref Classifier)
112*37da2899SCharles.Forsyth{
113*37da2899SCharles.Forsyth	rc := ref Classifier;
114*37da2899SCharles.Forsyth	l := len file;
115*37da2899SCharles.Forsyth	digestfile: string;
116*37da2899SCharles.Forsyth	if(l >= 4 && file[l-4:]==".clx")
117*37da2899SCharles.Forsyth		digestfile = file;
118*37da2899SCharles.Forsyth	else if(!needex && l >= 3 && file[l-3:]==".cl")
119*37da2899SCharles.Forsyth		digestfile = file[0:l-3]+".clx";	# try the digest file first
120*37da2899SCharles.Forsyth	err: string;
121*37da2899SCharles.Forsyth	if(digestfile != nil){
122*37da2899SCharles.Forsyth		fd := sys->open(digestfile, Sys->OREAD);
123*37da2899SCharles.Forsyth		if(fd != nil){
124*37da2899SCharles.Forsyth			(err, rc.cnames, rc.dompts) = read_digest(fd);
125*37da2899SCharles.Forsyth			rc.nclasses = len rc.cnames;
126*37da2899SCharles.Forsyth			if(rc.cnames == nil)
127*37da2899SCharles.Forsyth				err = "empty digest file";
128*37da2899SCharles.Forsyth			if(err == nil)
129*37da2899SCharles.Forsyth				return (nil, rc);
130*37da2899SCharles.Forsyth		}else
131*37da2899SCharles.Forsyth			err = sys->sprint("%r");
132*37da2899SCharles.Forsyth		if(!build)
133*37da2899SCharles.Forsyth			return (sys->sprint("digest file: %s", err), nil);
134*37da2899SCharles.Forsyth	}
135*37da2899SCharles.Forsyth
136*37da2899SCharles.Forsyth	if(buildstrokes == nil){
137*37da2899SCharles.Forsyth		buildstrokes = load Buildstrokes Buildstrokes->PATH;
138*37da2899SCharles.Forsyth		if(buildstrokes == nil)
139*37da2899SCharles.Forsyth			return (sys->sprint("module %s: %r", Buildstrokes->PATH), nil);
140*37da2899SCharles.Forsyth		buildstrokes->init(strokes);
141*37da2899SCharles.Forsyth	}
142*37da2899SCharles.Forsyth
143*37da2899SCharles.Forsyth	fd := sys->open(file, Sys->OREAD);
144*37da2899SCharles.Forsyth	if(fd == nil)
145*37da2899SCharles.Forsyth		return (sys->sprint("%r"), nil);
146*37da2899SCharles.Forsyth	(emsg, cnames, examples) := read_examples(fd);
147*37da2899SCharles.Forsyth	if(emsg != nil)
148*37da2899SCharles.Forsyth		return (emsg, nil);
149*37da2899SCharles.Forsyth	rc.nclasses = len cnames;
150*37da2899SCharles.Forsyth	(err, rc.canonex, rc.dompts) = buildstrokes->canonical_example(rc.nclasses, cnames, examples);
151*37da2899SCharles.Forsyth	if(err != nil)
152*37da2899SCharles.Forsyth		return ("failed to calculate canonical examples", nil);
153*37da2899SCharles.Forsyth	rc.cnames = cnames;
154*37da2899SCharles.Forsyth	if(needex)
155*37da2899SCharles.Forsyth		rc.examples = examples;
156*37da2899SCharles.Forsyth
157*37da2899SCharles.Forsyth	return (nil, rc);
158*37da2899SCharles.Forsyth}
159*37da2899SCharles.Forsyth
160*37da2899SCharles.Forsythread_examples(fd: ref Sys->FD): (string, array of string, array of list of ref Strokes->Stroke)
161*37da2899SCharles.Forsyth{
162*37da2899SCharles.Forsyth	fp := bufio->fopen(fd, Bufio->OREAD);
163*37da2899SCharles.Forsyth	(ok, nclasses) := getint(fp);
164*37da2899SCharles.Forsyth	if(ok <= 0)
165*37da2899SCharles.Forsyth		return ("missing number of classes", nil, nil);
166*37da2899SCharles.Forsyth	(okc, cnames, examples) := read_classifier_points(fp, nclasses);
167*37da2899SCharles.Forsyth	if(okc < 0)
168*37da2899SCharles.Forsyth		return ("couldn't read examples", nil, nil);
169*37da2899SCharles.Forsyth	return (nil, cnames, examples);
170*37da2899SCharles.Forsyth}
171*37da2899SCharles.Forsyth
172*37da2899SCharles.Forsyth#
173*37da2899SCharles.Forsyth# attempt to read the digest of a classifier,
174*37da2899SCharles.Forsyth# and return its contents if successful;
175*37da2899SCharles.Forsyth# return a diagnostic if not
176*37da2899SCharles.Forsyth#
177*37da2899SCharles.Forsythread_digest(fd: ref Sys->FD): (string, array of string, array of ref Stroke)
178*37da2899SCharles.Forsyth{
179*37da2899SCharles.Forsyth	#  Read-in the name and dominant points for each class.
180*37da2899SCharles.Forsyth	fp := bufio->fopen(fd, Bufio->OREAD);
181*37da2899SCharles.Forsyth	cnames := array[32] of string;
182*37da2899SCharles.Forsyth	dompts := array[32] of ref Stroke;
183*37da2899SCharles.Forsyth	for(nclasses := 0;; nclasses++){
184*37da2899SCharles.Forsyth		if(nclasses >= len cnames){
185*37da2899SCharles.Forsyth			a := array[nclasses+32] of string;
186*37da2899SCharles.Forsyth			a[0:] = cnames;
187*37da2899SCharles.Forsyth			cnames = a;
188*37da2899SCharles.Forsyth			b := array[nclasses+32] of ref Stroke;
189*37da2899SCharles.Forsyth			b[0:] = dompts;
190*37da2899SCharles.Forsyth			dompts = b;
191*37da2899SCharles.Forsyth		}
192*37da2899SCharles.Forsyth		(okn, class) := getstr(fp);
193*37da2899SCharles.Forsyth		if(okn == Bufio->EOF)
194*37da2899SCharles.Forsyth			break;
195*37da2899SCharles.Forsyth		if(class == nil)
196*37da2899SCharles.Forsyth			return ("expected class name", nil, nil);
197*37da2899SCharles.Forsyth		cnames[nclasses] = class;
198*37da2899SCharles.Forsyth		dpts := getpoints(fp);
199*37da2899SCharles.Forsyth		if(dpts == nil)
200*37da2899SCharles.Forsyth			return ("bad points list", nil, nil);
201*37da2899SCharles.Forsyth		strokes->compute_chain_code(dpts);
202*37da2899SCharles.Forsyth		dompts[nclasses] = dpts;
203*37da2899SCharles.Forsyth	}
204*37da2899SCharles.Forsyth	return (nil, cnames[0:nclasses], dompts[0:nclasses]);
205*37da2899SCharles.Forsyth}
206