This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Hmmm...strftime() does work on Win32, but tzset() is having problems
[perl5.git] / ext / ByteLoader / ByteLoader.xs
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4 #include "byterun.h"
5
6 /* Something arbitary for a buffer size */
7 #define BYTELOADER_BUFFER 8096
8
9 int
10 bl_getc(struct byteloader_fdata *data)
11 {
12     dTHX;
13     if (SvCUR(data->datasv) <= (STRLEN)data->next_out) {
14       int result;
15       /* Run out of buffered data, so attempt to read some more */
16       *(SvPV_nolen (data->datasv)) = '\0';
17       SvCUR_set (data->datasv, 0);
18       data->next_out = 0;
19       result = FILTER_READ (data->idx + 1, data->datasv, BYTELOADER_BUFFER);
20
21       /* Filter returned error, or we got EOF and no data, then return EOF.
22          Not sure if filter is allowed to return EOF and add data simultaneously
23          Think not, but will bullet proof against it. */
24       if (result < 0 || SvCUR(data->datasv) == 0)
25         return EOF;
26       /* Else there must be at least one byte present, which is good enough */
27     }
28
29     return *((U8 *) SvPV_nolen (data->datasv) + data->next_out++);
30 }
31
32 int
33 bl_read(struct byteloader_fdata *data, char *buf, size_t size, size_t n)
34 {
35     dTHX;
36     char *start;
37     STRLEN len;
38     size_t wanted = size * n;
39
40     start = SvPV (data->datasv, len);
41     if (len < (data->next_out + wanted)) {
42       int result;
43
44       /* Shuffle data to start of buffer */
45       len -= data->next_out;
46       if (len) {
47         memmove (start, start + data->next_out, len + 1);
48       } else {
49         *start = '\0';  /* Avoid call to memmove. */
50       }
51       SvCUR_set(data->datasv, len);
52       data->next_out = 0;
53
54       /* Attempt to read more data. */
55       do {
56         result = FILTER_READ (data->idx + 1, data->datasv, BYTELOADER_BUFFER);
57         
58         start = SvPV (data->datasv, len);
59       } while (result > 0 && len < wanted);
60       /* Loop while not (EOF || error) and short reads */
61
62       /* If not enough data read, truncate copy */
63       if (wanted > len)
64         wanted = len;
65     }
66
67     if (wanted > 0) {
68       memcpy (buf, start + data->next_out, wanted);
69         data->next_out += wanted;
70       wanted /= size;
71     }
72     return (int) wanted;
73 }
74
75 static I32
76 byteloader_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
77 {
78     OP *saveroot = PL_main_root;
79     OP *savestart = PL_main_start;
80     struct byteloader_state bstate;
81     struct byteloader_fdata data;
82     int len;
83     (void)buf_sv;
84     (void)maxlen;
85
86     data.next_out = 0;
87     data.datasv = FILTER_DATA(idx);
88     data.idx = idx;
89
90     bstate.bs_fdata = &data;
91     bstate.bs_obj_list = Null(void**);
92     bstate.bs_obj_list_fill = -1;
93     bstate.bs_sv = Nullsv;
94     bstate.bs_iv_overflows = 0;
95
96 /* KLUDGE */
97     if (byterun(aTHX_ &bstate)
98             && (len = SvCUR(data.datasv) - (STRLEN)data.next_out))
99     {
100         PerlIO_seek(PL_rsfp, -len, SEEK_CUR);
101         PL_rsfp = NULL;
102     }
103     filter_del(byteloader_filter);
104
105     if (PL_in_eval) {
106         OP *o;
107
108         PL_eval_start = PL_main_start;
109
110         o = newSVOP(OP_CONST, 0, newSViv(1));
111         PL_eval_root = newLISTOP(OP_LINESEQ, 0, PL_main_root, o);
112         PL_main_root->op_next = o;
113         PL_eval_root = newUNOP(OP_LEAVEEVAL, 0, PL_eval_root);
114         o->op_next = PL_eval_root;
115     
116         PL_main_root = saveroot;
117         PL_main_start = savestart;
118     }
119
120     return 0;
121 }
122
123 MODULE = ByteLoader             PACKAGE = ByteLoader
124
125 PROTOTYPES:     ENABLE
126
127 void
128 import(package="ByteLoader", ...)
129   char *package
130   PREINIT:
131     SV *sv = newSVpvn ("", 0);
132   PPCODE:
133     if (!sv)
134       croak ("Could not allocate ByteLoader buffers");
135     filter_add(byteloader_filter, sv);