lmtiolibext.c /size: 44 Kb    last modification: 2025-02-21 11:03
1/*
2    See license.txt in the root of this project.
3*/
4
5/*tex
6
7    Lua doesn't have cardinals so basically we could stick to integers and accept that we have a
8    limited range.
9
10*/
11
12/*tex
13
14    Maybe also make a string reader with a user data string, after all we can now store a position
15    in the userdata directly. 
16
17*/
18# include "luametatex.h"
19
20# ifdef _WIN32
21
22    # define lua_popen(L,c,m)   ((void)L, _popen(c,m))
23    # define lua_pclose(L,file) ((void)L, _pclose(file))
24
25# else
26
27    # define lua_popen(L,c,m)   ((void)L, fflush(NULL), popen(c,m))
28    # define lua_pclose(L,file) ((void)L, pclose(file))
29
30# endif
31
32/* Mojca: we need to sort this out! */
33
34# ifdef LUA_USE_POSIX
35
36    # define l_fseek(f,o,w) fseeko(f,o,w)
37    # define l_ftell(f)     ftello(f)
38    # define l_seeknum      off_t
39
40# elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) && defined(_MSC_VER) && (_MSC_VER >= 1400)
41
42    # define l_fseek(f,o,w) _fseeki64(f,o,w)
43    # define l_ftell(f)     _ftelli64(f)
44    # define l_seeknum      __int64
45
46# elif defined(__MINGW32__)
47
48    # define l_fseek(f,o,w) fseeko64(f,o,w)
49    # define l_ftell(f)     ftello64(f)
50    # define l_seeknum      int64_t
51
52# else
53
54    # define l_fseek(f,o,w) fseek(f,o,w)
55    # define l_ftell(f)     ftell(f)
56    # define l_seeknum      long
57
58# endif
59
60# define uchar(c) ((unsigned char)(c))
61
62/*tex
63
64    A few helpers to avoid reading numbers as strings. For now we put them in their own namespace.
65    We also have a few helpers that can make \IO\ functions \TEX\ friendly.
66
67*/
68
69static int fiolib_readcardinal1(lua_State *L) {
70    FILE *f = lmt_valid_file(L);
71    if (f) {
72        lua_Integer a = getc(f);
73        if (a == EOF) {
74            lua_pushnil(L);
75        } else {
76            lua_pushinteger(L, a);
77        }
78        return 1;
79    } else {
80        return 0;
81    }
82}
83
84static int siolib_readcardinal1(lua_State *L) {
85    size_t ls = 0;
86    const char *s = luaL_checklstring(L, 1, &ls);
87    lua_Integer p =  luaL_checkinteger(L, 2) - 1;
88    lua_Integer l = (lua_Integer) ls;
89    if (p >= l) {
90        lua_pushnil(L);
91    } else {
92        lua_Integer a = uchar(s[p]);
93        lua_pushinteger(L, a);
94    }
95    return 1;
96}
97
98static int fiolib_readcardinal2(lua_State *L) {
99    FILE *f = lmt_valid_file(L);
100    if (f) {
101        lua_Integer a = getc(f);
102        lua_Integer b = getc(f);
103        if (b == EOF) {
104            lua_pushnil(L);
105        } else {
106            /* (a<<8) | b */
107            lua_pushinteger(L, 0x100 * a + b);
108        }
109        return 1;
110    } else {
111        return 0;
112    }
113}
114
115static int fiolib_readcardinal2_le(lua_State *L) {
116    FILE *f = lmt_valid_file(L);
117    if (f) {
118        lua_Integer b = getc(f);
119        lua_Integer a = getc(f);
120        if (a == EOF) {
121            lua_pushnil(L);
122        } else {
123            /* (a<<8) | b */
124            lua_pushinteger(L, 0x100 * a + b);
125        }
126        return 1;
127    } else {
128        return 0;
129    }
130}
131
132static int siolib_readcardinal2(lua_State *L) {
133    size_t ls = 0;
134    const char *s = luaL_checklstring(L, 1, &ls);
135    lua_Integer p = luaL_checkinteger(L, 2) - 1;
136    lua_Integer l = (lua_Integer) ls;
137    if ((p + 1) >= l) {
138        lua_pushnil(L);
139    } else {
140        lua_Integer a = uchar(s[p++]);
141        lua_Integer b = uchar(s[p]);
142        lua_pushinteger(L, 0x100 * a + b);
143    }
144    return 1;
145}
146
147static int siolib_readcardinal2_le(lua_State *L) {
148    size_t ls = 0;
149    const char *s = luaL_checklstring(L, 1, &ls);
150    lua_Integer p = luaL_checkinteger(L, 2) - 1;
151    lua_Integer l = (lua_Integer) ls;
152    if ((p + 1) >= l) {
153        lua_pushnil(L);
154    } else {
155        lua_Integer b = uchar(s[p++]);
156        lua_Integer a = uchar(s[p]);
157        lua_pushinteger(L, 0x100 * a + b);
158    }
159    return 1;
160}
161
162static int fiolib_readcardinal3(lua_State *L) {
163    FILE *f = lmt_valid_file(L);
164    if (f) {
165        lua_Integer a = getc(f);
166        lua_Integer b = getc(f);
167        lua_Integer c = getc(f);
168        if (c == EOF) {
169            lua_pushnil(L);
170        } else {
171            /* (a<<16) | (b<<8) | c */
172            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
173        }
174        return 1;
175    } else {
176        return 0;
177    }
178}
179
180static int fiolib_readcardinal3_le(lua_State *L) {
181    FILE *f = lmt_valid_file(L);
182    if (f) {
183        lua_Integer c = getc(f);
184        lua_Integer b = getc(f);
185        lua_Integer a = getc(f);
186        if (a == EOF) {
187            lua_pushnil(L);
188        } else {
189            /* (a<<16) | (b<<8) | c */
190            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
191        }
192        return 1;
193    } else {
194        return 0;
195    }
196}
197
198static int siolib_readcardinal3(lua_State *L) {
199    size_t ls = 0;
200    const char *s = luaL_checklstring(L, 1, &ls);
201    lua_Integer p = luaL_checkinteger(L, 2) - 1;
202    lua_Integer l = (lua_Integer) ls;
203    if ((p + 2) >= l) {
204        lua_pushnil(L);
205    } else {
206        lua_Integer a = uchar(s[p++]);
207        lua_Integer b = uchar(s[p++]);
208        lua_Integer c = uchar(s[p]);
209        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
210    }
211    return 1;
212}
213
214static int siolib_readcardinal3_le(lua_State *L) {
215    size_t ls = 0;
216    const char *s = luaL_checklstring(L, 1, &ls);
217    lua_Integer p = luaL_checkinteger(L, 2) - 1;
218    lua_Integer l = (lua_Integer) ls;
219    if ((p + 2) >= l) {
220        lua_pushnil(L);
221    } else {
222        lua_Integer c = uchar(s[p++]);
223        lua_Integer b = uchar(s[p++]);
224        lua_Integer a = uchar(s[p]);
225        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
226    }
227    return 1;
228}
229
230static int fiolib_readcardinal4(lua_State *L) {
231    FILE *f = lmt_valid_file(L);
232    if (f) {
233        lua_Integer a = getc(f);
234        lua_Integer b = getc(f);
235        lua_Integer c = getc(f);
236        lua_Integer d = getc(f);
237        if (d == EOF) {
238            lua_pushnil(L);
239        } else {
240            /* (a<<24) | (b<<16) | (c<<8) | d */
241            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
242        }
243        return 1;
244    } else {
245        return 0;
246    }
247}
248
249static int fiolib_readcardinal4_le(lua_State *L) {
250    FILE *f = lmt_valid_file(L);
251    if (f) {
252        lua_Integer d = getc(f);
253        lua_Integer c = getc(f);
254        lua_Integer b = getc(f);
255        lua_Integer a = getc(f);
256        if (a == EOF) {
257            lua_pushnil(L);
258        } else {
259            /* (a<<24) | (b<<16) | (c<<8) | d */
260            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
261        }
262        return 1;
263    } else {
264        return 0;
265    }
266}
267
268static int siolib_readcardinal4(lua_State *L) {
269    size_t ls = 0;
270    const char *s = luaL_checklstring(L, 1, &ls);
271    lua_Integer p = luaL_checkinteger(L, 2) - 1;
272    lua_Integer l = (lua_Integer) ls;
273    if ((p + 3) >= l) {
274        lua_pushnil(L);
275    } else {
276        lua_Integer a = uchar(s[p++]);
277        lua_Integer b = uchar(s[p++]);
278        lua_Integer c = uchar(s[p++]);
279        lua_Integer d = uchar(s[p]);
280        lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
281    }
282    return 1;
283}
284
285static int siolib_readcardinal4_le(lua_State *L) {
286    size_t ls = 0;
287    const char *s = luaL_checklstring(L, 1, &ls);
288    lua_Integer p = luaL_checkinteger(L, 2) - 1;
289    lua_Integer l = (lua_Integer) ls;
290    if ((p + 3) >= l) {
291        lua_pushnil(L);
292    } else {
293        lua_Integer d = uchar(s[p++]);
294        lua_Integer c = uchar(s[p++]);
295        lua_Integer b = uchar(s[p++]);
296        lua_Integer a = uchar(s[p]);
297        lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
298    }
299    return 1;
300}
301
302static int fiolib_readcardinaltable(lua_State *L) {
303    FILE *f = lmt_valid_file(L);
304    if (f) {
305        lua_Integer n = lua_tointeger(L, 2);
306        lua_Integer m = lua_tointeger(L, 3);
307        lua_createtable(L, (int) n, 0);
308        switch (m) {
309            case 1:
310                for (lua_Integer i = 1; i <= n; i++) {
311                    lua_Integer a = getc(f);
312                    if (a == EOF) {
313                        break;
314                    } else {
315                        lua_pushinteger(L, a);
316                        lua_rawseti(L, -2, i);
317                    }
318                }
319                break;
320            case 2:
321                for (lua_Integer i = 1; i <= n; i++) {
322                    lua_Integer a = getc(f);
323                    lua_Integer b = getc(f);
324                    if (b == EOF) {
325                        break;
326                    } else {
327                        /* (a<<8) | b */
328                        lua_pushinteger(L, 0x100 * a + b);
329                        lua_rawseti(L, -2, i);
330                    }
331                }
332                break;
333            case 3:
334                for (lua_Integer i = 1; i <= n; i++) {
335                    lua_Integer a = getc(f);
336                    lua_Integer b = getc(f);
337                    lua_Integer c = getc(f);
338                    if (c == EOF) {
339                        break;
340                    } else {
341                        /* (a<<16) | (b<<8) | c */
342                        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
343                        lua_rawseti(L, -2, i);
344                    }
345                }
346                break;
347            case 4:
348                for (lua_Integer i = 1; i <= n; i++) {
349                    lua_Integer a = getc(f);
350                    lua_Integer b = getc(f);
351                    lua_Integer c = getc(f);
352                    lua_Integer d = getc(f);
353                    if (d == EOF) {
354                        break;
355                    } else {
356                        /* (a<<24) | (b<<16) | (c<<8) | d */
357                        lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
358                        lua_rawseti(L, -2, i);
359                    }
360                }
361                break;
362            default:
363                break;
364        }
365        return 1;
366    } else {
367        return 0;
368    }
369}
370
371static int siolib_readcardinaltable(lua_State *L) {
372    size_t ls = 0;
373    const char *s = luaL_checklstring(L, 1, &ls);
374    lua_Integer p = luaL_checkinteger(L, 2) - 1;
375    lua_Integer n = lua_tointeger(L, 3);
376    lua_Integer m = lua_tointeger(L, 4);
377    lua_Integer l = (lua_Integer) ls;
378    lua_createtable(L, (int) n, 0);
379    switch (m) {
380        case 1:
381            for (lua_Integer i = 1; i <= n; i++) {
382                if (p >= l) {
383                    break;
384                } else {
385                    lua_Integer a = uchar(s[p++]);
386                    lua_pushinteger(L, a);
387                    lua_rawseti(L, -2, i);
388                }
389            }
390            break;
391        case 2:
392            for (lua_Integer i = 1; i <= n; i++) {
393                if ((p + 1) >= l) {
394                    break;
395                } else {
396                    lua_Integer a = uchar(s[p++]);
397                    lua_Integer b = uchar(s[p++]);
398                    lua_pushinteger(L, 0x100 * a + b);
399                    lua_rawseti(L, -2, i);
400                }
401            }
402            break;
403        case 3:
404            for (lua_Integer i = 1; i <= n; i++) {
405                if ((p + 2) >= l) {
406                    break;
407                } else {
408                    lua_Integer a = uchar(s[p++]);
409                    lua_Integer b = uchar(s[p++]);
410                    lua_Integer c = uchar(s[p++]);
411                    lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
412                    lua_rawseti(L, -2, i);
413                }
414            }
415            break;
416        case 4:
417            for (lua_Integer i = 1; i <= n; i++) {
418                if ((p + 3) >= l) {
419                    break;
420                } else {
421                    lua_Integer a = uchar(s[p++]);
422                    lua_Integer b = uchar(s[p++]);
423                    lua_Integer c = uchar(s[p++]);
424                    lua_Integer d = uchar(s[p++]);
425                    lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
426                    lua_rawseti(L, -2, i);
427                }
428            }
429            break;
430        default:
431            break;
432    }
433    return 1;
434}
435
436static int fiolib_readinteger1(lua_State *L) {
437    FILE *f = lmt_valid_file(L);
438    if (f) {
439        lua_Integer a = getc(f);
440        if (a == EOF) {
441            lua_pushnil(L);
442        } else if (a >= 0x80) {
443            lua_pushinteger(L, a - 0x100);
444        } else {
445            lua_pushinteger(L, a);
446        }
447        return 1;
448    } else {
449        return 0;
450    }
451}
452
453static int siolib_readinteger1(lua_State *L) {
454    size_t ls = 0;
455    const char *s = luaL_checklstring(L, 1, &ls);
456    lua_Integer p = luaL_checkinteger(L, 2) - 1;
457    lua_Integer l = (lua_Integer) ls;
458    if (p >= l) {
459        lua_pushnil(L);
460    } else {
461        lua_Integer a = uchar(s[p]);
462        if (a >= 0x80) {
463            lua_pushinteger(L, a - 0x100);
464        } else {
465            lua_pushinteger(L, a);
466        }
467    }
468    return 1;
469}
470
471static int fiolib_readinteger2(lua_State *L) {
472    FILE *f = lmt_valid_file(L);
473    if (f) {
474        lua_Integer a = getc(f);
475        lua_Integer b = getc(f);
476        if (b == EOF) {
477            lua_pushnil(L);
478        } else if (a >= 0x80) {
479            lua_pushinteger(L, 0x100 * a + b - 0x10000);
480        } else {
481            lua_pushinteger(L, 0x100 * a + b);
482        }
483        return 1;
484    } else {
485        return 0;
486    }
487}
488
489static int fiolib_readinteger2_le(lua_State *L) {
490    FILE *f = lmt_valid_file(L);
491    if (f) {
492        lua_Integer b = getc(f);
493        lua_Integer a = getc(f);
494        if (a == EOF) {
495            lua_pushnil(L);
496        } else if (a >= 0x80) {
497            lua_pushinteger(L, 0x100 * a + b - 0x10000);
498        } else {
499            lua_pushinteger(L, 0x100 * a + b);
500        }
501        return 1;
502    } else {
503        return 0;
504    }
505}
506
507static int siolib_readinteger2(lua_State *L) {
508    size_t ls = 0;
509    const char *s = luaL_checklstring(L, 1, &ls);
510    lua_Integer p = luaL_checkinteger(L, 2) - 1;
511    lua_Integer l = (lua_Integer) ls;
512    if ((p + 1) >= l) {
513        lua_pushnil(L);
514    } else {
515        lua_Integer a = uchar(s[p++]);
516        lua_Integer b = uchar(s[p]);
517        if (a >= 0x80) {
518            lua_pushinteger(L, 0x100 * a + b - 0x10000);
519        } else {
520            lua_pushinteger(L, 0x100 * a + b);
521        }
522    }
523    return 1;
524}
525
526static int siolib_readinteger2_le(lua_State *L) {
527    size_t ls = 0;
528    const char *s = luaL_checklstring(L, 1, &ls);
529    lua_Integer p = luaL_checkinteger(L, 2) - 1;
530    lua_Integer l = (lua_Integer) ls;
531    if ((p + 1) >= l) {
532        lua_pushnil(L);
533    } else {
534        lua_Integer b = uchar(s[p++]);
535        lua_Integer a = uchar(s[p]);
536        if (a >= 0x80) {
537            lua_pushinteger(L, 0x100 * a + b - 0x10000);
538        } else {
539            lua_pushinteger(L, 0x100 * a + b);
540        }
541    }
542    return 1;
543}
544
545static int fiolib_readinteger3(lua_State *L) {
546    FILE *f = lmt_valid_file(L);
547    if (f) {
548        lua_Integer a = getc(f);
549        lua_Integer b = getc(f);
550        lua_Integer c = getc(f);
551        if (c == EOF) {
552            lua_pushnil(L);
553        } else if (a >= 0x80) {
554            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
555        } else {
556            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
557        }
558        return 1;
559    } else {
560        return 0;
561    }
562}
563
564static int fiolib_readinteger3_le(lua_State *L) {
565    FILE *f = lmt_valid_file(L);
566    if (f) {
567        lua_Integer c = getc(f);
568        lua_Integer b = getc(f);
569        lua_Integer a = getc(f);
570        if (a == EOF) {
571            lua_pushnil(L);
572        } else if (a >= 0x80) {
573            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
574        } else {
575            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
576        }
577        return 1;
578    } else {
579        return 0;
580    }
581}
582
583static int siolib_readinteger3(lua_State *L) {
584    size_t ls = 0;
585    const char *s = luaL_checklstring(L, 1, &ls);
586    lua_Integer p = luaL_checkinteger(L, 2) - 1;
587    lua_Integer l = (lua_Integer) ls;
588    if ((p + 2) >= l) {
589        lua_pushnil(L);
590    } else {
591        lua_Integer a = uchar(s[p++]);
592        lua_Integer b = uchar(s[p++]);
593        lua_Integer c = uchar(s[p]);
594        if (a >= 0x80) {
595            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
596        } else {
597            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
598        }
599    }
600    return 1;
601}
602
603static int siolib_readinteger3_le(lua_State *L) {
604    size_t ls = 0;
605    const char *s = luaL_checklstring(L, 1, &ls);
606    lua_Integer p = luaL_checkinteger(L, 2) - 1;
607    lua_Integer l = (lua_Integer) ls;
608    if ((p + 2) >= l) {
609        lua_pushnil(L);
610    } else {
611        lua_Integer c = uchar(s[p++]);
612        lua_Integer b = uchar(s[p++]);
613        lua_Integer a = uchar(s[p]);
614        if (a >= 0x80) {
615            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
616        } else {
617            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
618        }
619    }
620    return 1;
621}
622
623static int fiolib_readinteger4(lua_State *L) {
624    FILE *f = lmt_valid_file(L);
625    if (f) {
626        lua_Integer a = getc(f);
627        lua_Integer b = getc(f);
628        lua_Integer c = getc(f);
629        lua_Integer d = getc(f);
630        if (d == EOF) {
631            lua_pushnil(L);
632        } else if (a >= 0x80) {
633            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000);
634        } else {
635            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
636        }
637        return 1;
638    } else {
639        return 0;
640    }
641}
642
643static int fiolib_readinteger4_le(lua_State *L) {
644    FILE *f = lmt_valid_file(L);
645    if (f) {
646        lua_Integer d = getc(f);
647        lua_Integer c = getc(f);
648        lua_Integer b = getc(f);
649        lua_Integer a = getc(f);
650        if (a == EOF) {
651            lua_pushnil(L);
652        } else if (a >= 0x80) {
653            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000);
654        } else {
655            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
656        }
657        return 1;
658    } else {
659        return 0;
660    }
661}
662
663static int siolib_readinteger4(lua_State *L) {
664    size_t ls = 0;
665    const char *s = luaL_checklstring(L, 1, &ls);
666    lua_Integer p = luaL_checkinteger(L, 2) - 1;
667    lua_Integer l = (lua_Integer) ls;
668    if ((p + 3) >= l) {
669        lua_pushnil(L);
670    } else {
671        lua_Integer a = uchar(s[p++]);
672        lua_Integer b = uchar(s[p++]);
673        lua_Integer c = uchar(s[p++]);
674        lua_Integer d = uchar(s[p]);
675        if (a >= 0x80) {
676            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000);
677        } else {
678            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
679        }
680    }
681    return 1;
682}
683
684static int siolib_readinteger4_le(lua_State *L) {
685    size_t ls = 0;
686    const char *s = luaL_checklstring(L, 1, &ls);
687    lua_Integer p = luaL_checkinteger(L, 2) - 1;
688    lua_Integer l = (lua_Integer) ls;
689    if ((p + 3) >= l) {
690        lua_pushnil(L);
691    } else {
692        lua_Integer d = uchar(s[p++]);
693        lua_Integer c = uchar(s[p++]);
694        lua_Integer b = uchar(s[p++]);
695        lua_Integer a = uchar(s[p]);
696        if (a >= 0x80) {
697            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000);
698        } else {
699            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
700        }
701    }
702    return 1;
703}
704
705static int fiolib_readintegertable(lua_State *L) {
706    FILE *f = lmt_valid_file(L);
707    if (f) {
708        lua_Integer n = lua_tointeger(L, 2);
709        lua_Integer m = lua_tointeger(L, 3);
710        lua_createtable(L, (int) n, 0);
711        switch (m) {
712            case 1:
713                for (lua_Integer i = 1; i <= n; i++) {
714                    lua_Integer a = getc(f);
715                    if (a == EOF) {
716                        break;
717                    } else if (a >= 0x80) {
718                        lua_pushinteger(L, a - 0x100);
719                    } else {
720                        lua_pushinteger(L, a);
721                    }
722                    lua_rawseti(L, -2, i);
723                }
724                break;
725            case 2:
726                for (lua_Integer i = 1; i <= n; i++) {
727                    lua_Integer a = getc(f);
728                    lua_Integer b = getc(f);
729                    if (b == EOF) {
730                        break;
731                    } else if (a >= 0x80) {
732                        lua_pushinteger(L, 0x100 * a + b - 0x10000);
733                    } else {
734                        lua_pushinteger(L, 0x100 * a + b);
735                    }
736                    lua_rawseti(L, -2, i);
737                }
738                break;
739            case 3:
740                for (lua_Integer i = 1; i <= n; i++) {
741                    lua_Integer a = getc(f);
742                    lua_Integer b = getc(f);
743                    lua_Integer c = getc(f);
744                    if (c == EOF) {
745                        break;
746                    } else if (a >= 0x80) {
747                        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
748                    } else {
749                        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
750                    }
751                    lua_rawseti(L, -2, i);
752                }
753                break;
754            case 4:
755                for (lua_Integer i = 1; i <= n; i++) {
756                    lua_Integer a = getc(f);
757                    lua_Integer b = getc(f);
758                    lua_Integer c = getc(f);
759                    lua_Integer d = getc(f);
760                    if (d == EOF) {
761                        break;
762                    } else if (a >= 0x80) {
763                        lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000);
764                    } else {
765                        lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
766                    }
767                    lua_rawseti(L, -2, i);
768                }
769                break;
770            default:
771                break;
772        }
773        return 1;
774    } else {
775        return 0;
776    }
777}
778
779static int siolib_readintegertable(lua_State *L) {
780    size_t ls = 0;
781    const char *s = luaL_checklstring(L, 1, &ls);
782    lua_Integer p = luaL_checkinteger(L, 2) - 1;
783    lua_Integer n = lua_tointeger(L, 3);
784    lua_Integer m = lua_tointeger(L, 4);
785    lua_Integer l = (lua_Integer) ls;
786    lua_createtable(L, (int) n, 0);
787    switch (m) {
788        case 1:
789            for (lua_Integer i = 1; i <= n; i++) {
790                if (p >= l) {
791                    break;
792                } else {
793                    lua_Integer a = uchar(s[p++]);
794                    if (a >= 0x80) {
795                        lua_pushinteger(L, a - 0x100);
796                    } else {
797                        lua_pushinteger(L, a);
798                    }
799                    lua_rawseti(L, -2, i);
800                }
801            }
802            break;
803        case 2:
804            for (lua_Integer i = 1; i <= n; i++) {
805                if ((p + 1) >= l) {
806                    break;
807                } else {
808                    lua_Integer a = uchar(s[p++]);
809                    lua_Integer b = uchar(s[p++]);
810                    if (a >= 0x80) {
811                        lua_pushinteger(L, 0x100 * a + b - 0x10000);
812                    } else {
813                        lua_pushinteger(L, 0x100 * a + b);
814                    }
815                    lua_rawseti(L, -2, i);
816                }
817            }
818            break;
819        case 3:
820            for (lua_Integer i = 1; i <= n; i++) {
821                if ((p + 2) >= l) {
822                    break;
823                } else {
824                    lua_Integer a = uchar(s[p++]);
825                    lua_Integer b = uchar(s[p++]);
826                    lua_Integer c = uchar(s[p++]);
827                    if (a >= 0x80) {
828                        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
829                    } else {
830                        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
831                    }
832                    lua_rawseti(L, -2, i);
833                }
834            }
835            break;
836        case 4:
837            for (lua_Integer i = 1; i <= n; i++) {
838                if ((p + 3) >= l) {
839                    break;
840                } else {
841                    lua_Integer a = uchar(s[p++]);
842                    lua_Integer b = uchar(s[p++]);
843                    lua_Integer c = uchar(s[p++]);
844                    lua_Integer d = uchar(s[p++]);
845                    if (a >= 0x80) {
846                        lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000);
847                    } else {
848                        lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
849                    }
850                    lua_rawseti(L, -2, i);
851                }
852            }
853            break;
854        default:
855            break;
856    }
857    return 1;
858}
859
860/* from ff */
861
862static int fiolib_readfixed2(lua_State *L) {
863    FILE *f = lmt_valid_file(L);
864    if (f) {
865        int a = getc(f);
866        int b = getc(f);
867        if (b == EOF) {
868            lua_pushnil(L);
869        } else {
870            int n = 0x100 * a + b; /* really an int because we shift */
871            lua_pushnumber(L, (double) ((n>>8) + ((n&0xff)/256.0)));
872        }
873        return 1;
874    } else {
875        return 0;
876    }
877}
878
879static int siolib_readfixed2(lua_State *L) {
880    size_t ls = 0;
881    const char *s = luaL_checklstring(L, 1, &ls);
882    lua_Integer p = luaL_checkinteger(L, 2) - 1;
883    lua_Integer l = (lua_Integer) ls;
884    if ((p + 3) >= l) {
885        lua_pushnil(L);
886    } else {
887        int a = uchar(s[p++]);
888        int b = uchar(s[p]);
889        int n = 0x100 * a + b; /* really an int because we shift */
890        lua_pushnumber(L, (double) ((n>>8) + ((n&0xff)/256.0)));
891    }
892    return 1;
893}
894
895static int fiolib_readfixed4(lua_State *L) {
896    FILE *f = lmt_valid_file(L);
897    if (f) {
898        int a = getc(f);
899        int b = getc(f);
900        int c = getc(f);
901        int d = getc(f);
902        if (d == EOF) {
903            lua_pushnil(L);
904        } else {
905            int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d; /* really an int because we shift */
906            lua_pushnumber(L, (double) ((n>>16) + ((n&0xffff)/65536.0)));
907        }
908        return 1;
909    } else {
910        return 0;
911    }
912}
913
914static int siolib_readfixed4(lua_State *L) {
915    size_t ls = 0;
916    const char *s = luaL_checklstring(L, 1, &ls);
917    lua_Integer p = luaL_checkinteger(L, 2) - 1;
918    lua_Integer l = (lua_Integer) ls;
919    if ((p + 3) >= l) {
920        lua_pushnil(L);
921    } else {
922        int a = uchar(s[p++]);
923        int b = uchar(s[p++]);
924        int c = uchar(s[p++]);
925        int d = uchar(s[p]);
926        int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d; /* really an int because we shift */
927        lua_pushnumber(L, (double) ((n>>16) + ((n&0xffff)/65536.0)));
928    }
929    return 1;
930}
931
932static int fiolib_read2dot14(lua_State *L) {
933    FILE *f = lmt_valid_file(L);
934    if (f) {
935        int a = getc(f);
936        int b = getc(f);
937        if (b == EOF) {
938            lua_pushnil(L);
939        } else {
940            int n = 0x100 * a + b; /* really an int because we shift */
941            /* from ff */
942            lua_pushnumber(L, (double) (((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0)));
943        }
944        return 1;
945    } else {
946        return 0;
947    }
948}
949
950static int siolib_read2dot14(lua_State *L) {
951    size_t ls = 0;
952    const char *s = luaL_checklstring(L, 1, &ls);
953    lua_Integer p = luaL_checkinteger(L, 2) - 1;
954    lua_Integer l = (lua_Integer) ls;
955    if ((p + 1) >= l) {
956        lua_pushnil(L);
957    } else {
958        int a = uchar(s[p++]);
959        int b = uchar(s[p]);
960        int n = 0x100 * a + b; /* really an int because we shift */
961        lua_pushnumber(L, (double) (((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0)));
962    }
963    return 1;
964}
965
966static int fiolib_getposition(lua_State *L) {
967    FILE *f = lmt_valid_file(L);
968    if (f) {
969        long p = ftell(f);
970        if (p < 0) {
971            lua_pushnil(L);
972        } else {
973            lua_pushinteger(L, p);
974        }
975        return 1;
976    } else {
977        return 0;
978    }
979}
980
981static int fiolib_setposition(lua_State *L) {
982    FILE *f = lmt_valid_file(L);
983    if (f) {
984        long p = lmt_tolong(L, 2);
985        p = fseek(f, p, SEEK_SET);
986        if (p < 0) {
987            lua_pushnil(L);
988        } else {
989            lua_pushinteger(L, p);
990        }
991        return 1;
992    } else {
993        return 0;
994    }
995}
996
997static int fiolib_skipposition(lua_State *L) {
998    FILE *f = lmt_valid_file(L);
999    if (f) {
1000        long p = lmt_tolong(L, 2);
1001        p = fseek(f, ftell(f) + p, SEEK_SET);
1002        if (p < 0) {
1003            lua_pushnil(L);
1004        } else {
1005            lua_pushinteger(L, p);
1006        }
1007        return 1;
1008    } else {
1009        return 0;
1010    }
1011}
1012
1013static int fiolib_readbytetable(lua_State *L) {
1014    FILE *f = lmt_valid_file(L);
1015    if (f) {
1016        lua_Integer n = lua_tointeger(L, 2);
1017        lua_createtable(L, (int) n, 0);
1018        for (lua_Integer i = 1; i <= n; i++) {
1019            lua_Integer a = getc(f);
1020            if (a == EOF) {
1021                break;
1022            } else {
1023                /*
1024                    lua_pushinteger(L, i);
1025                    lua_pushinteger(L, a);
1026                    lua_rawset(L, -3);
1027                */
1028                lua_pushinteger(L, a);
1029                lua_rawseti(L, -2, i);
1030            }
1031        }
1032        return 1;
1033    } else {
1034        return 0;
1035    }
1036}
1037
1038static int siolib_readbytetable(lua_State *L) {
1039    size_t ls = 0;
1040    const char *s = luaL_checklstring(L, 1, &ls);
1041    lua_Integer p = luaL_checkinteger(L, 2) - 1;
1042    lua_Integer n = lua_tointeger(L, 3);
1043    lua_Integer l = (lua_Integer) ls;
1044    if (p >= l) {
1045        lua_pushnil(L);
1046    } else {
1047        if (p + n >= l) {
1048            n = l - p ;
1049        }
1050        lua_createtable(L, (int) n, 0);
1051        for (lua_Integer i = 1; i <= n; i++) {
1052            lua_Integer a = uchar(s[p++]);
1053            lua_pushinteger(L, a);
1054            lua_rawseti(L, -2, i);
1055        }
1056    }
1057    return 1;
1058}
1059
1060static int fiolib_readbytes(lua_State *L) {
1061    FILE *f = lmt_valid_file(L);
1062    if (f) {
1063        lua_Integer n = lua_tointeger(L, 2);
1064        for (lua_Integer i = 1; i <= n; i++) {
1065            lua_Integer a = getc(f);
1066            if (a == EOF) {
1067                return (int) (i - 1);
1068            } else {
1069                lua_pushinteger(L, a);
1070            }
1071        }
1072        return (int) n;
1073    } else {
1074        return 0;
1075    }
1076}
1077
1078static int siolib_readbytes(lua_State *L) {
1079    size_t ls = 0;
1080    const char *s = luaL_checklstring(L, 1, &ls);
1081    lua_Integer p = luaL_checkinteger(L, 2) - 1;
1082    lua_Integer n = lua_tointeger(L, 3);
1083    lua_Integer l = (lua_Integer) ls;
1084    if (p >= l) {
1085        return 0;
1086    } else {
1087        if (p + n >= l) {
1088            n = l - p ;
1089        }
1090        lua_createtable(L, (int) n, 0);
1091        for (lua_Integer i = 1; i <= n; i++) {
1092            lua_Integer a = uchar(s[p++]);
1093            lua_pushinteger(L, a);
1094        }
1095        return (int) n;
1096    }
1097}
1098
1099static int fiolib_readcline(lua_State *L)
1100{
1101    FILE *f = lmt_valid_file(L);
1102    if (f) {
1103        luaL_Buffer buf;
1104        int c = 0;
1105        int n = 0;
1106        luaL_buffinit(L, &buf);
1107        do {
1108            char *b = luaL_prepbuffer(&buf);
1109            int i = 0;
1110            while (i < LUAL_BUFFERSIZE) {
1111                c = fgetc(f);
1112                if (c == '\n') {
1113                    goto GOOD;
1114                } else if (c == '\r') {
1115                    c = fgetc(f);
1116                    if (c != EOF && c != '\n') {
1117                        ungetc((int) c, f);
1118                    }
1119                    goto GOOD;
1120                } else {
1121                    n++;
1122                    b[i++] = (char) c;
1123                }
1124            }
1125        }  while (c != EOF);
1126        goto BAD;
1127      GOOD:
1128        if (n > 0) {
1129            luaL_addsize(&buf, n);
1130            luaL_pushresult(&buf);
1131        } else {
1132            lua_pushnil(L);
1133        }
1134        lua_pushinteger(L, ftell(f));
1135        return 2;
1136    }
1137  BAD:
1138    lua_pushnil(L);
1139    return 1;
1140}
1141
1142
1143static int siolib_readcline(lua_State *L)
1144{
1145    size_t ls = 0;
1146    const char *s = luaL_checklstring(L, 1, &ls);
1147    lua_Integer p = luaL_checkinteger(L, 2) - 1;
1148    lua_Integer l = (lua_Integer) ls;
1149    if (p < l) {
1150        lua_Integer i = p;
1151        int n = 0;
1152        while  (p < l) {
1153            int c = uchar(s[p++]);
1154            if (c == '\n') {
1155                goto GOOD;
1156            } else if (c == '\r') {
1157                if (p < l) {
1158                    c = uchar(s[p++]);
1159                    if (c != EOF && c != '\n') {
1160                        --p;
1161                    }
1162                }
1163                goto GOOD;
1164            } else {
1165                n++;
1166            }
1167        }
1168        goto BAD;
1169      GOOD:
1170        if (n > 0) {
1171            lua_pushlstring(L, &s[i], n);
1172            lua_pushinteger(L, p);
1173            return 2;
1174        }
1175    }
1176  BAD:
1177    lua_pushnil(L);
1178    lua_pushinteger(L, p + 1);
1179    return 2;
1180}
1181
1182static int fiolib_readcstring(lua_State *L)
1183{
1184    FILE *f = lmt_valid_file(L);
1185    if (f) {
1186        luaL_Buffer buf;
1187        int c = 0;
1188        int n = 0;
1189        luaL_buffinit(L, &buf);
1190        do {
1191            char *b = luaL_prepbuffer(&buf);
1192            int i = 0;
1193            while (i < LUAL_BUFFERSIZE) {
1194                c = fgetc(f);
1195                if (c == '\0') {
1196                    goto GOOD;
1197                } else {
1198                    n++;
1199                    b[i++] = (char) c;
1200                }
1201            }
1202        }  while (c != EOF);
1203        goto BAD;
1204      GOOD:
1205        if (n > 0) {
1206            luaL_addsize(&buf, n);
1207            luaL_pushresult(&buf);
1208        } else {
1209            lua_pushliteral(L,"");
1210        }
1211        lua_pushinteger(L, ftell(f));
1212        return 2;
1213    }
1214  BAD:
1215    lua_pushnil(L);
1216    return 1;
1217}
1218
1219static int siolib_readcstring(lua_State *L)
1220{
1221    size_t ls = 0;
1222    const char *s = luaL_checklstring(L, 1, &ls);
1223    lua_Integer p = luaL_checkinteger(L, 2) - 1;
1224    lua_Integer l = (lua_Integer) ls;
1225    if (p < l) {
1226        lua_Integer i = p;
1227        int n = 0;
1228        while (p < l) {
1229            int c = uchar(s[p++]);
1230            if (c == '\0') {
1231                goto GOOD;
1232            } else {
1233                n++;
1234            }
1235        };
1236        goto BAD;
1237      GOOD:
1238        if (n > 0) {
1239            lua_pushlstring(L, &s[i], n);
1240        } else {
1241            lua_pushliteral(L,"");
1242        }
1243        lua_pushinteger(L, p + 1);
1244        return 2;
1245    }
1246  BAD:
1247    lua_pushnil(L);
1248    lua_pushinteger(L, p + 1);
1249    return 2;
1250}
1251
1252/* will be completed */
1253
1254static int fiolib_writecardinal1(lua_State *L)
1255{
1256    FILE *f = lmt_valid_file(L);
1257    if (f) {
1258        lua_Integer n = lua_tointeger(L, 2);
1259        putc(n & 0xFF, f);
1260    }
1261    return 0;
1262}
1263
1264static int siolib_tocardinal1(lua_State *L)
1265{
1266    lua_Integer n = lua_tointeger(L, 1);
1267    char buffer[1] = { n & 0xFF };
1268    lua_pushlstring(L, buffer, 1);
1269    return 1;
1270}
1271
1272static int fiolib_writecardinal2(lua_State *L)
1273{
1274    FILE *f = lmt_valid_file(L);
1275    if (f) {
1276        lua_Integer n = lua_tointeger(L, 2);
1277        putc((n >> 8) & 0xFF, f);
1278        putc( n       & 0xFF, f);
1279    }
1280    return 0;
1281}
1282
1283static int siolib_tocardinal2(lua_State *L)
1284{
1285    lua_Integer n = lua_tointeger(L, 1);
1286    char buffer[2] = { (n >> 8) & 0xFF, n & 0xFF };
1287    lua_pushlstring(L, buffer, 2);
1288    return 1;
1289}
1290
1291static int fiolib_writecardinal2_le(lua_State *L)
1292{
1293    FILE *f = lmt_valid_file(L);
1294    if (f) {
1295        lua_Integer n = lua_tointeger(L, 2);
1296        putc( n       & 0xFF, f);
1297        putc((n >> 8) & 0xFF, f);
1298    }
1299    return 0;
1300}
1301
1302static int siolib_tocardinal2_le(lua_State *L)
1303{
1304    lua_Integer n = lua_tointeger(L, 1);
1305    char buffer[2] = { n & 0xFF, (n >> 8) & 0xFF };
1306    lua_pushlstring(L, buffer, 2);
1307    return 1;
1308}
1309
1310static int fiolib_writecardinal3(lua_State *L)
1311{
1312    FILE *f = lmt_valid_file(L);
1313    if (f) {
1314        lua_Integer n = lua_tointeger(L, 2);
1315        putc((n >> 16) & 0xFF, f);
1316        putc((n >>  8) & 0xFF, f);
1317        putc( n        & 0xFF, f);
1318    }
1319    return 0;
1320}
1321
1322static int siolib_tocardinal3(lua_State *L)
1323{
1324    lua_Integer n = lua_tointeger(L, 1);
1325    char buffer[3] = { (n >> 16) & 0xFF, (n >>  8) & 0xFF, n & 0xFF };
1326    lua_pushlstring(L, buffer, 3);
1327    return 1;
1328}
1329
1330
1331static int fiolib_writecardinal3_le(lua_State *L)
1332{
1333    FILE *f = lmt_valid_file(L);
1334    if (f) {
1335        lua_Integer n = lua_tointeger(L, 2);
1336        putc( n        & 0xFF, f);
1337        putc((n >>  8) & 0xFF, f);
1338        putc((n >> 16) & 0xFF, f);
1339    }
1340    return 0;
1341}
1342
1343static int siolib_tocardinal3_le(lua_State *L)
1344{
1345    lua_Integer n = lua_tointeger(L, 1);
1346    char buffer[3] = { n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF };
1347    lua_pushlstring(L, buffer, 3);
1348    return 1;
1349}
1350
1351static int fiolib_writecardinal4(lua_State *L)
1352{
1353    FILE *f = lmt_valid_file(L);
1354    if (f) {
1355        lua_Integer n = lua_tointeger(L, 2);
1356        putc((n >> 24) & 0xFF, f);
1357        putc((n >> 16) & 0xFF, f);
1358        putc((n >>  8) & 0xFF, f);
1359        putc( n        & 0xFF, f);
1360    }
1361    return 0;
1362}
1363
1364static int siolib_tocardinal4(lua_State *L)
1365{
1366    lua_Integer n = lua_tointeger(L, 1);
1367    char buffer[4] = { (n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >>  8) & 0xFF, n & 0xFF };
1368    lua_pushlstring(L, buffer, 4);
1369    return 1;
1370}
1371
1372static int fiolib_writecardinal4_le(lua_State *L)
1373{
1374    FILE *f = lmt_valid_file(L);
1375    if (f) {
1376        lua_Integer n = lua_tointeger(L, 2);
1377        putc( n        & 0xFF, f);
1378        putc((n >>  8) & 0xFF, f);
1379        putc((n >> 16) & 0xFF, f);
1380        putc((n >> 24) & 0xFF, f);
1381    }
1382    return 0;
1383}
1384
1385static int siolib_tocardinal4_le(lua_State *L)
1386{
1387    lua_Integer n = lua_tointeger(L, 1);
1388    char buffer[4] = { n & 0xFF, (n >>  8) & 0xFF, (n >> 16) & 0xFF, (n >> 24) & 0xFF };
1389    lua_pushlstring(L, buffer, 4);
1390    return 1;
1391}
1392
1393/* */
1394
1395static const luaL_Reg fiolib_function_list[] = {
1396    /* helpers */
1397
1398    { "readcardinal1",     fiolib_readcardinal1     },
1399    { "readcardinal2",     fiolib_readcardinal2     },
1400    { "readcardinal3",     fiolib_readcardinal3     },
1401    { "readcardinal4",     fiolib_readcardinal4     },
1402
1403    { "readcardinal1le",   fiolib_readcardinal1     },
1404    { "readcardinal2le",   fiolib_readcardinal2_le  },
1405    { "readcardinal3le",   fiolib_readcardinal3_le  },
1406    { "readcardinal4le",   fiolib_readcardinal4_le  },
1407
1408    { "readcardinaltable", fiolib_readcardinaltable },
1409
1410    { "readinteger1",      fiolib_readinteger1      },
1411    { "readinteger2",      fiolib_readinteger2      },
1412    { "readinteger3",      fiolib_readinteger3      },
1413    { "readinteger4",      fiolib_readinteger4      },
1414
1415    { "readinteger1le",    fiolib_readinteger1      },
1416    { "readinteger2le",    fiolib_readinteger2_le   },
1417    { "readinteger3le",    fiolib_readinteger3_le   },
1418    { "readinteger4le",    fiolib_readinteger4_le   },
1419
1420    { "readintegertable",  fiolib_readintegertable  },
1421
1422    { "readfixed2",        fiolib_readfixed2        },
1423    { "readfixed4",        fiolib_readfixed4        },
1424
1425    { "read2dot14",        fiolib_read2dot14        },
1426
1427    { "setposition",       fiolib_setposition       },
1428    { "getposition",       fiolib_getposition       },
1429    { "skipposition",      fiolib_skipposition      },
1430
1431    { "readbytes",         fiolib_readbytes         },
1432    { "readbytetable",     fiolib_readbytetable     },
1433
1434    { "readcline",         fiolib_readcline         },
1435    { "readcstring",       fiolib_readcstring       },
1436
1437    { "writecardinal1",    fiolib_writecardinal1    },
1438    { "writecardinal2",    fiolib_writecardinal2    },
1439    { "writecardinal3",    fiolib_writecardinal3    },
1440    { "writecardinal4",    fiolib_writecardinal4    },
1441
1442    { "writecardinal1le",  fiolib_writecardinal1    },
1443    { "writecardinal2le",  fiolib_writecardinal2_le },
1444    { "writecardinal3le",  fiolib_writecardinal3_le },
1445    { "writecardinal4le",  fiolib_writecardinal4_le },
1446
1447    { NULL,                NULL                     }
1448};
1449
1450static const luaL_Reg siolib_function_list[] = {
1451
1452    { "readcardinal1",     siolib_readcardinal1     },
1453    { "readcardinal2",     siolib_readcardinal2     },
1454    { "readcardinal3",     siolib_readcardinal3     },
1455    { "readcardinal4",     siolib_readcardinal4     },
1456
1457    { "readcardinal1le",   siolib_readcardinal1     },
1458    { "readcardinal2le",   siolib_readcardinal2_le  },
1459    { "readcardinal3le",   siolib_readcardinal3_le  },
1460    { "readcardinal4le",   siolib_readcardinal4_le  },
1461
1462    { "readcardinaltable", siolib_readcardinaltable },
1463
1464    { "readinteger1",      siolib_readinteger1      },
1465    { "readinteger2",      siolib_readinteger2      },
1466    { "readinteger3",      siolib_readinteger3      },
1467    { "readinteger4",      siolib_readinteger4      },
1468
1469    { "readinteger1le",    siolib_readinteger1      },
1470    { "readinteger2le",    siolib_readinteger2_le   },
1471    { "readinteger3le",    siolib_readinteger3_le   },
1472    { "readinteger4le",    siolib_readinteger4_le   },
1473
1474    { "readintegertable",  siolib_readintegertable  },
1475
1476    { "readfixed2",        siolib_readfixed2        },
1477    { "readfixed4",        siolib_readfixed4        },
1478    { "read2dot14",        siolib_read2dot14        },
1479
1480    { "readbytes",         siolib_readbytes         },
1481    { "readbytetable",     siolib_readbytetable     },
1482
1483    { "readcline",         siolib_readcline         },
1484    { "readcstring",       siolib_readcstring       },
1485
1486    { "tocardinal1",       siolib_tocardinal1       },
1487    { "tocardinal2",       siolib_tocardinal2       },
1488    { "tocardinal3",       siolib_tocardinal3       },
1489    { "tocardinal4",       siolib_tocardinal4       },
1490
1491    { "tocardinal1le",     siolib_tocardinal1       },
1492    { "tocardinal2le",     siolib_tocardinal2_le    },
1493    { "tocardinal3le",     siolib_tocardinal3_le    },
1494    { "tocardinal4le",     siolib_tocardinal4_le    },
1495
1496    { NULL,                NULL                     }
1497};
1498
1499/*tex
1500
1501    The sio helpers might be handy at some point. Speed-wise there is no gain over file access
1502    because with ssd and caching we basically operate in memory too. We keep them as complement to
1503    the file ones. I did consider using an userdata object for the position etc but some simple
1504    tests demonstrated that there is no real gain and the current ones permits to wrap up whatever
1505    interface one likes.
1506
1507*/
1508
1509int luaopen_fio(lua_State *L) {
1510    lua_newtable(L);
1511    luaL_setfuncs(L, fiolib_function_list, 0);
1512    return 1;
1513}
1514
1515int luaopen_sio(lua_State *L) {
1516    lua_newtable(L);
1517    luaL_setfuncs(L, siolib_function_list, 0);
1518    return 1;
1519}
1520
1521/* We patch a function in the standard |io| library. */
1522
1523/*tex
1524
1525    The following code overloads the |io.open| function to deal with so called wide characters on
1526    windows.
1527
1528*/
1529
1530/* a variant on read_line but with nothing catched */
1531
1532static int io_gobble(lua_State *L) 
1533{
1534    FILE *f = lmt_valid_file(L);
1535    if (f) {
1536        int c;
1537        int n = 0;
1538        while ((c = getc(f)) != EOF && c != '\n') {
1539            n = 1;
1540        }
1541        lua_pushboolean(L, ((c == '\n') || n));
1542    } else { 
1543        lua_pushnil(L);
1544    }
1545    return 1;
1546}
1547
1548# if _WIN32
1549
1550#   define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
1551
1552    static int l_checkmode(const char *mode) {
1553        return (
1554             mode 
1555         && *mode != '\0'
1556         && strchr("rwa", *(mode++))
1557         && (*mode != '+' || ((void)(++mode), 1))
1558         && (strspn(mode, "b") == strlen(mode))
1559        );
1560    }
1561
1562    typedef luaL_Stream LStream;
1563
1564    static LStream *newprefile(lua_State *L) {
1565        LStream *p = (LStream *)lua_newuserdatauv(L, sizeof(LStream), 0);
1566        p->closef = NULL;
1567        luaL_setmetatable(L, LUA_FILEHANDLE);
1568        return p;
1569    }
1570
1571    static int io_fclose(lua_State *L) {
1572        LStream *p = tolstream(L);
1573        int res = fclose(p->f);
1574        return luaL_fileresult(L, (res == 0), NULL);
1575    }
1576
1577    static LStream *newfile(lua_State *L) {
1578        /*tex Watch out: lua 5.4 has different closers. */
1579        LStream *p = newprefile(L);
1580        p->f = NULL;
1581        p->closef = &io_fclose;
1582        return p;
1583    }
1584
1585    static int io_open(lua_State *L)
1586    {
1587        const char *filename = luaL_checkstring(L, 1);
1588        const char *mode = luaL_optstring(L, 2, "r");
1589        LStream *p = newfile(L);
1590        const char *md = mode;  /* to traverse/check mode */
1591        luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
1592        p->f = aux_utf8_fopen(filename, mode);
1593        return (p->f) ? 1 : luaL_fileresult(L, 0, filename);
1594    }
1595
1596    static int io_pclose(lua_State *L) {
1597        LStream *p = tolstream(L);
1598        return luaL_execresult(L, _pclose(p->f));
1599    }
1600
1601    static int io_popen(lua_State *L)
1602    {
1603        const char *filename = luaL_checkstring(L, 1);
1604        const char *mode = luaL_optstring(L, 2, "r");
1605        LStream *p = newprefile(L);
1606        p->f = aux_utf8_popen(filename, mode);
1607        p->closef = &io_pclose;
1608        return (p->f) ? 1 : luaL_fileresult(L, 0, filename);
1609    }
1610
1611    int luaextend_io(lua_State *L)
1612    {
1613        lua_getglobal(L, "io");
1614        lua_pushcfunction(L, io_open);  lua_setfield(L, -2, "open");
1615        lua_pushcfunction(L, io_popen); lua_setfield(L, -2, "popen");
1616        lua_pushcfunction(L, io_gobble); lua_setfield(L, -2, "gobble");
1617        lua_pop(L, 1);
1618         /*tex
1619            Larger doesn't work and limits to 512 but then no amount is okay as there's always more
1620            to demand.
1621        */
1622        _setmaxstdio(2048);
1623        return 1;
1624    }
1625
1626# else
1627
1628 // int luaextend_io(lua_State *L)
1629 // {
1630 //     (void) L;
1631 //     return 1;
1632 // }
1633
1634    int luaextend_io(lua_State *L)
1635    {
1636        lua_getglobal(L, "io");
1637        lua_pushcfunction(L, io_gobble); lua_setfield(L, -2, "gobble");
1638        lua_pop(L, 1);
1639        return 1;
1640    }
1641
1642# endif
1643