perl: remove conflicting re_compile define
[nvi.git] / perl_api / perl.xs
blob388642b73600f823359818bd83d923bc243d99d0
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.46 2001/08/28 11:33:42 skimo Exp $ (Berkeley) $Date: 2001/08/28 11:33:42 $";
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 re_compile
42 #undef USE_DYNAMIC_LOADING
43 #undef DEBUG
44 #undef PACKAGE
45 #undef ARGS
46 #define ARGS ARGS
48 #include "config.h"
50 #include "../common/common.h"
51 #include "../perl_api/extern.h"
53 #ifndef DEFSV
54 #define DEFSV GvSV(defgv)
55 #endif
56 #ifndef ERRSV
57 #define ERRSV GvSV(errgv)
58 #endif
59 #ifndef dTHX
60 #define dTHXs
61 #else
62 #define dTHXs dTHX;
63 #endif
65 static void msghandler __P((SCR *, mtype_t, char *, size_t));
67 typedef struct _perl_data {
68         PerlInterpreter*        interp;
69         SV      *svcurscr, *svstart, *svstop, *svid;
70         CONVWIN  cw;
71         char    *errmsg;
72 } perl_data_t;
74 #define PERLP(sp)   ((perl_data_t *)sp->wp->perl_private)
76 #define CHAR2INTP(sp,n,nlen,w,wlen)                                         \
77     CHAR2INT5(sp,((perl_data_t *)sp->wp->perl_private)->cw,n,nlen,w,wlen)
80  * INITMESSAGE --
81  *      Macros to point messages at the Perl message handler.
82  */
83 #define INITMESSAGE(sp)                                                 \
84         scr_msg = sp->wp->scr_msg;                                      \
85         sp->wp->scr_msg = msghandler;
86 #define ENDMESSAGE(sp)                                                  \
87         sp->wp->scr_msg = scr_msg;                                      \
88         if (rval) croak("%s", PERLP(sp)->errmsg);
90 void xs_init __P((pTHXo));
93  * perl_end --
94  *      Clean up perl interpreter
95  *
96  * PUBLIC: int perl_end __P((GS *));
97  */
98 int
99 perl_end(gp)
100         GS *gp;
102         /*
103          * Call perl_run and perl_destuct to call END blocks and DESTROY
104          * methods.
105          */
106         if (gp->perl_interp) {
107                 perl_run(gp->perl_interp);
108                 perl_destruct(gp->perl_interp);
109 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
110                 perl_free(gp->perl_interp);
111 #endif
112                 /* XXX rather make sure only one thread calls perl_end */
113                 gp->perl_interp = 0;
114         }
118  * perl_eval
119  *      Evaluate a string
120  *      We don't use mortal SVs because no one will clean up after us
121  */
122 static void 
123 perl_eval(string)
124         char *string;
126         dTHXs
128         SV* sv = newSVpv(string, 0);
130         /* G_KEEPERR to catch syntax error; better way ? */
131         sv_setpv(ERRSV,"");
132         perl_eval_sv(sv, G_DISCARD | G_NOARGS | G_KEEPERR);
133         SvREFCNT_dec(sv);
137  * perl_init --
138  *      Create the perl commands used by nvi.
140  * PUBLIC: int perl_init __P((SCR *));
141  */
143 perl_init(scrp)
144         SCR *scrp;
146         AV * av;
147         GS *gp;
148         WIN *wp;
149         char *bootargs[] = { "VI", NULL };
150 #ifndef USE_SFIO
151         SV *svcurscr;
152 #endif
153         perl_data_t *pp;
155         static char *args[] = { "", "-e", "" };
156         size_t length;
157         char *file = __FILE__;
159         gp = scrp->gp;
160         wp = scrp->wp;
162         if (gp->perl_interp == NULL) {
163         gp->perl_interp = perl_alloc();
164         perl_construct(gp->perl_interp);
165         if (perl_parse(gp->perl_interp, xs_init, 3, args, 0)) {
166                 perl_destruct(gp->perl_interp);
167                 perl_free(gp->perl_interp);
168                 gp->perl_interp = NULL;
169                 return 1;
170         }
171         {
172         dTHXs
174         perl_call_argv("VI::bootstrap", G_DISCARD, bootargs);
175         perl_eval("$SIG{__WARN__}='VI::Warn'");
177         av_unshift(av = GvAVn(PL_incgv), 1);
178         av_store(av, 0, newSVpv(_PATH_PERLSCRIPTS,
179                                 sizeof(_PATH_PERLSCRIPTS)-1));
181 #ifdef USE_SFIO
182         sfdisc(PerlIO_stdout(), sfdcnewnvi(scrp));
183         sfdisc(PerlIO_stderr(), sfdcnewnvi(scrp));
184 #else
185         svcurscr = perl_get_sv("curscr", TRUE);
186         sv_magic((SV *)gv_fetchpv("STDOUT",TRUE, SVt_PVIO), svcurscr,
187                         'q', Nullch, 0);
188         sv_magic((SV *)gv_fetchpv("STDERR",TRUE, SVt_PVIO), svcurscr,
189                         'q', Nullch, 0);
190 #endif /* USE_SFIO */
191         }
192         }
193         MALLOC(scrp, pp, perl_data_t *, sizeof(perl_data_t));
194         wp->perl_private = pp;
195         memset(&pp->cw, 0, sizeof(pp->cw));
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         pp->errmsg = 0;
208         {
209                 dTHXs
211                 SvREADONLY_on(pp->svcurscr = perl_get_sv("curscr", TRUE));
212                 SvREADONLY_on(pp->svstart = perl_get_sv("VI::StartLine", TRUE));
213                 SvREADONLY_on(pp->svstop = perl_get_sv("VI::StopLine", TRUE));
214                 SvREADONLY_on(pp->svid = perl_get_sv("VI::ScreenId", TRUE));
215         }
216         return (0);
220  * perl_screen_end
221  *      Remove all refences to the screen to be destroyed
223  * PUBLIC: int perl_screen_end __P((SCR*));
224  */
226 perl_screen_end(scrp)
227         SCR *scrp;
229         dTHXs
231         if (scrp->perl_private) {
232                 sv_setiv((SV*) scrp->perl_private, 0);
233         }
234         return 0;
237 static void
238 my_sighandler(i)
239         int i;
241         croak("Perl command interrupted by SIGINT");
244 /* Create a new reference to an SV pointing to the SCR structure
245  * The perl_private part of the SCR structure points to the SV,
246  * so there can only be one such SV for a particular SCR structure.
247  * When the last reference has gone (DESTROY is called),
248  * perl_private is reset; When the screen goes away before
249  * all references are gone, the value of the SV is reset;
250  * any subsequent use of any of those reference will produce
251  * a warning. (see typemap)
252  */
253 static SV *
254 newVIrv(rv, screen)
255         SV *rv;
256         SCR *screen;
258         dTHXs
260         if (!screen) return sv_setsv(rv, &PL_sv_undef), rv;
261         sv_upgrade(rv, SVt_RV);
262         if (!screen->perl_private) {
263                 screen->perl_private = newSV(0);
264                 sv_setiv(screen->perl_private, (IV) screen);
265         } 
266         else SvREFCNT_inc(screen->perl_private);
267         SvRV(rv) = screen->perl_private;
268         SvROK_on(rv);
269         return sv_bless(rv, gv_stashpv("VI", TRUE));
273  * perl_setenv
274  *      Use perl's setenv if perl interpreter has been started.
275  *      Perl uses its own setenv and gets confused if we change
276  *      the environment after it has started.
278  * PUBLIC: int perl_setenv __P((SCR* sp, const char *name, const char *value));
279  */
281 perl_setenv(SCR* scrp, const char *name, const char *value)
283         if (scrp->wp->perl_private == NULL) {
284             if (value == NULL)
285                 unsetenv(name);
286             else
287                 setenv(name, value, 1);
288         } else
289             my_setenv(name, value);
293 /* 
294  * perl_ex_perl -- :[line [,line]] perl [command]
295  *      Run a command through the perl interpreter.
297  * PUBLIC: int perl_ex_perl __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
298  */
299 int 
300 perl_ex_perl(scrp, cmdp, cmdlen, f_lno, t_lno)
301         SCR *scrp;
302         CHAR_T *cmdp;
303         size_t cmdlen;
304         db_recno_t f_lno, t_lno;
306         WIN *wp;
307         size_t length;
308         size_t len;
309         char *err;
310         char *np;
311         size_t nlen;
312         Signal_t (*istat)();
313         perl_data_t *pp;
315         /* Initialize the interpreter. */
316         if (scrp->wp->perl_private == NULL && perl_init(scrp))
317                         return (1);
318         pp = scrp->wp->perl_private;
319     {
320         dTHXs
321         dSP;
323         sv_setiv(pp->svstart, f_lno);
324         sv_setiv(pp->svstop, t_lno);
325         newVIrv(pp->svcurscr, scrp);
326         /* Backwards compatibility. */
327         newVIrv(pp->svid, scrp);
329         istat = signal(SIGINT, my_sighandler);
330         INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
331         perl_eval(np);
332         signal(SIGINT, istat);
334         SvREFCNT_dec(SvRV(pp->svcurscr));
335         SvROK_off(pp->svcurscr);
336         SvREFCNT_dec(SvRV(pp->svid));
337         SvROK_off(pp->svid);
339         err = SvPV(ERRSV, length);
340         if (!length)
341                 return (0);
343         err[length - 1] = '\0';
344         msgq(scrp, M_ERR, "perl: %s", err);
345         return (1);
346     }
350  * replace_line
351  *      replace a line with the contents of the perl variable $_
352  *      lines are split at '\n's
353  *      if $_ is undef, the line is deleted
354  *      returns possibly adjusted linenumber
355  */
356 static int 
357 replace_line(scrp, line, t_lno, defsv)
358         SCR *scrp;
359         db_recno_t line, *t_lno;
360         SV *defsv;
362         char *str, *next;
363         CHAR_T *wp;
364         size_t len, wlen;
365         dTHXs
367         if (SvOK(defsv)) {
368                 str = SvPV(defsv,len);
369                 next = memchr(str, '\n', len);
370                 CHAR2INTP(scrp, str, next ? (next - str) : len, wp, wlen);
371                 api_sline(scrp, line, wp, wlen);
372                 while (next++) {
373                         len -= next - str;
374                         next = memchr(str = next, '\n', len);
375                         CHAR2INTP(scrp, str, next ? (next - str) : len, 
376                                     wp, wlen);
377                         api_iline(scrp, ++line, wp, wlen);
378                         (*t_lno)++;
379                 }
380         } else {
381                 api_dline(scrp, line--);
382                 (*t_lno)--;
383         }
384         return line;
387 /* 
388  * perl_ex_perldo -- :[line [,line]] perl [command]
389  *      Run a set of lines through the perl interpreter.
391  * PUBLIC: int perl_ex_perldo __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
392  */
393 int 
394 perl_ex_perldo(scrp, cmdp, cmdlen, f_lno, t_lno)
395         SCR *scrp;
396         CHAR_T *cmdp;
397         size_t cmdlen;
398         db_recno_t f_lno, t_lno;
400         CHAR_T *p;
401         WIN *wp;
402         size_t length;
403         size_t len;
404         db_recno_t i;
405         CHAR_T *str;
406         char *estr;
407         SV* cv;
408         char *command;
409         perl_data_t *pp;
410         char *np;
411         size_t nlen;
413         /* Initialize the interpreter. */
414         if (scrp->wp->perl_private == NULL && perl_init(scrp))
415                         return (1);
416         pp = scrp->wp->perl_private;
417     {
418         dTHXs
419         dSP;
421         newVIrv(pp->svcurscr, scrp);
422         /* Backwards compatibility. */
423         newVIrv(pp->svid, scrp);
425         INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
426         if (!(command = malloc(length = nlen - 1 + sizeof("sub {}"))))
427                 return 1;
428         snprintf(command, length, "sub {%s}", np);
430         ENTER;
431         SAVETMPS;
433         cv = perl_eval_pv(command, FALSE);
434         free (command);
436         estr = SvPV(ERRSV,length);
437         if (length)
438                 goto err;
440         for (i = f_lno; i <= t_lno && !api_gline(scrp, i, &str, &len); i++) {
441                 INT2CHAR(scrp, str, len, np, nlen);
442                 sv_setpvn(DEFSV,np,nlen);
443                 sv_setiv(pp->svstart, i);
444                 sv_setiv(pp->svstop, i);
445                 PUSHMARK(sp);
446                 perl_call_sv(cv, G_SCALAR | G_EVAL);
447                 estr = SvPV(ERRSV, length);
448                 if (length) break;
449                 SPAGAIN;
450                 if(SvTRUEx(POPs)) 
451                         i = replace_line(scrp, i, &t_lno, DEFSV);
452                 PUTBACK;
453         }
454         FREETMPS;
455         LEAVE;
457         SvREFCNT_dec(SvRV(pp->svcurscr));
458         SvROK_off(pp->svcurscr);
459         SvREFCNT_dec(SvRV(pp->svid));
460         SvROK_off(pp->svid);
462         if (!length)
463                 return (0);
465 err:    estr[length - 1] = '\0';
466         msgq(scrp, M_ERR, "perl: %s", estr);
467         return (1);
468     }
472  * msghandler --
473  *      Perl message routine so that error messages are processed in
474  *      Perl, not in nvi.
475  */
476 static void
477 msghandler(sp, mtype, msg, len)
478         SCR *sp;
479         mtype_t mtype;
480         char *msg;
481         size_t len;
483         char    *errmsg;
485         errmsg = PERLP(sp)->errmsg;
487         /* Replace the trailing <newline> with an EOS. */
488         /* Let's do that later instead */
489         if (errmsg) free (errmsg);
490         errmsg = malloc(len + 1);
491         memcpy(errmsg, msg, len);
492         errmsg[len] = '\0';
493         PERLP(sp)->errmsg = errmsg;
497 typedef SCR *   VI;
498 typedef SCR *   VI__OPT;
499 typedef SCR *   VI__MAP;
500 typedef SCR *   VI__MARK;
501 typedef SCR *   VI__LINE;
502 typedef AV *    AVREF;
504 typedef struct {
505     SV      *sprv;
506     TAGQ    *tqp;
507 } perl_tagq;
509 typedef perl_tagq *  VI__TAGQ;
510 typedef perl_tagq *  VI__TAGQ2;
512 MODULE = VI     PACKAGE = VI
514 # msg --
515 #       Set the message line to text.
517 # Perl Command: VI::Msg
518 # Usage: VI::Msg screenId text
520 void
521 Msg(screen, text)
522         VI          screen
523         char *      text
525         ALIAS:
526         PRINT = 1
528         CODE:
529         api_imessage(screen, text);
531 # XS_VI_escreen --
532 #       End a screen.
534 # Perl Command: VI::EndScreen
535 # Usage: VI::EndScreen screenId
537 void
538 EndScreen(screen)
539         VI      screen
541         PREINIT:
542         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
543         int rval;
545         CODE:
546         INITMESSAGE(screen);
547         rval = api_escreen(screen);
548         ENDMESSAGE(screen);
550 # XS_VI_iscreen --
551 #       Create a new screen.  If a filename is specified then the screen
552 #       is opened with that file.
554 # Perl Command: VI::NewScreen
555 # Usage: VI::NewScreen screenId [file]
558 Edit(screen, ...)
559         VI screen
561         ALIAS:
562         NewScreen = 1
564         PROTOTYPE: $;$
565         PREINIT:
566         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
567         int rval;
568         char *file;
569         SCR *nsp;
571         CODE:
572         file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
573         INITMESSAGE(screen);
574         rval = api_edit(screen, file, &nsp, ix);
575         ENDMESSAGE(screen);
576         
577         RETVAL = ix ? nsp : screen;
579         OUTPUT:
580         RETVAL
582 # XS_VI_fscreen --
583 #       Return the screen id associated with file name.
585 # Perl Command: VI::FindScreen
586 # Usage: VI::FindScreen file
589 FindScreen(file)
590         char *file
592         PREINIT:
593         SCR *fsp;
594         CODE:
595         RETVAL = api_fscreen(0, file);
597         OUTPUT:
598         RETVAL
600 # XS_VI_GetFileName --
601 #       Return the file name of the screen
603 # Perl Command: VI::GetFileName
604 # Usage: VI::GetFileName screenId
606 char *
607 GetFileName(screen)
608         VI screen;
610         PPCODE:
611         EXTEND(sp,1);
612         PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
614 # XS_VI_aline --
615 #       -- Append the string text after the line in lineNumber.
617 # Perl Command: VI::AppendLine
618 # Usage: VI::AppendLine screenId lineNumber text
620 void
621 AppendLine(screen, linenumber, text)
622         VI screen
623         int linenumber
624         char *text
626         PREINIT:
627         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
628         int rval;
629         size_t length;
631         CODE:
632         SvPV(ST(2), length);
633         INITMESSAGE(screen);
634         rval = api_aline(screen, linenumber, text, length);
635         ENDMESSAGE(screen);
637 # XS_VI_dline --
638 #       Delete lineNum.
640 # Perl Command: VI::DelLine
641 # Usage: VI::DelLine screenId lineNum
643 void 
644 DelLine(screen, linenumber)
645         VI screen
646         int linenumber
648         PREINIT:
649         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
650         int rval;
652         CODE:
653         INITMESSAGE(screen);
654         rval = api_dline(screen, (db_recno_t)linenumber);
655         ENDMESSAGE(screen);
657 # XS_VI_gline --
658 #       Return lineNumber.
660 # Perl Command: VI::GetLine
661 # Usage: VI::GetLine screenId lineNumber
663 char *
664 GetLine(screen, linenumber)
665         VI screen
666         int linenumber
668         PREINIT:
669         size_t len;
670         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
671         int rval;
672         char *line;
673         CHAR_T *p;
675         PPCODE:
676         INITMESSAGE(screen);
677         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
678         ENDMESSAGE(screen);
680         EXTEND(sp,1);
681         PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
683 # XS_VI_sline --
684 #       Set lineNumber to the text supplied.
686 # Perl Command: VI::SetLine
687 # Usage: VI::SetLine screenId lineNumber text
689 void
690 SetLine(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         size_t 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_sline(screen, linenumber, line, len);
707         ENDMESSAGE(screen);
709 # XS_VI_iline --
710 #       Insert the string text before the line in lineNumber.
712 # Perl Command: VI::InsertLine
713 # Usage: VI::InsertLine screenId lineNumber text
715 void
716 InsertLine(screen, linenumber, text)
717         VI screen
718         int linenumber
719         char *text
721         PREINIT:
722         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
723         int rval;
724         size_t length;
725         size_t len;
726         CHAR_T *line;
728         CODE:
729         SvPV(ST(2), length);
730         INITMESSAGE(screen);
731         CHAR2INTP(screen, text, length, line, len);
732         rval = api_iline(screen, linenumber, line, len);
733         ENDMESSAGE(screen);
735 # XS_VI_lline --
736 #       Return the last line in the screen.
738 # Perl Command: VI::LastLine
739 # Usage: VI::LastLine screenId
741 int 
742 LastLine(screen)
743         VI screen
745         PREINIT:
746         db_recno_t last;
747         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
748         int rval;
750         CODE:
751         INITMESSAGE(screen);
752         rval = api_lline(screen, &last);
753         ENDMESSAGE(screen);
754         RETVAL=last;
756         OUTPUT:
757         RETVAL
759 # XS_VI_getmark --
760 #       Return the mark's cursor position as a list with two elements.
761 #       {line, column}.
763 # Perl Command: VI::GetMark
764 # Usage: VI::GetMark screenId mark
766 void
767 GetMark(screen, mark)
768         VI screen
769         char mark
771         PREINIT:
772         struct _mark cursor;
773         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
774         int rval;
776         PPCODE:
777         INITMESSAGE(screen);
778         rval = api_getmark(screen, (int)mark, &cursor);
779         ENDMESSAGE(screen);
781         EXTEND(sp,2);
782         PUSHs(sv_2mortal(newSViv(cursor.lno)));
783         PUSHs(sv_2mortal(newSViv(cursor.cno)));
785 # XS_VI_setmark --
786 #       Set the mark to the line and column numbers supplied.
788 # Perl Command: VI::SetMark
789 # Usage: VI::SetMark screenId mark line column
791 void
792 SetMark(screen, mark, line, column)
793         VI screen
794         char mark
795         int line
796         int column
798         PREINIT:
799         struct _mark cursor;
800         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
801         int rval;
803         CODE:
804         INITMESSAGE(screen);
805         cursor.lno = line;
806         cursor.cno = column;
807         rval = api_setmark(screen, (int)mark, &cursor);
808         ENDMESSAGE(screen);
810 # XS_VI_getcursor --
811 #       Return the current cursor position as a list with two elements.
812 #       {line, column}.
814 # Perl Command: VI::GetCursor
815 # Usage: VI::GetCursor screenId
817 void
818 GetCursor(screen)
819         VI screen
821         PREINIT:
822         struct _mark cursor;
823         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
824         int rval;
826         PPCODE:
827         INITMESSAGE(screen);
828         rval = api_getcursor(screen, &cursor);
829         ENDMESSAGE(screen);
831         EXTEND(sp,2);
832         PUSHs(sv_2mortal(newSViv(cursor.lno)));
833         PUSHs(sv_2mortal(newSViv(cursor.cno)));
835 # XS_VI_setcursor --
836 #       Set the cursor to the line and column numbers supplied.
838 # Perl Command: VI::SetCursor
839 # Usage: VI::SetCursor screenId line column
841 void
842 SetCursor(screen, line, column)
843         VI screen
844         int line
845         int column
847         PREINIT:
848         struct _mark cursor;
849         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
850         int rval;
852         CODE:
853         INITMESSAGE(screen);
854         cursor.lno = line;
855         cursor.cno = column;
856         rval = api_setcursor(screen, &cursor);
857         ENDMESSAGE(screen);
859 # XS_VI_swscreen --
860 #       Change the current focus to screen.
862 # Perl Command: VI::SwitchScreen
863 # Usage: VI::SwitchScreen screenId screenId
865 void
866 SwitchScreen(screenFrom, screenTo)
867         VI screenFrom
868         VI screenTo
870         PREINIT:
871         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
872         int rval;
874         CODE:
875         INITMESSAGE(screenFrom);
876         rval = api_swscreen(screenFrom, screenTo);
877         ENDMESSAGE(screenFrom);
879 # XS_VI_map --
880 #       Associate a key with a perl procedure.
882 # Perl Command: VI::MapKey
883 # Usage: VI::MapKey screenId key perlproc
885 void
886 MapKey(screen, key, commandsv)
887         VI screen
888         char *key
889         SV *commandsv
891         PREINIT:
892         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
893         int rval;
894         int length;
895         char *command;
897         CODE:
898         INITMESSAGE(screen);
899         command = SvPV(commandsv, length);
900         rval = api_map(screen, key, command, length);
901         ENDMESSAGE(screen);
903 # XS_VI_unmap --
904 #       Unmap a key.
906 # Perl Command: VI::UnmapKey
907 # Usage: VI::UnmmapKey screenId key
909 void
910 UnmapKey(screen, key)
911         VI screen
912         char *key
914         PREINIT:
915         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
916         int rval;
918         CODE:
919         INITMESSAGE(screen);
920         rval = api_unmap(screen, key);
921         ENDMESSAGE(screen);
923 # XS_VI_opts_set --
924 #       Set an option.
926 # Perl Command: VI::SetOpt
927 # Usage: VI::SetOpt screenId setting
929 void
930 SetOpt(screen, setting)
931         VI screen
932         char *setting
934         PREINIT:
935         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
936         int rval;
937         SV *svc;
939         CODE:
940         INITMESSAGE(screen);
941         svc = sv_2mortal(newSVpv(":set ", 5));
942         sv_catpv(svc, setting);
943         rval = api_run_str(screen, SvPV(svc, PL_na));
944         ENDMESSAGE(screen);
946 # XS_VI_opts_get --
947 #       Return the value of an option.
948 #       
949 # Perl Command: VI::GetOpt
950 # Usage: VI::GetOpt screenId option
952 void
953 GetOpt(screen, option)
954         VI screen
955         char *option
957         PREINIT:
958         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
959         int rval;
960         char *value;
961         CHAR_T *wp;
962         size_t wlen;
964         PPCODE:
965         INITMESSAGE(screen);
966         CHAR2INTP(screen, option, strlen(option)+1, wp, wlen);
967         rval = api_opts_get(screen, wp, &value, NULL);
968         ENDMESSAGE(screen);
970         EXTEND(SP,1);
971         PUSHs(sv_2mortal(newSVpv(value, 0)));
972         free(value);
974 # XS_VI_run --
975 #       Run the ex command cmd.
977 # Perl Command: VI::Run
978 # Usage: VI::Run screenId cmd
980 void
981 Run(screen, command)
982         VI screen
983         char *command;
985         PREINIT:
986         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
987         int rval;
989         CODE:
990         INITMESSAGE(screen);
991         rval = api_run_str(screen, command);
992         ENDMESSAGE(screen);
994 void 
995 DESTROY(screensv)
996         SV* screensv
998         PREINIT:
999         VI  screen;
1001         CODE:
1002         if (sv_isa(screensv, "VI")) {
1003                 IV tmp = SvIV((SV*)SvRV(screensv));
1004                 screen = (SCR *) tmp;
1005         }
1006         else
1007                 croak("screen is not of type VI");
1009         if (screen)
1010         screen->perl_private = 0;
1012 void
1013 Warn(warning)
1014         char *warning;
1016         CODE:
1017         sv_catpv(ERRSV,warning);
1019 #define TIED(kind,package) \
1020         sv_magic((SV *) (var = \
1021             (kind##V *)sv_2mortal((SV *)new##kind##V())), \
1022                 sv_setref_pv(sv_newmortal(), package, \
1023                         newVIrv(newSV(0), screen)),\
1024                 'P', Nullch, 0);\
1025         RETVAL = newRV((SV *)var)
1027 SV *
1028 Opt(screen)
1029         VI screen;
1030         PREINIT:
1031         HV *var;
1032         CODE:
1033         TIED(H,"VI::OPT");
1034         OUTPUT:
1035         RETVAL
1037 SV *
1038 Map(screen)
1039         VI screen;
1040         PREINIT:
1041         HV *var;
1042         CODE:
1043         TIED(H,"VI::MAP");
1044         OUTPUT:
1045         RETVAL
1047 SV *
1048 Mark(screen)
1049         VI screen
1050         PREINIT:
1051         HV *var;
1052         CODE:
1053         TIED(H,"VI::MARK");
1054         OUTPUT:
1055         RETVAL
1057 SV *
1058 Line(screen)
1059         VI screen
1060         PREINIT:
1061         AV *var;
1062         CODE:
1063         TIED(A,"VI::LINE");
1064         OUTPUT:
1065         RETVAL
1067 SV *
1068 TagQ(screen, tag)
1069         VI screen
1070         char *tag;
1072         PREINIT:
1073         perl_tagq *ptag;
1075         PPCODE:
1076         if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1077                 goto err;
1079         ptag->sprv = newVIrv(newSV(0), screen);
1080         ptag->tqp = api_tagq_new(screen, tag);
1081         if (ptag->tqp != NULL) {
1082                 EXTEND(SP,1);
1083                 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1084         } else {
1085 err:
1086                 ST(0) = &PL_sv_undef;
1087                 return;
1088         }
1090 MODULE = VI     PACKAGE = VI::OPT
1092 void 
1093 DESTROY(screen)
1094         VI::OPT screen
1096         CODE:
1097         # typemap did all the checking
1098         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1100 void
1101 FETCH(screen, key)
1102         VI::OPT screen
1103         char *key
1105         PREINIT:
1106         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1107         int rval;
1108         char *value;
1109         int boolvalue;
1110         CHAR_T *wp;
1111         size_t wlen;
1113         PPCODE:
1114         INITMESSAGE(screen);
1115         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1116         rval = api_opts_get(screen, wp, &value, &boolvalue);
1117         if (!rval) {
1118                 EXTEND(SP,1);
1119                 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1120                                                    : newSViv(boolvalue)));
1121                 free(value);
1122         } else ST(0) = &PL_sv_undef;
1123         rval = 0;
1124         ENDMESSAGE(screen);
1126 void
1127 STORE(screen, key, value)
1128         VI::OPT screen
1129         char    *key
1130         SV      *value
1132         PREINIT:
1133         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1134         int rval;
1135         CHAR_T *wp;
1136         size_t wlen;
1138         CODE:
1139         INITMESSAGE(screen);
1140         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1141         rval = api_opts_set(screen, wp, SvPV(value, PL_na), SvIV(value), 
1142                                          SvTRUEx(value));
1143         ENDMESSAGE(screen);
1145 MODULE = VI     PACKAGE = VI::MAP
1147 void 
1148 DESTROY(screen)
1149         VI::MAP screen
1151         CODE:
1152         # typemap did all the checking
1153         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1155 void
1156 STORE(screen, key, commandsv)
1157         VI::MAP screen
1158         char *key
1159         SV *commandsv
1161         PREINIT:
1162         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1163         int rval;
1164         int length;
1165         char *command;
1167         CODE:
1168         INITMESSAGE(screen);
1169         command = SvPV(commandsv, length);
1170         rval = api_map(screen, key, command, length);
1171         ENDMESSAGE(screen);
1173 void
1174 DELETE(screen, key)
1175         VI::MAP screen
1176         char *key
1178         PREINIT:
1179         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1180         int rval;
1182         CODE:
1183         INITMESSAGE(screen);
1184         rval = api_unmap(screen, key);
1185         ENDMESSAGE(screen);
1187 MODULE = VI     PACKAGE = VI::MARK
1189 void 
1190 DESTROY(screen)
1191         VI::MARK screen
1193         CODE:
1194         # typemap did all the checking
1195         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1198 EXISTS(screen, mark)
1199         VI::MARK screen
1200         char mark
1202         PREINIT:
1203         struct _mark cursor;
1204         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1205         int rval = 0; /* never croak */
1206         int missing;
1208         CODE:
1209         INITMESSAGE(screen);
1210         missing = api_getmark(screen, (int)mark, &cursor);
1211         ENDMESSAGE(screen);
1212         RETVAL = !missing;
1214         OUTPUT:
1215         RETVAL
1217 AV *
1218 FETCH(screen, mark)
1219         VI::MARK screen
1220         char mark
1222         PREINIT:
1223         struct _mark cursor;
1224         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1225         int rval;
1227         CODE:
1228         INITMESSAGE(screen);
1229         rval = api_getmark(screen, (int)mark, &cursor);
1230         ENDMESSAGE(screen);
1231         RETVAL = newAV();
1232         av_push(RETVAL, newSViv(cursor.lno));
1233         av_push(RETVAL, newSViv(cursor.cno));
1235         OUTPUT:
1236         RETVAL
1238 void
1239 STORE(screen, mark, pos)
1240         VI::MARK screen
1241         char mark
1242         AVREF pos
1244         PREINIT:
1245         struct _mark cursor;
1246         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1247         int rval;
1249         CODE:
1250         if (av_len(pos) < 1) 
1251             croak("cursor position needs 2 elements");
1252         INITMESSAGE(screen);
1253         cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1254         cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1255         rval = api_setmark(screen, (int)mark, &cursor);
1256         ENDMESSAGE(screen);
1258 void
1259 FIRSTKEY(screen, ...)
1260         VI::MARK screen
1262         ALIAS:
1263         NEXTKEY = 1
1264         
1265         PROTOTYPE: $;$
1267         PREINIT:
1268         int next;
1269         char key[] = {0, 0};
1271         PPCODE:
1272         if (items == 2) {
1273                 next = 1;
1274                 *key = *(char *)SvPV(ST(1),PL_na);
1275         } else next = 0;
1276         if (api_nextmark(screen, next, key) != 1) {
1277                 EXTEND(sp, 1);
1278                 PUSHs(sv_2mortal(newSVpv(key, 1)));
1279         } else ST(0) = &PL_sv_undef;
1281 MODULE = VI     PACKAGE = VI::LINE
1283 void 
1284 DESTROY(screen)
1285         VI::LINE screen
1287         CODE:
1288         # typemap did all the checking
1289         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1291 # similar to SetLine
1293 void
1294 STORE(screen, linenumber, text)
1295         VI::LINE screen
1296         int linenumber
1297         char *text
1299         PREINIT:
1300         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1301         int rval;
1302         size_t length;
1303         db_recno_t last;
1304         size_t len;
1305         CHAR_T *line;
1307         CODE:
1308         ++linenumber;   /* vi 1 based ; perl 0 based */
1309         SvPV(ST(2), length);
1310         INITMESSAGE(screen);
1311         rval = api_lline(screen, &last);
1312         if (!rval) {
1313             if (linenumber > last)
1314                 rval = api_extend(screen, linenumber);
1315             if (!rval)
1316                 CHAR2INTP(screen, text, length, line, len);
1317                 rval = api_sline(screen, linenumber, line, len);
1318         }
1319         ENDMESSAGE(screen);
1321 # similar to GetLine 
1323 char *
1324 FETCH(screen, linenumber)
1325         VI::LINE screen
1326         int linenumber
1328         PREINIT:
1329         size_t len;
1330         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1331         int rval;
1332         char *line;
1333         CHAR_T *p;
1335         PPCODE:
1336         ++linenumber;   /* vi 1 based ; perl 0 based */
1337         INITMESSAGE(screen);
1338         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1339         ENDMESSAGE(screen);
1341         EXTEND(sp,1);
1342         PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1344 # similar to LastLine 
1347 FETCHSIZE(screen)
1348         VI::LINE screen
1350         PREINIT:
1351         db_recno_t last;
1352         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1353         int rval;
1355         CODE:
1356         INITMESSAGE(screen);
1357         rval = api_lline(screen, &last);
1358         ENDMESSAGE(screen);
1359         RETVAL=last;
1361         OUTPUT:
1362         RETVAL
1364 void
1365 STORESIZE(screen, count)
1366         VI::LINE screen
1367         int count
1369         PREINIT:
1370         db_recno_t last;
1371         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1372         int rval;
1374         CODE:
1375         INITMESSAGE(screen);
1376         rval = api_lline(screen, &last);
1377         if (!rval) {
1378             if (count > last)
1379                 rval = api_extend(screen, count);
1380             else while(last && last > count) {
1381                 rval = api_dline(screen, last--);
1382                 if (rval) break;
1383             }
1384         }
1385         ENDMESSAGE(screen);
1387 void
1388 EXTEND(screen, count)
1389         VI::LINE screen
1390         int count
1392         CODE:
1394 void
1395 CLEAR(screen)
1396         VI::LINE screen
1398         PREINIT:
1399         db_recno_t last;
1400         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1401         int rval;
1403         CODE:
1404         INITMESSAGE(screen);
1405         rval = api_lline(screen, &last);
1406         if (!rval) {
1407             while(last) {
1408                 rval = api_dline(screen, last--);
1409                 if (rval) break;
1410             }
1411         }
1412         ENDMESSAGE(screen);
1414 void
1415 PUSH(screen, ...)
1416         VI::LINE screen;
1418         PREINIT:
1419         db_recno_t last;
1420         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1421         int rval, i, len;
1422         char *line;
1424         CODE:
1425         INITMESSAGE(screen);
1426         rval = api_lline(screen, &last);
1428         if (!rval)
1429                 for (i = 1; i < items; ++i) {
1430                         line = SvPV(ST(i), len);
1431                         if ((rval = api_aline(screen, last++, line, len)))
1432                                 break;
1433                 }
1434         ENDMESSAGE(screen);
1436 SV *
1437 POP(screen)
1438         VI::LINE screen;
1440         PREINIT:
1441         db_recno_t last;
1442         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1443         int rval, i, len;
1444         CHAR_T *line;
1446         PPCODE:
1447         INITMESSAGE(screen);
1448         rval = api_lline(screen, &last);
1449         if (rval || last < 1)
1450                 ST(0) = &PL_sv_undef;
1451         else {
1452                 rval = api_gline(screen, last, &line, &len) ||
1453                        api_dline(screen, last);
1454                 EXTEND(sp,1);
1455                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1456         }
1457         ENDMESSAGE(screen);
1459 SV *
1460 SHIFT(screen)
1461         VI::LINE screen;
1463         PREINIT:
1464         db_recno_t last;
1465         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1466         int rval, i, len;
1467         CHAR_T *line;
1469         PPCODE:
1470         INITMESSAGE(screen);
1471         rval = api_lline(screen, &last);
1472         if (rval || last < 1)
1473                 ST(0) = &PL_sv_undef;
1474         else {
1475                 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1476                        api_dline(screen, (db_recno_t)1);
1477                 EXTEND(sp,1);
1478                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1479         }
1480         ENDMESSAGE(screen);
1482 void
1483 UNSHIFT(screen, ...)
1484         VI::LINE screen;
1486         PREINIT:
1487         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1488         int rval, i, len;
1489         char *np;
1490         size_t nlen;
1491         CHAR_T *line;
1493         CODE:
1494         INITMESSAGE(screen);
1495         while (--items != 0) {
1496                 np = SvPV(ST(items), nlen);
1497                 CHAR2INTP(screen, np, nlen, line, len);
1498                 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1499                         break;
1500         }
1501         ENDMESSAGE(screen);
1503 void
1504 SPLICE(screen, ...)
1505         VI::LINE screen;
1507         PREINIT:
1508         db_recno_t last, db_offset;
1509         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1510         int rval, length, common, len, i, offset;
1511         CHAR_T *line;
1512         char *np;
1513         size_t nlen;
1515         PPCODE:
1516         INITMESSAGE(screen);
1517         rval = api_lline(screen, &last);
1518         offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1519         if (offset < 0) offset += last;
1520         if (offset < 0) {
1521             ENDMESSAGE(screen);
1522             croak("Invalid offset");
1523         }
1524         length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1525         if (length > last - offset)
1526                 length = last - offset;
1527         db_offset = offset + 1; /* 1 based */
1528         EXTEND(sp,length);
1529         for (common = MIN(length, items - 3), i = 3; common > 0; 
1530             --common, ++db_offset, --length, ++i) {
1531                 rval |= api_gline(screen, db_offset, &line, &len);
1532                 INT2CHAR(screen, line, len, np, nlen);
1533                 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1534                 np = SvPV(ST(i), nlen);
1535                 CHAR2INTP(screen, np, nlen, line, len);
1536                 rval |= api_sline(screen, db_offset, line, len);
1537         }
1538         for (; length; --length) {
1539                 rval |= api_gline(screen, db_offset, &line, &len);
1540                 INT2CHAR(screen, line, len, np, nlen);
1541                 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1542                 rval |= api_dline(screen, db_offset);
1543         }
1544         for (; i < items; ++i) {
1545                 np = SvPV(ST(i), len);
1546                 CHAR2INTP(screen, np, len, line, nlen);
1547                 rval |= api_iline(screen, db_offset, line, nlen);
1548         }
1549         ENDMESSAGE(screen);
1551 MODULE = VI     PACKAGE = VI::TAGQ
1553 void
1554 Add(tagq, filename, search, msg)
1555         VI::TAGQ    tagq;
1556         char       *filename;
1557         char       *search;
1558         char       *msg;
1560         PREINIT:
1561         SCR *sp;
1563         CODE:
1564         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1565         if (!sp)
1566                 croak("screen no longer exists");
1567         api_tagq_add(sp, tagq->tqp, filename, search, msg);
1569 void
1570 Push(tagq)
1571         VI::TAGQ    tagq;
1573         PREINIT:
1574         SCR *sp;
1576         CODE:
1577         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1578         if (!sp)
1579                 croak("screen no longer exists");
1580         api_tagq_push(sp, &tagq->tqp);
1582 void
1583 DESTROY(tagq)
1584         # Can already be invalidated by push 
1585         VI::TAGQ2    tagq; 
1587         PREINIT:
1588         SCR *sp;
1590         CODE:
1591         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1592         if (sp)
1593                 api_tagq_free(sp, tagq->tqp);
1594         SvREFCNT_dec(tagq->sprv);
1595         free(tagq);