summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/ffi/ffi.c61
-rw-r--r--ext/ffi/ffi.g6
-rw-r--r--ext/ffi/ffi_parser.c6
-rw-r--r--ext/ffi/php_ffi.h2
-rw-r--r--ext/ffi/tests/044.phpt30
5 files changed, 104 insertions, 1 deletions
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index dd223d1de1..dc86ef856f 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -5050,7 +5050,12 @@ void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val
{
zend_ffi_symbol *sym;
- if (FFI_G(symbols)) {
+ if (UNEXPECTED(FFI_G(attribute_parsing))) {
+ val->kind = ZEND_FFI_VAL_NAME;
+ val->str = name;
+ val->len = name_len;
+ return;
+ } else if (FFI_G(symbols)) {
sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
if (sym && sym->kind == ZEND_FFI_SYM_CONST) {
val->i64 = sym->value;
@@ -6060,6 +6065,60 @@ void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t na
}
break;
case attr_mode:
+ if (n == 0
+ && (val->kind == ZEND_FFI_VAL_NAME)) {
+ const char *str = val->str;
+ size_t len = val->len;
+ if (len > 4
+ && str[0] == '_'
+ && str[1] == '_'
+ && str[len-2] == '_'
+ && str[len-1] == '_') {
+ str += 2;
+ len -= 4;
+ }
+ // TODO: Add support for vector type 'VnXX' ???
+ if (len == 2) {
+ if (str[1] == 'I') {
+ if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED))) {
+ /* inappropriate type */
+ } else if (str[0] == 'Q') {
+ dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+ dcl->flags |= ZEND_FFI_DCL_CHAR;
+ break;
+ } else if (str[0] == 'H') {
+ dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+ dcl->flags |= ZEND_FFI_DCL_SHORT;
+ break;
+ } else if (str[0] == 'S') {
+ dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+ dcl->flags |= ZEND_FFI_DCL_INT;
+ break;
+ } else if (str[0] == 'D') {
+ dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+ if (sizeof(long) == 8) {
+ dcl->flags |= ZEND_FFI_DCL_LONG;
+ } else {
+ dcl->flags |= ZEND_FFI_DCL_LONG_LONG;
+ }
+ break;
+ }
+ } else if (str[1] == 'F') {
+ if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE))) {
+ /* inappropriate type */
+ } else if (str[0] == 'S') {
+ dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
+ dcl->flags |= ZEND_FFI_DCL_FLOAT;
+ break;
+ } else if (str[0] == 'D') {
+ dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
+ dcl->flags |= ZEND_FFI_DCL_DOUBLE;
+ break;
+ }
+ }
+ }
+ }
+ zend_ffi_parser_error("unsupported 'mode' value at line %d", FFI_G(line));
// TODO: ???
case attr_unsupported:
zend_ffi_parser_error("unsupported attribute '%.*s' at line %d", name_len, name, FFI_G(line));
diff --git a/ext/ffi/ffi.g b/ext/ffi/ffi.g
index a1dde95c64..2be2f11e7c 100644
--- a/ext/ffi/ffi.g
+++ b/ext/ffi/ffi.g
@@ -495,10 +495,13 @@ attrib(zend_ffi_dcl *dcl):
{size_t name_len;}
{int n;}
{zend_ffi_val val;}
+ {zend_bool orig_attribute_parsing;}
( ID(&name, &name_len)
( /* empty */
{zend_ffi_add_attribute(dcl, name, name_len);}
| "("
+ {orig_attribute_parsing = FFI_G(attribute_parsing);}
+ {FFI_G(attribute_parsing) = 1;}
assignment_expression(&val)
{zend_ffi_add_attribute_value(dcl, name, name_len, 0, &val);}
{n = 0;}
@@ -506,6 +509,7 @@ attrib(zend_ffi_dcl *dcl):
assignment_expression(&val)
{zend_ffi_add_attribute_value(dcl, name, name_len, ++n, &val);}
)*
+ {FFI_G(attribute_parsing) = orig_attribute_parsing;}
")"
)
| "const"
@@ -874,6 +878,7 @@ SKIP: ( EOL | WS | ONE_LINE_COMMENT | COMMENT )*;
int zend_ffi_parse_decl(const char *str, size_t len) {
if (SETJMP(FFI_G(bailout))==0) {
FFI_G(allow_vla) = 0;
+ FFI_G(attribute_parsing) = 0;
yy_buf = (unsigned char*)str;
yy_end = yy_buf + len;
parse();
@@ -888,6 +893,7 @@ int zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl) {
if (SETJMP(FFI_G(bailout))==0) {
FFI_G(allow_vla) = 0;
+ FFI_G(attribute_parsing) = 0;
yy_pos = yy_text = yy_buf = (unsigned char*)str;
yy_end = yy_buf + len;
yy_line = 1;
diff --git a/ext/ffi/ffi_parser.c b/ext/ffi/ffi_parser.c
index 94fb11d17b..816aa49dc8 100644
--- a/ext/ffi/ffi_parser.c
+++ b/ext/ffi/ffi_parser.c
@@ -2930,6 +2930,7 @@ static int parse_attrib(int sym, zend_ffi_dcl *dcl) {
size_t name_len;
int n;
zend_ffi_val val;
+ zend_bool orig_attribute_parsing;
if (sym == YY_ID || sym == YY_CONST || sym == YY___CONST || sym == YY___CONST__) {
if (sym == YY_ID) {
sym = parse_ID(sym, &name, &name_len);
@@ -2937,6 +2938,8 @@ static int parse_attrib(int sym, zend_ffi_dcl *dcl) {
zend_ffi_add_attribute(dcl, name, name_len);
} else if (sym == YY__LPAREN) {
sym = get_sym();
+ orig_attribute_parsing = FFI_G(attribute_parsing);
+ FFI_G(attribute_parsing) = 1;
sym = parse_assignment_expression(sym, &val);
zend_ffi_add_attribute_value(dcl, name, name_len, 0, &val);
n = 0;
@@ -2945,6 +2948,7 @@ static int parse_attrib(int sym, zend_ffi_dcl *dcl) {
sym = parse_assignment_expression(sym, &val);
zend_ffi_add_attribute_value(dcl, name, name_len, ++n, &val);
}
+ FFI_G(attribute_parsing) = orig_attribute_parsing;
if (sym != YY__RPAREN) {
yy_error_sym("')' expected, got", sym);
}
@@ -3516,6 +3520,7 @@ static void parse(void) {
int zend_ffi_parse_decl(const char *str, size_t len) {
if (SETJMP(FFI_G(bailout))==0) {
FFI_G(allow_vla) = 0;
+ FFI_G(attribute_parsing) = 0;
yy_buf = (unsigned char*)str;
yy_end = yy_buf + len;
parse();
@@ -3530,6 +3535,7 @@ int zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl) {
if (SETJMP(FFI_G(bailout))==0) {
FFI_G(allow_vla) = 0;
+ FFI_G(attribute_parsing) = 0;
yy_pos = yy_text = yy_buf = (unsigned char*)str;
yy_end = yy_buf + len;
yy_line = 1;
diff --git a/ext/ffi/php_ffi.h b/ext/ffi/php_ffi.h
index 35b5127875..664f473d9d 100644
--- a/ext/ffi/php_ffi.h
+++ b/ext/ffi/php_ffi.h
@@ -56,6 +56,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ffi)
HashTable *symbols;
HashTable *tags;
zend_bool allow_vla;
+ zend_bool attribute_parsing;
zend_bool persistent;
uint32_t default_type_attr;
ZEND_END_MODULE_GLOBALS(ffi)
@@ -182,6 +183,7 @@ typedef enum _zend_ffi_val_kind {
ZEND_FFI_VAL_LONG_DOUBLE,
ZEND_FFI_VAL_CHAR,
ZEND_FFI_VAL_STRING,
+ ZEND_FFI_VAL_NAME, /* attribute value */
} zend_ffi_val_kind;
#ifdef HAVE_LONG_DOUBLE
diff --git a/ext/ffi/tests/044.phpt b/ext/ffi/tests/044.phpt
new file mode 100644
index 0000000000..ab07e23e1b
--- /dev/null
+++ b/ext/ffi/tests/044.phpt
@@ -0,0 +1,30 @@
+--TEST--
+FFI 044: mode attribute
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--INI--
+ffi.enable=1
+--FILE--
+<?php
+$ffi = FFI::cdef("
+typedef int a __attribute__ ((__mode__ (__QI__)));
+typedef int b __attribute__ ((__mode__ (__HI__)));
+typedef int c __attribute__ ((__mode__ (__SI__)));
+typedef int d __attribute__ ((__mode__ (__DI__)));
+typedef float e __attribute__ ((__mode__ (__SF__)));
+typedef float f __attribute__ ((__mode__ (__DF__)));
+");
+var_dump(FFI::sizeof($ffi->new("a")));
+var_dump(FFI::sizeof($ffi->new("b")));
+var_dump(FFI::sizeof($ffi->new("c")));
+var_dump(FFI::sizeof($ffi->new("d")));
+var_dump(FFI::sizeof($ffi->new("e")));
+var_dump(FFI::sizeof($ffi->new("f")));
+?>
+--EXPECT--
+int(1)
+int(2)
+int(4)
+int(8)
+int(4)
+int(8)