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.
7 * George V. Neville-Neil. All rights reserved.
9 * Sven Verdoolaege. All rights reserved.
11 * See the LICENSE file for redistribution information.
17 static const char sccsid[] = "$Id: perl.xs,v 8.39 2001/06/09 18:26:30 skimo Exp $ (Berkeley) $Date: 2001/06/09 18:26:30 $";
20 #include <sys/types.h>
21 #include <sys/queue.h>
24 #include <bitstring.h>
38 /* perl redefines them
41 #undef USE_DYNAMIC_LOADING
49 #include "../common/common.h"
50 #include "../perl_api/extern.h"
53 #define DEFSV GvSV(defgv)
56 #define ERRSV GvSV(errgv)
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;
74 #define CHAR2INTP(sp,n,nlen,w,wlen) \
75 CHAR2INTB(sp,n,nlen,w,wlen,((perl_data_t *)sp->wp->perl_private)->cw)
79 * Macros to point messages at the Perl message handler.
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));
92 * Clean up perl interpreter
94 * PUBLIC: int perl_end __P((GS *));
101 * Call perl_run and perl_destuct to call END blocks and DESTROY
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);
110 /* XXX rather make sure only one thread calls perl_end */
118 * We don't use mortal SVs because no one will clean up after us
126 SV* sv = newSVpv(string, 0);
128 /* G_KEEPERR to catch syntax error; better way ? */
130 perl_eval_sv(sv, G_DISCARD | G_NOARGS | G_KEEPERR);
136 * Create the perl commands used by nvi.
138 * PUBLIC: int perl_init __P((SCR *));
147 char *bootargs[] = { "VI", NULL };
153 static char *args[] = { "", "-e", "" };
155 char *file = __FILE__;
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;
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));
180 sfdisc(PerlIO_stdout(), sfdcnewnvi(scrp));
181 sfdisc(PerlIO_stderr(), sfdcnewnvi(scrp));
183 svcurscr = perl_get_sv("curscr", TRUE);
184 sv_magic((SV *)gv_fetchpv("STDOUT",TRUE, SVt_PVIO), svcurscr,
186 sv_magic((SV *)gv_fetchpv("STDERR",TRUE, SVt_PVIO), svcurscr,
188 #endif /* USE_SFIO */
191 MALLOC(scrp, pp, perl_data_t *, sizeof(perl_data_t));
192 wp->perl_private = pp;
193 memset(&pp->cw, 0, sizeof(pp->cw));
195 pp->interp = perl_clone(gp->perl_interp, 0);
196 if (1) { /* hack for bug fixed in perl-current (5.6.1) */
198 if (PL_scopestack_ix == 0) {
203 pp->interp = gp->perl_interp;
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));
218 * Remove all refences to the screen to be destroyed
220 * PUBLIC: int perl_screen_end __P((SCR*));
223 perl_screen_end(scrp)
228 if (scrp->perl_private) {
229 sv_setiv((SV*) scrp->perl_private, 0);
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)
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);
263 else SvREFCNT_inc(screen->perl_private);
264 SvRV(rv) = screen->perl_private;
266 return sv_bless(rv, gv_stashpv("VI", TRUE));
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));
277 perl_ex_perl(scrp, cmdp, cmdlen, f_lno, t_lno)
281 db_recno_t f_lno, t_lno;
292 /* Initialize the interpreter. */
293 if (scrp->wp->perl_private == NULL && perl_init(scrp))
295 pp = scrp->wp->perl_private;
300 sv_setiv(pp->svstart, f_lno);
301 sv_setiv(pp->svstop, t_lno);
302 newVIrv(pp->svcurscr, scrp);
303 /* Backwards compatibility. */
304 newVIrv(pp->svid, scrp);
306 istat = signal(SIGINT, my_sighandler);
307 INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
309 signal(SIGINT, istat);
311 SvREFCNT_dec(SvRV(pp->svcurscr));
312 SvROK_off(pp->svcurscr);
313 SvREFCNT_dec(SvRV(pp->svid));
316 err = SvPV(ERRSV, length);
320 err[length - 1] = '\0';
321 msgq(scrp, M_ERR, "perl: %s", err);
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
334 replace_line(scrp, line, t_lno, defsv)
336 db_recno_t line, *t_lno;
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);
351 next = memchr(str = next, '\n', len);
352 CHAR2INTP(scrp, str, next ? (next - str) : len,
354 api_iline(scrp, ++line, wp, wlen);
358 api_dline(scrp, line--);
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));
371 perl_ex_perldo(scrp, cmdp, cmdlen, f_lno, t_lno)
375 db_recno_t f_lno, t_lno;
390 /* Initialize the interpreter. */
391 if (scrp->wp->perl_private == NULL && perl_init(scrp))
393 pp = scrp->wp->perl_private;
398 newVIrv(pp->svcurscr, scrp);
399 /* Backwards compatibility. */
400 newVIrv(pp->svid, scrp);
402 INT2CHAR(scrp, cmdp, STRLEN(cmdp)+1, np, nlen);
403 if (!(command = malloc(length = nlen - 1 + sizeof("sub {}"))))
405 snprintf(command, length, "sub {%s}", np);
410 cv = perl_eval_pv(command, FALSE);
413 estr = SvPV(ERRSV,length);
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);
423 perl_call_sv(cv, G_SCALAR | G_EVAL);
424 estr = SvPV(ERRSV, length);
428 i = replace_line(scrp, i, &t_lno, DEFSV);
434 SvREFCNT_dec(SvRV(pp->svcurscr));
435 SvROK_off(pp->svcurscr);
436 SvREFCNT_dec(SvRV(pp->svid));
442 err: estr[length - 1] = '\0';
443 msgq(scrp, M_ERR, "perl: %s", estr);
450 * Perl message routine so that error messages are processed in
454 msghandler(sp, mtype, msg, 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);
470 typedef SCR * VI__OPT;
471 typedef SCR * VI__MAP;
472 typedef SCR * VI__MARK;
473 typedef SCR * VI__LINE;
481 typedef perl_tagq * VI__TAGQ;
482 typedef perl_tagq * VI__TAGQ2;
484 MODULE = VI PACKAGE = VI
487 # Set the message line to text.
489 # Perl Command: VI::Msg
490 # Usage: VI::Msg screenId text
501 api_imessage(screen, text);
506 # Perl Command: VI::EndScreen
507 # Usage: VI::EndScreen screenId
514 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
519 rval = api_escreen(screen);
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]
538 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
544 file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
546 rval = api_edit(screen, file, &nsp, ix);
549 RETVAL = ix ? nsp : screen;
555 # Return the screen id associated with file name.
557 # Perl Command: VI::FindScreen
558 # Usage: VI::FindScreen file
567 RETVAL = api_fscreen(0, file);
572 # XS_VI_GetFileName --
573 # Return the file name of the screen
575 # Perl Command: VI::GetFileName
576 # Usage: VI::GetFileName screenId
584 PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
587 # -- Append the string text after the line in lineNumber.
589 # Perl Command: VI::AppendLine
590 # Usage: VI::AppendLine screenId lineNumber text
593 AppendLine(screen, linenumber, text)
599 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
606 rval = api_aline(screen, linenumber, text, length);
612 # Perl Command: VI::DelLine
613 # Usage: VI::DelLine screenId lineNum
616 DelLine(screen, linenumber)
621 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
626 rval = api_dline(screen, (db_recno_t)linenumber);
632 # Perl Command: VI::GetLine
633 # Usage: VI::GetLine screenId lineNumber
636 GetLine(screen, linenumber)
642 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
649 rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
653 PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
656 # Set lineNumber to the text supplied.
658 # Perl Command: VI::SetLine
659 # Usage: VI::SetLine screenId lineNumber text
662 SetLine(screen, linenumber, text)
668 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
677 CHAR2INTP(screen, text, length, line, len);
678 rval = api_sline(screen, linenumber, line, len);
682 # Insert the string text before the line in lineNumber.
684 # Perl Command: VI::InsertLine
685 # Usage: VI::InsertLine screenId lineNumber text
688 InsertLine(screen, linenumber, text)
694 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
703 CHAR2INTP(screen, text, length, line, len);
704 rval = api_iline(screen, linenumber, line, len);
708 # Return the last line in the screen.
710 # Perl Command: VI::LastLine
711 # Usage: VI::LastLine screenId
719 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
724 rval = api_lline(screen, &last);
732 # Return the mark's cursor position as a list with two elements.
735 # Perl Command: VI::GetMark
736 # Usage: VI::GetMark screenId mark
739 GetMark(screen, mark)
745 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
750 rval = api_getmark(screen, (int)mark, &cursor);
754 PUSHs(sv_2mortal(newSViv(cursor.lno)));
755 PUSHs(sv_2mortal(newSViv(cursor.cno)));
758 # Set the mark to the line and column numbers supplied.
760 # Perl Command: VI::SetMark
761 # Usage: VI::SetMark screenId mark line column
764 SetMark(screen, mark, line, column)
772 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
779 rval = api_setmark(screen, (int)mark, &cursor);
783 # Return the current cursor position as a list with two elements.
786 # Perl Command: VI::GetCursor
787 # Usage: VI::GetCursor screenId
795 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
800 rval = api_getcursor(screen, &cursor);
804 PUSHs(sv_2mortal(newSViv(cursor.lno)));
805 PUSHs(sv_2mortal(newSViv(cursor.cno)));
808 # Set the cursor to the line and column numbers supplied.
810 # Perl Command: VI::SetCursor
811 # Usage: VI::SetCursor screenId line column
814 SetCursor(screen, line, column)
821 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
828 rval = api_setcursor(screen, &cursor);
832 # Change the current focus to screen.
834 # Perl Command: VI::SwitchScreen
835 # Usage: VI::SwitchScreen screenId screenId
838 SwitchScreen(screenFrom, screenTo)
843 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
847 INITMESSAGE(screenFrom);
848 rval = api_swscreen(screenFrom, screenTo);
849 ENDMESSAGE(screenFrom);
852 # Associate a key with a perl procedure.
854 # Perl Command: VI::MapKey
855 # Usage: VI::MapKey screenId key perlproc
858 MapKey(screen, key, perlproc)
864 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
873 svc = sv_2mortal(newSVpv(":perl ", 6));
874 sv_catsv(svc, perlproc);
875 svn = sv_2mortal(newSVpv("
\r", 1));
877 command = SvPV(svc, length);
878 rval = api_map(screen, key, command, length);
884 # Perl Command: VI::UnmapKey
885 # Usage: VI::UnmmapKey screenId key
888 UnmapKey(screen, key)
893 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
898 rval = api_unmap(screen, key);
904 # Perl Command: VI::SetOpt
905 # Usage: VI::SetOpt screenId setting
908 SetOpt(screen, setting)
913 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
919 svc = sv_2mortal(newSVpv(":set ", 5));
920 sv_catpv(svc, setting);
921 rval = api_run_str(screen, SvPV(svc, PL_na));
925 # Return the value of an option.
927 # Perl Command: VI::GetOpt
928 # Usage: VI::GetOpt screenId option
931 GetOpt(screen, option)
936 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
944 CHAR2INTP(screen, option, strlen(option)+1, wp, wlen);
945 rval = api_opts_get(screen, wp, &value, NULL);
949 PUSHs(sv_2mortal(newSVpv(value, 0)));
953 # Run the ex command cmd.
955 # Perl Command: VI::Run
956 # Usage: VI::Run screenId cmd
964 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
969 rval = api_run_str(screen, command);
980 if (sv_isa(screensv, "VI")) {
981 IV tmp = SvIV((SV*)SvRV(screensv));
982 screen = (SCR *) tmp;
985 croak("screen is not of type VI");
988 screen->perl_private = 0;
995 sv_catpv(ERRSV,warning);
997 #define TIED(kind,package) \
998 sv_magic((SV *) (var = \
999 (##kind##V *)sv_2mortal((SV *)new##kind##V())), \
1000 sv_setref_pv(sv_newmortal(), package, \
1001 newVIrv(newSV(0), screen)),\
1003 RETVAL = newRV((SV *)var)
1054 if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1057 ptag->sprv = newVIrv(newSV(0), screen);
1058 ptag->tqp = api_tagq_new(screen, tag);
1059 if (ptag->tqp != NULL) {
1061 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1064 ST(0) = &PL_sv_undef;
1068 MODULE = VI PACKAGE = VI::OPT
1075 # typemap did all the checking
1076 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1084 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1092 INITMESSAGE(screen);
1093 CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1094 rval = api_opts_get(screen, wp, &value, &boolvalue);
1097 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1098 : newSViv(boolvalue)));
1100 } else ST(0) = &PL_sv_undef;
1105 STORE(screen, key, value)
1111 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1117 INITMESSAGE(screen);
1118 CHAR2INTP(screen, key, strlen(key)+1, wp, wlen);
1119 rval = api_opts_set(screen, wp, SvPV(value, PL_na), SvIV(value),
1123 MODULE = VI PACKAGE = VI::MAP
1130 # typemap did all the checking
1131 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1134 STORE(screen, key, perlproc)
1140 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1148 INITMESSAGE(screen);
1149 svc = sv_2mortal(newSVpv(":perl ", 6));
1150 sv_catsv(svc, perlproc);
1151 svn = sv_2mortal(newSVpv("
\r", 1));
1153 command = SvPV(svc, length);
1154 rval = api_map(screen, key, command, length);
1163 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1167 INITMESSAGE(screen);
1168 rval = api_unmap(screen, key);
1171 MODULE = VI PACKAGE = VI::MARK
1178 # typemap did all the checking
1179 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1187 struct _mark cursor;
1188 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1192 INITMESSAGE(screen);
1193 rval = api_getmark(screen, (int)mark, &cursor);
1196 av_push(RETVAL, newSViv(cursor.lno));
1197 av_push(RETVAL, newSViv(cursor.cno));
1203 STORE(screen, mark, pos)
1209 struct _mark cursor;
1210 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1214 if (av_len(pos) < 1)
1215 croak("cursor position needs 2 elements");
1216 INITMESSAGE(screen);
1217 cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1218 cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1219 rval = api_setmark(screen, (int)mark, &cursor);
1223 FIRSTKEY(screen, ...)
1233 char key[] = {0, 0};
1238 *key = *(char *)SvPV(ST(1),PL_na);
1240 if (api_nextmark(screen, next, key) != 1) {
1242 PUSHs(sv_2mortal(newSVpv(key, 1)));
1243 } else ST(0) = &PL_sv_undef;
1245 MODULE = VI PACKAGE = VI::LINE
1252 # typemap did all the checking
1253 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1255 # similar to SetLine
1258 STORE(screen, linenumber, text)
1264 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1272 ++linenumber; /* vi 1 based ; perl 0 based */
1273 SvPV(ST(2), length);
1274 INITMESSAGE(screen);
1275 rval = api_lline(screen, &last);
1277 if (linenumber > last)
1278 rval = api_extend(screen, linenumber);
1280 CHAR2INTP(screen, text, length, line, len);
1281 rval = api_sline(screen, linenumber, line, len);
1285 # similar to GetLine
1288 FETCH(screen, linenumber)
1294 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1300 ++linenumber; /* vi 1 based ; perl 0 based */
1301 INITMESSAGE(screen);
1302 rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1306 PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1308 # similar to LastLine
1316 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1320 INITMESSAGE(screen);
1321 rval = api_lline(screen, &last);
1329 STORESIZE(screen, count)
1335 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1339 INITMESSAGE(screen);
1340 rval = api_lline(screen, &last);
1343 rval = api_extend(screen, count);
1344 else while(last && last > count) {
1345 rval = api_dline(screen, last--);
1352 EXTEND(screen, count)
1364 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1368 INITMESSAGE(screen);
1369 rval = api_lline(screen, &last);
1372 rval = api_dline(screen, last--);
1384 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1389 INITMESSAGE(screen);
1390 rval = api_lline(screen, &last);
1393 for (i = 1; i < items; ++i) {
1394 line = SvPV(ST(i), len);
1395 if ((rval = api_aline(screen, last++, line, len)))
1406 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1411 INITMESSAGE(screen);
1412 rval = api_lline(screen, &last);
1413 if (rval || last < 1)
1414 ST(0) = &PL_sv_undef;
1416 rval = api_gline(screen, last, &line, &len) ||
1417 api_dline(screen, last);
1419 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1429 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1434 INITMESSAGE(screen);
1435 rval = api_lline(screen, &last);
1436 if (rval || last < 1)
1437 ST(0) = &PL_sv_undef;
1439 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1440 api_dline(screen, (db_recno_t)1);
1442 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1447 UNSHIFT(screen, ...)
1451 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1458 INITMESSAGE(screen);
1459 while (--items != 0) {
1460 np = SvPV(ST(items), nlen);
1461 CHAR2INTP(screen, np, nlen, line, len);
1462 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1472 db_recno_t last, db_offset;
1473 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1474 int rval, length, common, len, i, offset;
1480 INITMESSAGE(screen);
1481 rval = api_lline(screen, &last);
1482 offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1483 if (offset < 0) offset += last;
1486 croak("Invalid offset");
1488 length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1489 if (length > last - offset)
1490 length = last - offset;
1491 db_offset = offset + 1; /* 1 based */
1493 for (common = MIN(length, items - 3), i = 3; common > 0;
1494 --common, ++db_offset, --length, ++i) {
1495 rval |= api_gline(screen, db_offset, &line, &len);
1496 INT2CHAR(screen, line, len, np, nlen);
1497 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1498 np = SvPV(ST(i), nlen);
1499 CHAR2INTP(screen, np, nlen, line, len);
1500 rval |= api_sline(screen, db_offset, line, len);
1502 for (; length; --length) {
1503 rval |= api_gline(screen, db_offset, &line, &len);
1504 INT2CHAR(screen, line, len, np, nlen);
1505 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1506 rval |= api_dline(screen, db_offset);
1508 for (; i < items; ++i) {
1509 np = SvPV(ST(i), len);
1510 CHAR2INTP(screen, np, len, line, nlen);
1511 rval |= api_iline(screen, db_offset, line, nlen);
1515 MODULE = VI PACKAGE = VI::TAGQ
1518 Add(tagq, filename, search, msg)
1528 sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1530 croak("screen no longer exists");
1531 api_tagq_add(sp, tagq->tqp, filename, search, msg);
1541 sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1543 croak("screen no longer exists");
1544 api_tagq_push(sp, &tagq->tqp);
1548 # Can already be invalidated by push
1555 sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1557 api_tagq_free(sp, tagq->tqp);
1558 SvREFCNT_dec(tagq->sprv);