diff options
Diffstat (limited to 'src/builtin/sprintf.bi')
-rw-r--r-- | src/builtin/sprintf.bi | 96 |
1 files changed, 49 insertions, 47 deletions
diff --git a/src/builtin/sprintf.bi b/src/builtin/sprintf.bi index 11effd58..0a927dd2 100644 --- a/src/builtin/sprintf.bi +++ b/src/builtin/sprintf.bi | |||
@@ -31,132 +31,133 @@ typedef enum { | |||
31 | fmts_width_arg, /* Expect width argument position -- %2$#*_1$ */ | 31 | fmts_width_arg, /* Expect width argument position -- %2$#*_1$ */ |
32 | fmts_prec, /* Expect precision */ | 32 | fmts_prec, /* Expect precision */ |
33 | fmts_prec_arg, /* Expect precision argument position */ | 33 | fmts_prec_arg, /* Expect precision argument position */ |
34 | fmts_conv /* Expect conversion specifier */ | 34 | fmts_conv /* Expect conversion specifier */ |
35 | } printf_format_state; | 35 | } printf_format_state; |
36 | 36 | ||
37 | char * | 37 | static int |
38 | get_num(char *p, unsigned *pn) | 38 | get_num(const char *p, int i, unsigned *pn) |
39 | { | 39 | { |
40 | unsigned n = 0; | 40 | unsigned n = 0; |
41 | for (; *p && mu_isdigit(*p); p++) | 41 | |
42 | n = n * 10 + *p - '0'; | 42 | for (; p[i] && mu_isdigit(p[i]); i++) |
43 | n = n * 10 + p[i] - '0'; | ||
43 | *pn = n; | 44 | *pn = n; |
44 | return p; | 45 | return i; |
45 | } | 46 | } |
46 | 47 | ||
47 | #define __MF_MAX(a,b) ((a)>(b) ? (a) : (b)) | 48 | #define __MF_MAX(a,b) ((a)>(b) ? (a) : (b)) |
48 | #define SPRINTF_BUF_SIZE (__MF_MAX(3*sizeof(long), NUMERIC_BUFSIZE_BOUND) + 2) | 49 | #define SPRINTF_BUF_SIZE (__MF_MAX(3*sizeof(long), NUMERIC_BUFSIZE_BOUND) + 2) |
49 | 50 | ||
50 | MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) | 51 | MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) |
51 | { | 52 | { |
52 | int i = 0; | 53 | int i = 0; |
53 | char *p = format; | 54 | int cur = 0; |
54 | char *start; | 55 | int start; |
55 | char buf[SPRINTF_BUF_SIZE]; | 56 | char buf[SPRINTF_BUF_SIZE]; |
56 | printf_format_state state = fmts_copy; | 57 | printf_format_state state = fmts_copy; |
57 | int flags = 0; | 58 | int flags = 0; |
58 | unsigned width = 0; | 59 | unsigned width = 0; |
59 | unsigned prec = 0; | 60 | unsigned prec = 0; |
60 | unsigned argnum; | 61 | unsigned argnum; |
61 | 62 | ||
62 | MF_OBSTACK_BEGIN(); | 63 | MF_OBSTACK_BEGIN(); |
63 | MF_VA_START(); | 64 | MF_VA_START(); |
64 | while (*p) { | 65 | while (format[cur]) { |
65 | unsigned n; | 66 | unsigned n; |
66 | char *str; | 67 | char *str; |
67 | long num; | 68 | long num; |
68 | int negative; | 69 | int negative; |
69 | char fmtbuf[] = { '%', 'x', 0 }; | 70 | char fmtbuf[] = { '%', 'x', 0 }; |
70 | 71 | ||
71 | switch (state) { | 72 | switch (state) { |
72 | case fmts_copy: | 73 | case fmts_copy: |
73 | /* Expect `%', and copy all the rest verbatim */ | 74 | /* Expect `%', and copy all the rest verbatim */ |
74 | if (*p == '%') { | 75 | if (format[cur] == '%') { |
75 | start = p; | 76 | start = cur; |
76 | state = fmts_pos; | 77 | state = fmts_pos; |
77 | flags = 0; | 78 | flags = 0; |
78 | width = 0; | 79 | width = 0; |
79 | prec = 0; | 80 | prec = 0; |
80 | } else | 81 | } else |
81 | MF_OBSTACK_1GROW(*p); | 82 | MF_OBSTACK_1GROW(format[cur]); |
82 | p++; | 83 | cur++; |
83 | break; | 84 | break; |
84 | 85 | ||
85 | case fmts_pos: | 86 | case fmts_pos: |
86 | /* Expect '%' or an argument position -- %_% or %_2$ */ | 87 | /* Expect '%' or an argument position -- %_% or %_2$ */ |
87 | if (*p == '%') { | 88 | if (format[cur] == '%') { |
88 | MF_OBSTACK_1GROW('%'); | 89 | MF_OBSTACK_1GROW('%'); |
89 | p++; | 90 | cur++; |
90 | state = fmts_copy; | 91 | state = fmts_copy; |
91 | break; | 92 | break; |
92 | } | 93 | } |
93 | if (mu_isdigit(*p)) { | 94 | if (mu_isdigit(format[cur])) { |
94 | char *q = get_num(p, &n); | 95 | int pos = get_num(format, cur, &n); |
95 | if (*q == '$') { | 96 | if (format[pos] == '$') { |
96 | argnum = n - 1; | 97 | argnum = n - 1; |
97 | flags |= FMT_ALTPOS; | 98 | flags |= FMT_ALTPOS; |
98 | p = q + 1; | 99 | cur = pos + 1; |
99 | } | 100 | } |
100 | } | 101 | } |
101 | state = fmts_flags; | 102 | state = fmts_flags; |
102 | break; | 103 | break; |
103 | 104 | ||
104 | case fmts_flags: | 105 | case fmts_flags: |
105 | /* Expect flags -- %2$_# */ | 106 | /* Expect flags -- %2$_# */ |
106 | switch (*p) { | 107 | switch (format[cur]) { |
107 | case '#': | 108 | case '#': |
108 | flags |= FMT_ALTERNATE; | 109 | flags |= FMT_ALTERNATE; |
109 | p++; | 110 | cur++; |
110 | break; | 111 | break; |
111 | 112 | ||
112 | case '0': | 113 | case '0': |
113 | flags |= FMT_PADZERO; | 114 | flags |= FMT_PADZERO; |
114 | p++; | 115 | cur++; |
115 | break; | 116 | break; |
116 | 117 | ||
117 | case '-': | 118 | case '-': |
118 | flags |= FMT_ADJUST_LEFT; | 119 | flags |= FMT_ADJUST_LEFT; |
119 | p++; | 120 | cur++; |
120 | break; | 121 | break; |
121 | 122 | ||
122 | case ' ': | 123 | case ' ': |
123 | flags |= FMT_SPACEPFX; | 124 | flags |= FMT_SPACEPFX; |
124 | p++; | 125 | cur++; |
125 | break; | 126 | break; |
126 | 127 | ||
127 | case '+': | 128 | case '+': |
128 | flags |= FMT_SIGNPFX; | 129 | flags |= FMT_SIGNPFX; |
129 | p++; | 130 | cur++; |
130 | break; | 131 | break; |
131 | 132 | ||
132 | default: | 133 | default: |
133 | state = fmts_width; | 134 | state = fmts_width; |
134 | } | 135 | } |
135 | break; | 136 | break; |
136 | 137 | ||
137 | case fmts_width: | 138 | case fmts_width: |
138 | /* Expect width -- %2$#_8 or %2$#_* */ | 139 | /* Expect width -- %2$#_8 or %2$#_* */ |
139 | if (mu_isdigit(*p)) { | 140 | if (mu_isdigit(format[cur])) { |
140 | p = get_num(p, &width); | 141 | cur = get_num(format, cur, &width); |
141 | state = fmts_prec; | 142 | state = fmts_prec; |
142 | } else if (*p == '*') { | 143 | } else if (format[cur] == '*') { |
143 | p++; | 144 | cur++; |
144 | state = fmts_width_arg; | 145 | state = fmts_width_arg; |
145 | } else | 146 | } else |
146 | state = fmts_prec; | 147 | state = fmts_prec; |
147 | break; | 148 | break; |
148 | 149 | ||
149 | case fmts_width_arg: | 150 | case fmts_width_arg: |
150 | /* Expect width argument position -- %2$#*_1$ */ | 151 | /* Expect width argument position -- %2$#*_1$ */ |
151 | state = fmts_prec; | 152 | state = fmts_prec; |
152 | if (mu_isdigit(*p)) { | 153 | if (mu_isdigit(format[cur])) { |
153 | char *q = get_num(p, &n); | 154 | int pos = get_num(format, cur, &n); |
154 | if (*q == '$') { | 155 | if (format[pos] == '$') { |
155 | MF_VA_ARG(n-1, NUMBER, num); | 156 | MF_VA_ARG(n-1, NUMBER, num); |
156 | p = q + 1; | 157 | cur = pos + 1; |
157 | if (num < 0) { | 158 | if (num < 0) { |
158 | flags |= FMT_SPACEPFX; | 159 | flags |= FMT_SPACEPFX; |
159 | num = - num; | 160 | num = - num; |
160 | } | 161 | } |
161 | width = (unsigned) num; | 162 | width = (unsigned) num; |
162 | break; | 163 | break; |
@@ -173,47 +174,47 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) | |||
173 | width = (unsigned) num; | 174 | width = (unsigned) num; |
174 | break; | 175 | break; |
175 |