News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

How can i do a reverse line feed? (jump the cursor to the previous line.)

Started by bugthis, August 21, 2024, 11:21:11 PM

Previous topic - Next topic

bugthis

How can i do a reverse line feed?

Let's say i have the following code:
Code (asm) Select
.MODEL SMALL, C
.STACK 128

.DATA
STR1   DB "Hello World!", 13, 10, "$"
; Uncomment one of the following two lines:
; REV_LF DB 8Dh, 13, "$"     ; 8Dh character Reverse Line Feed didn't work
; REV_LF DB 1Bh, 7, 13, "$"  ; ESC-7 didn't work
STR2   DB "Hello in the Matrix!", 13, 10, "$"

.CODE
START:  MOV AX, @DATA
        MOV DS, AX

        ; print STR1
        MOV DX, OFFSET STR1
        MOV AH, 09h
        INT 21h

        ; do a reverse line feed
        MOV DX, OFFSET REV_LF
        MOV AH, 09h
        INT 21h

        ; print STR2
        MOV DX, OFFSET STR2
        MOV AH, 09h
        INT 21h

        MOV AH, 4Ch
        INT 21h
END START

STR2 should overwrite the output of STR1.
Thus a working REV_LF is required.
One REV_LF must be uncommented.

For REV_LF i tried to use character 8Dh:
https://unicode-explorer.com/c/008D

and ESC+7, which should be if I am not mistaken "1Bh, 7"
https://www.ibm.com/docs/en/zos/2.4.0?topic=descriptions-col-remove-reverse-line-feeds

But no variant works.
In both variants i get this output:
Hello World!
Hello in the Matrix!

I did not get this:
Hello in the Matrix!

So how can i jump back to the previous line with the cursor?

EDIT:
According to:
https://en.wikipedia.org/wiki/C0_and_C1_control_codes#C0_controls
8Dh is the same as 1Bh, 4Dh (ASCII M). So the 7 on the IBM page doesn't seem to be correct. At least it doesn't seem to be standard compliant.
So i tried this:
REV_LF DB 1Bh, 4Dh, 13, "$"  ; ESC-M didn't work
But that didn't work either.

_japheth

Quote from: bugthis on August 21, 2024, 11:21:11 PMBut that didn't work either.

IIRC, for ESC-sequences to work in DOS the ANSI.SYS driver must have been loaded in config.sys.
Dummheit, gepaart mit Dreistigkeit - eine furchtbare Macht.

FORTRANS

Hi,

  As _japheth says, load ANSI.SYS in your CONFIG.SYS to
use escape commands.

  Or use the BIOS interrupts.

INT 10,02, Set Cursor Position

  Sets the cursor's position.  If the page is the active page
the display is updated.

INPUT AH = 2
      BH = Page Number
      DH = Row (0 is top row)
      DL = Column (0 is leftmost column)

OUTPUT Cursor position changed

Note: DH, DL = 0, 0 = Upper Left

INT 10,03, Get Cursor Status

  Read current cursor position and configuration.

INPUT AH = 3
      BH = Page Number

OUTPUT DH = Row of cursor (0 is top row)
      DL = Column (0 is leftmost column)
      CH = Top line of cursor in character cell
      CL = Bottom line.

Regards,

Steve N.

bugthis

Thanks to both of you.

ANSI.SYS was loaded (in this case NANSI.SYS from FreeDOS).
But I still found a solution.
I had to change the following line from:

REV_LF DB 1Bh, 4Dh, 13, "$"  ; ESC-M didn't work even when ANSI.SYS is loaded
to:
REV_LF DB 1Bh, "[1A", 13, "$"  ; This works with ANSI.SYS loaded.
With this small change it works. I don't know what else is done by [1A, apart from [ defining the start of the ESC sequence in the string and the number standing for the number of lines to go back. I found this solution in the assembly language book I'm working with. I think I'll compare the hexdump of the two solutions.

Thanks for the tip about the BIOS interrupt routine. I would actually like this solution better, but it would mean additional code, as I would first have to determine the cursor position and then calculate where the cursor should be placed. The ANSI solution is simpler and is sufficient for now. But I will certainly use the solution with the BIOS routines in another case.

BTW, since ANSI.SYS was mentioned. Is there an easy way to check in assembler if ANSI.SYS is loaded?

EDIT:
Okay, i did a hexdump comparison. See the screenshots.
I wonder what this z instead of x at address 0x02 and # instead of ! at address 0x44 means?

Strings only:


All binary code as hex numbers:





zedd151

At 0x2 is different because of a 2 byte difference in size between the two compared files...

FORTRANS

Hi,

   I made a subroutine and modified your program to call it.
see the attachment.

Cheers,

Steve N.

FORTRANS

Hi,

Quote from: bugthis on August 22, 2024, 01:30:58 AMBTW, since ANSI.SYS was mentioned. Is there an easy way to
check in assembler if ANSI.SYS is loaded?

  Some reference information from "Undocumented DOS", Second
Edition, Andrew Schulman et. al., Addison Wesley, 1994.

QuoteNotes: COMMAND.COM 3.2 and 3.3 compare the INT 29h vector
against the INT 20h vector and assume that ANSI.SYS is installed
if the INT 29h segment is larger.

HTH,

Steve N.

sinsi

Quote from: bugthis on August 22, 2024, 01:30:58 AMBTW, since ANSI.SYS was mentioned. Is there an easy way to check in assembler if ANSI.SYS is loaded?
Ralf Brown's Interrupt List
INT 2F - DOS 4.0+ ANSI.SYS - INSTALLATION CHECK

    AX = 1A00h
Return: AL = FFh if installed

🍺🍺🍺

NoCforMe

Here's a program I wrote decades ago that shows all installed devices. You could modify it to search for a particular driver. It uses undocumented INT 21 function 52h.

/********************************
* SHOWDEVS.C
*
* 12/16/89 by me
********************************/

#include <stdio.h>
#include <dos.h>
#include <ctype.h>

struct SREGS segregs;
union REGS inregs,outregs;

main()
{
unsigned long far *devptr;
unsigned char far *nameptr;
char ioctl;

inregs.h.ah = 0x52; /* "Undocumented" (officially, at least) function */
int86x(0x21,&inregs,&outregs,&segregs);
segread (&segregs);
devptr = MK_FP (segregs.es, outregs.x.bx + 0x22);
devptr = *devptr;
printf("\nThe following devices are installed:\n\n");
printf(" address   type   name/# units\tIOCTL?\n-----------------------------------------\n");
while (FP_OFF (devptr) != 0xFFFF)
{
nameptr = (char far *)devptr;
if ((*(nameptr+5)&0x40)!=0)
ioctl='y';
else ioctl='n';
if ((*(nameptr+5)&0x80)!=0)
/* Character device: */
printf("%Fp   char.   %8.8Fs\t  %c\n",devptr,nameptr+10,ioctl);
/* Block device: */
else
printf("%Fp   block     [%c]\t  %c\n",devptr,*(nameptr + 10)+'0',ioctl);
devptr = *devptr;
}
}
Assembly language programming should be fun. That's why I do it.