1 /*******************************************************************************
2 Copyright (c) 2018, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * 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.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
29 # include "php_config.h"
40 HashTable psi_builtins
;
42 static bool has_include(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
43 static bool has_include_next(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
44 static bool has_feature(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
45 static bool builtin_constant_p(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
46 static bool signed__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
47 static bool BASE_FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
48 static bool COUNTER__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
49 static bool DATE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
50 static bool FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
51 static bool INCLUDE_LEVEL__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
52 static bool LINE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
53 static bool TIME__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
54 static bool TIMESTAMP__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
56 static inline struct psi_plist
*builtin_sig(token_t typ
, ...)
58 struct psi_plist
*sig
;
62 if (typ
== (token_t
) - 1) {
66 sig
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
70 struct psi_token
*arg
;
72 arg
= psi_token_init(typ
, &a
, 1, 0, 0, zend_empty_string
);
73 sig
= psi_plist_add(sig
, &arg
);
74 typ
= va_arg(args
, token_t
);
81 static void free_builtin(zval
*p
)
83 struct psi_builtin
*b
= Z_PTR_P(p
);
86 zend_string_release(b
->name
);
87 psi_cpp_macro_decl_free(&b
->decl
);
92 PHP_MINIT_FUNCTION(psi_builtin
);
93 PHP_MINIT_FUNCTION(psi_builtin
)
95 #define PSI_BUILTIN(builtin, ...) do { \
96 struct psi_builtin entry; \
97 struct psi_plist *sig = builtin_sig(__VA_ARGS__, 0); \
98 struct psi_cpp_macro_decl *decl = psi_cpp_macro_decl_init(sig, NULL, NULL); \
99 decl->token = psi_token_init(PSI_T_NAME, "__" #builtin, sizeof("__" #builtin)-1, \
100 0, 0, zend_empty_string); \
101 entry.name = zend_string_copy(decl->token->text); \
102 entry.func = &builtin; \
104 zend_hash_add_mem(&psi_builtins, entry.name, &entry, sizeof(entry)); \
107 zend_hash_init(&psi_builtins
, 0, NULL
, free_builtin
, 1);
108 PSI_BUILTIN(has_include
, PSI_T_CPP_HEADER
);
109 PSI_BUILTIN(has_include_next
, PSI_T_CPP_HEADER
);
110 PSI_BUILTIN(has_feature
, PSI_T_NAME
);
111 PSI_BUILTIN(builtin_constant_p
, PSI_T_NAME
);
113 PSI_BUILTIN(signed__
, -1);
115 PSI_BUILTIN(BASE_FILE__
, -1);
116 PSI_BUILTIN(COUNTER__
, -1);
117 PSI_BUILTIN(DATE__
, -1);
118 PSI_BUILTIN(FILE__
, -1);
119 PSI_BUILTIN(INCLUDE_LEVEL__
, -1);
120 PSI_BUILTIN(LINE__
, -1);
121 PSI_BUILTIN(TIME__
, -1);
122 PSI_BUILTIN(TIMESTAMP__
, -1);
127 PHP_MSHUTDOWN_FUNCTION(psi_builtin
);
128 PHP_MSHUTDOWN_FUNCTION(psi_builtin
)
130 zend_hash_destroy(&psi_builtins
);
134 bool psi_builtin_exists(zend_string
*name
)
136 return zend_hash_exists(&psi_builtins
, name
);
139 struct psi_builtin
*psi_builtin_get(zend_string
*name
)
141 return zend_hash_find_ptr(&psi_builtins
, name
);
144 static bool has_include(struct psi_cpp
*cpp
, struct psi_token
*target
,
145 struct psi_plist
**args
, struct psi_plist
**res
)
147 struct psi_plist
*arg
= args
[0];
148 struct psi_token
*tok
;
150 switch (psi_plist_count(arg
)) {
152 if (psi_plist_get(arg
, 0, &tok
)) {
153 const char *cpp_search
= cpp
->search
;
154 bool has
= psi_cpp_has_include(cpp
, tok
, 0, NULL
);
155 cpp
->search
= cpp_search
;
160 cpp
->parser
->error(PSI_DATA(cpp
->parser
), target
, PSI_WARNING
,
161 "Erroneous usage of builtin __%s", __FUNCTION__
);
166 static bool has_include_next(struct psi_cpp
*cpp
, struct psi_token
*target
,
167 struct psi_plist
**args
, struct psi_plist
**res
)
169 struct psi_plist
*arg
= args
[0];
170 struct psi_token
*tok
;
172 switch (psi_plist_count(arg
)) {
174 if (psi_plist_get(arg
, 0, &tok
)) {
175 const char *cpp_search
= cpp
->search
;
176 bool has
= psi_cpp_has_include(cpp
, tok
, PSI_CPP_INCLUDE_NEXT
, NULL
);
177 cpp
->search
= cpp_search
;
182 cpp
->parser
->error(PSI_DATA(cpp
->parser
), target
, PSI_WARNING
,
183 "Erroneous usage of builtin __%s", __FUNCTION__
);
188 static bool has_feature(struct psi_cpp
*cpp
, struct psi_token
*target
,
189 struct psi_plist
**args
, struct psi_plist
**res_ptr
)
194 static bool builtin_constant_p(struct psi_cpp
*cpp
, struct psi_token
*target
,
195 struct psi_plist
**args
, struct psi_plist
**res_ptr
)
197 /* we want functions, not macros for e.g. htonl() */
201 #define NEW_TOKEN(typ, str, len) \
202 psi_token_init((typ), (str), (len), (target)->col, (target)->line, (target)->file)
204 #define ADD_TOKEN(tok) do { \
205 struct psi_token *tok__ = tok; \
207 *res = psi_plist_init((psi_plist_dtor) psi_token_free); \
209 *res = psi_plist_add(*res, &tok__); \
212 #define ADD_QUOTED_STRING(buf, len) do { \
213 ADD_TOKEN(NEW_TOKEN(PSI_T_QUOTED_STRING, buf, len)); \
216 #define ADD_QUOTED_ZSTRING(zs) do { \
217 zend_string *zs_ = zs; \
218 ADD_QUOTED_STRING(zs_->val, zs_->len); \
221 #define ADD_UNSIGNED_NUMBER(u) do { \
224 size_t len = snprintf(buf, sizeof(buf), "%u", u_); \
225 struct psi_token *tok_ = NEW_TOKEN(PSI_T_NUMBER, buf, len); \
226 tok_->flags |= PSI_NUMBER_INT | PSI_NUMBER_U; \
230 static bool signed__(struct psi_cpp
*cpp
, struct psi_token
*target
,
231 struct psi_plist
**args
, struct psi_plist
**res
)
233 ADD_TOKEN(NEW_TOKEN(PSI_T_SIGNED
, "signed", 8));
237 static bool BASE_FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
238 struct psi_plist
**args
, struct psi_plist
**res
)
240 ADD_QUOTED_ZSTRING(cpp
->parser
->input
->file
);
244 static bool COUNTER__(struct psi_cpp
*cpp
, struct psi_token
*target
,
245 struct psi_plist
**args
, struct psi_plist
**res
)
247 ADD_UNSIGNED_NUMBER(cpp
->counter
++);
251 static bool DATE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
252 struct psi_plist
**args
, struct psi_plist
**res
)
256 time_t t
= time(NULL
);
259 tp
= localtime_r(&t
, &tm
);
264 strftime(buf
, sizeof(buf
), "%b %e %Y", tp
);
265 ADD_QUOTED_STRING(buf
, 11);
269 static bool FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
270 struct psi_plist
**args
, struct psi_plist
**res
)
272 ADD_QUOTED_ZSTRING(target
->file
);
276 static bool INCLUDE_LEVEL__(struct psi_cpp
*cpp
, struct psi_token
*target
,
277 struct psi_plist
**args
, struct psi_plist
**res
)
279 ADD_UNSIGNED_NUMBER(cpp
->include_level
);
283 static bool LINE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
284 struct psi_plist
**args
, struct psi_plist
**res
)
286 ADD_UNSIGNED_NUMBER(target
->line
);
290 static bool TIME__(struct psi_cpp
*cpp
, struct psi_token
*target
,
291 struct psi_plist
**args
, struct psi_plist
**res
)
295 time_t t
= time(NULL
);
298 tp
= localtime_r(&t
, &tm
);
303 strftime(buf
, sizeof(buf
), "%H:%M:%S", tp
);
304 ADD_QUOTED_STRING(buf
, 8);
308 static bool TIMESTAMP__(struct psi_cpp
*cpp
, struct psi_token
*target
,
309 struct psi_plist
**args
, struct psi_plist
**res
)
314 str
= ctime_r(&cpp
->parser
->input
->lmod
, buf
);
316 str
= ctime(&cpp
->parser
->input
->lmod
);
320 ADD_QUOTED_STRING(str
, 24);
326 #include <libkern/OSByteOrder.h>
327 # define bswap_16(u) _OSSwapInt16(u)
328 # define bswap_32(u) _OSSwapInt32(u)
329 # define bswap_64(u) _OSSwapInt64(u)
330 #elif defined(__FreeBSD__)
331 # include <sys/endian.h>
332 # define bswap_16(u) bswap16(u)
333 # define bswap_32(u) bswap32(u)
334 # define bswap_64(u) bswap64(u)
335 #elif defined(__OpenBSD__)
336 # include <sys/types.h>
337 # define bswap_16(u) swap16(u)
338 # define bswap_32(u) swap32(u)
339 # define bswap_64(u) swap64(u)
340 #elif defined(__NetBSD__)
341 # include <sys/types.h>
342 # include <machine/bswap.h>
343 # define bswap_16(u) bswap16(u)
344 # define bswap_32(u) bswap32(u)
345 # define bswap_64(u) bswap64(u)
347 # include <byteswap.h>
350 uint16_t psi_swap16(uint16_t u
)
355 uint32_t psi_swap32(uint32_t u
)
360 uint64_t psi_swap64(uint64_t u
)