.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "VT102 3pm" .TH VT102 3pm "2021-01-08" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Term::VT102 \- a class to emulate a DEC VT102 terminal .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use Term::VT102; \& \& my $vt = Term::VT102\->new (\*(Aqcols\*(Aq => 80, \*(Aqrows\*(Aq => 24); \& while (<>) { $vt\->process ($_); } .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" The \s-1VT102\s0 class provides emulation of most of the functions of a \s-1DEC VT102\s0 terminal. Once initialised, data passed to a \s-1VT102\s0 object is processed and the in-memory \*(L"screen\*(R" modified accordingly. This \*(L"screen\*(R" can be interrogated by the external program in a variety of ways. .PP This allows your program to interface with full-screen console programs by running them in a subprocess and passing their output to a \s-1VT102\s0 class. You can then see what the application has written on the screen by querying the class appropriately. .SH "OPTIONS" .IX Header "OPTIONS" Setting \fBcols\fR or \fBrows\fR in the \fB\fBnew()\fB\fR hash allows you to change the size of the terminal being emulated. If you do not specify a size, the default is 80 columns by 24 rows. .PP After initialisation, you can read and set the following terminal options using the \fB\fBoption_read()\fB\fR and \fB\fBoption_set()\fB\fR methods: .PP .Vb 3 \& LINEWRAP line wrapping; 1=on, 0=off. Default is OFF. \& LFTOCRLF treat LF (\en) as CRLF (\er\en); 1=on, 0=off. Default OFF. \& IGNOREXOFF ignore XON/XOFF characters; 1=on (ignore). Default ON. .Ve .SH "METHODS" .IX Header "METHODS" The following methods are provided: .IP "\fBattr_pack\fR (\fI\f(CI$fg\fI\fR,\fI\f(CI$bg\fI\fR,\fI\f(CI$bo\fI\fR,\fI\f(CI$fa\fI\fR,\fI\f(CI$st\fI\fR,\fI\f(CI$ul\fI\fR,\fI\f(CI$bl\fI\fR,\fI\f(CI$rv\fI\fR)" 4 .IX Item "attr_pack ($fg,$bg,$bo,$fa,$st,$ul,$bl,$rv)" Returns the packed version of the given attribute settings, which are given in the same order as returned by \fBattr_unpack\fR. The packed version will be a binary string not longer than 2 bytes. .IP "\fBattr_unpack\fR (\fI\f(CI$data\fI\fR)" 4 .IX Item "attr_unpack ($data)" Returns a list of the contents of the given packed attribute settings, of the form (\fI\f(CI$fg\fI\fR,\fI\f(CI$bg\fI\fR,\fI\f(CI$bo\fI\fR,\fI\f(CI$fa\fI\fR,\fI\f(CI$st\fI\fR,\fI\f(CI$ul\fI\fR,\fI\f(CI$bl\fI\fR,\fI\f(CI$rv\fI\fR). .Sp \&\fI\f(CI$fg\fI\fR and \fI\f(CI$bg\fI\fR are the \s-1ANSI\s0 foreground and background text colours, and \&\fI\f(CI$bo\fI\fR, \fI\f(CI$fa\fI\fR, \fI\f(CI$st\fI\fR, \fI\f(CI$ul\fI\fR, \fI\f(CI$bl\fI\fR, and \fI\f(CI$rv\fI\fR are flags (1 = on, 0 = off) for bold, faint, standout, underline, blink and reverse respectively. .IP "\fBcallback_call\fR (\fI\f(CI$name\fI\fR, \fI\f(CI$par1\fI\fR, \fI\f(CI$par2\fI\fR)" 4 .IX Item "callback_call ($name, $par1, $par2)" Calls the callback \fI\f(CI$name\fI\fR (eg \fB'\s-1ROWCHANGE\s0'\fR) with parameters \&\fI\f(CI$par1\fI\fR and \fI\f(CI$par2\fI\fR, as if the \s-1VT102\s0 module had called it. Does nothing if that callback has not been set with \&\fBcallback_set ()\fR. .IP "\fBcallback_set\fR (\fI\f(CI$callback\fI\fR, \fI\f(CI$ref\fI\fR, \fI\f(CI$private\fI\fR)" 4 .IX Item "callback_set ($callback, $ref, $private)" Sets the callback \fIcallback\fR to function reference \fIref\fR with private data \fI\f(CI$private\fI\fR. .Sp See the section on \fB\s-1CALLBACKS\s0\fR below. .IP "\fBnew\fR (\fI\f(CI%config\fI\fR)" 4 .IX Item "new (%config)" Returns a new \s-1VT102\s0 object with options specified in \fI\f(CI%config\fI\fR (see the \&\fB\s-1OPTIONS\s0\fR section for details). .IP "\fBoption_read\fR (\fI\f(CI$option\fI\fR)" 4 .IX Item "option_read ($option)" Returns the current value of terminal option \fI\f(CI$option\fI\fR (see \fB\s-1OPTIONS\s0\fR for details), or \fIundef\fR if that option does not exist. Note that you cannot read the terminal size with this call; use \fB\fBsize()\fB\fR for that. .IP "\fBoption_set\fR (\fI\f(CI$option\fI\fR, \fI\f(CI$value\fI\fR)" 4 .IX Item "option_set ($option, $value)" Sets the current value of terminal option \fI\f(CI$option\fI\fR to \fI\f(CI$value\fI\fR, returning the old value or \fIundef\fR if no such terminal option exists or you have specified an undefined \fI\f(CI$value\fI\fR. Note that you cannot resize the terminal with this call; use \fB\fBresize()\fB\fR for that. .IP "\fBprocess\fR (\fI\f(CI$string\fI\fR)" 4 .IX Item "process ($string)" Processes the string \fI\f(CI$string\fI\fR (which can be zero-length), updating the \&\s-1VT102\s0 object accordingly and calling any necessary callbacks on the way. .IP "\fBresize\fR (\fI\f(CI$cols\fI\fR, \fI\f(CI$rows\fI\fR)" 4 .IX Item "resize ($cols, $rows)" Resizes the \s-1VT102\s0 terminal to \fIcols\fR columns by \fIrows\fR rows, eg \fB\f(CB$vt\fB\-\fR>\fBresize (80, 24)\fR. The virtual screen is cleared first. .IP "\fBreset\fR ()" 4 .IX Item "reset ()" Resets the object to its \*(L"power-on\*(R" state. .IP "\fBrow_attr\fR (\fI\f(CI$row\fI\fR, [\fI\f(CI$startcol\fI\fR, \fI\f(CI$endcol\fI\fR])" 4 .IX Item "row_attr ($row, [$startcol, $endcol])" Returns the attributes for row \fI\f(CI$row\fI\fR (or \fIundef\fR if out of range) as a string of packed attributes, each character cell's attributes being 2 bytes long. To unpack the attributes for a given cell, use \fB\fBsubstr()\fB\fR, eg \fB\f(CB$attr\fB=substr($row,4,2)\fR would set \fI\f(CI$attr\fI\fR to the attributes for cell 3 (steps of 2: 0 .. 2 .. 4, so 4 means the 3rd character). You would then use the \fB\fBattr_unpack()\fB\fR method to unpack that character cell's attributes. .Sp If \fI\f(CI$startcol\fI\fR and \fI\f(CI$endcol\fI\fR are defined, only returns the part of the row between columns \fI\f(CI$startcol\fI\fR and \fI\f(CI$endcol\fI\fR inclusive instead of the whole row. .IP "\fBrow_text\fR (\fI\f(CI$row\fI\fR, [\fI\f(CI$startcol\fI\fR, \fI\f(CI$endcol\fI\fR])" 4 .IX Item "row_text ($row, [$startcol, $endcol])" Returns the textual contents of row \fI\f(CI$row\fI\fR (or \fIundef\fR if out of range), with totally unused characters being represented as \s-1NULL\s0 (\e0). If \fI\f(CI$startcol\fI\fR and \&\fI\f(CI$endcol\fI\fR are defined, only returns the part of the row between columns \&\fI\f(CI$startcol\fI\fR and \fI\f(CI$endcol\fI\fR inclusive instead of the whole row. .IP "\fBrow_plaintext\fR (\fI\f(CI$row\fI\fR, [\fI\f(CI$startcol\fI\fR, \fI\f(CI$endcol\fI\fR])" 4 .IX Item "row_plaintext ($row, [$startcol, $endcol])" Returns the textual contents of row \fI\f(CI$row\fI\fR (or \fIundef\fR if out of range), with unused characters being represented as spaces. If \fI\f(CI$startcol\fI\fR and \&\fI\f(CI$endcol\fI\fR are defined, only returns the part of the row between columns \&\fI\f(CI$startcol\fI\fR and \fI\f(CI$endcol\fI\fR inclusive instead of the whole row. .IP "\fBrow_sgrtext\fR (\fI\f(CI$row\fI\fR, [\fI\f(CI$startcol\fI\fR, \fI\f(CI$endcol\fI\fR])" 4 .IX Item "row_sgrtext ($row, [$startcol, $endcol])" Returns the textual contents of row \fI\f(CI$row\fI\fR (or \fIundef\fR if out of range), with unused characters being represented as spaces, and \s-1ANSI/ECMA\-48\s0 escape sequences (\s-1CSI SGR\s0) used to set the colours and attributes as appropriate. If \fI\f(CI$startcol\fI\fR and \fI\f(CI$endcol\fI\fR are defined, only returns the part of the row between columns \fI\f(CI$startcol\fI\fR and \fI\f(CI$endcol\fI\fR inclusive instead of the whole row. .Sp Use \fBrow_sgrtext\fR to get a row if you want to output it to a real terminal and preserve all colours, bold, etc. .IP "\fBsgr_change\fR (\fI\f(CI$source\fI\fR, \fI\f(CI$dest\fI\fR)" 4 .IX Item "sgr_change ($source, $dest)" Returns a string containing \s-1ANSI/ECMA\-48\s0 escape sequences to change colours and attributes from \fI\f(CI$source\fI\fR to \fI\f(CI$dest\fI\fR, which are both packed attributes (see \fBattr_pack\fR). This is used internally by \fBrow_sgrtext\fR. .IP "\fBcols\fR ()" 4 .IX Item "cols ()" Return the number of columns in the \s-1VT102\s0 object. .IP "\fBrows\fR ()" 4 .IX Item "rows ()" Return the number of rows in the \s-1VT102\s0 object. .IP "\fBsize\fR ()" 4 .IX Item "size ()" Return a pair of values (\fIcolumns\fR,\fIrows\fR) denoting the size of the terminal in the \s-1VT102\s0 object. .IP "\fBx\fR ()" 4 .IX Item "x ()" Return the current cursor X co-ordinate (1 being leftmost). .Sp \&\fBNote:\fR It is possible for the current X co-ordinate to be 1 more than the number of columns. This happens when the end of a row is reached such that the next character would wrap on to the next row. .IP "\fBy\fR ()" 4 .IX Item "y ()" Return the current cursor Y co-ordinate (1 being topmost). .IP "\fBcursor\fR ()" 4 .IX Item "cursor ()" Return the current cursor state (1 being on, 0 being off). .IP "\fBxtitle\fR ()" 4 .IX Item "xtitle ()" Return the current xterm window title. .IP "\fBxicon\fR ()" 4 .IX Item "xicon ()" Return the current xterm window icon name. .IP "\fBstatus\fR ()" 4 .IX Item "status ()" Return a list of values (\fI\f(CI$x\fI\fR,\fI\f(CI$y\fI\fR,\fI\f(CI$attr\fI\fR,\fI\f(CI$ti\fI\fR,\fI\f(CI$ic\fI\fR), where \fI\f(CI$x\fI\fR and \fI\f(CI$y\fI\fR are the cursor co-ordinates (1,1 = top left), \fI\f(CI$attr\fI\fR is a packed version of the current attributes (see \fBattr_unpack\fR), \fI\f(CI$ti\fI\fR is the xterm window title, and \&\fI\f(CI$ic\fI\fR is the xterm window icon name. .IP "\fBversion\fR ()" 4 .IX Item "version ()" Return the version of the \s-1VT102\s0 module being used. .SH "CALLBACKS" .IX Header "CALLBACKS" Callbacks are the processing loop's way of letting your main program know that something has happened. They are called while in a \fB\fBprocess()\fB\fR loop. .PP To specify a callback, use the \fBcallback_set\fR interface, giving a reference to the function to call. Your function should take five scalar arguments: the \s-1VT102\s0 object being processed, the name of the callback, and two arguments whose value depends on the callback, as shown below. The final argument is the private data scalar you passed when you called \&\fBcallback_set\fR. .PP The name of the callback is passed to the callback function so that you can have one function to handle all callbacks if you wish. .PP Available callback names are: .PP .Vb 12 \& BELL BEL (beep, \e007) character received \& CLEAR screen about to be cleared \& OUTPUT data (arg1) to be sent back to data source \& ROWCHANGE screen row (row number is argument 1) content has changed \& SCROLL_DOWN about to scroll down (arg1=top row, arg2=num to scroll) \& SCROLL_UP about to scroll up (ditto) \& UNKNOWN unknown/unsupported code (arg1=name, arg2=code/sequence) \& STRING string received (arg1=source, eg PM, APC, arg2=string) \& XICONNAME xterm icon name to be changed to arg1 \& XWINTITLE xterm title name to be changed to arg1 \& LINEFEED line feed about to be processed (arg1=row) \& GOTO cursor about to be moved (args=new pos) .Ve .PP Note that the wording of the above is significant in terms of exactly \&\fBwhen\fR the callback is called. For instance, \fB\s-1CLEAR\s0\fR is called just before the screen is cleared, whereas \fB\s-1ROWCHANGE\s0\fR is called \fIafter\fR the given row has been changed. .PP A good callback handler for \fB\s-1OUTPUT\s0\fR is to simply \fB\fBsyswrite()\fB\fR argument 1 to your data source \- eg if you're reading from a telnet session, write that argument straight to it. It is used for cursor position request responses and suchlike. .PP Note that \fB\s-1SCROLL_DOWN\s0\fR is called when scrolling down, so text is about to move \s-1UP\s0 the screen; \fIarg1\fR will be the row number of the bottom of the scrolling region, and \fIarg2\fR will be the number of rows to be scrolled. Likewise, \fB\s-1SCROLL_UP\s0\fR is called when text is about to move down; \fIarg1\fR will be the row number of the top of the scrolling region. .PP The \fB\s-1STRING\s0\fR callback is called for escape sequences that contain a string that would otherwise be ignored, such as \s-1DSC, PM,\s0 and \s-1APC.\s0 The first argument is the escape sequence that contained the string, such as \s-1DSC,\s0 and the second argument is the string itself. This callback doesn't get called for \s-1OSC\s0 strings. .PP The \fB\s-1LINEFEED\s0\fR callback can be thought of as \*(L"line completed\*(R", it's called when \s-1LF, NEL\s0 or \s-1IND\s0 are about to be processed or just before a line wraps, so it generally indicates that an application has finished updating a particular line on the screen. Handy for scrollback buffer processing. .PP The \fB\s-1GOTO\s0\fR callback is only called just before the cursor is explicitly moved, by one of \s-1CUU, CUD, VPR, CUF, HPR, CUB, CNL, CPL, CHA, HPA, CUP, HVP.\s0 The parameters give the destination column and row, without taking scrolling and boundaries into account. .PP Finally, note that \fB\s-1ROWCHANGE\s0\fR is only triggered when text is being entered; screen scrolling or screen clearance does not trigger it, that would trigger a \fB\s-1SCROLL_DOWN\s0\fR or \fB\s-1SCROLL_UP\s0\fR or \fB\s-1CLEAR\s0\fR. Line or character insertion or deletion will cause one or more \fB\s-1ROWCHANGE\s0\fR callbacks, however. .SH "SUPPORTED CODES" .IX Header "SUPPORTED CODES" The following sequences are supported: .PP .Vb 10 \& 007 (BEL) beep \& 010 (BS) backspace \& 011 (HT) horizontal tab to next tab stop \& 012 (LF) line feed \& 013 (VT) line feed \& 014 (FF) line feed \& 015 (CR) carriage return \& 021 (XON) resume transmission (only if option IGNOREXOFF is cleared) \& 023 (XOFF) stop transmission (only if option IGNOREXOFF is cleared) \& 030 (CAN) interrupt escape sequence \& 032 (SUB) interrupt escape sequence \& 033 (ESC) start escape sequence \& 177 (DEL) ignored \& 233 (CSI) same as ESC [ \& \& ESC 7 (DECSC) save state \& ESC 8 (DECRC) restore most recently saved state \& ESC H (HTS) set tab stop at current column \& ESC g visual beep \- treated as BEL \& \& ESC # 8 (DECALN) DEC screen alignment test \- fill screen with E\*(Aqs \& \& CSI @ (ICH) insert blank characters \& CSI A (CUU) move cursor up \& CSI B (CUD) move cursor down \& CSI C (CUF) move cursor right \& CSI D (CUB) move cursor left \& CSI E (CNL) move cursor down and to column 1 \& CSI F (CPL) move cursor up and to column 1 \& CSI G (CHA) move cursor to column in current row \& CSI H (CUP) move cursor to row, column \& CSI J (ED) erase display \& CSI K (EL) erase line \& CSI L (IL) insert blank lines \& CSI M (DL) delete lines \& CSI P (DCH) delete characters on current line \& CSI X (ECH) erase characters on current line \& CSI a (HPR) move cursor right \& CSI c (DA) return ESC [ ? 6 c (VT102) \& CSI d (VPA) move to row (current column) \& CSI e (VPR) move cursor down \& CSI f (HVP) move cursor to row, column \& CSI m (SGR) set graphic rendition \& CSI n (DSR) device status report \& CSI r (DECSTBM) set scrolling region to (top, bottom) rows \& CSI s (CUPSV) save cursor position \& CSI u (CUPRS) restore cursor position \& CSI \` (HPA) move cursor to column in current row \& CSI g (TBC) clear tab stop (CSI 3 g = clear all stops) .Ve .SH "LIMITATIONS" .IX Header "LIMITATIONS" Unknown escape sequences and control characters are ignored. All escape sequences pertaining to character sets are ignored. .PP The following known control characters / sequences are ignored: .PP .Vb 3 \& 005 (ENQ) trigger answerback message \& 016 (SO) activate G1 charset, carriage return \& 017 (SI) activate G0 charset .Ve .PP The following known escape sequences are ignored: .PP .Vb 10 \& ESC %@ (CSDFL) select default charset (ISO646/8859\-1) \& ESC %G (CSUTF8) select UTF\-8 \& ESC %8 (CSUTF8) select UTF\-8 (obsolete) \& ESC (8 (G0DFL) G0 charset = default mapping (ISO8859\-1) \& ESC (0 (G0GFX) G0 charset = VT100 graphics mapping \& ESC (U (G0ROM) G0 charset = null mapping (straight to ROM) \& ESC (K (G0USR) G0 charset = user defined mapping \& ESC (B (G0TXT) G0 charset = ASCII mapping \& ESC )8 (G1DFL) G1 charset = default mapping (ISO8859\-1) \& ESC )0 (G1GFX) G1 charset = VT100 graphics mapping \& ESC )U (G1ROM) G1 charset = null mapping (straight to ROM) \& ESC )K (G1USR) G1 charset = user defined mapping \& ESC )B (G1TXT) G1 charset = ASCII mapping \& ESC *8 (G2DFL) G2 charset = default mapping (ISO8859\-1) \& ESC *0 (G2GFX) G2 charset = VT100 graphics mapping \& ESC *U (G2ROM) G2 charset = null mapping (straight to ROM) \& ESC *K (G2USR) G2 charset = user defined mapping \& ESC +8 (G3DFL) G3 charset = default mapping (ISO8859\-1) \& ESC +0 (G3GFX) G3 charset = VT100 graphics mapping \& ESC +U (G3ROM) G3 charset = null mapping (straight to ROM) \& ESC +K (G3USR) G3 charset = user defined mapping \& ESC > (DECPNM) set numeric keypad mode \& ESC = (DECPAM) set application keypad mode \& ESC N (SS2) select G2 charset for next char only \& ESC O (SS3) select G3 charset for next char only \& ESC P (DCS) device control string (ended by ST) \& ESC X (SOS) start of string \& ESC ^ (PM) privacy message (ended by ST) \& ESC _ (APC) application program command (ended by ST) \& ESC \e (ST) string terminator \& ESC n (LS2) invoke G2 charset \& ESC o (LS3) invoke G3 charset \& ESC | (LS3R) invoke G3 charset as GR \& ESC } (LS2R) invoke G2 charset as GR \& ESC ~ (LS1R) invoke G1 charset as GR .Ve .PP The following known \s-1CSI\s0 (\s-1ESC\s0 [) sequences are ignored: .PP .Vb 1 \& CSI q (DECLL) set keyboard LEDs .Ve .PP The following known \s-1CSI\s0 (\s-1ESC\s0 [) sequences are only partially supported: .PP .Vb 2 \& CSI h (SM) set mode (only support CSI ? 25 h, cursor on/off) \& CSI l (RM) reset mode (as above) .Ve .SH "EXAMPLES" .IX Header "EXAMPLES" For some examples, including how to interface Term::VT102 with Net::Telnet or a command such as \s-1SSH,\s0 please see the \fBexamples/\fR directory in the distribution. .SH "AUTHORS" .IX Header "AUTHORS" Copyright (C) 2003 Andrew Wood \f(CW\*(C`\*(C'\fR. Distributed under the terms of the Artistic License 2.0. .PP Credit is also due to: .PP .Vb 2 \& Charles Harker \& \- reported and helped to diagnose a bug in the handling of TABs \& \& Steve van der Burg \& \- supplied basis for an example script using Net::Telnet \& \& Chris R. Donnelly \& \- added support for DECTCEM, partial support for SM/RM \& \& Paul L. Stoddard \& \- reported a possible bug in cursor movement handling \& \& Joerg Walter \& \- provided a patch for Unicode handling .Ve .SH "THINGS TO WATCH OUT FOR" .IX Header "THINGS TO WATCH OUT FOR" Make sure that your code understands \s-1NULL\s0 (\e000) \- you will get this in strings where nothing has been printed on the screen. For instance, the sequence \*(L"12\ee[C34\*(R" (\*(L"12\*(R", \*(L"\s-1CUF\s0 (move right)\*(R", \*(L"34\*(R") you might think would yield the string \*(L"12 34\*(R", but in fact it can also yield \*(L"12\e00034\*(R" \- that is, \*(L"12\*(R" followed by a zero byte followed by \*(L"34\*(R". This is because the screen's contents defaults to zeroes, not spaces. .PP To avoid that, use \fBrow_plaintext\fR, which will convert NULLs to spaces, instead of \fBrow_text\fR. .PP Different types of terminal disagree on certain corner cases. For example, \&\fBgnome-terminal\fR and \fBscreen\fR handle \s-1TAB\s0 stops and TABbing past the end of the screen in slightly different ways. Term::VT102 is closer to \fBscreen\fR in the way it handles this sort of thing. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fBconsole_codes\fR(4), \fBIO::Pty\fR(3)