use addnwstr
[nvi.git] / perl_api / perl.xs
blobce47342bf12447b2d16c0204d76da3f5af0d2485
1 /*-
2  * Copyright (c) 1992, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5  *      Keith Bostic.  All rights reserved.
6  * Copyright (c) 1995
7  *      George V. Neville-Neil. All rights reserved.
8  * Copyright (c) 1996
9  *      Sven Verdoolaege. All rights reserved.
10  *
11  * See the LICENSE file for redistribution information.
12  */
14 #undef VI
16 #ifndef lint
17 static const char sccsid[] = "$Id: perl.xs,v 8.37 2001/03/14 21:48:14 skimo Exp $ (Berkeley) $Date: 2001/03/14 21:48:14 $";
18 #endif /* not lint */
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/time.h>
24 #include <bitstring.h>
25 #include <ctype.h>
26 #include <limits.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <termios.h>
32 #include <unistd.h>
34 #include <EXTERN.h>
35 #include <perl.h>
36 #include <XSUB.h>
38 /* perl redefines them
39  * avoid warnings
40  */
41 #undef USE_DYNAMIC_LOADING
42 #undef DEBUG
43 #undef PACKAGE
44 #undef ARGS
45 #define ARGS ARGS
47 #include "config.h"
49 #include "../common/common.h"
50 #include "../perl_api/extern.h"
52 #ifndef DEFSV
53 #define DEFSV GvSV(defgv)
54 #endif
55 #ifndef ERRSV
56 #define ERRSV GvSV(errgv)
57 #endif
58 #ifndef dTHX
59 #define dTHXs
60 #else
61 #define dTHXs dTHX;
62 #endif
64 static void msghandler __P((SCR *, mtype_t, char *, size_t));
66 static char *errmsg = 0;
68 typedef struct _perl_data {
69         PerlInterpreter*        interp;
70         SV      *svcurscr, *svstart, *svstop, *svid;
71         void    *perl_bp;
72         size_t   perl_blen;
73 } perl_data_t;
75 #define CHAR2INTP(sp,n,nlen,w,wlen)                                         \
76     CHAR2INTB(sp,n,nlen,w,wlen,((perl_data_t *)sp->wp->perl_private)->perl)
79  * INITMESSAGE --
80  *      Macros to point messages at the Perl message handler.
81  */
82 #define INITMESSAGE(sp)                                                 \
83         scr_msg = sp->gp->scr_msg;                                      \
84         sp->gp->scr_msg = msghandler;
85 #define ENDMESSAGE(sp)                                                  \
86         sp->gp->scr_msg = scr_msg;                                      \
87         if (rval) croak(errmsg);
89 void xs_init __P((pTHXo));
92  * perl_end --
93  *      Clean up perl interpreter
94  *
95  * PUBLIC: int perl_end __P((GS *));
96  */
97 int
98 perl_end(gp)
99         GS *gp;
101         /*
102          * Call perl_run and perl_destuct to call END blocks and DESTROY
103          * methods.
104          */
105         if (gp->perl_interp) {
106                 perl_run(gp->perl_interp);
107                 perl_destruct(gp->perl_interp);
108 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
109                 perl_free(gp->perl_interp);
110 #endif
111                 /* XXX rather make sure only one thread calls perl_end */
112                 gp->perl_interp = 0;
113         }
117  * perl_eval
118  *      Evaluate a string
119  *      We don't use mortal SVs because no one will clean up after us
120  */
121 static void 
122 perl_eval(string)
123         char *string;
125         dTHXs
127         SV* sv = newSVpv(string, 0);
129         /* G_KEEPERR to catch syntax error; better way ? */
130         sv_setpv(ERRSV,"");
131         perl_eval_sv(sv, G_DISCARD | G_NOARGS | G_KEEPERR);
132         SvREFCNT_dec(sv);
136  * perl_init --
137  *      Create the perl commands used by nvi.
139  * PUBLIC: int perl_init __P((SCR *));
140  */
142 perl_init(scrp)
143         SCR *scrp;
145         AV * av;
146         GS *gp;
147         WIN *wp;
148         char *bootargs[] = { "VI", NULL };
149 #ifndef USE_SFIO
150         SV *svcurscr;
151 #endif
152         perl_data_t *pp;
154         static char *args[] = { "", "-e", "" };
155         STRLEN length;
156         char *file = __FILE__;
158         gp = scrp->gp;
159         wp = scrp->wp;
161         if (gp->perl_interp == NULL) {
162         gp->perl_interp = perl_alloc();
163         perl_construct(gp->perl_interp);
164         if (perl_parse(gp->perl_interp, xs_init, 3, args, 0)) {
165                 perl_destruct(gp->perl_interp);
166                 perl_free(gp->perl_interp);
167                 gp->perl_interp = NULL;
168                 return 1;
169         }
170         {
171         dTHXs
173         perl_call_argv("VI::bootstrap", G_DISCARD, bootargs);
174         perl_eval("$SIG{__WARN__}='VI::Warn'");
176         av_unshift(av = GvAVn(PL_incgv), 1);
177         av_store(av, 0, newSVpv(_PATH_PERLSCRIPTS,
178                                 sizeof(_PATH_PERLSCRIPTS)-1));
180 #ifdef USE_SFIO
181         sfdisc(PerlIO_stdout(), sfdcnewnvi(scrp));
182         sfdisc(PerlIO_stderr(), sfdcnewnvi(scrp));
183 #else
184         svcurscr = perl_get_sv("curscr", TRUE);
185         sv_magic((SV *)gv_fetchpv("STDOUT",TRUE, SVt_PVIO), svcurscr,
186                         'q', Nullch, 0);
187         sv_magic((SV *)gv_fetchpv("STDERR",TRUE, SVt_PVIO), svcurscr,
188                         'q', Nullch, 0);
189 #endif /* USE_SFIO */
190         }
191         }
192         MALLOC(scrp, pp, perl_data_t *, sizeof(perl_data_t));
193         wp->perl_private = pp;
194         pp->perl_blen = 0;
195         pp->perl_bp = 0;
196 #ifdef USE_ITHREADS
197         pp->interp = perl_clone(gp->perl_interp, 0);
198         if (1) { /* hack for bug fixed in perl-current (5.6.1) */
199             dTHXa(pp->interp);
200             if (PL_scopestack_ix == 0) {
201                 ENTER;
202             }
203         }
204 #else
205         pp->interp = gp->perl_interp;
206 #endif
207         {
208                 dTHXs
210                 SvREADONLY_on(pp->svcurscr = perl_get_sv("curscr", TRUE));
211                 SvREADONLY_on(pp->svstart = perl_get_sv("VI::StartLine", TRUE));
212                 SvREADONLY_on(pp->svstop = perl_get_sv("VI::StopLine", TRUE));
213                 SvREADONLY_on(pp->svid = perl_get_sv("VI::ScreenId", TRUE));
214         }
215         return (0);
219  * perl_screen_end
220  *      Remove all refences to the screen to be destroyed
222  * PUBLIC: int perl_screen_end __P((SCR*));
223  */
225 perl_screen_end(scrp)
226         SCR *scrp;
228         dTHXs
230         if (scrp->perl_private) {
231                 sv_setiv((SV*) scrp->perl_private, 0);
232         }
233         return 0;
236 static void
237 my_sighandler(i)
238         int i;
240         croak("Perl command interrupted by SIGINT");
243 /* Create a new reference to an SV pointing to the SCR structure
244  * The perl_private part of the SCR structure points to the SV,
245  * so there can only be one such SV for a particular SCR structure.
246  * When the last reference has gone (DESTROY is called),
247  * perl_private is reset; When the screen goes away before
248  * all references are gone, the value of the SV is reset;
249  * any subsequent use of any of those reference will produce
250  * a warning. (see typemap)
251  */
252 static SV *
253 newVIrv(rv, screen)
254         SV *rv;
255         SCR *screen;
257         dTHXs
259         if (!screen) return sv_setsv(rv, &PL_sv_undef), rv;
260         sv_upgrade(rv, SVt_RV);
261         if (!screen->perl_private) {
262                 screen->perl_private = newSV(0);
263                 sv_setiv(screen->perl_private, (IV) screen);
264         } 
265         else SvREFCNT_inc(screen->perl_private);
266         SvRV(rv) = screen->perl_private;
267         SvROK_on(rv);
268         return sv_bless(rv, gv_stashpv("VI", TRUE));
272 /* 
273  * perl_ex_perl -- :[line [,line]] perl [command]
274  *      Run a command through the perl interpreter.
276  * PUBLIC: int perl_ex_perl __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
277  */
278 int 
279 perl_ex_perl(scrp, cmdp, cmdlen, f_lno, t_lno)
280         SCR *scrp;
281         CHAR_T *cmdp;
282         size_t cmdlen;
283         db_recno_t f_lno, t_lno;
285         WIN *wp;
286         STRLEN length;
287         size_t len;
288         char *err;
289         char *np;
290         size_t nlen;
291         Signal_t (*istat)();
292         perl_data_t *pp;
294         /* Initialize the interpreter. */
295         if (scrp->wp->perl_private == NULL && perl_init(scrp))
296                         return (1);
297         pp = scrp->wp->perl_private;
298     {
299         dTHXs
300         dSP;
302         sv_setiv(pp->svstart, f_lno);
303         sv_setiv(pp->svstop, t_lno);
304         newVIrv(pp->svcurscr, scrp);
305         /* Backwards compatibility. */
306         newVIrv(pp->svid, scrp);
308         istat = signal(SIGINT, my_sighandler);
309         INT2CHAR(scrp, cmdp, v_strlen(cmdp)+1, np, nlen);
310         perl_eval(np);
311         signal(SIGINT, istat);
313         SvREFCNT_dec(SvRV(pp->svcurscr));
314         SvROK_off(pp->svcurscr);
315         SvREFCNT_dec(SvRV(pp->svid));
316         SvROK_off(pp->svid);
318         err = SvPV(ERRSV, length);
319         if (!length)
320                 return (0);
322         err[length - 1] = '\0';
323         msgq(scrp, M_ERR, "perl: %s", err);
324         return (1);
325     }
329  * replace_line
330  *      replace a line with the contents of the perl variable $_
331  *      lines are split at '\n's
332  *      if $_ is undef, the line is deleted
333  *      returns possibly adjusted linenumber
334  */
335 static int 
336 replace_line(scrp, line, t_lno, defsv)
337         SCR *scrp;
338         db_recno_t line, *t_lno;
339         SV *defsv;
341         char *str, *next;
342         CHAR_T *wp;
343         size_t len, wlen;
344         dTHXs
346         if (SvOK(defsv)) {
347                 str = SvPV(defsv,len);
348                 next = memchr(str, '\n', len);
349                 CHAR2INTP(scrp, str, next ? (next - str) : len, wp, wlen);
350                 api_sline(scrp, line, wp, wlen);
351                 while (next++) {
352                         len -= next - str;
353                         next = memchr(str = next, '\n', len);
354                         CHAR2INTP(scrp, str, next ? (next - str) : len, 
355                                     wp, wlen);
356                         api_iline(scrp, ++line, wp, wlen);
357                         (*t_lno)++;
358                 }
359         } else {
360                 api_dline(scrp, line--);
361                 (*t_lno)--;
362         }
363         return line;
366 /* 
367  * perl_ex_perldo -- :[line [,line]] perl [command]
368  *      Run a set of lines through the perl interpreter.
370  * PUBLIC: int perl_ex_perldo __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
371  */
372 int 
373 perl_ex_perldo(scrp, cmdp, cmdlen, f_lno, t_lno)
374         SCR *scrp;
375         CHAR_T *cmdp;
376         size_t cmdlen;
377         db_recno_t f_lno, t_lno;
379         CHAR_T *p;
380         WIN *wp;
381         STRLEN length;
382         size_t len;
383         db_recno_t i;
384         CHAR_T *str;
385         char *estr;
386         SV* cv;
387         char *command;
388         perl_data_t *pp;
389         char *np;
390         size_t nlen;
392         /* Initialize the interpreter. */
393         if (scrp->wp->perl_private == NULL && perl_init(scrp))
394                         return (1);
395         pp = scrp->wp->perl_private;
396     {
397         dTHXs
398         dSP;
400         newVIrv(pp->svcurscr, scrp);
401         /* Backwards compatibility. */
402         newVIrv(pp->svid, scrp);
404         INT2CHAR(scrp, cmdp, v_strlen(cmdp)+1, np, nlen);
405         if (!(command = malloc(length = nlen - 1 + sizeof("sub {}"))))
406                 return 1;
407         snprintf(command, length, "sub {%s}", np);
409         ENTER;
410         SAVETMPS;
412         cv = perl_eval_pv(command, FALSE);
413         free (command);
415         estr = SvPV(ERRSV,length);
416         if (length)
417                 goto err;
419         for (i = f_lno; i <= t_lno && !api_gline(scrp, i, &str, &len); i++) {
420                 INT2CHAR(scrp, str, len, np, nlen);
421                 sv_setpvn(DEFSV,np,nlen);
422                 sv_setiv(pp->svstart, i);
423                 sv_setiv(pp->svstop, i);
424                 PUSHMARK(sp);
425                 perl_call_sv(cv, G_SCALAR | G_EVAL);
426                 estr = SvPV(ERRSV, length);
427                 if (length) break;
428                 SPAGAIN;
429                 if(SvTRUEx(POPs)) 
430                         i = replace_line(scrp, i, &t_lno, DEFSV);
431                 PUTBACK;
432         }
433         FREETMPS;
434         LEAVE;
436         SvREFCNT_dec(SvRV(pp->svcurscr));
437         SvROK_off(pp->svcurscr);
438         SvREFCNT_dec(SvRV(pp->svid));
439         SvROK_off(pp->svid);
441         if (!length)
442                 return (0);
444 err:    estr[length - 1] = '\0';
445         msgq(scrp, M_ERR, "perl: %s", estr);
446         return (1);
447     }
451  * msghandler --
452  *      Perl message routine so that error messages are processed in
453  *      Perl, not in nvi.
454  */
455 static void
456 msghandler(sp, mtype, msg, len)
457         SCR *sp;
458         mtype_t mtype;
459         char *msg;
460         size_t len;
462         /* Replace the trailing <newline> with an EOS. */
463         /* Let's do that later instead */
464         if (errmsg) free (errmsg);
465         errmsg = malloc(len + 1);
466         memcpy(errmsg, msg, len);
467         errmsg[len] = '\0';
471 typedef SCR *   VI;
472 typedef SCR *   VI__OPT;
473 typedef SCR *   VI__MAP;
474 typedef SCR *   VI__MARK;
475 typedef SCR *   VI__LINE;
476 typedef AV *    AVREF;
478 typedef struct {
479     SV      *sprv;
480     TAGQ    *tqp;
481 } perl_tagq;
483 typedef perl_tagq *  VI__TAGQ;
484 typedef perl_tagq *  VI__TAGQ2;
486 MODULE = VI     PACKAGE = VI
488 # msg --
489 #       Set the message line to text.
491 # Perl Command: VI::Msg
492 # Usage: VI::Msg screenId text
494 void
495 Msg(screen, text)
496         VI          screen
497         char *      text
499         ALIAS:
500         PRINT = 1
502         CODE:
503         api_imessage(screen, text);
505 # XS_VI_escreen --
506 #       End a screen.
508 # Perl Command: VI::EndScreen
509 # Usage: VI::EndScreen screenId
511 void
512 EndScreen(screen)
513         VI      screen
515         PREINIT:
516         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
517         int rval;
519         CODE:
520         INITMESSAGE(screen);
521         rval = api_escreen(screen);
522         ENDMESSAGE(screen);
524 # XS_VI_iscreen --
525 #       Create a new screen.  If a filename is specified then the screen
526 #       is opened with that file.
528 # Perl Command: VI::NewScreen
529 # Usage: VI::NewScreen screenId [file]
532 Edit(screen, ...)
533         VI screen
535         ALIAS:
536         NewScreen = 1
538         PROTOTYPE: $;$
539         PREINIT:
540         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
541         int rval;
542         char *file;
543         SCR *nsp;
545         CODE:
546         file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
547         INITMESSAGE(screen);
548         rval = api_edit(screen, file, &nsp, ix);
549         ENDMESSAGE(screen);
550         
551         RETVAL = ix ? nsp : screen;
553         OUTPUT:
554         RETVAL
556 # XS_VI_fscreen --
557 #       Return the screen id associated with file name.
559 # Perl Command: VI::FindScreen
560 # Usage: VI::FindScreen file
563 FindScreen(file)
564         char *file
566         PREINIT:
567         SCR *fsp;
568         CODE:
569         RETVAL = api_fscreen(0, file);
571         OUTPUT:
572         RETVAL
574 # XS_VI_GetFileName --
575 #       Return the file name of the screen
577 # Perl Command: VI::GetFileName
578 # Usage: VI::GetFileName screenId
580 char *
581 GetFileName(screen)
582         VI screen;
584         PPCODE:
585         EXTEND(sp,1);
586         PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
588 # XS_VI_aline --
589 #       -- Append the string text after the line in lineNumber.
591 # Perl Command: VI::AppendLine
592 # Usage: VI::AppendLine screenId lineNumber text
594 void
595 AppendLine(screen, linenumber, text)
596         VI screen
597         int linenumber
598         char *text
600         PREINIT:
601         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
602         int rval;
603         STRLEN length;
605         CODE:
606         SvPV(ST(2), length);
607         INITMESSAGE(screen);
608         rval = api_aline(screen, linenumber, text, length);
609         ENDMESSAGE(screen);
611 # XS_VI_dline --
612 #       Delete lineNum.
614 # Perl Command: VI::DelLine
615 # Usage: VI::DelLine screenId lineNum
617 void 
618 DelLine(screen, linenumber)
619         VI screen
620         int linenumber
622         PREINIT:
623         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
624         int rval;
626         CODE:
627         INITMESSAGE(screen);
628         rval = api_dline(screen, (db_recno_t)linenumber);
629         ENDMESSAGE(screen);
631 # XS_VI_gline --
632 #       Return lineNumber.
634 # Perl Command: VI::GetLine
635 # Usage: VI::GetLine screenId lineNumber
637 char *
638 GetLine(screen, linenumber)
639         VI screen
640         int linenumber
642         PREINIT:
643         size_t len;
644         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
645         int rval;
646         char *line;
647         CHAR_T *p;
649         PPCODE:
650         INITMESSAGE(screen);
651         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
652         ENDMESSAGE(screen);
654         EXTEND(sp,1);
655         PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
657 # XS_VI_sline --
658 #       Set lineNumber to the text supplied.
660 # Perl Command: VI::SetLine
661 # Usage: VI::SetLine screenId lineNumber text
663 void
664 SetLine(screen, linenumber, text)
665         VI screen
666         int linenumber
667         char *text
669         PREINIT:
670         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
671         int rval;
672         STRLEN length;
673         size_t len;
674         CHAR_T *line;
676         CODE:
677         SvPV(ST(2), length);
678         INITMESSAGE(screen);
679         CHAR2INTP(screen, text, length, line, len);
680         rval = api_sline(screen, linenumber, line, len);
681         ENDMESSAGE(screen);
683 # XS_VI_iline --
684 #       Insert the string text before the line in lineNumber.
686 # Perl Command: VI::InsertLine
687 # Usage: VI::InsertLine screenId lineNumber text
689 void
690 InsertLine(screen, linenumber, text)
691         VI screen
692         int linenumber
693         char *text
695         PREINIT:
696         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
697         int rval;
698         STRLEN length;
699         size_t len;
700         CHAR_T *line;
702         CODE:
703         SvPV(ST(2), length);
704         INITMESSAGE(screen);
705         CHAR2INTP(screen, text, length, line, len);
706         rval = api_iline(screen, linenumber, line, len);
707         ENDMESSAGE(screen);
709 # XS_VI_lline --
710 #       Return the last line in the screen.
712 # Perl Command: VI::LastLine
713 # Usage: VI::LastLine screenId
715 int 
716 LastLine(screen)
717         VI screen
719         PREINIT:
720         db_recno_t last;
721         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
722         int rval;
724         CODE:
725         INITMESSAGE(screen);
726         rval = api_lline(screen, &last);
727         ENDMESSAGE(screen);
728         RETVAL=last;
730         OUTPUT:
731         RETVAL
733 # XS_VI_getmark --
734 #       Return the mark's cursor position as a list with two elements.
735 #       {line, column}.
737 # Perl Command: VI::GetMark
738 # Usage: VI::GetMark screenId mark
740 void
741 GetMark(screen, mark)
742         VI screen
743         char mark
745         PREINIT:
746         struct _mark cursor;
747         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
748         int rval;
750         PPCODE:
751         INITMESSAGE(screen);
752         rval = api_getmark(screen, (int)mark, &cursor);
753         ENDMESSAGE(screen);
755         EXTEND(sp,2);
756         PUSHs(sv_2mortal(newSViv(cursor.lno)));
757         PUSHs(sv_2mortal(newSViv(cursor.cno)));
759 # XS_VI_setmark --
760 #       Set the mark to the line and column numbers supplied.
762 # Perl Command: VI::SetMark
763 # Usage: VI::SetMark screenId mark line column
765 void
766 SetMark(screen, mark, line, column)
767         VI screen
768         char mark
769         int line
770         int column
772         PREINIT:
773         struct _mark cursor;
774         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
775         int rval;
777         CODE:
778         INITMESSAGE(screen);
779         cursor.lno = line;
780         cursor.cno = column;
781         rval = api_setmark(screen, (int)mark, &cursor);
782         ENDMESSAGE(screen);
784 # XS_VI_getcursor --
785 #       Return the current cursor position as a list with two elements.
786 #       {line, column}.
788 # Perl Command: VI::GetCursor
789 # Usage: VI::GetCursor screenId
791 void
792 GetCursor(screen)
793         VI screen
795         PREINIT:
796         struct _mark cursor;
797         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
798         int rval;
800         PPCODE:
801         INITMESSAGE(screen);
802         rval = api_getcursor(screen, &cursor);
803         ENDMESSAGE(screen);
805         EXTEND(sp,2);
806         PUSHs(sv_2mortal(newSViv(cursor.lno)));
807         PUSHs(sv_2mortal(newSViv(cursor.cno)));
809 # XS_VI_setcursor --
810 #       Set the cursor to the line and column numbers supplied.
812 # Perl Command: VI::SetCursor
813 # Usage: VI::SetCursor screenId line column
815 void
816 SetCursor(screen, line, column)
817         VI screen
818         int line
819         int column
821         PREINIT:
822         struct _mark cursor;
823         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
824         int rval;
826         CODE:
827         INITMESSAGE(screen);
828         cursor.lno = line;
829         cursor.cno = column;
830         rval = api_setcursor(screen, &cursor);
831         ENDMESSAGE(screen);
833 # XS_VI_swscreen --
834 #       Change the current focus to screen.
836 # Perl Command: VI::SwitchScreen
837 # Usage: VI::SwitchScreen screenId screenId
839 void
840 SwitchScreen(screenFrom, screenTo)
841         VI screenFrom
842         VI screenTo
844         PREINIT:
845         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
846         int rval;
848         CODE:
849         INITMESSAGE(screenFrom);
850         rval = api_swscreen(screenFrom, screenTo);
851         ENDMESSAGE(screenFrom);
853 # XS_VI_map --
854 #       Associate a key with a perl procedure.
856 # Perl Command: VI::MapKey
857 # Usage: VI::MapKey screenId key perlproc
859 void
860 MapKey(screen, key, perlproc)
861         VI screen
862         char *key
863         SV *perlproc
865         PREINIT:
866         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
867         int rval;
868         int length;
869         char *command;
870         SV *svc;
871         SV *svn;
873         CODE:
874         INITMESSAGE(screen);
875         svc = sv_2mortal(newSVpv(":perl ", 6));
876         sv_catsv(svc, perlproc);
877         svn = sv_2mortal(newSVpv("\r", 1));
878         sv_catsv(svc, svn);
879         command = SvPV(svc, length);
880         rval = api_map(screen, key, command, length);
881         ENDMESSAGE(screen);
883 # XS_VI_unmap --
884 #       Unmap a key.
886 # Perl Command: VI::UnmapKey
887 # Usage: VI::UnmmapKey screenId key
889 void
890 UnmapKey(screen, key)
891         VI screen
892         char *key
894         PREINIT:
895         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
896         int rval;
898         CODE:
899         INITMESSAGE(screen);
900         rval = api_unmap(screen, key);
901         ENDMESSAGE(screen);
903 # XS_VI_opts_set --
904 #       Set an option.
906 # Perl Command: VI::SetOpt
907 # Usage: VI::SetOpt screenId setting
909 void
910 SetOpt(screen, setting)
911         VI screen
912         char *setting
914         PREINIT:
915         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
916         int rval;
917         SV *svc;
919         CODE:
920         INITMESSAGE(screen);
921         svc = sv_2mortal(newSVpv(":set ", 5));
922         sv_catpv(svc, setting);
923         rval = api_run_str(screen, SvPV(svc, PL_na));
924         ENDMESSAGE(screen);
926 # XS_VI_opts_get --
927 #       Return the value of an option.
928 #       
929 # Perl Command: VI::GetOpt
930 # Usage: VI::GetOpt screenId option
932 void
933 GetOpt(screen, option)
934         VI screen
935         char *option
937         PREINIT:
938         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
939         int rval;
940         char *value;
942         PPCODE:
943         INITMESSAGE(screen);
944         rval = api_opts_get(screen, option, &value, NULL);
945         ENDMESSAGE(screen);
947         EXTEND(SP,1);
948         PUSHs(sv_2mortal(newSVpv(value, 0)));
949         free(value);
951 # XS_VI_run --
952 #       Run the ex command cmd.
954 # Perl Command: VI::Run
955 # Usage: VI::Run screenId cmd
957 void
958 Run(screen, command)
959         VI screen
960         char *command;
962         PREINIT:
963         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
964         int rval;
966         CODE:
967         INITMESSAGE(screen);
968         rval = api_run_str(screen, command);
969         ENDMESSAGE(screen);
971 void 
972 DESTROY(screensv)
973         SV* screensv
975         PREINIT:
976         VI  screen;
978         CODE:
979         if (sv_isa(screensv, "VI")) {
980                 IV tmp = SvIV((SV*)SvRV(screensv));
981                 screen = (SCR *) tmp;
982         }
983         else
984                 croak("screen is not of type VI");
986         if (screen)
987         screen->perl_private = 0;
989 void
990 Warn(warning)
991         char *warning;
993         CODE:
994         sv_catpv(ERRSV,warning);
996 #define TIED(kind,package) \
997         sv_magic((SV *) (var = \
998             (##kind##V *)sv_2mortal((SV *)new##kind##V())), \
999                 sv_setref_pv(sv_newmortal(), package, \
1000                         newVIrv(newSV(0), screen)),\
1001                 'P', Nullch, 0);\
1002         RETVAL = newRV((SV *)var)
1004 SV *
1005 Opt(screen)
1006         VI screen;
1007         PREINIT:
1008         HV *var;
1009         CODE:
1010         TIED(H,"VI::OPT");
1011         OUTPUT:
1012         RETVAL
1014 SV *
1015 Map(screen)
1016         VI screen;
1017         PREINIT:
1018         HV *var;
1019         CODE:
1020         TIED(H,"VI::MAP");
1021         OUTPUT:
1022         RETVAL
1024 SV *
1025 Mark(screen)
1026         VI screen
1027         PREINIT:
1028         HV *var;
1029         CODE:
1030         TIED(H,"VI::MARK");
1031         OUTPUT:
1032         RETVAL
1034 SV *
1035 Line(screen)
1036         VI screen
1037         PREINIT:
1038         AV *var;
1039         CODE:
1040         TIED(A,"VI::LINE");
1041         OUTPUT:
1042         RETVAL
1044 SV *
1045 TagQ(screen, tag)
1046         VI screen
1047         char *tag;
1049         PREINIT:
1050         perl_tagq *ptag;
1052         PPCODE:
1053         if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1054                 goto err;
1056         ptag->sprv = newVIrv(newSV(0), screen);
1057         ptag->tqp = api_tagq_new(screen, tag);
1058         if (ptag->tqp != NULL) {
1059                 EXTEND(SP,1);
1060                 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1061         } else {
1062 err:
1063                 ST(0) = &PL_sv_undef;
1064                 return;
1065         }
1067 MODULE = VI     PACKAGE = VI::OPT
1069 void 
1070 DESTROY(screen)
1071         VI::OPT screen
1073         CODE:
1074         # typemap did all the checking
1075         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1077 void
1078 FETCH(screen, key)
1079         VI::OPT screen
1080         char *key
1082         PREINIT:
1083         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1084         int rval;
1085         char *value;
1086         int boolvalue;
1088         PPCODE:
1089         INITMESSAGE(screen);
1090         rval = api_opts_get(screen, key, &value, &boolvalue);
1091         if (!rval) {
1092                 EXTEND(SP,1);
1093                 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1094                                                    : newSViv(boolvalue)));
1095                 free(value);
1096         } else ST(0) = &PL_sv_undef;
1097         rval = 0;
1098         ENDMESSAGE(screen);
1100 void
1101 STORE(screen, key, value)
1102         VI::OPT screen
1103         char    *key
1104         SV      *value
1106         PREINIT:
1107         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1108         int rval;
1110         CODE:
1111         INITMESSAGE(screen);
1112         rval = api_opts_set(screen, key, SvPV(value, PL_na), SvIV(value), 
1113                                          SvTRUEx(value));
1114         ENDMESSAGE(screen);
1116 MODULE = VI     PACKAGE = VI::MAP
1118 void 
1119 DESTROY(screen)
1120         VI::MAP screen
1122         CODE:
1123         # typemap did all the checking
1124         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1126 void
1127 STORE(screen, key, perlproc)
1128         VI::MAP screen
1129         char *key
1130         SV *perlproc
1132         PREINIT:
1133         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1134         int rval;
1135         int length;
1136         char *command;
1137         SV *svc;
1138         SV *svn;
1140         CODE:
1141         INITMESSAGE(screen);
1142         svc = sv_2mortal(newSVpv(":perl ", 6));
1143         sv_catsv(svc, perlproc);
1144         svn = sv_2mortal(newSVpv("\r", 1));
1145         sv_catsv(svc, svn);
1146         command = SvPV(svc, length);
1147         rval = api_map(screen, key, command, length);
1148         ENDMESSAGE(screen);
1150 void
1151 DELETE(screen, key)
1152         VI::MAP screen
1153         char *key
1155         PREINIT:
1156         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1157         int rval;
1159         CODE:
1160         INITMESSAGE(screen);
1161         rval = api_unmap(screen, key);
1162         ENDMESSAGE(screen);
1164 MODULE = VI     PACKAGE = VI::MARK
1166 void 
1167 DESTROY(screen)
1168         VI::MARK screen
1170         CODE:
1171         # typemap did all the checking
1172         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1174 AV *
1175 FETCH(screen, mark)
1176         VI::MARK screen
1177         char mark
1179         PREINIT:
1180         struct _mark cursor;
1181         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1182         int rval;
1184         CODE:
1185         INITMESSAGE(screen);
1186         rval = api_getmark(screen, (int)mark, &cursor);
1187         ENDMESSAGE(screen);
1188         RETVAL = newAV();
1189         av_push(RETVAL, newSViv(cursor.lno));
1190         av_push(RETVAL, newSViv(cursor.cno));
1192         OUTPUT:
1193         RETVAL
1195 void
1196 STORE(screen, mark, pos)
1197         VI::MARK screen
1198         char mark
1199         AVREF pos
1201         PREINIT:
1202         struct _mark cursor;
1203         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1204         int rval;
1206         CODE:
1207         if (av_len(pos) < 1) 
1208             croak("cursor position needs 2 elements");
1209         INITMESSAGE(screen);
1210         cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1211         cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1212         rval = api_setmark(screen, (int)mark, &cursor);
1213         ENDMESSAGE(screen);
1215 void
1216 FIRSTKEY(screen, ...)
1217         VI::MARK screen
1219         ALIAS:
1220         NEXTKEY = 1
1221         
1222         PROTOTYPE: $;$
1224         PREINIT:
1225         int next;
1226         char key[] = {0, 0};
1228         PPCODE:
1229         if (items == 2) {
1230                 next = 1;
1231                 *key = *(char *)SvPV(ST(1),PL_na);
1232         } else next = 0;
1233         if (api_nextmark(screen, next, key) != 1) {
1234                 EXTEND(sp, 1);
1235                 PUSHs(sv_2mortal(newSVpv(key, 1)));
1236         } else ST(0) = &PL_sv_undef;
1238 MODULE = VI     PACKAGE = VI::LINE
1240 void 
1241 DESTROY(screen)
1242         VI::LINE screen
1244         CODE:
1245         # typemap did all the checking
1246         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1248 # similar to SetLine
1250 void
1251 STORE(screen, linenumber, text)
1252         VI::LINE screen
1253         int linenumber
1254         char *text
1256         PREINIT:
1257         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1258         int rval;
1259         STRLEN length;
1260         db_recno_t last;
1261         size_t len;
1262         CHAR_T *line;
1264         CODE:
1265         ++linenumber;   /* vi 1 based ; perl 0 based */
1266         SvPV(ST(2), length);
1267         INITMESSAGE(screen);
1268         rval = api_lline(screen, &last);
1269         if (!rval) {
1270             if (linenumber > last)
1271                 rval = api_extend(screen, linenumber);
1272             if (!rval)
1273                 CHAR2INTP(screen, text, length, line, len);
1274                 rval = api_sline(screen, linenumber, line, len);
1275         }
1276         ENDMESSAGE(screen);
1278 # similar to GetLine 
1280 char *
1281 FETCH(screen, linenumber)
1282         VI::LINE screen
1283         int linenumber
1285         PREINIT:
1286         size_t len;
1287         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1288         int rval;
1289         char *line;
1290         CHAR_T *p;
1292         PPCODE:
1293         ++linenumber;   /* vi 1 based ; perl 0 based */
1294         INITMESSAGE(screen);
1295         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1296         ENDMESSAGE(screen);
1298         EXTEND(sp,1);
1299         PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1301 # similar to LastLine 
1304 FETCHSIZE(screen)
1305         VI::LINE screen
1307         PREINIT:
1308         db_recno_t last;
1309         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1310         int rval;
1312         CODE:
1313         INITMESSAGE(screen);
1314         rval = api_lline(screen, &last);
1315         ENDMESSAGE(screen);
1316         RETVAL=last;
1318         OUTPUT:
1319         RETVAL
1321 void
1322 STORESIZE(screen, count)
1323         VI::LINE screen
1324         int count
1326         PREINIT:
1327         db_recno_t last;
1328         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1329         int rval;
1331         CODE:
1332         INITMESSAGE(screen);
1333         rval = api_lline(screen, &last);
1334         if (!rval) {
1335             if (count > last)
1336                 rval = api_extend(screen, count);
1337             else while(last && last > count) {
1338                 rval = api_dline(screen, last--);
1339                 if (rval) break;
1340             }
1341         }
1342         ENDMESSAGE(screen);
1344 void
1345 EXTEND(screen, count)
1346         VI::LINE screen
1347         int count
1349         CODE:
1351 void
1352 CLEAR(screen)
1353         VI::LINE screen
1355         PREINIT:
1356         db_recno_t last;
1357         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1358         int rval;
1360         CODE:
1361         INITMESSAGE(screen);
1362         rval = api_lline(screen, &last);
1363         if (!rval) {
1364             while(last) {
1365                 rval = api_dline(screen, last--);
1366                 if (rval) break;
1367             }
1368         }
1369         ENDMESSAGE(screen);
1371 void
1372 PUSH(screen, ...)
1373         VI::LINE screen;
1375         PREINIT:
1376         db_recno_t last;
1377         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1378         int rval, i, len;
1379         char *line;
1381         CODE:
1382         INITMESSAGE(screen);
1383         rval = api_lline(screen, &last);
1385         if (!rval)
1386                 for (i = 1; i < items; ++i) {
1387                         line = SvPV(ST(i), len);
1388                         if ((rval = api_aline(screen, last++, line, len)))
1389                                 break;
1390                 }
1391         ENDMESSAGE(screen);
1393 SV *
1394 POP(screen)
1395         VI::LINE screen;
1397         PREINIT:
1398         db_recno_t last;
1399         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1400         int rval, i, len;
1401         CHAR_T *line;
1403         PPCODE:
1404         INITMESSAGE(screen);
1405         rval = api_lline(screen, &last);
1406         if (rval || last < 1)
1407                 ST(0) = &PL_sv_undef;
1408         else {
1409                 rval = api_gline(screen, last, &line, &len) ||
1410                        api_dline(screen, last);
1411                 EXTEND(sp,1);
1412                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1413         }
1414         ENDMESSAGE(screen);
1416 SV *
1417 SHIFT(screen)
1418         VI::LINE screen;
1420         PREINIT:
1421         db_recno_t last;
1422         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1423         int rval, i, len;
1424         CHAR_T *line;
1426         PPCODE:
1427         INITMESSAGE(screen);
1428         rval = api_lline(screen, &last);
1429         if (rval || last < 1)
1430                 ST(0) = &PL_sv_undef;
1431         else {
1432                 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1433                        api_dline(screen, (db_recno_t)1);
1434                 EXTEND(sp,1);
1435                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1436         }
1437         ENDMESSAGE(screen);
1439 void
1440 UNSHIFT(screen, ...)
1441         VI::LINE screen;
1443         PREINIT:
1444         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1445         int rval, i, len;
1446         char *np;
1447         size_t nlen;
1448         CHAR_T *line;
1450         CODE:
1451         INITMESSAGE(screen);
1452         while (--items != 0) {
1453                 np = SvPV(ST(items), nlen);
1454                 CHAR2INTP(screen, np, nlen, line, len);
1455                 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1456                         break;
1457         }
1458         ENDMESSAGE(screen);
1460 void
1461 SPLICE(screen, ...)
1462         VI::LINE screen;
1464         PREINIT:
1465         db_recno_t last, db_offset;
1466         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1467         int rval, length, common, len, i, offset;
1468         CHAR_T *line;
1469         char *np;
1470         size_t nlen;
1472         PPCODE:
1473         INITMESSAGE(screen);
1474         rval = api_lline(screen, &last);
1475         offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1476         if (offset < 0) offset += last;
1477         if (offset < 0) {
1478             ENDMESSAGE(screen);
1479             croak("Invalid offset");
1480         }
1481         length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1482         if (length > last - offset)
1483                 length = last - offset;
1484         db_offset = offset + 1; /* 1 based */
1485         EXTEND(sp,length);
1486         for (common = MIN(length, items - 3), i = 3; common > 0; 
1487             --common, ++db_offset, --length, ++i) {
1488                 rval |= api_gline(screen, db_offset, &line, &len);
1489                 INT2CHAR(screen, line, len, np, nlen);
1490                 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1491                 np = SvPV(ST(i), nlen);
1492                 CHAR2INTP(screen, np, nlen, line, len);
1493                 rval |= api_sline(screen, db_offset, line, len);
1494         }
1495         for (; length; --length) {
1496                 rval |= api_gline(screen, db_offset, &line, &len);
1497                 INT2CHAR(screen, line, len, np, nlen);
1498                 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1499                 rval |= api_dline(screen, db_offset);
1500         }
1501         for (; i < items; ++i) {
1502                 np = SvPV(ST(i), len);
1503                 CHAR2INTP(screen, np, len, line, nlen);
1504                 rval |= api_iline(screen, db_offset, line, nlen);
1505         }
1506         ENDMESSAGE(screen);
1508 MODULE = VI     PACKAGE = VI::TAGQ
1510 void
1511 Add(tagq, filename, search, msg)
1512         VI::TAGQ    tagq;
1513         char       *filename;
1514         char       *search;
1515         char       *msg;
1517         PREINIT:
1518         SCR *sp;
1520         CODE:
1521         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1522         if (!sp)
1523                 croak("screen no longer exists");
1524         api_tagq_add(sp, tagq->tqp, filename, search, msg);
1526 void
1527 Push(tagq)
1528         VI::TAGQ    tagq;
1530         PREINIT:
1531         SCR *sp;
1533         CODE:
1534         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1535         if (!sp)
1536                 croak("screen no longer exists");
1537         api_tagq_push(sp, &tagq->tqp);
1539 void
1540 DESTROY(tagq)
1541         # Can already be invalidated by push 
1542         VI::TAGQ2    tagq; 
1544         PREINIT:
1545         SCR *sp;
1547         CODE:
1548         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1549         if (sp)
1550                 api_tagq_free(sp, tagq->tqp);
1551         SvREFCNT_dec(tagq->sprv);
1552         free(tagq);