common/log.c: minor whitespace change
[nvi.git] / perl_api / perl.xs
blob076a61edcebb664ddc6b8e00504ef1a176704524
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 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  * perl_setenv
273  *      Use perl's setenv if perl interpreter has been started.
274  *      Perl uses its own setenv and gets confused if we change
275  *      the environment after it has started.
277  * PUBLIC: int perl_setenv __P((SCR* sp, const char *name, const char *value));
278  */
280 perl_setenv(SCR* scrp, const char *name, const char *value)
282         if (scrp->wp->perl_private == NULL) {
283             if (value == NULL)
284                 unsetenv(name);
285             else
286                 setenv(name, value, 1);
287         } else
288             my_setenv(name, value);
292 /* 
293  * perl_ex_perl -- :[line [,line]] perl [command]
294  *      Run a command through the perl interpreter.
296  * PUBLIC: int perl_ex_perl __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
297  */
298 int 
299 perl_ex_perl(scrp, cmdp, cmdlen, f_lno, t_lno)
300         SCR *scrp;
301         CHAR_T *cmdp;
302         size_t cmdlen;
303         db_recno_t f_lno, t_lno;
305         WIN *wp;
306         size_t length;
307         size_t len;
308         char *err;
309         char *np;
310         size_t nlen;
311         Signal_t (*istat)();
312         perl_data_t *pp;
314         /* Initialize the interpreter. */
315         if (scrp->wp->perl_private == NULL && perl_init(scrp))
316                         return (1);
317         pp = scrp->wp->perl_private;
318     {
319         dTHXs
320         dSP;
322         sv_setiv(pp->svstart, f_lno);
323         sv_setiv(pp->svstop, t_lno);
324         newVIrv(pp->svcurscr, scrp);
325         /* Backwards compatibility. */
326         newVIrv(pp->svid, scrp);
328         istat = signal(SIGINT, my_sighandler);
329         INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
330         perl_eval(np);
331         signal(SIGINT, istat);
333         SvREFCNT_dec(SvRV(pp->svcurscr));
334         SvROK_off(pp->svcurscr);
335         SvREFCNT_dec(SvRV(pp->svid));
336         SvROK_off(pp->svid);
338         err = SvPV(ERRSV, length);
339         if (!length)
340                 return (0);
342         err[length - 1] = '\0';
343         msgq(scrp, M_ERR, "perl: %s", err);
344         return (1);
345     }
349  * replace_line
350  *      replace a line with the contents of the perl variable $_
351  *      lines are split at '\n's
352  *      if $_ is undef, the line is deleted
353  *      returns possibly adjusted linenumber
354  */
355 static int 
356 replace_line(scrp, line, t_lno, defsv)
357         SCR *scrp;
358         db_recno_t line, *t_lno;
359         SV *defsv;
361         char *str, *next;
362         CHAR_T *wp;
363         size_t len, wlen;
364         dTHXs
366         if (SvOK(defsv)) {
367                 str = SvPV(defsv,len);
368                 next = memchr(str, '\n', len);
369                 CHAR2INTP(scrp, str, next ? (next - str) : len, wp, wlen);
370                 api_sline(scrp, line, wp, wlen);
371                 while (next++) {
372                         len -= next - str;
373                         next = memchr(str = next, '\n', len);
374                         CHAR2INTP(scrp, str, next ? (next - str) : len, 
375                                     wp, wlen);
376                         api_iline(scrp, ++line, wp, wlen);
377                         (*t_lno)++;
378                 }
379         } else {
380                 api_dline(scrp, line--);
381                 (*t_lno)--;
382         }
383         return line;
386 /* 
387  * perl_ex_perldo -- :[line [,line]] perl [command]
388  *      Run a set of lines through the perl interpreter.
390  * PUBLIC: int perl_ex_perldo __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
391  */
392 int 
393 perl_ex_perldo(scrp, cmdp, cmdlen, f_lno, t_lno)
394         SCR *scrp;
395         CHAR_T *cmdp;
396         size_t cmdlen;
397         db_recno_t f_lno, t_lno;
399         CHAR_T *p;
400         WIN *wp;
401         size_t length;
402         size_t len;
403         db_recno_t i;
404         CHAR_T *str;
405         char *estr;
406         SV* cv;
407         char *command;
408         perl_data_t *pp;
409         char *np;
410         size_t nlen;
412         /* Initialize the interpreter. */
413         if (scrp->wp->perl_private == NULL && perl_init(scrp))
414                         return (1);
415         pp = scrp->wp->perl_private;
416     {
417         dTHXs
418         dSP;
420         newVIrv(pp->svcurscr, scrp);
421         /* Backwards compatibility. */
422         newVIrv(pp->svid, scrp);
424         INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
425         if (!(command = malloc(length = nlen - 1 + sizeof("sub {}"))))
426                 return 1;
427         snprintf(command, length, "sub {%s}", np);
429         ENTER;
430         SAVETMPS;
432         cv = perl_eval_pv(command, FALSE);
433         free (command);
435         estr = SvPV(ERRSV,length);
436         if (length)
437                 goto err;
439         for (i = f_lno; i <= t_lno && !api_gline(scrp, i, &str, &len); i++) {
440                 INT2CHAR(scrp, str, len, np, nlen);
441                 sv_setpvn(DEFSV,np,nlen);
442                 sv_setiv(pp->svstart, i);
443                 sv_setiv(pp->svstop, i);
444                 PUSHMARK(sp);
445                 perl_call_sv(cv, G_SCALAR | G_EVAL);
446                 estr = SvPV(ERRSV, length);
447                 if (length) break;
448                 SPAGAIN;
449                 if(SvTRUEx(POPs)) 
450                         i = replace_line(scrp, i, &t_lno, DEFSV);
451                 PUTBACK;
452         }
453         FREETMPS;
454         LEAVE;
456         SvREFCNT_dec(SvRV(pp->svcurscr));
457         SvROK_off(pp->svcurscr);
458         SvREFCNT_dec(SvRV(pp->svid));
459         SvROK_off(pp->svid);
461         if (!length)
462                 return (0);
464 err:    estr[length - 1] = '\0';
465         msgq(scrp, M_ERR, "perl: %s", estr);
466         return (1);
467     }
471  * msghandler --
472  *      Perl message routine so that error messages are processed in
473  *      Perl, not in nvi.
474  */
475 static void
476 msghandler(sp, mtype, msg, len)
477         SCR *sp;
478         mtype_t mtype;
479         char *msg;
480         size_t len;
482         char    *errmsg;
484         errmsg = PERLP(sp)->errmsg;
486         /* Replace the trailing <newline> with an EOS. */
487         /* Let's do that later instead */
488         if (errmsg) free (errmsg);
489         errmsg = malloc(len + 1);
490         memcpy(errmsg, msg, len);
491         errmsg[len] = '\0';
492         PERLP(sp)->errmsg = errmsg;
496 typedef SCR *   VI;
497 typedef SCR *   VI__OPT;
498 typedef SCR *   VI__MAP;
499 typedef SCR *   VI__MARK;
500 typedef SCR *   VI__LINE;
501 typedef AV *    AVREF;
503 typedef struct {
504     SV      *sprv;
505     TAGQ    *tqp;
506 } perl_tagq;
508 typedef perl_tagq *  VI__TAGQ;
509 typedef perl_tagq *  VI__TAGQ2;
511 MODULE = VI     PACKAGE = VI
513 # msg --
514 #       Set the message line to text.
516 # Perl Command: VI::Msg
517 # Usage: VI::Msg screenId text
519 void
520 Msg(screen, text)
521         VI          screen
522         char *      text
524         ALIAS:
525         PRINT = 1
527         CODE:
528         api_imessage(screen, text);
530 # XS_VI_escreen --
531 #       End a screen.
533 # Perl Command: VI::EndScreen
534 # Usage: VI::EndScreen screenId
536 void
537 EndScreen(screen)
538         VI      screen
540         PREINIT:
541         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
542         int rval;
544         CODE:
545         INITMESSAGE(screen);
546         rval = api_escreen(screen);
547         ENDMESSAGE(screen);
549 # XS_VI_iscreen --
550 #       Create a new screen.  If a filename is specified then the screen
551 #       is opened with that file.
553 # Perl Command: VI::NewScreen
554 # Usage: VI::NewScreen screenId [file]
557 Edit(screen, ...)
558         VI screen
560         ALIAS:
561         NewScreen = 1
563         PROTOTYPE: $;$
564         PREINIT:
565         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
566         int rval;
567         char *file;
568         SCR *nsp;
570         CODE:
571         file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
572         INITMESSAGE(screen);
573         rval = api_edit(screen, file, &nsp, ix);
574         ENDMESSAGE(screen);
575         
576         RETVAL = ix ? nsp : screen;
578         OUTPUT:
579         RETVAL
581 # XS_VI_fscreen --
582 #       Return the screen id associated with file name.
584 # Perl Command: VI::FindScreen
585 # Usage: VI::FindScreen file
588 FindScreen(file)
589         char *file
591         PREINIT:
592         SCR *fsp;
593         CODE:
594         RETVAL = api_fscreen(0, file);
596         OUTPUT:
597         RETVAL
599 # XS_VI_GetFileName --
600 #       Return the file name of the screen
602 # Perl Command: VI::GetFileName
603 # Usage: VI::GetFileName screenId
605 char *
606 GetFileName(screen)
607         VI screen;
609         PPCODE:
610         EXTEND(sp,1);
611         PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
613 # XS_VI_aline --
614 #       -- Append the string text after the line in lineNumber.
616 # Perl Command: VI::AppendLine
617 # Usage: VI::AppendLine screenId lineNumber text
619 void
620 AppendLine(screen, linenumber, text)
621         VI screen
622         int linenumber
623         char *text
625         PREINIT:
626         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
627         int rval;
628         size_t length;
630         CODE:
631         SvPV(ST(2), length);
632         INITMESSAGE(screen);
633         rval = api_aline(screen, linenumber, text, length);
634         ENDMESSAGE(screen);
636 # XS_VI_dline --
637 #       Delete lineNum.
639 # Perl Command: VI::DelLine
640 # Usage: VI::DelLine screenId lineNum
642 void 
643 DelLine(screen, linenumber)
644         VI screen
645         int linenumber
647         PREINIT:
648         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
649         int rval;
651         CODE:
652         INITMESSAGE(screen);
653         rval = api_dline(screen, (db_recno_t)linenumber);
654         ENDMESSAGE(screen);
656 # XS_VI_gline --
657 #       Return lineNumber.
659 # Perl Command: VI::GetLine
660 # Usage: VI::GetLine screenId lineNumber
662 char *
663 GetLine(screen, linenumber)
664         VI screen
665         int linenumber
667         PREINIT:
668         size_t len;
669         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
670         int rval;
671         char *line;
672         CHAR_T *p;
674         PPCODE:
675         INITMESSAGE(screen);
676         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
677         ENDMESSAGE(screen);
679         EXTEND(sp,1);
680         PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
682 # XS_VI_sline --
683 #       Set lineNumber to the text supplied.
685 # Perl Command: VI::SetLine
686 # Usage: VI::SetLine screenId lineNumber text
688 void
689 SetLine(screen, linenumber, text)
690         VI screen
691         int linenumber
692         char *text
694         PREINIT:
695         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
696         int rval;
697         size_t length;
698         size_t len;
699         CHAR_T *line;
701         CODE:
702         SvPV(ST(2), length);
703         INITMESSAGE(screen);
704         CHAR2INTP(screen, text, length, line, len);
705         rval = api_sline(screen, linenumber, line, len);
706         ENDMESSAGE(screen);
708 # XS_VI_iline --
709 #       Insert the string text before the line in lineNumber.
711 # Perl Command: VI::InsertLine
712 # Usage: VI::InsertLine screenId lineNumber text
714 void
715 InsertLine(screen, linenumber, text)
716         VI screen
717         int linenumber
718         char *text
720         PREINIT:
721         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
722         int rval;
723         size_t length;
724         size_t len;
725         CHAR_T *line;
727         CODE:
728         SvPV(ST(2), length);
729         INITMESSAGE(screen);
730         CHAR2INTP(screen, text, length, line, len);
731         rval = api_iline(screen, linenumber, line, len);
732         ENDMESSAGE(screen);
734 # XS_VI_lline --
735 #       Return the last line in the screen.
737 # Perl Command: VI::LastLine
738 # Usage: VI::LastLine screenId
740 int 
741 LastLine(screen)
742         VI screen
744         PREINIT:
745         db_recno_t last;
746         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
747         int rval;
749         CODE:
750         INITMESSAGE(screen);
751         rval = api_lline(screen, &last);
752         ENDMESSAGE(screen);
753         RETVAL=last;
755         OUTPUT:
756         RETVAL
758 # XS_VI_getmark --
759 #       Return the mark's cursor position as a list with two elements.
760 #       {line, column}.
762 # Perl Command: VI::GetMark
763 # Usage: VI::GetMark screenId mark
765 void
766 GetMark(screen, mark)
767         VI screen
768         char mark
770         PREINIT:
771         struct _mark cursor;
772         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
773         int rval;
775         PPCODE:
776         INITMESSAGE(screen);
777         rval = api_getmark(screen, (int)mark, &cursor);
778         ENDMESSAGE(screen);
780         EXTEND(sp,2);
781         PUSHs(sv_2mortal(newSViv(cursor.lno)));
782         PUSHs(sv_2mortal(newSViv(cursor.cno)));
784 # XS_VI_setmark --
785 #       Set the mark to the line and column numbers supplied.
787 # Perl Command: VI::SetMark
788 # Usage: VI::SetMark screenId mark line column
790 void
791 SetMark(screen, mark, line, column)
792         VI screen
793         char mark
794         int line
795         int column
797         PREINIT:
798         struct _mark cursor;
799         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
800         int rval;
802         CODE:
803         INITMESSAGE(screen);
804         cursor.lno = line;
805         cursor.cno = column;
806         rval = api_setmark(screen, (int)mark, &cursor);
807         ENDMESSAGE(screen);
809 # XS_VI_getcursor --
810 #       Return the current cursor position as a list with two elements.
811 #       {line, column}.
813 # Perl Command: VI::GetCursor
814 # Usage: VI::GetCursor screenId
816 void
817 GetCursor(screen)
818         VI screen
820         PREINIT:
821         struct _mark cursor;
822         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
823         int rval;
825         PPCODE:
826         INITMESSAGE(screen);
827         rval = api_getcursor(screen, &cursor);
828         ENDMESSAGE(screen);
830         EXTEND(sp,2);
831         PUSHs(sv_2mortal(newSViv(cursor.lno)));
832         PUSHs(sv_2mortal(newSViv(cursor.cno)));
834 # XS_VI_setcursor --
835 #       Set the cursor to the line and column numbers supplied.
837 # Perl Command: VI::SetCursor
838 # Usage: VI::SetCursor screenId line column
840 void
841 SetCursor(screen, line, column)
842         VI screen
843         int line
844         int column
846         PREINIT:
847         struct _mark cursor;
848         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
849         int rval;
851         CODE:
852         INITMESSAGE(screen);
853         cursor.lno = line;
854         cursor.cno = column;
855         rval = api_setcursor(screen, &cursor);
856         ENDMESSAGE(screen);
858 # XS_VI_swscreen --
859 #       Change the current focus to screen.
861 # Perl Command: VI::SwitchScreen
862 # Usage: VI::SwitchScreen screenId screenId
864 void
865 SwitchScreen(screenFrom, screenTo)
866         VI screenFrom
867         VI screenTo
869         PREINIT:
870         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
871         int rval;
873         CODE:
874         INITMESSAGE(screenFrom);
875         rval = api_swscreen(screenFrom, screenTo);
876         ENDMESSAGE(screenFrom);
878 # XS_VI_map --
879 #       Associate a key with a perl procedure.
881 # Perl Command: VI::MapKey
882 # Usage: VI::MapKey screenId key perlproc
884 void
885 MapKey(screen, key, commandsv)
886         VI screen
887         char *key
888         SV *commandsv
890         PREINIT:
891         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
892         int rval;
893         int length;
894         char *command;
896         CODE:
897         INITMESSAGE(screen);
898         command = SvPV(commandsv, length);
899         rval = api_map(screen, key, command, length);
900         ENDMESSAGE(screen);
902 # XS_VI_unmap --
903 #       Unmap a key.
905 # Perl Command: VI::UnmapKey
906 # Usage: VI::UnmmapKey screenId key
908 void
909 UnmapKey(screen, key)
910         VI screen
911         char *key
913         PREINIT:
914         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
915         int rval;
917         CODE:
918         INITMESSAGE(screen);
919         rval = api_unmap(screen, key);
920         ENDMESSAGE(screen);
922 # XS_VI_opts_set --
923 #       Set an option.
925 # Perl Command: VI::SetOpt
926 # Usage: VI::SetOpt screenId setting
928 void
929 SetOpt(screen, setting)
930         VI screen
931         char *setting
933         PREINIT:
934         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
935         int rval;
936         SV *svc;
938         CODE:
939         INITMESSAGE(screen);
940         svc = sv_2mortal(newSVpv(":set ", 5));
941         sv_catpv(svc, setting);
942         rval = api_run_str(screen, SvPV(svc, PL_na));
943         ENDMESSAGE(screen);
945 # XS_VI_opts_get --
946 #       Return the value of an option.
947 #       
948 # Perl Command: VI::GetOpt
949 # Usage: VI::GetOpt screenId option
951 void
952 GetOpt(screen, option)
953         VI screen
954         char *option
956         PREINIT:
957         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
958         int rval;
959         char *value;
960         CHAR_T *wp;
961         size_t wlen;
963         PPCODE:
964         INITMESSAGE(screen);
965         CHAR2INTP(screen, option, strlen(option)+1, wp, wlen);
966         rval = api_opts_get(screen, wp, &value, NULL);
967         ENDMESSAGE(screen);
969         EXTEND(SP,1);
970         PUSHs(sv_2mortal(newSVpv(value, 0)));
971         free(value);
973 # XS_VI_run --
974 #       Run the ex command cmd.
976 # Perl Command: VI::Run
977 # Usage: VI::Run screenId cmd
979 void
980 Run(screen, command)
981         VI screen
982         char *command;
984         PREINIT:
985         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
986         int rval;
988         CODE:
989         INITMESSAGE(screen);
990         rval = api_run_str(screen, command);
991         ENDMESSAGE(screen);
993 void 
994 DESTROY(screensv)
995         SV* screensv
997         PREINIT:
998         VI  screen;
1000         CODE:
1001         if (sv_isa(screensv, "VI")) {
1002                 IV tmp = SvIV((SV*)SvRV(screensv));
1003                 screen = (SCR *) tmp;
1004         }
1005         else
1006                 croak("screen is not of type VI");
1008         if (screen)
1009         screen->perl_private = 0;
1011 void
1012 Warn(warning)
1013         char *warning;
1015         CODE:
1016         sv_catpv(ERRSV,warning);
1018 #define TIED(kind,package) \
1019         sv_magic((SV *) (var = \
1020             (kind##V *)sv_2mortal((SV *)new##kind##V())), \
1021                 sv_setref_pv(sv_newmortal(), package, \
1022                         newVIrv(newSV(0), screen)),\
1023                 'P', Nullch, 0);\
1024         RETVAL = newRV((SV *)var)
1026 SV *
1027 Opt(screen)
1028         VI screen;
1029         PREINIT:
1030         HV *var;
1031         CODE:
1032         TIED(H,"VI::OPT");
1033         OUTPUT:
1034         RETVAL
1036 SV *
1037 Map(screen)
1038         VI screen;
1039         PREINIT:
1040         HV *var;
1041         CODE:
1042         TIED(H,"VI::MAP");
1043         OUTPUT:
1044         RETVAL
1046 SV *
1047 Mark(screen)
1048         VI screen
1049         PREINIT:
1050         HV *var;
1051         CODE:
1052         TIED(H,"VI::MARK");
1053         OUTPUT:
1054         RETVAL
1056 SV *
1057 Line(screen)
1058         VI screen
1059         PREINIT:
1060         AV *var;
1061         CODE:
1062         TIED(A,"VI::LINE");
1063         OUTPUT:
1064         RETVAL
1066 SV *
1067 TagQ(screen, tag)
1068         VI screen
1069         char *tag;
1071         PREINIT:
1072         perl_tagq *ptag;
1074         PPCODE:
1075         if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1076                 goto err;
1078         ptag->sprv = newVIrv(newSV(0), screen);
1079         ptag->tqp = api_tagq_new(screen, tag);
1080         if (ptag->tqp != NULL) {
1081                 EXTEND(SP,1);
1082                 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1083         } else {
1084 err:
1085                 ST(0) = &PL_sv_undef;
1086                 return;
1087         }
1089 MODULE = VI     PACKAGE = VI::OPT
1091 void 
1092 DESTROY(screen)
1093         VI::OPT screen
1095         CODE:
1096         # typemap did all the checking
1097         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1099 void
1100 FETCH(screen, key)
1101         VI::OPT screen
1102         char *key
1104         PREINIT:
1105         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1106         int rval;
1107         char *value;
1108         int boolvalue;
1109         CHAR_T *wp;
1110         size_t wlen;
1112         PPCODE:
1113         INITMESSAGE(screen);
1114         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1115         rval = api_opts_get(screen, wp, &value, &boolvalue);
1116         if (!rval) {
1117                 EXTEND(SP,1);
1118                 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1119                                                    : newSViv(boolvalue)));
1120                 free(value);
1121         } else ST(0) = &PL_sv_undef;
1122         rval = 0;
1123         ENDMESSAGE(screen);
1125 void
1126 STORE(screen, key, value)
1127         VI::OPT screen
1128         char    *key
1129         SV      *value
1131         PREINIT:
1132         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1133         int rval;
1134         CHAR_T *wp;
1135         size_t wlen;
1137         CODE:
1138         INITMESSAGE(screen);
1139         CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1140         rval = api_opts_set(screen, wp, SvPV(value, PL_na), SvIV(value), 
1141                                          SvTRUEx(value));
1142         ENDMESSAGE(screen);
1144 MODULE = VI     PACKAGE = VI::MAP
1146 void 
1147 DESTROY(screen)
1148         VI::MAP screen
1150         CODE:
1151         # typemap did all the checking
1152         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1154 void
1155 STORE(screen, key, commandsv)
1156         VI::MAP screen
1157         char *key
1158         SV *commandsv
1160         PREINIT:
1161         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1162         int rval;
1163         int length;
1164         char *command;
1166         CODE:
1167         INITMESSAGE(screen);
1168         command = SvPV(commandsv, length);
1169         rval = api_map(screen, key, command, length);
1170         ENDMESSAGE(screen);
1172 void
1173 DELETE(screen, key)
1174         VI::MAP screen
1175         char *key
1177         PREINIT:
1178         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1179         int rval;
1181         CODE:
1182         INITMESSAGE(screen);
1183         rval = api_unmap(screen, key);
1184         ENDMESSAGE(screen);
1186 MODULE = VI     PACKAGE = VI::MARK
1188 void 
1189 DESTROY(screen)
1190         VI::MARK screen
1192         CODE:
1193         # typemap did all the checking
1194         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1197 EXISTS(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 = 0; /* never croak */
1205         int missing;
1207         CODE:
1208         INITMESSAGE(screen);
1209         missing = api_getmark(screen, (int)mark, &cursor);
1210         ENDMESSAGE(screen);
1211         RETVAL = !missing;
1213         OUTPUT:
1214         RETVAL
1216 AV *
1217 FETCH(screen, mark)
1218         VI::MARK screen
1219         char mark
1221         PREINIT:
1222         struct _mark cursor;
1223         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1224         int rval;
1226         CODE:
1227         INITMESSAGE(screen);
1228         rval = api_getmark(screen, (int)mark, &cursor);
1229         ENDMESSAGE(screen);
1230         RETVAL = newAV();
1231         av_push(RETVAL, newSViv(cursor.lno));
1232         av_push(RETVAL, newSViv(cursor.cno));
1234         OUTPUT:
1235         RETVAL
1237 void
1238 STORE(screen, mark, pos)
1239         VI::MARK screen
1240         char mark
1241         AVREF pos
1243         PREINIT:
1244         struct _mark cursor;
1245         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1246         int rval;
1248         CODE:
1249         if (av_len(pos) < 1) 
1250             croak("cursor position needs 2 elements");
1251         INITMESSAGE(screen);
1252         cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1253         cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1254         rval = api_setmark(screen, (int)mark, &cursor);
1255         ENDMESSAGE(screen);
1257 void
1258 FIRSTKEY(screen, ...)
1259         VI::MARK screen
1261         ALIAS:
1262         NEXTKEY = 1
1263         
1264         PROTOTYPE: $;$
1266         PREINIT:
1267         int next;
1268         char key[] = {0, 0};
1270         PPCODE:
1271         if (items == 2) {
1272                 next = 1;
1273                 *key = *(char *)SvPV(ST(1),PL_na);
1274         } else next = 0;
1275         if (api_nextmark(screen, next, key) != 1) {
1276                 EXTEND(sp, 1);
1277                 PUSHs(sv_2mortal(newSVpv(key, 1)));
1278         } else ST(0) = &PL_sv_undef;
1280 MODULE = VI     PACKAGE = VI::LINE
1282 void 
1283 DESTROY(screen)
1284         VI::LINE screen
1286         CODE:
1287         # typemap did all the checking
1288         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1290 # similar to SetLine
1292 void
1293 STORE(screen, linenumber, text)
1294         VI::LINE screen
1295         int linenumber
1296         char *text
1298         PREINIT:
1299         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1300         int rval;
1301         size_t length;
1302         db_recno_t last;
1303         size_t len;
1304         CHAR_T *line;
1306         CODE:
1307         ++linenumber;   /* vi 1 based ; perl 0 based */
1308         SvPV(ST(2), length);
1309         INITMESSAGE(screen);
1310         rval = api_lline(screen, &last);
1311         if (!rval) {
1312             if (linenumber > last)
1313                 rval = api_extend(screen, linenumber);
1314             if (!rval)
1315                 CHAR2INTP(screen, text, length, line, len);
1316                 rval = api_sline(screen, linenumber, line, len);
1317         }
1318         ENDMESSAGE(screen);
1320 # similar to GetLine 
1322 char *
1323 FETCH(screen, linenumber)
1324         VI::LINE screen
1325         int linenumber
1327         PREINIT:
1328         size_t len;
1329         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1330         int rval;
1331         char *line;
1332         CHAR_T *p;
1334         PPCODE:
1335         ++linenumber;   /* vi 1 based ; perl 0 based */
1336         INITMESSAGE(screen);
1337         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1338         ENDMESSAGE(screen);
1340         EXTEND(sp,1);
1341         PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1343 # similar to LastLine 
1346 FETCHSIZE(screen)
1347         VI::LINE screen
1349         PREINIT:
1350         db_recno_t last;
1351         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1352         int rval;
1354         CODE:
1355         INITMESSAGE(screen);
1356         rval = api_lline(screen, &last);
1357         ENDMESSAGE(screen);
1358         RETVAL=last;
1360         OUTPUT:
1361         RETVAL
1363 void
1364 STORESIZE(screen, count)
1365         VI::LINE screen
1366         int count
1368         PREINIT:
1369         db_recno_t last;
1370         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1371         int rval;
1373         CODE:
1374         INITMESSAGE(screen);
1375         rval = api_lline(screen, &last);
1376         if (!rval) {
1377             if (count > last)
1378                 rval = api_extend(screen, count);
1379             else while(last && last > count) {
1380                 rval = api_dline(screen, last--);
1381                 if (rval) break;
1382             }
1383         }
1384         ENDMESSAGE(screen);
1386 void
1387 EXTEND(screen, count)
1388         VI::LINE screen
1389         int count
1391         CODE:
1393 void
1394 CLEAR(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;
1402         CODE:
1403         INITMESSAGE(screen);
1404         rval = api_lline(screen, &last);
1405         if (!rval) {
1406             while(last) {
1407                 rval = api_dline(screen, last--);
1408                 if (rval) break;
1409             }
1410         }
1411         ENDMESSAGE(screen);
1413 void
1414 PUSH(screen, ...)
1415         VI::LINE screen;
1417         PREINIT:
1418         db_recno_t last;
1419         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1420         int rval, i, len;
1421         char *line;
1423         CODE:
1424         INITMESSAGE(screen);
1425         rval = api_lline(screen, &last);
1427         if (!rval)
1428                 for (i = 1; i < items; ++i) {
1429                         line = SvPV(ST(i), len);
1430                         if ((rval = api_aline(screen, last++, line, len)))
1431                                 break;
1432                 }
1433         ENDMESSAGE(screen);
1435 SV *
1436 POP(screen)
1437         VI::LINE screen;
1439         PREINIT:
1440         db_recno_t last;
1441         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1442         int rval, i, len;
1443         CHAR_T *line;
1445         PPCODE:
1446         INITMESSAGE(screen);
1447         rval = api_lline(screen, &last);
1448         if (rval || last < 1)
1449                 ST(0) = &PL_sv_undef;
1450         else {
1451                 rval = api_gline(screen, last, &line, &len) ||
1452                        api_dline(screen, last);
1453                 EXTEND(sp,1);
1454                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1455         }
1456         ENDMESSAGE(screen);
1458 SV *
1459 SHIFT(screen)
1460         VI::LINE screen;
1462         PREINIT:
1463         db_recno_t last;
1464         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1465         int rval, i, len;
1466         CHAR_T *line;
1468         PPCODE:
1469         INITMESSAGE(screen);
1470         rval = api_lline(screen, &last);
1471         if (rval || last < 1)
1472                 ST(0) = &PL_sv_undef;
1473         else {
1474                 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1475                        api_dline(screen, (db_recno_t)1);
1476                 EXTEND(sp,1);
1477                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1478         }
1479         ENDMESSAGE(screen);
1481 void
1482 UNSHIFT(screen, ...)
1483         VI::LINE screen;
1485         PREINIT:
1486         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1487         int rval, i, len;
1488         char *np;
1489         size_t nlen;
1490         CHAR_T *line;
1492         CODE:
1493         INITMESSAGE(screen);
1494         while (--items != 0) {
1495                 np = SvPV(ST(items), nlen);
1496                 CHAR2INTP(screen, np, nlen, line, len);
1497                 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1498                         break;
1499         }
1500         ENDMESSAGE(screen);
1502 void
1503 SPLICE(screen, ...)
1504         VI::LINE screen;
1506         PREINIT:
1507         db_recno_t last, db_offset;
1508         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1509         int rval, length, common, len, i, offset;
1510         CHAR_T *line;
1511         char *np;
1512         size_t nlen;
1514         PPCODE:
1515         INITMESSAGE(screen);
1516         rval = api_lline(screen, &last);
1517         offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1518         if (offset < 0) offset += last;
1519         if (offset < 0) {
1520             ENDMESSAGE(screen);
1521             croak("Invalid offset");
1522         }
1523         length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1524         if (length > last - offset)
1525                 length = last - offset;
1526         db_offset = offset + 1; /* 1 based */
1527         EXTEND(sp,length);
1528         for (common = MIN(length, items - 3), i = 3; common > 0; 
1529             --common, ++db_offset, --length, ++i) {
1530                 rval |= api_gline(screen, db_offset, &line, &len);
1531                 INT2CHAR(screen, line, len, np, nlen);
1532                 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1533                 np = SvPV(ST(i), nlen);
1534                 CHAR2INTP(screen, np, nlen, line, len);
1535                 rval |= api_sline(screen, db_offset, line, len);
1536         }
1537         for (; length; --length) {
1538                 rval |= api_gline(screen, db_offset, &line, &len);
1539                 INT2CHAR(screen, line, len, np, nlen);
1540                 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1541                 rval |= api_dline(screen, db_offset);
1542         }
1543         for (; i < items; ++i) {
1544                 np = SvPV(ST(i), len);
1545                 CHAR2INTP(screen, np, len, line, nlen);
1546                 rval |= api_iline(screen, db_offset, line, nlen);
1547         }
1548         ENDMESSAGE(screen);
1550 MODULE = VI     PACKAGE = VI::TAGQ
1552 void
1553 Add(tagq, filename, search, msg)
1554         VI::TAGQ    tagq;
1555         char       *filename;
1556         char       *search;
1557         char       *msg;
1559         PREINIT:
1560         SCR *sp;
1562         CODE:
1563         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1564         if (!sp)
1565                 croak("screen no longer exists");
1566         api_tagq_add(sp, tagq->tqp, filename, search, msg);
1568 void
1569 Push(tagq)
1570         VI::TAGQ    tagq;
1572         PREINIT:
1573         SCR *sp;
1575         CODE:
1576         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1577         if (!sp)
1578                 croak("screen no longer exists");
1579         api_tagq_push(sp, &tagq->tqp);
1581 void
1582 DESTROY(tagq)
1583         # Can already be invalidated by push 
1584         VI::TAGQ2    tagq; 
1586         PREINIT:
1587         SCR *sp;
1589         CODE:
1590         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1591         if (sp)
1592                 api_tagq_free(sp, tagq->tqp);
1593         SvREFCNT_dec(tagq->sprv);
1594         free(tagq);