void ph_logv(uint8_t level, const char *fmt, va_list ap) { struct timeval now = ph_time_now(); ph_thread_t *me; int len; va_list copy; char *buf; PH_STRING_DECLARE_STACK(mystr, 1024); void *args[] = { &level, &mystr }; static ph_hook_point_t *hook = NULL; char tname[32]; if (level > log_level) { return; } len = strlen(fmt); if (len == 0) { return; } me = ph_thread_self(); get_tname(me, tname, sizeof(tname)); va_copy(copy, ap); ph_string_printf(&mystr, "%" PRIi64 ".%03d %s: %s `Pv%s%p%s", (int64_t)now.tv_sec, (int)(now.tv_usec / 1000), log_labels[level], tname, fmt, ph_vaptr(copy), fmt[len-1] == '\n' ? "" : "\n"); va_end(copy); if (ph_unlikely(hook == NULL)) { hook = ph_hook_point_get_cstr(PH_LOG_HOOK_NAME, true); } ph_hook_invoke_inner(hook, sizeof(args)/sizeof(args[0]), args); if (disable_stderr) { return; } pthread_mutex_lock(&log_lock); buf = mystr.buf; len = mystr.len; while (len) { int x = write(STDERR_FILENO, buf, len); if (x <= 0) { break; } buf += x; len -= x; } pthread_mutex_unlock(&log_lock); }
static void stack_tests(void) { PH_STRING_DECLARE_STACK(stack1, 10); PH_STRING_DECLARE_GROW(stack2, 10, mt_misc); // Expect this to succeed; we silently truncate is(ph_string_append_cstr(&stack1, "12345678901"), PH_OK); // Ensure length is good is(10, ph_string_len(&stack1)); is(ph_string_append_cstr(&stack2, "12345678901234567890"), PH_OK); is(20, ph_string_len(&stack2)); ph_string_delref(&stack2); }
static void utf16_tests(void) { uint32_t i, len, n, off; int32_t cp; PH_STRING_DECLARE_STACK(str, 64); for (i = 0; i < sizeof(unicode_strings)/sizeof(unicode_strings[0]); i++) { ph_string_reset(&str); is(ph_string_append_cstr(&str, unicode_strings[i].input), PH_OK); is(ph_string_is_valid_utf8(&str), unicode_strings[i].valid); } for (i = 0; i < sizeof(utf16_strings)/sizeof(utf16_strings[0]); i++) { len = strlen(utf16_strings[i].output); ph_string_reset(&str); is(ph_string_append_utf16_as_utf8(&str, &utf16_strings[i].cp, 1, &n), PH_OK); is(n, len); ok(ph_string_equal_cstr(&str, utf16_strings[i].output), "matches"); // Iterate the codepoints; we should get out what we put in off = 0; is(ph_string_iterate_utf8_as_utf16(&str, &off, &cp), PH_OK); diag("expect %" PRIx32 " got %" PRIx32, utf16_strings[i].cp, cp); is(cp, utf16_strings[i].cp); // Round-trip; put in the output and expect to iterate and get the input cp ph_string_reset(&str); is(ph_string_append_cstr(&str, utf16_strings[i].output), PH_OK); ok(ph_string_is_valid_utf8(&str), "valid utf-8"); off = 0; is(ph_string_iterate_utf8_as_utf16(&str, &off, &cp), PH_OK); diag("round-trip: expect %" PRIx32 " got %" PRIx32, utf16_strings[i].cp, cp); is(cp, utf16_strings[i].cp); } for (i = 0; i < sizeof(surrogates)/sizeof(surrogates[0]); i++) { ph_string_reset(&str); is(ph_string_append_utf16_as_utf8(&str, surrogates[i].points, 2, &n), PH_OK); is(n, strlen(surrogates[i].encoded)); off = 0; // We don't do any magical transformation of surrogates, and we don't // consider them valid utf8 strings is(ph_string_iterate_utf8_as_utf16(&str, &off, &cp), PH_ERR); } }