Add the following packages libalgorithm-diff-perl libspiffy-perl libtext-diff-perl...
[pkg-perl] / deb-src / libfilter-perl / libfilter-perl-1.34 / Exec / Exec.xs
1 /* 
2  * Filename : exec.xs
3  * 
4  * Author   : Paul Marquess 
5  * Date     : 26th March 2000
6  * Version  : 1.05
7  *
8  */
9
10 #include "EXTERN.h"
11 #include "perl.h"
12 #include "XSUB.h"
13 #include "../Call/ppport.h"
14
15 #include <fcntl.h>
16
17 /* Global Data */
18  
19 #define MY_CXT_KEY "Filter::Util::Exec::_guts" XS_VERSION
20  
21 typedef struct {
22     int x_fdebug ;
23 #ifdef WIN32
24     int x_write_started;
25     int x_pipe_pid;
26 #endif
27 } my_cxt_t;
28  
29 START_MY_CXT
30  
31 #define fdebug          (MY_CXT.x_fdebug)
32 #ifdef WIN32
33 #define write_started   (MY_CXT.x_write_started)    
34 #define pipe_pid        (MY_CXT.x_pipe_pid)    
35 #endif
36
37 #ifdef PERL_FILTER_EXISTS
38 #  define CORE_FILTER_SCRIPT PL_parser->rsfp
39 #else
40 #  define CORE_FILTER_SCRIPT PL_rsfp
41 #endif
42
43
44 #define PIPE_IN(sv)     IoLINES(sv)
45 #define PIPE_OUT(sv)    IoPAGE(sv)
46 #define PIPE_PID(sv)    IoLINES_LEFT(sv)
47
48 #define BUF_SV(sv)      IoTOP_GV(sv)
49 #define BUF_START(sv)   SvPVX((SV*) BUF_SV(sv))
50 #define BUF_SIZE(sv)    SvCUR((SV*) BUF_SV(sv))
51 #define BUF_NEXT(sv)    IoFMT_NAME(sv)
52 #define BUF_END(sv)     (BUF_START(sv) + BUF_SIZE(sv))
53 #define BUF_OFFSET(sv)  IoPAGE_LEN(sv) 
54  
55 #define SET_LEN(sv,len) \
56         do { SvPVX(sv)[len] = '\0'; SvCUR_set(sv, len); } while (0)
57  
58 #define BLOCKSIZE       100
59
60
61 #ifdef WIN32
62
63 typedef struct {
64     SV *        sv;
65     int         idx;
66 #ifdef USE_THREADS
67     struct perl_thread *        parent;
68 #endif
69 #ifdef USE_ITHREADS
70     PerlInterpreter *           parent;
71 #endif
72 } thrarg;
73
74 static void
75 pipe_write(void *args)
76 {
77     thrarg *targ = (thrarg *)args;
78     SV *sv = targ->sv;
79     int idx = targ->idx;
80     int    pipe_in  = PIPE_IN(sv) ;
81     int    pipe_out = PIPE_OUT(sv) ;
82     int rawread_eof = 0;
83     int r,w,len;
84 #ifdef USE_THREADS
85     /* use the parent's perl thread context */
86     SET_THR(targ->parent);
87 #endif
88 #ifdef USE_ITHREADS
89     PERL_SET_THX(targ->parent);
90 #endif
91     {
92     dMY_CXT;
93     free(args);
94     for(;;)
95     {       
96
97         /* get some raw data to stuff down the pipe */
98         /* But only when BUF_SV is empty */
99         if (!rawread_eof && BUF_NEXT(sv) >= BUF_END(sv)) {       
100             /* empty BUF_SV */
101             SvCUR_set((SV*)BUF_SV(sv), 0) ;
102             if ((len = FILTER_READ(idx+1, (SV*) BUF_SV(sv), 0)) > 0) {
103                 BUF_NEXT(sv) = BUF_START(sv);
104                 if (fdebug)
105                     warn ("*pipe_write(%d) Filt Rd returned %d %d [%*s]\n", 
106                         idx, len, BUF_SIZE(sv), BUF_SIZE(sv), BUF_START(sv)) ;
107              }
108              else {
109                 /* eof, close write end of pipe after writing to it */
110                  rawread_eof = 1;
111              }
112         }
113  
114         /* write down the pipe */
115         if ((w = BUF_END(sv) - BUF_NEXT(sv)) > 0) {
116             errno = 0;
117             if ((w = write(pipe_out, BUF_NEXT(sv), w)) > 0) {
118                 BUF_NEXT(sv) += w;
119                 if (fdebug)
120                     warn ("*pipe_write(%d) wrote %d bytes to pipe\n", idx, w) ;
121             }
122             else {
123                 if (fdebug)
124                    warn ("*pipe_write(%d) closing pipe_out errno = %d %s\n", 
125                         idx, errno, Strerror(errno)) ;
126                 close(pipe_out) ;
127                 CloseHandle((HANDLE)pipe_pid);
128                 write_started = 0;
129                 return;
130             }
131         }
132         else if (rawread_eof) {
133             if (fdebug)
134                warn ("*pipe_write(%d) closing pipe_out errno = %d %s\n", 
135                 idx, errno, Strerror(errno)) ;
136             close(pipe_out);
137             CloseHandle((HANDLE)pipe_pid);
138             write_started = 0;
139             return;
140         }
141     }
142     }
143 }
144
145 static int
146 pipe_read(SV *sv, int idx, int maxlen)
147 {
148     dMY_CXT;
149     int    pipe_in  = PIPE_IN(sv) ;
150     int    pipe_out = PIPE_OUT(sv) ;
151
152     int r ;
153     int w ;
154     int len ;
155
156     if (fdebug)
157         warn ("*pipe_read(sv=%d, SvCUR(sv)=%d, idx=%d, maxlen=%d\n",
158                 sv, SvCUR(sv), idx, maxlen) ;
159
160     if (!maxlen)
161         maxlen = 1024 ;
162
163     /* just make sure the SV is big enough */
164     SvGROW(sv, SvCUR(sv) + maxlen) ;
165
166     if ( !BUF_NEXT(sv) )
167         BUF_NEXT(sv) = BUF_START(sv);
168
169     if (!write_started) {
170         thrarg *targ = (thrarg*)malloc(sizeof(thrarg));
171         targ->sv = sv; targ->idx = idx;
172 #ifdef USE_THREADS
173         targ->parent = THR;
174 #endif
175 #ifdef USE_ITHREADS
176         targ->parent = aTHX;
177 #endif
178         /* thread handle is closed when pipe_write() returns */
179         _beginthread(pipe_write,0,(void *)targ);
180         write_started = 1;
181     }
182
183     /* try to get data from filter, if any */
184     errno = 0;
185     len = SvCUR(sv) ;
186     if ((r = read(pipe_in, SvPVX(sv) + len, maxlen)) > 0)
187     {
188         if (fdebug)
189             warn ("*pipe_read(%d) from pipe returned %d [%*s]\n", 
190                         idx, r, r, SvPVX(sv) + len) ;
191         SvCUR_set(sv, r + len) ;
192         return SvCUR(sv);
193     }
194
195     if (fdebug)
196         warn ("*pipe_read(%d) returned %d, errno = %d %s\n", 
197                 idx, r, errno, Strerror(errno)) ;
198
199     /* close the read pipe on error/eof */
200     if (fdebug)
201         warn("*pipe_read(%d) -- EOF <#########\n", idx) ;
202     close (pipe_in) ; 
203     return 0;
204 }
205
206 #else /* !WIN32 */
207
208
209 static int
210 pipe_read(SV *sv, int idx, int maxlen)
211 {
212     dMY_CXT;
213     int    pipe_in  = PIPE_IN(sv) ;
214     int    pipe_out = PIPE_OUT(sv) ;
215     int    pipe_pid = PIPE_PID(sv) ;
216
217     int r ;
218     int w ;
219     int len ;
220
221     if (fdebug)
222         warn ("*pipe_read(sv=%d, SvCUR(sv)=%d, idx=%d, maxlen=%d\n",
223                 sv, SvCUR(sv), idx, maxlen) ;
224
225     if (!maxlen)
226         maxlen = 1024 ;
227
228     /* just make sure the SV is big enough */
229     SvGROW(sv, SvCUR(sv) + maxlen) ;
230
231     for(;;)
232     {       
233         if ( !BUF_NEXT(sv) )
234             BUF_NEXT(sv) = BUF_START(sv);
235         else
236         {       
237             /* try to get data from filter, if any */
238             errno = 0;
239             len = SvCUR(sv) ;
240             if ((r = read(pipe_in, SvPVX(sv) + len, maxlen)) > 0)
241             {
242                 if (fdebug)
243                     warn ("*pipe_read(%d) from pipe returned %d [%*s]\n", 
244                                 idx, r, r, SvPVX(sv) + len) ;
245                 SvCUR_set(sv, r + len) ;
246                 return SvCUR(sv);
247             }
248
249             if (fdebug)
250                 warn ("*pipe_read(%d) returned %d, errno = %d %s\n", 
251                         idx, r, errno, Strerror(errno)) ;
252
253             if (errno != VAL_EAGAIN)
254             {
255                 /* close the read pipe on error/eof */
256                 if (fdebug)
257                     warn("*pipe_read(%d) -- EOF <#########\n", idx) ;
258                 close (pipe_in) ; 
259 #ifdef HAVE_WAITPID
260                 waitpid(pipe_pid, NULL, 0) ;
261 #else
262                 wait(NULL);
263 #endif
264                 return 0;
265             }
266         }
267
268         /* get some raw data to stuff down the pipe */
269         /* But only when BUF_SV is empty */
270         if (BUF_NEXT(sv) >= BUF_END(sv))
271         {       
272             /* empty BUF_SV */
273             SvCUR_set((SV*)BUF_SV(sv), 0) ;
274             if ((len = FILTER_READ(idx+1, (SV*) BUF_SV(sv), 0)) > 0) {
275                 BUF_NEXT(sv) = BUF_START(sv);
276                 if (fdebug)
277                     warn ("*pipe_write(%d) Filt Rd returned %d %d [%*s]\n", 
278                         idx, len, BUF_SIZE(sv), BUF_SIZE(sv), BUF_START(sv)) ;
279              }
280              else {
281                 /* eof, close write end of pipe */
282                 close(pipe_out) ; 
283                 if (fdebug)
284                     warn ("*pipe_read(%d) closing pipe_out errno = %d %s\n", 
285                                 idx, errno,
286                         Strerror(errno)) ;
287              }
288          }
289  
290          /* write down the pipe */
291          if ((w = BUF_END(sv) - BUF_NEXT(sv)) > 0)
292          {       
293              errno = 0;
294              if ((w = write(pipe_out, BUF_NEXT(sv), w)) > 0) {
295                  BUF_NEXT(sv) += w;
296                  if (fdebug)
297                     warn ("*pipe_read(%d) wrote %d bytes to pipe\n", idx, w) ;
298              }
299             else if (errno != VAL_EAGAIN) {
300                  if (fdebug)
301                     warn ("*pipe_read(%d) closing pipe_out errno = %d %s\n", 
302                                 idx, errno, Strerror(errno)) ;
303                  /* close(pipe_out) ; */
304                  return 0;
305              }
306              else {    /* pipe is full, sleep for a while, then continue */
307                  if (fdebug)
308                     warn ("*pipe_read(%d) - sleeping\n", idx ) ;
309                  sleep(0);
310              }
311         }
312     }
313 }
314
315
316 static void
317 make_nonblock(int f)
318 {
319    int RETVAL ;
320    int mode = fcntl(f, F_GETFL);
321  
322    if (mode < 0)
323         croak("fcntl(f, F_GETFL) failed, RETVAL = %d, errno = %d",
324                 mode, errno) ;
325  
326    if (!(mode & VAL_O_NONBLOCK))
327        RETVAL = fcntl(f, F_SETFL, mode | VAL_O_NONBLOCK);
328  
329     if (RETVAL < 0)
330         croak("cannot create a non-blocking pipe, RETVAL = %d, errno = %d",
331                 RETVAL, errno) ;
332 }
333  
334 #endif
335
336
337 #define READER  0
338 #define WRITER  1
339
340 static Pid_t
341 spawnCommand(PerlIO *fil, char *command, char *parameters[], int *p0, int *p1)  
342 {
343     dMY_CXT;
344 #ifdef WIN32
345
346 #if defined(PERL_OBJECT)
347 #  define win32_pipe(p,n,f) _pipe(p,n,f)
348 #endif
349
350     int p[2], c[2];
351     SV * sv ;
352     int oldstdout, oldstdin;
353
354     /* create the pipes */
355     if (win32_pipe(p,512,O_TEXT|O_NOINHERIT) == -1
356         || win32_pipe(c,512,O_BINARY|O_NOINHERIT) == -1) {
357         PerlIO_close( fil );
358         croak("Can't get pipe for %s", command);
359     }
360
361     /* duplicate stdout and stdin */
362     oldstdout = dup(fileno(stdout));
363     if (oldstdout == -1) {
364         PerlIO_close( fil );
365         croak("Can't dup stdout for %s", command);
366     }
367     oldstdin  = dup(fileno(stdin));
368     if (oldstdin == -1) {
369         PerlIO_close( fil );
370         croak("Can't dup stdin for %s", command);
371     }
372
373     /* duplicate inheritable ends as std handles for the child */
374     if (dup2(p[WRITER], fileno(stdout))) {
375         PerlIO_close( fil );
376         croak("Can't attach pipe to stdout for %s", command);
377     }
378     if (dup2(c[READER], fileno(stdin))) {
379         PerlIO_close( fil );
380         croak("Can't attach pipe to stdin for %s", command);
381     }
382
383     /* close original inheritable ends in parent */
384     close(p[WRITER]);
385     close(c[READER]);
386
387     /* spawn child process (which inherits the redirected std handles) */
388     pipe_pid = spawnvp(P_NOWAIT, command, parameters);
389     if (pipe_pid == -1) {
390         PerlIO_close( fil );
391         croak("Can't spawn %s", command);
392     }
393
394     /* restore std handles */
395     if (dup2(oldstdout, fileno(stdout))) {
396         PerlIO_close( fil );
397         croak("Can't restore stdout for %s", command);
398     }
399     if (dup2(oldstdin, fileno(stdin))) {
400         PerlIO_close( fil );
401         croak("Can't restore stdin for %s", command);
402     }
403
404     /* close saved handles */
405     close(oldstdout);
406     close(oldstdin);
407
408     *p0 = p[READER] ;
409     *p1 = c[WRITER] ;
410
411 #else /* !WIN32 */
412
413     int p[2], c[2];
414     SV * sv ;
415     int pipepid;
416
417     /* Check that the file is seekable */
418     /* if (lseek(fileno(fil), ftell(fil), 0) == -1) { */
419         /* croak("lseek failed: %s", Strerror(errno)) ; */
420     /* }  */
421
422     if (pipe(p) < 0 || pipe(c)) {
423         PerlIO_close( fil );
424         croak("Can't get pipe for %s", command);
425     }
426
427     /* make sure that the child doesn't get anything extra */
428     fflush(stdout);
429     fflush(stderr);
430
431     while ((pipepid = fork()) < 0) {
432         if (errno != EAGAIN) {
433             close(p[0]);
434             close(p[1]);
435             close(c[0]) ;
436             close(c[1]) ;
437             PerlIO_close( fil );
438             croak("Can't fork for %s", command);
439         }
440         sleep(1);
441     }
442
443     if (pipepid == 0) {
444         /* The Child */
445
446         close(p[READER]) ;
447         close(c[WRITER]) ;
448         if (c[READER] != 0) {
449             dup2(c[READER], 0);
450             close(c[READER]); 
451         }
452         if (p[WRITER] != 1) {
453             dup2(p[WRITER], 1);
454             close(p[WRITER]); 
455         }
456
457         /* Run command */
458         execvp(command, parameters) ;
459         croak("execvp failed for command '%s': %s", command, Strerror(errno)) ;
460         fflush(stdout);
461         fflush(stderr);
462         _exit(0);
463     }
464
465     /* The parent */
466
467     close(p[WRITER]) ;
468     close(c[READER]) ;
469
470     /* make the pipe non-blocking */
471     make_nonblock(p[READER]) ;
472     make_nonblock(c[WRITER]) ;
473
474     *p0 = p[READER] ;
475     *p1 = c[WRITER] ;
476
477     return pipepid;
478 #endif
479 }
480
481
482 static I32
483 filter_exec(pTHX_ int idx, SV *buf_sv, int maxlen)
484 {
485     dMY_CXT;
486     I32 len;
487     SV   *buffer = FILTER_DATA(idx);
488     char * out_ptr = SvPVX(buffer) ;
489     int n ;
490     char *      p ;
491     char *      nl = "\n" ;
492  
493     if (fdebug)
494         warn ("filter_sh(idx=%d, SvCUR(buf_sv)=%d, maxlen=%d\n", 
495                 idx, SvCUR(buf_sv), maxlen) ;
496     while (1) {
497         STRLEN n_a;
498
499         /* If there was a partial line/block left from last time
500            copy it now
501         */
502         if (n = SvCUR(buffer)) {
503             out_ptr  = SvPVX(buffer) + BUF_OFFSET(buffer) ;
504             if (maxlen) { 
505                 /* want a block */
506                 if (fdebug)
507                     warn("filter_sh(%d) - wants a block\n", idx) ;
508                 sv_catpvn(buf_sv, out_ptr, maxlen > n ? n : maxlen );
509                 if(n <= maxlen) {
510                     BUF_OFFSET(buffer) = 0 ;
511                     SET_LEN(buffer, 0) ; 
512                 }
513                 else {
514                     BUF_OFFSET(buffer) += maxlen ;
515                     SvCUR_set(buffer, n - maxlen) ;
516                 }
517                 return SvCUR(buf_sv);
518             }
519             else {
520                 /* want a line */
521                 if (fdebug)
522                     warn("filter_sh(%d) - wants a line\n", idx) ;
523                 if (p = ninstr(out_ptr, out_ptr + n, nl, nl + 1)) {
524                     sv_catpvn(buf_sv, out_ptr, p - out_ptr + 1);
525                     n = n - (p - out_ptr + 1);
526                     BUF_OFFSET(buffer) += (p - out_ptr + 1);
527                     SvCUR_set(buffer, n) ;
528                     if (fdebug)
529                         warn("recycle(%d) - leaving %d [%s], returning %d %d [%s]", 
530                                 idx, n, 
531                                 SvPVX(buffer), p - out_ptr + 1, 
532                                 SvCUR(buf_sv), SvPVX(buf_sv)) ;
533      
534                     return SvCUR(buf_sv);
535                 }
536                 else /* partial buffer didn't have any newlines, so copy it all */
537                     sv_catpvn(buf_sv, out_ptr, n) ;
538             }
539  
540         }
541  
542
543         /* the buffer has been consumed, so reset the length */
544         SET_LEN(buffer, 0) ; 
545         BUF_OFFSET(buffer) = 0 ;
546
547         /* read from the sub-process */
548         if ( (n=pipe_read(buffer, idx, maxlen)) <= 0) {
549  
550             if (fdebug)
551                 warn ("filter_sh(%d) - pipe_read returned %d , returning %d\n", 
552                         idx, n, (SvCUR(buf_sv)>0) ? SvCUR(buf_sv) : n);
553  
554             SvCUR_set(buffer, 0);
555             BUF_NEXT(buffer) = Nullch;  /* or perl will try to free() it */
556             /* filter_del(filter_sh);  */
557  
558             /* If error, return the code */
559             if (n < 0)
560                 return n ;
561  
562             /* return what we have so far else signal eof */
563             return (SvCUR(buf_sv)>0) ? SvCUR(buf_sv) : n;
564         }
565  
566         if (fdebug)
567             warn("  filter_sh(%d): pipe_read returned %d %d: '%s'",
568                 idx, n, SvCUR(buffer), SvPV(buffer,n_a));
569  
570     }
571
572 }
573
574
575 MODULE = Filter::Util::Exec     PACKAGE = Filter::Util::Exec
576
577 REQUIRE:        1.924
578 PROTOTYPES:     ENABLE
579
580 BOOT:
581   {
582     MY_CXT_INIT;
583     fdebug = 0;
584     /* temporary hack to control debugging in toke.c */
585     filter_add(NULL, (fdebug) ? (SV*)"1" : (SV*)"0"); 
586   }
587
588
589 void
590 filter_add(module, command, ...)
591     SV *        module = NO_INIT
592     char **     command = (char**) safemalloc(items * sizeof(char*)) ;
593     PROTOTYPE:  $@
594     CODE:
595         dMY_CXT;
596         int i ;
597         int pipe_in, pipe_out ;
598         STRLEN n_a ;
599         /* SV * sv = newSVpv("", 0) ; */
600         SV * sv = newSV(1) ;
601         Pid_t pid;
602  
603       if (fdebug)
604           warn("Filter::exec::import\n") ;
605       for (i = 1 ; i < items ; ++i)
606       {
607           command[i-1] = SvPV(ST(i), n_a) ;
608           if (fdebug)
609               warn("    %s\n", command[i-1]) ;
610       }
611       command[i-1] = NULL ;
612       filter_add(filter_exec, sv);
613       pid = spawnCommand(CORE_FILTER_SCRIPT, command[0], command, &pipe_in, &pipe_out) ;
614       safefree((char*)command) ;
615
616       PIPE_PID(sv)  = pid ;
617       PIPE_IN(sv)   = pipe_in ;
618       PIPE_OUT(sv)  = pipe_out ;
619       /* BUF_SV(sv)    = newSVpv("", 0) ; */
620       BUF_SV(sv)    = (GV*) newSV(1) ;
621       (void)SvPOK_only(BUF_SV(sv)) ;
622       BUF_NEXT(sv)  = NULL ;
623       BUF_OFFSET(sv) = 0 ;
624
625