VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/nocrt-vsscanf.cpp@ 106580

Last change on this file since 106580 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/* $Id: nocrt-vsscanf.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - No-CRT - Simplistic vsscanf().
4 */
5
6/*
7 * Copyright (C) 2022-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define IPRT_NO_CRT_FOR_3RD_PARTY
42#include "internal/nocrt.h"
43#include <iprt/nocrt/stdio.h>
44#include <iprt/ctype.h>
45#include <iprt/err.h>
46#include <iprt/stdarg.h>
47#include <iprt/string.h>
48
49
50static const char *rtNoCrtScanString(const char *pszString, size_t cchWidth, char *pszDst, int *pcMatches)
51{
52 if (pszDst)
53 *pcMatches += 1;
54 while (cchWidth-- > 0)
55 {
56 char ch = *pszString;
57 if (pszDst)
58 *pszDst++ = ch;
59 if (ch != '\0')
60 pszString++;
61 else
62 return pszString;
63 }
64 if (pszDst)
65 *pszDst = '\0';
66 return pszString;
67}
68
69
70static const char *rtNoCrtScanChars(const char *pszString, unsigned cchWidth, char *pchDst, int *pcMatches)
71{
72 if (pchDst)
73 *pcMatches += 1;
74 while (cchWidth-- > 0)
75 {
76 char ch = *pszString;
77 if (pchDst)
78 *pchDst++ = ch;
79 if (ch != '\0')
80 pszString++;
81 else
82 {
83 /** @todo how do we handle a too short strings? memset the remainder and
84 * count it as a match? */
85 if (pchDst && cchWidth > 0)
86 RT_BZERO(pchDst, cchWidth);
87 return pszString;
88 }
89 }
90 return pszString;
91}
92
93
94static void rtNoCrtStorInt(void *pvDst, char chPrefix, uint64_t uValue)
95{
96 switch (chPrefix)
97 {
98 default:
99 AssertFailed();
100 RT_FALL_THRU();
101 case '\0': *(unsigned int *)pvDst = (unsigned int)uValue; break;
102 case 'H': *(unsigned char *)pvDst = (unsigned char)uValue; break;
103 case 'h': *(unsigned short *)pvDst = (unsigned short)uValue; break;
104 case 'j': *(uint64_t *)pvDst = uValue; break;
105 case 'l': *(unsigned long *)pvDst = (unsigned long)uValue; break;
106 case 'L': *(unsigned long long *)pvDst = (unsigned long long)uValue; break;
107 case 't': *(ptrdiff_t *)pvDst = (ptrdiff_t)uValue; break;
108 case 'Z':
109 case 'z': *(size_t *)pvDst = (size_t)uValue; break;
110 }
111}
112
113
114static const char *rtNoCrtScanInt(const char *pszString, unsigned uBase, bool fSigned, char chPrefix, int cchWidth,
115 void *pvDst, int *pcMatches)
116{
117 if (cchWidth >= 0 && cchWidth < _16M)
118 uBase |= (unsigned)cchWidth << 8;
119
120 int rc;
121 if (fSigned)
122 {
123 int64_t iVal = 0;
124 rc = RTStrToInt64Ex(pszString, (char **)&pszString, uBase, &iVal);
125 if (RT_SUCCESS(rc))
126 {
127 if (pvDst)
128 {
129 rtNoCrtStorInt(pvDst, chPrefix, (uint64_t)iVal);
130 *pcMatches += 1;
131 }
132 }
133 else
134 pszString = NULL;
135 }
136 else
137 {
138 uint64_t uVal = 0;
139 rc = RTStrToUInt64Ex(pszString, (char **)&pszString, uBase, &uVal);
140 if (RT_SUCCESS(rc))
141 {
142 if (pvDst)
143 {
144 rtNoCrtStorInt(pvDst, chPrefix, uVal);
145 *pcMatches += 1;
146 }
147 }
148 else
149 pszString = NULL;
150 }
151
152 return pszString;
153}
154
155
156static const char *rtNoCrtScanFloat(const char *pszString, char chPrefix, int cchWidth, void *pvDst, int *pcMatches)
157{
158 size_t const cchMax = cchWidth > 0 ? (unsigned)cchWidth : 0;
159 int rc;
160 switch (chPrefix)
161 {
162 default:
163 case '\0':
164#ifndef RT_OS_WINDOWS /* Windows doesn't do float, only double and "long" double (same as double). */
165 rc = RTStrToFloatEx(pszString, (char **)&pszString, cchMax, (float *)pvDst);
166 break;
167#else
168 RT_FALL_THRU();
169#endif
170 case 'l':
171 rc = RTStrToDoubleEx(pszString, (char **)&pszString, cchMax, (double *)pvDst);
172 break;
173
174 case 'L':
175 rc = RTStrToLongDoubleEx(pszString, (char **)&pszString, cchMax, (long double *)pvDst);
176 break;
177 }
178 if (rc != VERR_NO_DIGITS)
179 *pcMatches += pvDst != NULL;
180 else
181 pszString = NULL;
182 return pszString;
183}
184
185
186#undef vsscanf
187int RT_NOCRT(vsscanf)(const char *pszString, const char *pszFormat, va_list va)
188{
189#ifdef RT_STRICT
190 const char * const pszFormatStart = pszFormat;
191#endif
192 const char * const pszStart = pszString;
193 int cMatches = 0;
194 char chFmt;
195 while ((chFmt = *pszFormat++) != '\0')
196 {
197 switch (chFmt)
198 {
199 default:
200 if (chFmt == *pszString)
201 pszString++;
202 else
203 return cMatches;
204 break;
205
206 /*
207 * White space will match zero or more whitespace character in the
208 * source string, no specific type. So, we advance to the next no-space
209 * character in each of the string.
210 */
211 case ' ': /* See RT_C_IS_SPACE */
212 case '\t':
213 case '\n':
214 case '\r':
215 case '\v':
216 case '\f':
217 while (RT_C_IS_SPACE(*pszFormat))
218 pszFormat++;
219 while (RT_C_IS_SPACE(*pszString))
220 pszFormat++;
221 break;
222
223 /*
224 * %[*][width][h|l|ll|L|q|t|z|Z|]type
225 */
226 case '%':
227 {
228 chFmt = *pszFormat++;
229
230 /* Escaped '%s'? */
231 if (chFmt == '%')
232 {
233 if (*pszString == '%')
234 pszString++;
235 else
236 return cMatches;
237 break;
238 }
239
240 /* Assigning or non-assigning argument? */
241 bool const fAssign = chFmt != '*';
242 if (chFmt == '*')
243 chFmt = *pszFormat++;
244
245 /* Width specifier? */
246 int cchWidth = -1;
247 if (RT_C_IS_DIGIT(chFmt))
248 {
249 cchWidth = chFmt - '0';
250 for (;;)
251 {
252 chFmt = *pszFormat++;
253 if (!RT_C_IS_DIGIT(chFmt))
254 break;
255 cchWidth *= 10;
256 cchWidth += chFmt - '0';
257 }
258 }
259
260 /* Size prefix?
261 We convert 'hh' to 'H', 'll' to 'L', and 'I64' to 'L'. The
262 latter is for MSC compatibility, of course. */
263 char chPrefix = '\0';
264 switch (chFmt)
265 {
266 case 'q':
267 chPrefix = 'L';
268 RT_FALL_THRU();
269 case 'L':
270 case 'j':
271 case 'z':
272 case 'Z':
273 case 't':
274 chPrefix = chFmt;
275 chFmt = *pszFormat++;
276 break;
277 case 'l':
278 case 'h':
279 chPrefix = chFmt;
280 chFmt = *pszFormat++;
281 if (chPrefix != 'L' && chFmt == chPrefix)
282 {
283 chPrefix = chPrefix == 'l' ? 'L' : 'H';
284 chFmt = *pszFormat++;
285 }
286 break;
287 case 'I':
288 if (pszFormat[0] == '6' && pszFormat[1] == '4')
289 {
290 chPrefix = 'L';
291 pszFormat += 2;
292 }
293 break;
294 }
295
296 /* Now for the type. */
297 switch (chFmt)
298 {
299 case 'p':
300 chPrefix = 'j';
301 RT_FALL_THRU();
302 case 'd':
303 case 'i':
304 case 'o':
305 case 'u':
306 case 'x':
307 case 'X':
308 {
309 while (RT_C_IS_SPACE(*pszString))
310 pszString++;
311
312 void *pvDst = NULL;
313 if (fAssign)
314 pvDst = va_arg(va, void *); /* This ought to work most place... Probably not standard conforming. */
315 pszString = rtNoCrtScanInt(pszString,
316 chFmt == 'i' ? 0 : chFmt == 'd' || chFmt == 'u' ? 10 : chFmt == 'o' ? 8 : 16,
317 chFmt == 'd' || chFmt == 'i' /* fSigned */,
318 chPrefix, cchWidth, pvDst, &cMatches);
319 if (!pszString)
320 return cMatches;
321 break;
322 }
323
324 case 'a':
325 case 'A':
326 case 'e':
327 case 'E':
328 case 'f':
329 case 'F':
330 case 'g':
331 case 'G':
332 {
333 while (RT_C_IS_SPACE(*pszString))
334 pszString++;
335
336 /* Note! We don't really give a hoot what input format type we're given,
337 we keep and open mind and acceept whatever we find that looks like
338 floating point. This is doubtfully standard compliant. */
339 void *pvDst = NULL;
340 if (fAssign)
341 pvDst = va_arg(va, void *); /* This ought to work most place... Probably not standard conforming. */
342 pszString = rtNoCrtScanFloat(pszString, chPrefix, cchWidth, pvDst, &cMatches);
343 if (!pszString)
344 return cMatches;
345 break;
346 }
347
348 case 'n':
349 {
350 if (fAssign)
351 {
352 void *pvDst = va_arg(va, void *);
353 rtNoCrtStorInt(pvDst, chPrefix, (size_t)(pszString - pszStart));
354 }
355 break;
356 }
357
358 case 'c':
359 if (chPrefix != 'l' && chPrefix != 'L')
360 {
361 /* no whitespace skipped for %c */
362 char *pchDst = NULL;
363 if (fAssign)
364 pchDst = va_arg(va, char *);
365 pszString = rtNoCrtScanChars(pszString, cchWidth < 0 ? 1U : (unsigned)cchWidth, pchDst, &cMatches);
366 break;
367 }
368 RT_FALL_THRU();
369 case 'C':
370 AssertMsgFailedReturn(("Unsupported sscanf type: C/Lc (%s)\n", pszFormatStart), cMatches);
371 break;
372
373 case 's':
374 if (chPrefix != 'l' && chPrefix != 'L')
375 {
376 while (RT_C_IS_SPACE(*pszString))
377 pszString++;
378
379 char *pszDst = NULL;
380 if (fAssign)
381 pszDst = va_arg(va, char *);
382 pszString = rtNoCrtScanString(pszString, cchWidth < 0 ? RTSTR_MAX : (unsigned)cchWidth,
383 pszDst, &cMatches);
384 }
385 RT_FALL_THRU();
386 case 'S':
387 while (RT_C_IS_SPACE(*pszString))
388 pszString++;
389
390 AssertMsgFailedReturn(("Unsupported sscanf type: S/Ls (%s)\n", pszFormatStart), cMatches);
391 break;
392
393 default:
394 AssertMsgFailedReturn(("Unsupported sscanf type: %c (%s)\n", chFmt, pszFormatStart), cMatches);
395 }
396 break;
397 }
398 }
399 }
400 return cMatches;
401}
402RT_ALIAS_AND_EXPORT_NOCRT_SYMBOL(vsscanf);
403
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette