new test
[m6w6/ext-psi] / README.md
1 # ext-psi
2
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)
5
6 PSI is a PHP extension, which provides a foreign function interface through
7 `libffi` and/or `libjit`.
8
9 The acronym PSI may be read as:
10 * PHP System Interface
11
12 > **WARNING:**
13 > This is heavy WIP.
14
15 ## Features
16
17 * structs, unions, enums and typedefs
18 * numeric and boolean expressions
19 * scalar constants
20 * vararg calls
21
22 ## Installing
23
24 > **WARNING:**
25 > This is heavy WIP. Installation only works from a source checkout
26 > with php-src@master on x86_64-linux yet.
27
28 ### PECL
29
30 This extension is distributed through [PECL](http://pecl.php.net) and can be
31 installed with [PEAR](http://pear.php.net)'s pecl command:
32
33 pecl install psi
34
35 ### PHARext
36
37 Watch out for [PECL replicates](https://replicator.pharext.org?psi)
38 and [pharext](https://github.com/pharext) packages attached to
39 [releases](https://github.com/m6w6/ext-psi/releases).
40
41 ### Checkout
42
43 This extension is hosted at [Github](https://github.com/m6w6/ext-psi) with a
44 personal [mirror](https://git.m6w6.name/?p=m6w6/ext-psi) available.
45
46 git clone github.com:m6w6/ext-psi
47
48 cd ext-psi
49
50 /path/to/phpize
51 ./configure --with-php-config=/path/to/php-config
52 make
53 sudo make install
54
55 ## Configuring PSI at build time
56
57 PSI supports the following configure switches:
58
59 ### --enable-psi
60 **Enable PHP System Interface support.**
61
62 This is only relevant for an in-tree build. Use `--enable-psi` to include
63 the PSI extension in the build.
64
65 ### --with-psi-libjit
66 **Path to libjit.**
67
68 > **WARNING:**
69 > We currently rely on a patched libjit, because of an apparent bug in how
70 > libjit creates closures, which still needs to be verified, though.
71 > See https://github.com/m6w6/libjit for the preliminary patch.
72
73 ### --with-psi-libffi
74 **Path to libffi.**
75
76 ## Configuring PSI at runtime
77
78 ### psi.engine
79
80 The backend that PSI should use as FFI, either _jit_ for `libjit` or _ffi_ for `libffi`. Defaults to "ffi".
81
82 ### psi.directory
83
84 A colon separated list of directories to scan for `*.psi` files. Defaults to "psi.d".
85
86 ### psi.blacklist.decls
87
88 A comma separated list of C function declarations to ignore.
89
90 ### psi.blacklist.vars
91
92 A comma separated list of C variable declarations to ignore.
93
94 ## PSI files
95
96 ### CPP
97
98 * conditional parsing
99 * including headers
100
101 ```c
102 #include <string.h>
103 ```
104
105 ### Comments
106
107 * C style multi line comments
108 * C++ style single line comments
109
110 ```c
111 // this is a one line comment
112 /* followed
113 by a multi
114 line comment
115 */
116 ```
117
118 ### Typedefs
119
120 ```c
121 typedef unsigned char xmlChar;
122 ```
123
124 They follow the basic C-style `typedef` syntax.
125
126 ```c
127 typedef struct str {
128 char *p;
129 size_t l;
130 } str_t;
131 ```
132 You can also `typedef` unions and enums that way.
133
134 ### Structs
135
136 The following example results in exactly the same interpretation as the previous:
137
138 ```c
139 typedef struct str str_t;
140 struct str {
141 char *p;
142 size_t l;
143 }
144 ```
145
146 A struct will have the size of all its elements plus padding combined and an
147 alignment equal to that of the largest element's alignment.
148
149 ### Enums
150
151 Enums are considered to be of type `int`.
152
153 ```c
154 enum STATUS {
155 FAILURE = -1,
156 SUCCESS
157 }
158 ```
159
160 Enums will be registered as userland constants with the following pattern:
161
162 * `psi\STATUS\FAILURE` with value -1
163 * `psi\STATUS\SUCCESS` with value 0
164
165 ### Unions
166
167 ```c
168 union anyval {
169 char c;
170 short s;
171 int i;
172 long l;
173 float f;
174 double d;
175 str_t str;
176 }
177 ```
178
179 Unions will have the size and alignment of the largest element they contain.
180
181 ### Lib
182
183 ```c
184 lib "awesome";
185 ```
186
187 These statements define what library should be `dlopen()`-ed to look up symbols from declarations.
188 When a `lib` statement is omitted, stdlib is assumed.
189
190 ### Declarations
191
192 Declarations provide all information needed to make a foreign function call.
193
194 ```c
195 extern char *strerror(int errnum);
196 ```
197
198 You may specify a non-standard calling convention in place of `extern`, where `default` and `cdecl` have the same meaning as `extern`.
199
200 Additionally recognized calling conventions include: `stdcall` and `fastcall`.
201
202 ### Constants
203
204 ```c
205 const int num\ZERO = 0;
206 const string pwd\TOKEN = "4WlOjXGL";
207 ```
208
209 Constants must have a namespaced identifiers and are registered as userland constants.
210
211 ### Implementations
212
213 Implementations are the userland visible interfaces to the foreign function interface.
214
215 ```php
216 function str\error(int $num) : string {
217 let errnum = intval($num);
218 return to_string(strerror);
219 }
220 ```
221
222 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.
223
224 ## Complete example
225
226 ```c
227 // all declarations in this file should be looked up in libidn
228 lib "idn";
229
230 // IDNA errors
231 const int \IDNA_SUCCESS = 0;
232 const int \IDNA_STRINGPREP_ERROR = 1;
233 const int \IDNA_PUNYCODE_ERROR = 2;
234 const int \IDNA_CONTAINS_NON_LDH = 3;
235 const int \IDNA_CONTAINS_LDH = 3;
236 const int \IDNA_CONTAINS_MINUS = 4;
237 const int \IDNA_INVALID_LENGTH = 5;
238 const int \IDNA_NO_ACE_PREFIX = 6;
239 const int \IDNA_ROUNDTRIP_VERIFY_ERROR = 7;
240 const int \IDNA_CONTAINS_ACE_PREFIX = 8;
241 const int \IDNA_ICONV_ERROR = 9;
242 const int \IDNA_MALLOC_ERROR = 201;
243 const int \IDNA_DLOPEN_ERROR = 202;
244 // IDNA flags
245 const int \IDNA_ALLOW_UNASSIGNED = 1;
246 const int \IDNA_USE_STD3_ASCII_RULES = 2;
247
248 // nothing special about the declaration here
249 default int idna_to_ascii_8z(char *host, char **buffer, int flags);
250
251 function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int {
252 // there must be a `let` statement for each
253 // declared argument of the called function
254
255 // setup a pointer to NULL
256 let buffer = &NULL;
257
258 // setup a string pointer to $host
259 let host = strval($host);
260
261 // assing the integer value of $flags
262 let flags = intval($flags);
263
264 // the function to call is referenced in
265 // the return statement, along with the
266 // neccessary cast how to interpred the
267 // returned native value
268 return to_int(idna_to_ascii_8z);
269
270 // by-ref vars might receive output values
271 // through `set` statments, which also
272 // require a cast how to marshal the
273 // native data as PHP value
274 set $result = to_string(*buffer);
275
276 // after the buffer has been marshaled
277 // for the PHP engine, we have to free
278 // the buffer to avoid a memory leak
279 free free(*buffer);
280 // note that in this example we omit the
281 // declaration of the free() function called
282 // in our `free` statement for brevity
283 }
284
285 default char *idna_strerror(int rc);
286 function idn\strerror(int $rc) : string {
287 return to_string(idna_strerror);
288 let rc = intval($rc);
289 }
290 ```
291
292 ### Userland
293
294 ```php
295 $rc = idn\utf8_to_ascii("flöte.de", $result);
296 printf("<%s>\n", $result);
297 printf("%s\n", idn\strerror($rc));
298
299 $rc = idn\utf8_to_ascii("…asdf….de", $result, IDNA_USE_STD3_ASCII_RULES);
300 printf("<%s>\n", $result);
301 printf("%s\n", idn\strerror($rc));
302 ```
303
304 #### Output
305 ```
306 <xn--flte-6qa.de>
307 Success
308 <>
309 Non-digit/letter/hyphen in input
310 ```
311
312 ## ChangeLog
313
314 A comprehensive list of changes can be obtained from the
315 [PECL website](https://pecl.php.net/package-changelog.php?package=psi).
316
317 Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO).
318
319 ## License
320
321 ext-psi is licensed under the 2-Clause-BSD license, which can be found in
322 the accompanying [LICENSE](./LICENSE) file.
323
324 ## Contributing
325
326 All forms of contribution are welcome! Please see the bundled
327 [CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed.
328
329 The list of past and current contributors is maintained in [THANKS](./THANKS).