summaryrefslogtreecommitdiff
path: root/src/stdio/__conv.c
blob: 3dbfd6875f9338a0742758c683eebdea8ec13888 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <inttypes.h>
#include <ctype.h>
#include <string.h>
#include "_stdio.h"

size_t __conv(const char *format, struct io_conversion *conv)
{
	size_t ret = 0;

	if (format[0] != '%') {
		return 0;
	}

	ret++;

	conv->flags = 0;
	conv->length = L_default;
	conv->has_width = 0;
	conv->has_precision = 0;

	while (strchr("*-+ #0", format[ret])) {
		switch (format[ret]) {
		case '*':	conv->flags |= F_STAR; break;
		case '-':	conv->flags |= F_LEFT; break;
		case '+':	conv->flags |= F_SIGN; break;
		case ' ':	conv->flags |= F_SPACE; break;
		case '#':	conv->flags |= F_ALT; break;
		case '0':	conv->flags |= F_ZERO; break;
		}
		/* check for invalid input flags (only * is allowed) */
		ret++;
	}

	if (isdigit(format[ret])) {
		char *end = NULL;
		conv->has_width = 1;
		conv->width = strtoumax(format + ret, &end, 10);
		ret += (size_t)(end - (format + ret));
	}

	/* TODO: precision */

	if (strchr("hljztL", format[ret])) {
		switch (format[ret]) {
		case 'h':
			if (format[ret + 1] == 'h') {
				ret++;
				conv->length = L_hh;
			} else {
				conv->length = L_h;
			}
			break;
		case 'l':
			if (format[ret + 1] == 'l') {
				ret++;
				conv->length = L_ll;
			} else {
				conv->length = L_l;
			}
			break;
		case 'j':
			conv->length = L_j;
			break;
		case 'z':
			conv->length = L_z;
			break;
		case 't':
			conv->length = L_t;
			break;
		case 'L':
			conv->length = L_L;
			break;
		default:
			break;
		}
		ret++;
	}

	/* TODO: validate */

	conv->spec = format[ret];
	ret++;
	return ret;
}