-
Notifications
You must be signed in to change notification settings - Fork 0
/
fmt.cc
133 lines (116 loc) · 2.95 KB
/
fmt.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
extern "C" {
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_fmt.h"
#include "fmt_arginfo.h"
#include "ext/spl/spl_exceptions.h"
}
#define FMT_HEADER_ONLY
#include "fmt/format.h"
PHP_MINIT_FUNCTION(fmt)
{
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(fmt)
{
return SUCCESS;
}
PHP_MINFO_FUNCTION(fmt)
{
php_info_print_table_start();
php_info_print_table_header(2, "fmt support", "enabled");
php_info_print_table_end();
}
PHP_FUNCTION(fmt)
{
char* format = nullptr;
size_t format_length = 0;
zval *args = nullptr;
int argc = 0;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_STRING(format, format_length)
Z_PARAM_VARIADIC('*', args, argc)
ZEND_PARSE_PARAMETERS_END();
fmt::dynamic_format_arg_store<fmt::format_context> store;
std::vector<std::shared_ptr<zend_string>> tmp_str_list;
for (int i = 0; i < argc; ++i)
{
zval* tmp = &args[i];
loop:
ZVAL_DEREF(tmp);
switch (Z_TYPE_P(tmp)) {
case IS_UNDEF:
case IS_NULL:
store.push_back("");
case IS_FALSE:
store.push_back(false);
case IS_TRUE:
store.push_back(true);
case IS_LONG:
store.push_back(Z_LVAL_P(tmp));
break;
case IS_DOUBLE:
store.push_back(Z_DVAL_P(tmp));
break;
case IS_STRING:
store.push_back(Z_STRVAL_P(tmp));
break;
case IS_ARRAY:
store.push_back("array");
break;
case IS_OBJECT: {
// NOTE(rory): Resolve object to a string
std::shared_ptr<zend_string> tmp_str(_zval_get_string_func(tmp), [](zend_string* s) {
zend_string_release(s);
});
store.push_back(ZSTR_VAL(tmp_str));
tmp_str_list.push_back(tmp_str);
}
break;
case IS_RESOURCE:
store.push_back("resource");
break;
case IS_REFERENCE:
goto loop;
break;
default:
store.push_back("unknown");
break;
}
}
try {
std::string result = fmt::vformat(format, store);
RETURN_STRING(result.c_str());
} catch (const fmt::format_error& ex) {
zend_throw_error(spl_ce_InvalidArgumentException, ex.what());
return;
}
}
static const zend_module_dep fmt_deps[] = {
ZEND_MOD_REQUIRED("spl")
ZEND_MOD_END
};
zend_module_entry fmt_module_entry = {
STANDARD_MODULE_HEADER_EX,
NULL,
fmt_deps,
"fmt",
ext_functions,
PHP_MINIT(fmt),
PHP_MSHUTDOWN(fmt),
NULL,
NULL,
PHP_MINFO(fmt),
PHP_FMT_VERSION,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_FMT
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(fmt)
#endif