comparison toys/pending/printf.c @ 1645:2ffee259f519 draft

Another cleanup pass on printf.
author Rob Landley <rob@landley.net>
date Sat, 03 Jan 2015 20:31:41 -0600
parents 54c092c3ee38
children 35c035b7e3e0
comparison
equal deleted inserted replaced
1644:492bd41f8b9a 1645:2ffee259f519
25 char *hv_w; 25 char *hv_w;
26 char *hv_p; 26 char *hv_p;
27 int encountered; 27 int encountered;
28 ) 28 )
29 29
30 // Calculate width and precision from format string 30 // Detect matching character (return true/valse) and advance pointer if match.
31 static int get_w_p() 31 static int eat(char **s, char c)
32 { 32 {
33 char *ptr, *str = *toys.optargs; 33 int x = (**s == c);
34 34
35 errno = 0; 35 if (x) ++*s;
36 if (*str == '-') str++;
37 long value = strtol(str, &ptr, 10);
38 if (errno || (ptr && (*ptr != '\0' || ptr == str)))
39 perror_msg("Invalid num %s", *toys.optargs);
40 if (*--str == '-') return (int)(-1 * value);
41 36
42 return value; 37 return x;
43 } 38 }
44 39
45 // Add ll and L to Interger and floating point formats respectively. 40 // Add ll and L to Interger and floating point formats respectively.
46 static char *get_format(char *f) 41 static char *get_format(char *f)
47 { 42 {
99 } else if (*ptr == 'c') printf(fmt, arg ? *arg : 0); 94 } else if (*ptr == 'c') printf(fmt, arg ? *arg : 0);
100 95
101 if (format) free(format); 96 if (format) free(format);
102 } 97 }
103 98
104 // Handle the escape sequences. 99 // Parse escape sequences.
105 static int handle_slash(char **esc_val) 100 static int handle_slash(char **esc_val)
106 { 101 {
107 char *ptr = *esc_val; 102 char *ptr = *esc_val;
108 int esc_length = 0; 103 int len = 1, base = 0;
109 unsigned base = 0, num = 0, result = 0, count = 0; 104 unsigned result = 0;
110 105
111 /* 106 if (*ptr == 'c') xexit();
112 * Hex escape sequence have only 1 or 2 digits, xHH. Oct escape sequence
113 * have 1,2 or 3 digits, xHHH. Leading "0" (\0HHH) we are ignoring.
114 */
115 if (*ptr == 'x') {
116 ptr++;
117 esc_length++;
118 base = 16;
119 } else if (isdigit(*ptr)) base = 8;
120 107
121 while (esc_length < 3 && base) { 108 // 0x12 hex escapes have 1-2 digits, \123 octal escapes have 1-3 digits.
122 num = tolower(*ptr) - '0'; 109 if (eat(&ptr, 'x')) base = 16;
123 if (num > 10) num += ('0' - 'a' + 10); 110 else if (*ptr >= '0' && *ptr <= '8') base = 8;
111 len += (base-8)/8;
112
113 // Not a hex or octal escape? (This catches trailing \)
114 if (!len) {
115 if (!(result = unescape(*ptr))) result = '\\';
116 else ++*esc_val;
117
118 return result;
119 }
120
121 while (len) {
122 unsigned num = tolower(*ptr)-'0';
123
124 if (num > 10) num += '0'-'a'+10;
124 if (num >= base) { 125 if (num >= base) {
125 if (base == 16) { 126 // Don't parse invalid hex value ala "\xvd", print it verbatim
126 esc_length--; 127 if (base == 16 && len == 2) {
127 if (!esc_length) {// Invalid hex value eg. /xvd, print as it is /xvd 128 ptr--;
128 result = '\\'; 129 result = '\\';
129 ptr--;
130 }
131 } 130 }
132 break; 131 break;
133 } 132 }
134 esc_length++; 133 result = (result*base)+num;
135 count = result = (count * base) + num;
136 ptr++; 134 ptr++;
137 } 135 len--;
138 if (base) ptr--;
139 else if (!(result = unescape(*ptr))) {
140 result = '\\';
141 ptr--; // Let pointer pointing to / we will increment after returning.
142 } 136 }
143 *esc_val = ptr; 137 *esc_val = ptr;
138
144 return (char)result; 139 return (char)result;
145 }
146
147 // Handle "%b" option with '\' interpreted.
148 static void print_esc_str(char *str)
149 {
150 for (; *str; str++) {
151 if (*str == '\\') {
152 str++;
153 xputc(handle_slash(&str)); //print corresponding char
154 } else xputc(*str);
155 }
156 }
157
158 // Parse the format string and print.
159 static void parse_print(char *format)
160 {
161 char *start, *p, *f = format;
162 int len = 0, width = 0, prec = 0;
163
164 while (*f) {
165 if (*f == '%') {
166 start = f++;
167 len++;
168 if (*f == '%') {
169 xputc('%');
170 break;
171 }
172 if (*f == 'b') {
173 if (*toys.optargs) {
174 print_esc_str(*toys.optargs++);
175 TT.encountered = 1;
176 } else print_esc_str("");
177 break;
178 }
179 if (strchr("-+# ", *f)) f++, len++;
180 if (*f == '*') {
181 f++, len++;
182 if (*toys.optargs) {
183 width = get_w_p();
184 toys.optargs++;
185 }
186 } else while (isdigit(*f)) f++, len++;
187
188 if (*f == '.') {
189 f++, len++;
190 if (*f == '*') {
191 f++, len++;
192 if (*toys.optargs) {
193 prec = get_w_p();
194 toys.optargs++;
195 }
196 } else {
197 while (isdigit(*f)) f++, len++;
198 }
199 }
200 if (!(p = strchr("diouxXfeEgGcs", *f)))
201 perror_exit("bad format@%ld", f-format);
202 else {
203 len++;
204 TT.hv_p = strstr(start, ".*");
205 TT.hv_w = strchr(start, '*');
206 //pitfall: handle diff b/w * and .*
207 if ((TT.hv_w-1) == TT.hv_p) TT.hv_w = NULL;
208 memcpy((p = xzalloc(len+1)), start, len);
209 print(p+len-1, width, prec);
210 if (*toys.optargs) toys.optargs++;
211 free(p);
212 p = NULL;
213 }
214 TT.encountered = 1;
215 } else if (*f == '\\' && f[1]) {
216 if (*++f == 'c') exit(0); //Got '\c', so no further output
217 xputc(handle_slash(&f));
218 } else xputc(*f);
219 f++;
220 len = 0;
221 }
222 } 140 }
223 141
224 void printf_main(void) 142 void printf_main(void)
225 { 143 {
226 char *format = *toys.optargs++; 144 char *format = *toys.optargs, **arg = toys.optargs+1, *f, *p;
227 145
228 TT.encountered = 0; 146 for (f = format; *f; f++) {
229 parse_print(format); //printf acc. to format. 147 if (eat(&f, '\\')) putchar(handle_slash(&f));
230 //Re-use FORMAT arg as necessary to convert all given ARGS. 148 else if (*f != '%' || *++f == '%') xputc(*f);
231 while (*toys.optargs && TT.encountered) parse_print(format); 149 else if (*f == 'b')
232 xflush(); 150 for (p = *arg ? *(arg++) : ""; *p; p++)
151 putchar(eat(&p, '\\') ? handle_slash(&p) : *p);
152 else {
153 char *start = f;
154 int wp[2], i;
155
156 // todo: we currently ignore these?
157 if (strchr("-+# ", *f)) f++;
158 memset(wp, 0, 8);
159 for (i=0; i<2; i++) {
160 if (eat(&f, '*')) {
161 if (*arg) wp[i] = atolx(*(arg++));
162 } else while (isdigit(*f)) f++;
163 if (!eat(&f, '.')) break;
164 }
165 if (!(p = strchr("diouxXfeEgGcs", *f)))
166 perror_exit("bad format@%ld", f-format);
167 else {
168 int len = f-start;
169
170 TT.hv_p = strstr(start, ".*");
171 TT.hv_w = strchr(start, '*');
172 //pitfall: handle diff b/w * and .*
173 if ((TT.hv_w-1) == TT.hv_p) TT.hv_w = NULL;
174 memcpy((p = xzalloc(len+1)), start, len);
175 print(p+len-1, wp[0], wp[1]);
176 if (*arg) arg++;
177 free(p);
178 p = NULL;
179 }
180 TT.encountered = 1;
181 }
182 }
233 } 183 }