xref: /plan9-contrib/sys/src/cmd/postscript/tr2post/Bgetfield.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "../common/common.h"
5 #include "tr2post.h"
6 
7 int
8 isspace(Rune r)
9 {
10 	return(r==' ' || r=='\t' || r=='\n' || r == '\r' || r=='\f');
11 }
12 
13 int
14 Bskipws(Biobufhdr *bp) {
15 	int r;
16 	char c[UTFmax];
17 	int sindex = 0;
18 
19 	/* skip over initial white space */
20 	do {
21 		r = Bgetrune(bp);
22 		if (r == '\n') inputlineno++;
23 		sindex++;
24 	} while (r>=0 && isspace(r));
25 	if (r<0) {
26 		return(-1);
27 	} else if (!isspace(r)) {
28 		Bungetrune(bp);
29 		--sindex;
30 	}
31 	return(sindex);
32 }
33 
34 int
35 asc2dig(char c, int base) {
36 	if (c >= '0' && c <= '9')
37 		if (base == 8 && c > '7') return(-1);
38 		else return(c - '0');
39 
40 	if (base == 16)
41 		if (c >= 'a' && c <= 'f') return(10 + c - 'a');
42 		else if (c >= 'A' && c <= 'F') return(10 + c - 'A');
43 
44 	return(-1);
45 }
46 
47 /* get a string of type: "d" for decimal integer, "u" for unsigned,
48  * "s" for string", "c" for char,
49  * return the number of characters gotten for the field.  If nothing
50  * was gotten and the end of file was reached, a negative value
51  * from the Bgetrune is returned.
52  */
53 
54 int
55 Bgetfield(Biobufhdr *bp, int type, void *thing, int size) {
56 	int r;
57 	Rune R;
58 	char c[UTFmax];
59 	int sindex = 0, i, j, n = 0;
60 	int negate = 0;
61 	int base = 10;
62 	BOOLEAN bailout = FALSE;
63 	int dig;
64 	unsigned int u = 0;
65 
66 	/* skip over initial white space */
67 	if (Bskipws(bp) < 0)
68 		return(-1);
69 
70 	switch (type) {
71 	case 'd':
72 		while (!bailout && (r = Bgetrune(bp))>=0) {
73 			switch (sindex++) {
74 			case 0:
75 				switch (r) {
76 				case '-':
77 					negate = 1;
78 					continue;
79 				case '+':
80 					continue;
81 				case '0':
82 					base = 8;
83 					continue;
84 				default:
85 					break;
86 				}
87 				break;
88 			case 1:
89 				if ((r == 'x' || r == 'X') && base == 8) {
90 					base = 16;
91 					continue;
92 				}
93 			}
94 			if ((dig = asc2dig(r, base)) == -1) bailout = TRUE;
95 			else n = dig + (n * base);
96 		}
97 		if (r < 0) return(-1);
98 		*(int *)thing = (negate)?-n:n;
99 		Bungetrune(bp);
100 		break;
101 	case 'u':
102 		while (!bailout && (r = Bgetrune(bp))>=0) {
103 			switch (sindex++) {
104 			case 0:
105 				if (*c == '0') {
106 					base = 8;
107 					continue;
108 				}
109 				break;
110 			case 1:
111 				if ((r == 'x' || r == 'X') && base == 8) {
112 					base = 16;
113 					continue;
114 				}
115 			}
116 			if ((dig = asc2dig(r, base)) == -1) bailout = TRUE;
117 			else u = dig + (n * base);
118 		}
119 		*(int *)thing = u;
120 		if (r < 0) return(-1);
121 		Bungetrune(bp);
122 		break;
123 	case 's':
124 		j = 0;
125 		while ((size>j+UTFmax) && (r = Bgetrune(bp))>=0 && !isspace(r)) {
126 			R = r;
127 			i = runetochar(&(((char *)thing)[j]), &R);
128 			j += i;
129 			sindex++;
130 		}
131 		((char *)thing)[j++] = '\0';
132 		if (r < 0) return(-1);
133 		Bungetrune(bp);
134 		break;
135 	case 'r':
136 		if ((r = Bgetrune(bp))>=0) {
137 			*(Rune *)thing = r;
138 			sindex++;
139 			return(sindex);
140 		}
141 		if (r <= 0) return(-1);
142 		Bungetrune(bp);
143 		break;
144 	default:
145 		return(-2);
146 	}
147 	if (r < 0 && sindex == 0)
148 		return(r);
149 	else if (bailout && sindex == 1) {
150 		return(0);
151 	} else
152 		return(sindex);
153 }
154