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