nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan |
||
3 | * (Royal Institute of Technology, Stockholm, Sweden). |
||
4 | * All rights reserved. |
||
5 | * |
||
6 | * Redistribution and use in source and binary forms, with or without |
||
7 | * modification, are permitted provided that the following conditions |
||
8 | * are met: |
||
9 | * |
||
10 | * 1. Redistributions of source code must retain the above copyright |
||
11 | * notice, this list of conditions and the following disclaimer. |
||
12 | * |
||
13 | * 2. Redistributions in binary form must reproduce the above copyright |
||
14 | * notice, this list of conditions and the following disclaimer in the |
||
15 | * documentation and/or other materials provided with the distribution. |
||
16 | * |
||
17 | * 3. Neither the name of the Institute nor the names of its contributors |
||
18 | * may be used to endorse or promote products derived from this software |
||
19 | * without specific prior written permission. |
||
20 | * |
||
21 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND |
||
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE |
||
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
31 | * SUCH DAMAGE. |
||
32 | */ |
||
33 | |||
34 | #ifdef HAVE_CONFIG_H |
||
35 | #include <config.h> |
||
36 | #endif |
||
37 | |||
38 | #include <stdio.h> |
||
39 | #include <stdarg.h> |
||
40 | #include <stdlib.h> |
||
41 | #include <string.h> |
||
42 | #include <ctype.h> |
||
43 | #include <sys/types.h> |
||
44 | |||
45 | #include <interface.h> |
||
46 | |||
47 | enum format_flags { |
||
48 | minus_flag = 1, |
||
49 | plus_flag = 2, |
||
50 | space_flag = 4, |
||
51 | alternate_flag = 8, |
||
52 | zero_flag = 16 |
||
53 | }; |
||
54 | |||
55 | /* |
||
56 | * Common state |
||
57 | */ |
||
58 | |||
59 | struct state { |
||
60 | unsigned char *str; |
||
61 | unsigned char *s; |
||
62 | unsigned char *theend; |
||
63 | size_t sz; |
||
64 | size_t max_sz; |
||
65 | int (*append_char)(struct state *, unsigned char); |
||
66 | int (*reserve)(struct state *, size_t); |
||
67 | /* XXX - methods */ |
||
68 | }; |
||
69 | |||
70 | #ifndef HAVE_VSNPRINTF |
||
71 | static int |
||
72 | sn_reserve (struct state *state, size_t n) |
||
73 | { |
||
74 | return state->s + n > state->theend; |
||
75 | } |
||
76 | |||
77 | static int |
||
78 | sn_append_char (struct state *state, unsigned char c) |
||
79 | { |
||
80 | if (sn_reserve (state, 1)) { |
||
81 | return 1; |
||
82 | } else { |
||
83 | *state->s++ = c; |
||
84 | return 0; |
||
85 | } |
||
86 | } |
||
87 | #endif |
||
88 | |||
89 | #if 0 |
||
90 | static int |
||
91 | as_reserve (struct state *state, size_t n) |
||
92 | { |
||
93 | if (state->s + n > state->theend) { |
||
94 | int off = state->s - state->str; |
||
95 | unsigned char *tmp; |
||
96 | |||
97 | if (state->max_sz && state->sz >= state->max_sz) |
||
98 | return 1; |
||
99 | |||
100 | state->sz = max(state->sz * 2, state->sz + n); |
||
101 | if (state->max_sz) |
||
102 | state->sz = min(state->sz, state->max_sz); |
||
103 | tmp = realloc (state->str, state->sz); |
||
104 | if (tmp == NULL) |
||
105 | return 1; |
||
106 | state->str = tmp; |
||
107 | state->s = state->str + off; |
||
108 | state->theend = state->str + state->sz - 1; |
||
109 | } |
||
110 | return 0; |
||
111 | } |
||
112 | |||
113 | static int |
||
114 | as_append_char (struct state *state, unsigned char c) |
||
115 | { |
||
116 | if(as_reserve (state, 1)) |
||
117 | return 1; |
||
118 | else { |
||
119 | *state->s++ = c; |
||
120 | return 0; |
||
121 | } |
||
122 | } |
||
123 | #endif |
||
124 | |||
125 | static int |
||
126 | append_number(struct state *state, |
||
127 | unsigned long num, unsigned base, char *rep, |
||
128 | int width, int prec, int flags, int minusp) |
||
129 | { |
||
130 | int len = 0; |
||
131 | int i; |
||
132 | |||
133 | /* given precision, ignore zero flag */ |
||
134 | if(prec != -1) |
||
135 | flags &= ~zero_flag; |
||
136 | else |
||
137 | prec = 1; |
||
138 | /* zero value with zero precision -> "" */ |
||
139 | if(prec == 0 && num == 0) |
||
140 | return 0; |
||
141 | do{ |
||
142 | if((*state->append_char)(state, rep[num % base])) |
||
143 | return 1; |
||
144 | len++; |
||
145 | num /= base; |
||
146 | }while(num); |
||
147 | prec -= len; |
||
148 | /* pad with prec zeros */ |
||
149 | while(prec-- > 0){ |
||
150 | if((*state->append_char)(state, '0')) |
||
151 | return 1; |
||
152 | len++; |
||
153 | } |
||
154 | /* add length of alternate prefix (added later) to len */ |
||
155 | if(flags & alternate_flag && (base == 16 || base == 8)) |
||
156 | len += base / 8; |
||
157 | /* pad with zeros */ |
||
158 | if(flags & zero_flag){ |
||
159 | width -= len; |
||
160 | if(minusp || (flags & space_flag) || (flags & plus_flag)) |
||
161 | width--; |
||
162 | while(width-- > 0){ |
||
163 | if((*state->append_char)(state, '0')) |
||
164 | return 1; |
||
165 | len++; |
||
166 | } |
||
167 | } |
||
168 | /* add alternate prefix */ |
||
169 | if(flags & alternate_flag && (base == 16 || base == 8)){ |
||
170 | if(base == 16) |
||
171 | if((*state->append_char)(state, rep[10] + 23)) /* XXX */ |
||
172 | return 1; |
||
173 | if((*state->append_char)(state, '0')) |
||
174 | return 1; |
||
175 | } |
||
176 | /* add sign */ |
||
177 | if(minusp){ |
||
178 | if((*state->append_char)(state, '-')) |
||
179 | return 1; |
||
180 | len++; |
||
181 | } else if(flags & plus_flag) { |
||
182 | if((*state->append_char)(state, '+')) |
||
183 | return 1; |
||
184 | len++; |
||
185 | } else if(flags & space_flag) { |
||
186 | if((*state->append_char)(state, ' ')) |
||
187 | return 1; |
||
188 | len++; |
||
189 | } |
||
190 | if(flags & minus_flag) |
||
191 | /* swap before padding with spaces */ |
||
192 | for(i = 0; i < len / 2; i++){ |
||
193 | char c = state->s[-i-1]; |
||
194 | state->s[-i-1] = state->s[-len+i]; |
||
195 | state->s[-len+i] = c; |
||
196 | } |
||
197 | width -= len; |
||
198 | while(width-- > 0){ |
||
199 | if((*state->append_char)(state, ' ')) |
||
200 | return 1; |
||
201 | len++; |
||
202 | } |
||
203 | if(!(flags & minus_flag)) |
||
204 | /* swap after padding with spaces */ |
||
205 | for(i = 0; i < len / 2; i++){ |
||
206 | char c = state->s[-i-1]; |
||
207 | state->s[-i-1] = state->s[-len+i]; |
||
208 | state->s[-len+i] = c; |
||
209 | } |
||
210 | |||
211 | return 0; |
||
212 | } |
||
213 | |||
214 | static int |
||
215 | append_string (struct state *state, |
||
216 | unsigned char *arg, |
||
217 | int width, |
||
218 | int prec, |
||
219 | int flags) |
||
220 | { |
||
221 | if(prec != -1) |
||
222 | width -= prec; |
||
223 | else |
||
224 | width -= strlen((char *)arg); |
||
225 | if(!(flags & minus_flag)) |
||
226 | while(width-- > 0) |
||
227 | if((*state->append_char) (state, ' ')) |
||
228 | return 1; |
||
229 | if (prec != -1) { |
||
230 | while (*arg && prec--) |
||
231 | if ((*state->append_char) (state, *arg++)) |
||
232 | return 1; |
||
233 | } else { |
||
234 | while (*arg) |
||
235 | if ((*state->append_char) (state, *arg++)) |
||
236 | return 1; |
||
237 | } |
||
238 | if(flags & minus_flag) |
||
239 | while(width-- > 0) |
||
240 | if((*state->append_char) (state, ' ')) |
||
241 | return 1; |
||
242 | return 0; |
||
243 | } |
||
244 | |||
245 | static int |
||
246 | append_char(struct state *state, |
||
247 | unsigned char arg, |
||
248 | int width, |
||
249 | int flags) |
||
250 | { |
||
251 | while(!(flags & minus_flag) && --width > 0) |
||
252 | if((*state->append_char) (state, ' ')) |
||
253 | return 1; |
||
254 | |||
255 | if((*state->append_char) (state, arg)) |
||
256 | return 1; |
||
257 | while((flags & minus_flag) && --width > 0) |
||
258 | if((*state->append_char) (state, ' ')) |
||
259 | return 1; |
||
260 | |||
261 | return 0; |
||
262 | } |
||
263 | |||
264 | /* |
||
265 | * This can't be made into a function... |
||
266 | */ |
||
267 | |||
268 | #define PARSE_INT_FORMAT(res, arg, unsig) \ |
||
269 | if (long_flag) \ |
||
270 | res = (unsig long)va_arg(arg, unsig long); \ |
||
271 | else if (short_flag) \ |
||
272 | res = (unsig short)va_arg(arg, unsig int); \ |
||
273 | else \ |
||
274 | res = (unsig int)va_arg(arg, unsig int) |
||
275 | |||
276 | /* |
||
277 | * zyxprintf - return 0 or -1 |
||
278 | */ |
||
279 | |||
280 | static int |
||
281 | xyzprintf (struct state *state, const char *char_format, va_list ap) |
||
282 | { |
||
283 | const unsigned char *format = (const unsigned char *)char_format; |
||
284 | unsigned char c; |
||
285 | |||
286 | while((c = *format++)) { |
||
287 | if (c == '%') { |
||
288 | int flags = 0; |
||
289 | int width = 0; |
||
290 | int prec = -1; |
||
291 | int long_flag = 0; |
||
292 | int short_flag = 0; |
||
293 | |||
294 | /* flags */ |
||
295 | while((c = *format++)){ |
||
296 | if(c == '-') |
||
297 | flags |= minus_flag; |
||
298 | else if(c == '+') |
||
299 | flags |= plus_flag; |
||
300 | else if(c == ' ') |
||
301 | flags |= space_flag; |
||
302 | else if(c == '#') |
||
303 | flags |= alternate_flag; |
||
304 | else if(c == '0') |
||
305 | flags |= zero_flag; |
||
306 | else |
||
307 | break; |
||
308 | } |
||
309 | |||
310 | if((flags & space_flag) && (flags & plus_flag)) |
||
311 | flags ^= space_flag; |
||
312 | |||
313 | if((flags & minus_flag) && (flags & zero_flag)) |
||
314 | flags ^= zero_flag; |
||
315 | |||
316 | /* width */ |
||
317 | if (isdigit(c)) |
||
318 | do { |
||
319 | width = width * 10 + c - '0'; |
||
320 | c = *format++; |
||
321 | } while(isdigit(c)); |
||
322 | else if(c == '*') { |
||
323 | width = va_arg(ap, int); |
||
324 | c = *format++; |
||
325 | } |
||
326 | |||
327 | /* precision */ |
||
328 | if (c == '.') { |
||
329 | prec = 0; |
||
330 | c = *format++; |
||
331 | if (isdigit(c)) |
||
332 | do { |
||
333 | prec = prec * 10 + c - '0'; |
||
334 | c = *format++; |
||
335 | } while(isdigit(c)); |
||
336 | else if (c == '*') { |
||
337 | prec = va_arg(ap, int); |
||
338 | c = *format++; |
||
339 | } |
||
340 | } |
||
341 | |||
342 | /* size */ |
||
343 | |||
344 | if (c == 'h') { |
||
345 | short_flag = 1; |
||
346 | c = *format++; |
||
347 | } else if (c == 'l') { |
||
348 | long_flag = 1; |
||
349 | c = *format++; |
||
350 | } |
||
351 | |||
352 | switch (c) { |
||
353 | case 'c' : |
||
354 | if(append_char(state, va_arg(ap, int), width, flags)) |
||
355 | return -1; |
||
356 | break; |
||
357 | case 's' : |
||
358 | if (append_string(state, |
||
359 | va_arg(ap, unsigned char*), |
||
360 | width, |
||
361 | prec, |
||
362 | flags)) |
||
363 | return -1; |
||
364 | break; |
||
365 | case 'd' : |
||
366 | case 'i' : { |
||
367 | long arg; |
||
368 | unsigned long num; |
||
369 | int minusp = 0; |
||
370 | |||
371 | PARSE_INT_FORMAT(arg, ap, signed); |
||
372 | |||
373 | if (arg < 0) { |
||
374 | minusp = 1; |
||
375 | num = -arg; |
||
376 | } else |
||
377 | num = arg; |
||
378 | |||
379 | if (append_number (state, num, 10, "0123456789", |
||
380 | width, prec, flags, minusp)) |
||
381 | return -1; |
||
382 | break; |
||
383 | } |
||
384 | case 'u' : { |
||
385 | unsigned long arg; |
||
386 | |||
387 | PARSE_INT_FORMAT(arg, ap, unsigned); |
||
388 | |||
389 | if (append_number (state, arg, 10, "0123456789", |
||
390 | width, prec, flags, 0)) |
||
391 | return -1; |
||
392 | break; |
||
393 | } |
||
394 | case 'o' : { |
||
395 | unsigned long arg; |
||
396 | |||
397 | PARSE_INT_FORMAT(arg, ap, unsigned); |
||
398 | |||
399 | if (append_number (state, arg, 010, "01234567", |
||
400 | width, prec, flags, 0)) |
||
401 | return -1; |
||
402 | break; |
||
403 | } |
||
404 | case 'x' : { |
||
405 | unsigned long arg; |
||
406 | |||
407 | PARSE_INT_FORMAT(arg, ap, unsigned); |
||
408 | |||
409 | if (append_number (state, arg, 0x10, "0123456789abcdef", |
||
410 | width, prec, flags, 0)) |
||
411 | return -1; |
||
412 | break; |
||
413 | } |
||
414 | case 'X' :{ |
||
415 | unsigned long arg; |
||
416 | |||
417 | PARSE_INT_FORMAT(arg, ap, unsigned); |
||
418 | |||
419 | if (append_number (state, arg, 0x10, "0123456789ABCDEF", |
||
420 | width, prec, flags, 0)) |
||
421 | return -1; |
||
422 | break; |
||
423 | } |
||
424 | case 'p' : { |
||
425 | unsigned long arg = (unsigned long)va_arg(ap, void*); |
||
426 | |||
427 | if (append_number (state, arg, 0x10, "0123456789ABCDEF", |
||
428 | width, prec, flags, 0)) |
||
429 | return -1; |
||
430 | break; |
||
431 | } |
||
432 | case 'n' : { |
||
433 | int *arg = va_arg(ap, int*); |
||
434 | *arg = state->s - state->str; |
||
435 | break; |
||
436 | } |
||
437 | case '\0' : |
||
438 | --format; |
||
439 | /* FALLTHROUGH */ |
||
440 | case '%' : |
||
441 | if ((*state->append_char)(state, c)) |
||
442 | return -1; |
||
443 | break; |
||
444 | default : |
||
445 | if ( (*state->append_char)(state, '%') |
||
446 | || (*state->append_char)(state, c)) |
||
447 | return -1; |
||
448 | break; |
||
449 | } |
||
450 | } else |
||
451 | if ((*state->append_char) (state, c)) |
||
452 | return -1; |
||
453 | } |
||
454 | return 0; |
||
455 | } |
||
456 | |||
457 | #ifndef HAVE_SNPRINTF |
||
458 | int |
||
459 | snprintf (char *str, size_t sz, const char *format, ...) |
||
460 | { |
||
461 | va_list args; |
||
462 | int ret; |
||
463 | |||
464 | va_start(args, format); |
||
465 | ret = vsnprintf (str, sz, format, args); |
||
466 | |||
467 | #ifdef PARANOIA |
||
468 | { |
||
469 | int ret2; |
||
470 | char *tmp; |
||
471 | |||
472 | tmp = malloc (sz); |
||
473 | if (tmp == NULL) |
||
474 | abort (); |
||
475 | |||
476 | ret2 = vsprintf (tmp, format, args); |
||
477 | if (ret != ret2 || strcmp(str, tmp)) |
||
478 | abort (); |
||
479 | free (tmp); |
||
480 | } |
||
481 | #endif |
||
482 | |||
483 | va_end(args); |
||
484 | return ret; |
||
485 | } |
||
486 | #endif |
||
487 | |||
488 | #if 0 |
||
489 | #ifndef HAVE_ASPRINTF |
||
490 | int |
||
491 | asprintf (char **ret, const char *format, ...) |
||
492 | { |
||
493 | va_list args; |
||
494 | int val; |
||
495 | |||
496 | va_start(args, format); |
||
497 | val = vasprintf (ret, format, args); |
||
498 | |||
499 | #ifdef PARANOIA |
||
500 | { |
||
501 | int ret2; |
||
502 | char *tmp; |
||
503 | tmp = malloc (val + 1); |
||
504 | if (tmp == NULL) |
||
505 | abort (); |
||
506 | |||
507 | ret2 = vsprintf (tmp, format, args); |
||
508 | if (val != ret2 || strcmp(*ret, tmp)) |
||
509 | abort (); |
||
510 | free (tmp); |
||
511 | } |
||
512 | #endif |
||
513 | |||
514 | va_end(args); |
||
515 | return val; |
||
516 | } |
||
517 | #endif |
||
518 | |||
519 | #ifndef HAVE_ASNPRINTF |
||
520 | int |
||
521 | asnprintf (char **ret, size_t max_sz, const char *format, ...) |
||
522 | { |
||
523 | va_list args; |
||
524 | int val; |
||
525 | |||
526 | va_start(args, format); |
||
527 | val = vasnprintf (ret, max_sz, format, args); |
||
528 | |||
529 | #ifdef PARANOIA |
||
530 | { |
||
531 | int ret2; |
||
532 | char *tmp; |
||
533 | tmp = malloc (val + 1); |
||
534 | if (tmp == NULL) |
||
535 | abort (); |
||
536 | |||
537 | ret2 = vsprintf (tmp, format, args); |
||
538 | if (val != ret2 || strcmp(*ret, tmp)) |
||
539 | abort (); |
||
540 | free (tmp); |
||
541 | } |
||
542 | #endif |
||
543 | |||
544 | va_end(args); |
||
545 | return val; |
||
546 | } |
||
547 | #endif |
||
548 | |||
549 | #ifndef HAVE_VASPRINTF |
||
550 | int |
||
551 | vasprintf (char **ret, const char *format, va_list args) |
||
552 | { |
||
553 | return vasnprintf (ret, 0, format, args); |
||
554 | } |
||
555 | #endif |
||
556 | |||
557 | |||
558 | #ifndef HAVE_VASNPRINTF |
||
559 | int |
||
560 | vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) |
||
561 | { |
||
562 | int st; |
||
563 | size_t len; |
||
564 | struct state state; |
||
565 | |||
566 | state.max_sz = max_sz; |
||
567 | state.sz = 1; |
||
568 | state.str = malloc(state.sz); |
||
569 | if (state.str == NULL) { |
||
570 | *ret = NULL; |
||
571 | return -1; |
||
572 | } |
||
573 | state.s = state.str; |
||
574 | state.theend = state.s + state.sz - 1; |
||
575 | state.append_char = as_append_char; |
||
576 | state.reserve = as_reserve; |
||
577 | |||
578 | st = xyzprintf (&state, format, args); |
||
579 | if (st) { |
||
580 | free (state.str); |
||
581 | *ret = NULL; |
||
582 | return -1; |
||
583 | } else { |
||
584 | char *tmp; |
||
585 | |||
586 | *state.s = '\0'; |
||
587 | len = state.s - state.str; |
||
588 | tmp = realloc (state.str, len+1); |
||
589 | if (tmp == NULL) { |
||
590 | free (state.str); |
||
591 | *ret = NULL; |
||
592 | return -1; |
||
593 | } |
||
594 | *ret = tmp; |
||
595 | return len; |
||
596 | } |
||
597 | } |
||
598 | #endif |
||
599 | #endif |
||
600 | |||
601 | #ifndef HAVE_VSNPRINTF |
||
602 | int |
||
603 | vsnprintf (char *str, size_t sz, const char *format, va_list args) |
||
604 | { |
||
605 | struct state state; |
||
606 | int ret; |
||
607 | unsigned char *ustr = (unsigned char *)str; |
||
608 | |||
609 | state.max_sz = 0; |
||
610 | state.sz = sz; |
||
611 | state.str = ustr; |
||
612 | state.s = ustr; |
||
613 | state.theend = ustr + sz - 1; |
||
614 | state.append_char = sn_append_char; |
||
615 | state.reserve = sn_reserve; |
||
616 | |||
617 | ret = xyzprintf (&state, format, args); |
||
618 | *state.s = '\0'; |
||
619 | if (ret) |
||
620 | return sz; |
||
621 | else |
||
622 | return state.s - state.str; |
||
623 | } |
||
624 | #endif |
||
625 |