align CHAR_T string in log
[nvi.git] / perl_api / perl.xs
blob28677732685d6854df5bf54d92e45cba2f698be4
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.38 2001/04/23 22:46:56 skimo Exp $ (Berkeley) $Date: 2001/04/23 22:46:56 $";
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         STRLEN 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         STRLEN 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, v_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         STRLEN 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, v_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         STRLEN 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         STRLEN 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         STRLEN 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;
940         PPCODE:
941         INITMESSAGE(screen);
942         rval = api_opts_get(screen, option, &value, NULL);
943         ENDMESSAGE(screen);
945         EXTEND(SP,1);
946         PUSHs(sv_2mortal(newSVpv(value, 0)));
947         free(value);
949 # XS_VI_run --
950 #       Run the ex command cmd.
952 # Perl Command: VI::Run
953 # Usage: VI::Run screenId cmd
955 void
956 Run(screen, command)
957         VI screen
958         char *command;
960         PREINIT:
961         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
962         int rval;
964         CODE:
965         INITMESSAGE(screen);
966         rval = api_run_str(screen, command);
967         ENDMESSAGE(screen);
969 void 
970 DESTROY(screensv)
971         SV* screensv
973         PREINIT:
974         VI  screen;
976         CODE:
977         if (sv_isa(screensv, "VI")) {
978                 IV tmp = SvIV((SV*)SvRV(screensv));
979                 screen = (SCR *) tmp;
980         }
981         else
982                 croak("screen is not of type VI");
984         if (screen)
985         screen->perl_private = 0;
987 void
988 Warn(warning)
989         char *warning;
991         CODE:
992         sv_catpv(ERRSV,warning);
994 #define TIED(kind,package) \
995         sv_magic((SV *) (var = \
996             (##kind##V *)sv_2mortal((SV *)new##kind##V())), \
997                 sv_setref_pv(sv_newmortal(), package, \
998                         newVIrv(newSV(0), screen)),\
999                 'P', Nullch, 0);\
1000         RETVAL = newRV((SV *)var)
1002 SV *
1003 Opt(screen)
1004         VI screen;
1005         PREINIT:
1006         HV *var;
1007         CODE:
1008         TIED(H,"VI::OPT");
1009         OUTPUT:
1010         RETVAL
1012 SV *
1013 Map(screen)
1014         VI screen;
1015         PREINIT:
1016         HV *var;
1017         CODE:
1018         TIED(H,"VI::MAP");
1019         OUTPUT:
1020         RETVAL
1022 SV *
1023 Mark(screen)
1024         VI screen
1025         PREINIT:
1026         HV *var;
1027         CODE:
1028         TIED(H,"VI::MARK");
1029         OUTPUT:
1030         RETVAL
1032 SV *
1033 Line(screen)
1034         VI screen
1035         PREINIT:
1036         AV *var;
1037         CODE:
1038         TIED(A,"VI::LINE");
1039         OUTPUT:
1040         RETVAL
1042 SV *
1043 TagQ(screen, tag)
1044         VI screen
1045         char *tag;
1047         PREINIT:
1048         perl_tagq *ptag;
1050         PPCODE:
1051         if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1052                 goto err;
1054         ptag->sprv = newVIrv(newSV(0), screen);
1055         ptag->tqp = api_tagq_new(screen, tag);
1056         if (ptag->tqp != NULL) {
1057                 EXTEND(SP,1);
1058                 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1059         } else {
1060 err:
1061                 ST(0) = &PL_sv_undef;
1062                 return;
1063         }
1065 MODULE = VI     PACKAGE = VI::OPT
1067 void 
1068 DESTROY(screen)
1069         VI::OPT screen
1071         CODE:
1072         # typemap did all the checking
1073         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1075 void
1076 FETCH(screen, key)
1077         VI::OPT screen
1078         char *key
1080         PREINIT:
1081         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1082         int rval;
1083         char *value;
1084         int boolvalue;
1086         PPCODE:
1087         INITMESSAGE(screen);
1088         rval = api_opts_get(screen, key, &value, &boolvalue);
1089         if (!rval) {
1090                 EXTEND(SP,1);
1091                 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1092                                                    : newSViv(boolvalue)));
1093                 free(value);
1094         } else ST(0) = &PL_sv_undef;
1095         rval = 0;
1096         ENDMESSAGE(screen);
1098 void
1099 STORE(screen, key, value)
1100         VI::OPT screen
1101         char    *key
1102         SV      *value
1104         PREINIT:
1105         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1106         int rval;
1108         CODE:
1109         INITMESSAGE(screen);
1110         rval = api_opts_set(screen, key, SvPV(value, PL_na), SvIV(value), 
1111                                          SvTRUEx(value));
1112         ENDMESSAGE(screen);
1114 MODULE = VI     PACKAGE = VI::MAP
1116 void 
1117 DESTROY(screen)
1118         VI::MAP screen
1120         CODE:
1121         # typemap did all the checking
1122         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1124 void
1125 STORE(screen, key, perlproc)
1126         VI::MAP screen
1127         char *key
1128         SV *perlproc
1130         PREINIT:
1131         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1132         int rval;
1133         int length;
1134         char *command;
1135         SV *svc;
1136         SV *svn;
1138         CODE:
1139         INITMESSAGE(screen);
1140         svc = sv_2mortal(newSVpv(":perl ", 6));
1141         sv_catsv(svc, perlproc);
1142         svn = sv_2mortal(newSVpv("\r", 1));
1143         sv_catsv(svc, svn);
1144         command = SvPV(svc, length);
1145         rval = api_map(screen, key, command, length);
1146         ENDMESSAGE(screen);
1148 void
1149 DELETE(screen, key)
1150         VI::MAP screen
1151         char *key
1153         PREINIT:
1154         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1155         int rval;
1157         CODE:
1158         INITMESSAGE(screen);
1159         rval = api_unmap(screen, key);
1160         ENDMESSAGE(screen);
1162 MODULE = VI     PACKAGE = VI::MARK
1164 void 
1165 DESTROY(screen)
1166         VI::MARK screen
1168         CODE:
1169         # typemap did all the checking
1170         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1172 AV *
1173 FETCH(screen, mark)
1174         VI::MARK screen
1175         char mark
1177         PREINIT:
1178         struct _mark cursor;
1179         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1180         int rval;
1182         CODE:
1183         INITMESSAGE(screen);
1184         rval = api_getmark(screen, (int)mark, &cursor);
1185         ENDMESSAGE(screen);
1186         RETVAL = newAV();
1187         av_push(RETVAL, newSViv(cursor.lno));
1188         av_push(RETVAL, newSViv(cursor.cno));
1190         OUTPUT:
1191         RETVAL
1193 void
1194 STORE(screen, mark, pos)
1195         VI::MARK screen
1196         char mark
1197         AVREF pos
1199         PREINIT:
1200         struct _mark cursor;
1201         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1202         int rval;
1204         CODE:
1205         if (av_len(pos) < 1) 
1206             croak("cursor position needs 2 elements");
1207         INITMESSAGE(screen);
1208         cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1209         cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1210         rval = api_setmark(screen, (int)mark, &cursor);
1211         ENDMESSAGE(screen);
1213 void
1214 FIRSTKEY(screen, ...)
1215         VI::MARK screen
1217         ALIAS:
1218         NEXTKEY = 1
1219         
1220         PROTOTYPE: $;$
1222         PREINIT:
1223         int next;
1224         char key[] = {0, 0};
1226         PPCODE:
1227         if (items == 2) {
1228                 next = 1;
1229                 *key = *(char *)SvPV(ST(1),PL_na);
1230         } else next = 0;
1231         if (api_nextmark(screen, next, key) != 1) {
1232                 EXTEND(sp, 1);
1233                 PUSHs(sv_2mortal(newSVpv(key, 1)));
1234         } else ST(0) = &PL_sv_undef;
1236 MODULE = VI     PACKAGE = VI::LINE
1238 void 
1239 DESTROY(screen)
1240         VI::LINE screen
1242         CODE:
1243         # typemap did all the checking
1244         SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1246 # similar to SetLine
1248 void
1249 STORE(screen, linenumber, text)
1250         VI::LINE screen
1251         int linenumber
1252         char *text
1254         PREINIT:
1255         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1256         int rval;
1257         STRLEN length;
1258         db_recno_t last;
1259         size_t len;
1260         CHAR_T *line;
1262         CODE:
1263         ++linenumber;   /* vi 1 based ; perl 0 based */
1264         SvPV(ST(2), length);
1265         INITMESSAGE(screen);
1266         rval = api_lline(screen, &last);
1267         if (!rval) {
1268             if (linenumber > last)
1269                 rval = api_extend(screen, linenumber);
1270             if (!rval)
1271                 CHAR2INTP(screen, text, length, line, len);
1272                 rval = api_sline(screen, linenumber, line, len);
1273         }
1274         ENDMESSAGE(screen);
1276 # similar to GetLine 
1278 char *
1279 FETCH(screen, linenumber)
1280         VI::LINE screen
1281         int linenumber
1283         PREINIT:
1284         size_t len;
1285         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1286         int rval;
1287         char *line;
1288         CHAR_T *p;
1290         PPCODE:
1291         ++linenumber;   /* vi 1 based ; perl 0 based */
1292         INITMESSAGE(screen);
1293         rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1294         ENDMESSAGE(screen);
1296         EXTEND(sp,1);
1297         PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1299 # similar to LastLine 
1302 FETCHSIZE(screen)
1303         VI::LINE screen
1305         PREINIT:
1306         db_recno_t last;
1307         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1308         int rval;
1310         CODE:
1311         INITMESSAGE(screen);
1312         rval = api_lline(screen, &last);
1313         ENDMESSAGE(screen);
1314         RETVAL=last;
1316         OUTPUT:
1317         RETVAL
1319 void
1320 STORESIZE(screen, count)
1321         VI::LINE screen
1322         int count
1324         PREINIT:
1325         db_recno_t last;
1326         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1327         int rval;
1329         CODE:
1330         INITMESSAGE(screen);
1331         rval = api_lline(screen, &last);
1332         if (!rval) {
1333             if (count > last)
1334                 rval = api_extend(screen, count);
1335             else while(last && last > count) {
1336                 rval = api_dline(screen, last--);
1337                 if (rval) break;
1338             }
1339         }
1340         ENDMESSAGE(screen);
1342 void
1343 EXTEND(screen, count)
1344         VI::LINE screen
1345         int count
1347         CODE:
1349 void
1350 CLEAR(screen)
1351         VI::LINE screen
1353         PREINIT:
1354         db_recno_t last;
1355         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1356         int rval;
1358         CODE:
1359         INITMESSAGE(screen);
1360         rval = api_lline(screen, &last);
1361         if (!rval) {
1362             while(last) {
1363                 rval = api_dline(screen, last--);
1364                 if (rval) break;
1365             }
1366         }
1367         ENDMESSAGE(screen);
1369 void
1370 PUSH(screen, ...)
1371         VI::LINE screen;
1373         PREINIT:
1374         db_recno_t last;
1375         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1376         int rval, i, len;
1377         char *line;
1379         CODE:
1380         INITMESSAGE(screen);
1381         rval = api_lline(screen, &last);
1383         if (!rval)
1384                 for (i = 1; i < items; ++i) {
1385                         line = SvPV(ST(i), len);
1386                         if ((rval = api_aline(screen, last++, line, len)))
1387                                 break;
1388                 }
1389         ENDMESSAGE(screen);
1391 SV *
1392 POP(screen)
1393         VI::LINE screen;
1395         PREINIT:
1396         db_recno_t last;
1397         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1398         int rval, i, len;
1399         CHAR_T *line;
1401         PPCODE:
1402         INITMESSAGE(screen);
1403         rval = api_lline(screen, &last);
1404         if (rval || last < 1)
1405                 ST(0) = &PL_sv_undef;
1406         else {
1407                 rval = api_gline(screen, last, &line, &len) ||
1408                        api_dline(screen, last);
1409                 EXTEND(sp,1);
1410                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1411         }
1412         ENDMESSAGE(screen);
1414 SV *
1415 SHIFT(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_T *line;
1424         PPCODE:
1425         INITMESSAGE(screen);
1426         rval = api_lline(screen, &last);
1427         if (rval || last < 1)
1428                 ST(0) = &PL_sv_undef;
1429         else {
1430                 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1431                        api_dline(screen, (db_recno_t)1);
1432                 EXTEND(sp,1);
1433                 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1434         }
1435         ENDMESSAGE(screen);
1437 void
1438 UNSHIFT(screen, ...)
1439         VI::LINE screen;
1441         PREINIT:
1442         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1443         int rval, i, len;
1444         char *np;
1445         size_t nlen;
1446         CHAR_T *line;
1448         CODE:
1449         INITMESSAGE(screen);
1450         while (--items != 0) {
1451                 np = SvPV(ST(items), nlen);
1452                 CHAR2INTP(screen, np, nlen, line, len);
1453                 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1454                         break;
1455         }
1456         ENDMESSAGE(screen);
1458 void
1459 SPLICE(screen, ...)
1460         VI::LINE screen;
1462         PREINIT:
1463         db_recno_t last, db_offset;
1464         void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1465         int rval, length, common, len, i, offset;
1466         CHAR_T *line;
1467         char *np;
1468         size_t nlen;
1470         PPCODE:
1471         INITMESSAGE(screen);
1472         rval = api_lline(screen, &last);
1473         offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1474         if (offset < 0) offset += last;
1475         if (offset < 0) {
1476             ENDMESSAGE(screen);
1477             croak("Invalid offset");
1478         }
1479         length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1480         if (length > last - offset)
1481                 length = last - offset;
1482         db_offset = offset + 1; /* 1 based */
1483         EXTEND(sp,length);
1484         for (common = MIN(length, items - 3), i = 3; common > 0; 
1485             --common, ++db_offset, --length, ++i) {
1486                 rval |= api_gline(screen, db_offset, &line, &len);
1487                 INT2CHAR(screen, line, len, np, nlen);
1488                 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1489                 np = SvPV(ST(i), nlen);
1490                 CHAR2INTP(screen, np, nlen, line, len);
1491                 rval |= api_sline(screen, db_offset, line, len);
1492         }
1493         for (; length; --length) {
1494                 rval |= api_gline(screen, db_offset, &line, &len);
1495                 INT2CHAR(screen, line, len, np, nlen);
1496                 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1497                 rval |= api_dline(screen, db_offset);
1498         }
1499         for (; i < items; ++i) {
1500                 np = SvPV(ST(i), len);
1501                 CHAR2INTP(screen, np, len, line, nlen);
1502                 rval |= api_iline(screen, db_offset, line, nlen);
1503         }
1504         ENDMESSAGE(screen);
1506 MODULE = VI     PACKAGE = VI::TAGQ
1508 void
1509 Add(tagq, filename, search, msg)
1510         VI::TAGQ    tagq;
1511         char       *filename;
1512         char       *search;
1513         char       *msg;
1515         PREINIT:
1516         SCR *sp;
1518         CODE:
1519         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1520         if (!sp)
1521                 croak("screen no longer exists");
1522         api_tagq_add(sp, tagq->tqp, filename, search, msg);
1524 void
1525 Push(tagq)
1526         VI::TAGQ    tagq;
1528         PREINIT:
1529         SCR *sp;
1531         CODE:
1532         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1533         if (!sp)
1534                 croak("screen no longer exists");
1535         api_tagq_push(sp, &tagq->tqp);
1537 void
1538 DESTROY(tagq)
1539         # Can already be invalidated by push 
1540         VI::TAGQ2    tagq; 
1542         PREINIT:
1543         SCR *sp;
1545         CODE:
1546         sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1547         if (sp)
1548                 api_tagq_free(sp, tagq->tqp);
1549         SvREFCNT_dec(tagq->sprv);
1550         free(tagq);