add EXISTS for marks
[nvi.git] / perl_api / perl.xs
blob5e903813b8a2160bfea1d55606c09a40e97d1f29
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-2001
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.45 2001/07/29 19:51:21 skimo Exp $ (Berkeley) $Date: 2001/07/29 19:51:21 $";
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 typedef struct _perl_data {
67         PerlInterpreter*        interp;
68         SV      *svcurscr, *svstart, *svstop, *svid;
69         CONVWIN  cw;
70         char    *errmsg;
71 } perl_data_t;
73 #define PERLP(sp)   ((perl_data_t *)sp->wp->perl_private)
75 #define CHAR2INTP(sp,n,nlen,w,wlen)                                         \
76     CHAR2INT5(sp,((perl_data_t *)sp->wp->perl_private)->cw,n,nlen,w,wlen)
79  * INITMESSAGE --
80  *      Macros to point messages at the Perl message handler.
81  */
82 #define INITMESSAGE(sp)                                                 \
83         scr_msg = sp->wp->scr_msg;                                      \
84         sp->wp->scr_msg = msghandler;
85 #define ENDMESSAGE(sp)                                                  \
86         sp->wp->scr_msg = scr_msg;                                      \
87         if (rval) croak(PERLP(sp)->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         size_t 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         memset(&pp->cw, 0, sizeof(pp->cw));
195 #ifdef USE_ITHREADS
196         pp->interp = perl_clone(gp->perl_interp, 0);
197         if (1) { /* hack for bug fixed in perl-current (5.6.1) */
198             dTHXa(pp->interp);
199             if (PL_scopestack_ix == 0) {
200                 ENTER;
201             }
202         }
203 #else
204         pp->interp = gp->perl_interp;
205 #endif
206         pp->errmsg = 0;
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         size_t 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, 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         size_t 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, 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         char    *errmsg;
464         errmsg = PERLP(sp)->errmsg;
466         /* Replace the trailing <newline> with an EOS. */
467         /* Let's do that later instead */
468         if (errmsg) free (errmsg);
469         errmsg = malloc(len + 1);
470         memcpy(errmsg, msg, len);
471         errmsg[len] = '\0';
472         PERLP(sp)->errmsg = errmsg;
476 typedef SCR *   VI;
477 typedef SCR *   VI__OPT;
478 typedef SCR *   VI__MAP;
479 typedef SCR *   VI__MARK;
480 typedef SCR *   VI__LINE;
481 typedef AV *    AVREF;
483 typedef struct {
484     SV      *sprv;
485     TAGQ    *tqp;
486 } perl_tagq;
488 typedef perl_tagq *  VI__TAGQ;
489 typedef perl_tagq *  VI__TAGQ2;
491 MODULE = VI     PACKAGE = VI
493 # msg --
494 #       Set the message line to text.
496 # Perl Command: VI::Msg
497 # Usage: VI::Msg screenId text
499 void
500 Msg(screen, text)
501         VI          screen
502         char *      text
504         ALIAS:
505         PRINT = 1
507         CODE:
508         api_imessage(screen, text);
510 # XS_VI_escreen --
511 #       End a screen.
513 # Perl Command: VI::EndScreen
514 # Usage: VI::EndScreen screenId
516 void
517 EndScreen(screen)
518         VI      screen
520         PREINIT:
521         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
522         int rval;
524         CODE:
525         INITMESSAGE(screen);
526         rval = api_escreen(screen);
527         ENDMESSAGE(screen);
529 # XS_VI_iscreen --
530 #       Create a new screen.  If a filename is specified then the screen
531 #       is opened with that file.
533 # Perl Command: VI::NewScreen
534 # Usage: VI::NewScreen screenId [file]
537 Edit(screen, ...)
538         VI screen
540         ALIAS:
541         NewScreen = 1
543         PROTOTYPE: $;$
544         PREINIT:
545         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
546         int rval;
547         char *file;
548         SCR *nsp;
550         CODE:
551         file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
552         INITMESSAGE(screen);
553         rval = api_edit(screen, file, &nsp, ix);
554         ENDMESSAGE(screen);
555         
556         RETVAL = ix ? nsp : screen;
558         OUTPUT:
559         RETVAL
561 # XS_VI_fscreen --
562 #       Return the screen id associated with file name.
564 # Perl Command: VI::FindScreen
565 # Usage: VI::FindScreen file
568 FindScreen(file)
569         char *file
571         PREINIT:
572         SCR *fsp;
573         CODE:
574         RETVAL = api_fscreen(0, file);
576         OUTPUT:
577         RETVAL
579 # XS_VI_GetFileName --
580 #       Return the file name of the screen
582 # Perl Command: VI::GetFileName
583 # Usage: VI::GetFileName screenId
585 char *
586 GetFileName(screen)
587         VI screen;
589         PPCODE:
590         EXTEND(sp,1);
591         PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
593 # XS_VI_aline --
594 #       -- Append the string text after the line in lineNumber.
596 # Perl Command: VI::AppendLine
597 # Usage: VI::AppendLine screenId lineNumber text
599 void
600 AppendLine(screen, linenumber, text)
601         VI screen
602         int linenumber
603         char *text
605         PREINIT:
606         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
607         int rval;
608         size_t length;
610         CODE:
611         SvPV(ST(2), length);
612         INITMESSAGE(screen);
613         rval = api_aline(screen, linenumber, text, length);
614         ENDMESSAGE(screen);
616 # XS_VI_dline --
617 #       Delete lineNum.
619 # Perl Command: VI::DelLine
620 # Usage: VI::DelLine screenId lineNum
622 void 
623 DelLine(screen, linenumber)
624         VI screen
625         int linenumber
627         PREINIT:
628         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
629         int rval;
631         CODE:
632         INITMESSAGE(screen);
633         rval = api_dline(screen, (db_recno_t)linenumber);
634         ENDMESSAGE(screen);
636 # XS_VI_gline --
637 #       Return lineNumber.
639 # Perl Command: VI::GetLine
640 # Usage: VI::GetLine screenId lineNumber
642 char *
643 GetLine(screen, linenumber)
644         VI screen
645         int linenumber
647         PREINIT:
648         size_t len;
649         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
650         int rval;
651         char *line;
652         CHAR_T *p;
654         PPCODE:
655         INITMESSAGE(screen);
656         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
657         ENDMESSAGE(screen);
659         EXTEND(sp,1);
660         PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
662 # XS_VI_sline --
663 #       Set lineNumber to the text supplied.
665 # Perl Command: VI::SetLine
666 # Usage: VI::SetLine screenId lineNumber text
668 void
669 SetLine(screen, linenumber, text)
670         VI screen
671         int linenumber
672         char *text
674         PREINIT:
675         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
676         int rval;
677         size_t length;
678         size_t len;
679         CHAR_T *line;
681         CODE:
682         SvPV(ST(2), length);
683         INITMESSAGE(screen);
684         CHAR2INTP(screen, text, length, line, len);
685         rval = api_sline(screen, linenumber, line, len);
686         ENDMESSAGE(screen);
688 # XS_VI_iline --
689 #       Insert the string text before the line in lineNumber.
691 # Perl Command: VI::InsertLine
692 # Usage: VI::InsertLine screenId lineNumber text
694 void
695 InsertLine(screen, linenumber, text)
696         VI screen
697         int linenumber
698         char *text
700         PREINIT:
701         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
702         int rval;
703         size_t length;
704         size_t len;
705         CHAR_T *line;
707         CODE:
708         SvPV(ST(2), length);
709         INITMESSAGE(screen);
710         CHAR2INTP(screen, text, length, line, len);
711         rval = api_iline(screen, linenumber, line, len);
712         ENDMESSAGE(screen);
714 # XS_VI_lline --
715 #       Return the last line in the screen.
717 # Perl Command: VI::LastLine
718 # Usage: VI::LastLine screenId
720 int 
721 LastLine(screen)
722         VI screen
724         PREINIT:
725         db_recno_t last;
726         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
727         int rval;
729         CODE:
730         INITMESSAGE(screen);
731         rval = api_lline(screen, &last);
732         ENDMESSAGE(screen);
733         RETVAL=last;
735         OUTPUT:
736         RETVAL
738 # XS_VI_getmark --
739 #       Return the mark's cursor position as a list with two elements.
740 #       {line, column}.
742 # Perl Command: VI::GetMark
743 # Usage: VI::GetMark screenId mark
745 void
746 GetMark(screen, mark)
747         VI screen
748         char mark
750         PREINIT:
751         struct _mark cursor;
752         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
753         int rval;
755         PPCODE:
756         INITMESSAGE(screen);
757         rval = api_getmark(screen, (int)mark, &cursor);
758         ENDMESSAGE(screen);
760         EXTEND(sp,2);
761         PUSHs(sv_2mortal(newSViv(cursor.lno)));
762         PUSHs(sv_2mortal(newSViv(cursor.cno)));
764 # XS_VI_setmark --
765 #       Set the mark to the line and column numbers supplied.
767 # Perl Command: VI::SetMark
768 # Usage: VI::SetMark screenId mark line column
770 void
771 SetMark(screen, mark, line, column)
772         VI screen
773         char mark
774         int line
775         int column
777         PREINIT:
778         struct _mark cursor;
779         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
780         int rval;
782         CODE:
783         INITMESSAGE(screen);
784         cursor.lno = line;
785         cursor.cno = column;
786         rval = api_setmark(screen, (int)mark, &cursor);
787         ENDMESSAGE(screen);
789 # XS_VI_getcursor --
790 #       Return the current cursor position as a list with two elements.
791 #       {line, column}.
793 # Perl Command: VI::GetCursor
794 # Usage: VI::GetCursor screenId
796 void
797 GetCursor(screen)
798         VI screen
800         PREINIT:
801         struct _mark cursor;
802         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
803         int rval;
805         PPCODE:
806         INITMESSAGE(screen);
807         rval = api_getcursor(screen, &cursor);
808         ENDMESSAGE(screen);
810         EXTEND(sp,2);
811         PUSHs(sv_2mortal(newSViv(cursor.lno)));
812         PUSHs(sv_2mortal(newSViv(cursor.cno)));
814 # XS_VI_setcursor --
815 #       Set the cursor to the line and column numbers supplied.
817 # Perl Command: VI::SetCursor
818 # Usage: VI::SetCursor screenId line column
820 void
821 SetCursor(screen, line, column)
822         VI screen
823         int line
824         int column
826         PREINIT:
827         struct _mark cursor;
828         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
829         int rval;
831         CODE:
832         INITMESSAGE(screen);
833         cursor.lno = line;
834         cursor.cno = column;
835         rval = api_setcursor(screen, &cursor);
836         ENDMESSAGE(screen);
838 # XS_VI_swscreen --
839 #       Change the current focus to screen.
841 # Perl Command: VI::SwitchScreen
842 # Usage: VI::SwitchScreen screenId screenId
844 void
845 SwitchScreen(screenFrom, screenTo)
846         VI screenFrom
847         VI screenTo
849         PREINIT:
850         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
851         int rval;
853         CODE:
854         INITMESSAGE(screenFrom);
855         rval = api_swscreen(screenFrom, screenTo);
856         ENDMESSAGE(screenFrom);
858 # XS_VI_map --
859 #       Associate a key with a perl procedure.
861 # Perl Command: VI::MapKey
862 # Usage: VI::MapKey screenId key perlproc
864 void
865 MapKey(screen, key, commandsv)
866         VI screen
867         char *key
868         SV *commandsv
870         PREINIT:
871         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
872         int rval;
873         int length;
874         char *command;
876         CODE:
877         INITMESSAGE(screen);
878         command = SvPV(commandsv, length);
879         rval = api_map(screen, key, command, length);
880         ENDMESSAGE(screen);
882 # XS_VI_unmap --
883 #       Unmap a key.
885 # Perl Command: VI::UnmapKey
886 # Usage: VI::UnmmapKey screenId key
888 void
889 UnmapKey(screen, key)
890         VI screen
891         char *key
893         PREINIT:
894         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
895         int rval;
897         CODE:
898         INITMESSAGE(screen);
899         rval = api_unmap(screen, key);
900         ENDMESSAGE(screen);
902 # XS_VI_opts_set --
903 #       Set an option.
905 # Perl Command: VI::SetOpt
906 # Usage: VI::SetOpt screenId setting
908 void
909 SetOpt(screen, setting)
910         VI screen
911         char *setting
913         PREINIT:
914         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
915         int rval;
916         SV *svc;
918         CODE:
919         INITMESSAGE(screen);
920         svc = sv_2mortal(newSVpv(":set ", 5));
921         sv_catpv(svc, setting);
922         rval = api_run_str(screen, SvPV(svc, PL_na));
923         ENDMESSAGE(screen);
925 # XS_VI_opts_get --
926 #       Return the value of an option.
927 #       
928 # Perl Command: VI::GetOpt
929 # Usage: VI::GetOpt screenId option
931 void
932 GetOpt(screen, option)
933         VI screen
934         char *option
936         PREINIT:
937         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
938         int rval;
939         char *value;
940         CHAR_T *wp;
941         size_t wlen;
943         PPCODE:
944         INITMESSAGE(screen);
945         CHAR2INTP(screen, option, strlen(option)+1, wp, wlen);
946         rval = api_opts_get(screen, wp, &value, NULL);
947         ENDMESSAGE(screen);
949         EXTEND(SP,1);
950         PUSHs(sv_2mortal(newSVpv(value, 0)));
951         free(value);
953 # XS_VI_run --
954 #       Run the ex command cmd.
956 # Perl Command: VI::Run
957 # Usage: VI::Run screenId cmd
959 void
960 Run(screen, command)
961         VI screen
962         char *command;
964         PREINIT:
965         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
966         int rval;
968         CODE:
969         INITMESSAGE(screen);
970         rval = api_run_str(screen, command);
971         ENDMESSAGE(screen);
973 void 
974 DESTROY(screensv)
975         SV* screensv
977         PREINIT:
978         VI  screen;
980         CODE:
981         if (sv_isa(screensv, "VI")) {
982                 IV tmp = SvIV((SV*)SvRV(screensv));
983                 screen = (SCR *) tmp;
984         }
985         else
986                 croak("screen is not of type VI");
988         if (screen)
989         screen->perl_private = 0;
991 void
992 Warn(warning)
993         char *warning;
995         CODE:
996         sv_catpv(ERRSV,warning);
998 #define TIED(kind,package) \
999         sv_magic((SV *) (var = \
1000             (kind##V *)sv_2mortal((SV *)new##kind##V())), \
1001                 sv_setref_pv(sv_newmortal(), package, \
1002                         newVIrv(newSV(0), screen)),\
1003                 'P', Nullch, 0);\
1004         RETVAL = newRV((SV *)var)
1006 SV *
1007 Opt(screen)
1008         VI screen;
1009         PREINIT:
1010         HV *var;
1011         CODE:
1012         TIED(H,"VI::OPT");
1013         OUTPUT:
1014         RETVAL
1016 SV *
1017 Map(screen)
1018         VI screen;
1019         PREINIT:
1020         HV *var;
1021         CODE:
1022         TIED(H,"VI::MAP");
1023         OUTPUT:
1024         RETVAL
1026 SV *
1027 Mark(screen)
1028         VI screen
1029         PREINIT:
1030         HV *var;
1031         CODE:
1032         TIED(H,"VI::MARK");
1033         OUTPUT:
1034         RETVAL
1036 SV *
1037 Line(screen)
1038         VI screen
1039         PREINIT:
1040         AV *var;
1041         CODE:
1042         TIED(A,"VI::LINE");
1043         OUTPUT:
1044         RETVAL
1046 SV *
1047 TagQ(screen, tag)
1048         VI screen
1049         char *tag;
1051         PREINIT:
1052         perl_tagq *ptag;
1054         PPCODE:
1055         if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1056                 goto err;
1058         ptag->sprv = newVIrv(newSV(0), screen);
1059         ptag->tqp = api_tagq_new(screen, tag);
1060         if (ptag->tqp != NULL) {
1061                 EXTEND(SP,1);
1062                 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1063         } else {
1064 err:
1065                 ST(0) = &PL_sv_undef;
1066                 return;
1067         }
1069 MODULE = VI     PACKAGE = VI::OPT
1071 void 
1072 DESTROY(screen)
1073         VI::OPT screen
1075         CODE:
1076         # typemap did all the checking
1077         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1079 void
1080 FETCH(screen, key)
1081         VI::OPT screen
1082         char *key
1084         PREINIT:
1085         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1086         int rval;
1087         char *value;
1088         int boolvalue;
1089         CHAR_T *wp;
1090         size_t wlen;
1092         PPCODE:
1093         INITMESSAGE(screen);
1094         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1095         rval = api_opts_get(screen, wp, &value, &boolvalue);
1096         if (!rval) {
1097                 EXTEND(SP,1);
1098                 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1099                                                    : newSViv(boolvalue)));
1100                 free(value);
1101         } else ST(0) = &PL_sv_undef;
1102         rval = 0;
1103         ENDMESSAGE(screen);
1105 void
1106 STORE(screen, key, value)
1107         VI::OPT screen
1108         char    *key
1109         SV      *value
1111         PREINIT:
1112         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1113         int rval;
1114         CHAR_T *wp;
1115         size_t wlen;
1117         CODE:
1118         INITMESSAGE(screen);
1119         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1120         rval = api_opts_set(screen, wp, SvPV(value, PL_na), SvIV(value), 
1121                                          SvTRUEx(value));
1122         ENDMESSAGE(screen);
1124 MODULE = VI     PACKAGE = VI::MAP
1126 void 
1127 DESTROY(screen)
1128         VI::MAP screen
1130         CODE:
1131         # typemap did all the checking
1132         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1134 void
1135 STORE(screen, key, commandsv)
1136         VI::MAP screen
1137         char *key
1138         SV *commandsv
1140         PREINIT:
1141         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1142         int rval;
1143         int length;
1144         char *command;
1146         CODE:
1147         INITMESSAGE(screen);
1148         command = SvPV(commandsv, length);
1149         rval = api_map(screen, key, command, length);
1150         ENDMESSAGE(screen);
1152 void
1153 DELETE(screen, key)
1154         VI::MAP screen
1155         char *key
1157         PREINIT:
1158         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1159         int rval;
1161         CODE:
1162         INITMESSAGE(screen);
1163         rval = api_unmap(screen, key);
1164         ENDMESSAGE(screen);
1166 MODULE = VI     PACKAGE = VI::MARK
1168 void 
1169 DESTROY(screen)
1170         VI::MARK screen
1172         CODE:
1173         # typemap did all the checking
1174         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1177 EXISTS(screen, mark)
1178         VI::MARK screen
1179         char mark
1181         PREINIT:
1182         struct _mark cursor;
1183         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1184         int rval = 0; /* never croak */
1185         int missing;
1187         CODE:
1188         INITMESSAGE(screen);
1189         missing = api_getmark(screen, (int)mark, &cursor);
1190         ENDMESSAGE(screen);
1191         RETVAL = !missing;
1193         OUTPUT:
1194         RETVAL
1196 AV *
1197 FETCH(screen, mark)
1198         VI::MARK screen
1199         char mark
1201         PREINIT:
1202         struct _mark cursor;
1203         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1204         int rval;
1206         CODE:
1207         INITMESSAGE(screen);
1208         rval = api_getmark(screen, (int)mark, &cursor);
1209         ENDMESSAGE(screen);
1210         RETVAL = newAV();
1211         av_push(RETVAL, newSViv(cursor.lno));
1212         av_push(RETVAL, newSViv(cursor.cno));
1214         OUTPUT:
1215         RETVAL
1217 void
1218 STORE(screen, mark, pos)
1219         VI::MARK screen
1220         char mark
1221         AVREF pos
1223         PREINIT:
1224         struct _mark cursor;
1225         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1226         int rval;
1228         CODE:
1229         if (av_len(pos) < 1) 
1230             croak("cursor position needs 2 elements");
1231         INITMESSAGE(screen);
1232         cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1233         cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1234         rval = api_setmark(screen, (int)mark, &cursor);
1235         ENDMESSAGE(screen);
1237 void
1238 FIRSTKEY(screen, ...)
1239         VI::MARK screen
1241         ALIAS:
1242         NEXTKEY = 1
1243         
1244         PROTOTYPE: $;$
1246         PREINIT:
1247         int next;
1248         char key[] = {0, 0};
1250         PPCODE:
1251         if (items == 2) {
1252                 next = 1;
1253                 *key = *(char *)SvPV(ST(1),PL_na);
1254         } else next = 0;
1255         if (api_nextmark(screen, next, key) != 1) {
1256                 EXTEND(sp, 1);
1257                 PUSHs(sv_2mortal(newSVpv(key, 1)));
1258         } else ST(0) = &PL_sv_undef;
1260 MODULE = VI     PACKAGE = VI::LINE
1262 void 
1263 DESTROY(screen)
1264         VI::LINE screen
1266         CODE:
1267         # typemap did all the checking
1268         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1270 # similar to SetLine
1272 void
1273 STORE(screen, linenumber, text)
1274         VI::LINE screen
1275         int linenumber
1276         char *text
1278         PREINIT:
1279         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1280         int rval;
1281         size_t length;
1282         db_recno_t last;
1283         size_t len;
1284         CHAR_T *line;
1286         CODE:
1287         ++linenumber;   /* vi 1 based ; perl 0 based */
1288         SvPV(ST(2), length);
1289         INITMESSAGE(screen);
1290         rval = api_lline(screen, &last);
1291         if (!rval) {
1292             if (linenumber > last)
1293                 rval = api_extend(screen, linenumber);
1294             if (!rval)
1295                 CHAR2INTP(screen, text, length, line, len);
1296                 rval = api_sline(screen, linenumber, line, len);
1297         }
1298         ENDMESSAGE(screen);
1300 # similar to GetLine 
1302 char *
1303 FETCH(screen, linenumber)
1304         VI::LINE screen
1305         int linenumber
1307         PREINIT:
1308         size_t len;
1309         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1310         int rval;
1311         char *line;
1312         CHAR_T *p;
1314         PPCODE:
1315         ++linenumber;   /* vi 1 based ; perl 0 based */
1316         INITMESSAGE(screen);
1317         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1318         ENDMESSAGE(screen);
1320         EXTEND(sp,1);
1321         PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1323 # similar to LastLine 
1326 FETCHSIZE(screen)
1327         VI::LINE screen
1329         PREINIT:
1330         db_recno_t last;
1331         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1332         int rval;
1334         CODE:
1335         INITMESSAGE(screen);
1336         rval = api_lline(screen, &last);
1337         ENDMESSAGE(screen);
1338         RETVAL=last;
1340         OUTPUT:
1341         RETVAL
1343 void
1344 STORESIZE(screen, count)
1345         VI::LINE screen
1346         int count
1348         PREINIT:
1349         db_recno_t last;
1350         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1351         int rval;
1353         CODE:
1354         INITMESSAGE(screen);
1355         rval = api_lline(screen, &last);
1356         if (!rval) {
1357             if (count > last)
1358                 rval = api_extend(screen, count);
1359             else while(last && last > count) {
1360                 rval = api_dline(screen, last--);
1361                 if (rval) break;
1362             }
1363         }
1364         ENDMESSAGE(screen);
1366 void
1367 EXTEND(screen, count)
1368         VI::LINE screen
1369         int count
1371         CODE:
1373 void
1374 CLEAR(screen)
1375         VI::LINE screen
1377         PREINIT:
1378         db_recno_t last;
1379         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1380         int rval;
1382         CODE:
1383         INITMESSAGE(screen);
1384         rval = api_lline(screen, &last);
1385         if (!rval) {
1386             while(last) {
1387                 rval = api_dline(screen, last--);
1388                 if (rval) break;
1389             }
1390         }
1391         ENDMESSAGE(screen);
1393 void
1394 PUSH(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 *line;
1403         CODE:
1404         INITMESSAGE(screen);
1405         rval = api_lline(screen, &last);
1407         if (!rval)
1408                 for (i = 1; i < items; ++i) {
1409                         line = SvPV(ST(i), len);
1410                         if ((rval = api_aline(screen, last++, line, len)))
1411                                 break;
1412                 }
1413         ENDMESSAGE(screen);
1415 SV *
1416 POP(screen)
1417         VI::LINE screen;
1419         PREINIT:
1420         db_recno_t last;
1421         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1422         int rval, i, len;
1423         CHAR_T *line;
1425         PPCODE:
1426         INITMESSAGE(screen);
1427         rval = api_lline(screen, &last);
1428         if (rval || last < 1)
1429                 ST(0) = &PL_sv_undef;
1430         else {
1431                 rval = api_gline(screen, last, &line, &len) ||
1432                        api_dline(screen, last);
1433                 EXTEND(sp,1);
1434                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1435         }
1436         ENDMESSAGE(screen);
1438 SV *
1439 SHIFT(screen)
1440         VI::LINE screen;
1442         PREINIT:
1443         db_recno_t last;
1444         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1445         int rval, i, len;
1446         CHAR_T *line;
1448         PPCODE:
1449         INITMESSAGE(screen);
1450         rval = api_lline(screen, &last);
1451         if (rval || last < 1)
1452                 ST(0) = &PL_sv_undef;
1453         else {
1454                 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1455                        api_dline(screen, (db_recno_t)1);
1456                 EXTEND(sp,1);
1457                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1458         }
1459         ENDMESSAGE(screen);
1461 void
1462 UNSHIFT(screen, ...)
1463         VI::LINE screen;
1465         PREINIT:
1466         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1467         int rval, i, len;
1468         char *np;
1469         size_t nlen;
1470         CHAR_T *line;
1472         CODE:
1473         INITMESSAGE(screen);
1474         while (--items != 0) {
1475                 np = SvPV(ST(items), nlen);
1476                 CHAR2INTP(screen, np, nlen, line, len);
1477                 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1478                         break;
1479         }
1480         ENDMESSAGE(screen);
1482 void
1483 SPLICE(screen, ...)
1484         VI::LINE screen;
1486         PREINIT:
1487         db_recno_t last, db_offset;
1488         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1489         int rval, length, common, len, i, offset;
1490         CHAR_T *line;
1491         char *np;
1492         size_t nlen;
1494         PPCODE:
1495         INITMESSAGE(screen);
1496         rval = api_lline(screen, &last);
1497         offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1498         if (offset < 0) offset += last;
1499         if (offset < 0) {
1500             ENDMESSAGE(screen);
1501             croak("Invalid offset");
1502         }
1503         length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1504         if (length > last - offset)
1505                 length = last - offset;
1506         db_offset = offset + 1; /* 1 based */
1507         EXTEND(sp,length);
1508         for (common = MIN(length, items - 3), i = 3; common > 0; 
1509             --common, ++db_offset, --length, ++i) {
1510                 rval |= api_gline(screen, db_offset, &line, &len);
1511                 INT2CHAR(screen, line, len, np, nlen);
1512                 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1513                 np = SvPV(ST(i), nlen);
1514                 CHAR2INTP(screen, np, nlen, line, len);
1515                 rval |= api_sline(screen, db_offset, line, len);
1516         }
1517         for (; length; --length) {
1518                 rval |= api_gline(screen, db_offset, &line, &len);
1519                 INT2CHAR(screen, line, len, np, nlen);
1520                 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1521                 rval |= api_dline(screen, db_offset);
1522         }
1523         for (; i < items; ++i) {
1524                 np = SvPV(ST(i), len);
1525                 CHAR2INTP(screen, np, len, line, nlen);
1526                 rval |= api_iline(screen, db_offset, line, nlen);
1527         }
1528         ENDMESSAGE(screen);
1530 MODULE = VI     PACKAGE = VI::TAGQ
1532 void
1533 Add(tagq, filename, search, msg)
1534         VI::TAGQ    tagq;
1535         char       *filename;
1536         char       *search;
1537         char       *msg;
1539         PREINIT:
1540         SCR *sp;
1542         CODE:
1543         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1544         if (!sp)
1545                 croak("screen no longer exists");
1546         api_tagq_add(sp, tagq->tqp, filename, search, msg);
1548 void
1549 Push(tagq)
1550         VI::TAGQ    tagq;
1552         PREINIT:
1553         SCR *sp;
1555         CODE:
1556         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1557         if (!sp)
1558                 croak("screen no longer exists");
1559         api_tagq_push(sp, &tagq->tqp);
1561 void
1562 DESTROY(tagq)
1563         # Can already be invalidated by push 
1564         VI::TAGQ2    tagq; 
1566         PREINIT:
1567         SCR *sp;
1569         CODE:
1570         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1571         if (sp)
1572                 api_tagq_free(sp, tagq->tqp);
1573         SvREFCNT_dec(tagq->sprv);
1574         free(tagq);