3 [![Join the chat at https://gitter.im/m6w6/ext-psi](https://badges.gitter.im/m6w6/ext-psi.svg)](https://gitter.im/m6w6/ext-psi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 [![Build Status](https://travis-ci.org/m6w6/ext-psi.svg?branch=master)](https://travis-ci.org/m6w6/ext-psi)
6 PSI is a PHP extension, which provides a foreign function interface through
7 `libffi` and/or `libjit`.
9 The acronym PSI may be read as:
10 * PHP System Interface
17 * structs, unions, enums and typedefs
18 * numeric and boolean expressions
25 > This is heavy WIP. Installation only works from a source checkout with php-src@master yet.
29 This extension is distributed through [PECL](http://pecl.php.net) and can be
30 installed with [PEAR](http://pear.php.net)'s pecl command:
36 Watch out for [PECL replicates](https://replicator.pharext.org?psi)
37 and [pharext](https://github.com/pharext) packages attached to
38 [releases](https://github.com/m6w6/ext-psi/releases).
42 This extension is hosted at [Github](https://github.com/m6w6/ext-psi) with a
43 personal [mirror](https://git.m6w6.name/?p=m6w6/ext-psi) available.
45 git clone github.com:m6w6/ext-psi
50 ./configure --with-php-config=/path/to/php-config
54 ## Configuring PSI at build time
56 PSI supports the following configure switches:
59 **Enable PHP System Interface support.**
61 This is only relevant for an in-tree build. Use `--enable-psi` to include
62 the PSI extension in the build.
68 > We currently rely on a patched libjit, because of an apparent bug in how
69 > libjit creates closures, which still needs to be verified, though.
70 > See https://github.com/m6w6/libjit for the preliminary patch.
75 ## Configuring PSI at runtime
79 The backend that PSI should use as FFI, either _jit_ for `libjit` or _ffi_ for `libffi`. Defaults to "ffi".
83 A colon separated list of directories to scan for `*.psi` files. Defaults to "psi.d".
85 ### psi.blacklist.decls
87 A comma separated list of C function declarations to ignore.
89 ### psi.blacklist.vars
91 A comma separated list of C variable declarations to ignore.
106 * C style multi line comments
107 * C++ style single line comments
110 // this is a one line comment
120 typedef unsigned char xmlChar;
123 They follow the basic C-style `typedef` syntax.
131 You can also `typedef` unions and enums that way.
135 The following example results in exactly the same interpretation as the previous:
138 typedef struct str str_t;
145 A struct will have the size of all its elements plus padding combined and an
146 alignment equal to that of the largest element's alignment.
150 Enums are considered to be of type `int`.
159 Enums will be registered as userland constants with the following pattern:
161 * `psi\STATUS\FAILURE` with value -1
162 * `psi\STATUS\SUCCESS` with value 0
178 Unions will have the size and alignment of the largest element they contain.
186 These statements define what library should be `dlopen()`-ed to look up symbols from declarations.
187 When a `lib` statement is omitted, stdlib is assumed.
191 Declarations provide all information needed to make a foreign function call.
194 extern char *strerror(int errnum);
197 You may specify a non-standard calling convention in place of `extern`, where `default` and `cdecl` have the same meaning as `extern`.
199 Additionally recognized calling conventions include: `stdcall` and `fastcall`.
204 const int num\ZERO = 0;
205 const string pwd\TOKEN = "4WlOjXGL";
208 Constants must have a namespaced identifiers and are registered as userland constants.
212 Implementations are the userland visible interfaces to the foreign function interface.
215 function str\error(int $num) : string {
216 let errnum = intval($num);
217 return to_string(strerror);
221 Each implementation refers to exactly one declared foreign function referenced in its `return` statement. Each declaration, on the other hand, may have any number of implementations.
226 // all declarations in this file should be looked up in libidn
230 const int \IDNA_SUCCESS = 0;
231 const int \IDNA_STRINGPREP_ERROR = 1;
232 const int \IDNA_PUNYCODE_ERROR = 2;
233 const int \IDNA_CONTAINS_NON_LDH = 3;
234 const int \IDNA_CONTAINS_LDH = 3;
235 const int \IDNA_CONTAINS_MINUS = 4;
236 const int \IDNA_INVALID_LENGTH = 5;
237 const int \IDNA_NO_ACE_PREFIX = 6;
238 const int \IDNA_ROUNDTRIP_VERIFY_ERROR = 7;
239 const int \IDNA_CONTAINS_ACE_PREFIX = 8;
240 const int \IDNA_ICONV_ERROR = 9;
241 const int \IDNA_MALLOC_ERROR = 201;
242 const int \IDNA_DLOPEN_ERROR = 202;
244 const int \IDNA_ALLOW_UNASSIGNED = 1;
245 const int \IDNA_USE_STD3_ASCII_RULES = 2;
247 // nothing special about the declaration here
248 default int idna_to_ascii_8z(char *host, char **buffer, int flags);
250 function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int {
251 // there must be a `let` statement for each
252 // declared argument of the called function
254 // setup a pointer to NULL
257 // setup a string pointer to $host
258 let host = strval($host);
260 // assing the integer value of $flags
261 let flags = intval($flags);
263 // the function to call is referenced in
264 // the return statement, along with the
265 // neccessary cast how to interpred the
266 // returned native value
267 return to_int(idna_to_ascii_8z);
269 // by-ref vars might receive output values
270 // through `set` statments, which also
271 // require a cast how to marshal the
272 // native data as PHP value
273 set $result = to_string(*buffer);
275 // after the buffer has been marshaled
276 // for the PHP engine, we have to free
277 // the buffer to avoid a memory leak
279 // note that in this example we omit the
280 // declaration of the free() function called
281 // in our `free` statement for brevity
284 default char *idna_strerror(int rc);
285 function idn\strerror(int $rc) : string {
286 return to_string(idna_strerror);
287 let rc = intval($rc);
294 $rc = idn\utf8_to_ascii("flöte.de", $result);
295 printf("<%s>\n", $result);
296 printf("%s\n", idn\strerror($rc));
298 $rc = idn\utf8_to_ascii("…asdf….de", $result, IDNA_USE_STD3_ASCII_RULES);
299 printf("<%s>\n", $result);
300 printf("%s\n", idn\strerror($rc));
308 Non-digit/letter/hyphen in input
313 A comprehensive list of changes can be obtained from the
314 [PECL website](https://pecl.php.net/package-changelog.php?package=psi).
316 Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO).
320 ext-psi is licensed under the 2-Clause-BSD license, which can be found in
321 the accompanying [LICENSE](./LICENSE) file.
325 All forms of contribution are welcome! Please see the bundled
326 [CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed.
328 The list of past and current contributors is maintained in [THANKS](./THANKS).