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