Re: FreeCOM bug in CTTY: Should not open O_BINARY (CR/LF issue)

Bart Oldeman <[email protected]> Tue, 12 Nov 2002 00:34:18 -0500 (EST)
Newsgroups gmane.os.freedos.devel
Message-ID <[email protected]>
On Tue, 12 Nov 2002, Eric Auer wrote:

> Whatever. Strange enough, the MS kernel seems to have an internal CR-LF
> conversion, so in MS-DOS, opening CON in O_BINARY mode does not harm.
> Not sure if I should like this feature.

be aware that DOSEMU's BIOS int10/ah=0xe when presented with a bare line
feed will also perform a CR. DOSEMU's source code (src/base/bios/int10.c)
says

  case '\n':         /* Newline */
    /* Color newline */
    newline_att = gfx_mode ? 0 : ATTR(SCREEN_ADR(s) + ypos*co + xpos);
    ypos++;
    xpos = 0;                  /* EDLIN needs this behavior */
    break;

not sure why EDLIN needs this ....

However if you use NANSI.SYS in DOSEMU, then the BIOS isn't used for this
screen output, and it processes an LF as a pure line feed.

> To whoever wants to know: The kernel uses the CON device -> ConTable ->
> CONSOLE.ASM -> int 0x29 ("fast console output") -> int 0x10.ah=0x0e.bx=7,
> plus some more steps of abstraction between you doing "printf" and the
> file I/O functions reaching CON. Surprising how layered even the DOS
> architecture is. I bet that int 0x10 call is a "single point of failure"
> where you could catch most DOS output (well, apart from the other two
> popular int 0x10.ah=2 and int 0x10.ah=9). Let us read CHARIO.C and CONSOLE.ASM
> -> BinaryCharIO or int 0x29 used... but hey, it seems to boil down
> to the same int 0x29 -> int 0x10.0x0e !

yes. This is how NANSI.SYS can gain such an enormous speed difference,
replacing the
                mov     al,[es:di]
                inc     di
                int     29h                     ; Do fast output call
                loop    ConWr1                  ; Loop if more to output
loop in console.asm (used for raw(binary) output by one that writes
directly to video memory. On the other hand NANSI doesn't play nicely with
dosemu -dumb.

when you use cooked output it will also use int29 but now in the chario.c
loop.

  for (xfer = 0; err >= SUCCESS && xfer < n && *bp != CTL_Z; bp++, xfer++)
    err = cooked_put_char(sft_idx, *bp);

where cooked_put_char expands TABs and calls raw_put_char, which calls
int29.

LF -> CRLF expansion is something that is not done by the FreeDOS kernel
at all.

> Conclusion: Bart/Tom, correct me if I am wrong, but am I right that
> FreeDOS -never- uses INT 0x10.2/9 for console output?

that is correct.

> Then I have
> to tell all of you that my TURBO3.COM driver will NOT speed up the
> output of FreeDOS. Probably it WILL speed up the output when NANSI.SYS
> is used.

Nope.

> Would be nice if some NANSI expert could tell me. When my
> assumptions are all correct, then I should probably write a TURBOFD.COM
> driver that speeds up INT 0x10.0x0e instead of INT 0x10.2/9 !?!?

Yep.

Bart

P.S. this is the nansi loop:

        ; The Inner Loop: 4+12 +4+4 +4+4 +4+4 +4+18 = 60? cycles/loop
        ; on 8088; at 4.77 MHz, that gives 13 microseconds/loop.
        ; At that speed, it takes 25 milliseconds to fill a screen.

        ; Get a character, put it on the screen, repeat 'til end of line
        ; or no more characters.
        jcxz    f_loopdone              ; if count = 0, we're already
done.
        cmp     cs:escvector, 0         ; If in middle of an escape
sequence,
        jnz     f_in_escapex            ; jump to escape sequence handler.

f_tloop:; | If in graphics mode, jump to alternate loop
        ; | What a massive kludge!  A better approach would have been
        ; | to collect characters for a "write n chars" routine
        ; | which would handle both text and graphics modes.
        call    in_g_mode
        jc      f_t_cloop
        jmp     f_g_cloop

f_t_cloop:
        LODSB                           ; get char! (al = ds:[si++])
        cmp     al, 28                  ; is it a control char?
        jb      f_control               ;  maybe...
f_t_nctl:
        STOSW                           ; Put Char! (es:[di++] = ax)
        dec     dx                      ; count down to end of line
        loopnz  f_t_cloop               ; and go back for more.
        jz      f_t_at_eol              ; at end of line; maybe do a crlf.
        jmp     short f_loopdone

f_looploop:
f_ansi_exit:                            ; in case we switched into
        loopnz  f_tloop                 ; a graphics mode
f_t_at_eol:
        jz      f_at_eol

f_loopdone: