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 BASE_FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
47 static bool COUNTER__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
48 static bool DATE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
49 static bool FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
50 static bool INCLUDE_LEVEL__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
51 static bool LINE__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
52 static bool TIME__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
53 static bool TIMESTAMP__(struct psi_cpp
*cpp
, struct psi_token
*target
, struct psi_plist
**args
, struct psi_plist
**res
);
55 static inline struct psi_plist
*builtin_sig(token_t typ
, ...)
57 struct psi_plist
*sig
;
61 if (typ
== (token_t
) - 1) {
65 sig
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
69 struct psi_token
*arg
;
71 arg
= psi_token_init(typ
, &a
, 1, 0, 0, zend_empty_string
);
72 sig
= psi_plist_add(sig
, &arg
);
73 typ
= va_arg(args
, token_t
);
80 static void free_builtin(zval
*p
)
82 struct psi_builtin
*b
= Z_PTR_P(p
);
85 zend_string_release(b
->name
);
86 psi_cpp_macro_decl_free(&b
->decl
);
91 PHP_MINIT_FUNCTION(psi_builtin
);
92 PHP_MINIT_FUNCTION(psi_builtin
)
94 #define PSI_BUILTIN(builtin, ...) do { \
95 struct psi_builtin entry; \
96 struct psi_plist *sig = builtin_sig(__VA_ARGS__, 0); \
97 struct psi_cpp_macro_decl *decl = psi_cpp_macro_decl_init(sig, NULL, NULL); \
98 decl->token = psi_token_init(PSI_T_NAME, "__" #builtin, sizeof("__" #builtin)-1, \
99 0, 0, zend_empty_string); \
100 entry.name = zend_string_copy(decl->token->text); \
101 entry.func = &builtin; \
103 zend_hash_add_mem(&psi_builtins, entry.name, &entry, sizeof(entry)); \
106 zend_hash_init(&psi_builtins
, 0, NULL
, free_builtin
, 1);
107 PSI_BUILTIN(has_include
, PSI_T_CPP_HEADER
);
108 PSI_BUILTIN(has_include_next
, PSI_T_CPP_HEADER
);
109 PSI_BUILTIN(has_feature
, PSI_T_NAME
);
110 PSI_BUILTIN(builtin_constant_p
, PSI_T_NAME
);
112 PSI_BUILTIN(BASE_FILE__
, -1);
113 PSI_BUILTIN(COUNTER__
, -1);
114 PSI_BUILTIN(DATE__
, -1);
115 PSI_BUILTIN(FILE__
, -1);
116 PSI_BUILTIN(INCLUDE_LEVEL__
, -1);
117 PSI_BUILTIN(LINE__
, -1);
118 PSI_BUILTIN(TIME__
, -1);
119 PSI_BUILTIN(TIMESTAMP__
, -1);
124 PHP_MSHUTDOWN_FUNCTION(psi_builtin
);
125 PHP_MSHUTDOWN_FUNCTION(psi_builtin
)
127 zend_hash_destroy(&psi_builtins
);
131 bool psi_builtin_exists(zend_string
*name
)
133 return zend_hash_exists(&psi_builtins
, name
);
136 struct psi_builtin
*psi_builtin_get(zend_string
*name
)
138 return zend_hash_find_ptr(&psi_builtins
, name
);
141 static bool has_include(struct psi_cpp
*cpp
, struct psi_token
*target
,
142 struct psi_plist
**args
, struct psi_plist
**res
)
144 struct psi_plist
*arg
= args
[0];
145 struct psi_token
*tok
;
147 switch (psi_plist_count(arg
)) {
149 if (psi_plist_get(arg
, 0, &tok
)) {
150 const char *cpp_search
= cpp
->search
;
151 bool has
= psi_cpp_has_include(cpp
, tok
, 0, NULL
);
152 cpp
->search
= cpp_search
;
157 cpp
->parser
->error(PSI_DATA(cpp
->parser
), target
, PSI_WARNING
,
158 "Erroneous usage of builtin __%s", __FUNCTION__
);
163 static bool has_include_next(struct psi_cpp
*cpp
, struct psi_token
*target
,
164 struct psi_plist
**args
, struct psi_plist
**res
)
166 struct psi_plist
*arg
= args
[0];
167 struct psi_token
*tok
;
169 switch (psi_plist_count(arg
)) {
171 if (psi_plist_get(arg
, 0, &tok
)) {
172 const char *cpp_search
= cpp
->search
;
173 bool has
= psi_cpp_has_include(cpp
, tok
, PSI_CPP_INCLUDE_NEXT
, NULL
);
174 cpp
->search
= cpp_search
;
179 cpp
->parser
->error(PSI_DATA(cpp
->parser
), target
, PSI_WARNING
,
180 "Erroneous usage of builtin __%s", __FUNCTION__
);
185 static bool has_feature(struct psi_cpp
*cpp
, struct psi_token
*target
,
186 struct psi_plist
**args
, struct psi_plist
**res_ptr
)
191 static bool builtin_constant_p(struct psi_cpp
*cpp
, struct psi_token
*target
,
192 struct psi_plist
**args
, struct psi_plist
**res_ptr
)
194 /* we want functions, not macros for e.g. htonl() */
198 #define NEW_TOKEN(typ, str, len) \
199 psi_token_init((typ), (str), (len), (target)->col, (target)->line, (target)->file)
201 #define ADD_TOKEN(tok) do { \
202 struct psi_token *tok__ = tok; \
204 *res = psi_plist_init((psi_plist_dtor) psi_token_free); \
206 *res = psi_plist_add(*res, &tok__); \
209 #define ADD_QUOTED_STRING(buf, len) do { \
210 ADD_TOKEN(NEW_TOKEN(PSI_T_QUOTED_STRING, buf, len)); \
213 #define ADD_QUOTED_ZSTRING(zs) do { \
214 zend_string *zs_ = zs; \
215 ADD_QUOTED_STRING(zs_->val, zs_->len); \
218 #define ADD_UNSIGNED_NUMBER(u) do { \
221 size_t len = snprintf(buf, sizeof(buf), "%u", u_); \
222 struct psi_token *tok_ = NEW_TOKEN(PSI_T_NUMBER, buf, len); \
223 tok_->flags |= PSI_NUMBER_INT | PSI_NUMBER_U; \
227 static bool BASE_FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
228 struct psi_plist
**args
, struct psi_plist
**res
)
230 ADD_QUOTED_ZSTRING(cpp
->parser
->input
->file
);
234 static bool COUNTER__(struct psi_cpp
*cpp
, struct psi_token
*target
,
235 struct psi_plist
**args
, struct psi_plist
**res
)
237 ADD_UNSIGNED_NUMBER(cpp
->counter
++);
241 static bool DATE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
242 struct psi_plist
**args
, struct psi_plist
**res
)
246 time_t t
= time(NULL
);
249 tp
= localtime_r(&t
, &tm
);
254 strftime(buf
, sizeof(buf
), "%b %e %Y", tp
);
255 ADD_QUOTED_STRING(buf
, 11);
259 static bool FILE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
260 struct psi_plist
**args
, struct psi_plist
**res
)
262 ADD_QUOTED_ZSTRING(target
->file
);
266 static bool INCLUDE_LEVEL__(struct psi_cpp
*cpp
, struct psi_token
*target
,
267 struct psi_plist
**args
, struct psi_plist
**res
)
269 ADD_UNSIGNED_NUMBER(cpp
->include_level
);
273 static bool LINE__(struct psi_cpp
*cpp
, struct psi_token
*target
,
274 struct psi_plist
**args
, struct psi_plist
**res
)
276 ADD_UNSIGNED_NUMBER(target
->line
);
280 static bool TIME__(struct psi_cpp
*cpp
, struct psi_token
*target
,
281 struct psi_plist
**args
, struct psi_plist
**res
)
285 time_t t
= time(NULL
);
288 tp
= localtime_r(&t
, &tm
);
293 strftime(buf
, sizeof(buf
), "%H:%M:%S", tp
);
294 ADD_QUOTED_STRING(buf
, 8);
298 static bool TIMESTAMP__(struct psi_cpp
*cpp
, struct psi_token
*target
,
299 struct psi_plist
**args
, struct psi_plist
**res
)
304 str
= ctime_r(&cpp
->parser
->input
->lmod
, buf
);
306 str
= ctime(&cpp
->parser
->input
->lmod
);
310 ADD_QUOTED_STRING(str
, 24);
316 #include <libkern/OSByteOrder.h>
317 # define bswap_16(u) _OSSwapInt16(u)
318 # define bswap_32(u) _OSSwapInt32(u)
319 # define bswap_64(u) _OSSwapInt64(u)
320 #elif defined(__FreeBSD__)
321 # include <sys/endian.h>
322 # define bswap_16(u) bswap16(u)
323 # define bswap_32(u) bswap32(u)
324 # define bswap_64(u) bswap64(u)
325 #elif defined(__OpenBSD__)
326 # include <sys/types.h>
327 # define bswap_16(u) swap16(u)
328 # define bswap_32(u) swap32(u)
329 # define bswap_64(u) swap64(u)
330 #elif defined(__NetBSD__)
331 # include <sys/types.h>
332 # include <machine/bswap.h>
333 # define bswap_16(u) bswap16(u)
334 # define bswap_32(u) bswap32(u)
335 # define bswap_64(u) bswap64(u)
337 # include <byteswap.h>
340 uint16_t psi_swap16(uint16_t u
)
345 uint32_t psi_swap32(uint32_t u
)
350 uint64_t psi_swap64(uint64_t u
)