1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2023 Keith Packard
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #define _GNU_SOURCE
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <assert.h>
42 
43 #if !defined(__PICOLIBC__) || defined(TINY_STDIO) || defined(_WANT_IO_LONG_LONG)
44 
45 unsigned long long
naive_atou(const char * buf)46 naive_atou(const char *buf)
47 {
48     unsigned long long v = 0;
49     int sign = 1;
50     char c;
51 
52     while ((c = *buf++) == ' ')
53         ;
54     do {
55         assert('0' <= c && c <= '9');
56         v = v * 10 + (c - '0');
57         c = *buf++;
58     } while(c);
59     return v * sign;
60 }
61 
62 long long
naive_atol(const char * buf)63 naive_atol(const char *buf)
64 {
65     long long v = 0;
66     int sign = 1;
67     char c;
68 
69     while ((c = *buf++) == ' ')
70         ;
71     switch (c) {
72     case '+':
73         sign = 1;
74         c = *buf++;
75         break;
76     case '-':
77         sign = -1;
78         c = *buf++;
79         break;
80     }
81     do {
82         assert('0' <= c && c <= '9');
83         v = v * 10 + (c - '0');
84         c = *buf++;
85     } while(c);
86     return v * sign;
87 }
88 
89 char *
naive_utoa(char * buf,unsigned long long v)90 naive_utoa(char *buf, unsigned long long v)
91 {
92     buf += 21;
93     *--buf = '\0';
94     do {
95         *--buf = v % 10 + '0';
96         v /= 10;
97     } while (v);
98     return buf;
99 }
100 
101 char *
naive_ltoa(char * buf,long long v)102 naive_ltoa(char *buf, long long v)
103 {
104     int sign = 0;
105     buf += 21;
106     *--buf = '\0';
107     if (v < 0) {
108         sign = 1;
109         v = -v;
110     }
111     do {
112         *--buf = v % 10 + '0';
113         v /= 10;
114     } while (v);
115     if (sign)
116         *--buf = '-';
117     return buf;
118 }
119 
120 static int
check(long long x)121 check(long long x)
122 {
123     long long   scanned, uscanned, u;
124     char        buf[64], naive_buf[64];
125     char        *naive;
126     int         ret = 0;
127 
128     sprintf(buf, "%lld", x);
129     naive = naive_ltoa(naive_buf, x);
130     sscanf(naive, "%lld", &scanned);
131     if (strcmp(buf, naive) != 0) {
132         printf("sprintf '%s' naive '%s'\n", buf, naive);
133         ret = 1;
134     }
135     if (scanned != x) {
136         printf("sscanf '%lld' actual '%lld'\n", scanned, x);
137         ret = 1;
138     }
139 
140     u = (unsigned long long) x;
141     sprintf(buf, "%llu", u);
142     naive = naive_utoa(naive_buf, u);
143     sscanf(naive, "%llu", &uscanned);
144     if (strcmp(buf, naive) != 0) {
145         printf("unsigned sprintf '%s' naive '%s'\n", buf, naive);
146         ret = 1;
147     }
148     if (scanned != x) {
149         printf("unsigned sscanf '%llu' actual '%llu'\n", uscanned, u);
150         ret = 1;
151     }
152     return ret;
153 }
154 
155 static long long
randval(void)156 randval(void)
157 {
158     unsigned long        a, b, c;
159 
160     a = random();
161     b = random();
162     c = random();
163     return ((unsigned long long) a << 33) ^ ((unsigned long long) b << 15) ^ ((unsigned long long) c);
164 }
165 
166 #ifdef __MSP430__
167 #define RAND_LOOPS 1000ll
168 #define SMALL_MIN -1024ll
169 #define SMALL_MAX 1024ll
170 #else
171 #define RAND_LOOPS 100000ll
172 #define SMALL_MIN -65536
173 #define SMALL_MAX 65536
174 #endif
175 
main(void)176 int main(void)
177 {
178     long long   x;
179     int         ret = 0;
180     long long   t;
181 
182     for (x = SMALL_MIN; x <= SMALL_MAX; x++)
183         ret |= check(x);
184 
185     for (t = 0; t < RAND_LOOPS; t++) {
186         x = randval();
187         ret |= check(x);
188     }
189     return ret;
190 }
191 
192 #else
193 
main(void)194 int main(void)
195 {
196     printf("skipping long long I/O test\n");
197     return 77;
198 }
199 
200 #endif
201