Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmlibarchive/libarchive/archive_string_sprintf.c
Line
Count
Source
1
/*-
2
 * Copyright (c) 2003-2007 Tim Kientzle
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#include "archive_platform.h"
27
28
/*
29
 * The use of printf()-family functions can be troublesome
30
 * for space-constrained applications.  In addition, correctly
31
 * implementing this function in terms of vsnprintf() requires
32
 * two calls (one to determine the size, another to format the
33
 * result), which in turn requires duplicating the argument list
34
 * using va_copy, which isn't yet universally available. <sigh>
35
 *
36
 * So, I've implemented a bare minimum of printf()-like capability
37
 * here.  This is only used to format error messages, so doesn't
38
 * require any floating-point support or field-width handling.
39
 */
40
#ifdef HAVE_ERRNO_H
41
#include <errno.h>
42
#endif
43
#include <stdio.h>
44
45
#include "archive_string.h"
46
#include "archive_private.h"
47
48
/*
49
 * Utility functions to format signed/unsigned integers and append
50
 * them to an archive_string.
51
 */
52
static void
53
append_uint(struct archive_string *as, uintmax_t d, unsigned base)
54
39.6k
{
55
39.6k
  static const char digits[] = "0123456789abcdef";
56
39.6k
  if (d >= base)
57
23.5k
    append_uint(as, d/base, base);
58
39.6k
  archive_strappend_char(as, digits[d % base]);
59
39.6k
}
60
61
static void
62
append_int(struct archive_string *as, intmax_t d, unsigned base)
63
14.3k
{
64
14.3k
  uintmax_t ud;
65
66
14.3k
  if (d < 0) {
67
666
    archive_strappend_char(as, '-');
68
666
    ud = (d == INTMAX_MIN) ? (uintmax_t)(INTMAX_MAX) + 1 : (uintmax_t)(-d);
69
666
  } else
70
13.7k
    ud = d;
71
14.3k
  append_uint(as, ud, base);
72
14.3k
}
73
74
75
void
76
archive_string_sprintf(struct archive_string *as, const char *fmt, ...)
77
4.33k
{
78
4.33k
  va_list ap;
79
80
4.33k
  va_start(ap, fmt);
81
4.33k
  archive_string_vsprintf(as, fmt, ap);
82
4.33k
  va_end(ap);
83
4.33k
}
84
85
/*
86
 * Like 'vsprintf', but ensures the target is big enough, resizing if
87
 * necessary.
88
 */
89
void
90
archive_string_vsprintf(struct archive_string *as, const char *fmt,
91
    va_list ap)
92
186k
{
93
186k
  char long_flag;
94
186k
  intmax_t s; /* Signed integer temp. */
95
186k
  uintmax_t u; /* Unsigned integer temp. */
96
186k
  const char *p, *p2;
97
186k
  const wchar_t *pw;
98
99
186k
  if (archive_string_ensure(as, 64) == NULL)
100
0
    __archive_errx(1, "Out of memory");
101
102
186k
  if (fmt == NULL) {
103
0
    as->s[0] = 0;
104
0
    return;
105
0
  }
106
107
7.57M
  for (p = fmt; *p != '\0'; p++) {
108
7.38M
    const char *saved_p = p;
109
110
7.38M
    if (*p != '%') {
111
7.34M
      archive_strappend_char(as, *p);
112
7.34M
      continue;
113
7.34M
    }
114
115
35.3k
    p++;
116
117
35.3k
    long_flag = '\0';
118
35.3k
    switch(*p) {
119
1.46k
    case 'l':
120
1.46k
      if (p[1] == 'l') {
121
0
        long_flag = 'L';
122
0
        p += 2;
123
0
        break;
124
0
      }
125
1.46k
      __LA_FALLTHROUGH;
126
3.31k
    case 'j':
127
3.31k
    case 'z':
128
3.31k
      long_flag = *p;
129
3.31k
      p++;
130
3.31k
      break;
131
35.3k
    }
132
133
35.3k
    switch (*p) {
134
0
    case '%':
135
0
      archive_strappend_char(as, '%');
136
0
      break;
137
0
    case 'c':
138
0
      s = va_arg(ap, int);
139
0
      archive_strappend_char(as, (char)s);
140
0
      break;
141
14.3k
    case 'd':
142
14.3k
      switch(long_flag) {
143
1.55k
      case 'j': s = va_arg(ap, intmax_t); break;
144
0
      case 'l': s = va_arg(ap, long); break;
145
0
      case 'L': s = va_arg(ap, long long); break;
146
0
      case 'z': s = va_arg(ap, ssize_t); break;
147
12.8k
      default:  s = va_arg(ap, int); break;
148
14.3k
      }
149
14.3k
      append_int(as, s, 10);
150
14.3k
      break;
151
19.0k
    case 's':
152
19.0k
      switch(long_flag) {
153
0
      case 'l':
154
0
      case 'L':
155
0
        pw = va_arg(ap, wchar_t *);
156
0
        if (pw == NULL)
157
0
          pw = L"(null)";
158
0
        if (archive_string_append_from_wcs(as, pw,
159
0
            wcslen(pw)) != 0 && errno == ENOMEM)
160
0
          __archive_errx(1, "Out of memory");
161
0
        break;
162
19.0k
      default:
163
19.0k
        p2 = va_arg(ap, char *);
164
19.0k
        if (p2 == NULL)
165
0
          p2 = "(null)";
166
19.0k
        archive_strcat(as, p2);
167
19.0k
        break;
168
19.0k
      }
169
19.0k
      break;
170
19.0k
    case 'S':
171
0
      pw = va_arg(ap, wchar_t *);
172
0
      if (pw == NULL)
173
0
        pw = L"(null)";
174
0
      if (archive_string_append_from_wcs(as, pw,
175
0
          wcslen(pw)) != 0 && errno == ENOMEM)
176
0
        __archive_errx(1, "Out of memory");
177
0
      break;
178
1.78k
    case 'o': case 'u': case 'x': case 'X':
179
      /* Common handling for unsigned integer formats. */
180
1.78k
      switch(long_flag) {
181
298
      case 'j': u = va_arg(ap, uintmax_t); break;
182
1.46k
      case 'l': u = va_arg(ap, unsigned long); break;
183
0
      case 'L': u = va_arg(ap, unsigned long long); break;
184
4
      case 'z': u = va_arg(ap, size_t); break;
185
24
      default:  u = va_arg(ap, unsigned int); break;
186
1.78k
      }
187
      /* Format it in the correct base. */
188
1.78k
      switch (*p) {
189
0
      case 'o': append_uint(as, u, 8); break;
190
326
      case 'u': append_uint(as, u, 10); break;
191
1.46k
      default: append_uint(as, u, 16); break;
192
1.78k
      }
193
1.78k
      break;
194
1.78k
    default:
195
      /* Rewind and print the initial '%' literally. */
196
146
      p = saved_p;
197
146
      archive_strappend_char(as, *p);
198
35.3k
    }
199
35.3k
  }
200
186k
}