Coverage Report

Created: 2026-02-09 06:05

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
20.2k
{
55
20.2k
  static const char digits[] = "0123456789abcdef";
56
20.2k
  if (d >= base)
57
12.3k
    append_uint(as, d/base, base);
58
20.2k
  archive_strappend_char(as, digits[d % base]);
59
20.2k
}
60
61
static void
62
append_int(struct archive_string *as, intmax_t d, unsigned base)
63
6.40k
{
64
6.40k
  uintmax_t ud;
65
66
6.40k
  if (d < 0) {
67
372
    archive_strappend_char(as, '-');
68
372
    ud = (d == INTMAX_MIN) ? (uintmax_t)(INTMAX_MAX) + 1 : (uintmax_t)(-d);
69
372
  } else
70
6.02k
    ud = d;
71
6.40k
  append_uint(as, ud, base);
72
6.40k
}
73
74
75
void
76
archive_string_sprintf(struct archive_string *as, const char *fmt, ...)
77
2.65k
{
78
2.65k
  va_list ap;
79
80
2.65k
  va_start(ap, fmt);
81
2.65k
  archive_string_vsprintf(as, fmt, ap);
82
2.65k
  va_end(ap);
83
2.65k
}
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
117k
{
93
117k
  char long_flag;
94
117k
  intmax_t s; /* Signed integer temp. */
95
117k
  uintmax_t u; /* Unsigned integer temp. */
96
117k
  const char *p, *p2;
97
117k
  const wchar_t *pw;
98
99
117k
  if (archive_string_ensure(as, 64) == NULL)
100
0
    __archive_errx(1, "Out of memory");
101
102
117k
  if (fmt == NULL) {
103
0
    as->s[0] = 0;
104
0
    return;
105
0
  }
106
107
4.82M
  for (p = fmt; *p != '\0'; p++) {
108
4.71M
    const char *saved_p = p;
109
110
4.71M
    if (*p != '%') {
111
4.69M
      archive_strappend_char(as, *p);
112
4.69M
      continue;
113
4.69M
    }
114
115
15.7k
    p++;
116
117
15.7k
    long_flag = '\0';
118
15.7k
    switch(*p) {
119
1.30k
    case 'l':
120
1.30k
      if (p[1] == 'l') {
121
0
        long_flag = 'L';
122
0
        p += 2;
123
0
        break;
124
0
      }
125
1.30k
      __LA_FALLTHROUGH;
126
2.02k
    case 'j':
127
2.02k
    case 'z':
128
2.02k
      long_flag = *p;
129
2.02k
      p++;
130
2.02k
      break;
131
15.7k
    }
132
133
15.7k
    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
6.40k
    case 'd':
142
6.40k
      switch(long_flag) {
143
560
      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
5.84k
      default:  s = va_arg(ap, int); break;
148
6.40k
      }
149
6.40k
      append_int(as, s, 10);
150
6.40k
      break;
151
7.77k
    case 's':
152
7.77k
      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
7.77k
      default:
163
7.77k
        p2 = va_arg(ap, char *);
164
7.77k
        if (p2 == NULL)
165
0
          p2 = "(null)";
166
7.77k
        archive_strcat(as, p2);
167
7.77k
        break;
168
7.77k
      }
169
7.77k
      break;
170
7.77k
    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.48k
    case 'o': case 'u': case 'x': case 'X':
179
      /* Common handling for unsigned integer formats. */
180
1.48k
      switch(long_flag) {
181
154
      case 'j': u = va_arg(ap, uintmax_t); break;
182
1.30k
      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
20
      default:  u = va_arg(ap, unsigned int); break;
186
1.48k
      }
187
      /* Format it in the correct base. */
188
1.48k
      switch (*p) {
189
0
      case 'o': append_uint(as, u, 8); break;
190
178
      case 'u': append_uint(as, u, 10); break;
191
1.30k
      default: append_uint(as, u, 16); break;
192
1.48k
      }
193
1.48k
      break;
194
1.48k
    default:
195
      /* Rewind and print the initial '%' literally. */
196
116
      p = saved_p;
197
116
      archive_strappend_char(as, *p);
198
15.7k
    }
199
15.7k
  }
200
117k
}