/src/ghostpdl/base/spprint.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Print values in ASCII form on a stream */ |
18 | | #include "math_.h" /* for fabs */ |
19 | | #include "stdio_.h" /* for stream.h */ |
20 | | #include "string_.h" /* for strchr */ |
21 | | #include "stream.h" |
22 | | #include "spprint.h" |
23 | | |
24 | | /* ------ Output ------ */ |
25 | | |
26 | | /* Put a byte array on a stream. */ |
27 | | int |
28 | | stream_write(stream * s, const void *ptr, uint count) |
29 | 6.00M | { |
30 | 6.00M | uint used; |
31 | | |
32 | 6.00M | sputs(s, (const byte *)ptr, count, &used); |
33 | 6.00M | return (int)used; |
34 | 6.00M | } |
35 | | |
36 | | /* Put a string on a stream. */ |
37 | | int |
38 | | stream_puts(stream * s, const char *str) |
39 | 4.59M | { |
40 | 4.59M | uint len = strlen(str); |
41 | 4.59M | uint used; |
42 | 4.59M | int status = sputs(s, (const byte *)str, len, &used); |
43 | | |
44 | 4.59M | return (status >= 0 && used == len ? 0 : EOF); |
45 | 4.59M | } |
46 | | |
47 | | /* Print a format string up to the first variable substitution. */ |
48 | | /* Return a pointer to the %, or to the terminating 0 if no % found. */ |
49 | | static const char * |
50 | | pprintf_scan(stream * s, const char *format) |
51 | 41.7M | { |
52 | 41.7M | const char *fp = format; |
53 | | |
54 | 74.9M | for (; *fp != 0; ++fp) { |
55 | 63.5M | if (*fp == '%') { |
56 | 30.3M | if (fp[1] != '%') |
57 | 30.2M | break; |
58 | 10.3k | ++fp; |
59 | 10.3k | } |
60 | 33.2M | sputc(s, *fp); |
61 | 33.2M | } |
62 | 41.7M | return fp; |
63 | 41.7M | } |
64 | | |
65 | | /* Print a short string on a stream. */ |
66 | | static void |
67 | | pputs_short(stream *s, const char *str) |
68 | 20.8M | { |
69 | 20.8M | const char *p = str; |
70 | | |
71 | 143M | for (; *p; ++p) |
72 | 122M | sputc(s, *p); |
73 | 20.8M | } |
74 | | |
75 | | /* Print (an) int value(s) using a format. */ |
76 | | const char * |
77 | | pprintd1(stream * s, const char *format, int v) |
78 | 345k | { |
79 | 345k | const char *fp = pprintf_scan(s, format); |
80 | 345k | char str[25]; |
81 | | |
82 | | #ifdef DEBUG |
83 | | if (*fp == 0 || fp[1] != 'd') /* shouldn't happen! */ |
84 | | lprintf1("Bad format in pprintd1: %s\n", format); |
85 | | #endif |
86 | 345k | gs_snprintf(str, sizeof(str), "%d", v); |
87 | 345k | pputs_short(s, str); |
88 | 345k | return pprintf_scan(s, fp + 2); |
89 | 345k | } |
90 | | const char * |
91 | | pprintd2(stream * s, const char *format, int v1, int v2) |
92 | 51.3k | { |
93 | 51.3k | return pprintd1(s, pprintd1(s, format, v1), v2); |
94 | 51.3k | } |
95 | | const char * |
96 | | pprintd3(stream * s, const char *format, int v1, int v2, int v3) |
97 | 2 | { |
98 | 2 | return pprintd2(s, pprintd1(s, format, v1), v2, v3); |
99 | 2 | } |
100 | | const char * |
101 | | pprintd4(stream * s, const char *format, int v1, int v2, int v3, int v4) |
102 | 11.8k | { |
103 | 11.8k | return pprintd2(s, pprintd2(s, format, v1, v2), v3, v4); |
104 | 11.8k | } |
105 | | |
106 | | /* Print (a) floating point number(s) using a format. */ |
107 | | /* See gdevpdfx.h for why this is needed. */ |
108 | | const char * |
109 | | pprintg1(stream * s, const char *format, double v) |
110 | 19.1M | { |
111 | 19.1M | const char *fp = pprintf_scan(s, format); |
112 | 19.1M | char dot, str[150]; |
113 | | |
114 | | #ifdef DEBUG |
115 | | if (*fp == 0 || fp[1] != 'g') /* shouldn't happen! */ |
116 | | lprintf1("Bad format in pprintg: %s\n", format); |
117 | | #endif |
118 | 19.1M | gs_snprintf(str, sizeof(str), "%f", 1.5); |
119 | 19.1M | dot = str[1]; /* locale-dependent */ |
120 | 19.1M | gs_snprintf(str, sizeof(str), "%g", v); |
121 | 19.1M | if (strchr(str, 'e')) { |
122 | | /* Bad news. Try again using f-format. */ |
123 | 75.6k | gs_snprintf(str, sizeof(str), (fabs(v) > 1 ? "%1.1f" : "%1.8f"), v); |
124 | 75.6k | } |
125 | | /* Juggling locales isn't thread-safe. Posix me harder. */ |
126 | 19.1M | if (dot != '.') { |
127 | 0 | char *pdot = strchr(str, dot); |
128 | 0 | if (pdot) |
129 | 0 | *pdot = '.'; |
130 | 0 | } |
131 | 19.1M | pputs_short(s, str); |
132 | 19.1M | return pprintf_scan(s, fp + 2); |
133 | 19.1M | } |
134 | | const char * |
135 | | pprintg2(stream * s, const char *format, double v1, double v2) |
136 | 5.46M | { |
137 | 5.46M | return pprintg1(s, pprintg1(s, format, v1), v2); |
138 | 5.46M | } |
139 | | const char * |
140 | | pprintg3(stream * s, const char *format, double v1, double v2, double v3) |
141 | 2.37M | { |
142 | 2.37M | return pprintg2(s, pprintg1(s, format, v1), v2, v3); |
143 | 2.37M | } |
144 | | const char * |
145 | | pprintg4(stream * s, const char *format, double v1, double v2, double v3, |
146 | | double v4) |
147 | 335k | { |
148 | 335k | return pprintg2(s, pprintg2(s, format, v1, v2), v3, v4); |
149 | 335k | } |
150 | | const char * |
151 | | pprintg6(stream * s, const char *format, double v1, double v2, double v3, |
152 | | double v4, double v5, double v6) |
153 | 1.18M | { |
154 | 1.18M | return pprintg3(s, pprintg3(s, format, v1, v2, v3), v4, v5, v6); |
155 | 1.18M | } |
156 | | |
157 | | /* Print a long value using a format. */ |
158 | | const char * |
159 | | pprintld1(stream *s, const char *format, long v) |
160 | 10.7k | { |
161 | 10.7k | const char *fp = pprintf_scan(s, format); |
162 | 10.7k | char str[25]; |
163 | | |
164 | | #ifdef DEBUG |
165 | | if (*fp == 0 || fp[1] != 'l' || fp[2] != 'd') /* shouldn't happen! */ |
166 | | lprintf1("Bad format in pprintld: %s\n", format); |
167 | | #endif |
168 | 10.7k | gs_snprintf(str, sizeof(str), "%ld", v); |
169 | 10.7k | pputs_short(s, str); |
170 | 10.7k | return pprintf_scan(s, fp + 3); |
171 | 10.7k | } |
172 | | const char * |
173 | | pprintld2(stream *s, const char *format, long v1, long v2) |
174 | 0 | { |
175 | 0 | return pprintld1(s, pprintld1(s, format, v1), v2); |
176 | 0 | } |
177 | | const char * |
178 | | pprintld3(stream *s, const char *format, long v1, long v2, long v3) |
179 | 0 | { |
180 | 0 | return pprintld2(s, pprintld1(s, format, v1), v2, v3); |
181 | 0 | } |
182 | | |
183 | | /* Print a size_t value using a format. */ |
184 | | const char * |
185 | | pprintzd1(stream *s, const char *format, size_t v) |
186 | 0 | { |
187 | 0 | const char *fp = pprintf_scan(s, format); |
188 | 0 | char str[25]; |
189 | 0 | const size_t z = strlen("%"PRIdSIZE); |
190 | |
|
191 | | #ifdef DEBUG |
192 | | size_t i; |
193 | | |
194 | | for (i = 0; i < z; i++) |
195 | | if (fp[i] != ("%"PRIdSIZE)[i]) |
196 | | break; |
197 | | if (i != z) |
198 | | lprintf1("Bad format in pprintzd: %s\n", format); |
199 | | #endif |
200 | 0 | gs_snprintf(str, sizeof(str), "%"PRIdSIZE, v); |
201 | 0 | pputs_short(s, str); |
202 | 0 | return pprintf_scan(s, fp + z); |
203 | 0 | } |
204 | | const char * |
205 | | pprintzd2(stream *s, const char *format, size_t v1, size_t v2) |
206 | 0 | { |
207 | 0 | return pprintzd1(s, pprintzd1(s, format, v1), v2); |
208 | 0 | } |
209 | | const char * |
210 | | pprintzd3(stream *s, const char *format, size_t v1, size_t v2, size_t v3) |
211 | 0 | { |
212 | 0 | return pprintzd2(s, pprintzd1(s, format, v1), v2, v3); |
213 | 0 | } |
214 | | |
215 | | /* Print an int64_t value using a format. */ |
216 | | const char * |
217 | | pprinti64d1(stream *s, const char *format, int64_t v) |
218 | 565k | { |
219 | 565k | const char *fp = pprintf_scan(s, format); |
220 | 565k | char str[25]; |
221 | 565k | const size_t z = strlen("%"PRId64); |
222 | | |
223 | | #ifdef DEBUG |
224 | | size_t i; |
225 | | |
226 | | for (i = 0; i < z; i++) |
227 | | if (fp[i] != ("%"PRId64)[i]) |
228 | | break; |
229 | | if (i != z) |
230 | | lprintf1("Bad format in pprinti64d: %s\n", format); |
231 | | #endif |
232 | 565k | gs_snprintf(str, sizeof(str), "%"PRId64, v); |
233 | 565k | pputs_short(s, str); |
234 | 565k | return pprintf_scan(s, fp + z); |
235 | 565k | } |
236 | | const char * |
237 | | pprinti64d2(stream *s, const char *format, int64_t v1, int64_t v2) |
238 | 10.8k | { |
239 | 10.8k | return pprinti64d1(s, pprinti64d1(s, format, v1), v2); |
240 | 10.8k | } |
241 | | const char * |
242 | | pprinti64d3(stream *s, const char *format, int64_t v1, int64_t v2, int64_t v3) |
243 | 6 | { |
244 | 6 | return pprinti64d2(s, pprinti64d1(s, format, v1), v2, v3); |
245 | 6 | } |
246 | | |
247 | | /* Print (a) string(s) using a format. */ |
248 | | const char * |
249 | | pprints1(stream * s, const char *format, const char *str) |
250 | 818k | { |
251 | 818k | const char *fp = pprintf_scan(s, format); |
252 | | |
253 | | #ifdef DEBUG |
254 | | if (*fp == 0 || fp[1] != 's') /* shouldn't happen! */ |
255 | | lprintf1("Bad format in pprints: %s\n", format); |
256 | | #endif |
257 | 818k | pputs_short(s, str); |
258 | 818k | return pprintf_scan(s, fp + 2); |
259 | 818k | } |
260 | | const char * |
261 | | pprints2(stream * s, const char *format, const char *str1, const char *str2) |
262 | 0 | { |
263 | 0 | return pprints1(s, pprints1(s, format, str1), str2); |
264 | 0 | } |
265 | | const char * |
266 | | pprints3(stream * s, const char *format, const char *str1, const char *str2, |
267 | | const char *str3) |
268 | 0 | { |
269 | 0 | return pprints2(s, pprints1(s, format, str1), str2, str3); |
270 | 0 | } |