minix/dist/nvi/perl_api/perl.xs

1595 lines
30 KiB
Text
Raw Normal View History

/*-
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1992, 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
* Copyright (c) 1995
* George V. Neville-Neil. All rights reserved.
* Copyright (c) 1996-2001
* Sven Verdoolaege. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#undef VI
#ifndef lint
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";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <bitstring.h>
#include <ctype.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
/* perl redefines them
* avoid warnings
*/
#undef USE_DYNAMIC_LOADING
#undef DEBUG
#undef PACKAGE
#undef ARGS
#define ARGS ARGS
#include "config.h"
#include "../common/common.h"
#include "../perl_api/extern.h"
#ifndef DEFSV
#define DEFSV GvSV(defgv)
#endif
#ifndef ERRSV
#define ERRSV GvSV(errgv)
#endif
#ifndef dTHX
#define dTHXs
#else
#define dTHXs dTHX;
#endif
static void msghandler __P((SCR *, mtype_t, char *, size_t));
typedef struct _perl_data {
PerlInterpreter* interp;
SV *svcurscr, *svstart, *svstop, *svid;
CONVWIN cw;
char *errmsg;
} perl_data_t;
#define PERLP(sp) ((perl_data_t *)sp->wp->perl_private)
#define CHAR2INTP(sp,n,nlen,w,wlen) \
CHAR2INT5(sp,((perl_data_t *)sp->wp->perl_private)->cw,n,nlen,w,wlen)
/*
* INITMESSAGE --
* Macros to point messages at the Perl message handler.
*/
#define INITMESSAGE(sp) \
scr_msg = sp->wp->scr_msg; \
sp->wp->scr_msg = msghandler;
#define ENDMESSAGE(sp) \
sp->wp->scr_msg = scr_msg; \
if (rval) croak(PERLP(sp)->errmsg);
void xs_init __P((pTHXo));
/*
* perl_end --
* Clean up perl interpreter
*
* PUBLIC: int perl_end __P((GS *));
*/
int
perl_end(gp)
GS *gp;
{
/*
* Call perl_run and perl_destuct to call END blocks and DESTROY
* methods.
*/
if (gp->perl_interp) {
perl_run(gp->perl_interp);
perl_destruct(gp->perl_interp);
#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
perl_free(gp->perl_interp);
#endif
/* XXX rather make sure only one thread calls perl_end */
gp->perl_interp = 0;
}
}
/*
* perl_eval
* Evaluate a string
* We don't use mortal SVs because no one will clean up after us
*/
static void
perl_eval(string)
char *string;
{
dTHXs
SV* sv = newSVpv(string, 0);
/* G_KEEPERR to catch syntax error; better way ? */
sv_setpv(ERRSV,"");
perl_eval_sv(sv, G_DISCARD | G_NOARGS | G_KEEPERR);
SvREFCNT_dec(sv);
}
/*
* perl_init --
* Create the perl commands used by nvi.
*
* PUBLIC: int perl_init __P((SCR *));
*/
int
perl_init(scrp)
SCR *scrp;
{
AV * av;
GS *gp;
WIN *wp;
char *bootargs[] = { "VI", NULL };
#ifndef USE_SFIO
SV *svcurscr;
#endif
perl_data_t *pp;
static char *args[] = { "", "-e", "" };
size_t length;
char *file = __FILE__;
gp = scrp->gp;
wp = scrp->wp;
if (gp->perl_interp == NULL) {
gp->perl_interp = perl_alloc();
perl_construct(gp->perl_interp);
if (perl_parse(gp->perl_interp, xs_init, 3, args, 0)) {
perl_destruct(gp->perl_interp);
perl_free(gp->perl_interp);
gp->perl_interp = NULL;
return 1;
}
{
dTHXs
perl_call_argv("VI::bootstrap", G_DISCARD, bootargs);
perl_eval("$SIG{__WARN__}='VI::Warn'");
av_unshift(av = GvAVn(PL_incgv), 1);
av_store(av, 0, newSVpv(_PATH_PERLSCRIPTS,
sizeof(_PATH_PERLSCRIPTS)-1));
#ifdef USE_SFIO
sfdisc(PerlIO_stdout(), sfdcnewnvi(scrp));
sfdisc(PerlIO_stderr(), sfdcnewnvi(scrp));
#else
svcurscr = perl_get_sv("curscr", TRUE);
sv_magic((SV *)gv_fetchpv("STDOUT",TRUE, SVt_PVIO), svcurscr,
'q', Nullch, 0);
sv_magic((SV *)gv_fetchpv("STDERR",TRUE, SVt_PVIO), svcurscr,
'q', Nullch, 0);
#endif /* USE_SFIO */
}
}
MALLOC(scrp, pp, perl_data_t *, sizeof(perl_data_t));
wp->perl_private = pp;
memset(&pp->cw, 0, sizeof(pp->cw));
#ifdef USE_ITHREADS
pp->interp = perl_clone(gp->perl_interp, 0);
if (1) { /* hack for bug fixed in perl-current (5.6.1) */
dTHXa(pp->interp);
if (PL_scopestack_ix == 0) {
ENTER;
}
}
#else
pp->interp = gp->perl_interp;
#endif
pp->errmsg = 0;
{
dTHXs
SvREADONLY_on(pp->svcurscr = perl_get_sv("curscr", TRUE));
SvREADONLY_on(pp->svstart = perl_get_sv("VI::StartLine", TRUE));
SvREADONLY_on(pp->svstop = perl_get_sv("VI::StopLine", TRUE));
SvREADONLY_on(pp->svid = perl_get_sv("VI::ScreenId", TRUE));
}
return (0);
}
/*
* perl_screen_end
* Remove all refences to the screen to be destroyed
*
* PUBLIC: int perl_screen_end __P((SCR*));
*/
int
perl_screen_end(scrp)
SCR *scrp;
{
dTHXs
if (scrp->perl_private) {
sv_setiv((SV*) scrp->perl_private, 0);
}
return 0;
}
static void
my_sighandler(i)
int i;
{
croak("Perl command interrupted by SIGINT");
}
/* Create a new reference to an SV pointing to the SCR structure
* The perl_private part of the SCR structure points to the SV,
* so there can only be one such SV for a particular SCR structure.
* When the last reference has gone (DESTROY is called),
* perl_private is reset; When the screen goes away before
* all references are gone, the value of the SV is reset;
* any subsequent use of any of those reference will produce
* a warning. (see typemap)
*/
static SV *
newVIrv(rv, screen)
SV *rv;
SCR *screen;
{
dTHXs
if (!screen) return sv_setsv(rv, &PL_sv_undef), rv;
sv_upgrade(rv, SVt_RV);
if (!screen->perl_private) {
screen->perl_private = newSV(0);
sv_setiv(screen->perl_private, (IV) screen);
}
else SvREFCNT_inc(screen->perl_private);
SvRV(rv) = screen->perl_private;
SvROK_on(rv);
return sv_bless(rv, gv_stashpv("VI", TRUE));
}
/*
* perl_setenv
* Use perl's setenv if perl interpreter has been started.
* Perl uses its own setenv and gets confused if we change
* the environment after it has started.
*
* PUBLIC: int perl_setenv __P((SCR* sp, const char *name, const char *value));
*/
int
perl_setenv(SCR* scrp, const char *name, const char *value)
{
if (scrp->wp->perl_private == NULL) {
if (value == NULL)
unsetenv(name);
else
setenv(name, value, 1);
} else
my_setenv(name, value);
}
/*
* perl_ex_perl -- :[line [,line]] perl [command]
* Run a command through the perl interpreter.
*
* PUBLIC: int perl_ex_perl __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
*/
int
perl_ex_perl(scrp, cmdp, cmdlen, f_lno, t_lno)
SCR *scrp;
CHAR_T *cmdp;
size_t cmdlen;
db_recno_t f_lno, t_lno;
{
WIN *wp;
size_t length;
size_t len;
char *err;
char *np;
size_t nlen;
Signal_t (*istat)();
perl_data_t *pp;
/* Initialize the interpreter. */
if (scrp->wp->perl_private == NULL && perl_init(scrp))
return (1);
pp = scrp->wp->perl_private;
{
dTHXs
dSP;
sv_setiv(pp->svstart, f_lno);
sv_setiv(pp->svstop, t_lno);
newVIrv(pp->svcurscr, scrp);
/* Backwards compatibility. */
newVIrv(pp->svid, scrp);
istat = signal(SIGINT, my_sighandler);
INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
perl_eval(np);
signal(SIGINT, istat);
SvREFCNT_dec(SvRV(pp->svcurscr));
SvROK_off(pp->svcurscr);
SvREFCNT_dec(SvRV(pp->svid));
SvROK_off(pp->svid);
err = SvPV(ERRSV, length);
if (!length)
return (0);
err[length - 1] = '\0';
msgq(scrp, M_ERR, "perl: %s", err);
return (1);
}
}
/*
* replace_line
* replace a line with the contents of the perl variable $_
* lines are split at '\n's
* if $_ is undef, the line is deleted
* returns possibly adjusted linenumber
*/
static int
replace_line(scrp, line, t_lno, defsv)
SCR *scrp;
db_recno_t line, *t_lno;
SV *defsv;
{
char *str, *next;
CHAR_T *wp;
size_t len, wlen;
dTHXs
if (SvOK(defsv)) {
str = SvPV(defsv,len);
next = memchr(str, '\n', len);
CHAR2INTP(scrp, str, next ? (next - str) : len, wp, wlen);
api_sline(scrp, line, wp, wlen);
while (next++) {
len -= next - str;
next = memchr(str = next, '\n', len);
CHAR2INTP(scrp, str, next ? (next - str) : len,
wp, wlen);
api_iline(scrp, ++line, wp, wlen);
(*t_lno)++;
}
} else {
api_dline(scrp, line--);
(*t_lno)--;
}
return line;
}
/*
* perl_ex_perldo -- :[line [,line]] perl [command]
* Run a set of lines through the perl interpreter.
*
* PUBLIC: int perl_ex_perldo __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
*/
int
perl_ex_perldo(scrp, cmdp, cmdlen, f_lno, t_lno)
SCR *scrp;
CHAR_T *cmdp;
size_t cmdlen;
db_recno_t f_lno, t_lno;
{
CHAR_T *p;
WIN *wp;
size_t length;
size_t len;
db_recno_t i;
CHAR_T *str;
char *estr;
SV* cv;
char *command;
perl_data_t *pp;
char *np;
size_t nlen;
/* Initialize the interpreter. */
if (scrp->wp->perl_private == NULL && perl_init(scrp))
return (1);
pp = scrp->wp->perl_private;
{
dTHXs
dSP;
newVIrv(pp->svcurscr, scrp);
/* Backwards compatibility. */
newVIrv(pp->svid, scrp);
INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
if (!(command = malloc(length = nlen - 1 + sizeof("sub {}"))))
return 1;
snprintf(command, length, "sub {%s}", np);
ENTER;
SAVETMPS;
cv = perl_eval_pv(command, FALSE);
free (command);
estr = SvPV(ERRSV,length);
if (length)
goto err;
for (i = f_lno; i <= t_lno && !api_gline(scrp, i, &str, &len); i++) {
INT2CHAR(scrp, str, len, np, nlen);
sv_setpvn(DEFSV,np,nlen);
sv_setiv(pp->svstart, i);
sv_setiv(pp->svstop, i);
PUSHMARK(sp);
perl_call_sv(cv, G_SCALAR | G_EVAL);
estr = SvPV(ERRSV, length);
if (length) break;
SPAGAIN;
if(SvTRUEx(POPs))
i = replace_line(scrp, i, &t_lno, DEFSV);
PUTBACK;
}
FREETMPS;
LEAVE;
SvREFCNT_dec(SvRV(pp->svcurscr));
SvROK_off(pp->svcurscr);
SvREFCNT_dec(SvRV(pp->svid));
SvROK_off(pp->svid);
if (!length)
return (0);
err: estr[length - 1] = '\0';
msgq(scrp, M_ERR, "perl: %s", estr);
return (1);
}
}
/*
* msghandler --
* Perl message routine so that error messages are processed in
* Perl, not in nvi.
*/
static void
msghandler(sp, mtype, msg, len)
SCR *sp;
mtype_t mtype;
char *msg;
size_t len;
{
char *errmsg;
errmsg = PERLP(sp)->errmsg;
/* Replace the trailing <newline> with an EOS. */
/* Let's do that later instead */
if (errmsg) free (errmsg);
errmsg = malloc(len + 1);
memcpy(errmsg, msg, len);
errmsg[len] = '\0';
PERLP(sp)->errmsg = errmsg;
}
typedef SCR * VI;
typedef SCR * VI__OPT;
typedef SCR * VI__MAP;
typedef SCR * VI__MARK;
typedef SCR * VI__LINE;
typedef AV * AVREF;
typedef struct {
SV *sprv;
TAGQ *tqp;
} perl_tagq;
typedef perl_tagq * VI__TAGQ;
typedef perl_tagq * VI__TAGQ2;
MODULE = VI PACKAGE = VI
# msg --
# Set the message line to text.
#
# Perl Command: VI::Msg
# Usage: VI::Msg screenId text
void
Msg(screen, text)
VI screen
char * text
ALIAS:
PRINT = 1
CODE:
api_imessage(screen, text);
# XS_VI_escreen --
# End a screen.
#
# Perl Command: VI::EndScreen
# Usage: VI::EndScreen screenId
void
EndScreen(screen)
VI screen
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_escreen(screen);
ENDMESSAGE(screen);
# XS_VI_iscreen --
# Create a new screen. If a filename is specified then the screen
# is opened with that file.
#
# Perl Command: VI::NewScreen
# Usage: VI::NewScreen screenId [file]
VI
Edit(screen, ...)
VI screen
ALIAS:
NewScreen = 1
PROTOTYPE: $;$
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
char *file;
SCR *nsp;
CODE:
file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
INITMESSAGE(screen);
rval = api_edit(screen, file, &nsp, ix);
ENDMESSAGE(screen);
RETVAL = ix ? nsp : screen;
OUTPUT:
RETVAL
# XS_VI_fscreen --
# Return the screen id associated with file name.
#
# Perl Command: VI::FindScreen
# Usage: VI::FindScreen file
VI
FindScreen(file)
char *file
PREINIT:
SCR *fsp;
CODE:
RETVAL = api_fscreen(0, file);
OUTPUT:
RETVAL
# XS_VI_GetFileName --
# Return the file name of the screen
#
# Perl Command: VI::GetFileName
# Usage: VI::GetFileName screenId
char *
GetFileName(screen)
VI screen;
PPCODE:
EXTEND(sp,1);
PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
# XS_VI_aline --
# -- Append the string text after the line in lineNumber.
#
# Perl Command: VI::AppendLine
# Usage: VI::AppendLine screenId lineNumber text
void
AppendLine(screen, linenumber, text)
VI screen
int linenumber
char *text
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
size_t length;
CODE:
SvPV(ST(2), length);
INITMESSAGE(screen);
rval = api_aline(screen, linenumber, text, length);
ENDMESSAGE(screen);
# XS_VI_dline --
# Delete lineNum.
#
# Perl Command: VI::DelLine
# Usage: VI::DelLine screenId lineNum
void
DelLine(screen, linenumber)
VI screen
int linenumber
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_dline(screen, (db_recno_t)linenumber);
ENDMESSAGE(screen);
# XS_VI_gline --
# Return lineNumber.
#
# Perl Command: VI::GetLine
# Usage: VI::GetLine screenId lineNumber
char *
GetLine(screen, linenumber)
VI screen
int linenumber
PREINIT:
size_t len;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
char *line;
CHAR_T *p;
PPCODE:
INITMESSAGE(screen);
rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
ENDMESSAGE(screen);
EXTEND(sp,1);
PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
# XS_VI_sline --
# Set lineNumber to the text supplied.
#
# Perl Command: VI::SetLine
# Usage: VI::SetLine screenId lineNumber text
void
SetLine(screen, linenumber, text)
VI screen
int linenumber
char *text
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
size_t length;
size_t len;
CHAR_T *line;
CODE:
SvPV(ST(2), length);
INITMESSAGE(screen);
CHAR2INTP(screen, text, length, line, len);
rval = api_sline(screen, linenumber, line, len);
ENDMESSAGE(screen);
# XS_VI_iline --
# Insert the string text before the line in lineNumber.
#
# Perl Command: VI::InsertLine
# Usage: VI::InsertLine screenId lineNumber text
void
InsertLine(screen, linenumber, text)
VI screen
int linenumber
char *text
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
size_t length;
size_t len;
CHAR_T *line;
CODE:
SvPV(ST(2), length);
INITMESSAGE(screen);
CHAR2INTP(screen, text, length, line, len);
rval = api_iline(screen, linenumber, line, len);
ENDMESSAGE(screen);
# XS_VI_lline --
# Return the last line in the screen.
#
# Perl Command: VI::LastLine
# Usage: VI::LastLine screenId
int
LastLine(screen)
VI screen
PREINIT:
db_recno_t last;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
ENDMESSAGE(screen);
RETVAL=last;
OUTPUT:
RETVAL
# XS_VI_getmark --
# Return the mark's cursor position as a list with two elements.
# {line, column}.
#
# Perl Command: VI::GetMark
# Usage: VI::GetMark screenId mark
void
GetMark(screen, mark)
VI screen
char mark
PREINIT:
struct _mark cursor;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
PPCODE:
INITMESSAGE(screen);
rval = api_getmark(screen, (int)mark, &cursor);
ENDMESSAGE(screen);
EXTEND(sp,2);
PUSHs(sv_2mortal(newSViv(cursor.lno)));
PUSHs(sv_2mortal(newSViv(cursor.cno)));
# XS_VI_setmark --
# Set the mark to the line and column numbers supplied.
#
# Perl Command: VI::SetMark
# Usage: VI::SetMark screenId mark line column
void
SetMark(screen, mark, line, column)
VI screen
char mark
int line
int column
PREINIT:
struct _mark cursor;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
cursor.lno = line;
cursor.cno = column;
rval = api_setmark(screen, (int)mark, &cursor);
ENDMESSAGE(screen);
# XS_VI_getcursor --
# Return the current cursor position as a list with two elements.
# {line, column}.
#
# Perl Command: VI::GetCursor
# Usage: VI::GetCursor screenId
void
GetCursor(screen)
VI screen
PREINIT:
struct _mark cursor;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
PPCODE:
INITMESSAGE(screen);
rval = api_getcursor(screen, &cursor);
ENDMESSAGE(screen);
EXTEND(sp,2);
PUSHs(sv_2mortal(newSViv(cursor.lno)));
PUSHs(sv_2mortal(newSViv(cursor.cno)));
# XS_VI_setcursor --
# Set the cursor to the line and column numbers supplied.
#
# Perl Command: VI::SetCursor
# Usage: VI::SetCursor screenId line column
void
SetCursor(screen, line, column)
VI screen
int line
int column
PREINIT:
struct _mark cursor;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
cursor.lno = line;
cursor.cno = column;
rval = api_setcursor(screen, &cursor);
ENDMESSAGE(screen);
# XS_VI_swscreen --
# Change the current focus to screen.
#
# Perl Command: VI::SwitchScreen
# Usage: VI::SwitchScreen screenId screenId
void
SwitchScreen(screenFrom, screenTo)
VI screenFrom
VI screenTo
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screenFrom);
rval = api_swscreen(screenFrom, screenTo);
ENDMESSAGE(screenFrom);
# XS_VI_map --
# Associate a key with a perl procedure.
#
# Perl Command: VI::MapKey
# Usage: VI::MapKey screenId key perlproc
void
MapKey(screen, key, commandsv)
VI screen
char *key
SV *commandsv
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
int length;
char *command;
CODE:
INITMESSAGE(screen);
command = SvPV(commandsv, length);
rval = api_map(screen, key, command, length);
ENDMESSAGE(screen);
# XS_VI_unmap --
# Unmap a key.
#
# Perl Command: VI::UnmapKey
# Usage: VI::UnmmapKey screenId key
void
UnmapKey(screen, key)
VI screen
char *key
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_unmap(screen, key);
ENDMESSAGE(screen);
# XS_VI_opts_set --
# Set an option.
#
# Perl Command: VI::SetOpt
# Usage: VI::SetOpt screenId setting
void
SetOpt(screen, setting)
VI screen
char *setting
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
SV *svc;
CODE:
INITMESSAGE(screen);
svc = sv_2mortal(newSVpv(":set ", 5));
sv_catpv(svc, setting);
rval = api_run_str(screen, SvPV(svc, PL_na));
ENDMESSAGE(screen);
# XS_VI_opts_get --
# Return the value of an option.
#
# Perl Command: VI::GetOpt
# Usage: VI::GetOpt screenId option
void
GetOpt(screen, option)
VI screen
char *option
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
char *value;
CHAR_T *wp;
size_t wlen;
PPCODE:
INITMESSAGE(screen);
CHAR2INTP(screen, option, strlen(option)+1, wp, wlen);
rval = api_opts_get(screen, wp, &value, NULL);
ENDMESSAGE(screen);
EXTEND(SP,1);
PUSHs(sv_2mortal(newSVpv(value, 0)));
free(value);
# XS_VI_run --
# Run the ex command cmd.
#
# Perl Command: VI::Run
# Usage: VI::Run screenId cmd
void
Run(screen, command)
VI screen
char *command;
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_run_str(screen, command);
ENDMESSAGE(screen);
void
DESTROY(screensv)
SV* screensv
PREINIT:
VI screen;
CODE:
if (sv_isa(screensv, "VI")) {
IV tmp = SvIV((SV*)SvRV(screensv));
screen = (SCR *) tmp;
}
else
croak("screen is not of type VI");
if (screen)
screen->perl_private = 0;
void
Warn(warning)
char *warning;
CODE:
sv_catpv(ERRSV,warning);
#define TIED(kind,package) \
sv_magic((SV *) (var = \
(kind##V *)sv_2mortal((SV *)new##kind##V())), \
sv_setref_pv(sv_newmortal(), package, \
newVIrv(newSV(0), screen)),\
'P', Nullch, 0);\
RETVAL = newRV((SV *)var)
SV *
Opt(screen)
VI screen;
PREINIT:
HV *var;
CODE:
TIED(H,"VI::OPT");
OUTPUT:
RETVAL
SV *
Map(screen)
VI screen;
PREINIT:
HV *var;
CODE:
TIED(H,"VI::MAP");
OUTPUT:
RETVAL
SV *
Mark(screen)
VI screen
PREINIT:
HV *var;
CODE:
TIED(H,"VI::MARK");
OUTPUT:
RETVAL
SV *
Line(screen)
VI screen
PREINIT:
AV *var;
CODE:
TIED(A,"VI::LINE");
OUTPUT:
RETVAL
SV *
TagQ(screen, tag)
VI screen
char *tag;
PREINIT:
perl_tagq *ptag;
PPCODE:
if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
goto err;
ptag->sprv = newVIrv(newSV(0), screen);
ptag->tqp = api_tagq_new(screen, tag);
if (ptag->tqp != NULL) {
EXTEND(SP,1);
PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
} else {
err:
ST(0) = &PL_sv_undef;
return;
}
MODULE = VI PACKAGE = VI::OPT
void
DESTROY(screen)
VI::OPT screen
CODE:
# typemap did all the checking
SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
void
FETCH(screen, key)
VI::OPT screen
char *key
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
char *value;
int boolvalue;
CHAR_T *wp;
size_t wlen;
PPCODE:
INITMESSAGE(screen);
CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
rval = api_opts_get(screen, wp, &value, &boolvalue);
if (!rval) {
EXTEND(SP,1);
PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
: newSViv(boolvalue)));
free(value);
} else ST(0) = &PL_sv_undef;
rval = 0;
ENDMESSAGE(screen);
void
STORE(screen, key, value)
VI::OPT screen
char *key
SV *value
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CHAR_T *wp;
size_t wlen;
CODE:
INITMESSAGE(screen);
CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
rval = api_opts_set(screen, wp, SvPV(value, PL_na), SvIV(value),
SvTRUEx(value));
ENDMESSAGE(screen);
MODULE = VI PACKAGE = VI::MAP
void
DESTROY(screen)
VI::MAP screen
CODE:
# typemap did all the checking
SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
void
STORE(screen, key, commandsv)
VI::MAP screen
char *key
SV *commandsv
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
int length;
char *command;
CODE:
INITMESSAGE(screen);
command = SvPV(commandsv, length);
rval = api_map(screen, key, command, length);
ENDMESSAGE(screen);
void
DELETE(screen, key)
VI::MAP screen
char *key
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_unmap(screen, key);
ENDMESSAGE(screen);
MODULE = VI PACKAGE = VI::MARK
void
DESTROY(screen)
VI::MARK screen
CODE:
# typemap did all the checking
SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
int
EXISTS(screen, mark)
VI::MARK screen
char mark
PREINIT:
struct _mark cursor;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval = 0; /* never croak */
int missing;
CODE:
INITMESSAGE(screen);
missing = api_getmark(screen, (int)mark, &cursor);
ENDMESSAGE(screen);
RETVAL = !missing;
OUTPUT:
RETVAL
AV *
FETCH(screen, mark)
VI::MARK screen
char mark
PREINIT:
struct _mark cursor;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_getmark(screen, (int)mark, &cursor);
ENDMESSAGE(screen);
RETVAL = newAV();
av_push(RETVAL, newSViv(cursor.lno));
av_push(RETVAL, newSViv(cursor.cno));
OUTPUT:
RETVAL
void
STORE(screen, mark, pos)
VI::MARK screen
char mark
AVREF pos
PREINIT:
struct _mark cursor;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
if (av_len(pos) < 1)
croak("cursor position needs 2 elements");
INITMESSAGE(screen);
cursor.lno = SvIV(*av_fetch(pos, 0, 0));
cursor.cno = SvIV(*av_fetch(pos, 1, 0));
rval = api_setmark(screen, (int)mark, &cursor);
ENDMESSAGE(screen);
void
FIRSTKEY(screen, ...)
VI::MARK screen
ALIAS:
NEXTKEY = 1
PROTOTYPE: $;$
PREINIT:
int next;
char key[] = {0, 0};
PPCODE:
if (items == 2) {
next = 1;
*key = *(char *)SvPV(ST(1),PL_na);
} else next = 0;
if (api_nextmark(screen, next, key) != 1) {
EXTEND(sp, 1);
PUSHs(sv_2mortal(newSVpv(key, 1)));
} else ST(0) = &PL_sv_undef;
MODULE = VI PACKAGE = VI::LINE
void
DESTROY(screen)
VI::LINE screen
CODE:
# typemap did all the checking
SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
# similar to SetLine
void
STORE(screen, linenumber, text)
VI::LINE screen
int linenumber
char *text
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
size_t length;
db_recno_t last;
size_t len;
CHAR_T *line;
CODE:
++linenumber; /* vi 1 based ; perl 0 based */
SvPV(ST(2), length);
INITMESSAGE(screen);
rval = api_lline(screen, &last);
if (!rval) {
if (linenumber > last)
rval = api_extend(screen, linenumber);
if (!rval)
CHAR2INTP(screen, text, length, line, len);
rval = api_sline(screen, linenumber, line, len);
}
ENDMESSAGE(screen);
# similar to GetLine
char *
FETCH(screen, linenumber)
VI::LINE screen
int linenumber
PREINIT:
size_t len;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
char *line;
CHAR_T *p;
PPCODE:
++linenumber; /* vi 1 based ; perl 0 based */
INITMESSAGE(screen);
rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
ENDMESSAGE(screen);
EXTEND(sp,1);
PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
# similar to LastLine
int
FETCHSIZE(screen)
VI::LINE screen
PREINIT:
db_recno_t last;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
ENDMESSAGE(screen);
RETVAL=last;
OUTPUT:
RETVAL
void
STORESIZE(screen, count)
VI::LINE screen
int count
PREINIT:
db_recno_t last;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
if (!rval) {
if (count > last)
rval = api_extend(screen, count);
else while(last && last > count) {
rval = api_dline(screen, last--);
if (rval) break;
}
}
ENDMESSAGE(screen);
void
EXTEND(screen, count)
VI::LINE screen
int count
CODE:
void
CLEAR(screen)
VI::LINE screen
PREINIT:
db_recno_t last;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval;
CODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
if (!rval) {
while(last) {
rval = api_dline(screen, last--);
if (rval) break;
}
}
ENDMESSAGE(screen);
void
PUSH(screen, ...)
VI::LINE screen;
PREINIT:
db_recno_t last;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval, i, len;
char *line;
CODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
if (!rval)
for (i = 1; i < items; ++i) {
line = SvPV(ST(i), len);
if ((rval = api_aline(screen, last++, line, len)))
break;
}
ENDMESSAGE(screen);
SV *
POP(screen)
VI::LINE screen;
PREINIT:
db_recno_t last;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval, i, len;
CHAR_T *line;
PPCODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
if (rval || last < 1)
ST(0) = &PL_sv_undef;
else {
rval = api_gline(screen, last, &line, &len) ||
api_dline(screen, last);
EXTEND(sp,1);
PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
}
ENDMESSAGE(screen);
SV *
SHIFT(screen)
VI::LINE screen;
PREINIT:
db_recno_t last;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval, i, len;
CHAR_T *line;
PPCODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
if (rval || last < 1)
ST(0) = &PL_sv_undef;
else {
rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
api_dline(screen, (db_recno_t)1);
EXTEND(sp,1);
PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
}
ENDMESSAGE(screen);
void
UNSHIFT(screen, ...)
VI::LINE screen;
PREINIT:
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval, i, len;
char *np;
size_t nlen;
CHAR_T *line;
CODE:
INITMESSAGE(screen);
while (--items != 0) {
np = SvPV(ST(items), nlen);
CHAR2INTP(screen, np, nlen, line, len);
if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
break;
}
ENDMESSAGE(screen);
void
SPLICE(screen, ...)
VI::LINE screen;
PREINIT:
db_recno_t last, db_offset;
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
int rval, length, common, len, i, offset;
CHAR_T *line;
char *np;
size_t nlen;
PPCODE:
INITMESSAGE(screen);
rval = api_lline(screen, &last);
offset = items > 1 ? (int)SvIV(ST(1)) : 0;
if (offset < 0) offset += last;
if (offset < 0) {
ENDMESSAGE(screen);
croak("Invalid offset");
}
length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
if (length > last - offset)
length = last - offset;
db_offset = offset + 1; /* 1 based */
EXTEND(sp,length);
for (common = MIN(length, items - 3), i = 3; common > 0;
--common, ++db_offset, --length, ++i) {
rval |= api_gline(screen, db_offset, &line, &len);
INT2CHAR(screen, line, len, np, nlen);
PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
np = SvPV(ST(i), nlen);
CHAR2INTP(screen, np, nlen, line, len);
rval |= api_sline(screen, db_offset, line, len);
}
for (; length; --length) {
rval |= api_gline(screen, db_offset, &line, &len);
INT2CHAR(screen, line, len, np, nlen);
PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
rval |= api_dline(screen, db_offset);
}
for (; i < items; ++i) {
np = SvPV(ST(i), len);
CHAR2INTP(screen, np, len, line, nlen);
rval |= api_iline(screen, db_offset, line, nlen);
}
ENDMESSAGE(screen);
MODULE = VI PACKAGE = VI::TAGQ
void
Add(tagq, filename, search, msg)
VI::TAGQ tagq;
char *filename;
char *search;
char *msg;
PREINIT:
SCR *sp;
CODE:
sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
if (!sp)
croak("screen no longer exists");
api_tagq_add(sp, tagq->tqp, filename, search, msg);
void
Push(tagq)
VI::TAGQ tagq;
PREINIT:
SCR *sp;
CODE:
sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
if (!sp)
croak("screen no longer exists");
api_tagq_push(sp, &tagq->tqp);
void
DESTROY(tagq)
# Can already be invalidated by push
VI::TAGQ2 tagq;
PREINIT:
SCR *sp;
CODE:
sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
if (sp)
api_tagq_free(sp, tagq->tqp);
SvREFCNT_dec(tagq->sprv);
free(tagq);