1 /*
2  * Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved.
3  * This program is free software; you can redistribute it and/or
4  * modify it under the same terms as Perl itself.
5  */
6 
7 #define PERL_EXT_IO
8 
9 #define PERL_NO_GET_CONTEXT
10 #include "EXTERN.h"
11 #define PERLIO_NOT_STDIO 1
12 #include "perl.h"
13 #include "XSUB.h"
14 #include "poll.h"
15 #ifdef I_UNISTD
16 #  include <unistd.h>
17 #endif
18 #if defined(I_FCNTL) || defined(HAS_FCNTL)
19 #  include <fcntl.h>
20 #endif
21 
22 #ifndef SIOCATMARK
23 #   ifdef I_SYS_SOCKIO
24 #       include <sys/sockio.h>
25 #   endif
26 #endif
27 
28 #ifdef PerlIO
29 #if defined(MACOS_TRADITIONAL) && defined(USE_SFIO)
30 #define PERLIO_IS_STDIO 1
31 #undef setbuf
32 #undef setvbuf
33 #define setvbuf		_stdsetvbuf
34 #define setbuf(f,b)	( __sf_setbuf(f,b) )
35 #endif
36 typedef int SysRet;
37 typedef PerlIO * InputStream;
38 typedef PerlIO * OutputStream;
39 #else
40 #define PERLIO_IS_STDIO 1
41 typedef int SysRet;
42 typedef FILE * InputStream;
43 typedef FILE * OutputStream;
44 #endif
45 
46 #define MY_start_subparse(fmt,flags) start_subparse(fmt,flags)
47 
48 #ifndef gv_stashpvn
49 #define gv_stashpvn(str,len,flags) gv_stashpv(str,flags)
50 #endif
51 
52 #ifndef __attribute__noreturn__
53 #  define __attribute__noreturn__
54 #endif
55 
56 #ifndef NORETURN_FUNCTION_END
57 # define NORETURN_FUNCTION_END /* NOT REACHED */ return 0
58 #endif
59 
60 static int not_here(const char *s) __attribute__noreturn__;
61 static int
not_here(const char * s)62 not_here(const char *s)
63 {
64     croak("%s not implemented on this architecture", s);
65     NORETURN_FUNCTION_END;
66 }
67 
68 
69 #ifndef PerlIO
70 #define PerlIO_fileno(f) fileno(f)
71 #endif
72 
73 static int
io_blocking(pTHX_ InputStream f,int block)74 io_blocking(pTHX_ InputStream f, int block)
75 {
76 #if defined(HAS_FCNTL)
77     int RETVAL;
78     if(!f) {
79 	errno = EBADF;
80 	return -1;
81     }
82     RETVAL = fcntl(PerlIO_fileno(f), F_GETFL, 0);
83     if (RETVAL >= 0) {
84 	int mode = RETVAL;
85 	int newmode = mode;
86 #ifdef O_NONBLOCK
87 	/* POSIX style */
88 
89 # ifndef O_NDELAY
90 #  define O_NDELAY O_NONBLOCK
91 # endif
92 	/* Note: UNICOS and UNICOS/mk a F_GETFL returns an O_NDELAY
93 	 * after a successful F_SETFL of an O_NONBLOCK. */
94 	RETVAL = RETVAL & (O_NONBLOCK | O_NDELAY) ? 0 : 1;
95 
96 	if (block == 0) {
97 	    newmode &= ~O_NDELAY;
98 	    newmode |= O_NONBLOCK;
99 	} else if (block > 0) {
100 	    newmode &= ~(O_NDELAY|O_NONBLOCK);
101 	}
102 #else
103 	/* Not POSIX - better have O_NDELAY or we can't cope.
104 	 * for BSD-ish machines this is an acceptable alternative
105 	 * for SysV we can't tell "would block" from EOF but that is
106 	 * the way SysV is...
107 	 */
108 	RETVAL = RETVAL & O_NDELAY ? 0 : 1;
109 
110 	if (block == 0) {
111 	    newmode |= O_NDELAY;
112 	} else if (block > 0) {
113 	    newmode &= ~O_NDELAY;
114 	}
115 #endif
116 	if (newmode != mode) {
117 	    const int ret = fcntl(PerlIO_fileno(f),F_SETFL,newmode);
118 	    if (ret < 0)
119 		RETVAL = ret;
120 	}
121     }
122     return RETVAL;
123 #else
124     return -1;
125 #endif
126 }
127 
128 MODULE = IO	PACKAGE = IO::Seekable	PREFIX = f
129 
130 void
131 fgetpos(handle)
132 	InputStream	handle
133     CODE:
134 	if (handle) {
135 #ifdef PerlIO
136 	    ST(0) = sv_newmortal();
137 #if PERL_VERSION < 8
138 	    Fpos_t pos;
139 	    if (PerlIO_getpos(handle, &pos) != 0) {
140 		ST(0) = &PL_sv_undef;
141 	    }
142 	    else {
143 		sv_setpvn(ST(0), (char *)&pos, sizeof(Fpos_t));
144 	    }
145 #else
146 	    if (PerlIO_getpos(handle, ST(0)) != 0) {
147 		ST(0) = &PL_sv_undef;
148 	    }
149 #endif
150 #else
151 	    Fpos_t pos;
152 	    if (fgetpos(handle, &pos)) {
153 		ST(0) = &PL_sv_undef;
154 	    } else {
155 		ST(0) = sv_2mortal(newSVpvn((char*)&pos, sizeof(Fpos_t)));
156 	    }
157 #endif
158 	}
159 	else {
160 	    errno = EINVAL;
161 	    ST(0) = &PL_sv_undef;
162 	}
163 
164 SysRet
165 fsetpos(handle, pos)
166 	InputStream	handle
167 	SV *		pos
168     CODE:
169 	if (handle) {
170 #ifdef PerlIO
171 #if PERL_VERSION < 8
172 	    char *p;
173 	    STRLEN len;
174 	    if (SvOK(pos) && (p = SvPV(pos,len)) && len == sizeof(Fpos_t)) {
175 		RETVAL = PerlIO_setpos(handle, (Fpos_t*)p);
176 	    }
177 	    else {
178 		RETVAL = -1;
179 		errno = EINVAL;
180 	    }
181 #else
182 	    RETVAL = PerlIO_setpos(handle, pos);
183 #endif
184 #else
185 	    char *p;
186 	    STRLEN len;
187 	    if ((p = SvPV(pos,len)) && len == sizeof(Fpos_t)) {
188 		RETVAL = fsetpos(handle, (Fpos_t*)p);
189 	    }
190 	    else {
191 		RETVAL = -1;
192 		errno = EINVAL;
193 	    }
194 #endif
195 	}
196 	else {
197 	    RETVAL = -1;
198 	    errno = EINVAL;
199 	}
200     OUTPUT:
201 	RETVAL
202 
203 MODULE = IO	PACKAGE = IO::File	PREFIX = f
204 
205 void
206 new_tmpfile(packname = "IO::File")
207     char *	packname
208     PREINIT:
209 	OutputStream fp;
210 	GV *gv;
211     CODE:
212 #ifdef PerlIO
213 	fp = PerlIO_tmpfile();
214 #else
215 	fp = tmpfile();
216 #endif
217 	gv = (GV*)SvREFCNT_inc(newGVgen(packname));
218 	hv_delete(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), G_DISCARD);
219 	if (do_open(gv, "+>&", 3, FALSE, 0, 0, fp)) {
220 	    ST(0) = sv_2mortal(newRV((SV*)gv));
221 	    sv_bless(ST(0), gv_stashpv(packname, TRUE));
222 	    SvREFCNT_dec(gv);   /* undo increment in newRV() */
223 	}
224 	else {
225 	    ST(0) = &PL_sv_undef;
226 	    SvREFCNT_dec(gv);
227 	}
228 
229 MODULE = IO	PACKAGE = IO::Poll
230 
231 void
_poll(timeout,...)232 _poll(timeout,...)
233 	int timeout;
234 PPCODE:
235 {
236 #ifdef HAS_POLL
237     const int nfd = (items - 1) / 2;
238     SV *tmpsv = NEWSV(999,nfd * sizeof(struct pollfd));
239     struct pollfd *fds = (struct pollfd *)SvPVX(tmpsv);
240     int i,j,ret;
241     for(i=1, j=0  ; j < nfd ; j++) {
242 	fds[j].fd = SvIV(ST(i));
243 	i++;
244 	fds[j].events = (short)SvIV(ST(i));
245 	i++;
246 	fds[j].revents = 0;
247     }
248     if((ret = poll(fds,nfd,timeout)) >= 0) {
249 	for(i=1, j=0 ; j < nfd ; j++) {
250 	    sv_setiv(ST(i), fds[j].fd); i++;
251 	    sv_setiv(ST(i), fds[j].revents); i++;
252 	}
253     }
254     SvREFCNT_dec(tmpsv);
255     XSRETURN_IV(ret);
256 #else
257 	not_here("IO::Poll::poll");
258 #endif
259 }
260 
261 MODULE = IO	PACKAGE = IO::Handle	PREFIX = io_
262 
263 void
264 io_blocking(handle,blk=-1)
265 	InputStream	handle
266 	int		blk
267 PROTOTYPE: $;$
268 CODE:
269 {
270     const int ret = io_blocking(aTHX_ handle, items == 1 ? -1 : blk ? 1 : 0);
271     if(ret >= 0)
272 	XSRETURN_IV(ret);
273     else
274 	XSRETURN_UNDEF;
275 }
276 
277 MODULE = IO	PACKAGE = IO::Handle	PREFIX = f
278 
279 int
280 ungetc(handle, c)
281 	InputStream	handle
282 	int		c
283     CODE:
284 	if (handle)
285 #ifdef PerlIO
286 	    RETVAL = PerlIO_ungetc(handle, c);
287 #else
288 	    RETVAL = ungetc(c, handle);
289 #endif
290 	else {
291 	    RETVAL = -1;
292 	    errno = EINVAL;
293 	}
294     OUTPUT:
295 	RETVAL
296 
297 int
298 ferror(handle)
299 	InputStream	handle
300     CODE:
301 	if (handle)
302 #ifdef PerlIO
303 	    RETVAL = PerlIO_error(handle);
304 #else
305 	    RETVAL = ferror(handle);
306 #endif
307 	else {
308 	    RETVAL = -1;
309 	    errno = EINVAL;
310 	}
311     OUTPUT:
312 	RETVAL
313 
314 int
315 clearerr(handle)
316 	InputStream	handle
317     CODE:
318 	if (handle) {
319 #ifdef PerlIO
320 	    PerlIO_clearerr(handle);
321 #else
322 	    clearerr(handle);
323 #endif
324 	    RETVAL = 0;
325 	}
326 	else {
327 	    RETVAL = -1;
328 	    errno = EINVAL;
329 	}
330     OUTPUT:
331 	RETVAL
332 
333 int
334 untaint(handle)
335        SV *	handle
336     CODE:
337 #ifdef IOf_UNTAINT
338 	IO * io;
339 	io = sv_2io(handle);
340 	if (io) {
341 	    IoFLAGS(io) |= IOf_UNTAINT;
342 	    RETVAL = 0;
343 	}
344         else {
345 #endif
346 	    RETVAL = -1;
347 	    errno = EINVAL;
348 #ifdef IOf_UNTAINT
349 	}
350 #endif
351     OUTPUT:
352 	RETVAL
353 
354 SysRet
355 fflush(handle)
356 	OutputStream	handle
357     CODE:
358 	if (handle)
359 #ifdef PerlIO
360 	    RETVAL = PerlIO_flush(handle);
361 #else
362 	    RETVAL = Fflush(handle);
363 #endif
364 	else {
365 	    RETVAL = -1;
366 	    errno = EINVAL;
367 	}
368     OUTPUT:
369 	RETVAL
370 
371 void
372 setbuf(handle, ...)
373 	OutputStream	handle
374     CODE:
375 	if (handle)
376 #ifdef PERLIO_IS_STDIO
377         {
378 	    char *buf = items == 2 && SvPOK(ST(1)) ?
379 	      sv_grow(ST(1), BUFSIZ) : 0;
380 	    setbuf(handle, buf);
381 	}
382 #else
383 	    not_here("IO::Handle::setbuf");
384 #endif
385 
386 SysRet
387 setvbuf(...)
388     CODE:
389 	if (items != 4)
390             Perl_croak(aTHX_ "Usage: IO::Handle::setvbuf(handle, buf, type, size)");
391 #if defined(PERLIO_IS_STDIO) && defined(_IOFBF) && defined(HAS_SETVBUF)
392     {
393         OutputStream	handle = 0;
394 	char *		buf = SvPOK(ST(1)) ? sv_grow(ST(1), SvIV(ST(3))) : 0;
395 	int		type;
396 	int		size;
397 
398 	if (items == 4) {
399 	    handle = IoOFP(sv_2io(ST(0)));
400 	    buf    = SvPOK(ST(1)) ? sv_grow(ST(1), SvIV(ST(3))) : 0;
401 	    type   = (int)SvIV(ST(2));
402 	    size   = (int)SvIV(ST(3));
403 	}
404 	if (!handle)			/* Try input stream. */
405 	    handle = IoIFP(sv_2io(ST(0)));
406 	if (items == 4 && handle)
407 	    RETVAL = setvbuf(handle, buf, type, size);
408 	else {
409 	    RETVAL = -1;
410 	    errno = EINVAL;
411 	}
412     }
413 #else
414 	RETVAL = (SysRet) not_here("IO::Handle::setvbuf");
415 #endif
416     OUTPUT:
417 	RETVAL
418 
419 
420 SysRet
421 fsync(handle)
422 	OutputStream handle
423     CODE:
424 #ifdef HAS_FSYNC
425 	if(handle)
426 	    RETVAL = fsync(PerlIO_fileno(handle));
427 	else {
428 	    RETVAL = -1;
429 	    errno = EINVAL;
430 	}
431 #else
432 	RETVAL = (SysRet) not_here("IO::Handle::sync");
433 #endif
434     OUTPUT:
435 	RETVAL
436 
437 
438 MODULE = IO	PACKAGE = IO::Socket
439 
440 SysRet
sockatmark(sock)441 sockatmark (sock)
442    InputStream sock
443    PROTOTYPE: $
444    PREINIT:
445      int fd;
446    CODE:
447    {
448      fd = PerlIO_fileno(sock);
449 #ifdef HAS_SOCKATMARK
450      RETVAL = sockatmark(fd);
451 #else
452      {
453        int flag = 0;
454 #   ifdef SIOCATMARK
455 #     if defined(NETWARE) || defined(WIN32)
456        if (ioctl(fd, SIOCATMARK, (void*)&flag) != 0)
457 #     else
458        if (ioctl(fd, SIOCATMARK, &flag) != 0)
459 #     endif
460 	 XSRETURN_UNDEF;
461 #   else
462        not_here("IO::Socket::atmark");
463 #   endif
464        RETVAL = flag;
465      }
466 #endif
467    }
468    OUTPUT:
469      RETVAL
470 
471 BOOT:
472 {
473     HV *stash;
474     /*
475      * constant subs for IO::Poll
476      */
477     stash = gv_stashpvn("IO::Poll", 8, TRUE);
478 #ifdef	POLLIN
479 	newCONSTSUB(stash,"POLLIN",newSViv(POLLIN));
480 #endif
481 #ifdef	POLLPRI
482         newCONSTSUB(stash,"POLLPRI", newSViv(POLLPRI));
483 #endif
484 #ifdef	POLLOUT
485         newCONSTSUB(stash,"POLLOUT", newSViv(POLLOUT));
486 #endif
487 #ifdef	POLLRDNORM
488         newCONSTSUB(stash,"POLLRDNORM", newSViv(POLLRDNORM));
489 #endif
490 #ifdef	POLLWRNORM
491         newCONSTSUB(stash,"POLLWRNORM", newSViv(POLLWRNORM));
492 #endif
493 #ifdef	POLLRDBAND
494         newCONSTSUB(stash,"POLLRDBAND", newSViv(POLLRDBAND));
495 #endif
496 #ifdef	POLLWRBAND
497         newCONSTSUB(stash,"POLLWRBAND", newSViv(POLLWRBAND));
498 #endif
499 #ifdef	POLLNORM
500         newCONSTSUB(stash,"POLLNORM", newSViv(POLLNORM));
501 #endif
502 #ifdef	POLLERR
503         newCONSTSUB(stash,"POLLERR", newSViv(POLLERR));
504 #endif
505 #ifdef	POLLHUP
506         newCONSTSUB(stash,"POLLHUP", newSViv(POLLHUP));
507 #endif
508 #ifdef	POLLNVAL
509         newCONSTSUB(stash,"POLLNVAL", newSViv(POLLNVAL));
510 #endif
511     /*
512      * constant subs for IO::Handle
513      */
514     stash = gv_stashpvn("IO::Handle", 10, TRUE);
515 #ifdef _IOFBF
516         newCONSTSUB(stash,"_IOFBF", newSViv(_IOFBF));
517 #endif
518 #ifdef _IOLBF
519         newCONSTSUB(stash,"_IOLBF", newSViv(_IOLBF));
520 #endif
521 #ifdef _IONBF
522         newCONSTSUB(stash,"_IONBF", newSViv(_IONBF));
523 #endif
524 #ifdef SEEK_SET
525         newCONSTSUB(stash,"SEEK_SET", newSViv(SEEK_SET));
526 #endif
527 #ifdef SEEK_CUR
528         newCONSTSUB(stash,"SEEK_CUR", newSViv(SEEK_CUR));
529 #endif
530 #ifdef SEEK_END
531         newCONSTSUB(stash,"SEEK_END", newSViv(SEEK_END));
532 #endif
533 }
534 
535