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