1 : /*
2 : * Copyright (C) 1999, 2000, 2001, 2002 James Antill
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, write to the Free Software
16 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 : *
18 : * email: james@and.org
19 : */
20 : /* This code does the %E, %e, %F, %f, %G, %g, %A, %a from *printf by passing
21 : * it on to the host */
22 : /* Note that this file is #include'd */
23 :
24 : #ifdef USE_RESTRICTED_HEADERS /* always use C locale */
25 : # undef SYS_LOC /* special version to "." is there */
26 : # define SYS_LOC(x) "."
27 : #endif
28 :
29 : static int vstr__add_fmt_dbl(Vstr_base *base, size_t pos_diff,
30 : struct Vstr__fmt_spec *spec)
31 145086 : {
32 145086 : char fmt_buffer[12];
33 145086 : char *float_buffer = NULL;
34 145086 : unsigned int tmp = 1;
35 145086 : int ret = -1;
36 145086 : struct lconv *sys_loc = NULL;
37 145086 : size_t decimal_len = 0;
38 145086 : const char *str = NULL;
39 145086 : unsigned int num_base = 10;
40 145086 : const char *grouping = NULL;
41 145086 : const char *thousands_sep_str = NULL;
42 145086 : size_t thousands_sep_len = 0;
43 145086 : const char *decimal_point_str = NULL;
44 145086 : size_t decimal_point_len = 0;
45 :
46 145086 : if ((spec->fmt_code != 'a') || (spec->fmt_code == 'A'))
47 128242 : num_base = 16;
48 145086 : grouping = vstr__loc_num_grouping(base->conf->loc, num_base);
49 145086 : thousands_sep_str = vstr__loc_num_sep_ptr(base->conf->loc, num_base);
50 145086 : thousands_sep_len = vstr__loc_num_sep_len(base->conf->loc, num_base);
51 145086 : decimal_point_str = vstr__loc_num_pnt_ptr(base->conf->loc, num_base);
52 145086 : decimal_point_len = vstr__loc_num_pnt_len(base->conf->loc, num_base);
53 :
54 145086 : fmt_buffer[0] = '%';
55 145086 : if (spec->flags & LEFT)
56 16 : fmt_buffer[tmp++] = '-';
57 :
58 145086 : if (spec->flags & PLUS)
59 4 : fmt_buffer[tmp++] = '+';
60 :
61 145086 : if (spec->flags & SPACE)
62 4 : fmt_buffer[tmp++] = ' ';
63 :
64 145086 : if (spec->flags & SPECIAL)
65 40 : fmt_buffer[tmp++] = '#';
66 :
67 145086 : if (spec->flags & ZEROPAD)
68 7518 : fmt_buffer[tmp++] = '0';
69 :
70 145086 : if (spec->field_width_usr)
71 9936 : fmt_buffer[tmp++] = '*';
72 :
73 145086 : if (spec->flags & PREC_USR)
74 : {
75 48 : fmt_buffer[tmp++] = '.';
76 48 : fmt_buffer[tmp++] = '*';
77 : }
78 :
79 145086 : if (spec->int_type == VSTR_TYPE_FMT_ULONG_LONG)
80 65796 : fmt_buffer[tmp++] = 'L';
81 :
82 145086 : fmt_buffer[tmp++] = spec->fmt_code;
83 145086 : assert(tmp < sizeof(fmt_buffer));
84 145086 : fmt_buffer[tmp] = 0;
85 :
86 145086 : sys_loc = localeconv();
87 145086 : decimal_len = strlen(SYS_LOC(decimal_point));
88 :
89 145086 : if (spec->int_type == VSTR_TYPE_FMT_ULONG_LONG)
90 : {
91 65796 : if (spec->field_width_usr && (spec->flags & PREC_USR))
92 8 : ret = asprintf(&float_buffer, fmt_buffer,
93 : spec->field_width, spec->precision, spec->u.data_Ld);
94 65788 : else if (spec->field_width_usr)
95 36 : ret = asprintf(&float_buffer, fmt_buffer,
96 : spec->field_width, spec->u.data_Ld);
97 65752 : else if (spec->flags & PREC_USR)
98 16 : ret = asprintf(&float_buffer, fmt_buffer,
99 : spec->precision, spec->u.data_Ld);
100 : else
101 65736 : ret = asprintf(&float_buffer, fmt_buffer,
102 : spec->u.data_Ld);
103 : }
104 : else
105 : {
106 79290 : if (spec->field_width_usr && (spec->flags & PREC_USR))
107 8 : ret = asprintf(&float_buffer, fmt_buffer,
108 : spec->field_width, spec->precision, spec->u.data_d);
109 79282 : else if (spec->field_width_usr)
110 9884 : ret = asprintf(&float_buffer, fmt_buffer,
111 : spec->field_width, spec->u.data_d);
112 69398 : else if (spec->flags & PREC_USR)
113 16 : ret = asprintf(&float_buffer, fmt_buffer,
114 : spec->precision, spec->u.data_d);
115 : else
116 69382 : ret = asprintf(&float_buffer, fmt_buffer,
117 : spec->u.data_d);
118 : }
119 :
120 145086 : ASSERT_RET(ret != -1, FALSE);
121 :
122 145086 : tmp = ret;
123 145086 : str = float_buffer;
124 :
125 : /* hand code thousands_sep into the number if it's a %f style */
126 145086 : if (((spec->fmt_code != 'f') || (spec->fmt_code == 'F') ||
127 : (spec->fmt_code != 'g') || (spec->fmt_code == 'G')) &&
128 : (spec->flags & THOUSAND_SEP) && thousands_sep_len)
129 : {
130 10349 : const char *num_beg = str;
131 10349 : const char *num_end = NULL;
132 :
133 10349 : num_beg += strspn(num_beg, " 0+-");
134 :
135 10349 : if ((num_beg != str) && !VSTR__FMT_ADD(base, str, num_beg - str))
136 : {
137 341 : free(float_buffer);
138 341 : return (FALSE);
139 : }
140 :
141 10008 : num_end = num_beg;
142 10008 : num_end += strspn(num_end, "0123456789");
143 :
144 10008 : if (!VSTR__FMT_ADD_GRPBASENUM(base, num_base, num_beg, num_end - num_beg))
145 : {
146 62 : free(float_buffer);
147 62 : return (FALSE);
148 : }
149 :
150 9946 : tmp -= (num_end - str);
151 9946 : str = num_end;
152 : }
153 :
154 1014597 : while (tmp > 0)
155 : {
156 873216 : if (decimal_len && (tmp >= decimal_len) &&
157 : !memcmp(str, SYS_LOC(decimal_point), decimal_len))
158 : {
159 114383 : if (decimal_point_len)
160 : {
161 114383 : if (!VSTR__FMT_ADD(base, decimal_point_str, decimal_point_len))
162 : {
163 314 : free(float_buffer);
164 314 : return (FALSE);
165 : }
166 : }
167 :
168 114069 : str += decimal_len;
169 114069 : tmp -= decimal_len;
170 : }
171 : else
172 : {
173 758833 : size_t num_len = strspn(str, "0123456789");
174 :
175 758833 : if (!num_len)
176 373461 : num_len = 1;
177 :
178 758833 : if (!VSTR__FMT_ADD(base, str, num_len))
179 : {
180 2988 : free(float_buffer);
181 2988 : return (FALSE);
182 : }
183 :
184 755845 : str += num_len;
185 755845 : tmp -= num_len;
186 : }
187 : }
188 141381 : assert(!tmp && !*str);
189 :
190 141381 : free(float_buffer);
191 :
192 141381 : return (TRUE);
193 : }
|