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.37 2001/03/14 21:48:14 skimo Exp $ (Berkeley) $Date: 2001/03/14 21:48:14 $";
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;
75 #define CHAR2INTP(sp,n,nlen,w,wlen) \
76 CHAR2INTB(sp,n,nlen,w,wlen,((perl_data_t *)sp->wp->perl_private)->perl)
80 * Macros to point messages at the Perl message handler.
82 #define INITMESSAGE(sp) \
83 scr_msg = sp->gp->scr_msg; \
84 sp->gp->scr_msg = msghandler;
85 #define ENDMESSAGE(sp) \
86 sp->gp->scr_msg = scr_msg; \
87 if (rval) croak(errmsg);
89 void xs_init __P((pTHXo));
93 * Clean up perl interpreter
95 * PUBLIC: int perl_end __P((GS *));
102 * Call perl_run and perl_destuct to call END blocks and DESTROY
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);
111 /* XXX rather make sure only one thread calls perl_end */
119 * We don't use mortal SVs because no one will clean up after us
127 SV* sv = newSVpv(string, 0);
129 /* G_KEEPERR to catch syntax error; better way ? */
131 perl_eval_sv(sv, G_DISCARD | G_NOARGS | G_KEEPERR);
137 * Create the perl commands used by nvi.
139 * PUBLIC: int perl_init __P((SCR *));
148 char *bootargs[] = { "VI", NULL };
154 static char *args[] = { "", "-e", "" };
156 char *file = __FILE__;
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;
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));
181 sfdisc(PerlIO_stdout(), sfdcnewnvi(scrp));
182 sfdisc(PerlIO_stderr(), sfdcnewnvi(scrp));
184 svcurscr = perl_get_sv("curscr", TRUE);
185 sv_magic((SV *)gv_fetchpv("STDOUT",TRUE, SVt_PVIO), svcurscr,
187 sv_magic((SV *)gv_fetchpv("STDERR",TRUE, SVt_PVIO), svcurscr,
189 #endif /* USE_SFIO */
192 MALLOC(scrp, pp, perl_data_t *, sizeof(perl_data_t));
193 wp->perl_private = pp;
197 pp->interp = perl_clone(gp->perl_interp, 0);
198 if (1) { /* hack for bug fixed in perl-current (5.6.1) */
200 if (PL_scopestack_ix == 0) {
205 pp->interp = gp->perl_interp;
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));
220 * Remove all refences to the screen to be destroyed
222 * PUBLIC: int perl_screen_end __P((SCR*));
225 perl_screen_end(scrp)
230 if (scrp->perl_private) {
231 sv_setiv((SV*) scrp->perl_private, 0);
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)
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);
265 else SvREFCNT_inc(screen->perl_private);
266 SvRV(rv) = screen->perl_private;
268 return sv_bless(rv, gv_stashpv("VI", TRUE));
273 * perl_ex_perl -- :[line [,line]] perl [command]
274 * Run a command through the perl interpreter.
276 * PUBLIC: int perl_ex_perl __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
279 perl_ex_perl(scrp, cmdp, cmdlen, f_lno, t_lno)
283 db_recno_t f_lno, t_lno;
294 /* Initialize the interpreter. */
295 if (scrp->wp->perl_private == NULL && perl_init(scrp))
297 pp = scrp->wp->perl_private;
302 sv_setiv(pp->svstart, f_lno);
303 sv_setiv(pp->svstop, t_lno);
304 newVIrv(pp->svcurscr, scrp);
305 /* Backwards compatibility. */
306 newVIrv(pp->svid, scrp);
308 istat = signal(SIGINT, my_sighandler);
309 INT2CHAR(scrp, cmdp, v_strlen(cmdp)+1, np, nlen);
311 signal(SIGINT, istat);
313 SvREFCNT_dec(SvRV(pp->svcurscr));
314 SvROK_off(pp->svcurscr);
315 SvREFCNT_dec(SvRV(pp->svid));
318 err = SvPV(ERRSV, length);
322 err[length - 1] = '\0';
323 msgq(scrp, M_ERR, "perl: %s", err);
330 * replace a line with the contents of the perl variable $_
331 * lines are split at '\n's
332 * if $_ is undef, the line is deleted
333 * returns possibly adjusted linenumber
336 replace_line(scrp, line, t_lno, defsv)
338 db_recno_t line, *t_lno;
347 str = SvPV(defsv,len);
348 next = memchr(str, '\n', len);
349 CHAR2INTP(scrp, str, next ? (next - str) : len, wp, wlen);
350 api_sline(scrp, line, wp, wlen);
353 next = memchr(str = next, '\n', len);
354 CHAR2INTP(scrp, str, next ? (next - str) : len,
356 api_iline(scrp, ++line, wp, wlen);
360 api_dline(scrp, line--);
367 * perl_ex_perldo -- :[line [,line]] perl [command]
368 * Run a set of lines through the perl interpreter.
370 * PUBLIC: int perl_ex_perldo __P((SCR*, CHAR_T *, size_t, db_recno_t, db_recno_t));
373 perl_ex_perldo(scrp, cmdp, cmdlen, f_lno, t_lno)
377 db_recno_t f_lno, t_lno;
392 /* Initialize the interpreter. */
393 if (scrp->wp->perl_private == NULL && perl_init(scrp))
395 pp = scrp->wp->perl_private;
400 newVIrv(pp->svcurscr, scrp);
401 /* Backwards compatibility. */
402 newVIrv(pp->svid, scrp);
404 INT2CHAR(scrp, cmdp, v_strlen(cmdp)+1, np, nlen);
405 if (!(command = malloc(length = nlen - 1 + sizeof("sub {}"))))
407 snprintf(command, length, "sub {%s}", np);
412 cv = perl_eval_pv(command, FALSE);
415 estr = SvPV(ERRSV,length);
419 for (i = f_lno; i <= t_lno && !api_gline(scrp, i, &str, &len); i++) {
420 INT2CHAR(scrp, str, len, np, nlen);
421 sv_setpvn(DEFSV,np,nlen);
422 sv_setiv(pp->svstart, i);
423 sv_setiv(pp->svstop, i);
425 perl_call_sv(cv, G_SCALAR | G_EVAL);
426 estr = SvPV(ERRSV, length);
430 i = replace_line(scrp, i, &t_lno, DEFSV);
436 SvREFCNT_dec(SvRV(pp->svcurscr));
437 SvROK_off(pp->svcurscr);
438 SvREFCNT_dec(SvRV(pp->svid));
444 err: estr[length - 1] = '\0';
445 msgq(scrp, M_ERR, "perl: %s", estr);
452 * Perl message routine so that error messages are processed in
456 msghandler(sp, mtype, msg, len)
462 /* Replace the trailing <newline> with an EOS. */
463 /* Let's do that later instead */
464 if (errmsg) free (errmsg);
465 errmsg = malloc(len + 1);
466 memcpy(errmsg, msg, len);
472 typedef SCR * VI__OPT;
473 typedef SCR * VI__MAP;
474 typedef SCR * VI__MARK;
475 typedef SCR * VI__LINE;
483 typedef perl_tagq * VI__TAGQ;
484 typedef perl_tagq * VI__TAGQ2;
486 MODULE = VI PACKAGE = VI
489 # Set the message line to text.
491 # Perl Command: VI::Msg
492 # Usage: VI::Msg screenId text
503 api_imessage(screen, text);
508 # Perl Command: VI::EndScreen
509 # Usage: VI::EndScreen screenId
516 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
521 rval = api_escreen(screen);
525 # Create a new screen. If a filename is specified then the screen
526 # is opened with that file.
528 # Perl Command: VI::NewScreen
529 # Usage: VI::NewScreen screenId [file]
540 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
546 file = (items == 1) ? NULL : (char *)SvPV(ST(1),PL_na);
548 rval = api_edit(screen, file, &nsp, ix);
551 RETVAL = ix ? nsp : screen;
557 # Return the screen id associated with file name.
559 # Perl Command: VI::FindScreen
560 # Usage: VI::FindScreen file
569 RETVAL = api_fscreen(0, file);
574 # XS_VI_GetFileName --
575 # Return the file name of the screen
577 # Perl Command: VI::GetFileName
578 # Usage: VI::GetFileName screenId
586 PUSHs(sv_2mortal(newSVpv(screen->frp->name, 0)));
589 # -- Append the string text after the line in lineNumber.
591 # Perl Command: VI::AppendLine
592 # Usage: VI::AppendLine screenId lineNumber text
595 AppendLine(screen, linenumber, text)
601 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
608 rval = api_aline(screen, linenumber, text, length);
614 # Perl Command: VI::DelLine
615 # Usage: VI::DelLine screenId lineNum
618 DelLine(screen, linenumber)
623 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
628 rval = api_dline(screen, (db_recno_t)linenumber);
634 # Perl Command: VI::GetLine
635 # Usage: VI::GetLine screenId lineNumber
638 GetLine(screen, linenumber)
644 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
651 rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
655 PUSHs(sv_2mortal(newSVpv(len ? (char *)p : "", len)));
658 # Set lineNumber to the text supplied.
660 # Perl Command: VI::SetLine
661 # Usage: VI::SetLine screenId lineNumber text
664 SetLine(screen, linenumber, text)
670 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
679 CHAR2INTP(screen, text, length, line, len);
680 rval = api_sline(screen, linenumber, line, len);
684 # Insert the string text before the line in lineNumber.
686 # Perl Command: VI::InsertLine
687 # Usage: VI::InsertLine screenId lineNumber text
690 InsertLine(screen, linenumber, text)
696 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
705 CHAR2INTP(screen, text, length, line, len);
706 rval = api_iline(screen, linenumber, line, len);
710 # Return the last line in the screen.
712 # Perl Command: VI::LastLine
713 # Usage: VI::LastLine screenId
721 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
726 rval = api_lline(screen, &last);
734 # Return the mark's cursor position as a list with two elements.
737 # Perl Command: VI::GetMark
738 # Usage: VI::GetMark screenId mark
741 GetMark(screen, mark)
747 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
752 rval = api_getmark(screen, (int)mark, &cursor);
756 PUSHs(sv_2mortal(newSViv(cursor.lno)));
757 PUSHs(sv_2mortal(newSViv(cursor.cno)));
760 # Set the mark to the line and column numbers supplied.
762 # Perl Command: VI::SetMark
763 # Usage: VI::SetMark screenId mark line column
766 SetMark(screen, mark, line, column)
774 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
781 rval = api_setmark(screen, (int)mark, &cursor);
785 # Return the current cursor position as a list with two elements.
788 # Perl Command: VI::GetCursor
789 # Usage: VI::GetCursor screenId
797 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
802 rval = api_getcursor(screen, &cursor);
806 PUSHs(sv_2mortal(newSViv(cursor.lno)));
807 PUSHs(sv_2mortal(newSViv(cursor.cno)));
810 # Set the cursor to the line and column numbers supplied.
812 # Perl Command: VI::SetCursor
813 # Usage: VI::SetCursor screenId line column
816 SetCursor(screen, line, column)
823 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
830 rval = api_setcursor(screen, &cursor);
834 # Change the current focus to screen.
836 # Perl Command: VI::SwitchScreen
837 # Usage: VI::SwitchScreen screenId screenId
840 SwitchScreen(screenFrom, screenTo)
845 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
849 INITMESSAGE(screenFrom);
850 rval = api_swscreen(screenFrom, screenTo);
851 ENDMESSAGE(screenFrom);
854 # Associate a key with a perl procedure.
856 # Perl Command: VI::MapKey
857 # Usage: VI::MapKey screenId key perlproc
860 MapKey(screen, key, perlproc)
866 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
875 svc = sv_2mortal(newSVpv(":perl ", 6));
876 sv_catsv(svc, perlproc);
877 svn = sv_2mortal(newSVpv("
\r", 1));
879 command = SvPV(svc, length);
880 rval = api_map(screen, key, command, length);
886 # Perl Command: VI::UnmapKey
887 # Usage: VI::UnmmapKey screenId key
890 UnmapKey(screen, key)
895 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
900 rval = api_unmap(screen, key);
906 # Perl Command: VI::SetOpt
907 # Usage: VI::SetOpt screenId setting
910 SetOpt(screen, setting)
915 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
921 svc = sv_2mortal(newSVpv(":set ", 5));
922 sv_catpv(svc, setting);
923 rval = api_run_str(screen, SvPV(svc, PL_na));
927 # Return the value of an option.
929 # Perl Command: VI::GetOpt
930 # Usage: VI::GetOpt screenId option
933 GetOpt(screen, option)
938 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
944 rval = api_opts_get(screen, option, &value, NULL);
948 PUSHs(sv_2mortal(newSVpv(value, 0)));
952 # Run the ex command cmd.
954 # Perl Command: VI::Run
955 # Usage: VI::Run screenId cmd
963 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
968 rval = api_run_str(screen, command);
979 if (sv_isa(screensv, "VI")) {
980 IV tmp = SvIV((SV*)SvRV(screensv));
981 screen = (SCR *) tmp;
984 croak("screen is not of type VI");
987 screen->perl_private = 0;
994 sv_catpv(ERRSV,warning);
996 #define TIED(kind,package) \
997 sv_magic((SV *) (var = \
998 (##kind##V *)sv_2mortal((SV *)new##kind##V())), \
999 sv_setref_pv(sv_newmortal(), package, \
1000 newVIrv(newSV(0), screen)),\
1002 RETVAL = newRV((SV *)var)
1053 if ((ptag = malloc(sizeof(perl_tagq))) == NULL)
1056 ptag->sprv = newVIrv(newSV(0), screen);
1057 ptag->tqp = api_tagq_new(screen, tag);
1058 if (ptag->tqp != NULL) {
1060 PUSHs(sv_2mortal(sv_setref_pv(newSV(0), "VI::TAGQ", ptag)));
1063 ST(0) = &PL_sv_undef;
1067 MODULE = VI PACKAGE = VI::OPT
1074 # typemap did all the checking
1075 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1083 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1089 INITMESSAGE(screen);
1090 rval = api_opts_get(screen, key, &value, &boolvalue);
1093 PUSHs(sv_2mortal((boolvalue == -1) ? newSVpv(value, 0)
1094 : newSViv(boolvalue)));
1096 } else ST(0) = &PL_sv_undef;
1101 STORE(screen, key, value)
1107 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1111 INITMESSAGE(screen);
1112 rval = api_opts_set(screen, key, SvPV(value, PL_na), SvIV(value),
1116 MODULE = VI PACKAGE = VI::MAP
1123 # typemap did all the checking
1124 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1127 STORE(screen, key, perlproc)
1133 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1141 INITMESSAGE(screen);
1142 svc = sv_2mortal(newSVpv(":perl ", 6));
1143 sv_catsv(svc, perlproc);
1144 svn = sv_2mortal(newSVpv("
\r", 1));
1146 command = SvPV(svc, length);
1147 rval = api_map(screen, key, command, length);
1156 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1160 INITMESSAGE(screen);
1161 rval = api_unmap(screen, key);
1164 MODULE = VI PACKAGE = VI::MARK
1171 # typemap did all the checking
1172 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1180 struct _mark cursor;
1181 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1185 INITMESSAGE(screen);
1186 rval = api_getmark(screen, (int)mark, &cursor);
1189 av_push(RETVAL, newSViv(cursor.lno));
1190 av_push(RETVAL, newSViv(cursor.cno));
1196 STORE(screen, mark, pos)
1202 struct _mark cursor;
1203 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1207 if (av_len(pos) < 1)
1208 croak("cursor position needs 2 elements");
1209 INITMESSAGE(screen);
1210 cursor.lno = SvIV(*av_fetch(pos, 0, 0));
1211 cursor.cno = SvIV(*av_fetch(pos, 1, 0));
1212 rval = api_setmark(screen, (int)mark, &cursor);
1216 FIRSTKEY(screen, ...)
1226 char key[] = {0, 0};
1231 *key = *(char *)SvPV(ST(1),PL_na);
1233 if (api_nextmark(screen, next, key) != 1) {
1235 PUSHs(sv_2mortal(newSVpv(key, 1)));
1236 } else ST(0) = &PL_sv_undef;
1238 MODULE = VI PACKAGE = VI::LINE
1245 # typemap did all the checking
1246 SvREFCNT_dec((SV*)SvIV((SV*)SvRV(ST(0))));
1248 # similar to SetLine
1251 STORE(screen, linenumber, text)
1257 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1265 ++linenumber; /* vi 1 based ; perl 0 based */
1266 SvPV(ST(2), length);
1267 INITMESSAGE(screen);
1268 rval = api_lline(screen, &last);
1270 if (linenumber > last)
1271 rval = api_extend(screen, linenumber);
1273 CHAR2INTP(screen, text, length, line, len);
1274 rval = api_sline(screen, linenumber, line, len);
1278 # similar to GetLine
1281 FETCH(screen, linenumber)
1287 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1293 ++linenumber; /* vi 1 based ; perl 0 based */
1294 INITMESSAGE(screen);
1295 rval = api_gline(screen, (db_recno_t)linenumber, &p, &len);
1299 PUSHs(sv_2mortal(newSVpv(len ? (char*)p : "", len)));
1301 # similar to LastLine
1309 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1313 INITMESSAGE(screen);
1314 rval = api_lline(screen, &last);
1322 STORESIZE(screen, count)
1328 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1332 INITMESSAGE(screen);
1333 rval = api_lline(screen, &last);
1336 rval = api_extend(screen, count);
1337 else while(last && last > count) {
1338 rval = api_dline(screen, last--);
1345 EXTEND(screen, count)
1357 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1361 INITMESSAGE(screen);
1362 rval = api_lline(screen, &last);
1365 rval = api_dline(screen, last--);
1377 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1382 INITMESSAGE(screen);
1383 rval = api_lline(screen, &last);
1386 for (i = 1; i < items; ++i) {
1387 line = SvPV(ST(i), len);
1388 if ((rval = api_aline(screen, last++, line, len)))
1399 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1404 INITMESSAGE(screen);
1405 rval = api_lline(screen, &last);
1406 if (rval || last < 1)
1407 ST(0) = &PL_sv_undef;
1409 rval = api_gline(screen, last, &line, &len) ||
1410 api_dline(screen, last);
1412 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1422 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1427 INITMESSAGE(screen);
1428 rval = api_lline(screen, &last);
1429 if (rval || last < 1)
1430 ST(0) = &PL_sv_undef;
1432 rval = api_gline(screen, (db_recno_t)1, &line, &len) ||
1433 api_dline(screen, (db_recno_t)1);
1435 PUSHs(sv_2mortal(newSVpv(len ? (char *)line : "", len)));
1440 UNSHIFT(screen, ...)
1444 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1451 INITMESSAGE(screen);
1452 while (--items != 0) {
1453 np = SvPV(ST(items), nlen);
1454 CHAR2INTP(screen, np, nlen, line, len);
1455 if ((rval = api_iline(screen, (db_recno_t)1, line, len)))
1465 db_recno_t last, db_offset;
1466 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
1467 int rval, length, common, len, i, offset;
1473 INITMESSAGE(screen);
1474 rval = api_lline(screen, &last);
1475 offset = items > 1 ? (int)SvIV(ST(1)) : 0;
1476 if (offset < 0) offset += last;
1479 croak("Invalid offset");
1481 length = items > 2 ? (int)SvIV(ST(2)) : last - offset;
1482 if (length > last - offset)
1483 length = last - offset;
1484 db_offset = offset + 1; /* 1 based */
1486 for (common = MIN(length, items - 3), i = 3; common > 0;
1487 --common, ++db_offset, --length, ++i) {
1488 rval |= api_gline(screen, db_offset, &line, &len);
1489 INT2CHAR(screen, line, len, np, nlen);
1490 PUSHs(sv_2mortal(newSVpv(nlen ? np : "", nlen)));
1491 np = SvPV(ST(i), nlen);
1492 CHAR2INTP(screen, np, nlen, line, len);
1493 rval |= api_sline(screen, db_offset, line, len);
1495 for (; length; --length) {
1496 rval |= api_gline(screen, db_offset, &line, &len);
1497 INT2CHAR(screen, line, len, np, nlen);
1498 PUSHs(sv_2mortal(newSVpv(len ? np : "", nlen)));
1499 rval |= api_dline(screen, db_offset);
1501 for (; i < items; ++i) {
1502 np = SvPV(ST(i), len);
1503 CHAR2INTP(screen, np, len, line, nlen);
1504 rval |= api_iline(screen, db_offset, line, nlen);
1508 MODULE = VI PACKAGE = VI::TAGQ
1511 Add(tagq, filename, search, msg)
1521 sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1523 croak("screen no longer exists");
1524 api_tagq_add(sp, tagq->tqp, filename, search, msg);
1534 sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1536 croak("screen no longer exists");
1537 api_tagq_push(sp, &tagq->tqp);
1541 # Can already be invalidated by push
1548 sp = (SCR *)SvIV((SV*)SvRV(tagq->sprv));
1550 api_tagq_free(sp, tagq->tqp);
1551 SvREFCNT_dec(tagq->sprv);