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