missing pieces in previous patch
[nvi.git] / perl_api / perl.xs
blobd3452025ec59abfbb8a070977f96f7c188590fec
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.39 2001/06/09 18:26:30 skimo Exp $ (Berkeley) $Date: 2001/06/09 18:26:30 $";
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         CONVWIN  cw;
72 } perl_data_t;
74 #define CHAR2INTP(sp,n,nlen,w,wlen)                                         \
75     CHAR2INTB(sp,n,nlen,w,wlen,((perl_data_t *)sp->wp->perl_private)->cw)
78  * INITMESSAGE --
79  *      Macros to point messages at the Perl message handler.
80  */
81 #define INITMESSAGE(sp)                                                 \
82         scr_msg = sp->gp->scr_msg;                                      \
83         sp->gp->scr_msg = msghandler;
84 #define ENDMESSAGE(sp)                                                  \
85         sp->gp->scr_msg = scr_msg;                                      \
86         if (rval) croak(errmsg);
88 void xs_init __P((pTHXo));
91  * perl_end --
92  *      Clean up perl interpreter
93  *
94  * PUBLIC: int perl_end __P((GS *));
95  */
96 int
97 perl_end(gp)
98         GS *gp;
100         /*
101          * Call perl_run and perl_destuct to call END blocks and DESTROY
102          * methods.
103          */
104         if (gp->perl_interp) {
105                 perl_run(gp->perl_interp);
106                 perl_destruct(gp->perl_interp);
107 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
108                 perl_free(gp->perl_interp);
109 #endif
110                 /* XXX rather make sure only one thread calls perl_end */
111                 gp->perl_interp = 0;
112         }
116  * perl_eval
117  *      Evaluate a string
118  *      We don't use mortal SVs because no one will clean up after us
119  */
120 static void 
121 perl_eval(string)
122         char *string;
124         dTHXs
126         SV* sv = newSVpv(string, 0);
128         /* G_KEEPERR to catch syntax error; better way ? */
129         sv_setpv(ERRSV,"");
130         perl_eval_sv(sv, G_DISCARD | G_NOARGS | G_KEEPERR);
131         SvREFCNT_dec(sv);
135  * perl_init --
136  *      Create the perl commands used by nvi.
138  * PUBLIC: int perl_init __P((SCR *));
139  */
141 perl_init(scrp)
142         SCR *scrp;
144         AV * av;
145         GS *gp;
146         WIN *wp;
147         char *bootargs[] = { "VI", NULL };
148 #ifndef USE_SFIO
149         SV *svcurscr;
150 #endif
151         perl_data_t *pp;
153         static char *args[] = { "", "-e", "" };
154         size_t length;
155         char *file = __FILE__;
157         gp = scrp->gp;
158         wp = scrp->wp;
160         if (gp->perl_interp == NULL) {
161         gp->perl_interp = perl_alloc();
162         perl_construct(gp->perl_interp);
163         if (perl_parse(gp->perl_interp, xs_init, 3, args, 0)) {
164                 perl_destruct(gp->perl_interp);
165                 perl_free(gp->perl_interp);
166                 gp->perl_interp = NULL;
167                 return 1;
168         }
169         {
170         dTHXs
172         perl_call_argv("VI::bootstrap", G_DISCARD, bootargs);
173         perl_eval("$SIG{__WARN__}='VI::Warn'");
175         av_unshift(av = GvAVn(PL_incgv), 1);
176         av_store(av, 0, newSVpv(_PATH_PERLSCRIPTS,
177                                 sizeof(_PATH_PERLSCRIPTS)-1));
179 #ifdef USE_SFIO
180         sfdisc(PerlIO_stdout(), sfdcnewnvi(scrp));
181         sfdisc(PerlIO_stderr(), sfdcnewnvi(scrp));
182 #else
183         svcurscr = perl_get_sv("curscr", TRUE);
184         sv_magic((SV *)gv_fetchpv("STDOUT",TRUE, SVt_PVIO), svcurscr,
185                         'q', Nullch, 0);
186         sv_magic((SV *)gv_fetchpv("STDERR",TRUE, SVt_PVIO), svcurscr,
187                         'q', Nullch, 0);
188 #endif /* USE_SFIO */
189         }
190         }
191         MALLOC(scrp, pp, perl_data_t *, sizeof(perl_data_t));
192         wp->perl_private = pp;
193         memset(&pp->cw, 0, sizeof(pp->cw));
194 #ifdef USE_ITHREADS
195         pp->interp = perl_clone(gp->perl_interp, 0);
196         if (1) { /* hack for bug fixed in perl-current (5.6.1) */
197             dTHXa(pp->interp);
198             if (PL_scopestack_ix == 0) {
199                 ENTER;
200             }
201         }
202 #else
203         pp->interp = gp->perl_interp;
204 #endif
205         {
206                 dTHXs
208                 SvREADONLY_on(pp->svcurscr = perl_get_sv("curscr", TRUE));
209                 SvREADONLY_on(pp->svstart = perl_get_sv("VI::StartLine", TRUE));
210                 SvREADONLY_on(pp->svstop = perl_get_sv("VI::StopLine", TRUE));
211                 SvREADONLY_on(pp->svid = perl_get_sv("VI::ScreenId", TRUE));
212         }
213         return (0);
217  * perl_screen_end
218  *      Remove all refences to the screen to be destroyed
220  * PUBLIC: int perl_screen_end __P((SCR*));
221  */
223 perl_screen_end(scrp)
224         SCR *scrp;
226         dTHXs
228         if (scrp->perl_private) {
229                 sv_setiv((SV*) scrp->perl_private, 0);
230         }
231         return 0;
234 static void
235 my_sighandler(i)
236         int i;
238         croak("Perl command interrupted by SIGINT");
241 /* Create a new reference to an SV pointing to the SCR structure
242  * The perl_private part of the SCR structure points to the SV,
243  * so there can only be one such SV for a particular SCR structure.
244  * When the last reference has gone (DESTROY is called),
245  * perl_private is reset; When the screen goes away before
246  * all references are gone, the value of the SV is reset;
247  * any subsequent use of any of those reference will produce
248  * a warning. (see typemap)
249  */
250 static SV *
251 newVIrv(rv, screen)
252         SV *rv;
253         SCR *screen;
255         dTHXs
257         if (!screen) return sv_setsv(rv, &PL_sv_undef), rv;
258         sv_upgrade(rv, SVt_RV);
259         if (!screen->perl_private) {
260                 screen->perl_private = newSV(0);
261                 sv_setiv(screen->perl_private, (IV) screen);
262         } 
263         else SvREFCNT_inc(screen->perl_private);
264         SvRV(rv) = screen->perl_private;
265         SvROK_on(rv);
266         return sv_bless(rv, gv_stashpv("VI", TRUE));
270 /* 
271  * perl_ex_perl -- :[line [,line]] perl [command]
272  *      Run a command through the perl interpreter.
274  * PUBLIC: int perl_ex_perl __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
275  */
276 int 
277 perl_ex_perl(scrp, cmdp, cmdlen, f_lno, t_lno)
278         SCR *scrp;
279         CHAR_T *cmdp;
280         size_t cmdlen;
281         db_recno_t f_lno, t_lno;
283         WIN *wp;
284         size_t length;
285         size_t len;
286         char *err;
287         char *np;
288         size_t nlen;
289         Signal_t (*istat)();
290         perl_data_t *pp;
292         /* Initialize the interpreter. */
293         if (scrp->wp->perl_private == NULL && perl_init(scrp))
294                         return (1);
295         pp = scrp->wp->perl_private;
296     {
297         dTHXs
298         dSP;
300         sv_setiv(pp->svstart, f_lno);
301         sv_setiv(pp->svstop, t_lno);
302         newVIrv(pp->svcurscr, scrp);
303         /* Backwards compatibility. */
304         newVIrv(pp->svid, scrp);
306         istat = signal(SIGINT, my_sighandler);
307         INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
308         perl_eval(np);
309         signal(SIGINT, istat);
311         SvREFCNT_dec(SvRV(pp->svcurscr));
312         SvROK_off(pp->svcurscr);
313         SvREFCNT_dec(SvRV(pp->svid));
314         SvROK_off(pp->svid);
316         err = SvPV(ERRSV, length);
317         if (!length)
318                 return (0);
320         err[length - 1] = '\0';
321         msgq(scrp, M_ERR, "perl: %s", err);
322         return (1);
323     }
327  * replace_line
328  *      replace a line with the contents of the perl variable $_
329  *      lines are split at '\n's
330  *      if $_ is undef, the line is deleted
331  *      returns possibly adjusted linenumber
332  */
333 static int 
334 replace_line(scrp, line, t_lno, defsv)
335         SCR *scrp;
336         db_recno_t line, *t_lno;
337         SV *defsv;
339         char *str, *next;
340         CHAR_T *wp;
341         size_t len, wlen;
342         dTHXs
344         if (SvOK(defsv)) {
345                 str = SvPV(defsv,len);
346                 next = memchr(str, '\n', len);
347                 CHAR2INTP(scrp, str, next ? (next - str) : len, wp, wlen);
348                 api_sline(scrp, line, wp, wlen);
349                 while (next++) {
350                         len -= next - str;
351                         next = memchr(str = next, '\n', len);
352                         CHAR2INTP(scrp, str, next ? (next - str) : len, 
353                                     wp, wlen);
354                         api_iline(scrp, ++line, wp, wlen);
355                         (*t_lno)++;
356                 }
357         } else {
358                 api_dline(scrp, line--);
359                 (*t_lno)--;
360         }
361         return line;
364 /* 
365  * perl_ex_perldo -- :[line [,line]] perl [command]
366  *      Run a set of lines through the perl interpreter.
368  * PUBLIC: int perl_ex_perldo __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
369  */
370 int 
371 perl_ex_perldo(scrp, cmdp, cmdlen, f_lno, t_lno)
372         SCR *scrp;
373         CHAR_T *cmdp;
374         size_t cmdlen;
375         db_recno_t f_lno, t_lno;
377         CHAR_T *p;
378         WIN *wp;
379         size_t length;
380         size_t len;
381         db_recno_t i;
382         CHAR_T *str;
383         char *estr;
384         SV* cv;
385         char *command;
386         perl_data_t *pp;
387         char *np;
388         size_t nlen;
390         /* Initialize the interpreter. */
391         if (scrp->wp->perl_private == NULL && perl_init(scrp))
392                         return (1);
393         pp = scrp->wp->perl_private;
394     {
395         dTHXs
396         dSP;
398         newVIrv(pp->svcurscr, scrp);
399         /* Backwards compatibility. */
400         newVIrv(pp->svid, scrp);
402         INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
403         if (!(command = malloc(length = nlen - 1 + sizeof("sub {}"))))
404                 return 1;
405         snprintf(command, length, "sub {%s}", np);
407         ENTER;
408         SAVETMPS;
410         cv = perl_eval_pv(command, FALSE);
411         free (command);
413         estr = SvPV(ERRSV,length);
414         if (length)
415                 goto err;
417         for (i = f_lno; i <= t_lno && !api_gline(scrp, i, &str, &len); i++) {
418                 INT2CHAR(scrp, str, len, np, nlen);
419                 sv_setpvn(DEFSV,np,nlen);
420                 sv_setiv(pp->svstart, i);
421                 sv_setiv(pp->svstop, i);
422                 PUSHMARK(sp);
423                 perl_call_sv(cv, G_SCALAR | G_EVAL);
424                 estr = SvPV(ERRSV, length);
425                 if (length) break;
426                 SPAGAIN;
427                 if(SvTRUEx(POPs)) 
428                         i = replace_line(scrp, i, &t_lno, DEFSV);
429                 PUTBACK;
430         }
431         FREETMPS;
432         LEAVE;
434         SvREFCNT_dec(SvRV(pp->svcurscr));
435         SvROK_off(pp->svcurscr);
436         SvREFCNT_dec(SvRV(pp->svid));
437         SvROK_off(pp->svid);
439         if (!length)
440                 return (0);
442 err:    estr[length - 1] = '\0';
443         msgq(scrp, M_ERR, "perl: %s", estr);
444         return (1);
445     }
449  * msghandler --
450  *      Perl message routine so that error messages are processed in
451  *      Perl, not in nvi.
452  */
453 static void
454 msghandler(sp, mtype, msg, len)
455         SCR *sp;
456         mtype_t mtype;
457         char *msg;
458         size_t len;
460         /* Replace the trailing <newline> with an EOS. */
461         /* Let's do that later instead */
462         if (errmsg) free (errmsg);
463         errmsg = malloc(len + 1);
464         memcpy(errmsg, msg, len);
465         errmsg[len] = '\0';
469 typedef SCR *   VI;
470 typedef SCR *   VI__OPT;
471 typedef SCR *   VI__MAP;
472 typedef SCR *   VI__MARK;
473 typedef SCR *   VI__LINE;
474 typedef AV *    AVREF;
476 typedef struct {
477     SV      *sprv;
478     TAGQ    *tqp;
479 } perl_tagq;
481 typedef perl_tagq *  VI__TAGQ;
482 typedef perl_tagq *  VI__TAGQ2;
484 MODULE = VI     PACKAGE = VI
486 # msg --
487 #       Set the message line to text.
489 # Perl Command: VI::Msg
490 # Usage: VI::Msg screenId text
492 void
493 Msg(screen, text)
494         VI          screen
495         char *      text
497         ALIAS:
498         PRINT = 1
500         CODE:
501         api_imessage(screen, text);
503 # XS_VI_escreen --
504 #       End a screen.
506 # Perl Command: VI::EndScreen
507 # Usage: VI::EndScreen screenId
509 void
510 EndScreen(screen)
511         VI      screen
513         PREINIT:
514         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
515         int rval;
517         CODE:
518         INITMESSAGE(screen);
519         rval = api_escreen(screen);
520         ENDMESSAGE(screen);
522 # XS_VI_iscreen --
523 #       Create a new screen.  If a filename is specified then the screen
524 #       is opened with that file.
526 # Perl Command: VI::NewScreen
527 # Usage: VI::NewScreen screenId [file]
530 Edit(screen, ...)
531         VI screen
533         ALIAS:
534         NewScreen = 1
536         PROTOTYPE: $;$
537         PREINIT:
538         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
539         int rval;
540         char *file;
541         SCR *nsp;
543         CODE:
544         file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
545         INITMESSAGE(screen);
546         rval = api_edit(screen, file, &nsp, ix);
547         ENDMESSAGE(screen);
548         
549         RETVAL = ix ? nsp : screen;
551         OUTPUT:
552         RETVAL
554 # XS_VI_fscreen --
555 #       Return the screen id associated with file name.
557 # Perl Command: VI::FindScreen
558 # Usage: VI::FindScreen file
561 FindScreen(file)
562         char *file
564         PREINIT:
565         SCR *fsp;
566         CODE:
567         RETVAL = api_fscreen(0, file);
569         OUTPUT:
570         RETVAL
572 # XS_VI_GetFileName --
573 #       Return the file name of the screen
575 # Perl Command: VI::GetFileName
576 # Usage: VI::GetFileName screenId
578 char *
579 GetFileName(screen)
580         VI screen;
582         PPCODE:
583         EXTEND(sp,1);
584         PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
586 # XS_VI_aline --
587 #       -- Append the string text after the line in lineNumber.
589 # Perl Command: VI::AppendLine
590 # Usage: VI::AppendLine screenId lineNumber text
592 void
593 AppendLine(screen, linenumber, text)
594         VI screen
595         int linenumber
596         char *text
598         PREINIT:
599         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
600         int rval;
601         size_t length;
603         CODE:
604         SvPV(ST(2), length);
605         INITMESSAGE(screen);
606         rval = api_aline(screen, linenumber, text, length);
607         ENDMESSAGE(screen);
609 # XS_VI_dline --
610 #       Delete lineNum.
612 # Perl Command: VI::DelLine
613 # Usage: VI::DelLine screenId lineNum
615 void 
616 DelLine(screen, linenumber)
617         VI screen
618         int linenumber
620         PREINIT:
621         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
622         int rval;
624         CODE:
625         INITMESSAGE(screen);
626         rval = api_dline(screen, (db_recno_t)linenumber);
627         ENDMESSAGE(screen);
629 # XS_VI_gline --
630 #       Return lineNumber.
632 # Perl Command: VI::GetLine
633 # Usage: VI::GetLine screenId lineNumber
635 char *
636 GetLine(screen, linenumber)
637         VI screen
638         int linenumber
640         PREINIT:
641         size_t len;
642         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
643         int rval;
644         char *line;
645         CHAR_T *p;
647         PPCODE:
648         INITMESSAGE(screen);
649         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
650         ENDMESSAGE(screen);
652         EXTEND(sp,1);
653         PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
655 # XS_VI_sline --
656 #       Set lineNumber to the text supplied.
658 # Perl Command: VI::SetLine
659 # Usage: VI::SetLine screenId lineNumber text
661 void
662 SetLine(screen, linenumber, text)
663         VI screen
664         int linenumber
665         char *text
667         PREINIT:
668         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
669         int rval;
670         size_t length;
671         size_t len;
672         CHAR_T *line;
674         CODE:
675         SvPV(ST(2), length);
676         INITMESSAGE(screen);
677         CHAR2INTP(screen, text, length, line, len);
678         rval = api_sline(screen, linenumber, line, len);
679         ENDMESSAGE(screen);
681 # XS_VI_iline --
682 #       Insert the string text before the line in lineNumber.
684 # Perl Command: VI::InsertLine
685 # Usage: VI::InsertLine screenId lineNumber text
687 void
688 InsertLine(screen, linenumber, text)
689         VI screen
690         int linenumber
691         char *text
693         PREINIT:
694         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
695         int rval;
696         size_t length;
697         size_t len;
698         CHAR_T *line;
700         CODE:
701         SvPV(ST(2), length);
702         INITMESSAGE(screen);
703         CHAR2INTP(screen, text, length, line, len);
704         rval = api_iline(screen, linenumber, line, len);
705         ENDMESSAGE(screen);
707 # XS_VI_lline --
708 #       Return the last line in the screen.
710 # Perl Command: VI::LastLine
711 # Usage: VI::LastLine screenId
713 int 
714 LastLine(screen)
715         VI screen
717         PREINIT:
718         db_recno_t last;
719         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
720         int rval;
722         CODE:
723         INITMESSAGE(screen);
724         rval = api_lline(screen, &last);
725         ENDMESSAGE(screen);
726         RETVAL=last;
728         OUTPUT:
729         RETVAL
731 # XS_VI_getmark --
732 #       Return the mark's cursor position as a list with two elements.
733 #       {line, column}.
735 # Perl Command: VI::GetMark
736 # Usage: VI::GetMark screenId mark
738 void
739 GetMark(screen, mark)
740         VI screen
741         char mark
743         PREINIT:
744         struct _mark cursor;
745         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
746         int rval;
748         PPCODE:
749         INITMESSAGE(screen);
750         rval = api_getmark(screen, (int)mark, &cursor);
751         ENDMESSAGE(screen);
753         EXTEND(sp,2);
754         PUSHs(sv_2mortal(newSViv(cursor.lno)));
755         PUSHs(sv_2mortal(newSViv(cursor.cno)));
757 # XS_VI_setmark --
758 #       Set the mark to the line and column numbers supplied.
760 # Perl Command: VI::SetMark
761 # Usage: VI::SetMark screenId mark line column
763 void
764 SetMark(screen, mark, line, column)
765         VI screen
766         char mark
767         int line
768         int column
770         PREINIT:
771         struct _mark cursor;
772         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
773         int rval;
775         CODE:
776         INITMESSAGE(screen);
777         cursor.lno = line;
778         cursor.cno = column;
779         rval = api_setmark(screen, (int)mark, &cursor);
780         ENDMESSAGE(screen);
782 # XS_VI_getcursor --
783 #       Return the current cursor position as a list with two elements.
784 #       {line, column}.
786 # Perl Command: VI::GetCursor
787 # Usage: VI::GetCursor screenId
789 void
790 GetCursor(screen)
791         VI screen
793         PREINIT:
794         struct _mark cursor;
795         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
796         int rval;
798         PPCODE:
799         INITMESSAGE(screen);
800         rval = api_getcursor(screen, &cursor);
801         ENDMESSAGE(screen);
803         EXTEND(sp,2);
804         PUSHs(sv_2mortal(newSViv(cursor.lno)));
805         PUSHs(sv_2mortal(newSViv(cursor.cno)));
807 # XS_VI_setcursor --
808 #       Set the cursor to the line and column numbers supplied.
810 # Perl Command: VI::SetCursor
811 # Usage: VI::SetCursor screenId line column
813 void
814 SetCursor(screen, line, column)
815         VI screen
816         int line
817         int column
819         PREINIT:
820         struct _mark cursor;
821         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
822         int rval;
824         CODE:
825         INITMESSAGE(screen);
826         cursor.lno = line;
827         cursor.cno = column;
828         rval = api_setcursor(screen, &cursor);
829         ENDMESSAGE(screen);
831 # XS_VI_swscreen --
832 #       Change the current focus to screen.
834 # Perl Command: VI::SwitchScreen
835 # Usage: VI::SwitchScreen screenId screenId
837 void
838 SwitchScreen(screenFrom, screenTo)
839         VI screenFrom
840         VI screenTo
842         PREINIT:
843         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
844         int rval;
846         CODE:
847         INITMESSAGE(screenFrom);
848         rval = api_swscreen(screenFrom, screenTo);
849         ENDMESSAGE(screenFrom);
851 # XS_VI_map --
852 #       Associate a key with a perl procedure.
854 # Perl Command: VI::MapKey
855 # Usage: VI::MapKey screenId key perlproc
857 void
858 MapKey(screen, key, perlproc)
859         VI screen
860         char *key
861         SV *perlproc
863         PREINIT:
864         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
865         int rval;
866         int length;
867         char *command;
868         SV *svc;
869         SV *svn;
871         CODE:
872         INITMESSAGE(screen);
873         svc = sv_2mortal(newSVpv(":perl ", 6));
874         sv_catsv(svc, perlproc);
875         svn = sv_2mortal(newSVpv("\r", 1));
876         sv_catsv(svc, svn);
877         command = SvPV(svc, length);
878         rval = api_map(screen, key, command, length);
879         ENDMESSAGE(screen);
881 # XS_VI_unmap --
882 #       Unmap a key.
884 # Perl Command: VI::UnmapKey
885 # Usage: VI::UnmmapKey screenId key
887 void
888 UnmapKey(screen, key)
889         VI screen
890         char *key
892         PREINIT:
893         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
894         int rval;
896         CODE:
897         INITMESSAGE(screen);
898         rval = api_unmap(screen, key);
899         ENDMESSAGE(screen);
901 # XS_VI_opts_set --
902 #       Set an option.
904 # Perl Command: VI::SetOpt
905 # Usage: VI::SetOpt screenId setting
907 void
908 SetOpt(screen, setting)
909         VI screen
910         char *setting
912         PREINIT:
913         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
914         int rval;
915         SV *svc;
917         CODE:
918         INITMESSAGE(screen);
919         svc = sv_2mortal(newSVpv(":set ", 5));
920         sv_catpv(svc, setting);
921         rval = api_run_str(screen, SvPV(svc, PL_na));
922         ENDMESSAGE(screen);
924 # XS_VI_opts_get --
925 #       Return the value of an option.
926 #       
927 # Perl Command: VI::GetOpt
928 # Usage: VI::GetOpt screenId option
930 void
931 GetOpt(screen, option)
932         VI screen
933         char *option
935         PREINIT:
936         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
937         int rval;
938         char *value;
939         CHAR_T *wp;
940         size_t wlen;
942         PPCODE:
943         INITMESSAGE(screen);
944         CHAR2INTP(screen, option, strlen(option)+1, wp, wlen);
945         rval = api_opts_get(screen, wp, &value, NULL);
946         ENDMESSAGE(screen);
948         EXTEND(SP,1);
949         PUSHs(sv_2mortal(newSVpv(value, 0)));
950         free(value);
952 # XS_VI_run --
953 #       Run the ex command cmd.
955 # Perl Command: VI::Run
956 # Usage: VI::Run screenId cmd
958 void
959 Run(screen, command)
960         VI screen
961         char *command;
963         PREINIT:
964         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
965         int rval;
967         CODE:
968         INITMESSAGE(screen);
969         rval = api_run_str(screen, command);
970         ENDMESSAGE(screen);
972 void 
973 DESTROY(screensv)
974         SV* screensv
976         PREINIT:
977         VI  screen;
979         CODE:
980         if (sv_isa(screensv, "VI")) {
981                 IV tmp = SvIV((SV*)SvRV(screensv));
982                 screen = (SCR *) tmp;
983         }
984         else
985                 croak("screen is not of type VI");
987         if (screen)
988         screen->perl_private = 0;
990 void
991 Warn(warning)
992         char *warning;
994         CODE:
995         sv_catpv(ERRSV,warning);
997 #define TIED(kind,package) \
998         sv_magic((SV *) (var = \
999             (##kind##V *)sv_2mortal((SV *)new##kind##V())), \
1000                 sv_setref_pv(sv_newmortal(), package, \
1001                         newVIrv(newSV(0), screen)),\
1002                 'P', Nullch, 0);\
1003         RETVAL = newRV((SV *)var)
1005 SV *
1006 Opt(screen)
1007         VI screen;
1008         PREINIT:
1009         HV *var;
1010         CODE:
1011         TIED(H,"VI::OPT");
1012         OUTPUT:
1013         RETVAL
1015 SV *
1016 Map(screen)
1017         VI screen;
1018         PREINIT:
1019         HV *var;
1020         CODE:
1021         TIED(H,"VI::MAP");
1022         OUTPUT:
1023         RETVAL
1025 SV *
1026 Mark(screen)
1027         VI screen
1028         PREINIT:
1029         HV *var;
1030         CODE:
1031         TIED(H,"VI::MARK");
1032         OUTPUT:
1033         RETVAL
1035 SV *
1036 Line(screen)
1037         VI screen
1038         PREINIT:
1039         AV *var;
1040         CODE:
1041         TIED(A,"VI::LINE");
1042         OUTPUT:
1043         RETVAL
1045 SV *
1046 TagQ(screen, tag)
1047         VI screen
1048         char *tag;
1050         PREINIT:
1051         perl_tagq *ptag;
1053         PPCODE:
1054         if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1055                 goto err;
1057         ptag->sprv = newVIrv(newSV(0), screen);
1058         ptag->tqp = api_tagq_new(screen, tag);
1059         if (ptag->tqp != NULL) {
1060                 EXTEND(SP,1);
1061                 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1062         } else {
1063 err:
1064                 ST(0) = &PL_sv_undef;
1065                 return;
1066         }
1068 MODULE = VI     PACKAGE = VI::OPT
1070 void 
1071 DESTROY(screen)
1072         VI::OPT screen
1074         CODE:
1075         # typemap did all the checking
1076         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1078 void
1079 FETCH(screen, key)
1080         VI::OPT screen
1081         char *key
1083         PREINIT:
1084         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1085         int rval;
1086         char *value;
1087         int boolvalue;
1088         CHAR_T *wp;
1089         size_t wlen;
1091         PPCODE:
1092         INITMESSAGE(screen);
1093         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1094         rval = api_opts_get(screen, wp, &value, &boolvalue);
1095         if (!rval) {
1096                 EXTEND(SP,1);
1097                 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1098                                                    : newSViv(boolvalue)));
1099                 free(value);
1100         } else ST(0) = &PL_sv_undef;
1101         rval = 0;
1102         ENDMESSAGE(screen);
1104 void
1105 STORE(screen, key, value)
1106         VI::OPT screen
1107         char    *key
1108         SV      *value
1110         PREINIT:
1111         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1112         int rval;
1113         CHAR_T *wp;
1114         size_t wlen;
1116         CODE:
1117         INITMESSAGE(screen);
1118         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1119         rval = api_opts_set(screen, wp, SvPV(value, PL_na), SvIV(value), 
1120                                          SvTRUEx(value));
1121         ENDMESSAGE(screen);
1123 MODULE = VI     PACKAGE = VI::MAP
1125 void 
1126 DESTROY(screen)
1127         VI::MAP screen
1129         CODE:
1130         # typemap did all the checking
1131         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1133 void
1134 STORE(screen, key, perlproc)
1135         VI::MAP screen
1136         char *key
1137         SV *perlproc
1139         PREINIT:
1140         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1141         int rval;
1142         int length;
1143         char *command;
1144         SV *svc;
1145         SV *svn;
1147         CODE:
1148         INITMESSAGE(screen);
1149         svc = sv_2mortal(newSVpv(":perl ", 6));
1150         sv_catsv(svc, perlproc);
1151         svn = sv_2mortal(newSVpv("\r", 1));
1152         sv_catsv(svc, svn);
1153         command = SvPV(svc, length);
1154         rval = api_map(screen, key, command, length);
1155         ENDMESSAGE(screen);
1157 void
1158 DELETE(screen, key)
1159         VI::MAP screen
1160         char *key
1162         PREINIT:
1163         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1164         int rval;
1166         CODE:
1167         INITMESSAGE(screen);
1168         rval = api_unmap(screen, key);
1169         ENDMESSAGE(screen);
1171 MODULE = VI     PACKAGE = VI::MARK
1173 void 
1174 DESTROY(screen)
1175         VI::MARK screen
1177         CODE:
1178         # typemap did all the checking
1179         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1181 AV *
1182 FETCH(screen, mark)
1183         VI::MARK screen
1184         char mark
1186         PREINIT:
1187         struct _mark cursor;
1188         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1189         int rval;
1191         CODE:
1192         INITMESSAGE(screen);
1193         rval = api_getmark(screen, (int)mark, &cursor);
1194         ENDMESSAGE(screen);
1195         RETVAL = newAV();
1196         av_push(RETVAL, newSViv(cursor.lno));
1197         av_push(RETVAL, newSViv(cursor.cno));
1199         OUTPUT:
1200         RETVAL
1202 void
1203 STORE(screen, mark, pos)
1204         VI::MARK screen
1205         char mark
1206         AVREF pos
1208         PREINIT:
1209         struct _mark cursor;
1210         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1211         int rval;
1213         CODE:
1214         if (av_len(pos) < 1) 
1215             croak("cursor position needs 2 elements");
1216         INITMESSAGE(screen);
1217         cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1218         cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1219         rval = api_setmark(screen, (int)mark, &cursor);
1220         ENDMESSAGE(screen);
1222 void
1223 FIRSTKEY(screen, ...)
1224         VI::MARK screen
1226         ALIAS:
1227         NEXTKEY = 1
1228         
1229         PROTOTYPE: $;$
1231         PREINIT:
1232         int next;
1233         char key[] = {0, 0};
1235         PPCODE:
1236         if (items == 2) {
1237                 next = 1;
1238                 *key = *(char *)SvPV(ST(1),PL_na);
1239         } else next = 0;
1240         if (api_nextmark(screen, next, key) != 1) {
1241                 EXTEND(sp, 1);
1242                 PUSHs(sv_2mortal(newSVpv(key, 1)));
1243         } else ST(0) = &PL_sv_undef;
1245 MODULE = VI     PACKAGE = VI::LINE
1247 void 
1248 DESTROY(screen)
1249         VI::LINE screen
1251         CODE:
1252         # typemap did all the checking
1253         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1255 # similar to SetLine
1257 void
1258 STORE(screen, linenumber, text)
1259         VI::LINE screen
1260         int linenumber
1261         char *text
1263         PREINIT:
1264         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1265         int rval;
1266         size_t length;
1267         db_recno_t last;
1268         size_t len;
1269         CHAR_T *line;
1271         CODE:
1272         ++linenumber;   /* vi 1 based ; perl 0 based */
1273         SvPV(ST(2), length);
1274         INITMESSAGE(screen);
1275         rval = api_lline(screen, &last);
1276         if (!rval) {
1277             if (linenumber > last)
1278                 rval = api_extend(screen, linenumber);
1279             if (!rval)
1280                 CHAR2INTP(screen, text, length, line, len);
1281                 rval = api_sline(screen, linenumber, line, len);
1282         }
1283         ENDMESSAGE(screen);
1285 # similar to GetLine 
1287 char *
1288 FETCH(screen, linenumber)
1289         VI::LINE screen
1290         int linenumber
1292         PREINIT:
1293         size_t len;
1294         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1295         int rval;
1296         char *line;
1297         CHAR_T *p;
1299         PPCODE:
1300         ++linenumber;   /* vi 1 based ; perl 0 based */
1301         INITMESSAGE(screen);
1302         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1303         ENDMESSAGE(screen);
1305         EXTEND(sp,1);
1306         PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1308 # similar to LastLine 
1311 FETCHSIZE(screen)
1312         VI::LINE screen
1314         PREINIT:
1315         db_recno_t last;
1316         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1317         int rval;
1319         CODE:
1320         INITMESSAGE(screen);
1321         rval = api_lline(screen, &last);
1322         ENDMESSAGE(screen);
1323         RETVAL=last;
1325         OUTPUT:
1326         RETVAL
1328 void
1329 STORESIZE(screen, count)
1330         VI::LINE screen
1331         int count
1333         PREINIT:
1334         db_recno_t last;
1335         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1336         int rval;
1338         CODE:
1339         INITMESSAGE(screen);
1340         rval = api_lline(screen, &last);
1341         if (!rval) {
1342             if (count > last)
1343                 rval = api_extend(screen, count);
1344             else while(last && last > count) {
1345                 rval = api_dline(screen, last--);
1346                 if (rval) break;
1347             }
1348         }
1349         ENDMESSAGE(screen);
1351 void
1352 EXTEND(screen, count)
1353         VI::LINE screen
1354         int count
1356         CODE:
1358 void
1359 CLEAR(screen)
1360         VI::LINE screen
1362         PREINIT:
1363         db_recno_t last;
1364         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1365         int rval;
1367         CODE:
1368         INITMESSAGE(screen);
1369         rval = api_lline(screen, &last);
1370         if (!rval) {
1371             while(last) {
1372                 rval = api_dline(screen, last--);
1373                 if (rval) break;
1374             }
1375         }
1376         ENDMESSAGE(screen);
1378 void
1379 PUSH(screen, ...)
1380         VI::LINE screen;
1382         PREINIT:
1383         db_recno_t last;
1384         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1385         int rval, i, len;
1386         char *line;
1388         CODE:
1389         INITMESSAGE(screen);
1390         rval = api_lline(screen, &last);
1392         if (!rval)
1393                 for (i = 1; i < items; ++i) {
1394                         line = SvPV(ST(i), len);
1395                         if ((rval = api_aline(screen, last++, line, len)))
1396                                 break;
1397                 }
1398         ENDMESSAGE(screen);
1400 SV *
1401 POP(screen)
1402         VI::LINE screen;
1404         PREINIT:
1405         db_recno_t last;
1406         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1407         int rval, i, len;
1408         CHAR_T *line;
1410         PPCODE:
1411         INITMESSAGE(screen);
1412         rval = api_lline(screen, &last);
1413         if (rval || last < 1)
1414                 ST(0) = &PL_sv_undef;
1415         else {
1416                 rval = api_gline(screen, last, &line, &len) ||
1417                        api_dline(screen, last);
1418                 EXTEND(sp,1);
1419                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1420         }
1421         ENDMESSAGE(screen);
1423 SV *
1424 SHIFT(screen)
1425         VI::LINE screen;
1427         PREINIT:
1428         db_recno_t last;
1429         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1430         int rval, i, len;
1431         CHAR_T *line;
1433         PPCODE:
1434         INITMESSAGE(screen);
1435         rval = api_lline(screen, &last);
1436         if (rval || last < 1)
1437                 ST(0) = &PL_sv_undef;
1438         else {
1439                 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1440                        api_dline(screen, (db_recno_t)1);
1441                 EXTEND(sp,1);
1442                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1443         }
1444         ENDMESSAGE(screen);
1446 void
1447 UNSHIFT(screen, ...)
1448         VI::LINE screen;
1450         PREINIT:
1451         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1452         int rval, i, len;
1453         char *np;
1454         size_t nlen;
1455         CHAR_T *line;
1457         CODE:
1458         INITMESSAGE(screen);
1459         while (--items != 0) {
1460                 np = SvPV(ST(items), nlen);
1461                 CHAR2INTP(screen, np, nlen, line, len);
1462                 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1463                         break;
1464         }
1465         ENDMESSAGE(screen);
1467 void
1468 SPLICE(screen, ...)
1469         VI::LINE screen;
1471         PREINIT:
1472         db_recno_t last, db_offset;
1473         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1474         int rval, length, common, len, i, offset;
1475         CHAR_T *line;
1476         char *np;
1477         size_t nlen;
1479         PPCODE:
1480         INITMESSAGE(screen);
1481         rval = api_lline(screen, &last);
1482         offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1483         if (offset < 0) offset += last;
1484         if (offset < 0) {
1485             ENDMESSAGE(screen);
1486             croak("Invalid offset");
1487         }
1488         length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1489         if (length > last - offset)
1490                 length = last - offset;
1491         db_offset = offset + 1; /* 1 based */
1492         EXTEND(sp,length);
1493         for (common = MIN(length, items - 3), i = 3; common > 0; 
1494             --common, ++db_offset, --length, ++i) {
1495                 rval |= api_gline(screen, db_offset, &line, &len);
1496                 INT2CHAR(screen, line, len, np, nlen);
1497                 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1498                 np = SvPV(ST(i), nlen);
1499                 CHAR2INTP(screen, np, nlen, line, len);
1500                 rval |= api_sline(screen, db_offset, line, len);
1501         }
1502         for (; length; --length) {
1503                 rval |= api_gline(screen, db_offset, &line, &len);
1504                 INT2CHAR(screen, line, len, np, nlen);
1505                 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1506                 rval |= api_dline(screen, db_offset);
1507         }
1508         for (; i < items; ++i) {
1509                 np = SvPV(ST(i), len);
1510                 CHAR2INTP(screen, np, len, line, nlen);
1511                 rval |= api_iline(screen, db_offset, line, nlen);
1512         }
1513         ENDMESSAGE(screen);
1515 MODULE = VI     PACKAGE = VI::TAGQ
1517 void
1518 Add(tagq, filename, search, msg)
1519         VI::TAGQ    tagq;
1520         char       *filename;
1521         char       *search;
1522         char       *msg;
1524         PREINIT:
1525         SCR *sp;
1527         CODE:
1528         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1529         if (!sp)
1530                 croak("screen no longer exists");
1531         api_tagq_add(sp, tagq->tqp, filename, search, msg);
1533 void
1534 Push(tagq)
1535         VI::TAGQ    tagq;
1537         PREINIT:
1538         SCR *sp;
1540         CODE:
1541         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1542         if (!sp)
1543                 croak("screen no longer exists");
1544         api_tagq_push(sp, &tagq->tqp);
1546 void
1547 DESTROY(tagq)
1548         # Can already be invalidated by push 
1549         VI::TAGQ2    tagq; 
1551         PREINIT:
1552         SCR *sp;
1554         CODE:
1555         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1556         if (sp)
1557                 api_tagq_free(sp, tagq->tqp);
1558         SvREFCNT_dec(tagq->sprv);
1559         free(tagq);