Files
swift-mirror/stdlib/public/Darwin/os/format.m
Saleem Abdulrasool 7e050d14e6 stdlib: remove usage of GNU extensions in the Darwin os module
Remove the gratuitous use of the GNU extensions to implement the OS logging
module.  This allows us to enable `-Werror=gnu` globally, even on macOS builds.
2019-10-30 08:38:46 -07:00

307 lines
11 KiB
Objective-C

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include <sys/param.h>
#include <Foundation/Foundation.h>
#include "format.h"
static inline void
_os_log_encode_arg(os_trace_blob_t ob, os_log_fmt_cmd_t cmd, const void *data)
{
os_trace_blob_add(ob, cmd, sizeof(os_log_fmt_cmd_s));
os_trace_blob_add(ob, data, cmd->cmd_size);
}
bool
_os_log_encode(char buf[OS_LOG_FMT_BUF_SIZE], const char *format, va_list args,
int saved_errno, os_trace_blob_t ob)
{
os_log_fmt_hdr_s hdr = {0};
os_trace_blob_add(ob, &hdr, sizeof(hdr));
const char *percent = strchr(format, '%');
while (percent != NULL) {
++percent;
if (percent[0] != '%') {
os_log_fmt_cmd_s cmd = {0};
os_log_count_type_t widtht = T_C_NONE;
os_log_count_type_t prect = T_C_NONE;
os_log_fmt_cmd_flags_t flags = 0;
int type = T_INT;
bool long_double = false;
int precision = 0;
char ch;
if (hdr.hdr_cmd_cnt == OS_LOG_FMT_MAX_CMDS) {
break;
}
for (bool done = false; !done; percent++) {
switch (ch = percent[0]) {
/* type of types or other */
case 'l': type++; break; // longer
case 'h': type--; break; // shorter
case 'z': type = T_SIZE; break;
case 'j': type = T_INTMAX; break;
case 't': type = T_PTRDIFF; break;
case '*': // dynamic width
widtht = T_C_DYNAMIC;
// if the next character is a '.' then increment percent
// and fallthrough to the precision handling code
if (percent[1] != '.') {
break;
}
percent++;
// FALLTHROUGH
case '.': // precision
if ((percent[1]) == '*') {
prect = T_C_DYNAMIC;
percent++;
} else {
while (isdigit(percent[1])) {
precision = 10 * precision + (percent[1] - '0');
percent++;
}
if (precision > 1024) precision = 1024;
prect = T_C_STATIC;
}
break;
case '-': // left-align
case '+': // force sign
case ' ': // prefix non-negative with space
case '#': // alternate
case '\'': // group by thousands
break;
case '{': // annotated symbols
for (const char *curr2 = percent + 1; (ch = (*curr2)) != 0; curr2++) {
if (ch == '}') {
if (strncmp(percent + 1, "private", MIN(curr2 - percent - 1, 7)) == 0) {
hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_PRIVATE;
flags |= OSLF_CMD_FLAG_PRIVATE;
} else if (strncmp(percent + 1, "public", MIN(curr2 - percent - 1, 6)) == 0) {
flags |= OSLF_CMD_FLAG_PUBLIC;
}
percent = curr2;
break;
}
}
break;
#define encode_width() \
do { \
if (widtht == T_C_DYNAMIC) { \
cmd.cmd_type = OSLF_CMD_TYPE_SCALAR; \
encode(int, 0); \
} \
} while (0)
// clang inconsistency: static precision counts are still marked with the
// privacy bits of the command they preceed
#define encode_precision(type) \
do { \
if (prect != T_C_NONE) { \
cmd.cmd_type = type; \
cmd.cmd_size = sizeof(int); \
if (prect == T_C_STATIC && type == OSLF_CMD_TYPE_COUNT) { \
cmd.cmd_flags = flags; \
} else if (prect == T_C_DYNAMIC) { \
precision = va_arg(args, int); \
} \
_os_log_encode_arg(ob, &cmd, &precision); \
hdr.hdr_cmd_cnt++; \
prect = T_C_NONE; \
} \
} while (0)
// scalar data types encode their precision as a scalar
#define encode_scalar_preamble() \
do { \
encode_width(); \
if (prect == T_C_DYNAMIC) { \
encode_precision(OSLF_CMD_TYPE_SCALAR); \
} \
} while (0)
#define encode_pointer_preamble() \
do { \
encode_width(); \
encode_precision(OSLF_CMD_TYPE_COUNT); \
} while (0)
#define encode_nsstring(flags) \
do { \
NSString *__arg = va_arg(args, NSString *); \
const char *_Nullable __var = __arg.UTF8String; \
cmd.cmd_flags = flags; \
cmd.cmd_size = sizeof(__var); \
_os_log_encode_arg(ob, &cmd, &__var); \
hdr.hdr_cmd_cnt++; \
} while (0)
#define encode_smallint(ty, flags) \
do { \
int __var = va_arg(args, int); \
cmd.cmd_flags = flags; \
cmd.cmd_size = sizeof(__var); \
_os_log_encode_arg(ob, &cmd, &__var); \
hdr.hdr_cmd_cnt++; \
} while (0)
#define encode(ty, flags) \
do { \
ty __var = va_arg(args, ty); \
cmd.cmd_flags = flags; \
cmd.cmd_size = sizeof(__var); \
_os_log_encode_arg(ob, &cmd, &__var); \
hdr.hdr_cmd_cnt++; \
} while (0)
/* fixed types */
case 'c': // char
case 'd': // integer
case 'i': // integer
case 'o': // octal
case 'u': // unsigned
case 'x': // hex
case 'X': // upper-hex
encode_scalar_preamble();
cmd.cmd_type = OSLF_CMD_TYPE_SCALAR;
switch (type) {
case T_CHAR:
encode_smallint(char, flags);
break;
case T_SHORT:
encode_smallint(short, flags);
break;
case T_INT:
encode(int, flags);
break;
case T_LONG:
encode(long, flags);
break;
case T_LONGLONG:
encode(long long, flags);
break;
case T_SIZE:
encode(size_t, flags);
break;
case T_INTMAX:
encode(intmax_t, flags);
break;
case T_PTRDIFF:
encode(ptrdiff_t, flags);
break;
default:
return false;
}
done = true;
break;
case 'p': // emit pointers as scalars
cmd.cmd_type = OSLF_CMD_TYPE_SCALAR;
encode(void *, flags);
done = true;
break;
case 'C': // wchar is treated like %lc
encode_scalar_preamble();
cmd.cmd_type = OSLF_CMD_TYPE_SCALAR;
encode_smallint(wint_t, flags);
done = true;
break;
case 'P': // pointer data
encode_pointer_preamble();
hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_NON_SCALAR;
cmd.cmd_type = OSLF_CMD_TYPE_DATA;
cmd.cmd_size = sizeof(void *);
encode(void *, flags);
done = true;
break;
case 'L': // long double
long_double = true;
break;
case 'a':
case 'A':
case 'e':
case 'E': // floating types
case 'f':
case 'F':
case 'g':
case 'G':
encode_scalar_preamble();
cmd.cmd_type = OSLF_CMD_TYPE_SCALAR;
if (long_double) {
encode(long double, flags);
} else {
encode(double, flags);
}
done = true;
break;
case 's': // Strings sent from Swift as NSString objects
encode_pointer_preamble();
hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_NON_SCALAR;
cmd.cmd_type = OSLF_CMD_TYPE_STRING;
encode_nsstring(flags);
done = true;
break;
case '@': // CFTypeRef aka NSObject *
// %@ does not support precision
encode_width();
hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_NON_SCALAR;
cmd.cmd_type = OSLF_CMD_TYPE_OBJECT;
encode(void *, flags);
done = true;
break;
case 'm':
cmd.cmd_type = OSLF_CMD_TYPE_SCALAR;
cmd.cmd_size = sizeof(int);
cmd.cmd_flags = flags;
_os_log_encode_arg(ob, &cmd, &saved_errno);
hdr.hdr_cmd_cnt++;
done = true;
break;
default:
if (isdigit(ch)) { // [0-9]
continue;
}
done = true;
break;
}
if (done) {
percent = strchr(percent, '%'); // Find next format
break;
}
}
} else {
percent = strchr(percent+1, '%'); // Find next format after %%
}
}
*(os_log_fmt_hdr_t)buf = hdr;
return true;
}
#undef encode_nsstring
#undef encode_smallint
#undef encode