Full Code of taviso/lotusdrv for AI

master fb6ebcafc44e cached
58 files
298.7 KB
94.3k tokens
258 symbols
1 requests
Download .txt
Showing preview only (316K chars total). Download the full file or copy to clipboard to get everything.
Repository: taviso/lotusdrv
Branch: master
Commit: fb6ebcafc44e
Files: 58
Total size: 298.7 KB

Directory structure:
gitextract_179s49fo/

├── .gitignore
├── Makefile
├── README.md
├── addin/
│   ├── Makefile
│   ├── lpl.cnf
│   └── modern.pl
├── attr.c
├── attr.h
├── bundle.c
├── bundle.h
├── cgadraw/
│   ├── COPYING
│   ├── Makefile
│   ├── README.md
│   ├── attr.c
│   ├── box.c
│   ├── caca.h
│   ├── cacaint.h
│   ├── cacastub.h
│   ├── cacatyp.h
│   ├── canvas.c
│   ├── cgadraw.c
│   ├── charset.c
│   ├── codec.h
│   ├── config.h
│   ├── conic.c
│   ├── drawtest.c
│   ├── frame.c
│   ├── line.c
│   ├── snprintf.c
│   ├── snprintf.h
│   ├── string.c
│   ├── transfrm.c
│   └── triangle.c
├── config.h
├── debug/
│   ├── CGAF25CC.VBD
│   ├── CGAF25CC.cmarkers
│   ├── CGAF25CC.names
│   ├── Makefile
│   ├── exports.inc
│   ├── l13vcgad.asm
│   ├── logcalls.c
│   └── logcbs.c
├── debug.c
├── debug.h
├── draw.c
├── draw.h
├── idatypes.h
├── l13vdemu.asm
├── l13vdemu.def
├── lmbcs.c
├── lmbcs.h
├── lotcalls.h
├── lotdemu.c
├── lottypes.h
├── raster.c
├── raster.h
├── snprintf.c
└── snprintf.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.obj
.*.sw?
*.pdb
*.tlb
*.res
*.exe
*.manifest
*.exp
*.ilk
*.lib
*.udb
*.msi
*.wixobj
*.wixpdb
*.dll
*.o
*.core
*.map
*.dld
*.zip
*.id0
*.id1
*.idb
*.nam
*.til
compile_commands.json
build-*/
a.out
autom4te.cache/
config.log
.clangd/


================================================
FILE: Makefile
================================================
DFLAGS=-quiet -dumb
ASFLAGS=/m3 /q /z /w0
#CPPFLAGS=/Icgadraw /I. /DNDEBUG
CPPFLAGS=/Icgadraw /I.
WARNLEVEL=4
CFLAGS=/AL /nologo /NDAAA /Od /G3 /Gs /Gc /Zi /FPi87 /Zp1 /Zl /Gf /f- /W$(WARNLEVEL)
LDFLAGS=/map:full /b /nologo /onerror:noexe /nod /noe
LDLIBS=LLIBC7
EFLAGS=/verbose /nologo
LFLAGS=-q

.PHONY: clean distclean cgadraw.lib l13vcgaf.obj l13vcgad.obj logcalls.obj logcbs.obj

%.plc: %.pl
	@rm -f $@
	dosemu $(DFLAGS) -E "IN G:/ LPL $(LFLAGS) $<"

%.plh: %.plc
	@rm -f $@
	dosemu $(DFLAGS) -E "IN G:/ DESCRIBE $<"

# MS-DOS doesn't allow long commandlines, so params are written to a "response"
# file.

%.obj: %.c
	@rm -f $@
	printf "$(CPPFLAGS) $(CFLAGS)\r\n" > $(@:.obj=.cl)
	dosemu $(DFLAGS) -E "IN G:/ CL /c @$(@:.obj=.cl) /Fo$@ $<"
	@rm -f $(@:.obj=.cl)

%.obj: %.asm
	@rm -f $@
	dosemu $(DFLAGS) -E "IN G:/ TASM32 /c $(ASFLAGS) $<"

%.exe: %.obj
	@rm -f $@
	printf "$^,$@,$(@:.exe=),$(LDLIBS),nul\r\n" > $(@:.exe=.lnk)
	dosemu $(DFLAGS) -E "IN G:/ LINK $(LDFLAGS) @$(@:.exe=.lnk)"
	@rm -f $(@:.exe=.lnk)

%.dld: %.exe
	mv $< $@
#	dosemu $(DFLAGS) -E "IN G:/ EXEHDR $(EFLAGS) $@"

all: l13vdemu.dld

cgadraw.lib:
	make -C cgadraw $@
	@cp cgadraw/$@ $@

l13vcgaf.obj l13vcgad.obj logcalls.obj logcbs.obj:
	make -C debug $@
	@cp debug/$@ $@

# Third party code, reduce warning level
snprintf.obj: WARNLEVEL=1

l13vdemu.exe: LDLIBS+=CGADRAW
l13vdemu.exe: l13vdemu.obj lotdemu.obj snprintf.obj debug.obj bundle.obj \
              lmbcs.obj attr.obj draw.obj raster.obj | cgadraw.lib

# Original driver.
l13vcgaf.exe: l13vcgaf.obj

# Original driver patched to add debugging calls.
l13vcgad.exe: l13vcgad.obj logcalls.obj logcbs.obj snprintf.obj debug.obj \
              l13vcgaf.obj

release: CPPFLAGS+=/DRELEASE
release: clean l13vdemu.dld
	zip l13vdemu.zip l13vdemu.dld README.md

install: l13vdemu.dld
	cp $< ~/.dosemu/drive_c/123R4D/L13VCGAF.DLD

clean:
	rm -f *.exe *.obj *.dld *.map *.pdb *.lnk *.cl *.lib *.plc l13vdemu.zip

distclean: clean
	make -C cgadraw clean
	make -C debug clean
	make -C addin clean


================================================
FILE: README.md
================================================
# Lotus 1-2-3 R4D Display Driver for DOSEMU2

This is a work-in-progress display driver for Lotus 1-2-3 R4D to enable support
for arbitrary text resolutions in [DOSEMU2](https://github.com/dosemu2/dosemu2).

That means you can run 123 in a maximized xterm, and see more columns than
you could possibly need!

![screenshot](screenshot.png)

> Note: This driver is intended for DOSEMU2 in *term* mode, i.e. running in a terminal.

This driver basically works, but I haven't fully implemented all the API, so if you
do something unusual it might trap.

If you are excited to help hacking on this, or writing modern add-ins for
1-2-3, I'd love to hear about it!

Future ideas:

- A FILE driver that adds native support for XLS, or ODT?
- ~~libcaca support so that text mode graphs work?~~ working on it!
- More modern @functions?
- Javascript/Python/lua bindings?

# Graphs

I have an incomplete ascii-art graphics implementation. That means drawing
simple graphs will work even in a terminal! Don't expect high resolution
graphics, but simple line, bar, and even pie charts really do work!

Here is a screenshot of a sine wave line graph, it will improve in future.

![sinewave](lotus-sine-wave.gif)

I have some development notes available
[here](https://lock.cmpxchg8b.com/lotus123.html).

# Building

> If you just want a binary to try, check out the Releases section.

Note that this code isn't really ready for non-developer use yet, but you're
welcome to try it out and tell me about any visual glitches or crashes!

# 123 FAQ

**Q. Which display driver should I be using for terminal mode?**

A. Select the CGA driver during install, then install this driver :-)

**Q. If I use the /Worksheet/Status command, 123 does not see all the EMS/XMS memory I have configured in DOSEMU?**

A. Try adding `SET 123MEMSIZE=134217728` (that's 128M, use an appropriate number for your configuration) to `fdppauto.bat`.

There is also `123SWAPPATH`, `123VIRTSIZE` and `123SWAPSIZE` if you want to tweak it.

**Q. If I try to use 123 in two xterms simultaneously, I get an error like "The stand-alone license is not currently available".**

A. Add something like this to your `fdppauto.bat`

```bat
REM CLEAN UP LICENSE FOR 1-2-3
DEL C:\123R4D\LICENSE.000 > NUL
COPY NUL C:\123R4D\LICENSE.000 > NUL
```

**Q. What DOSEMU settings do you use for 123?**

A. Here is my [dosemurc](https://lock.cmpxchg8b.com/files/dosemurc)

**Q. How can I send 123 worksheets to someone else?**

A. LibreOffice can open and convert WK3 files, if necessary. Most formulas and features will be preserved.

**Q. Can I fetch external data into 123, like stock prices with a macro?**

A. I use a macro like this to fetch stock prices (simplified):

```
{SYSTEM "UNIX stocks.sh GOOGL > %TEMP%\STOCKS.TXT"}
{OPEN "C:\TMP\STOCKS.TXT", "r"}
{READLN C1}
{CLOSE}
```

The `UNIX` command is a `DOSEMU` feature, it runs a command on the host. The
123 online help explains how to loop over ranges, etc.

I have an example sheet that demonstrates how to do this available
[here](https://lock.cmpxchg8b.com/files/findemo.wk3), you can use it as a
template.

It automatically populates a table of stock prices when you press `Alt-R`. Use
`Ctrl-PgUp` and `Ctrl-PgDn` to switch sheets and browse around.

You will need a script in your `$PATH` called `stocks.sh` like this, and don't
forget to add the full path to your `$_unix_exec` in `.dosemurc`.

```bash
#!/bin/bash

declare api="https://query1.finance.yahoo.com/v7/finance/quote"
declare filter=".quoteResponse.result[].regularMarketPrice"

curl -s "${api}?symbols=${1:-^GSPC}" | jq -r "${filter}" | cat
```

**Q. What do I need to know to get started?**

A. If you don't have a manual, there's one available online [here](https://archive.org/details/lotus-1-2-3-release-3.1-reference/Lotus%201-2-3%20Release%203.1%20-%20Tutorial).

If you've used any spreadsheet before, you should be able to get started
quickly. Functions use `@` instead of `=`, but the common functions like
`@SUM`, `@AVG`, `@INDEX`, and even `@HLOOKUP` all work as you would expect.

| Key | Description |
| --- | ------------|
|  /  | Open the 123 menu.
| F1  | Open online help.
| F2  | Edit an existing cell contents, just type to overwrite cell.
| F3  | Show names, press F3 while editing to see a list of functions or ranges.
| F4  | Enter point mode - it's like visual mode in Vim - to select ranges.
| F5  | Goto Address.
| Ctrl PgUp/PgDn | Move between open tabs/sheets (use /Worksheet/Insert/Sheet to add a tab).
| F9  | Recalculate, if you press it while entering a formula, the text will be replaced with it's value.

If you want to be able to save your documents to your home directory, you can
add something like `LREDIR D: \\linux\fs\home\foo\Documents` to your `fdppauto.bat`.

**Q. Why does selecting text with the mouse not work?**

DOSEMU emulates a mouse (even in terminal mode!) so when you try to select text
DOSEMU is reporting mouse events to DOS.

How to stop that happening depends on your terminal.

In `XTerm` you can Shift-RightClick and disable "Allow Mouse Ops", change the
`allowMouseOps` resource to make it permanent.

In most terminals you can hold down `Shift` while selecting.

**Q. How do I undo my last action?**

The default keybinding is `Alt-F4`, but that can be hard to enter on modern systems.

If you can't press `Alt-F4` easily, there are two options.

1. DOSEMU has support for simulating modifier keys, you can
   type: Ctrl-6 Shift-A F4 Ctrl-6 Shift-A.
2. That's a lot of keys though, another workaround is to add
   [SCANCODE](http://bretjohnson.us/index.htm) to your `%PATH%`, and then bind
   a macro to something like `{SYSTEM "SCANCODE M 2,W 1,0 \"READY\",ALT-F4"}`.

You can then bind a macro to `Alt-Z` by naming a range `\z`.



================================================
FILE: addin/Makefile
================================================
addins: modern.plc

include ../Makefile



================================================
FILE: addin/lpl.cnf
================================================
-U C:\123DADK\INCLUDE
-U C:\123R4D\


================================================
FILE: addin/modern.pl
================================================
-- vim: set ft=rexx:
--
-- This is an attempt to implement some modern @FUNCTIONS in 1-2-3 DOS.
--
-- Tavis Ormandy <taviso@gmail.com>, April 2022
--

module modern is

use Register
use Range
use Cell
use AtStr
use Utility

Register("Match", At_Function)

-- MATCH(lookup_value, lookup_array, [match_type])
procedure Match (integer value, Range table, integer mtype) returns (integer result)
    signals (Err, NA)
    purpose ("Searches for a specified item in a range of cells") is

    integer count = 0

    result = 0

    -- This only works on one-dimensional tables.
    if table.Columns <> 1 & table.Rows <> 1 then
        signal Err
    end if

    if table.Sheets <> 1 then
        signal Err
    end if

    begin
        for integer i = 1 to table.Sheets loop
            for integer j = 1 to table.Columns loop
                for integer k = 1 to table.Rows loop
                    count = count + 1
                    case mtype
                        of 1:
                        -- MATCH finds the largest value that is less than or equal to lookup_value
                            if table[i, j, k] <= value then
                                result = count
                            end if
                        of 0:
                        -- MATCH finds the first value that is exactly equal to lookup_value
                            if table[i, j, k] = value then
                                result = count
                                return
                            end if
                        of -1:
                        -- MATCH finds the smallest value that is greater than or equal to lookup_value
                            if table[i, j, k] >= value then
                                result = count
                            end if
                    end case
                end loop
            end loop
        end loop

        -- If MATCH is unsuccessful in finding a match, it returns the #N/A error value.
        if result = 0 then
            signal NA
        end if
    end
    except on others (string sig) do
        Print("Signal ", sig, " raised.")
    end except

end procedure Match



================================================
FILE: attr.c
================================================
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <conio.h>
#include <dos.h>

#include "config.h"
#include "debug.h"
#include "idatypes.h"
#include "lottypes.h"
#include "lotcalls.h"
#include "bundle.h"
#include "lmbcs.h"
#include "attr.h"

// These map 1-2-3's character attribute flags onto CGA character attributes.
// i.e.
//
// NOTE: I tend to write 123 attributes in octal, and CGA attributes in hex.
//
//                               BG  FG
//   123  CGA    Decoded         *RGB*RGB   BG        FG (* is bright or blinking)
//   000  0x07   0b00000111 -> 0b00000111   WHITE  /  BLACK
//   001  0x30   0b00110000 -> 0b00110000   CYAN   /  WHITE
//   002  0x17   0b00010111 -> 0b00010111   BLUE   /  BLACK
//   003  0xC0   0b11000000 -> 0b11000000  *RED    /  WHITE
//   030  0x06   0b00000110 -> 0b00000110  BLACK   /  YELLOW
//   ...and so on.
//
//  123 has 6 bits of attributes, 3 FG and 3 BG bits
//
//  111 111
//
//  CGA has two additional bits, for bright/blinking.
//
const unsigned char lot_char_attr_table[0100] = {
   0x07, 0x30, 0x17, 0xC0, 0x70, 0x30, 0x10, 0x40,
   0x01, 0x32, 0x13, 0xC1, 0x71, 0x31, 0x11, 0x41,
   0x02, 0x31, 0x12, 0xC2, 0x72, 0x32, 0x12, 0x42,
   0x06, 0x36, 0x16, 0xC6, 0x73, 0x33, 0x13, 0x43,
   0x04, 0x34, 0x14, 0xC7, 0x74, 0x34, 0x14, 0x44,
   0x09, 0x3A, 0x1B, 0xC9, 0x75, 0x35, 0x15, 0x45,
   0x0C, 0x3C, 0x1C, 0xCF, 0x76, 0x36, 0x16, 0x46,
   0x0E, 0x3E, 0x1E, 0xCE, 0x77, 0x37, 0x17, 0x47,
};



================================================
FILE: attr.h
================================================
#ifndef __ATTR_H
#define __ATTR_H

// The octal usage here is intentional, doesn't it make the numbers look nice?

extern const unsigned char lot_char_attr_table[0100];

// Masks to change only bg/fg.
#define ATTR_FG   070
#define ATTR_BG   007
#define ATTR_ALL  077
#define ATTR_NONE 000

// Sometimes lotus will pass a BG attribute only.
#define MKFG(c) (unsigned char)((((c) & 007) << 3))

// Just for symmetry, not sure it's needed.
#define MKBG(c) (unsigned char)((((c) & 007)))

// If you need to specify them both.
#define MKFGBG(f,b) (unsigned char)(((((b) & 007) << 3)) | ((((f) & 007))))

// Translate a 123 attribute into a CGA attribute.
#define LATTR(c) (lot_char_attr_table[(c) & ATTR_ALL])

#endif


================================================
FILE: bundle.c
================================================
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <conio.h>
#include <dos.h>

#include "config.h"
#include "debug.h"
#include "lottypes.h"
#include "idatypes.h"
#include "lotcalls.h"
#include "bundle.h"

int ParseConfig(struct BDLHDR far *bdlptr)
{
    trace("ParseVbdConfig");

    //callbacks->MapMemVmr(bdlptr, 0);
    //callbacks->LoadVmr(0);

    traceint(bdlptr->bdllen);
    traceint(bdlptr->bdlver);
    traceint(bdlptr->driver_id);
    traceint(bdlptr->bundle_id);

    tracebuf(bdlptr, bdlptr->bdllen);

    return 0;
}


================================================
FILE: bundle.h
================================================
#ifndef __BUNDLE_H
#define __BUNDLE_H

int ParseConfig(struct BDLHDR far *bdlptr);

#endif


================================================
FILE: cgadraw/COPYING
================================================

The files in this directory are derived from libcaca, which is published under
the license below.

        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
                    Version 2, December 2004

 Copyright (C) 2004 Sam Hocevar

 Everyone is permitted to copy and distribute verbatim or modified
 copies of this license document, and changing it is allowed as long
 as the name is changed.

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. You just DO WHAT THE FUCK YOU WANT TO.



================================================
FILE: cgadraw/Makefile
================================================
DFLAGS=-quiet -dumb
WARNLEVEL=0
CPPFLAGS=/I.
CFLAGS=/AL /nologo /NDAAB /Od /G3 /Gs /Gc /Zi /FPi87 /Zp1 /Zl /Gf /f- /W$(WARNLEVEL) /WX
LDFLAGS=
LDLIBS=CGADRAW

.PHONY: clean

# MS-DOS doesn't allow long commandlines, so params are written to a "response"
# file.

%.obj: %.c
	@rm -f $@
	printf "$(CPPFLAGS) $(CFLAGS)\r\n" > $(@:.obj=.cl)
	dosemu $(DFLAGS) -E "IN G:/ CL /c @$(@:.obj=.cl) /Fo$@ $<"
	@rm -f $(@:.obj=.cl)

%.lib: %.obj
	@rm -f $@
	printf "$(LFLAGS) $(addprefix +,$^),nul\r\n" > $(@:.lib=.cl)
	dosemu $(DFLAGS) -E "IN G:/ LIB $@ @$(@:.lib=.cl)"
	@rm -f $(@:.lib=.cl)

%.exe: %.obj
	@rm -f $@
	printf "$(CFLAGS) $(LDFLAGS) $^ $(addprefix /link ,$(LDLIBS))\r\n" > $(@:.exe=.cl)
	dosemu $(DFLAGS) -E "IN G:/ CL /Fe$@ @$(@:.exe=.cl)"
	@rm -f $(@:.exe=.cl)

all: cgadraw.lib

drawtest.obj: CFLAGS:=$(filter-out /Zl,$(CFLAGS))
drawtest.exe: snprintf.obj | cgadraw.lib

cgadraw.lib: attr.obj box.obj canvas.obj charset.obj conic.obj frame.obj \
             line.obj string.obj transfrm.obj triangle.obj

clean:
	rm -f *.exe *.lib *.obj *.map *.pdb *.cl


================================================
FILE: cgadraw/README.md
================================================
# cgadraw

This is a stripped down version of libcaca 0.99 used for adding drawing
primitives to the CGA framebuffer.

You might ask why not just use full libcaca, but it requires around
`8 * width * height` bytes for the canvas, plus another `width * height`
to get the data out of a canvas, and some management overhead.

If you want to add frames or any kind of transformation, double that again at
least.

That is a totally reasonable amount normally, but in a tiny display driver
it's really pushing the limits of what I can scratch together.


================================================
FILE: cgadraw/attr.c
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains functions for attribute management and colourspace
 *  conversions.
 */

#include "config.h"

#include "caca.h"
#include "cacaint.h"

static uint8_t nearest_ansi(uint16_t);

/* RGB colours for the ANSI palette. There is no real standard, so we
 * use the same values as gnome-terminal. The 7th colour (brown) is a bit
 * special: 0xfa50 instead of 0xfaa0. */
static const uint16_t ansitab16[16] =
{
    0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
    0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
};

/* Same table, except on 14 bits (3-4-4-3) */
static const uint16_t ansitab14[16] =
{
    0x3800, 0x3805, 0x3850, 0x3855, 0x3d00, 0x3d05, 0x3d28, 0x3d55,
    0x3aaa, 0x3aaf, 0x3afa, 0x3aff, 0x3faa, 0x3faf, 0x3ffa, 0x3fff,
};

/** \brief Get the text attribute at the given coordinates.
 *
 *  Get the internal \e libcaca attribute value of the character at the
 *  given coordinates. The attribute value has 32 significant bits,
 *  organised as follows from MSB to LSB:
 *  - 3 bits for the background alpha
 *  - 4 bits for the background red component
 *  - 4 bits for the background green component
 *  - 3 bits for the background blue component
 *  - 3 bits for the foreground alpha
 *  - 4 bits for the foreground red component
 *  - 4 bits for the foreground green component
 *  - 3 bits for the foreground blue component
 *  - 4 bits for the bold, italics, underline and blink flags
 *
 *  If the coordinates are outside the canvas boundaries, the current
 *  attribute is returned.
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param x X coordinate.
 *  \param y Y coordinate.
 *  \return The requested attribute.
 */
uint32_t caca_get_attr(caca_canvas_t const *cv, int x, int y)
{
    if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
        return cv->curattr;

    return cv->c[x + y * cv->width].attr; // XXX FIXME
}

/** \brief Set the default character attribute.
 *
 *  Set the default character attribute for drawing. Attributes define
 *  foreground and background colour, transparency, bold, italics and
 *  underline styles, as well as blink. String functions such as
 *  caca_printf() and graphical primitive functions such as caca_draw_line()
 *  will use this attribute.
 *
 *  The value of \e attr is either:
 *  - a 32-bit integer as returned by caca_get_attr(), in which case it
 *    also contains colour information,
 *  - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
 *    \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
 *    setting the attribute does not modify the current colour information.
 *
 *  To retrieve the current attribute value, use caca_get_attr(-1,-1).
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param attr The requested attribute value.
 *  \return This function always returns 0.
 */
int caca_set_attr(caca_canvas_t *cv, uint32_t attr)
{
    if(attr < 0x00000010)
        attr = (cv->curattr & 0xfffffff0) | attr;

    cv->curattr = attr;

    return 0;
}

/** \brief Unset flags in the default character attribute.
 *
 *  Unset flags in the default character attribute for drawing. Attributes
 *  define foreground and background colour, transparency, bold, italics and
 *  underline styles, as well as blink. String functions such as
 *  caca_printf() and graphical primitive functions such as caca_draw_line()
 *  will use this attribute.
 *
 *  The value of \e attr is a combination (bitwise OR) of style values
 *  (\e CACA_UNDERLINE, \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS).
 *  Unsetting these attributes does not modify the current colour information.
 *
 *  To retrieve the current attribute value, use caca_get_attr(-1,-1).
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param attr The requested attribute values to unset.
 *  \return This function always returns 0.
 */
int caca_unset_attr(caca_canvas_t *cv, uint32_t attr)
{
    cv->curattr &= ~(attr & 0x0000000f);

    return 0;
}

/** \brief Toggle flags in the default character attribute.
 *
 *  Toggle flags in the default character attribute for drawing. Attributes
 *  define foreground and background colour, transparency, bold, italics and
 *  underline styles, as well as blink. String functions such as
 *  caca_printf() and graphical primitive functions such as caca_draw_line()
 *  will use this attribute.
 *
 *  The value of \e attr is a combination (bitwise OR) of style values
 *  (\e CACA_UNDERLINE, \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS).
 *  Toggling these attributes does not modify the current colour information.
 *
 *  To retrieve the current attribute value, use caca_get_attr(-1,-1).
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param attr The requested attribute values to toggle.
 *  \return This function always returns 0.
 */
int caca_toggle_attr(caca_canvas_t *cv, uint32_t attr)
{
    cv->curattr ^= attr & 0x0000000f;

    return 0;
}

/** \brief Set the character attribute at the given coordinates.
 *
 *  Set the character attribute, without changing the character's value. If
 *  the character at the given coordinates is a fullwidth character, both
 *  cells' attributes are replaced.
 *
 *  The value of \e attr is either:
 *  - a 32-bit integer as returned by caca_get_attr(), in which case it
 *    also contains colour information,
 *  - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
 *    \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
 *    setting the attribute does not modify the current colour information.
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param x X coordinate.
 *  \param y Y coordinate.
 *  \param attr The requested attribute value.
 *  \return This function always returns 0.
 */
int caca_put_attr(caca_canvas_t *cv, int x, int y, uint32_t attr)
{
    if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
        return 0;

    cv->c[x + y * cv->width].attr = caca_attr_to_ansi(attr);
    return 0;
}

/** \brief Set the default colour pair for text (ANSI version).
 *
 *  Set the default ANSI colour pair for text drawing. String functions such
 *  as caca_printf() and graphical primitive functions such as caca_draw_line()
 *  will use these attributes.
 *
 *  Color values are those defined in caca.h, such as CACA_RED
 *  or CACA_TRANSPARENT.
 *
 *  If an error occurs, -1 is returned and \b errno is set accordingly:
 *  - \c EINVAL At least one of the colour values is invalid.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param fg The requested ANSI foreground colour.
 *  \param bg The requested ANSI background colour.
 *  \return 0 in case of success, -1 if an error occurred.
 */
int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
{
    uint32_t attr;

    if(fg > 0x20 || bg > 0x20)
    {
        seterrno(EINVAL);
        return -1;
    }

    attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
    cv->curattr = (cv->curattr & 0x0000000f) | attr;

    return 0;
}

/** \brief Set the default colour pair for text (truecolor version).
 *
 *  Set the default ARGB colour pair for text drawing. String functions such
 *  as caca_printf() and graphical primitive functions such as caca_draw_line()
 *  will use these attributes.
 *
 *  Colors are 16-bit ARGB values, each component being coded on 4 bits. For
 *  instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
 *  white with 50% alpha (A=8 R=15 G=15 B=15).
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param fg The requested ARGB foreground colour.
 *  \param bg The requested ARGB background colour.
 *  \return This function always returns 0.
 */
int caca_set_color_argb(caca_canvas_t *cv, uint16_t fg, uint16_t bg)
{
    uint32_t attr;

    if(fg < 0x100)
        fg += 0x100;

    if(bg < 0x100)
        bg += 0x100;

    fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
    bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);

    attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
    cv->curattr = (cv->curattr & 0x0000000f) | attr;

    return 0;
}

/** \brief Get DOS ANSI information from attribute.
 *
 *  Get the ANSI colour pair for a given attribute. The returned value is
 *  an 8-bit value whose higher 4 bits are the background colour and lower
 *  4 bits are the foreground colour.
 *
 *  If the attribute has ARGB colours, the nearest colour is used. Special
 *  attributes such as \e CACA_DEFAULT and \e CACA_TRANSPARENT are not
 *  handled and are both replaced with \e CACA_LIGHTGRAY for the foreground
 *  colour and \e CACA_BLACK for the background colour.
 *
 *  This function never fails. If the attribute value is outside the expected
 *  32-bit range, higher order bits are simply ignored.
 *
 *  \param attr The requested attribute value.
 *  \return The corresponding DOS ANSI value.
 */
uint8_t caca_attr_to_ansi(uint32_t attr)
{
    uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
    uint8_t bg = nearest_ansi(attr >> 18);

    return (fg < 0x10 ? fg : CACA_LIGHTGRAY)
            | ((bg < 0x10 ? bg : CACA_BLACK) << 4);
}

/** \brief Get ANSI foreground information from attribute.
 *
 *  Get the ANSI foreground colour value for a given attribute. The returned
 *  value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
 *  colours, or the special value \e CACA_DEFAULT meaning the media's
 *  default foreground value, or the special value \e CACA_TRANSPARENT.
 *
 *  If the attribute has ARGB colours, the nearest colour is returned.
 *
 *  This function never fails. If the attribute value is outside the expected
 *  32-bit range, higher order bits are simply ignored.
 *
 *  \param attr The requested attribute value.
 *  \return The corresponding ANSI foreground value.
 */
uint8_t caca_attr_to_ansi_fg(uint32_t attr)
{
    return nearest_ansi((attr >> 4) & 0x3fff);
}

/** \brief Get ANSI background information from attribute.
 *
 *  Get the ANSI background colour value for a given attribute. The returned
 *  value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
 *  colours, or the special value \e CACA_DEFAULT meaning the media's
 *  default background value, or the special value \e CACA_TRANSPARENT.
 *
 *  If the attribute has ARGB colours, the nearest colour is returned.
 *
 *  This function never fails. If the attribute value is outside the expected
 *  32-bit range, higher order bits are simply ignored.
 *
 *  \param attr The requested attribute value.
 *  \return The corresponding ANSI background value.
 */
uint8_t caca_attr_to_ansi_bg(uint32_t attr)
{
    return nearest_ansi(attr >> 18);
}

/** \brief Get 12-bit RGB foreground information from attribute.
 *
 *  Get the 12-bit foreground colour value for a given attribute. The returned
 *  value is a native-endian encoded integer with each red, green and blue
 *  values encoded on 8 bits in the following order:
 *   - 8-11 most significant bits: red
 *   - 4-7 most significant bits: green
 *   - least significant bits: blue
 *
 *  This function never fails. If the attribute value is outside the expected
 *  32-bit range, higher order bits are simply ignored.
 *
 *  \param attr The requested attribute value.
 *  \return The corresponding 12-bit RGB foreground value.
 */
uint16_t caca_attr_to_rgb12_fg(uint32_t attr)
{
    uint16_t fg = (attr >> 4) & 0x3fff;

    if(fg < (0x10 | 0x40))
        return ansitab16[fg ^ 0x40] & 0x0fff;

    if(fg == (CACA_DEFAULT | 0x40))
        return ansitab16[CACA_LIGHTGRAY] & 0x0fff;

    if(fg == (CACA_TRANSPARENT | 0x40))
        return ansitab16[CACA_LIGHTGRAY] & 0x0fff;

    return (fg << 1) & 0x0fff;
}

/** \brief Get 12-bit RGB background information from attribute.
 *
 *  Get the 12-bit background colour value for a given attribute. The returned
 *  value is a native-endian encoded integer with each red, green and blue
 *  values encoded on 8 bits in the following order:
 *   - 8-11 most significant bits: red
 *   - 4-7 most significant bits: green
 *   - least significant bits: blue
 *
 *  This function never fails. If the attribute value is outside the expected
 *  32-bit range, higher order bits are simply ignored.
 *
 *  \param attr The requested attribute value.
 *  \return The corresponding 12-bit RGB background value.
 */
uint16_t caca_attr_to_rgb12_bg(uint32_t attr)
{
    uint16_t bg = attr >> 18;

    if(bg < (0x10 | 0x40))
        return ansitab16[bg ^ 0x40] & 0x0fff;

    if(bg == (CACA_DEFAULT | 0x40))
        return ansitab16[CACA_BLACK] & 0x0fff;

    if(bg == (CACA_TRANSPARENT | 0x40))
        return ansitab16[CACA_BLACK] & 0x0fff;

    return (bg << 1) & 0x0fff;
}

/** \brief Get 64-bit ARGB information from attribute.
 *
 *  Get the 64-bit colour and alpha values for a given attribute. The values
 *  are written as 8-bit integers in the \e argb array in the following order:
 *   - \e argb[0]: background alpha value
 *   - \e argb[1]: background red value
 *   - \e argb[2]: background green value
 *   - \e argb[3]: background blue value
 *   - \e argb[4]: foreground alpha value
 *   - \e argb[5]: foreground red value
 *   - \e argb[6]: foreground green value
 *   - \e argb[7]: foreground blue value
 *
 *  This function never fails. If the attribute value is outside the expected
 *  32-bit range, higher order bits are simply ignored.
 *
 *  \param attr The requested attribute value.
 *  \param argb An array of 8-bit integers.
 */
void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
{
    uint16_t fg = (attr >> 4) & 0x3fff;
    uint16_t bg = attr >> 18;

    if(bg < (0x10 | 0x40))
        bg = ansitab16[bg ^ 0x40];
    else if(bg == (CACA_DEFAULT | 0x40))
        bg = ansitab16[CACA_BLACK];
    else if(bg == (CACA_TRANSPARENT | 0x40))
        bg = 0x0fff;
    else
        bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);

    argb[0] = bg >> 12;
    argb[1] = (bg >> 8) & 0xf;
    argb[2] = (bg >> 4) & 0xf;
    argb[3] = bg & 0xf;

    if(fg < (0x10 | 0x40))
        fg = ansitab16[fg ^ 0x40];
    else if(fg == (CACA_DEFAULT | 0x40))
        fg = ansitab16[CACA_LIGHTGRAY];
    else if(fg == (CACA_TRANSPARENT | 0x40))
        fg = 0x0fff;
    else
        fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);

    argb[4] = fg >> 12;
    argb[5] = (fg >> 8) & 0xf;
    argb[6] = (fg >> 4) & 0xf;
    argb[7] = fg & 0xf;
}

/*
 * XXX: the following functions are local
 */

static uint8_t nearest_ansi(uint16_t argb14)
{
    unsigned int i, best, dist;

    if(argb14 < (0x10 | 0x40))
        return argb14 ^ 0x40;

    if(argb14 == (CACA_DEFAULT | 0x40) || argb14 == (CACA_TRANSPARENT | 0x40))
        return argb14 ^ 0x40;

    if(argb14 < 0x0fff) /* too transparent */
        return CACA_TRANSPARENT;

    best = CACA_DEFAULT;
    dist = 0x3fff;
    for(i = 0; i < 16; i++)
    {
        unsigned int d = 0;
        int a, b;

        a = (ansitab14[i] >> 7) & 0xf;
        b = (argb14 >> 7) & 0xf;
        d += (a - b) * (a - b);

        a = (ansitab14[i] >> 3) & 0xf;
        b = (argb14 >> 3) & 0xf;
        d += (a - b) * (a - b);

        a = (ansitab14[i] << 1) & 0xf;
        b = (argb14 << 1) & 0xf;
        d += (a - b) * (a - b);

        if(d < dist)
        {
            dist = d;
            best = i;
        }
    }

    return best;
}

#define RGB12TO24(i) \
   (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
  | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
  | ((uint32_t)(i & 0x00f) * 0x000011))

uint32_t _caca_attr_to_rgb24fg(uint32_t attr)
{
    return RGB12TO24(caca_attr_to_rgb12_fg(attr));
}

uint32_t _caca_attr_to_rgb24bg(uint32_t attr)
{
    return RGB12TO24(caca_attr_to_rgb12_bg(attr));
}



================================================
FILE: cgadraw/box.c
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains box drawing functions, both filled and outline.
 */

#include "config.h"

#if !defined(__KERNEL__)
#   include <stdlib.h>
#endif

#include "caca.h"
#include "cacaint.h"

static int draw_box(caca_canvas_t *cv, int x, int y, int w, int h,
                    uint32_t const *chars);

/** \brief Draw a box on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x X coordinate of the upper-left corner of the box.
 *  \param y Y coordinate of the upper-left corner of the box.
 *  \param w Width of the box.
 *  \param h Height of the box.
 *  \param ch UTF-32 character to be used to draw the box.
 *  \return This function always returns 0.
 */
int caca_draw_box(caca_canvas_t *cv, int x, int y, int w, int h, uint32_t ch)
{
    int x2 = x + w - 1;
    int y2 = y + h - 1;

    caca_draw_line(cv,  x,  y,  x, y2, ch);
    caca_draw_line(cv,  x, y2, x2, y2, ch);
    caca_draw_line(cv, x2, y2, x2,  y, ch);
    caca_draw_line(cv, x2,  y,  x,  y, ch);

    return 0;
}

/** \brief Draw a thin box on the canvas.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x X coordinate of the upper-left corner of the box.
 *  \param y Y coordinate of the upper-left corner of the box.
 *  \param w Width of the box.
 *  \param h Height of the box.
 *  \return This function always returns 0.
 */
int caca_draw_thin_box(caca_canvas_t *cv, int x, int y, int w, int h)
{
    static uint32_t const ascii_chars[] =
    {
        '-', '|', ',', '`', '.', '\''
    };

    return draw_box(cv, x, y, w, h, ascii_chars);
}

/** \brief Draw a box on the canvas using CP437 characters.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x X coordinate of the upper-left corner of the box.
 *  \param y Y coordinate of the upper-left corner of the box.
 *  \param w Width of the box.
 *  \param h Height of the box.
 *  \return This function always returns 0.
 */
int caca_draw_cp437_box(caca_canvas_t *cv, int x, int y, int w, int h)
{
    static uint32_t const cp437_chars[] =
    {
        /* ─ │ ┌ └ ┐ ┘ */
        0x2500, 0x2502, 0x250c, 0x2514, 0x2510, 0x2518
    };

    return draw_box(cv, x, y, w, h, cp437_chars);
}

/** \brief Fill a box on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x X coordinate of the upper-left corner of the box.
 *  \param y Y coordinate of the upper-left corner of the box.
 *  \param w Width of the box.
 *  \param h Height of the box.
 *  \param ch UTF-32 character to be used to draw the box.
 *  \return This function always returns 0.
 */
int caca_fill_box(caca_canvas_t *cv, int x, int y, int w, int h,
                   uint32_t ch)
{
    int i, j, xmax, ymax;

    int x2 = x + w - 1;
    int y2 = y + h - 1;

    if(x > x2)
    {
        int tmp = x;
        x = x2; x2 = tmp;
    }

    if(y > y2)
    {
        int tmp = y;
        y = y2; y2 = tmp;
    }

    xmax = cv->width - 1;
    ymax = cv->height - 1;

    if(x2 < 0 || y2 < 0 || x > xmax || y > ymax)
        return 0;

    if(x < 0) x = 0;
    if(y < 0) y = 0;
    if(x2 > xmax) x2 = xmax;
    if(y2 > ymax) y2 = ymax;

#if 0
    /* FIXME: this fails with fullwidth character blits. Also, the dirty
     * rectangle handling may miss fullwidth cells. */
    /* Optimise dirty rectangle handling, part 1 */
    cv->dirty_disabled++;
#endif

    for(j = y; j <= y2; j++)
        for(i = x; i <= x2; i++)
            caca_put_char(cv, i, j, ch);

#if 0
    /* Optimise dirty rectangle handling, part 2 */
    cv->dirty_disabled--;
    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, x, y, x2 - x + 1, y2 - y + 1);
#endif

    return 0;
}

/*
 * XXX: The following functions are local.
 */

static int draw_box(caca_canvas_t *cv, int x, int y, int w, int h,
                    uint32_t const *chars)
{
    int i, j, xmax, ymax;

    int x2 = x + w - 1;
    int y2 = y + h - 1;

    if(x > x2)
    {
        int tmp = x;
        x = x2; x2 = tmp;
    }

    if(y > y2)
    {
        int tmp = y;
        y = y2; y2 = tmp;
    }

    xmax = cv->width - 1;
    ymax = cv->height - 1;

    if(x2 < 0 || y2 < 0 || x > xmax || y > ymax)
        return 0;

    /* Draw edges */
    if(y >= 0)
        for(i = x < 0 ? 1 : x + 1; i < x2 && i < xmax; i++)
            caca_put_char(cv, i, y, chars[0]);

    if(y2 <= ymax)
        for(i = x < 0 ? 1 : x + 1; i < x2 && i < xmax; i++)
            caca_put_char(cv, i, y2, chars[0]);

    if(x >= 0)
        for(j = y < 0 ? 1 : y + 1; j < y2 && j < ymax; j++)
            caca_put_char(cv, x, j, chars[1]);

    if(x2 <= xmax)
        for(j = y < 0 ? 1 : y + 1; j < y2 && j < ymax; j++)
            caca_put_char(cv, x2, j, chars[1]);

    /* Draw corners */
    caca_put_char(cv, x, y, chars[2]);
    caca_put_char(cv, x, y2, chars[3]);
    caca_put_char(cv, x2, y, chars[4]);
    caca_put_char(cv, x2, y2, chars[5]);

    return 0;
}



================================================
FILE: cgadraw/caca.h
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/** \file caca.h
 *  \author Sam Hocevar <sam@hocevar.net>
 *  \brief The \e libcaca public header.
 *
 *  This header contains the public types and functions that applications
 *  using \e libcaca may use.
 */

#ifndef __CACA_H__
#define __CACA_H__

#include <cacatyp.h>

#include <stdarg.h>

#undef __extern
#if defined _DOXYGEN_SKIP_ME
#elif defined _WIN32 && defined __LIBCACA__ && defined DLL_EXPORT
#   define __extern extern __declspec(dllexport)
#elif defined _WIN32 && !defined __LIBCACA__ && !defined CACA_STATIC
#   define __extern extern __declspec(dllimport)
#elif defined CACA_ENABLE_VISIBILITY
#   define __extern extern __attribute__((visibility("default")))
#else
#   define __extern extern
#endif

/** libcaca API version */
#define CACA_API_VERSION_1

#ifdef __cplusplus
extern "C"
{
#endif

/** \e libcaca canvas */
typedef struct caca_canvas caca_canvas_t;
/** dither structure */
typedef struct caca_dither caca_dither_t;
/** character font structure */
typedef struct caca_charfont caca_charfont_t;
/** bitmap font structure */
typedef struct caca_font caca_font_t;
/** file handle structure */
typedef struct caca_file caca_file_t;
/** \e libcaca display context */
typedef struct caca_display caca_display_t;
/** \e libcaca event structure */
typedef struct caca_event caca_event_t;

/** \defgroup caca_attr libcaca attribute definitions
 *
 *  Colours and styles that can be used with caca_set_attr().
 *
 *  @{ */
/** \e libcaca colour keyword */
enum caca_color
{
    CACA_BLACK =        0x00, /**< The colour index for black. */
    CACA_BLUE =         0x01, /**< The colour index for blue. */
    CACA_GREEN =        0x02, /**< The colour index for green. */
    CACA_CYAN =         0x03, /**< The colour index for cyan. */
    CACA_RED =          0x04, /**< The colour index for red. */
    CACA_MAGENTA =      0x05, /**< The colour index for magenta. */
    CACA_BROWN =        0x06, /**< The colour index for brown. */
    CACA_LIGHTGRAY =    0x07, /**< The colour index for light gray. */
    CACA_DARKGRAY =     0x08, /**< The colour index for dark gray. */
    CACA_LIGHTBLUE =    0x09, /**< The colour index for blue. */
    CACA_LIGHTGREEN =   0x0a, /**< The colour index for light green. */
    CACA_LIGHTCYAN =    0x0b, /**< The colour index for light cyan. */
    CACA_LIGHTRED =     0x0c, /**< The colour index for light red. */
    CACA_LIGHTMAGENTA = 0x0d, /**< The colour index for light magenta. */
    CACA_YELLOW =       0x0e, /**< The colour index for yellow. */
    CACA_WHITE =        0x0f, /**< The colour index for white. */
    CACA_DEFAULT =      0x10, /**< The output driver's default colour. */
    CACA_TRANSPARENT =  0x20, /**< The transparent colour. */
};

/** \e libcaca style keyword */
enum caca_style
{
    CACA_BOLD =      0x01, /**< The style mask for bold. */
    CACA_ITALICS =   0x02, /**< The style mask for italics. */
    CACA_UNDERLINE = 0x04, /**< The style mask for underline. */
    CACA_BLINK =     0x08, /**< The style mask for blink. */
};
/*  @} */

/** \brief User event type enumeration.
 *
 *  This enum serves two purposes:
 *  - Build listening masks for caca_get_event().
 *  - Define the type of a \e caca_event_t.
 */
enum caca_event_type
{
    CACA_EVENT_NONE =          0x0000, /**< No event. */

    CACA_EVENT_KEY_PRESS =     0x0001, /**< A key was pressed. */
    CACA_EVENT_KEY_RELEASE =   0x0002, /**< A key was released. */
    CACA_EVENT_MOUSE_PRESS =   0x0004, /**< A mouse button was pressed. */
    CACA_EVENT_MOUSE_RELEASE = 0x0008, /**< A mouse button was released. */
    CACA_EVENT_MOUSE_MOTION =  0x0010, /**< The mouse was moved. */
    CACA_EVENT_RESIZE =        0x0020, /**< The window was resized. */
    CACA_EVENT_QUIT =          0x0040, /**< The user requested to quit. */

};

#define CACA_EVENT_ANY 0xffff  /**< Bitmask for any event. */

/** \brief Handling of user events.
 *
 *  This structure is filled by caca_get_event() when an event is received.
 *  It is an opaque structure that should only be accessed through
 *  caca_event_get_type() and similar functions. The struct members may no
 *  longer be directly accessible in future versions.
 */
struct caca_event
{
    enum caca_event_type type; /**< The event type. */
    union
    {
        struct { int x, y, button; } mouse;
        struct { int w, h; } resize;
        struct { int ch; uint32_t utf32; char utf8[8]; } key;
    } data; /**< The event information data */
#if !defined(_DOXYGEN_SKIP_ME)
    uint8_t padding[16];
#endif
};

/** \brief Option parsing.
 *
 * This structure contains commandline parsing information for systems
 * where getopt_long() is unavailable.
 */
struct caca_option
{
    char const *name;
    int has_arg;
    int *flag;
    int val;
};

/** \brief Special key values.
 *
 *  Special key values returned by caca_get_event() for which there is no
 *  printable ASCII equivalent.
 */
enum caca_key
{
    CACA_KEY_UNKNOWN = 0x00, /**< Unknown key. */

    /* The following keys have ASCII equivalents */
    CACA_KEY_CTRL_A =    0x01, /**< The Ctrl-A key. */
    CACA_KEY_CTRL_B =    0x02, /**< The Ctrl-B key. */
    CACA_KEY_CTRL_C =    0x03, /**< The Ctrl-C key. */
    CACA_KEY_CTRL_D =    0x04, /**< The Ctrl-D key. */
    CACA_KEY_CTRL_E =    0x05, /**< The Ctrl-E key. */
    CACA_KEY_CTRL_F =    0x06, /**< The Ctrl-F key. */
    CACA_KEY_CTRL_G =    0x07, /**< The Ctrl-G key. */
    CACA_KEY_BACKSPACE = 0x08, /**< The backspace key. */
    CACA_KEY_TAB =       0x09, /**< The tabulation key. */
    CACA_KEY_CTRL_J =    0x0a, /**< The Ctrl-J key. */
    CACA_KEY_CTRL_K =    0x0b, /**< The Ctrl-K key. */
    CACA_KEY_CTRL_L =    0x0c, /**< The Ctrl-L key. */
    CACA_KEY_RETURN =    0x0d, /**< The return key. */
    CACA_KEY_CTRL_N =    0x0e, /**< The Ctrl-N key. */
    CACA_KEY_CTRL_O =    0x0f, /**< The Ctrl-O key. */
    CACA_KEY_CTRL_P =    0x10, /**< The Ctrl-P key. */
    CACA_KEY_CTRL_Q =    0x11, /**< The Ctrl-Q key. */
    CACA_KEY_CTRL_R =    0x12, /**< The Ctrl-R key. */
    CACA_KEY_PAUSE =     0x13, /**< The pause key. */
    CACA_KEY_CTRL_T =    0x14, /**< The Ctrl-T key. */
    CACA_KEY_CTRL_U =    0x15, /**< The Ctrl-U key. */
    CACA_KEY_CTRL_V =    0x16, /**< The Ctrl-V key. */
    CACA_KEY_CTRL_W =    0x17, /**< The Ctrl-W key. */
    CACA_KEY_CTRL_X =    0x18, /**< The Ctrl-X key. */
    CACA_KEY_CTRL_Y =    0x19, /**< The Ctrl-Y key. */
    CACA_KEY_CTRL_Z =    0x1a, /**< The Ctrl-Z key. */
    CACA_KEY_ESCAPE =    0x1b, /**< The escape key. */
    CACA_KEY_DELETE =    0x7f, /**< The delete key. */

    /* The following keys do not have ASCII equivalents but have been
     * chosen to match the SDL equivalents */
    CACA_KEY_UP =    0x111, /**< The up arrow key. */
    CACA_KEY_DOWN =  0x112, /**< The down arrow key. */
    CACA_KEY_LEFT =  0x113, /**< The left arrow key. */
    CACA_KEY_RIGHT = 0x114, /**< The right arrow key. */

    CACA_KEY_INSERT =   0x115, /**< The insert key. */
    CACA_KEY_HOME =     0x116, /**< The home key. */
    CACA_KEY_END =      0x117, /**< The end key. */
    CACA_KEY_PAGEUP =   0x118, /**< The page up key. */
    CACA_KEY_PAGEDOWN = 0x119, /**< The page down key. */

    CACA_KEY_F1 =  0x11a, /**< The F1 key. */
    CACA_KEY_F2 =  0x11b, /**< The F2 key. */
    CACA_KEY_F3 =  0x11c, /**< The F3 key. */
    CACA_KEY_F4 =  0x11d, /**< The F4 key. */
    CACA_KEY_F5 =  0x11e, /**< The F5 key. */
    CACA_KEY_F6 =  0x11f, /**< The F6 key. */
    CACA_KEY_F7 =  0x120, /**< The F7 key. */
    CACA_KEY_F8 =  0x121, /**< The F8 key. */
    CACA_KEY_F9 =  0x122, /**< The F9 key. */
    CACA_KEY_F10 = 0x123, /**< The F10 key. */
    CACA_KEY_F11 = 0x124, /**< The F11 key. */
    CACA_KEY_F12 = 0x125, /**< The F12 key. */
    CACA_KEY_F13 = 0x126, /**< The F13 key. */
    CACA_KEY_F14 = 0x127, /**< The F14 key. */
    CACA_KEY_F15 = 0x128  /**< The F15 key. */
};

/** \defgroup libcaca libcaca basic functions
 *
 *  These functions provide the basic \e libcaca routines for library
 *  initialisation, system information retrieval and configuration.
 *
 *  @{ */
__extern caca_canvas_t * far caca_create_canvas(int, int, int, int);
__extern int caca_manage_canvas(caca_canvas_t *, int (*)(void *), void *);
__extern int caca_unmanage_canvas(caca_canvas_t *, int (*)(void *), void *);
__extern int caca_set_canvas_size(caca_canvas_t *, int, int);
__extern int caca_get_canvas_width(caca_canvas_t const *);
__extern int caca_get_canvas_height(caca_canvas_t const *);
__extern uint32_t const * far caca_get_canvas_chars(caca_canvas_t const *);
__extern uint32_t const * far caca_get_canvas_attrs(caca_canvas_t const *);
__extern int caca_free_canvas(caca_canvas_t *);
__extern int caca_rand(int, int);
__extern char const * far caca_get_version(void);
/*  @} */

/** \defgroup caca_canvas libcaca canvas drawing
 *
 *  These functions provide low-level character printing routines and
 *  higher level graphics functions.
 *
 *  @{ */
#define CACA_MAGIC_FULLWIDTH 0x000ffffe /**< Used to indicate that the previous character was a fullwidth glyph. */
__extern int caca_gotoxy(caca_canvas_t *, int, int);
__extern int caca_wherex(caca_canvas_t const *);
__extern int caca_wherey(caca_canvas_t const *);
__extern int caca_put_char(caca_canvas_t *, int, int, uint32_t);
__extern uint32_t caca_get_char(caca_canvas_t const *, int, int);
__extern int caca_put_str(caca_canvas_t *, int, int, char const *);
__extern int caca_printf(caca_canvas_t *, int, int, char const *, ...);
__extern int caca_vprintf(caca_canvas_t *, int, int, char const *, va_list);
__extern int caca_clear_canvas(caca_canvas_t *);
__extern int caca_set_canvas_handle(caca_canvas_t *, int, int);
__extern int caca_get_canvas_handle_x(caca_canvas_t const *);
__extern int caca_get_canvas_handle_y(caca_canvas_t const *);
__extern int caca_blit(caca_canvas_t *, int, int, caca_canvas_t const *,
                       caca_canvas_t const *);
__extern int caca_set_canvas_boundaries(caca_canvas_t *, int, int, int, int);
/*  @} */

/** \defgroup caca_dirty libcaca dirty rectangle manipulation
 *
 *  These functions manipulate dirty rectangles for optimised blitting.
 *  @{ */
__extern int caca_disable_dirty_rect(caca_canvas_t *);
__extern int caca_enable_dirty_rect(caca_canvas_t *);
__extern int caca_get_dirty_rect_count(caca_canvas_t *);
__extern int caca_get_dirty_rect(caca_canvas_t *, int, int *, int *,
                                 int *, int *);
__extern int caca_add_dirty_rect(caca_canvas_t *, int, int, int, int);
__extern int caca_remove_dirty_rect(caca_canvas_t *, int, int, int, int);
__extern int caca_clear_dirty_rect_list(caca_canvas_t *);
/*  @} */

/** \defgroup caca_transform libcaca canvas transformation
 *
 *  These functions perform horizontal and vertical canvas flipping.
 *
 *  @{ */
__extern int caca_invert(caca_canvas_t *);
__extern int caca_flip(caca_canvas_t *);
__extern int caca_flop(caca_canvas_t *);
__extern int caca_rotate_180(caca_canvas_t *);
__extern int caca_rotate_left(caca_canvas_t *);
__extern int caca_rotate_right(caca_canvas_t *);
__extern int caca_stretch_left(caca_canvas_t *);
__extern int caca_stretch_right(caca_canvas_t *);
/*  @} */

/** \defgroup caca_attributes libcaca attribute conversions
 *
 *  These functions perform conversions between attribute values.
 *
 *  @{ */
__extern uint32_t caca_get_attr(caca_canvas_t const *, int, int);
__extern int caca_set_attr(caca_canvas_t *, uint32_t);
__extern int caca_unset_attr(caca_canvas_t *, uint32_t);
__extern int caca_toggle_attr(caca_canvas_t *, uint32_t);
__extern int caca_put_attr(caca_canvas_t *, int, int, uint32_t);
__extern int caca_set_color_ansi(caca_canvas_t *, uint8_t, uint8_t);
__extern int caca_set_color_argb(caca_canvas_t *, uint16_t, uint16_t);
__extern uint8_t caca_attr_to_ansi(uint32_t);
__extern uint8_t caca_attr_to_ansi_fg(uint32_t);
__extern uint8_t caca_attr_to_ansi_bg(uint32_t);
__extern uint16_t caca_attr_to_rgb12_fg(uint32_t);
__extern uint16_t caca_attr_to_rgb12_bg(uint32_t);
__extern void caca_attr_to_argb64(uint32_t, uint8_t[8]);
/*  @} */

/** \defgroup caca_charset libcaca character set conversions
 *
 *  These functions perform conversions between usual character sets.
 *
 *  @{ */
__extern uint32_t caca_utf8_to_utf32(char const *, size_t *);
__extern size_t caca_utf32_to_utf8(char *, uint32_t);
__extern uint8_t caca_utf32_to_cp437(uint32_t);
__extern uint32_t caca_cp437_to_utf32(uint8_t);
__extern char caca_utf32_to_ascii(uint32_t);
__extern int caca_utf32_is_fullwidth(uint32_t);
/*  @} */

/** \defgroup caca_primitives libcaca primitives drawing
 *
 *  These functions provide routines for primitive drawing, such as lines,
 *  boxes, triangles and ellipses.
 *
 *  @{ */
__extern int caca_draw_line(caca_canvas_t *, int, int, int, int, uint32_t);
__extern int caca_draw_polyline(caca_canvas_t *, int const x[],
                                 int const y[], int, uint32_t);
__extern int caca_draw_thin_line(caca_canvas_t *, int, int, int, int);
__extern int caca_draw_thin_polyline(caca_canvas_t *, int const x[],
                                      int const y[], int);

__extern int caca_draw_circle(caca_canvas_t *, int, int, int, uint32_t);
__extern int caca_draw_ellipse(caca_canvas_t *, int, int, int, int, uint32_t);
__extern int caca_draw_thin_ellipse(caca_canvas_t *, int, int, int, int);
__extern int caca_fill_ellipse(caca_canvas_t *, int, int, int, int, uint32_t);

__extern int caca_draw_box(caca_canvas_t *, int, int, int, int, uint32_t);
__extern int caca_draw_thin_box(caca_canvas_t *, int, int, int, int);
__extern int caca_draw_cp437_box(caca_canvas_t *, int, int, int, int);
__extern int caca_fill_box(caca_canvas_t *, int, int, int, int, uint32_t);

__extern int caca_draw_triangle(caca_canvas_t *, int, int, int, int, int,
                                 int, uint32_t);
__extern int caca_draw_thin_triangle(caca_canvas_t *, int, int, int, int,
                                      int, int);
__extern int caca_fill_triangle(caca_canvas_t *, int, int, int, int, int,
                                 int, uint32_t);
__extern int caca_fill_triangle_textured(caca_canvas_t *cv,
                                         int coords[6],
                                         caca_canvas_t *tex,
                                         float uv[6]);
/*  @} */

/** \defgroup caca_frame libcaca canvas frame handling
 *
 *  These functions provide high level routines for canvas frame insertion,
 *  removal, copying etc.
 *
 *  @{ */
__extern int caca_get_frame_count(caca_canvas_t const *);
__extern int caca_set_frame(caca_canvas_t *, int);
__extern char const *caca_get_frame_name(caca_canvas_t const *);
__extern int caca_set_frame_name(caca_canvas_t *, char const *);
__extern int caca_create_frame(caca_canvas_t *, int);
__extern int caca_free_frame(caca_canvas_t *, int);
/*  @} */

/** \defgroup caca_dither libcaca bitmap dithering
 *
 *  These functions provide high level routines for dither allocation and
 *  rendering.
 *
 *  @{ */
__extern caca_dither_t *caca_create_dither(int, int, int, int,
                                             uint32_t, uint32_t,
                                             uint32_t, uint32_t);
__extern int caca_set_dither_palette(caca_dither_t *,
                                      uint32_t r[], uint32_t g[],
                                      uint32_t b[], uint32_t a[]);
__extern int caca_set_dither_brightness(caca_dither_t *, float);
__extern float caca_get_dither_brightness(caca_dither_t const *);
__extern int caca_set_dither_gamma(caca_dither_t *, float);
__extern float caca_get_dither_gamma(caca_dither_t const *);
__extern int caca_set_dither_contrast(caca_dither_t *, float);
__extern float caca_get_dither_contrast(caca_dither_t const *);
__extern int caca_set_dither_antialias(caca_dither_t *, char const *);
__extern char const * const * caca_get_dither_antialias_list(caca_dither_t
                                                              const *);
__extern char const * caca_get_dither_antialias(caca_dither_t const *);
__extern int caca_set_dither_color(caca_dither_t *, char const *);
__extern char const * const * caca_get_dither_color_list(caca_dither_t
                                                          const *);
__extern char const * caca_get_dither_color(caca_dither_t const *);
__extern int caca_set_dither_charset(caca_dither_t *, char const *);
__extern char const * const * caca_get_dither_charset_list(caca_dither_t
                                                            const *);
__extern char const * caca_get_dither_charset(caca_dither_t const *);
__extern int caca_set_dither_algorithm(caca_dither_t *, char const *);
__extern char const * const * caca_get_dither_algorithm_list(caca_dither_t
                                                              const *);
__extern char const * caca_get_dither_algorithm(caca_dither_t const *);
__extern int caca_dither_bitmap(caca_canvas_t *, int, int, int, int,
                         caca_dither_t const *, void const *);
__extern int caca_free_dither(caca_dither_t *);
/*  @} */

/** \defgroup caca_charfont libcaca character font handling
 *
 *  These functions provide character font handling routines.
 *
 *  @{ */
__extern caca_charfont_t *caca_load_charfont(void const *, size_t);
__extern int caca_free_charfont(caca_charfont_t *);
/*  @} */

/** \defgroup caca_font libcaca bitmap font handling
 *
 *  These functions provide bitmap font handling routines and high quality
 *  canvas to bitmap rendering.
 *
 *  @{ */
__extern caca_font_t *caca_load_font(void const *, size_t);
__extern char const * const * caca_get_font_list(void);
__extern int caca_get_font_width(caca_font_t const *);
__extern int caca_get_font_height(caca_font_t const *);
__extern uint32_t const *caca_get_font_blocks(caca_font_t const *);
__extern int caca_render_canvas(caca_canvas_t const *, caca_font_t const *,
                                 void *, int, int, int);
__extern int caca_free_font(caca_font_t *);
/*  @} */

/** \defgroup caca_figfont libcaca FIGfont handling
 *
 *  These functions provide FIGlet and TOIlet font handling routines.
 *
 *  @{ */
__extern int caca_canvas_set_figfont(caca_canvas_t *, char const *);
__extern int caca_set_figfont_smush(caca_canvas_t *, char const *);
__extern int caca_set_figfont_width(caca_canvas_t *, int);
__extern int caca_put_figchar(caca_canvas_t *, uint32_t);
__extern int caca_flush_figlet(caca_canvas_t *);
/*  @} */

/** \defgroup caca_file libcaca file IO
 *
 *  These functions allow to read and write files in a platform-independent
 *  way.
 *  @{ */
__extern caca_file_t *caca_file_open(char const *, const char *);
__extern int caca_file_close(caca_file_t *);
__extern uint32_t caca_file_tell(caca_file_t *);
__extern size_t caca_file_read(caca_file_t *, void *, size_t);
__extern size_t caca_file_write(caca_file_t *, const void *, size_t);
__extern char * caca_file_gets(caca_file_t *, char *, int);
__extern int caca_file_eof(caca_file_t *);
/*  @} */

/** \defgroup caca_importexport libcaca importers/exporters from/to various
 *  formats
 *
 *  These functions import various file formats into a new canvas, or export
 *  the current canvas to various text formats.
 *
 *  @{ */
__extern ssize_t caca_import_canvas_from_memory(caca_canvas_t *, void const *,
                                                size_t, char const *);
__extern ssize_t caca_import_canvas_from_file(caca_canvas_t *, char const *,
                                              char const *);
__extern ssize_t caca_import_area_from_memory(caca_canvas_t *, int, int,
                                              void const *, size_t,
                                              char const *);
__extern ssize_t caca_import_area_from_file(caca_canvas_t *, int, int,
                                            char const *, char const *);
__extern char const * const * caca_get_import_list(void);
__extern void *caca_export_canvas_to_memory(caca_canvas_t const *,
                                            char const *, size_t *);
__extern void *caca_export_area_to_memory(caca_canvas_t const *, int, int,
                                          int, int, char const *, size_t *);
__extern char const * const * caca_get_export_list(void);
/*  @} */

/** \defgroup caca_display libcaca display functions
 *
 *  These functions provide the basic \e libcaca routines for display
 *  initialisation, system information retrieval and configuration.
 *
 *  @{ */
__extern caca_display_t * caca_create_display(caca_canvas_t *);
__extern caca_display_t * caca_create_display_with_driver(caca_canvas_t *,
                                                          char const *);
__extern char const * const * caca_get_display_driver_list(void);
__extern char const * caca_get_display_driver(caca_display_t *);
__extern int caca_set_display_driver(caca_display_t *, char const *);
__extern int caca_free_display(caca_display_t *);
__extern caca_canvas_t * caca_get_canvas(caca_display_t *);
__extern int caca_refresh_display(caca_display_t *);
__extern int caca_set_display_time(caca_display_t *, int);
__extern int caca_get_display_time(caca_display_t const *);
__extern int caca_get_display_width(caca_display_t const *);
__extern int caca_get_display_height(caca_display_t const *);
__extern int caca_set_display_title(caca_display_t *, char const *);
__extern int caca_set_mouse(caca_display_t *, int);
__extern int caca_set_cursor(caca_display_t *, int);
/*  @} */

/** \defgroup caca_event libcaca event handling
 *
 *  These functions handle user events such as keyboard input and mouse
 *  clicks.
 *
 *  @{ */
__extern int caca_get_event(caca_display_t *, int, caca_event_t *, int);
__extern int caca_get_mouse_x(caca_display_t const *);
__extern int caca_get_mouse_y(caca_display_t const *);
__extern enum caca_event_type caca_get_event_type(caca_event_t const *);
__extern int caca_get_event_key_ch(caca_event_t const *);
__extern uint32_t caca_get_event_key_utf32(caca_event_t const *);
__extern int caca_get_event_key_utf8(caca_event_t const *, char *);
__extern int caca_get_event_mouse_button(caca_event_t const *);
__extern int caca_get_event_mouse_x(caca_event_t const *);
__extern int caca_get_event_mouse_y(caca_event_t const *);
__extern int caca_get_event_resize_width(caca_event_t const *);
__extern int caca_get_event_resize_height(caca_event_t const *);
/*  @} */

/** \defgroup caca_process libcaca process management
 *
 *  These functions help with various process handling tasks such as
 *  option parsing, DLL injection.
 *
 *  @{ */
__extern int caca_optind;
__extern char *caca_optarg;
__extern int caca_getopt(int, char * const[], char const *,
                         struct caca_option const *, int *);
/*  @} */

/** \brief DOS colours
 *
 *  This enum lists the colour values for the DOS conio.h compatibility
 *  layer.
 */
enum CACA_CONIO_COLORS
{
    CACA_CONIO_BLINK = 128,
    CACA_CONIO_BLACK = 0,
    CACA_CONIO_BLUE = 1,
    CACA_CONIO_GREEN = 2,
    CACA_CONIO_CYAN = 3,
    CACA_CONIO_RED = 4,
    CACA_CONIO_MAGENTA = 5,
    CACA_CONIO_BROWN = 6,
    CACA_CONIO_LIGHTGRAY = 7,
    CACA_CONIO_DARKGRAY = 8,
    CACA_CONIO_LIGHTBLUE = 9,
    CACA_CONIO_LIGHTGREEN = 10,
    CACA_CONIO_LIGHTCYAN = 11,
    CACA_CONIO_LIGHTRED = 12,
    CACA_CONIO_LIGHTMAGENTA = 13,
    CACA_CONIO_YELLOW = 14,
    CACA_CONIO_WHITE = 15,
};

/** \brief DOS cursor modes
 *
 *  This enum lists the cursor mode values for the DOS conio.h compatibility
 *  layer.
 */
enum CACA_CONIO_CURSOR
{
    CACA_CONIO__NOCURSOR = 0,
    CACA_CONIO__SOLIDCURSOR = 1,
    CACA_CONIO__NORMALCURSOR = 2,
};

/** \brief DOS video modes
 *
 *  This enum lists the video mode values for the DOS conio.h compatibility
 *  layer.
 */
enum CACA_CONIO_MODE
{
    CACA_CONIO_LASTMODE = -1,
    CACA_CONIO_BW40 = 0,
    CACA_CONIO_C40 = 1,
    CACA_CONIO_BW80 = 2,
    CACA_CONIO_C80 = 3,
    CACA_CONIO_MONO = 7,
    CACA_CONIO_C4350 = 64,
};

/** \brief DOS text area information
 *
 *  This structure stores text area information for the DOS conio.h
 *  compatibility layer.
 */
struct caca_conio_text_info
{
    unsigned char winleft;        /**< left window coordinate */
    unsigned char wintop;         /**< top window coordinate */
    unsigned char winright;       /**< right window coordinate */
    unsigned char winbottom;      /**< bottom window coordinate */
    unsigned char attribute;      /**< text attribute */
    unsigned char normattr;       /**< normal attribute */
    unsigned char currmode;       /**< current video mode:
                                       BW40, BW80, C40, C80, or C4350 */
    unsigned char screenheight;   /**< text screen's height */
    unsigned char screenwidth;    /**< text screen's width */
    unsigned char curx;           /**< x-coordinate in current window */
    unsigned char cury;           /**< y-coordinate in current window */
};

/** \brief DOS direct video control */
__extern int caca_conio_directvideo;

/** \brief DOS scrolling control */
__extern int caca_conio__wscroll;

/** \defgroup conio libcaca DOS conio.h compatibility layer
 *
 *  These functions implement DOS-like functions for high-level text
 *  operations.
 *
 *  @{ */
__extern char * caca_conio_cgets(char *str);
__extern void   caca_conio_clreol(void);
__extern void   caca_conio_clrscr(void);
__extern int    caca_conio_cprintf(const char *format, ...);
__extern int    caca_conio_cputs(const char *str);
__extern int    caca_conio_cscanf(char *format, ...);
__extern void   caca_conio_delay(unsigned int);
__extern void   caca_conio_delline(void);
__extern int    caca_conio_getch(void);
__extern int    caca_conio_getche(void);
__extern char * caca_conio_getpass(const char *prompt);
__extern int    caca_conio_gettext(int left, int top, int right, int bottom,
                                   void *destin);
__extern void   caca_conio_gettextinfo(struct caca_conio_text_info *r);
__extern void   caca_conio_gotoxy(int x, int y);
__extern void   caca_conio_highvideo(void);
__extern void   caca_conio_insline(void);
__extern int    caca_conio_kbhit(void);
__extern void   caca_conio_lowvideo(void);
__extern int    caca_conio_movetext(int left, int top, int right, int bottom,
                                    int destleft, int desttop);
__extern void   caca_conio_normvideo(void);
__extern void   caca_conio_nosound(void);
__extern int    caca_conio_printf(const char *format, ...);
__extern int    caca_conio_putch(int ch);
__extern int    caca_conio_puttext(int left, int top, int right, int bottom,
                                   void *destin);
__extern void   caca_conio__setcursortype(int cur_t);
__extern void   caca_conio_sleep(unsigned int);
__extern void   caca_conio_sound(unsigned int);
__extern void   caca_conio_textattr(int newattr);
__extern void   caca_conio_textbackground(int newcolor);
__extern void   caca_conio_textcolor(int newcolor);
__extern void   caca_conio_textmode(int newmode);
__extern int    caca_conio_ungetch(int ch);
__extern int    caca_conio_wherex(void);
__extern int    caca_conio_wherey(void);
__extern void   caca_conio_window(int left, int top, int right, int bottom);
/*  @} */

#if !defined(_DOXYGEN_SKIP_ME)
    /* Legacy stuff from beta versions, will probably disappear in 1.0 */

#   if defined __GNUC__ && __GNUC__ >= 3
#       define CACA_DEPRECATED __attribute__ ((__deprecated__))
#   else
#       define CACA_DEPRECATED
#   endif

#   if defined __GNUC__ && __GNUC__ > 3 && !defined __APPLE__
#       define CACA_ALIAS(x) __attribute__ ((weak, alias(#x)))
#   else
#       define CACA_ALIAS(x)
#   endif

#   if defined __GNUC__ && __GNUC__ > 3
#       define CACA_WEAK __attribute__ ((weak))
#   else
#       define CACA_WEAK
#   endif


/* Aliases from old libcaca functions */
#if !defined _WIN32 || !defined __GNUC__
__extern ssize_t caca_import_memory(caca_canvas_t *, void const *, size_t,
                                    char const *) CACA_DEPRECATED;
__extern ssize_t caca_import_file(caca_canvas_t *, char const *,
                                  char const *) CACA_DEPRECATED;
__extern void *caca_export_memory(caca_canvas_t const *, char const *,
                                  size_t *) CACA_DEPRECATED;
#endif

#   if !defined __LIBCACA__
#       define caca_get_cursor_x caca_wherex
#       define caca_get_cursor_y caca_wherey
#   endif
#endif

#ifdef __cplusplus
}
#endif

#undef __extern

#endif /* __CACA_H__ */


================================================
FILE: cgadraw/cacaint.h
================================================
/*
 *  libcaca       Colour ASCII-Art library
 *  Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
 *                All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

#ifndef __CACA_INTERNALS_H__
#define __CACA_INTERNALS_H__

#include <errno.h>

#include "cacastub.h"

typedef struct caca_timer caca_timer_t;
typedef struct caca_privevent caca_privevent_t;

#if !defined(_DOXYGEN_SKIP_ME)
#   define STAT_VALUES 32
#   define EVENTBUF_LEN 10
#   define MAX_DIRTY_COUNT 8
#endif

struct cgachar
{
    uint8_t c;
    uint8_t attr;
};

struct caca_frame
{
    /* Frame size */
    int width, height;

    /* Cell information */
    //uint32_t *chars;
    //uint32_t *attrs;
    struct cgachar far *c;

    /* Painting context */
    int x, y;
    int handlex, handley;
    uint32_t curattr;

    /* Frame name */
    char *name;
};

struct caca_canvas
{
    /* XXX: look at caca_set_canvas_boundaries() before adding anything
     * to this structure. The function is quite hacky. */

    /* Frame information */
    int frame, framecount;
    struct caca_frame *frames;

    /* Canvas management */
    int refcount;
    int autoinc;
    int (*resize_callback)(void *);
    void *resize_data;

    /* Dirty rectangles */
    int ndirty, dirty_disabled;
    struct
    {
        int xmin, ymin, xmax, ymax;
    }
    dirty[MAX_DIRTY_COUNT + 1];

    /* Shortcut to the active frame information */
    int width, height;
    //uint32_t *chars;
    //uint32_t *attrs;
    struct cgachar far *c;
    uint32_t curattr;

    /* FIGfont management */
    caca_charfont_t *ff;
};

/* Graphics driver */
enum caca_driver
{
    CACA_DRIVER_NULL = 0,
    CACA_DRIVER_RAW = 1,
#if defined(USE_COCOA)
    CACA_DRIVER_COCOA = 2,
#endif
#if defined(USE_CONIO)
    CACA_DRIVER_CONIO = 3,
#endif
#if defined(USE_GL)
    CACA_DRIVER_GL = 4,
#endif
#if defined(USE_NCURSES)
    CACA_DRIVER_NCURSES = 5,
#endif
#if defined(USE_SLANG)
    CACA_DRIVER_SLANG = 6,
#endif
#if defined(USE_VGA)
    CACA_DRIVER_VGA = 7,
#endif
#if defined(USE_WIN32)
    CACA_DRIVER_WIN32 = 8,
#endif
#if defined(USE_X11)
    CACA_DRIVER_X11 = 9,
#endif
};

/* Available external drivers */
#if defined(USE_COCOA)
int cocoa_install(caca_display_t *);
#endif
#if defined(USE_CONIO)
int conio_install(caca_display_t *);
#endif
#if defined(USE_GL)
int gl_install(caca_display_t *);
#endif
#if defined(USE_NCURSES)
int ncurses_install(caca_display_t *);
#endif
int null_install(caca_display_t *);
int raw_install(caca_display_t *);
#if defined(USE_SLANG)
int slang_install(caca_display_t *);
#endif
#if defined(USE_VGA)
int vga_install(caca_display_t *);
#endif
#if defined(USE_WIN32)
int win32_install(caca_display_t *);
#endif
#if defined(USE_X11)
int x11_install(caca_display_t *);
#endif

/* Timer structure */
struct caca_timer
{
    int last_sec, last_usec;
};

/* Statistic structure for profiling */
struct caca_stat
{
    int itable[STAT_VALUES];
    int32_t imean;
    char *name;
};

/* Private event structure */
struct caca_privevent
{
    enum caca_event_type type;

    union
    {
        struct { int x, y, button; } mouse;
        struct { int w, h; } resize;
        struct { int ch; uint32_t utf32; char utf8[8]; } key;
    } data;
};

/* Internal caca display context */
struct caca_display
{
    /* A link to our caca canvas */
    caca_canvas_t *cv;
    int autorelease;

#if defined(USE_PLUGINS)
    void *plugin;
#endif

    /* Device-specific functions */
    struct drv
    {
        char const * driver;
        enum caca_driver id;
        struct driver_private *p;

        int (* init_graphics) (caca_display_t *);
        int (* end_graphics) (caca_display_t *);
        int (* set_display_title) (caca_display_t *, char const *);
        int (* get_display_width) (caca_display_t const *);
        int (* get_display_height) (caca_display_t const *);
        void (* display) (caca_display_t *);
        void (* handle_resize) (caca_display_t *);
        int (* get_event) (caca_display_t *, caca_privevent_t *);
        void (* set_mouse) (caca_display_t *, int);
        void (* set_cursor) (caca_display_t *, int);
    } drv;

    /* Mouse position */
    struct mouse
    {
        int x, y;
    } mouse;

    /* Window resize handling */
    struct resize
    {
        int resized;   /* A resize event was requested */
        int allow;     /* The display driver allows resizing */
        int w, h; /* Requested width and height */
    } resize;

    /* Framerate handling */
    int delay, rendertime;
    caca_timer_t timer;
#if defined PROF
    struct caca_stat display_stat, wait_stat;
    struct caca_stat ev_sys_stat, ev_wait_stat;
#endif
    int lastticks;

    struct events
    {
#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
        caca_privevent_t buf[EVENTBUF_LEN];
        int queue;
#endif
#if defined(USE_SLANG) || defined(USE_NCURSES)
        caca_timer_t key_timer;
        int last_key_ticks;
        int autorepeat_ticks;
        caca_privevent_t last_key_event;
#endif
        uint8_t not_empty_struct;
    } events;
};

/* Dirty rectangle functions */
extern void _caca_clip_dirty_rect_list(caca_canvas_t *);

/* Colour functions */
extern uint32_t _caca_attr_to_rgb24fg(uint32_t);
extern uint32_t _caca_attr_to_rgb24bg(uint32_t);

/* Frames functions */
extern void _caca_save_frame_info(caca_canvas_t *);
extern void _caca_load_frame_info(caca_canvas_t *);

/* Internal timer functions */
extern void _caca_sleep(int);
extern int _caca_getticks(caca_timer_t *);

/* Internal event functions */
extern void _caca_handle_resize(caca_display_t *);
#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
extern void _push_event(caca_display_t *, caca_privevent_t *);
extern int _pop_event(caca_display_t *, caca_privevent_t *);
#endif

/* Internal window functions */
extern void _caca_set_term_title(char const *);

/* Profiling functions */
#if defined PROF
extern void _caca_dump_stats(void);
extern void _caca_init_stat(struct caca_stat *, char const *, ...);
extern void _caca_fini_stat(struct caca_stat *);
#endif

#endif /* __CACA_INTERNALS_H__ */


================================================
FILE: cgadraw/cacastub.h
================================================
/*
 *  libcaca       Colour ASCII-Art library
 *  Copyright (c) 2006-2012 Sam Hocevar <sam@hocevar.net>
 *                All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains replacements for commonly found object types and
 *  function prototypes that are sometimes missing.
 */

#ifndef __CACA_STUBS_H__
#define __CACA_STUBS_H__

/* errno handling */
#if defined HAVE_ERRNO_H && !defined __KERNEL__
#   include <errno.h>
static inline void seterrno(int e) { errno = e; }
static inline int geterrno(void) { return errno; }
#else
#   define seterrno(x) do { (void)(x); } while(0)
#   define geterrno(x) 0
#endif

/* hton16() and hton32() */
#if defined HAVE_HTONS && !defined __KERNEL__
#   if defined HAVE_ARPA_INET_H
#       include <arpa/inet.h>
#   elif defined HAVE_NETINET_IN_H
#       include <netinet/in.h>
#   endif
#   define hton16 htons
#   define hton32 htonl
#else
#   if defined __KERNEL__
        /* Nothing to do */
#   elif defined HAVE_ENDIAN_H
#       include <endian.h>
#   endif
static inline uint16_t hton16(uint16_t x)
{
    /* This is compile-time optimised with at least -O1 or -Os */
#if defined HAVE_ENDIAN_H
    if(__BYTE_ORDER == __BIG_ENDIAN)
#else
    uint32_t const dummy = 0x12345678;
    if(*(uint8_t const *)&dummy == 0x12)
#endif
        return x;
    else
        return (x >> 8) | (x << 8);
}

static inline uint32_t hton32(uint32_t x)
{
    /* This is compile-time optimised with at least -O1 or -Os */
#if defined HAVE_ENDIAN_H
    if(__BYTE_ORDER == __BIG_ENDIAN)
#else
    uint32_t const dummy = 0x12345678;
    if(*(uint8_t const *)&dummy == 0x12)
#endif
        return x;
    else
        return (x >> 24) | ((x >> 8) & 0x0000ff00)
                | ((x << 8) & 0x00ff0000) | (x << 24);
}
#endif

#endif /* __CACA_STUBS_H__ */



================================================
FILE: cgadraw/cacatyp.h
================================================
/*
 *  libcaca       Colour ASCII-Art library
 *  Copyright (c) 2008-2012 Sam Hocevar <sam@hocevar.net>
 *                All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains definitions for required C99 integer types.
 */

#ifndef __CACA_TYPES_H__
#define __CACA_TYPES_H__

typedef signed char _caca_int8_t;
typedef signed short _caca_int16_t;
typedef signed long int _caca_int32_t;
#   undef int8_t
#   define int8_t _caca_int8_t
#   undef int16_t
#   define int16_t _caca_int16_t
#   undef int32_t
#   define int32_t _caca_int32_t
typedef unsigned char _caca_uint8_t;
typedef unsigned short _caca_uint16_t;
typedef unsigned long int _caca_uint32_t;
#   undef uint8_t
#   define uint8_t _caca_uint8_t
#   undef uint16_t
#   define uint16_t _caca_uint16_t
#   undef uint32_t
#   define uint32_t _caca_uint32_t
typedef long int _caca_intptr_t;
typedef unsigned long int _caca_uintptr_t;
#   undef intptr_t
#   define intptr_t _caca_intptr_t
#   undef uintptr_t
#   define uintptr_t _caca_uintptr_t
typedef int _caca_ssize_t;
typedef unsigned int _caca_size_t;
#   undef ssize_t
#   define ssize_t _caca_ssize_t
#   undef size_t
#   define size_t _caca_size_t

#endif __CACA_TYPES_H__



================================================
FILE: cgadraw/canvas.c
================================================
//
// This file is derived from libcaca, but modified to add simple drawing
// primitives to a CGA framebuffer for Lotus 1-2-3.
//
// The original copyright notice is below.

/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

#include "config.h"
#include <stddef.h>
#include <dos.h>
#include <string.h>

#include "caca.h"
#include "cacaint.h"

caca_canvas_t * far caca_create_canvas(int width, int height, int sel, int off)
{
    static caca_canvas_t canvas;
    static struct caca_frame frame;
    caca_canvas_t * far cv;

    if (canvas.refcount != 0)
        return NULL;

    if (width < 0 || height < 0) {
        seterrno(EINVAL);
        return NULL;
    }

    cv = &canvas;
    cv->refcount++;
    cv->autoinc = 0;
    cv->resize_callback = NULL;
    cv->resize_data = NULL;

    cv->frame = 0;
    cv->framecount = 1;
    cv->frames = &frame;
    cv->frames[0].width = width;
    cv->frames[0].height = height;
    cv->frames[0].c = MK_FP(sel, off);
    cv->frames[0].x = cv->frames[0].y = 0;
    cv->frames[0].handlex = cv->frames[0].handley = 0;
    cv->frames[0].curattr = 0;
    cv->frames[0].name = "frame#00000000";

    _caca_load_frame_info(cv);
    caca_set_color_ansi(cv, CACA_DEFAULT, CACA_TRANSPARENT);

    cv->ndirty = 0;
    cv->dirty_disabled = 1;
    cv->ff = NULL;
    return cv;
}

int caca_manage_canvas(caca_canvas_t *cv, int (*callback)(void *), void *p)
{
    return -1;
}

int caca_unmanage_canvas(caca_canvas_t *cv, int (*callback)(void *), void *p)
{
    return -1;
}

int caca_set_canvas_size(caca_canvas_t *cv, int width, int height)
{
    return -1;
}

int caca_get_canvas_width(caca_canvas_t const *cv)
{
    return cv->width;
}

int caca_get_canvas_height(caca_canvas_t const *cv)
{
    return cv->height;
}

uint32_t const * caca_get_canvas_chars(caca_canvas_t const *cv)
{
    return NULL;
}

uint32_t const * caca_get_canvas_attrs(caca_canvas_t const *cv)
{
    return NULL;
}

int caca_free_canvas(caca_canvas_t *cv)
{
    cv->refcount--;
    return 0;
}

int caca_rand(int min, int max)
{
    return min;
}

int caca_resize(caca_canvas_t *cv, int width, int height)
{
    return -1;
}



================================================
FILE: cgadraw/cgadraw.c
================================================
#include "config.h"
#include "caca.h"
#include "cacaint.h"

char const * caca_get_version(void)
{
    return "cgadraw";
}


================================================
FILE: cgadraw/charset.c
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              2007 Ben Wiley Sittler <bsittler@gmail.com>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains functions for converting characters between
 *  various character sets.
 */

#include "config.h"

#if !defined(__KERNEL__)
#   include <string.h>
#endif

#include "caca.h"
#include "cacaint.h"

/*
 * UTF-8 handling
 */

static uint8_t const trailing[256] =
{
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};

static uint32_t const offsets[6] =
{
    0x00000000UL, 0x00003080UL, 0x000E2080UL,
    0x03C82080UL, 0xFA082080UL, 0x82082080UL
};

/*
 * CP437 handling
 */

static uint32_t const cp437_lookup1[] =
{
    /* 0x01 - 0x0f: ☺ ☻ ♥ ♦ ♣ ♠ • ◘ ○ ◙ ♂ ♀ ♪ ♫ ☼ */
            0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
    /* 0x10 - 0x1f: ► ◄ ↕ ‼ ¶ § ▬ ↨ ↑ ↓ → ← ∟ ↔ ▲ ▼ */
    0x25ba, 0x25c4, 0x2195, 0x203c, 0xb6, 0xa7, 0x25ac, 0x21a8,
    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc
};

static uint32_t const cp437_lookup2[] =
{
    /* 0x7f: ⌂ */
    0x2302,
    /* 0x80 - 0x8f: Ç ü é â ä à å ç ê ë è ï î ì Ä Å */
    0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7,
    0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5,
    /* 0x90 - 0x9f: É æ Æ ô ö ò û ù ÿ Ö Ü ¢ £ ¥ ₧ ƒ */
    0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9,
    0xff, 0xd6, 0xdc, 0xa2, 0xa3, 0xa5, 0x20a7, 0x192,
    /* 0xa0 - 0xaf: á í ó ú ñ Ñ ª º ¿ ⌐ ¬ ½ ¼ ¡ « » */
    0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba,
    0xbf, 0x2310, 0xac, 0xbd, 0xbc, 0xa1, 0xab, 0xbb,
    /* 0xb0 - 0xbf: ░ ▒ ▓ │ ┤ ╡ ╢ ╖ ╕ ╣ ║ ╗ ╝ ╜ ╛ ┐ */
    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
    /* 0xc0 - 0xcf: └ ┴ ┬ ├ ─ ┼ ╞ ╟ ╚ ╔ ╩ ╦ ╠ ═ ╬ ╧ */
    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
    /* 0xd0 - 0xdf: ╨ ╤ ╥ ╙ ╘ ╒ ╓ ╫ ╪ ┘ ┌ █ ▄ ▌ ▐ ▀ */
    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
    /* 0xe0 - 0xef: α ß Γ π Σ σ µ τ Φ Θ Ω δ ∞ φ ε ∩ */
    0x3b1, 0xdf, 0x393, 0x3c0, 0x3a3, 0x3c3, 0xb5, 0x3c4,
    0x3a6, 0x398, 0x3a9, 0x3b4, 0x221e, 0x3c6, 0x3b5, 0x2229,
    /* 0xf0 - 0xff: ≡ ± ≥ ≤ ⌠ ⌡ ÷ ≈ ° ∙ · √ ⁿ ² ■ <nbsp> */
    0x2261, 0xb1, 0x2265, 0x2264, 0x2320, 0x2321, 0xf7, 0x2248,
    0xb0, 0x2219, 0xb7, 0x221a, 0x207f, 0xb2, 0x25a0, 0xa0
};

/** \brief Convert a UTF-8 character to UTF-32.
 *
 *  Convert a UTF-8 character read from a string and return its value in
 *  the UTF-32 character set. If the second argument is not null, the total
 *  number of read bytes is written in it.
 *
 *  If a null byte was reached before the expected end of the UTF-8 sequence,
 *  this function returns zero and the number of read bytes is set to zero.
 *
 *  This function never fails, but its behaviour with illegal UTF-8 sequences
 *  is undefined.
 *
 *  \param s A string containing the UTF-8 character.
 *  \param bytes A pointer to a size_t to store the number of bytes in the
 *         character, or NULL.
 *  \return The corresponding UTF-32 character, or zero if the character
 *  is incomplete.
 */
uint32_t caca_utf8_to_utf32(char const *s, size_t *bytes)
{
    int todo = trailing[(int)(unsigned char)*s];
    int i = 0;
    uint32_t ret = 0;

    for(;;)
    {
        if(!*s)
        {
            if(bytes)
                *bytes = 0;
            return 0;
        }

        ret += ((uint32_t)(unsigned char)*s++) << (6 * (todo - i));

        if(todo == i++)
        {
            if(bytes)
                *bytes = i;
            return ret - offsets[todo];
        }
    }
}

/** \brief Convert a UTF-32 character to UTF-8.
 *
 *  Convert a UTF-32 character read from a string and write its value in
 *  the UTF-8 character set into the given buffer.
 *
 *  This function never fails, but its behaviour with illegal UTF-32 characters
 *  is undefined.
 *
 *  \param buf A pointer to a character buffer where the UTF-8 sequence will
 *  be written.
 *  \param ch The UTF-32 character.
 *  \return The number of bytes written.
 */
size_t caca_utf32_to_utf8(char *buf, uint32_t ch)
{
    static const uint8_t mark[7] =
    {
        0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
    };

    char *parser = buf;
    size_t bytes;

    if(ch < 0x80)
    {
        *parser++ = ch;
        return 1;
    }

    bytes = (ch < 0x800) ? 2 : (ch < 0x10000) ? 3 : 4;
    parser += bytes;

    switch(bytes)
    {
        case 4: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
        case 3: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
        case 2: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
    }
    *--parser = ch | mark[bytes];

    return bytes;
}

/** \brief Convert a UTF-32 character to CP437.
 *
 *  Convert a UTF-32 character read from a string and return its value in
 *  the CP437 character set, or "?" if the character has no equivalent.
 *
 *  This function never fails.
 *
 *  \param ch The UTF-32 character.
 *  \return The corresponding CP437 character, or "?" if not representable.
 */
uint8_t caca_utf32_to_cp437(uint32_t ch)
{
    unsigned int i;

    if(ch < 0x00000020)
        return '?';

    if(ch < 0x00000080)
        return ch;

    for(i = 0; i < sizeof(cp437_lookup1) / sizeof(*cp437_lookup1); i++)
        if(cp437_lookup1[i] == ch)
            return 0x01 + i;

    for(i = 0; i < sizeof(cp437_lookup2) / sizeof(*cp437_lookup2); i++)
        if(cp437_lookup2[i] == ch)
            return 0x7f + i;

    return '?';
}

/** \brief Convert a CP437 character to UTF-32.
 *
 *  Convert a CP437 character read from a string and return its value in
 *  the UTF-32 character set, or zero if the character is a CP437 control
 *  character.
 *
 *  This function never fails.
 *
 *  \param ch The CP437 character.
 *  \return The corresponding UTF-32 character, or zero if not representable.
 */
uint32_t caca_cp437_to_utf32(uint8_t ch)
{
    if(ch > 0x7f)
        return cp437_lookup2[ch - 0x7f];

    if(ch >= 0x20)
        return (uint32_t)ch;

    if(ch > 0)
        return cp437_lookup1[ch - 0x01];

    return 0x00000000;
}

/** \brief Convert a UTF-32 character to ASCII.
 *
 *  Convert a UTF-32 character into an ASCII character. When no equivalent
 *  exists, a graphically close equivalent is sought.
 *
 *  This function never fails, but its behaviour with illegal UTF-32 characters
 *  is undefined.
 *
 *  \param ch The UTF-32 character.
 *  \return The corresponding ASCII character, or a graphically close
 *  equivalent if found, or "?" if not representable.
 */
char caca_utf32_to_ascii(uint32_t ch)
{
    /* Standard ASCII */
    if(ch < 0x80)
        return ch;

    /* Fullwidth Forms */
    if(ch > 0x0000ff00 && ch < 0x0000ff5f)
        return ' ' + (ch - 0x0000ff00);

    switch (ch)
    {
    case 0x000000a0: /*   (nbsp) */
    case 0x00003000: /*   (ideographic space) */
        return ' ';
    case 0x000000a3: /* £ */
        return 'f';
    case 0x000000b0: /* ° */
        return '\'';
    case 0x000000b1: /* ± */
        return '#';
    case 0x000000b7: /* · */
    case 0x00002219: /* ∙ */
    case 0x000030fb: /* ・ */
        return '.';
    case 0x000003c0: /* π */
        return '*';
    case 0x00002018: /* ‘ */
    case 0x00002019: /* ’ */
        return '\'';
    case 0x0000201c: /* “ */
    case 0x0000201d: /* ” */
        return '"';
    case 0x00002190: /* ← */
        return '<';
    case 0x00002191: /* ↑ */
        return '^';
    case 0x00002192: /* → */
        return '>';
    case 0x00002193: /* ↓ */
        return 'v';
    case 0x00002260: /* ≠ */
        return '!';
    case 0x00002261: /* ≡ */
        return '=';
    case 0x00002264: /* ≤ */
        return '<';
    case 0x00002265: /* ≥ */
        return '>';
    case 0x000023ba: /* ⎺ */
    case 0x000023bb: /* ⎻ */
    case 0x000023bc: /* ⎼ */
    case 0x000023bd: /* ⎽ */
    case 0x00002500: /* ─ */
    case 0x00002550: /* ═ */
        return '-';
    case 0x00002502: /* │ */
    case 0x00002551: /* ║ */
        return '|';
    case 0x0000250c: /* ┌ */
    case 0x00002552: /* ╒ */
    case 0x00002553: /* ╓ */
    case 0x00002554: /* ╔ */
    case 0x00002514: /* └ */
    case 0x00002558: /* ╘ */
    case 0x00002559: /* ╙ */
    case 0x0000255a: /* ╚ */
    case 0x0000251c: /* ├ */
    case 0x0000255e: /* ╞ */
    case 0x0000255f: /* ╟ */
    case 0x00002560: /* ╠ */
    case 0x0000252c: /* ┬ */
    case 0x00002564: /* ╤ */
    case 0x00002565: /* ╥ */
    case 0x00002566: /* ╦ */
    case 0x00002534: /* ┴ */
    case 0x00002567: /* ╧ */
    case 0x00002568: /* ╨ */
    case 0x00002569: /* ╩ */
    case 0x0000253c: /* ┼ */
    case 0x0000256a: /* ╪ */
    case 0x0000256b: /* ╫ */
    case 0x0000256c: /* ╬ */
        return '+';
    case 0x00002510: /* ┐ */
    case 0x00002555: /* ╕ */
    case 0x00002556: /* ╖ */
    case 0x00002557: /* ╗ */
    case 0x00002518: /* ┘ */
    case 0x0000255b: /* ╛ */
    case 0x0000255c: /* ╜ */
    case 0x0000255d: /* ╝ */
    case 0x00002524: /* ┤ */
    case 0x00002561: /* ╡ */
    case 0x00002562: /* ╢ */
    case 0x00002563: /* ╣ */
        return '+';
    case 0x00002591: /* ░ */
    case 0x00002592: /* ▒ */
    case 0x00002593: /* ▓ */
    case 0x00002588: /* █ */
    case 0x0000258c: /* ▌ */
    case 0x00002590: /* ▐ */
    case 0x000025a0: /* ■ */
    case 0x000025ac: /* ▬ */
    case 0x000025ae: /* ▮ */
        return '#';
    case 0x00002580: /* ▀ */
        return '"';
    case 0x00002584: /* ▄ */
        return ',';
    case 0x000025c6: /* ◆ */
    case 0x00002666: /* ♦ */
        return '+';
    case 0x00002022: /* • */
    case 0x000025cb: /* ○ */
    case 0x000025cf: /* ● */
    case 0x00002603: /* ☃ */
    case 0x0000263c: /* ☼ */
        return 'o';
    case 0x0000301c: /* 〜 */
        return '~';
    }

    return '?';
}

/** \brief Tell whether a UTF-32 character is fullwidth.
 *
 *  Check whether the given UTF-32 character should be printed at twice
 *  the normal width (fullwidth characters). If the character is unknown
 *  or if its status cannot be decided, it is treated as a standard-width
 *  character.
 *
 *  This function never fails.
 *
 *  \param ch The UTF-32 character.
 *  \return 1 if the character is fullwidth, 0 otherwise.
 */
int caca_utf32_is_fullwidth(uint32_t ch)
{
    if(ch < 0x2e80) /* Standard stuff */
        return 0;
    if(ch < 0xa700) /* Japanese, Korean, CJK, Yi... */
        return 1;
    if(ch < 0xac00) /* Modified Tone Letters, Syloti Nagri */
        return 0;
    if(ch < 0xd800) /* Hangul Syllables */
        return 1;
    if(ch < 0xf900) /* Misc crap */
        return 0;
    if(ch < 0xfb00) /* More CJK */
        return 1;
    if(ch < 0xfe20) /* Misc crap */
        return 0;
    if(ch < 0xfe70) /* More CJK */
        return 1;
    if(ch < 0xff00) /* Misc crap */
        return 0;
    if(ch < 0xff61) /* Fullwidth forms */
        return 1;
    if(ch < 0xffe0) /* Halfwidth forms */
        return 0;
    if(ch < 0xffe8) /* More fullwidth forms */
        return 1;
    if(ch < 0x20000) /* Misc crap */
        return 0;
    if(ch < 0xe0000) /* More CJK */
        return 1;
    return 0;
}



================================================
FILE: cgadraw/codec.h
================================================
/*
 *  libcaca       Colour ASCII-Art library
 *  Copyright (c) 2002-2014 Sam Hocevar <sam@hocevar.net>
 *                2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
 *                All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

ssize_t _import_text(caca_canvas_t *, void const *, size_t);
ssize_t _import_ansi(caca_canvas_t *, void const *, size_t, int);
ssize_t _import_bin(caca_canvas_t *, void const *, size_t);

void *_export_ansi(caca_canvas_t const *, size_t *);
void *_export_plain(caca_canvas_t const *, size_t *);
void *_export_utf8(caca_canvas_t const *, size_t *, int);
void *_export_irc(caca_canvas_t const *, size_t *);



================================================
FILE: cgadraw/config.h
================================================
#define inline
#define EOVERFLOW E2BIG
#define ENOSYS EINVAL
#define HAVE_VSNPRINTF 1

#define __KERNEL__

#include <stddef.h>

#define abs(x) (((x) < 0) ? (x) * -1 : (x))

#define snprintf  portable_snprintf
#define vsnprintf portable_vsnprintf


================================================
FILE: cgadraw/conic.c
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains ellipse and circle drawing functions, both filled
 *  and outline.
 */

#include "config.h"

#if !defined(__KERNEL__)
#   include <stdlib.h>
#endif

#include "caca.h"
#include "cacaint.h"

static void ellipsepoints(caca_canvas_t *, int, int, int, int, uint32_t, int);

/** \brief Draw a circle on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x Center X coordinate.
 *  \param y Center Y coordinate.
 *  \param r Circle radius.
 *  \param ch UTF-32 character to be used to draw the circle outline.
 *  \return This function always returns 0.
 */
int caca_draw_circle(caca_canvas_t *cv, int x, int y, int r, uint32_t ch)
{
    int test, dx, dy;

    /* Optimized Bresenham. Kick ass. */
    for(test = 0, dx = 0, dy = r ; dx <= dy ; dx++)
    {
        ellipsepoints(cv, x, y, dx, dy, ch, 1);
        ellipsepoints(cv, x, y, dy, dx, ch, 1);

        test += test > 0 ? dx - dy-- : dx;
    }

    return 0;
}

/** \brief Fill an ellipse on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param xo Center X coordinate.
 *  \param yo Center Y coordinate.
 *  \param a Ellipse X radius.
 *  \param b Ellipse Y radius.
 *  \param ch UTF-32 character to be used to fill the ellipse.
 *  \return This function always returns 0.
 */
int caca_fill_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b,
                       uint32_t ch)
{
    int d2;
    int x = 0;
    int y = b;
    int d1 = b*b - (a*a*b) + (a*a/4);

    while(a*a*y - a*a/2 > b*b*(x+1))
    {
        if(d1 < 0)
        {
            d1 += b*b*(2*x+1); /* XXX: "Computer Graphics" has + 3 here. */
        }
        else
        {
            d1 += b*b*(2*x*1) + a*a*(-2*y+2);
            caca_draw_line(cv, xo - x, yo - y, xo + x, yo - y, ch);
            caca_draw_line(cv, xo - x, yo + y, xo + x, yo + y, ch);
            y--;
        }
        x++;
    }

    caca_draw_line(cv, xo - x, yo - y, xo + x, yo - y, ch);
    caca_draw_line(cv, xo - x, yo + y, xo + x, yo + y, ch);

    d2 = b*b*(x+0.5)*(x+0.5) + a*a*(y-1)*(y-1) - a*a*b*b;
    while(y > 0)
    {
        if(d2 < 0)
        {
            d2 += b*b*(2*x+2) + a*a*(-2*y+3);
            x++;
        }
        else
        {
            d2 += a*a*(-2*y+3);
        }

        y--;
        caca_draw_line(cv, xo - x, yo - y, xo + x, yo - y, ch);
        caca_draw_line(cv, xo - x, yo + y, xo + x, yo + y, ch);
    }

    return 0;
}

/** \brief Draw an ellipse on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param xo Center X coordinate.
 *  \param yo Center Y coordinate.
 *  \param a Ellipse X radius.
 *  \param b Ellipse Y radius.
 *  \param ch UTF-32 character to be used to draw the ellipse outline.
 *  \return This function always returns 0.
 */
int caca_draw_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b,
                       uint32_t ch)
{
    int d2;
    int x = 0;
    int y = b;
    int d1 = b*b - (a*a*b) + (a*a/4);

    ellipsepoints(cv, xo, yo, x, y, ch, 0);

    while(a*a*y - a*a/2 > b*b*(x+1))
    {
        if(d1 < 0)
        {
            d1 += b*b*(2*x+1); /* XXX: "Computer Graphics" has + 3 here. */
        }
        else
        {
            d1 += b*b*(2*x*1) + a*a*(-2*y+2);
            y--;
        }
        x++;
        ellipsepoints(cv, xo, yo, x, y, ch, 0);
    }

    d2 = b*b*(x+0.5)*(x+0.5) + a*a*(y-1)*(y-1) - a*a*b*b;
    while(y > 0)
    {
        if(d2 < 0)
        {
            d2 += b*b*(2*x+2) + a*a*(-2*y+3);
            x++;
        }
        else
        {
            d2 += a*a*(-2*y+3);
        }

        y--;
        ellipsepoints(cv, xo, yo, x, y, ch, 0);
    }

    return 0;
}

/** \brief Draw a thin ellipse on the canvas.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param xo Center X coordinate.
 *  \param yo Center Y coordinate.
 *  \param a Ellipse X radius.
 *  \param b Ellipse Y radius.
 *  \return This function always returns 0.
 */
int caca_draw_thin_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b)
{
    /* FIXME: this is not correct */
    int d2;
    int x = 0;
    int y = b;
    int d1 = b*b - (a*a*b) + (a*a/4);

    ellipsepoints(cv, xo, yo, x, y, '-', 1);

    while(a*a*y - a*a/2 > b*b*(x+1))
    {
        if(d1 < 0)
        {
            d1 += b*b*(2*x+1); /* XXX: "Computer Graphics" has + 3 here. */
            ellipsepoints(cv, xo, yo, x + 1, y, '0', 1);
        }
        else
        {
            d1 += b*b*(2*x*1) + a*a*(-2*y+2);
            y--;
            ellipsepoints(cv, xo, yo, x + 1, y, '1', 1);
        }
        x++;


    }

    d2 = b*b*(x+0.5)*(x+0.5) + a*a*(y-1)*(y-1) - a*a*b*b;
    while(y > 0)
    {
        if(d2 < 0)
        {
            d2 += b*b*(2*x+2) + a*a*(-2*y+3);
            x++;
            ellipsepoints(cv, xo, yo, x , y - 1, '2', 1);
        }
        else
        {
            d2 += a*a*(-2*y+3);
            ellipsepoints(cv, xo, yo, x , y - 1, '3', 1);
        }

        y--;


    }

    return 0;
}

static void ellipsepoints(caca_canvas_t *cv, int xo, int yo, int x, int y,
                          uint32_t ch, int thin)
{
    uint8_t b = 0;

    if(xo + x >= 0 && xo + x < (int)cv->width)
        b |= 0x1;
    if(xo - x >= 0 && xo - x < (int)cv->width)
        b |= 0x2;
    if(yo + y >= 0 && yo + y < (int)cv->height)
        b |= 0x4;
    if(yo - y >= 0 && yo - y < (int)cv->height)
        b |= 0x8;

    if((b & (0x1|0x4)) == (0x1|0x4)) {
        uint32_t c = ch;

        if(thin) {
            switch(c) {
            case '0':
                c = '-';
                break;
            case '1':
                c = ',';
                break;
            case '2':
                c = '/';
                break;
            case '3':
                c = '|';
                break;
            }

        }
        caca_put_char(cv, xo + x, yo + y, c);
    }
    if((b & (0x2|0x4)) == (0x2|0x4)) {
        uint32_t c = ch;

        if(thin) {
            switch(c) {
            case '0':
                c = '-';
                break;
            case '1':
                c = '.';
                break;
            case '2':
                c = '\\';
                break;
            case '3':
                c = '|';
                break;
            }

        }
        caca_put_char(cv, xo - x, yo + y, c);
    }


    if((b & (0x1|0x8)) == (0x1|0x8)) {
        uint32_t c = ch;

        if(thin) {
            switch(c) {
            case '0':
                c = '-';
                break;
            case '1':
                c = '`';
                break;
            case '2':
                c = '\\';
                break;
            case '3':
                c = '|';
                break;
            }

        }
        caca_put_char(cv, xo + x, yo - y, c);
    }

    if((b & (0x2|0x8)) == (0x2|0x8)) {
        uint32_t c = ch;

        if(thin) {
            switch(c) {
            case '0':
                c = '-';
                break;
            case '1':
                c = '\'';
                break;
            case '2':
                c = '/';
                break;
            case '3':
                c = '|';
                break;
            }

        }
        caca_put_char(cv, xo - x, yo - y, c);
    }
}



================================================
FILE: cgadraw/drawtest.c
================================================
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <conio.h>
#include "config.h"

#include "caca.h"

int __cdecl main(int argc, char *argv[])
{
    caca_canvas_t *cv;

    cv = caca_create_canvas(100, 30, 0xB800, 0);
    caca_draw_thin_line(cv, 10, 10, 80, 25);
    caca_draw_cp437_box(cv, 20, 5, 20, 10);
    caca_fill_ellipse(cv, 80, 8, 5, 5, '#');
    return 0;
}


================================================
FILE: cgadraw/frame.c
================================================
#include "config.h"
#include "caca.h"
#include "cacaint.h"

int caca_get_frame_count(caca_canvas_t const *cv)
{
    return cv->framecount;
}

int caca_set_frame(caca_canvas_t *cv, int id)
{
    if(id < 0 || id >= cv->framecount)
    {
        seterrno(EINVAL);
        return -1;
    }

    if(id != cv->frame)
        return -1;

    return 0;
}

char const *caca_get_frame_name(caca_canvas_t const *cv)
{
    return cv->frames[cv->frame].name;
}

int caca_set_frame_name(caca_canvas_t *cv, char const *name)
{
    return -1;
}

int caca_create_frame(caca_canvas_t *cv, int id)
{
    return -1;
}

int caca_free_frame(caca_canvas_t *cv, int id)
{
    int f;

    if(id < 0 || id >= cv->framecount)
    {
        seterrno(EINVAL);
        return -1;
    }

    if(cv->framecount == 1)
    {
        seterrno(EINVAL);
        return -1;
    }

    return 0;
}

void _caca_save_frame_info(caca_canvas_t *cv)
{
    cv->frames[cv->frame].width = cv->width;
    cv->frames[cv->frame].height = cv->height;
    cv->frames[cv->frame].curattr = cv->curattr;
}

void _caca_load_frame_info(caca_canvas_t *cv)
{
    cv->width = cv->frames[cv->frame].width;
    cv->height = cv->frames[cv->frame].height;
    cv->c = cv->frames[cv->frame].c;
    cv->curattr = cv->frames[cv->frame].curattr;
}



================================================
FILE: cgadraw/line.c
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains line and polyline drawing functions, with both thin
 *  and thick styles.
 */

#include "config.h"
#include <conio.h>

#if !defined(__KERNEL__)
#   include <stdlib.h>
#endif

#include "caca.h"
#include "cacaint.h"

#if !defined(_DOXYGEN_SKIP_ME)
struct line
{
    int x1, y1;
    int x2, y2;
    uint32_t ch;
    void (far *draw) (caca_canvas_t *, struct line*);
};
#endif

static void clip_line(caca_canvas_t*, struct line*);
static uint8_t clip_bits(caca_canvas_t*, int, int);
static void draw_solid_line(caca_canvas_t*, struct line*);
static void draw_thin_line(caca_canvas_t*, struct line*);

/** \brief Draw a line on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x1 X coordinate of the first point.
 *  \param y1 Y coordinate of the first point.
 *  \param x2 X coordinate of the second point.
 *  \param y2 Y coordinate of the second point.
 *  \param ch UTF-32 character to be used to draw the line.
 *  \return This function always returns 0.
 */
int caca_draw_line(caca_canvas_t *cv, int x1, int y1, int x2, int y2,
                    uint32_t ch)
{
    struct line s;
    s.x1 = x1;
    s.y1 = y1;
    s.x2 = x2;
    s.y2 = y2;
    s.ch = ch;
    s.draw = draw_solid_line;
    clip_line(cv, &s);

    return 0;
}

/** \brief Draw a polyline.
 *
 *  Draw a polyline on the canvas using the given character and coordinate
 *  arrays. The first and last points are not connected, hence in order to
 *  draw a polygon you need to specify the starting point at the end of the
 *  list as well.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x Array of X coordinates. Must have \p n + 1 elements.
 *  \param y Array of Y coordinates. Must have \p n + 1 elements.
 *  \param n Number of lines to draw.
 *  \param ch UTF-32 character to be used to draw the lines.
 *  \return This function always returns 0.
 */
int caca_draw_polyline(caca_canvas_t *cv, int const x[], int const y[],
                        int n, uint32_t ch)
{
    int i;
    struct line s;
    s.ch = ch;
    s.draw = draw_solid_line;

    for(i = 0; i < n; i++)
    {
        s.x1 = x[i];
        s.y1 = y[i];
        s.x2 = x[i+1];
        s.y2 = y[i+1];
        clip_line(cv, &s);
    }

    return 0;
}

/** \brief Draw a thin line on the canvas, using ASCII art.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x1 X coordinate of the first point.
 *  \param y1 Y coordinate of the first point.
 *  \param x2 X coordinate of the second point.
 *  \param y2 Y coordinate of the second point.
 *  \return This function always returns 0.
 */
int caca_draw_thin_line(caca_canvas_t *cv, int x1, int y1, int x2, int y2)
{
    struct line s;
    s.x1 = x1;
    s.y1 = y1;
    s.x2 = x2;
    s.y2 = y2;
    s.draw = draw_thin_line;
    clip_line(cv, &s);

    return 0;
}

/** \brief Draw an ASCII art thin polyline.
 *
 *  Draw a thin polyline on the canvas using the given coordinate arrays and
 *  with ASCII art. The first and last points are not connected, so in order
 *  to draw a polygon you need to specify the starting point at the end of
 *  the list as well.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x Array of X coordinates. Must have \p n + 1 elements.
 *  \param y Array of Y coordinates. Must have \p n + 1 elements.
 *  \param n Number of lines to draw.
 *  \return This function always returns 0.
 */
int caca_draw_thin_polyline(caca_canvas_t *cv, int const x[], int const y[],
                             int n)
{
    int i;
    struct line s;
    s.draw = draw_thin_line;

    for(i = 0; i < n; i++)
    {
        s.x1 = x[i];
        s.y1 = y[i];
        s.x2 = x[i+1];
        s.y2 = y[i+1];
        clip_line(cv, &s);
    }

    return 0;
}

/*
 * XXX: The following functions are local.
 */

/* Generic Cohen-Sutherland line clipping function. */
static void clip_line(caca_canvas_t *cv, struct line* s)
{
    uint8_t bits1, bits2;

    bits1 = clip_bits(cv, s->x1, s->y1);
    bits2 = clip_bits(cv, s->x2, s->y2);

    if(bits1 & bits2)
        return;

    if(bits1 == 0)
    {
        if(bits2 == 0)
            s->draw(cv, s);
        else
        {
            int tmp;
            tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
            tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
            clip_line(cv, s);
        }

        return;
    }

    if(bits1 & (1<<0))
    {
        s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
        s->x1 = 0;
    }
    else if(bits1 & (1<<1))
    {
        int xmax = cv->width - 1;
        s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
        s->x1 = xmax;
    }
    else if(bits1 & (1<<2))
    {
        s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
        s->y1 = 0;
    }
    else if(bits1 & (1<<3))
    {
        int ymax = cv->height - 1;
        s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
        s->y1 = ymax;
    }

    clip_line(cv, s);
}

/* Helper function for clip_line(). */
static uint8_t clip_bits(caca_canvas_t *cv, int x, int y)
{
    uint8_t b = 0;

    if(x < 0)
        b |= (1<<0);
    else if(x >= (int)cv->width)
        b |= (1<<1);

    if(y < 0)
        b |= (1<<2);
    else if(y >= (int)cv->height)
        b |= (1<<3);

    return b;
}

/* Solid line drawing function, using Bresenham's mid-point line
 * scan-conversion algorithm. */
static void draw_solid_line(caca_canvas_t *cv, struct line* s)
{
    int x1, y1, x2, y2;
    int dx, dy;
    int xinc, yinc;

    x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;

    dx = abs(x2 - x1);
    dy = abs(y2 - y1);

    xinc = (x1 > x2) ? -1 : 1;
    yinc = (y1 > y2) ? -1 : 1;

    if(dx >= dy)
    {
        int dpr = dy << 1;
        int dpru = dpr - (dx << 1);
        int delta = dpr - dx;

        for(; dx>=0; dx--)
        {
            caca_put_char(cv, x1, y1, s->ch);
            if(delta > 0)
            {
                x1 += xinc;
                y1 += yinc;
                delta += dpru;
            }
            else
            {
                x1 += xinc;
                delta += dpr;
            }
        }
    }
    else
    {
        int dpr = dx << 1;
        int dpru = dpr - (dy << 1);
        int delta = dpr - dy;

        for(; dy >= 0; dy--)
        {
            caca_put_char(cv, x1, y1, s->ch);
            if(delta > 0)
            {
                x1 += xinc;
                y1 += yinc;
                delta += dpru;
            }
            else
            {
                y1 += yinc;
                delta += dpr;
            }
        }
    }
}

/* Thin line drawing function, using Bresenham's mid-point line
 * scan-conversion algorithm and ASCII art graphics. */
static void draw_thin_line(caca_canvas_t *cv, struct line* s)
{
    uint32_t charmapx[2], charmapy[2];
    int x1, y1, x2, y2;
    int dx, dy;
    int yinc;

    if(s->x2 >= s->x1)
    {
        charmapx[0] = (s->y1 > s->y2) ? ',' : '`';
        charmapx[1] = (s->y1 > s->y2) ? '\'' : '.';
        x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
    }
    else
    {
        charmapx[0] = (s->y1 > s->y2) ? '`' : '.';
        charmapx[1] = (s->y1 > s->y2) ? ',' : '\'';
        x2 = s->x1; y2 = s->y1; x1 = s->x2; y1 = s->y2;
    }

    dx = abs(x2 - x1);
    dy = abs(y2 - y1);

    if(y1 > y2)
    {
        charmapy[0] = ',';
        charmapy[1] = '\'';
        yinc = -1;
    }
    else
    {
        yinc = 1;
        charmapy[0] = '`';
        charmapy[1] = '.';
    }

    if(dx >= dy)
    {
        int dpr = dy << 1;
        int dpru = dpr - (dx << 1);
        int delta = dpr - dx;
        int prev = 0;

        for(; dx>=0; dx--)
        {
            if(delta > 0)
            {
                caca_put_char(cv, x1, y1, charmapy[1]);
                x1++;
                y1 += yinc;
                delta += dpru;
                prev = 1;
            }
            else
            {
                if(prev)
                    caca_put_char(cv, x1, y1, charmapy[0]);
                else
                    caca_put_char(cv, x1, y1, '-');
                x1++;
                delta += dpr;
                prev = 0;
            }
        }
    }
    else
    {
        int dpr = dx << 1;
        int dpru = dpr - (dy << 1);
        int delta = dpr - dy;

        for(; dy >= 0; dy--)
        {
            if(delta > 0)
            {
                caca_put_char(cv, x1, y1, charmapx[0]);
                caca_put_char(cv, x1 + 1, y1, charmapx[1]);
                x1++;
                y1 += yinc;
                delta += dpru;
            }
            else
            {
                caca_put_char(cv, x1, y1, '|');
                y1 += yinc;
                delta += dpr;
            }
        }
    }
}



================================================
FILE: cgadraw/snprintf.c
================================================
/*
 * snprintf.c - a portable implementation of snprintf
 *
 * AUTHOR
 *   Mark Martinec <mark.martinec@ijs.si>, April 1999.
 *
 *   Copyright 1999, Mark Martinec. All rights reserved.
 *
 * TERMS AND CONDITIONS
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the "Frontier Artistic License" which comes
 *   with this Kit.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty
 *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *   See the Frontier Artistic License for more details.
 *
 *   You should have received a copy of the Frontier Artistic License
 *   with this Kit in the file named LICENSE.txt .
 *   If not, I'll be glad to provide one.
 *
 * FEATURES
 * - careful adherence to specs regarding flags, field width and precision;
 * - good performance for large string handling (large format, large
 *   argument or large paddings). Performance is similar to system's sprintf
 *   and in several cases significantly better (make sure you compile with
 *   optimizations turned on, tell the compiler the code is strict ANSI
 *   if necessary to give it more freedom for optimizations);
 * - return value semantics per ISO/IEC 9899:1999 ("ISO C99");
 * - written in standard ISO/ANSI C - requires an ANSI C compiler.
 *
 * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES
 *
 * This snprintf only supports the following conversion specifiers:
 * s, c, d, u, o, x, X, p  (and synonyms: i, D, U, O - see below)
 * with flags: '-', '+', ' ', '0' and '#'.
 * An asterisk is supported for field width as well as precision.
 *
 * Length modifiers 'h' (short int), 'l' (long int),
 * and 'll' (long long int) are supported.
 * NOTE:
 *   If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the
 *   length modifier 'll' is recognized but treated the same as 'l',
 *   which may cause argument value truncation! Defining
 *   SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also
 *   handles length modifier 'll'.  long long int is a language extension
 *   which may not be portable.
 *
 * Conversion of numeric data (conversion specifiers d, u, o, x, X, p)
 * with length modifiers (none or h, l, ll) is left to the system routine
 * sprintf, but all handling of flags, field width and precision as well as
 * c and s conversions is done very carefully by this portable routine.
 * If a string precision (truncation) is specified (e.g. %.8s) it is
 * guaranteed the string beyond the specified precision will not be referenced.
 *
 * Length modifiers h, l and ll are ignored for c and s conversions (data
 * types wint_t and wchar_t are not supported).
 *
 * The following common synonyms for conversion characters are supported:
 *   - i is a synonym for d
 *   - D is a synonym for ld, explicit length modifiers are ignored
 *   - U is a synonym for lu, explicit length modifiers are ignored
 *   - O is a synonym for lo, explicit length modifiers are ignored
 * The D, O and U conversion characters are nonstandard, they are supported
 * for backward compatibility only, and should not be used for new code.
 *
 * The following is specifically NOT supported:
 *   - flag ' (thousands' grouping character) is recognized but ignored
 *   - numeric conversion specifiers: f, e, E, g, G and synonym F,
 *     as well as the new a and A conversion specifiers
 *   - length modifier 'L' (long double) and 'q' (quad - use 'll' instead)
 *   - wide character/string conversions: lc, ls, and nonstandard
 *     synonyms C and S
 *   - writeback of converted string length: conversion character n
 *   - the n$ specification for direct reference to n-th argument
 *   - locales
 *
 * It is permitted for str_m to be zero, and it is permitted to specify NULL
 * pointer for resulting string argument if str_m is zero (as per ISO C99).
 *
 * The return value is the number of characters which would be generated
 * for the given input, excluding the trailing null. If this value
 * is greater or equal to str_m, not all characters from the result
 * have been stored in str, output bytes beyond the (str_m-1) -th character
 * are discarded. If str_m is greater than zero it is guaranteed
 * the resulting string will be null-terminated.
 *
 * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
 * but is different from some older and vendor implementations,
 * and is also different from XPG, XSH5, SUSv2 specifications.
 * For historical discussion on changes in the semantics and standards
 * of snprintf see printf(3) man page in the Linux programmers manual.
 *
 * Routines asprintf and vasprintf return a pointer (in the ptr argument)
 * to a buffer sufficiently large to hold the resulting string. This pointer
 * should be passed to free(3) to release the allocated storage when it is
 * no longer needed. If sufficient space cannot be allocated, these functions
 * will return -1 and set ptr to be a NULL pointer. These two routines are a
 * GNU C library extensions (glibc).
 *
 * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
 * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
 * characters into the allocated output string, the last character in the
 * allocated buffer then gets the terminating null. If the formatted string
 * length (the return value) is greater than or equal to the str_m argument,
 * the resulting string was truncated and some of the formatted characters
 * were discarded. These routines present a handy way to limit the amount
 * of allocated memory to some sane value.
 *
 * AVAILABILITY
 *   http://www.ijs.si/software/snprintf/
 *
 * REVISION HISTORY
 * 1999-04	V0.9  Mark Martinec
 *		- initial version, some modifications after comparing printf
 *		  man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10,
 *		  and checking how Perl handles sprintf (differently!);
 * 1999-04-09	V1.0  Mark Martinec <mark.martinec@ijs.si>
 *		- added main test program, fixed remaining inconsistencies,
 *		  added optional (long long int) support;
 * 1999-04-12	V1.1  Mark Martinec <mark.martinec@ijs.si>
 *		- support the 'p' conversion (pointer to void);
 *		- if a string precision is specified
 *		  make sure the string beyond the specified precision
 *		  will not be referenced (e.g. by strlen);
 * 1999-04-13	V1.2  Mark Martinec <mark.martinec@ijs.si>
 *		- support synonyms %D=%ld, %U=%lu, %O=%lo;
 *		- speed up the case of long format string with few conversions;
 * 1999-06-30	V1.3  Mark Martinec <mark.martinec@ijs.si>
 *		- fixed runaway loop (eventually crashing when str_l wraps
 *		  beyond 2^31) while copying format string without
 *		  conversion specifiers to a buffer that is too short
 *		  (thanks to Edwin Young <edwiny@autonomy.com> for
 *		  spotting the problem);
 *		- added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR)
 *		  to snprintf.h
 * 2000-02-14	V2.0 (never released) Mark Martinec <mark.martinec@ijs.si>
 *		- relaxed license terms: The Artistic License now applies.
 *		  You may still apply the GNU GENERAL PUBLIC LICENSE
 *		  as was distributed with previous versions, if you prefer;
 *		- changed REVISION HISTORY dates to use ISO 8601 date format;
 *		- added vsnprintf (patch also independently proposed by
 *		  Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01)
 * 2000-06-27	V2.1  Mark Martinec <mark.martinec@ijs.si>
 *		- removed POSIX check for str_m<1; value 0 for str_m is
 *		  allowed by ISO C99 (and GNU C library 2.1) - (pointed out
 *		  on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie).
 *		  Besides relaxed license this change in standards adherence
 *		  is the main reason to bump up the major version number;
 *		- added nonstandard routines asnprintf, vasnprintf, asprintf,
 *		  vasprintf that dynamically allocate storage for the
 *		  resulting string; these routines are not compiled by default,
 *		  see comments where NEED_V?ASN?PRINTF macros are defined;
 *		- autoconf contributed by Caolan McNamara
 * 2000-10-06	V2.2  Mark Martinec <mark.martinec@ijs.si>
 *		- BUG FIX: the %c conversion used a temporary variable
 *		  that was no longer in scope when referenced,
 *		  possibly causing incorrect resulting character;
 *		- BUG FIX: make precision and minimal field width unsigned
 *		  to handle huge values (2^31 <= n < 2^32) correctly;
 *		  also be more careful in the use of signed/unsigned/size_t
 *		  internal variables - probably more careful than many
 *		  vendor implementations, but there may still be a case
 *		  where huge values of str_m, precision or minimal field
 *		  could cause incorrect behaviour;
 *		- use separate variables for signed/unsigned arguments,
 *		  and for short/int, long, and long long argument lengths
 *		  to avoid possible incompatibilities on certain
 *		  computer architectures. Also use separate variable
 *		  arg_sign to hold sign of a numeric argument,
 *		  to make code more transparent;
 *		- some fiddling with zero padding and "0x" to make it
 *		  Linux compatible;
 *		- systematically use macros fast_memcpy and fast_memset
 *		  instead of case-by-case hand optimization; determine some
 *		  breakeven string lengths for different architectures;
 *		- terminology change: 'format' -> 'conversion specifier',
 *		  'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")',
 *		  'alternative form' -> 'alternate form',
 *		  'data type modifier' -> 'length modifier';
 *		- several comments rephrased and new ones added;
 *		- make compiler not complain about 'credits' defined but
 *		  not used;
 */


/* Define HAVE_SNPRINTF if your system already has snprintf and vsnprintf.
 *
 * If HAVE_SNPRINTF is defined this module will not produce code for
 * snprintf and vsnprintf, unless PREFER_PORTABLE_SNPRINTF is defined as well,
 * causing this portable version of snprintf to be called portable_snprintf
 * (and portable_vsnprintf).
 */
#define HAVE_SNPRINTF

/* Define PREFER_PORTABLE_SNPRINTF if your system does have snprintf and
 * vsnprintf but you would prefer to use the portable routine(s) instead.
 * In this case the portable routine is declared as portable_snprintf
 * (and portable_vsnprintf) and a macro 'snprintf' (and 'vsnprintf')
 * is defined to expand to 'portable_v?snprintf' - see file snprintf.h .
 * Defining this macro is only useful if HAVE_SNPRINTF is also defined,
 * but does does no harm if defined nevertheless.
 */
#define PREFER_PORTABLE_SNPRINTF

/* Define SNPRINTF_LONGLONG_SUPPORT if you want to support
 * data type (long long int) and length modifier 'll' (e.g. %lld).
 * If undefined, 'll' is recognized but treated as a single 'l'.
 *
 * If the system's sprintf does not handle 'll'
 * the SNPRINTF_LONGLONG_SUPPORT must not be defined!
 *
 * This is off by default as (long long int) is a language extension.
 */
/* #define SNPRINTF_LONGLONG_SUPPORT */

/* Define NEED_SNPRINTF_ONLY if you only need snprintf, and not vsnprintf.
 * If NEED_SNPRINTF_ONLY is defined, the snprintf will be defined directly,
 * otherwise both snprintf and vsnprintf routines will be defined
 * and snprintf will be a simple wrapper around vsnprintf, at the expense
 * of an extra procedure call.
 */
/* #define NEED_SNPRINTF_ONLY */

/* Define NEED_V?ASN?PRINTF macros if you need library extension
 * routines asprintf, vasprintf, asnprintf, vasnprintf respectively,
 * and your system library does not provide them. They are all small
 * wrapper routines around portable_vsnprintf. Defining any of the four
 * NEED_V?ASN?PRINTF macros automatically turns off NEED_SNPRINTF_ONLY
 * and turns on PREFER_PORTABLE_SNPRINTF.
 *
 * Watch for name conflicts with the system library if these routines
 * are already present there.
 *
 * NOTE: vasprintf and vasnprintf routines need va_copy() from stdarg.h, as
 * specified by C99, to be able to traverse the same list of arguments twice.
 * I don't know of any other standard and portable way of achieving the same.
 * With some versions of gcc you may use __va_copy(). You might even get away
 * with "ap2 = ap", in this case you must not call va_end(ap2) !
 *   #define va_copy(ap2,ap) ap2 = ap
 */
/* #define NEED_ASPRINTF   */
/* #define NEED_ASNPRINTF  */
/* #define NEED_VASPRINTF  */
/* #define NEED_VASNPRINTF */


/* Define the following macros if desired:
 *   SOLARIS_COMPATIBLE, SOLARIS_BUG_COMPATIBLE,
 *   HPUX_COMPATIBLE, HPUX_BUG_COMPATIBLE, LINUX_COMPATIBLE,
 *   DIGITAL_UNIX_COMPATIBLE, DIGITAL_UNIX_BUG_COMPATIBLE,
 *   PERL_COMPATIBLE, PERL_BUG_COMPATIBLE,
 *
 * - For portable applications it is best not to rely on peculiarities
 *   of a given implementation so it may be best not to define any
 *   of the macros that select compatibility and to avoid features
 *   that vary among the systems.
 *
 * - Selecting compatibility with more than one operating system
 *   is not strictly forbidden but is not recommended.
 *
 * - 'x'_BUG_COMPATIBLE implies 'x'_COMPATIBLE .
 *
 * - 'x'_COMPATIBLE refers to (and enables) a behaviour that is
 *   documented in a sprintf man page on a given operating system
 *   and actually adhered to by the system's sprintf (but not on
 *   most other operating systems). It may also refer to and enable
 *   a behaviour that is declared 'undefined' or 'implementation specific'
 *   in the man page but a given implementation behaves predictably
 *   in a certain way.
 *
 * - 'x'_BUG_COMPATIBLE refers to (and enables) a behaviour of system's sprintf
 *   that contradicts the sprintf man page on the same operating system.
 *
 * - I do not claim that the 'x'_COMPATIBLE and 'x'_BUG_COMPATIBLE
 *   conditionals take into account all idiosyncrasies of a particular
 *   implementation, there may be other incompatibilities.
 */



/* ============================================= */
/* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */
/* ============================================= */

#define PORTABLE_SNPRINTF_VERSION_MAJOR 2
#define PORTABLE_SNPRINTF_VERSION_MINOR 2

#if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF)
# if defined(NEED_SNPRINTF_ONLY)
# undef NEED_SNPRINTF_ONLY
# endif
# if !defined(PREFER_PORTABLE_SNPRINTF)
# define PREFER_PORTABLE_SNPRINTF
# endif
#endif

#if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE)
#define SOLARIS_COMPATIBLE
#endif

#if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
#define HPUX_COMPATIBLE
#endif

#if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE)
#define DIGITAL_UNIX_COMPATIBLE
#endif

#if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE)
#define PERL_COMPATIBLE
#endif

#if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE)
#define LINUX_COMPATIBLE
#endif

#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <errno.h>

#ifdef isdigit
#undef isdigit
#endif
#define isdigit(c) ((c) >= '0' && (c) <= '9')

/* For copying strings longer or equal to 'breakeven_point'
 * it is more efficient to call memcpy() than to do it inline.
 * The value depends mostly on the processor architecture,
 * but also on the compiler and its optimization capabilities.
 * The value is not critical, some small value greater than zero
 * will be just fine if you don't care to squeeze every drop
 * of performance out of the code.
 *
 * Small values favor memcpy, large values favor inline code.
 */
#if defined(__alpha__) || defined(__alpha)
#  define breakeven_point   2	/* AXP (DEC Alpha)     - gcc or cc or egcs */
#endif
#if defined(__i386__)  || defined(__i386)
#  define breakeven_point  12	/* Intel Pentium/Linux - gcc 2.96 */
#endif
#if defined(__hppa)
#  define breakeven_point  10	/* HP-PA               - gcc */
#endif
#if defined(__sparc__) || defined(__sparc)
#  define breakeven_point  33	/* Sun Sparc 5         - gcc 2.8.1 */
#endif

/* some other values of possible interest: */
/* #define breakeven_point  8 */  /* VAX 4000          - vaxc */
/* #define breakeven_point 19 */  /* VAX 4000          - gcc 2.7.0 */

#ifndef breakeven_point
#  define breakeven_point   6	/* some reasonable one-size-fits-all value */
#endif

#define fast_memcpy(d,s,n) \
  { register size_t nn = (size_t)(n); \
    if (nn >= breakeven_point) memcpy((d), (s), nn); \
    else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
      register char *dd; register const char *ss; \
      for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }

#define fast_memset(d,c,n) \
  { register size_t nn = (size_t)(n); \
    if (nn >= breakeven_point) memset((d), (int)(c), nn); \
    else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
      register char *dd; register const int cc=(int)(c); \
      for (dd=(d); nn>0; nn--) *dd++ = cc; } }

/* prototypes */

#if defined(NEED_ASPRINTF)
int asprintf   (char **ptr, const char *fmt, /*args*/ ...);
#endif
#if defined(NEED_VASPRINTF)
int vasprintf  (char **ptr, const char *fmt, va_list ap);
#endif
#if defined(NEED_ASNPRINTF)
int asnprintf  (char **ptr, size_t str_m, const char *fmt, /*args*/ ...);
#endif
#if defined(NEED_VASNPRINTF)
int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap);
#endif

#if defined(HAVE_SNPRINTF)
/* declare our portable snprintf  routine under name portable_snprintf  */
/* declare our portable vsnprintf routine under name portable_vsnprintf */
#else
/* declare our portable routines under names snprintf and vsnprintf */
#define portable_snprintf snprintf
#if !defined(NEED_SNPRINTF_ONLY)
#define portable_vsnprintf vsnprintf
#endif
#endif

#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...);
#if !defined(NEED_SNPRINTF_ONLY)
int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
#endif
#endif

/* declarations */

#if 0
static char credits[] = "\n\
@(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
#endif

#if defined(NEED_ASPRINTF)
int asprintf(char **ptr, const char *fmt, /*args*/ ...) {
  va_list ap;
  size_t str_m;
  int str_l;

  *ptr = NULL;
  va_start(ap, fmt);                            /* measure the required size */
  str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
  va_end(ap);
  assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
  *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
  if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
  else {
    int str_l2;
    va_start(ap, fmt);
    str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
    va_end(ap);
    assert(str_l2 == str_l);
  }
  return str_l;
}
#endif

#if defined(NEED_VASPRINTF)
int vasprintf(char **ptr, const char *fmt, va_list ap) {
  size_t str_m;
  int str_l;

  *ptr = NULL;
  { va_list ap2;
    va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
    str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
    va_end(ap2);
  }
  assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
  *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
  if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
  else {
    int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
    assert(str_l2 == str_l);
  }
  return str_l;
}
#endif

#if defined(NEED_ASNPRINTF)
int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
  va_list ap;
  int str_l;

  *ptr = NULL;
  va_start(ap, fmt);                            /* measure the required size */
  str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
  va_end(ap);
  assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
  if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
  /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
  if (str_m == 0) {  /* not interested in resulting string, just return size */
  } else {
    *ptr = (char *) malloc(str_m);
    if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
    else {
      int str_l2;
      va_start(ap, fmt);
      str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
      va_end(ap);
      assert(str_l2 == str_l);
    }
  }
  return str_l;
}
#endif

#if defined(NEED_VASNPRINTF)
int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
  int str_l;

  *ptr = NULL;
  { va_list ap2;
    va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
    str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
    va_end(ap2);
  }
  assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
  if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
  /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
  if (str_m == 0) {  /* not interested in resulting string, just return size */
  } else {
    *ptr = (char *) malloc(str_m);
    if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
    else {
      int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
      assert(str_l2 == str_l);
    }
  }
  return str_l;
}
#endif

/*
 * If the system does have snprintf and the portable routine is not
 * specifically required, this module produces no code for snprintf/vsnprintf.
 */
#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)

#if !defined(NEED_SNPRINTF_ONLY)
int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
  va_list ap;
  int str_l;

  va_start(ap, fmt);
  str_l = portable_vsnprintf(str, str_m, fmt, ap);
  va_end(ap);
  return str_l;
}
#endif

#if defined(NEED_SNPRINTF_ONLY)
int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
#else
int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
#endif

#if defined(NEED_SNPRINTF_ONLY)
  va_list ap;
#endif
  size_t str_l = 0;
  const char *p = fmt;

/* In contrast with POSIX, the ISO C99 now says
 * that str can be NULL and str_m can be 0.
 * This is more useful than the old:  if (str_m < 1) return -1; */

#if defined(NEED_SNPRINTF_ONLY)
  va_start(ap, fmt);
#endif
  if (!p) p = "";
  while (*p) {
    if (*p != '%') {
   /* if (str_l < str_m) str[str_l++] = *p++;    -- this would be sufficient */
   /* but the following code achieves better performance for cases
    * where format string is long and contains few conversions */
      const char *q = strchr(p+1,'%');
      size_t n = !q ? strlen(p) : (q-p);
      if (str_l < str_m) {
        size_t avail = str_m-str_l;
        fast_memcpy(str+str_l, p, (n>avail?avail:n));
      }
      p += n; str_l += n;
    } else {
      const char *starting_p;
      size_t min_field_width = 0, precision = 0;
      int zero_padding = 0, precision_specified = 0, justify_left = 0;
      int alternate_form = 0, force_sign = 0;
      int space_for_positive = 1; /* If both the ' ' and '+' flags appear,
                                     the ' ' flag should be ignored. */
      char length_modifier = '\0';            /* allowed values: \0, h, l, L */
      char tmp[32];/* temporary buffer for simple numeric->string conversion */

      const char *str_arg;      /* string address in case of string argument */
      size_t str_arg_l;         /* natural field width of arg without padding
                                   and sign */
      unsigned char uchar_arg;
        /* unsigned char argument value - only defined for c conversion.
           N.B. standard explicitly states the char argument for
           the c conversion is unsigned */

      size_t number_of_zeros_to_pad = 0;
        /* number of zeros to be inserted for numeric conversions
           as required by the precision or minimal field width */

      size_t zero_padding_insertion_ind = 0;
        /* index into tmp where zero padding is to be inserted */

      char fmt_spec = '\0';
        /* current conversion specifier character */

      str_arg = NULL;
      starting_p = p; p++;  /* skip '%' */
   /* parse flags */
      while (*p == '0' || *p == '-' || *p == '+' ||
             *p == ' ' || *p == '#' || *p == '\'') {
        switch (*p) {
        case '0': zero_padding = 1; break;
        case '-': justify_left = 1; break;
        case '+': force_sign = 1; space_for_positive = 0; break;
        case ' ': force_sign = 1;
     /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
#ifdef PERL_COMPATIBLE
     /* ... but in Perl the last of ' ' and '+' applies */
                  space_for_positive = 1;
#endif
                  break;
        case '#': alternate_form = 1; break;
        case '\'': break;
        }
        p++;
      }
   /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */

   /* parse field width */
      if (*p == '*') {
        int j;
        p++; j = va_arg(ap, int);
        if (j >= 0) min_field_width = j;
        else { min_field_width = -j; justify_left = 1; }
      } else if (isdigit((int)(*p))) {
        /* size_t could be wider than unsigned int;
           make sure we treat argument like common implementations do */
        unsigned int uj = *p++ - '0';
        while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
        min_field_width = uj;
      }
   /* parse precision */
      if (*p == '.') {
        p++; precision_specified = 1;
        if (*p == '*') {
          int j = va_arg(ap, int);
          p++;
          if (j >= 0) precision = j;
          else {
            precision_specified = 0; precision = 0;
         /* NOTE:
          *   Solaris 2.6 man page claims that in this case the precision
          *   should be set to 0.  Digital Unix 4.0, HPUX 10 and BSD man page
          *   claim that this case should be treated as unspecified precision,
          *   which is what we do here.
          */
          }
        } else if (isdigit((int)(*p))) {
          /* size_t could be wider than unsigned int;
             make sure we treat argument like common implementations do */
          unsigned int uj = *p++ - '0';
          while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
          precision = uj;
        }
      }
   /* parse 'h', 'l' and 'll' length modifiers */
      if (*p == 'h' || *p == 'l') {
        length_modifier = *p; p++;
        if (length_modifier == 'l' && *p == 'l') {   /* double l = long long */
#ifdef SNPRINTF_LONGLONG_SUPPORT
          length_modifier = '2';                  /* double l encoded as '2' */
#else
          length_modifier = 'l';                 /* treat it as a single 'l' */
#endif
          p++;
        }
      }
      fmt_spec = *p;
   /* common synonyms: */
      switch (fmt_spec) {
      case 'i': fmt_spec = 'd'; break;
      case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
      case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
      case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
      default: break;
      }
   /* get parameter value, do initial processing */
      switch (fmt_spec) {
      case '%': /* % behaves similar to 's' regarding flags and field widths */
      case 'c': /* c behaves similar to 's' regarding flags and field widths */
      case 's':
        length_modifier = '\0';          /* wint_t and wchar_t not supported */
     /* the result of zero padding flag with non-numeric conversion specifier*/
     /* is undefined. Solaris and HPUX 10 does zero padding in this case,    */
     /* Digital Unix and Linux does not. */
#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
        zero_padding = 0;    /* turn zero padding off for string conversions */
#endif
        str_arg_l = 1;
        switch (fmt_spec) {
        case '%':
          str_arg = p; break;
        case 'c': {
          int j = va_arg(ap, int);
          uchar_arg = (unsigned char) j;   /* standard demands unsigned char */
          str_arg = (const char *) &uchar_arg;
          break;
        }
        case 's':
          str_arg = va_arg(ap, const char *);
          if (!str_arg) str_arg_l = 0;
       /* make sure not to address string beyond the specified precision !!! */
          else if (!precision_specified) str_arg_l = strlen(str_arg);
       /* truncate string if necessary as requested by precision */
          else if (precision == 0) str_arg_l = 0;
          else {
            const char *q = memchr(str_arg, '\0', precision);

            str_arg_l = !q ? precision : (q-str_arg);
          }
          break;
        default: break;
        }
        break;
      case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
        /* NOTE: the u, o, x, X and p conversion specifiers imply
                 the value is unsigned;  d implies a signed value */
        int arg_sign = 0;
          /* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
            +1 if greater than zero (or nonzero for unsigned arguments),
            -1 if negative (unsigned argument is never negative) */

        int int_arg = 0;  unsigned int uint_arg = 0;
          /* only defined for length modifier h, or for no length modifiers */

        long int long_arg = 0;  unsigned long int ulong_arg = 0;
          /* only defined for length modifier l */

        void *ptr_arg = NULL;
          /* pointer argument value -only defined for p conversion */

#ifdef SNPRINTF_LONGLONG_SUPPORT
        long long int long_long_arg = 0;
        unsigned long long int ulong_long_arg = 0;
          /* only defined for length modifier ll */
#endif
        if (fmt_spec == 'p') {
        /* HPUX 10: An l, h, ll or L before any other conversion character
         *   (other than d, i, u, o, x, or X) is ignored.
         * Digital Unix:
         *   not specified, but seems to behave as HPUX does.
         * Solaris: If an h, l, or L appears before any other conversion
         *   specifier (other than d, i, u, o, x, or X), the behavior
         *   is undefined. (Actually %hp converts only 16-bits of address
         *   and %llp treats address as 64-bit data which is incompatible
         *   with (void *) argument on a 32-bit system).
         */
#ifdef SOLARIS_COMPATIBLE
#  ifdef SOLARIS_BUG_COMPATIBLE
          /* keep length modifiers even if it represents 'll' */
#  else
          if (length_modifier == '2') length_modifier = '\0';
#  endif
#else
          length_modifier = '\0';
#endif
          ptr_arg = va_arg(ap, void *);
          if (ptr_arg != NULL) arg_sign = 1;
        } else if (fmt_spec == 'd') {  /* signed */
          switch (length_modifier) {
          case '\0':
          case 'h':
         /* It is non-portable to specify a second argument of char or short
          * to va_arg, because arguments seen by the called function
          * are not char or short.  C converts char and short arguments
          * to int before passing them to a function.
          */
            int_arg = va_arg(ap, int);
            if      (int_arg > 0) arg_sign =  1;
            else if (int_arg < 0) arg_sign = -1;
            break;
          case 'l':
            long_arg = va_arg(ap, long int);
            if      (long_arg > 0) arg_sign =  1;
            else if (long_arg < 0) arg_sign = -1;
            break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
          case '2':
            long_long_arg = va_arg(ap, long long int);
            if      (long_long_arg > 0) arg_sign =  1;
            else if (long_long_arg < 0) arg_sign = -1;
            break;
#endif
          }
        } else {  /* unsigned */
          switch (length_modifier) {
          case '\0':
          case 'h':
            uint_arg = va_arg(ap, unsigned int);
            if (uint_arg) arg_sign = 1;
            break;
          case 'l':
            ulong_arg = va_arg(ap, unsigned long int);
            if (ulong_arg) arg_sign = 1;
            break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
          case '2':
            ulong_long_arg = va_arg(ap, unsigned long long int);
            if (ulong_long_arg) arg_sign = 1;
            break;
#endif
          }
        }
        str_arg = tmp; str_arg_l = 0;
     /* NOTE:
      *   For d, i, u, o, x, and X conversions, if precision is specified,
      *   the '0' flag should be ignored. This is so with Solaris 2.6,
      *   Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
      */
#ifndef PERL_COMPATIBLE
        if (precision_specified) zero_padding = 0;
#endif
        if (fmt_spec == 'd') {
          if (force_sign && arg_sign >= 0)
            tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
         /* leave negative numbers for sprintf to handle,
            to avoid handling tricky cases like (short int)(-32768) */
#ifdef LINUX_COMPATIBLE
        } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
          tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
#endif
        } else if (alternate_form) {
          if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
            { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
         /* alternate form should have no effect for p conversion, but ... */
#ifdef HPUX_COMPATIBLE
          else if (fmt_spec == 'p'
         /* HPUX 10: for an alternate form of p conversion,
          *          a nonzero result is prefixed by 0x. */
#ifndef HPUX_BUG_COMPATIBLE
         /* Actually it uses 0x prefix even for a zero value. */
                   && arg_sign != 0
#endif
                  ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
#endif
        }
        zero_padding_insertion_ind = str_arg_l;
        if (!precision_specified) precision = 1;   /* default precision is 1 */
        if (precision == 0 && arg_sign == 0
#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
            && fmt_spec != 'p'
         /* HPUX 10 man page claims: With conversion character p the result of
          * converting a zero value with a precision of zero is a null string.
          * Actually HP returns all zeroes, and Linux returns "(nil)". */
#endif
        ) {
         /* converted to null string */
         /* When zero value is formatted with an explicit precision 0,
            the resulting formatted string is empty (d, i, u, o, x, X, p).   */
        } else {
          char f[5]; int f_l = 0;
          f[f_l++] = '%';    /* construct a simple format string for sprintf */
          if (!length_modifier) { }
          else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
          else f[f_l++] = length_modifier;
          f[f_l++] = fmt_spec; f[f_l++] = '\0';
          if (fmt_spec == 'p') {
              str_arg_l += strlen(_ultoa((unsigned long)(ptr_arg), tmp+str_arg_l, 16));

              // str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
          }
          else if (fmt_spec == 'd') {  /* signed */
            switch (length_modifier) {
            case '\0':
            case 'h': //str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg);  break;
                      str_arg_l += strlen(_ltoa(int_arg, tmp+str_arg_l, 10)); break;
            case 'l': //str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
                      str_arg_l += strlen(_ltoa(long_arg, tmp+str_arg_l, 10)); break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
#error not translated
            case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
#endif
            }
          } else {  /* unsigned */
            int base = 10;
            if (fmt_spec == 'x' || fmt_spec == 'X') {
                base = 16;
            }
            if (fmt_spec == 'o') {
                base = 8;
            }
            switch (length_modifier) {
            case '\0':
            case 'h': //str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg);  break;
                      str_arg_l += strlen(_ultoa(uint_arg, tmp+str_arg_l, base)); break;
            case 'l': //str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
                      str_arg_l += strlen(_ultoa(ulong_arg, tmp+str_arg_l, base)); break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
#error not translated
            case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
#endif
            }
          }
         /* include the optional minus sign and possible "0x"
            in the region before the zero padding insertion point */
          if (zero_padding_insertion_ind < str_arg_l &&
              tmp[zero_padding_insertion_ind] == '-') {
            zero_padding_insertion_ind++;
          }
          if (zero_padding_insertion_ind+1 < str_arg_l &&
              tmp[zero_padding_insertion_ind]   == '0' &&
             (tmp[zero_padding_insertion_ind+1] == 'x' ||
              tmp[zero_padding_insertion_ind+1] == 'X') ) {
            zero_padding_insertion_ind += 2;
          }
        }
        { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
          if (alternate_form && fmt_spec == 'o'
#ifdef HPUX_COMPATIBLE                                  /* ("%#.o",0) -> ""  */
              && (str_arg_l > 0)
#endif
#ifdef DIGITAL_UNIX_BUG_COMPATIBLE                      /* ("%#o",0) -> "00" */
#else
              /* unless zero is already the first character */
              && !(zero_padding_insertion_ind < str_arg_l
                   && tmp[zero_padding_insertion_ind] == '0')
#endif
          ) {        /* assure leading zero for alternate-form octal numbers */
            if (!precision_specified || precision < num_of_digits+1) {
             /* precision is increased to force the first character to be zero,
                except if a zero value is formatted with an explicit precision
                of zero */
              precision = num_of_digits+1; precision_specified = 1;
            }
          }
       /* zero padding to specified precision? */
          if (num_of_digits < precision) 
            number_of_zeros_to_pad = precision - num_of_digits;
        }
     /* zero padding to specified minimal field width? */
        if (!justify_left && zero_padding) {
          int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
          if (n > 0) number_of_zeros_to_pad += n;
        }
        break;
      }
      default: /* unrecognized conversion specifier, keep format string as-is*/
        zero_padding = 0;  /* turn zero padding off for non-numeric convers. */
#ifndef DIGITAL_UNIX_COMPATIBLE
        justify_left = 1; min_field_width = 0;                /* reset flags */
#endif
#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
     /* keep the entire format string unchanged */
        str_arg = starting_p; str_arg_l = p - starting_p;
     /* well, not exactly so for Linux, which does something inbetween,
      * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y"  */
#else
     /* discard the unrecognized conversion, just keep *
      * the unrecognized conversion character          */
        str_arg = p; str_arg_l = 0;
#endif
        if (*p) str_arg_l++;  /* include invalid conversion specifier unchanged
                                 if not at end-of-string */
        break;
      }
      if (*p) p++;      /* step over the just processed conversion specifier */
   /* insert padding to the left as requested by min_field_width;
      this does not include the zero padding in case of numerical conversions*/
      if (!justify_left) {                /* left padding with blank or zero */
        int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
        if (n > 0) {
          if (str_l < str_m) {
            size_t avail = str_m-str_l;
            fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
          }
          str_l += n;
        }
      }
   /* zero padding as requested by the precision or by the minimal field width
    * for numeric conversions required? */
      if (number_of_zeros_to_pad <= 0) {
     /* will not copy first part of numeric right now, *
      * force it to be copied later in its entirety    */
        zero_padding_insertion_ind = 0;
      } else {
     /* insert first part of numerics (sign or '0x') before zero padding */
        int n = zero_padding_insertion_ind;
        if (n > 0) {
          if (str_l < str_m) {
            size_t avail = str_m-str_l;
            fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
          }
          str_l += n;
        }
     /* insert zero padding as requested by the precision or min field width */
        n = number_of_zeros_to_pad;
        if (n > 0) {
          if (str_l < str_m) {
            size_t avail = str_m-str_l;
            fast_memset(str+str_l, '0', (n>avail?avail:n));
          }
          str_l += n;
        }
      }
   /* insert formatted string
    * (or as-is conversion specifier for unknown conversions) */
      { int n = str_arg_l - zero_padding_insertion_ind;
        if (n > 0) {
          if (str_l < str_m) {
            size_t avail = str_m-str_l;
            fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
                        (n>avail?avail:n));
          }
          str_l += n;
        }
      }
   /* insert right padding */
      if (justify_left) {          /* right blank padding to the field width */
        int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
        if (n > 0) {
          if (str_l < str_m) {
            size_t avail = str_m-str_l;
            fast_memset(str+str_l, ' ', (n>avail?avail:n));
          }
          str_l += n;
        }
      }
    }
  }
#if defined(NEED_SNPRINTF_ONLY)
  va_end(ap);
#endif
  if (str_m > 0) { /* make sure the string is null-terminated
                      even at the expense of overwriting the last character
                      (shouldn't happen, but just in case) */
    str[str_l <= str_m-1 ? str_l : str_m-1] = '\0';
  }
  /* Return the number of characters formatted (excluding trailing null
   * character), that is, the number of characters that would have been
   * written to the buffer if it were large enough.
   *
   * The value of str_l should be returned, but str_l is of unsigned type
   * size_t, and snprintf is int, possibly leading to an undetected
   * integer overflow, resulting in a negative return value, which is illegal.
   * Both XSH5 and ISO C99 (at least the draft) are silent on this issue.
   * Should errno be set to EOVERFLOW and EOF returned in this case???
   */
  return (int) str_l;
}
#endif


================================================
FILE: cgadraw/snprintf.h
================================================
#ifndef _PORTABLE_SNPRINTF_H_
#define _PORTABLE_SNPRINTF_H_

extern int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...);
extern int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
#define snprintf  portable_snprintf
#define vsnprintf portable_vsnprintf

#endif


================================================
FILE: cgadraw/string.c
================================================
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include "config.h"
#include "snprintf.h"

#include "caca.h"
#include "cacaint.h"

int caca_gotoxy(caca_canvas_t *cv, int x, int y)
{
    cv->frames[cv->frame].x = x;
    cv->frames[cv->frame].y = y;

    return 0;
}

int caca_wherex(caca_canvas_t const *cv)
{
    return cv->frames[cv->frame].x;
}

int caca_wherey(caca_canvas_t const *cv)
{
    return cv->frames[cv->frame].y;
}

int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch)
{
    cv->c[x + y * cv->width].c = caca_utf32_to_cp437(ch);
    cv->c[x + y * cv->width].attr = caca_attr_to_ansi(cv->curattr);
    return 1;
}

uint32_t caca_get_char(caca_canvas_t const *cv, int x, int y)
{
    if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
        return ' ';

    return caca_cp437_to_utf32(cv->c[x + y * cv->width].c);
}

int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s)
{
    int len;

    if (y < 0 || y >= (int)cv->height || x >= (int)cv->width) {
        return strlen(s);
    }

    for (len = 0; *s; len++) {
        caca_put_char(cv, x + len, y, *s++);
    }

    return len;
}

int caca_printf(caca_canvas_t *cv, int x, int y, char const *format, ...)
{
    va_list args;
    int ret;
    va_start(args, format);
    ret = caca_vprintf(cv, x, y, format, args);
    va_end(args);
    return ret;
}

int caca_vprintf(caca_canvas_t *cv, int x, int y, char const *format,
                 va_list args)
{
    char tmp[256];
    char *buf = tmp;
    int bufsize = sizeof(tmp), ret;

    if(cv->width - x + 1 > sizeof(tmp))
    {
        return -1;
    }

    vsnprintf(buf, bufsize, format, args);
    buf[bufsize - 1] = '\0';

    ret = caca_put_str(cv, x, y, buf);

    return ret;
}

int caca_clear_canvas(caca_canvas_t *cv)
{
    uint32_t attr = cv->curattr;
    int n;

    for(n = cv->width * cv->height; n--; )
    {
        cv->c[n].c = ' ';
        cv->c[n].attr = caca_attr_to_ansi(attr);
    }

    return 0;
}

int caca_set_canvas_handle(caca_canvas_t *cv, int x, int y)
{
    cv->frames[cv->frame].handlex = x;
    cv->frames[cv->frame].handley = y;

    return 0;
}

int caca_get_canvas_handle_x(caca_canvas_t const *cv)
{
    return cv->frames[cv->frame].handlex;
}

int caca_get_canvas_handle_y(caca_canvas_t const *cv)
{
    return cv->frames[cv->frame].handley;
}

int caca_blit(caca_canvas_t *dst, int x, int y,
              caca_canvas_t const *src, caca_canvas_t const *mask)
{
    return -1;
}

int caca_set_canvas_boundaries(caca_canvas_t *cv, int x, int y, int w, int h)
{
    return -1;
}



================================================
FILE: cgadraw/transfrm.c
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains horizontal and vertical flipping routines.
 */

#include "config.h"
#include "caca.h"
#include "cacaint.h"

static uint32_t flipchar(uint32_t ch);
static uint32_t flopchar(uint32_t ch);
static uint32_t rotatechar(uint32_t ch);
static uint32_t leftchar(uint32_t ch);
static uint32_t rightchar(uint32_t ch);
static void leftpair(uint32_t pair[2]);
static void rightpair(uint32_t pair[2]);

int caca_invert(caca_canvas_t *cv)
{
    return -1;
}

int caca_flip(caca_canvas_t *cv)
{
    return -1;
}

int caca_flop(caca_canvas_t *cv)
{
    return -1;
}

int caca_rotate_180(caca_canvas_t *cv)
{
    return -1;
}

int caca_rotate_left(caca_canvas_t *cv)
{
    return -1;
}

int caca_rotate_right(caca_canvas_t *cv)
{
    return -1;
}

int caca_stretch_left(caca_canvas_t *cv)
{
    return -1;
}

int caca_stretch_right(caca_canvas_t *cv)
{
    return -1;
}

/* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
 * of linear lookup. */
static uint32_t flipchar(uint32_t ch)
{
    int i;

    static uint32_t const noflip[] =
    {
         /* ASCII */
         ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
         'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
         '_', 'i', 'o', 'v', 'w', 'x', '|',
         /* CP437 and box drawing */
         0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
         0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
         0x2575, 0x2577, 0x2579, 0x257b, /* ╵ ╷ ╹ ╻ */
         0
    };

    static uint32_t const pairs[] =
    {
         /* ASCII */
         '(', ')',
         '/', '\\',
         '<', '>',
         '[', ']',
         'b', 'd',
         'p', 'q',
         '{', '}',
         /* ASCII-Unicode */
         ';', 0x204f, /* ; ⁏ */
         '`', 0x00b4, /* ` ´ */
         ',', 0x02ce, /* , ˎ */
         '1', 0x07c1, /* 1 ߁ */
         'B', 0x10412,/* B 𐐒 */
         'C', 0x03fd, /* C Ͻ */
         'D', 0x15e1, /* D ᗡ */
         'E', 0x018e, /* E Ǝ */
         'J', 0x1490, /* J ᒐ */
         'L', 0x2143, /* L ⅃ */
         'N', 0x0418, /* N И */
         'P', 0x1040b,/* P 𐐋 */
         'R', 0x042f, /* R Я */
         'S', 0x01a7, /* S Ƨ */
         'c', 0x0254, /* c ɔ */
         'e', 0x0258, /* e ɘ */
         /* CP437 */
         0x258c, 0x2590, /* ▌ ▐ */
         0x2596, 0x2597, /* ▖ ▗ */
         0x2598, 0x259d, /* ▘ ▝ */
         0x2599, 0x259f, /* ▙ ▟ */
         0x259a, 0x259e, /* ▚ ▞ */
         0x259b, 0x259c, /* ▛ ▜ */
         0x25ba, 0x25c4, /* ► ◄ */
         0x2192, 0x2190, /* → ← */
         0x2310, 0xac,   /* ⌐ ¬ */
         /* Box drawing */
         0x250c, 0x2510, /* ┌ ┐ */
         0x2514, 0x2518, /* └ ┘ */
         0x251c, 0x2524, /* ├ ┤ */
         0x250f, 0x2513, /* ┏ ┓ */
         0x2517, 0x251b, /* ┗ ┛ */
         0x2523, 0x252b, /* ┣ ┫ */
         0x2552, 0x2555, /* ╒ ╕ */
         0x2558, 0x255b, /* ╘ ╛ */
         0x2553, 0x2556, /* ╓ ╖ */
         0x2559, 0x255c, /* ╙ ╜ */
         0x2554, 0x2557, /* ╔ ╗ */
         0x255a, 0x255d, /* ╚ ╝ */
         0x255e, 0x2561, /* ╞ ╡ */
         0x255f, 0x2562, /* ╟ ╢ */
         0x2560, 0x2563, /* ╠ ╣ */
         0x2574, 0x2576, /* ╴ ╶ */
         0x2578, 0x257a, /* ╸ ╺ */
         /* Misc Unicode */
         0x22f2, 0x22fa, /* ⋲ ⋺ */
         0x22f3, 0x22fb, /* ⋳ ⋻ */
         0x2308, 0x2309, /* ⌈ ⌉ */
         0x230a, 0x230b, /* ⌊ ⌋ */
         0x230c, 0x230d, /* ⌌ ⌍ */
         0x230e, 0x230f, /* ⌎ ⌏ */
         0x231c, 0x231d, /* ⌜ ⌝ */
         0x231e, 0x231f, /* ⌞ ⌟ */
         0x2326, 0x232b, /* ⌦ ⌫ */
         0x2329, 0x232a, /* 〈 〉 */
         0x2341, 0x2342, /* ⍁ ⍂ */
         0x2343, 0x2344, /* ⍃ ⍄ */
         0x2345, 0x2346, /* ⍅ ⍆ */
         0x2347, 0x2348, /* ⍇ ⍈ */
         0x233f, 0x2340, /* ⌿ ⍀ */
         0x239b, 0x239e, /* ⎛ ⎞ */
         0x239c, 0x239f, /* ⎜ ⎟ */
         0x239d, 0x23a0, /* ⎝ ⎠ */
         0x23a1, 0x23a4, /* ⎡ ⎤ */
         0x23a2, 0x23a5, /* ⎢ ⎥ */
         0x23a3, 0x23a6, /* ⎣ ⎦ */
         0x23a7, 0x23ab, /* ⎧ ⎫ */
         0x23a8, 0x23ac, /* ⎨ ⎬ */
         0x23a9, 0x23ad, /* ⎩ ⎭ */
         0x23b0, 0x23b1, /* ⎰ ⎱ */
         0x23be, 0x23cb, /* ⎾ ⏋ */
         0x23bf, 0x23cc, /* ⎿ ⏌ */
         0
    };

    for(i = 0; noflip[i]; i++)
        if(ch == noflip[i])
            return ch;

    for(i = 0; pairs[i]; i++)
        if(ch == pairs[i])
            return pairs[i ^ 1];

    return ch;
}

static uint32_t flopchar(uint32_t ch)
{
    int i;

    static uint32_t const noflop[] =
    {
         /* ASCII */
         ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
         '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
         'c', 'o', '{', '|', '}',
         /* CP437 and box drawing */
         0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
         0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
         0x2574, 0x2576, 0x2578, 0x257a, /* ╴ ╶ ╸ ╺ */
         /* Misc Unicode */
         0x22f2, 0x22fa, 0x22f3, 0x22fb, 0x2326, 0x232b, /* ⋲ ⋺ ⋳ ⋻ ⌦ ⌫ */
         0x2329, 0x232a, 0x2343, 0x2344, 0x2345, 0x2346, /* 〈 〉 ⍃ ⍄ ⍅ ⍆ */
         0x2347, 0x2348, 0x239c, 0x239f, 0x23a2, 0x23a5, /* ⍇ ⍈ ⎜ ⎟ ⎢ ⎥ */
         0x23a8, 0x23ac, /* ⎨ ⎬ */
         0
    };

    static uint32_t const pairs[] =
    {
         /* ASCII */
         '/', '\\',
         'M', 'W',
         ',', '`',
         'b', 'p',
         'd', 'q',
         'p', 'q',
         'f', 't',
         '.', '\'',
         /* ASCII-Unicode */
         '_', 0x203e, /* _ ‾ */
         '!', 0x00a1, /* ! ¡ */
         'A', 0x2200, /* A ∀ */
         'J', 0x1489, /* J ᒉ */
         'L', 0x0413, /* L Г */
         'N', 0x0418, /* N И */
         'P', 0x042c, /* P Ь */
         'R', 0x0281, /* R ʁ */
         'S', 0x01a7, /* S Ƨ */
         'U', 0x0548, /* U Ո */
         'V', 0x039b, /* V Λ */
         'Y', 0x2144, /* Y ⅄ */
         'h', 0x03bc, /* h μ */
         'i', 0x1d09, /* i ᴉ */
         'j', 0x1e37, /* j ḷ */
         'l', 0x0237, /* l ȷ */
         'v', 0x028c, /* v ʌ */
         'w', 0x028d, /* w ʍ */
         'y', 0x03bb, /* y λ */
         /* Not perfect, but better than nothing */
         '"', 0x201e, /* " „ */
         'm', 0x026f, /* m ɯ */
         'n', 'u',
         /* CP437 */
         0x2584, 0x2580, /* ▄ ▀ */
         0x2596, 0x2598, /* ▖ ▘ */
         0x2597, 0x259d, /* ▗ ▝ */
         0x2599, 0x259b, /* ▙ ▛ */
         0x259f, 0x259c, /* ▟ ▜ */
         0x259a, 0x259e, /* ▚ ▞ */
         /* Box drawing */
         0x250c, 0x2514, /* ┌ └ */
         0x2510, 0x2518, /* ┐ ┘ */
         0x252c, 0x2534, /* ┬ ┴ */
         0x250f, 0x2517, /* ┏ ┗ */
         0x2513, 0x251b, /* ┓ ┛ */
         0x2533, 0x253b, /* ┳ ┻ */
         0x2554, 0x255a, /* ╔ ╚ */
         0x2557, 0x255d, /* ╗ ╝ */
         0x2566, 0x2569, /* ╦ ╩ */
         0x2552, 0x2558, /* ╒ ╘ */
         0x2555, 0x255b, /* ╕ ╛ */
         0x2564, 0x2567, /* ╤ ╧ */
         0x2553, 0x2559, /* ╓ ╙ */
         0x2556, 0x255c, /* ╖ ╜ */
         0x2565, 0x2568, /* ╥ ╨ */
         0x2575, 0x2577, /* ╵ ╷ */
         0x2579, 0x257b, /* ╹ ╻ */
         /* Misc Unicode */
         0x2308, 0x230a, /* ⌈ ⌊ */
         0x2309, 0x230b, /* ⌉ ⌋ */
         0x230c, 0x230e, /* ⌌ ⌎ */
         0x230d, 0x230f, /* ⌍ ⌏ */
         0x231c, 0x231e, /* ⌜ ⌞ */
         0x231d, 0x231f, /* ⌝ ⌟ */
         0x2341, 0x2342, /* ⍁ ⍂ */
         0x233f, 0x2340, /* ⌿ ⍀ */
         0x239b, 0x239d, /* ⎛ ⎝ */
         0x239e, 0x23a0, /* ⎞ ⎠ */
         0x23a1, 0x23a3, /* ⎡ ⎣ */
         0x23a4, 0x23a6, /* ⎤ ⎦ */
         0x23a7, 0x23a9, /* ⎧ ⎩ */
         0x23ab, 0x23ad, /* ⎫ ⎭ */
         0x23b0, 0x23b1, /* ⎰ ⎱ */
         0x23be, 0x23bf, /* ⎾ ⎿ */
         0x23cb, 0x23cc, /* ⏋ ⏌ */
         0
    };

    for(i = 0; noflop[i]; i++)
        if(ch == noflop[i])
            return ch;

    for(i = 0; pairs[i]; i++)
        if(ch == pairs[i])
            return pairs[i ^ 1];

    return ch;
}

static uint32_t rotatechar(uint32_t ch)
{
    int i;

    static uint32_t const norotate[] =
    {
         /* ASCII */
         ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
         'O', 'S', 'X', 'Z', '\\', 'o', 's', 'x', 'z', '|',
         /* Unicode */
         0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
         /* Misc Unicode */
         0x233f, 0x2340, 0x23b0, 0x23b1, /* ⌿ ⍀ ⎰ ⎱ */
         0
    };

    static uint32_t const pairs[] =
    {
         /* ASCII */
         '(', ')',
         '<', '>',
         '[', ']',
         '{', '}',
         '.', '\'',
         '6', '9',
         'M', 'W',
         'b', 'q',
         'd', 'p',
         'n', 'u',
         /* ASCII-Unicode */
         '_', 0x203e, /* _ ‾ */
         ',', 0x00b4, /* , ´ */
         ';', 0x061b, /* ; ؛ */
         '`', 0x02ce, /* ` ˎ */
         '&', 0x214b, /* & ⅋ */
         '!', 0x00a1, /* ! ¡ */
         '?', 0x00bf, /* ? ¿ */
         '3', 0x0190, /* 3 Ɛ */
         '4', 0x152d, /* 4 ᔭ */
         'A', 0x2200, /* A ∀ */
         'B', 0x10412,/* B 𐐒 */
         'C', 0x03fd, /* C Ͻ */
         'D', 0x15e1, /* D ᗡ */
         'E', 0x018e, /* E Ǝ */
         'F', 0x2132, /* F Ⅎ -- 0x07c3 looks better, but is RTL */
         'G', 0x2141, /* G ⅁ */
         'J', 0x148b, /* J ᒋ */
         'L', 0x2142, /* L ⅂ */
         'P', 0x0500, /* P Ԁ */
         'Q', 0x038c, /* Q Ό */
         'R', 0x1d1a, /* R ᴚ */
         'T', 0x22a5, /* T ⊥ */
         'U', 0x0548, /* U Ո */
         'V', 0x039b, /* V Λ */
         'Y', 0x2144, /* Y ⅄ */
         'a', 0x0250, /* a ɐ */
         'c', 0x0254, /* c ɔ */
         'e', 0x01dd, /* e ǝ */
         'f', 0x025f, /* f ɟ */
         'g', 0x1d77, /* g ᵷ */
         'h', 0x0265, /* h ɥ */
         'i', 0x1d09, /* i ᴉ */
         'j', 0x1e37, /* j ḷ */
         'k', 0x029e, /* k ʞ */
         'l', 0x0237, /* l ȷ */
         'm', 0x026f, /* m ɯ */
         'r', 0x0279, /* r ɹ */
         't', 0x0287, /* t ʇ */
         'v', 0x028c, /* v ʌ */
         'w', 0x028d, /* w ʍ */
         'y', 0x028e, /* y ʎ */
         /* Unicode-ASCII to match third-party software */
         0x0183, 'g', /* ƃ g */
         0x0259, 'e', /* ə e */
         0x027e, 'j', /* ɾ j */
         0x02d9, '.', /* ˙ . */
         0x05df, 'l', /* ן l */
         /* Not perfect, but better than nothing */
         '"', 0x201e, /* " „ */
         /* Misc Unicode */
         0x00e6, 0x1d02, /* æ ᴂ */
         0x0153, 0x1d14, /* œ ᴔ */
         0x03b5, 0x025c, /* ε ɜ */
         0x025b, 0x025c, /* ɛ ɜ */
         /* CP437 */
         0x258c, 0x2590, /* ▌ ▐ */
         0x2584, 0x2580, /* ▄ ▀ */
         0x2596, 0x259d, /* ▖ ▝ */
         0x2597, 0x2598, /* ▗ ▘ */
         0x2599, 0x259c, /* ▙ ▜ */
         0x259f, 0x259b, /* ▟ ▛ */
         /* Box drawing */
         0x250c, 0x2518, /* ┌ ┘ */
         0x2510, 0x2514, /* ┐ └ */
         0x251c, 0x2524, /* ├ ┤ */
         0x252c, 0x2534, /* ┬ ┴ */
         0x250f, 0x251b, /* ┏ ┛ */
         0x2513, 0x2517, /* ┓ ┗ */
         0x2523, 0x252b, /* ┣ ┫ */
         0x2533, 0x253b, /* ┳ ┻ */
         0x2554, 0x255d, /* ╔ ╝ */
         0x2557, 0x255a, /* ╗ ╚ */
         0x2560, 0x2563, /* ╠ ╣ */
         0x2566, 0x2569, /* ╦ ╩ */
         0x2552, 0x255b, /* ╒ ╛ */
         0x2555, 0x2558, /* ╕ ╘ */
         0x255e, 0x2561, /* ╞ ╡ */
         0x2564, 0x2567, /* ╤ ╧ */
         0x2553, 0x255c, /* ╓ ╜ */
         0x2556, 0x2559, /* ╖ ╙ */
         0x255f, 0x2562, /* ╟ ╢ */
         0x2565, 0x2568, /* ╥ ╨ */
         0x2574, 0x2576, /* ╴ ╶ */
         0x2575, 0x2577, /* ╵ ╷ */
         0x2578, 0x257a, /* ╸ ╺ */
         0x2579, 0x257b, /* ╹ ╻ */
         /* Misc Unicode */
         0x22f2, 0x22fa, /* ⋲ ⋺ */
         0x22f3, 0x22fb, /* ⋳ ⋻ */
         0x2308, 0x230b, /* ⌈ ⌋ */
         0x2309, 0x230a, /* ⌉ ⌊ */
         0x230c, 0x230f, /* ⌌ ⌏ */
         0x230d, 0x230e, /* ⌍ ⌎ */
         0x231c, 0x231f, /* ⌜ ⌟ */
         0x231d, 0x231e, /* ⌝ ⌞ */
         0x2326, 0x232b, /* ⌦ ⌫ */
         0x2329, 0x232a, /* 〈 〉 */
         0x2343, 0x2344, /* ⍃ ⍄ */
         0x2345, 0x2346, /* ⍅ ⍆ */
         0x2347, 0x2348, /* ⍇ ⍈ */
         0x239b, 0x23a0, /* ⎛ ⎠ */
         0x239c, 0x239f, /* ⎜ ⎟ */
         0x239e, 0x239d, /* ⎞ ⎝ */
         0x23a1, 0x23a6, /* ⎡ ⎦ */
         0x23a2, 0x23a5, /* ⎢ ⎥ */
         0x23a4, 0x23a3, /* ⎤ ⎣ */
         0x23a7, 0x23ad, /* ⎧ ⎭ */
         0x23a8, 0x23ac, /* ⎨ ⎬ */
         0x23ab, 0x23a9, /* ⎫ ⎩ */
         0x23be, 0x23cc, /* ⎾ ⏌ */
         0x23cb, 0x23bf, /* ⏋ ⎿ */
         0
    };

    for(i = 0; norotate[i]; i++)
        if(ch == norotate[i])
            return ch;

    for(i = 0; pairs[i]; i++)
        if(ch == pairs[i])
            return pairs[i ^ 1];

    return ch;
}

static uint32_t const leftright2[] =
{
    /* ASCII */
    '/', '\\',
    '|', '-',
    '|', '_', /* This is all right because there was already a '|' before */
    /* ASCII-Unicode */
    '|', 0x203e, /* | ‾ */
    /* Misc Unicode */
    0x2571, 0x2572, /* ╱ ╲ */
    /* Box drawing */
    0x2500, 0x2502, /* ─ │ */
    0x2501, 0x2503, /* ━ ┃ */
    0x2550, 0x2551, /* ═ ║ */
    0, 0
};

static uint32_t const leftright4[] =
{
    /* ASCII */
    '<', 'v', '>', '^',
    ',', '.', '\'', '`',
    /* ASCII / Unicode */
    '(', 0x203f, ')', 0x2040,       /* ( ‿ ) ⁀ */
    /* Misc Unicode */
    0x256d, 0x2570, 0x256f, 0x256e, /* ╭ ╰ ╯ ╮ */
    /* CP437 */
    0x258c, 0x2584, 0x2590, 0x2580, /* ▌ ▄ ▐ ▀ */
    0x2596, 0x2597, 0x259d, 0x2598, /* ▖ ▗ ▝ ▘ */
    0x2599, 0x259f, 0x259c, 0x259b, /* ▙ ▟ ▜ ▛ */
    /* Box drawing */
    0x250c, 0x2514, 0x2518, 0x2510, /* ┌ └ ┘ ┐ */
    0x250f, 0x2517, 0x251b, 0x2513, /* ┏ ┗ ┛ ┓ */
    0x251c, 0x2534, 0x2524, 0x252c, /* ├ ┴ ┤ ┬ */
    0x2523, 0x253b, 0x252b, 0x2533, /* ┣ ┻ ┫ ┳ */
    0x2552, 0x2559, 0x255b, 0x2556, /* ╒ ╙ ╛ ╖ */
    0x2553, 0x2558, 0x255c, 0x2555, /* ╓ ╘ ╜ ╕ */
    0x2554, 0x255a, 0x255d, 0x2557, /* ╔ ╚ ╝ ╗ */
    0x255e, 0x2568, 0x2561, 0x2565, /* ╞ ╨ ╡ ╥ */
    0x255f, 0x2567, 0x2562, 0x2564, /* ╟ ╧ ╢ ╤ */
    0x2560, 0x2569, 0x2563, 0x2566, /* ╠ ╩ ╣ ╦ */
    0x2574, 0x2577, 0x2576, 0x2575, /* ╴ ╷ ╶ ╵ */
    0x2578, 0x257b, 0x257a, 0x2579, /* ╸ ╻ ╺ ╹ */
    0, 0, 0, 0
};

static uint32_t leftchar(uint32_t ch)
{
    int i;

    for(i = 0; leftright2[i]; i++)
        if(ch == leftright2[i])
            return leftright2[(i & ~1) | ((i + 1) & 1)];

    for(i = 0; leftright4[i]; i++)
        if(ch == leftright4[i])
            return leftright4[(i & ~3) | ((i + 1) & 3)];

    return ch;
}

static uint32_t rightchar(uint32_t ch)
{
    int i;

    for(i = 0; leftright2[i]; i++)
        if(ch == leftright2[i])
            return leftright2[(i & ~1) | ((i - 1) & 1)];

    for(i = 0; leftright4[i]; i++)
        if(ch == leftright4[i])
            return leftright4[(i & ~3) | ((i - 1) & 3)];

    return ch;
}

static uint32_t const leftright2x2[] =
{
    /* ASCII / Unicode */
    '-', '-', 0x4e28, CACA_MAGIC_FULLWIDTH, /* -- 丨 */
    '|', '|', 0x2f06, CACA_MAGIC_FULLWIDTH, /* || ⼆ */
    /* Unicode */
    0x2584, 0x2580, 0x2580, 0x2584, /* ▄▀ ▀▄ */
    0, 0, 0, 0
};

static uint32_t const leftright2x4[] =
{
    /* ASCII */
    ':', ' ', '.', '.', ' ', ':', '\'', '\'',
    /* ASCII / Unicode */
    ' ', '`', 0x00b4, ' ', 0x02ce, ' ', ' ', ',',      /*  ` ´  ˎ   , */
    ' ', '`', '\'',   ' ', '.',    ' ', ' ', ',',      /* fallback ASCII */
    '`', ' ', ',', ' ', ' ', 0x00b4, ' ', 0x02ce,      /*  ` ,   ˎ  ´ */
    '`', ' ', ',', ' ', ' ', '.',    ' ', '\'',        /* fallback ASCII */
    '/', ' ', '-', 0x02ce, ' ', '/', '`', '-',         /* /  -ˎ  / `- */
    '/', ' ', '-', '.',    ' ', '/', '\'', '-',        /* fallback ASCII */
    '\\', ' ', ',', '-', ' ', '\\', '-', 0x00b4,       /* \  ,-  \ -´ */
    '\\', ' ', '.', '-', ' ', '\\', '-', '\'',         /* fallback ASCII */
    '\\', ' ', '_', ',', ' ', '\\', 0x00b4, 0x203e,    /* \  _,  \ ´‾ */
    '\\', '_', '_', '/', 0x203e, '\\', '/', 0x203e,    /* \_ _/ ‾\ /‾ */
    '_', '\\', 0x203e, '/', '\\', 0x203e, '/', '_',    /* _\ ‾/ \‾ /_ */
    '|', ' ', '_', '_', ' ', '|', 0x203e, 0x203e,      /* |  __  | ‾‾ */
    '_', '|', 0x203e, '|', '|', 0x203e, '|', '_',      /* _| ‾| |‾ |_ */
    '|', '_', '_', '|', 0x203e, '|', '|', 0x203e,      /* |_ _| ‾| |‾ */
    '_', ' ', ' ', 0x2577, ' ', 0x203e, 0x2575, ' ',   /* _   ╷  ‾ ╵  */
    ' ', '_', ' ', 0x2575, 0x203e, ' ', 0x2577, ' ',   /*  _  ╵ ‾  ╷  */
    '.', '_', '.', 0x2575, 0x203e, '\'', 0x2577, '\'', /* ._ .╵ ‾' ╷' */
    '(', '_', 0x203f, '|', 0x203e, ')', '|', 0x2040,   /* (_ ‿| ‾) |⁀ */
    '(', 0x203e, '|', 0x203f, '_', ')', 0x2040, '|',   /* (‾ |‿ _) ⁀| */
    '\\', '/', 0xff1e, CACA_MAGIC_FULLWIDTH,
            '/', '\\', 0xff1c, CACA_MAGIC_FULLWIDTH,  /* \/ > /\ < */
    ')', ' ', 0xfe35, CACA_MAGIC_FULLWIDTH,
            ' ', '(', 0xfe36, CACA_MAGIC_FULLWIDTH,   /* )  ︵  ( ︶ */
    '}', ' ', 0xfe37, CACA_MAGIC_FULLWIDTH,
            ' ', '{', 0xfe38, CACA_MAGIC_FULLWIDTH,   /* }  ︷  { ︸ */
    /* Not perfect, but better than nothing */
    '(', ' ', 0x02ce, ',', ' ', ')', 0x00b4, '`',      /* (  ˎ,  ) ´` */
    ' ', 'v', '>', ' ', 0x028c, ' ', ' ', '<',         /*  v >  ʌ   < */
    ' ', 'V', '>', ' ', 0x039b, ' ', ' ', '<',         /*  V >  Λ   < */
    'v', ' ', '>', ' ', ' ', 0x028c, ' ', '<',         /* v  >   ʌ  < */
    'V', ' ', '>', ' ', ' ', 0x039b, ' ', '<',         /* V  >   Λ  < */
    '\\', '|', 0xff1e, CACA_MAGIC_FULLWIDTH,
            '|', '\\', 0xff1c, CACA_MAGIC_FULLWIDTH,  /* \| > |\ < */
    '|', '/', 0xff1e, CACA_MAGIC_FULLWIDTH,
            '/', '|', 0xff1c, CACA_MAGIC_FULLWIDTH,   /* |/ > /| < */
    /* Unicode */
    0x2584, ' ', ' ', 0x2584, ' ', 0x2580, 0x2580, ' ',       /* ▄   ▄  ▀ ▀  */
    0x2588, ' ', 0x2584, 0x2584, ' ', 0x2588, 0x2580, 0x2580, /* █  ▄▄  █ ▀▀ */
    0x2588, 0x2584, 0x2584, 0x2588,
            0x2580, 0x2588, 0x2588, 0x2580,                   /* █▄ ▄█ ▀█ █▀ */
    /* TODO: Braille */
    /* Not perfect, but better than nothing */
    0x2591, ' ', 0x28e4, 0x28e4, ' ', 0x2591, 0x281b, 0x281b, /* ░  ⣤⣤  ░ ⠛⠛ */
    0x2592, ' ', 0x28f6, 0x28f6, ' ', 0x2592, 0x283f, 0x283f, /* ▒  ⣶⣶  ▒ ⠿⠿ */
    0, 0, 0, 0, 0, 0, 0, 0
};

static void leftpair(uint32_t pair[2])
{
    int i;

    for(i = 0; leftright2x2[i]; i += 2)
        if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
        {
            pair[0] = leftright2x2[(i & ~3) | ((i + 2) & 3)];
            pair[1] = leftright2x2[((i & ~3) | ((i + 2) & 3)) + 1];
            return;
        }

    for(i = 0; leftright2x4[i]; i += 2)
        if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
        {
            pair[0] = leftright2x4[(i & ~7) | ((i + 2) & 7)];
            pair[1] = leftright2x4[((i & ~7) | ((i + 2) & 7)) + 1];
            return;
        }
}

static void rightpair(uint32_t pair[2])
{
    int i;

    for(i = 0; leftright2x2[i]; i += 2)
        if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
        {
            pair[0] = leftright2x2[(i & ~3) | ((i - 2) & 3)];
            pair[1] = leftright2x2[((i & ~3) | ((i - 2) & 3)) + 1];
            return;
        }

    for(i = 0; leftright2x4[i]; i += 2)
        if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
        {
            pair[0] = leftright2x4[(i & ~7) | ((i - 2) & 7)];
            pair[1] = leftright2x4[((i & ~7) | ((i - 2) & 7)) + 1];
            return;
        }
}



================================================
FILE: cgadraw/triangle.c
================================================
/*
 *  libcaca     Colour ASCII-Art library
 *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
 *              All Rights Reserved
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What the Fuck You Want
 *  to Public License, Version 2, as published by Sam Hocevar. See
 *  http://www.wtfpl.net/ for more details.
 */

/*
 *  This file contains triangle drawing functions, both filled and outline.
 */

#include "config.h"

#if !defined(__KERNEL__)
#   include <stdlib.h>
#endif

#include "caca.h"
#include "cacaint.h"

/** \brief Draw a triangle on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x1 X coordinate of the first point.
 *  \param y1 Y coordinate of the first point.
 *  \param x2 X coordinate of the second point.
 *  \param y2 Y coordinate of the second point.
 *  \param x3 X coordinate of the third point.
 *  \param y3 Y coordinate of the third point.
 *  \param ch UTF-32 character to be used to draw the triangle outline.
 *  \return This function always returns 0.
 */
int caca_draw_triangle(caca_canvas_t * cv, int x1, int y1, int x2, int y2,
                       int x3, int y3, uint32_t ch)
{
    caca_draw_line(cv, x1, y1, x2, y2, ch);
    caca_draw_line(cv, x2, y2, x3, y3, ch);
    caca_draw_line(cv, x3, y3, x1, y1, ch);

    return 0;
}

/** \brief Draw a thin triangle on the canvas.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x1 X coordinate of the first point.
 *  \param y1 Y coordinate of the first point.
 *  \param x2 X coordinate of the second point.
 *  \param y2 Y coordinate of the second point.
 *  \param x3 X coordinate of the third point.
 *  \param y3 Y coordinate of the third point.
 *  \return This function always returns 0.
 */
int caca_draw_thin_triangle(caca_canvas_t * cv, int x1, int y1,
                            int x2, int y2, int x3, int y3)
{
    caca_draw_thin_line(cv, x1, y1, x2, y2);
    caca_draw_thin_line(cv, x2, y2, x3, y3);
    caca_draw_thin_line(cv, x3, y3, x1, y1);

    return 0;
}

/** \brief Fill a triangle on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x1 X coordinate of the first point.
 *  \param y1 Y coordinate of the first point.
 *  \param x2 X coordinate of the second point.
 *  \param y2 Y coordinate of the second point.
 *  \param x3 X coordinate of the third point.
 *  \param y3 Y coordinate of the third point.
 *  \param ch UTF-32 character to be used to fill the triangle.
 *  \return This function always returns 0.
 */
int caca_fill_triangle(caca_canvas_t * cv, int x1, int y1, int x2, int y2,
                       int x3, int y3, uint32_t ch)
{
    int x, y, xmin, xmax, ymin, ymax;
    int xx1, xx2, xa, xb, sl21, sl31, sl32;

    /* Bubble-sort y1 <= y2 <= y3 */
    if (y1 > y2)
        return caca_fill_triangle(cv, x2, y2, x1, y1, x3, y3, ch);

    if (y2 > y3)
        return caca_fill_triangle(cv, x1, y1, x3, y3, x2, y2, ch);

    /* Compute slopes and promote precision */
    sl21 = (y2 == y1) ? 0 : (x2 - x1) * 0x10000 / (y2 - y1);
    sl31 = (y3 == y1) ? 0 : (x3 - x1) * 0x10000 / (y3 - y1);
    sl32 = (y3 == y2) ? 0 : (x3 - x2) * 0x10000 / (y3 - y2);

    x1 *= 0x10000;
    x2 *= 0x10000;
    x3 *= 0x10000;

    ymin = y1 < 0 ? 0 : y1;
    ymax = y3 + 1 < cv->height ? y3 + 1 : cv->height;

    if (ymin < y2)
    {
        xa = x1 + sl21 * (ymin - y1);
        xb = x1 + sl31 * (ymin - y1);
    }
    else if (ymin == y2)
    {
        xa = x2;
        xb = (y1 == y3) ? x3 : x1 + sl31 * (ymin - y1);
    }
    else                        /* (ymin > y2) */
    {
        xa = x3 + sl32 * (ymin - y3);
        xb = x3 + sl31 * (ymin - y3);
    }

    /* Rasterize our triangle */
    for (y = ymin; y < ymax; y++)
    {
        /* Rescale xa and xb, recentering the division */
        if (xa < xb)
        {
            xx1 = (xa + 0x800) / 0x10000;
            xx2 = (xb + 0x801) / 0x10000;
        }
        else
        {
            xx1 = (xb + 0x800) / 0x10000;
            xx2 = (xa + 0x801) / 0x10000;
        }

        xmin = xx1 < 0 ? 0 : xx1;
        xmax = xx2 + 1 < cv->width ? xx2 + 1 : cv->width;

        for (x = xmin; x < xmax; x++)
            caca_put_char(cv, x, y, ch);

        xa += y < y2 ? sl21 : sl32;
        xb += sl31;
    }

    return 0;
}

/* This function actually renders the triangle, but is not exported due to
   sam's pedantic will. */
static int caca_fill_triangle_textured_l(caca_canvas_t * cv,
                                         int x1, int y1,
                                         int x2, int y2,
                                         int x3, int y3,
                                         caca_canvas_t * tex,
                                         float u1, float v1,
                                         float u2, float v2,
                                         float u3, float v3)
{
    float y2y1, y3y1, y3y2;
    float sl12, sl13, sl23;
    float usl12, usl13, usl23, vsl12, vsl13, vsl23;
    float xa, xb, ua, va, ub, vb, u, v;
    uint32_t savedattr;
    int tw, th, x, y, s;

#define SWAP_F(a, b) {float c = a; a = b; b = c; }

    /* (very) Naive and (very) float-based affine and (very) non-clipped and
       (very) non-corrected triangle mapper Accepts arbitrary texture sizes
       Coordinates clamped to [0.0 - 1.0] (no repeat) */
    if (!cv || !tex)
        return -1;

    /* Bubble-sort y1 <= y2 <= y3 */
    if (y1 > y2)
        return caca_fill_triangle_textured_l(cv,
                                             x2, y2, x1, y1, x3, y3,
                                             tex, u2, v2, u1, v1, u3, v3);
    if (y2 > y3)
        return caca_fill_triangle_textured_l(cv,
                                             x1, y1, x3, y3, x2, y2,
                                             tex, u1, v1, u3, v3, u2, v2);

    savedattr = caca_get_attr(cv, -1, -1);

    /* Clip texture coordinates */
    if (u1 < 0.0f) u1 = 0.0f; else if (u1 > 1.0f) u1 = 1.0f;
    if (u2 < 0.0f) u2 = 0.0f; else if (u2 > 1.0f) u2 = 1.0f;
    if (u3 < 0.0f) u3 = 0.0f; else if (u3 > 1.0f) u3 = 1.0f;
    if (v1 < 0.0f) v1 = 0.0f; else if (v1 > 1.0f) v1 = 1.0f;
    if (v2 < 0.0f) v2 = 0.0f; else if (v2 > 1.0f) v2 = 1.0f;
    if (v3 < 0.0f) v3 = 0.0f; else if (v3 > 1.0f) v3 = 1.0f;

    /* Convert relative tex coordinates to absolute */
    tw = caca_get_canvas_width(tex);
    th = caca_get_canvas_height(tex);

    u1 *= (float)tw;
    u2 *= (float)tw;
    u3 *= (float)tw;
    v1 *= (float)th;
    v2 *= (float)th;
    v3 *= (float)th;

    y2y1 = (float)(y2 - y1);
    y3y1 = (float)(y3 - y1);
    y3y2 = (float)(y3 - y2);

    /* Compute slopes, making sure we don't divide by zero */
    /* (in this case, we don't need the value anyway) */
    /* FIXME : only compute needed slopes */
    sl12 = ((float)x2 - x1) / (y2y1 == 0 ? 1 : y2y1);
    sl13 = ((float)x3 - x1) / (y3y1 == 0 ? 1 : y3y1);
    sl23 = ((float)x3 - x2) / (y3y2 == 0 ? 1 : y3y2);

    usl12 = (u2 - u1) / (y2y1 == 0 ? 1 : y2y1);
    usl13 = (u3 - u1) / (y3y1 == 0 ? 1 : y3y1);
    usl23 = (u3 - u2) / (y3y2 == 0 ? 1 : y3y2);
    vsl12 = (v2 - v1) / (y2y1 == 0 ? 1 : y2y1);
    vsl13 = (v3 - v1) / (y3y1 == 0 ? 1 : y3y1);
    vsl23 = (v3 - v2) / (y3y2 == 0 ? 1 : y3y2);

    xa = (float)x1;
    xb = (float)x1;
    ua = u1; ub = u1;
    va = v1; vb = v1;

    s = 0;

    /* Top */
    for (y = y1; y < y2; y++)
    {
        float tus, tvs;

        if (xb < xa)
        {
            SWAP_F(xb, xa);
            SWAP_F(sl13, sl12);
            SWAP_F(ua, ub);
            SWAP_F(va, vb);
            SWAP_F(usl13, usl12);
            SWAP_F(vsl13, vsl12);
            s = 1;
        }

        tus = (ub - ua) / (xb - xa);
        tvs = (vb - va) / (xb - xa);
        v = va;
        u = ua;

        /* scanline */
        for (x = xa; x < xb; x++)
        {
            uint32_t attr, c;
            u += tus;
            v += tvs;
            /* FIXME: use caca_get_canvas_attrs / caca_get_canvas_chars */
            attr = caca_get_attr(tex, u, v);
            c = caca_get_char(tex, u, v);
            caca_set_attr(cv, attr);
            caca_put_char(cv, x, y, c);
        }

        xa += sl13;
        xb += sl12;

        ua += usl13;
        va += vsl13;
        ub += usl12;
        vb += vsl12;
    }

    if (s)
    {
        SWAP_F(xb, xa);
        SWAP_F(sl13, sl12);
        SWAP_F(ua, ub);
        SWAP_F(va, vb);
        SWAP_F(usl13, usl12);
        SWAP_F(vsl13, vsl12);
    }


    /* Bottom */
    xb = (float)x2;

    /* These variables are set by 'top' routine and are in an incorrect state
       if we only draw the bottom part */
    if (y1 == y2)
    {
        ua = u1;
        ub = u2;
        va = v1;
        vb = v2;
    }

    for (y = y2; y < y3; y++)
    {
        float tus, tvs;

        if (xb <= xa)
        {
            SWAP_F(xb, xa);
            SWAP_F(sl13, sl23);
            SWAP_F(ua, ub);
            SWAP_F(va, vb);
            SWAP_F(usl13, usl23);
            SWAP_F(vsl13, vsl23);
        }

        tus = (ub - ua) / ((float)xb - xa);
        tvs = (vb - va) / ((float)xb - xa);
        u = ua;
        v = va;

        /* scanline */
        for (x = xa; x < xb; x++)
        {
            uint32_t attr, c;
            u += tus;
            v += tvs;
            /* FIXME, can be heavily optimised */
            attr = caca_get_attr(tex, u, v);
            c = caca_get_char(tex, u, v);
            caca_set_attr(cv, attr);
            caca_put_char(cv, x, y, c);
        }

        xa += sl13;
        xb += sl23;

        ua += usl13;
        va += vsl13;
        ub += usl23;
        vb += vsl23;
    }

    caca_set_attr(cv, savedattr);

    return 0;
}

/** \brief Fill a triangle on the canvas using an arbitrary-sized texture.
 *
 *  This function fails if one or both the canvas are missing
 *
 *  \param cv     The handle to the libcaca canvas.
 *  \param coords The coordinates of the triangle (3{x,y})
 *  \param tex    The handle of the canvas texture.
 *  \param uv     The coordinates of the texture (3{u,v})
 *  \return This function return 0 if ok, -1 if canvas or texture are missing.
 */
int caca_fill_triangle_textured(caca_canvas_t * cv,
                                int coords[6],
                                caca_canvas_t * tex, float uv[6])
{
    return caca_fill_triangle_textured_l(cv,
                                         coords[0], coords[1],
                                         coords[2], coords[3],
                                         coords[4], coords[5],
                                         tex,
                                         uv[0], uv[1],
                                         uv[2], uv[3], uv[4], uv[5]);
}



================================================
FILE: config.h
================================================
#ifndef __CONFIG_H
#define __CONFIG_H

/* Warnings I don't care about */
#pragma warning(disable : 4001) // single-line comments
#pragma warning(disable : 4096) // varargs are always cdecl
#pragma warning(disable : 4127) // conditional expression constant
#pragma warning(disable : 4704) // in-line assembler
#pragma warning(disable : 4505) // unreferenced local function

// Warnings i don't mind unless i'm debugging.
#ifdef NDEBUG
# pragma warning(disable : 4100) // unreferenced formal parameter
# pragma warning(disable : 4101) // unreferenced local variable
#endif

// Dont create logfiles for release builds.
#ifdef RELEASE
# define DEBUG_LOGFILE NULL
#else
// You can also set "CON" to show messages on stdout.
# define DEBUG_LOGFILE "H:\\DEBUG.LOG"
#endif

// Unfortunately we can't use stdio in addins, because the crt uses malloc.
#define HAVE_SNPRINTF
#define PREFER_PORTABLE_SNPRINTF
#include "snprintf.h"

#define snprintf portable_snprintf
#define vsnprintf portable_vsnprintf

#define true 1
#define false 0

// In text mode, the screen resolution is queried via int 10,f:
// https://stanislavs.org/helppc/int_10-f.html
//
// The number of columns is returned in AL, so it cannot possibly
// exceed 256, because that's only an 8bit register.
#define MAX_COLS 256

// The selectors for the BIOS Data Area and CGA Framebuffer. We
// can't access these directly, we need to request 123 installs
// an LDT entry for us.
#define BIOS_DATA_AREA 0x0040
#define CGA_FRAMEBUF 0xb800

#endif


================================================
FILE: debug/Makefile
================================================
DFLAGS=-quiet -dumb
ASFLAGS=/m3 /q /z /w0
CPPFLAGS=/Iinclude
WARNLEVEL=4
CFLAGS=/AL /nologo /NDAAA /Od /G3 /Gs /Gc /Zi /FPi87 /Zp1 /Zl /Gf /f- /W$(WARNLEVEL) /WX
LDFLAGS=/b /nologo /onerror:noexe /nod /noe
LDLIBS=LLIBC7
EFLAGS=/verbose /nologo

.PHONY: clean

# MS-DOS doesn't allow long commandlines, so params are written to a "response"
# file.

%.obj: %.c
	@rm -f $@
	printf "$(CPPFLAGS) $(CFLAGS)\r\n" > $(@:.obj=.cl)
	dosemu $(DFLAGS) -E "IN G:/ CL /c @$(@:.obj=.cl) /Fo$@ $<"
	@rm -f $(@:.obj=.cl)

%.obj: %.asm
	@rm -f $@
	dosemu $(DFLAGS) -E "IN G:/ TASM32 /c $(ASFLAGS) $<"

all: l13vcgad.obj l13vcgaf.obj logcalls.obj logcbs.obj

clean:
	rm -f *.exe *.obj *.dld *.map *.pdb *.lnk *.cl
	chmod u=rw,go=r *.asm *.names *.idb


================================================
FILE: debug/exports.inc
================================================
GLOBAL GetDisplayInfo
GLOBAL DriverInit
GLOBAL DriverTerminate
GLOBAL ResetDisplay
GLOBAL SetGraphicsMode
GLOBAL MoveCursor
GLOBAL WriteLmbcsStringWithAttributes
GLOBAL WritePaddedLmbcsStringWithAttributes
GLOBAL SetRegionBgAttributes
GLOBAL ClearRegionForeground
GLOBAL ClearRegionForegroundKeepBg
GLOBAL BlockRegionCopy
GLOBAL CalcSizeTranslatedString
GLOBAL FitTranslatedString
GLOBAL SetCursorInvisible
GLOBAL SetCursorVisible
GLOBAL LockCursorAttributes
GLOBAL QQCalledBeforeGraphicsMode
GLOBAL QQLotusApiJustCallsFunc_1
GLOBAL MoveCursor2
GLOBAL QQLotusApiJustCallsFunc_0
GLOBAL ComplicatedNop
GLOBAL zerosub_0
GLOBAL LotusApiPassedPtr
GLOBAL LotusApiJustCallsFunc
GLOBAL nullsub_5
GLOBAL exprt_scan_linx
GLOBAL exprt_fill_rect
GLOBAL exprt_thin_diag_line
GLOBAL exprt_thin_vert_line
GLOBAL exprt_shade_rect
GLOBAL exprt_fill_scan_list


================================================
FILE: debug/l13vcgad.asm
================================================
; vim: set ft=tasm:

                version m520
                .model large,stdcall
                .486

DOSSEG
CODESEG

extern  _wrap_DriverInit: proc
extern  _wrap_GetDisplayInfo: proc
extern  _wrap_DriverTerminate: proc
extern  _wrap_ResetDisplay: proc
extern  _wrap_SetGraphicsMode: proc
extern  _wrap_MoveCursor: proc
extern  _wrap_WriteLmbcsStringWithAttributes: proc
extern  _wrap_WritePaddedLmbcsStringWithAttributes: proc
extern  _wrap_SetRegionBgAttributes: proc
extern  _wrap_ClearRegionForeground: proc
extern  _wrap_ClearRegionForegroundKeepBg: proc
extern  _wrap_BlockRegionCopy: proc
extern  _wrap_CalcSizeTranslatedString: proc
extern  _wrap_FitTranslatedString: proc
extern  _wrap_SetCursorInvisible: proc
extern  _wrap_SetCursorVisible: proc
extern  _wrap_LockCursorAttributes: proc
extern  _wrap_QQCalledBeforeGraphicsMode: proc
extern  _wrap_QQLotusApiJustCallsFunc_1: proc
extern  _wrap_MoveCursor2: proc
extern  _wrap_QQLotusApiJustCallsFunc_0: proc
extern  _wrap_ComplicatedNop: proc
extern  _wrap_zerosub_0: proc
extern  _wrap_LotusApiPassedPtr: proc
extern  _wrap_LotusApiJustCallsFunc: proc
extern  _wrap_nullsub_5: proc

start           dd _wrap_GetDisplayInfo
                dd _wrap_DriverInit
                dd _wrap_DriverTerminate
                dd _wrap_ResetDisplay
                dd _wrap_SetGraphicsMode
                dd _wrap_MoveCursor
                dd _wrap_WriteLmbcsStringWithAttributes
                dd _wrap_WritePaddedLmbcsStringWithAttributes
                dd _wrap_SetRegionBgAttributes
                dd _wrap_ClearRegionForeground
                dd _wrap_ClearRegionForegroundKeepBg
                dd _wrap_BlockRegionCopy
                dd _wrap_CalcSizeTranslatedString
                dd _wrap_FitTranslatedString
                dd _wrap_SetCursorInvisible
                dd _wrap_SetCursorVisible
                dd _wrap_LockCursorAttributes
                dd _wrap_QQCalledBeforeGraphicsMode
                dd _wrap_QQLotusApiJustCallsFunc_1
                dd _wrap_MoveCursor2
                dd _wrap_QQLotusApiJustCallsFunc_0
                dd _wrap_ComplicatedNop
                dd _wrap_zerosub_0
                dd _wrap_LotusApiPassedPtr
                dd _wrap_LotusApiJustCallsFunc
                dd _wrap_nullsub_5
                dw seg _DATA

; This is just here to satisfy the crt, it should never be called.
global _main: proc
_main proc far
        mov     ax, 4141h
        int     3
_main endp

; There is an object file that screws up my alignment in the CRT, and
; I don't even need it.
;
; If you define a symbol, and then use /NOE, the linkers uses this one,
; so this stops that nuisance object from being linked into my executable.
global __nullcheck: proc
__nullcheck proc far
        mov     ax, 4242h
        int     3
__nullcheck endp

end start


================================================
FILE: debug/logcalls.c
================================================
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <conio.h>
#include <dos.h>

#include "config.h"
#include "debug.h"
#include "idatypes.h"
#include "lottypes.h"
#include "lotcalls.h"

// This is a debugging shim that logs what a real driver is doing.
//
// The idea is that I can compare the logs with what my driver is doing, and
// check where they disagree.
//
// Because 123 uses callee clears calling convention, unfortunately I
// have to know the correct parameters, and can't just use a generic
// logger.

struct LOTUSFUNCS far *callbacks;

struct LOTUSFUNCS cbwrappers;

extern void InstallCallbackWrapper(struct LOTUSFUNCS *cbarray);

extern int __pascal GetDisplayInfo(struct DISPLAYINFO far *dspinfo);

int __pascal _wrap_GetDisplayInfo(struct DISPLAYINFO far *dspinfo)
{
    int result;
    traceent("GetDisplayInfo");
    traceptr(dspinfo);
    result = GetDisplayInfo(dspinfo);
    tracebuf(dspinfo, sizeof *dspinfo);
    return result;
}

extern int __pascal DriverInit(void *drvapi,
                               void *vbdptr,
                               char *cfgname,
                               char deflmbcsgrp);
static unsigned d;

int __pascal _wrap_DriverInit(void *drvapi,
                              void *vbdptr,
                              char *cfgname,
                              char deflmbcsgrp)
{
    int result;
    openlog("H:\\CORRECT.LOG");
    traceent("DriverInit");

    traceptr(drvapi);
    traceptr(vbdptr);
    tracestr(cfgname);
    tracechr(deflmbcsgrp);

    // Save a pointer to real callbacks.
    callbacks = drvapi;

    // Make a copy of these callbacks so that I can patch them and replace
    // with debugging wrappers.
    memcpy(&cbwrappers, callbacks, sizeof *callbacks);

    tracebuf(callbacks, sizeof *callbacks);

    Inst
Download .txt
gitextract_179s49fo/

├── .gitignore
├── Makefile
├── README.md
├── addin/
│   ├── Makefile
│   ├── lpl.cnf
│   └── modern.pl
├── attr.c
├── attr.h
├── bundle.c
├── bundle.h
├── cgadraw/
│   ├── COPYING
│   ├── Makefile
│   ├── README.md
│   ├── attr.c
│   ├── box.c
│   ├── caca.h
│   ├── cacaint.h
│   ├── cacastub.h
│   ├── cacatyp.h
│   ├── canvas.c
│   ├── cgadraw.c
│   ├── charset.c
│   ├── codec.h
│   ├── config.h
│   ├── conic.c
│   ├── drawtest.c
│   ├── frame.c
│   ├── line.c
│   ├── snprintf.c
│   ├── snprintf.h
│   ├── string.c
│   ├── transfrm.c
│   └── triangle.c
├── config.h
├── debug/
│   ├── CGAF25CC.VBD
│   ├── CGAF25CC.cmarkers
│   ├── CGAF25CC.names
│   ├── Makefile
│   ├── exports.inc
│   ├── l13vcgad.asm
│   ├── logcalls.c
│   └── logcbs.c
├── debug.c
├── debug.h
├── draw.c
├── draw.h
├── idatypes.h
├── l13vdemu.asm
├── l13vdemu.def
├── lmbcs.c
├── lmbcs.h
├── lotcalls.h
├── lotdemu.c
├── lottypes.h
├── raster.c
├── raster.h
├── snprintf.c
└── snprintf.h
Download .txt
SYMBOL INDEX (258 symbols across 30 files)

FILE: bundle.c
  function ParseConfig (line 16) | int ParseConfig(struct BDLHDR far *bdlptr)

FILE: bundle.h
  type BDLHDR (line 4) | struct BDLHDR

FILE: cgadraw/attr.c
  function caca_get_attr (line 66) | uint32_t caca_get_attr(caca_canvas_t const *cv, int x, int y)
  function caca_set_attr (line 97) | int caca_set_attr(caca_canvas_t *cv, uint32_t attr)
  function caca_unset_attr (line 127) | int caca_unset_attr(caca_canvas_t *cv, uint32_t attr)
  function caca_toggle_attr (line 154) | int caca_toggle_attr(caca_canvas_t *cv, uint32_t attr)
  function caca_put_attr (line 182) | int caca_put_attr(caca_canvas_t *cv, int x, int y, uint32_t attr)
  function caca_set_color_ansi (line 208) | int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
  function caca_set_color_argb (line 241) | int caca_set_color_argb(caca_canvas_t *cv, uint16_t fg, uint16_t bg)
  function caca_attr_to_ansi (line 277) | uint8_t caca_attr_to_ansi(uint32_t attr)
  function caca_attr_to_ansi_fg (line 301) | uint8_t caca_attr_to_ansi_fg(uint32_t attr)
  function caca_attr_to_ansi_bg (line 321) | uint8_t caca_attr_to_ansi_bg(uint32_t attr)
  function caca_attr_to_rgb12_fg (line 341) | uint16_t caca_attr_to_rgb12_fg(uint32_t attr)
  function caca_attr_to_rgb12_bg (line 372) | uint16_t caca_attr_to_rgb12_bg(uint32_t attr)
  function caca_attr_to_argb64 (line 407) | void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
  function nearest_ansi (line 445) | static uint8_t nearest_ansi(uint16_t argb14)
  function _caca_attr_to_rgb24fg (line 492) | uint32_t _caca_attr_to_rgb24fg(uint32_t attr)
  function _caca_attr_to_rgb24bg (line 497) | uint32_t _caca_attr_to_rgb24bg(uint32_t attr)

FILE: cgadraw/box.c
  function caca_draw_box (line 41) | int caca_draw_box(caca_canvas_t *cv, int x, int y, int w, int h, uint32_...
  function caca_draw_thin_box (line 65) | int caca_draw_thin_box(caca_canvas_t *cv, int x, int y, int w, int h)
  function caca_draw_cp437_box (line 86) | int caca_draw_cp437_box(caca_canvas_t *cv, int x, int y, int w, int h)
  function caca_fill_box (line 109) | int caca_fill_box(caca_canvas_t *cv, int x, int y, int w, int h,
  function draw_box (line 165) | static int draw_box(caca_canvas_t *cv, int x, int y, int w, int h,

FILE: cgadraw/caca.h
  type caca_canvas_t (line 49) | typedef struct caca_canvas caca_canvas_t;
  type caca_dither_t (line 51) | typedef struct caca_dither caca_dither_t;
  type caca_charfont_t (line 53) | typedef struct caca_charfont caca_charfont_t;
  type caca_font_t (line 55) | typedef struct caca_font caca_font_t;
  type caca_file_t (line 57) | typedef struct caca_file caca_file_t;
  type caca_display_t (line 59) | typedef struct caca_display caca_display_t;
  type caca_event_t (line 61) | typedef struct caca_event caca_event_t;
  type caca_color (line 69) | enum caca_color
  type caca_style (line 92) | enum caca_style
  type caca_event_type (line 107) | enum caca_event_type
  type caca_event (line 130) | struct caca_event
  type caca_option (line 149) | struct caca_option
  type caca_key (line 162) | enum caca_key
  type caca_option (line 547) | struct caca_option
  type CACA_CONIO_COLORS (line 555) | enum CACA_CONIO_COLORS
  type CACA_CONIO_CURSOR (line 581) | enum CACA_CONIO_CURSOR
  type CACA_CONIO_MODE (line 593) | enum CACA_CONIO_MODE
  type caca_conio_text_info (line 609) | struct caca_conio_text_info
  type caca_conio_text_info (line 650) | struct caca_conio_text_info

FILE: cgadraw/cacaint.h
  type caca_timer_t (line 20) | typedef struct caca_timer caca_timer_t;
  type caca_privevent_t (line 21) | typedef struct caca_privevent caca_privevent_t;
  type cgachar (line 29) | struct cgachar
  type caca_frame (line 35) | struct caca_frame
  type caca_canvas (line 54) | struct caca_canvas
  type caca_driver (line 89) | enum caca_driver
  type caca_timer (line 148) | struct caca_timer
  type caca_stat (line 154) | struct caca_stat
  type caca_privevent (line 162) | struct caca_privevent
  type caca_display (line 175) | struct caca_display
  type caca_stat (line 271) | struct caca_stat
  type caca_stat (line 272) | struct caca_stat

FILE: cgadraw/cacastub.h
  function seterrno (line 24) | static inline void seterrno(int e) { errno = e; }
  function geterrno (line 25) | static inline int geterrno(void) { return errno; }

FILE: cgadraw/cacatyp.h
  type _caca_int8_t (line 20) | typedef signed char _caca_int8_t;
  type _caca_int16_t (line 21) | typedef signed short _caca_int16_t;
  type _caca_int32_t (line 22) | typedef signed long int _caca_int32_t;
  type _caca_uint8_t (line 29) | typedef unsigned char _caca_uint8_t;
  type _caca_uint16_t (line 30) | typedef unsigned short _caca_uint16_t;
  type _caca_uint32_t (line 31) | typedef unsigned long int _caca_uint32_t;
  type _caca_intptr_t (line 38) | typedef long int _caca_intptr_t;
  type _caca_uintptr_t (line 39) | typedef unsigned long int _caca_uintptr_t;
  type _caca_ssize_t (line 44) | typedef int _caca_ssize_t;
  type _caca_size_t (line 45) | typedef unsigned int _caca_size_t;

FILE: cgadraw/canvas.c
  type caca_frame (line 30) | struct caca_frame
  function caca_manage_canvas (line 67) | int caca_manage_canvas(caca_canvas_t *cv, int (*callback)(void *), void *p)
  function caca_unmanage_canvas (line 72) | int caca_unmanage_canvas(caca_canvas_t *cv, int (*callback)(void *), voi...
  function caca_set_canvas_size (line 77) | int caca_set_canvas_size(caca_canvas_t *cv, int width, int height)
  function caca_get_canvas_width (line 82) | int caca_get_canvas_width(caca_canvas_t const *cv)
  function caca_get_canvas_height (line 87) | int caca_get_canvas_height(caca_canvas_t const *cv)
  function caca_free_canvas (line 102) | int caca_free_canvas(caca_canvas_t *cv)
  function caca_rand (line 108) | int caca_rand(int min, int max)
  function caca_resize (line 113) | int caca_resize(caca_canvas_t *cv, int width, int height)

FILE: cgadraw/charset.c
  function caca_utf8_to_utf32 (line 112) | uint32_t caca_utf8_to_utf32(char const *s, size_t *bytes)
  function caca_utf32_to_utf8 (line 151) | size_t caca_utf32_to_utf8(char *buf, uint32_t ch)
  function caca_utf32_to_cp437 (line 191) | uint8_t caca_utf32_to_cp437(uint32_t ch)
  function caca_cp437_to_utf32 (line 223) | uint32_t caca_cp437_to_utf32(uint8_t ch)
  function caca_utf32_to_ascii (line 249) | char caca_utf32_to_ascii(uint32_t ch)
  function caca_utf32_is_fullwidth (line 388) | int caca_utf32_is_fullwidth(uint32_t ch)

FILE: cgadraw/conic.c
  function caca_draw_circle (line 40) | int caca_draw_circle(caca_canvas_t *cv, int x, int y, int r, uint32_t ch)
  function caca_fill_ellipse (line 68) | int caca_fill_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b,
  function caca_draw_ellipse (line 128) | int caca_draw_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b,
  function caca_draw_thin_ellipse (line 184) | int caca_draw_thin_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b)
  function ellipsepoints (line 235) | static void ellipsepoints(caca_canvas_t *cv, int xo, int yo, int x, int y,

FILE: cgadraw/drawtest.c
  function main (line 11) | int __cdecl main(int argc, char *argv[])

FILE: cgadraw/frame.c
  function caca_get_frame_count (line 5) | int caca_get_frame_count(caca_canvas_t const *cv)
  function caca_set_frame (line 10) | int caca_set_frame(caca_canvas_t *cv, int id)
  function caca_set_frame_name (line 29) | int caca_set_frame_name(caca_canvas_t *cv, char const *name)
  function caca_create_frame (line 34) | int caca_create_frame(caca_canvas_t *cv, int id)
  function caca_free_frame (line 39) | int caca_free_frame(caca_canvas_t *cv, int id)
  function _caca_save_frame_info (line 58) | void _caca_save_frame_info(caca_canvas_t *cv)
  function _caca_load_frame_info (line 65) | void _caca_load_frame_info(caca_canvas_t *cv)

FILE: cgadraw/line.c
  type line (line 29) | struct line
  type line (line 38) | struct line
  type line (line 40) | struct line
  type line (line 41) | struct line
  function caca_draw_line (line 55) | int caca_draw_line(caca_canvas_t *cv, int x1, int y1, int x2, int y2,
  function caca_draw_polyline (line 86) | int caca_draw_polyline(caca_canvas_t *cv, int const x[], int const y[],
  function caca_draw_thin_line (line 117) | int caca_draw_thin_line(caca_canvas_t *cv, int x1, int y1, int x2, int y2)
  function caca_draw_thin_polyline (line 145) | int caca_draw_thin_polyline(caca_canvas_t *cv, int const x[], int const ...
  function clip_line (line 169) | static void clip_line(caca_canvas_t *cv, struct line* s)
  function clip_bits (line 221) | static uint8_t clip_bits(caca_canvas_t *cv, int x, int y)
  function draw_solid_line (line 240) | static void draw_solid_line(caca_canvas_t *cv, struct line* s)
  function draw_thin_line (line 302) | static void draw_thin_line(caca_canvas_t *cv, struct line* s)

FILE: cgadraw/snprintf.c
  function asprintf (line 420) | int asprintf(char **ptr, const char *fmt, /*args*/ ...) {
  function vasprintf (line 444) | int vasprintf(char **ptr, const char *fmt, va_list ap) {
  function asnprintf (line 466) | int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
  function vasnprintf (line 494) | int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
  function portable_snprintf (line 526) | int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/...

FILE: cgadraw/string.c
  function caca_gotoxy (line 10) | int caca_gotoxy(caca_canvas_t *cv, int x, int y)
  function caca_wherex (line 18) | int caca_wherex(caca_canvas_t const *cv)
  function caca_wherey (line 23) | int caca_wherey(caca_canvas_t const *cv)
  function caca_put_char (line 28) | int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch)
  function caca_get_char (line 35) | uint32_t caca_get_char(caca_canvas_t const *cv, int x, int y)
  function caca_put_str (line 43) | int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s)
  function caca_printf (line 58) | int caca_printf(caca_canvas_t *cv, int x, int y, char const *format, ...)
  function caca_vprintf (line 68) | int caca_vprintf(caca_canvas_t *cv, int x, int y, char const *format,
  function caca_clear_canvas (line 88) | int caca_clear_canvas(caca_canvas_t *cv)
  function caca_set_canvas_handle (line 102) | int caca_set_canvas_handle(caca_canvas_t *cv, int x, int y)
  function caca_get_canvas_handle_x (line 110) | int caca_get_canvas_handle_x(caca_canvas_t const *cv)
  function caca_get_canvas_handle_y (line 115) | int caca_get_canvas_handle_y(caca_canvas_t const *cv)
  function caca_blit (line 120) | int caca_blit(caca_canvas_t *dst, int x, int y,
  function caca_set_canvas_boundaries (line 126) | int caca_set_canvas_boundaries(caca_canvas_t *cv, int x, int y, int w, i...

FILE: cgadraw/transfrm.c
  function caca_invert (line 29) | int caca_invert(caca_canvas_t *cv)
  function caca_flip (line 34) | int caca_flip(caca_canvas_t *cv)
  function caca_flop (line 39) | int caca_flop(caca_canvas_t *cv)
  function caca_rotate_180 (line 44) | int caca_rotate_180(caca_canvas_t *cv)
  function caca_rotate_left (line 49) | int caca_rotate_left(caca_canvas_t *cv)
  function caca_rotate_right (line 54) | int caca_rotate_right(caca_canvas_t *cv)
  function caca_stretch_left (line 59) | int caca_stretch_left(caca_canvas_t *cv)
  function caca_stretch_right (line 64) | int caca_stretch_right(caca_canvas_t *cv)
  function flipchar (line 71) | static uint32_t flipchar(uint32_t ch)
  function flopchar (line 187) | static uint32_t flopchar(uint32_t ch)
  function rotatechar (line 303) | static uint32_t rotatechar(uint32_t ch)
  function leftchar (line 506) | static uint32_t leftchar(uint32_t ch)
  function rightchar (line 521) | static uint32_t rightchar(uint32_t ch)
  function leftpair (line 598) | static void leftpair(uint32_t pair[2])
  function rightpair (line 619) | static void rightpair(uint32_t pair[2])

FILE: cgadraw/triangle.c
  function caca_draw_triangle (line 40) | int caca_draw_triangle(caca_canvas_t * cv, int x1, int y1, int x2, int y2,
  function caca_draw_thin_triangle (line 63) | int caca_draw_thin_triangle(caca_canvas_t * cv, int x1, int y1,
  function caca_fill_triangle (line 87) | int caca_fill_triangle(caca_canvas_t * cv, int x1, int y1, int x2, int y2,
  function caca_fill_triangle_textured_l (line 158) | static int caca_fill_triangle_textured_l(caca_canvas_t * cv,
  function caca_fill_triangle_textured (line 361) | int caca_fill_triangle_textured(caca_canvas_t * cv,

FILE: debug.c
  function openlog (line 15) | int openlog(const char *name)
  function closelog (line 33) | int closelog(void)
  function logstr (line 48) | int logstr(const char *fmt, ...)
  function logmsg (line 70) | int logmsg(const char *fmt, ...)
  function loghex (line 92) | void loghex(const void far *ptr, int buflen) {

FILE: debug/logcalls.c
  type LOTUSFUNCS (line 24) | struct LOTUSFUNCS
  type LOTUSFUNCS (line 26) | struct LOTUSFUNCS
  type LOTUSFUNCS (line 28) | struct LOTUSFUNCS
  type DISPLAYINFO (line 30) | struct DISPLAYINFO
  function _wrap_GetDisplayInfo (line 32) | int __pascal _wrap_GetDisplayInfo(struct DISPLAYINFO far *dspinfo)
  function _wrap_DriverInit (line 48) | int __pascal _wrap_DriverInit(void *drvapi,
  function _wrap_DriverTerminate (line 83) | int __pascal _wrap_DriverTerminate()
  function _wrap_ResetDisplay (line 96) | int __pascal _wrap_ResetDisplay()
  function _wrap_SetGraphicsMode (line 103) | int __pascal _wrap_SetGraphicsMode()
  function _wrap_MoveCursor (line 109) | void __pascal _wrap_MoveCursor(int col, int line)
  function _wrap_WriteLmbcsStringWithAttributes (line 121) | int __pascal _wrap_WriteLmbcsStringWithAttributes(int byteslen,
  function _wrap_WritePaddedLmbcsStringWithAttributes (line 140) | int __pascal _wrap_WritePaddedLmbcsStringWithAttributes(int byteslen,
  function _wrap_SetRegionBgAttributes (line 159) | int __pascal _wrap_SetRegionBgAttributes(int cols, int lines, char attrs)
  function _wrap_ClearRegionForeground (line 168) | void __pascal _wrap_ClearRegionForeground(int cols, int lines, char attrs)
  function _wrap_ClearRegionForegroundKeepBg (line 179) | int __pascal _wrap_ClearRegionForegroundKeepBg(int cols, int lines)
  function _wrap_BlockRegionCopy (line 188) | int __pascal _wrap_BlockRegionCopy()
  function _wrap_CalcSizeTranslatedString (line 196) | int __pascal _wrap_CalcSizeTranslatedString(int argstrlen, char far *arg...
  function _wrap_FitTranslatedString (line 211) | int __pascal _wrap_FitTranslatedString(int strarglen,
  function _wrap_SetCursorInvisible (line 232) | int __pascal _wrap_SetCursorInvisible()
  function _wrap_SetCursorVisible (line 239) | int __pascal _wrap_SetCursorVisible()
  function _wrap_LockCursorAttributes (line 246) | int __pascal _wrap_LockCursorAttributes()
  function _wrap_QQCalledBeforeGraphicsMode (line 253) | int __pascal _wrap_QQCalledBeforeGraphicsMode(void far *p)
  function _wrap_QQLotusApiJustCallsFunc_1 (line 263) | int __pascal _wrap_QQLotusApiJustCallsFunc_1(int strarglen, void far *st...
  function _wrap_MoveCursor2 (line 275) | int __pascal _wrap_MoveCursor2(int col, int line)
  function _wrap_QQLotusApiJustCallsFunc_0 (line 287) | int __pascal _wrap_QQLotusApiJustCallsFunc_0(void far *ptr)
  function _wrap_ComplicatedNop (line 300) | int __pascal _wrap_ComplicatedNop()
  function _wrap_zerosub_0 (line 308) | int __pascal _wrap_zerosub_0()
  function _wrap_LotusApiPassedPtr (line 316) | int __pascal _wrap_LotusApiPassedPtr(void far *ptr)
  function _wrap_LotusApiJustCallsFunc (line 324) | int __pascal _wrap_LotusApiJustCallsFunc(int a, void far *ptra, int d, v...
  function _wrap_nullsub_5 (line 340) | int __pascal _wrap_nullsub_5()

FILE: debug/logcbs.c
  function _wrap_lfield_8 (line 39) | static void __pascal _wrap_lfield_8(void far *ptr, int size)
  function _wrap_Free (line 62) | static int __pascal _wrap_Free(void *addr, int unknown, int size)
  function _wrap_UnregisterDevdata (line 97) | static void __pascal _wrap_UnregisterDevdata(int hdl)
  function _wrap_GetDescriptor (line 105) | static unsigned __pascal _wrap_GetDescriptor(unsigned far *ptr, int base...
  function _wrap_FreeDescriptor (line 119) | static void __pascal _wrap_FreeDescriptor(int seg)
  function _wrap_exprt_scan_linx (line 127) | static void __pascal _wrap_exprt_scan_linx(int a, int b, int c, int d)
  function _wrap_exprt_fill_rect (line 138) | static void __pascal _wrap_exprt_fill_rect(int a, int b, int c, int d, i...
  function _wrap_exprt_thin_diag_line (line 150) | static void __pascal _wrap_exprt_thin_diag_line(int a, int b, int c, int...
  function _wrap_exprt_thin_vert_line (line 162) | static void __pascal _wrap_exprt_thin_vert_line(int a, int b, int c, int d)
  function _wrap_exprt_shade_rect (line 173) | static void __pascal _wrap_exprt_shade_rect(int a, int b, int c, int d, ...
  function _wrap_exprt_fill_scan_list (line 186) | static void __pascal _wrap_exprt_fill_scan_list()
  function _wrap_RegisterDevdataStruct (line 193) | static int __pascal _wrap_RegisterDevdataStruct(struct DEVDATA far *a, i...
  function _wrap_field_64 (line 244) | static int __pascal _wrap_field_64(int a, void far *ptr)
  function _wrap_field_58 (line 259) | static void __pascal _wrap_field_58(int a, int b)
  function _wrap_field_5C (line 268) | static int __pascal _wrap_field_5C(int a, void far *b)
  function _wrap_field_68 (line 279) | static int __pascal _wrap_field_68(int a, int b, void far *ptr1, void fa...
  function _wrap_field_6C (line 293) | static int __pascal _wrap_field_6C(int a,
  function InstallCallbackWrapper (line 313) | void InstallCallbackWrapper(struct LOTUSFUNCS *cbarray)

FILE: draw.c
  function exprt_scan_linx (line 24) | void __pascal exprt_scan_linx(int x, int y, int width, int attr)
  function exprt_fill_rect (line 36) | void __pascal exprt_fill_rect(int x, int y, int width, int height, int a...
  function exprt_thin_diag_line (line 50) | void __pascal exprt_thin_diag_line(int x1, int y1, int x2, int y2, int a...
  function exprt_thin_vert_line (line 63) | void __pascal exprt_thin_vert_line(int x, int y, int height, int attr)
  function exprt_shade_rect (line 75) | void __pascal exprt_shade_rect(int a, int b, int c, int d, void far *e, ...
  function exprt_fill_scan_list (line 87) | void __pascal exprt_fill_scan_list()

FILE: idatypes.h
  type __int32 (line 5) | typedef long __int32;

FILE: lmbcs.c
  function translate_lmbcs (line 93) | int translate_lmbcs(const void *src,

FILE: lotcalls.h
  type LOTUSFUNCS (line 7) | struct LOTUSFUNCS
  type LOTUSFUNCS (line 69) | struct LOTUSFUNCS

FILE: lotdemu.c
  type DISPLAYINFO (line 65) | struct DISPLAYINFO
  type FONTINFO (line 79) | struct FONTINFO
  type DEVDATA (line 106) | struct DEVDATA
  type LOTUSFUNCS (line 157) | struct LOTUSFUNCS
  function drv_disp_info (line 162) | void __pascal drv_disp_info(struct DISPLAYINFO far *dspinfo)
  function start_lotus_rasterizer (line 175) | static int start_lotus_rasterizer()
  function drv_disp_open (line 205) | int __pascal drv_disp_open(void far *drvapi,
  function drv_disp_close (line 308) | int __pascal drv_disp_close()
  function drv_disp_text (line 341) | int __pascal drv_disp_text()
  function drv_disp_graph (line 349) | int __pascal drv_disp_graph()
  function drv_disp_set_pos (line 355) | void __pascal drv_disp_set_pos(int col, int line)
  function WriteStringToFramebuffer (line 381) | static int WriteStringToFramebuffer(unsigned char far *str,
  function drv_disp_write (line 453) | int __pascal drv_disp_write(unsigned byteslen,
  function drv_disp_zone (line 474) | int __pascal drv_disp_zone(unsigned byteslen,
  function drv_disp_set_bg (line 517) | void __pascal drv_disp_set_bg(unsigned cols, unsigned lines, char attrs)
  function drv_disp_clear (line 545) | void __pascal drv_disp_clear(unsigned cols,
  function drv_disp_fg_clear (line 575) | void __pascal drv_disp_fg_clear(unsigned cols, unsigned lines)
  function DrawSquare (line 603) | static void DrawSquare(int topx, int topy, int bottomx, int bottomy, cha...
  function drv_disp_copy (line 637) | void __pascal drv_disp_copy(int width, int height, int dstx, int dsty)
  function drv_disp_size (line 694) | int __pascal drv_disp_size(int argstrlen, char far *argstr)
  function drv_disp_fit (line 707) | int __pascal drv_disp_fit(int strarglen,
  function drv_disp_curs_type (line 771) | void __pascal drv_disp_curs_type(int unused, int cursmodenum)
  function drv_disp_grph_process (line 788) | int __pascal drv_disp_grph_process(struct GRAPH far *graph)
  function drv_disp_grph_txt_size (line 848) | int __pascal drv_disp_grph_txt_size(int strarglen, void far *strarg)
  function drv_disp_set_pos_hpu (line 865) | void __pascal drv_disp_set_pos_hpu(int col, int line)
  function drv_disp_grph_compute_view (line 872) | int __pascal drv_disp_grph_compute_view(void far *ptr)
  function drv_disp_unlock (line 886) | int __pascal drv_disp_unlock()
  function drv_disp_lock (line 892) | int __pascal drv_disp_lock()
  function drv_disp_grph_set_cur_view (line 898) | int __pascal drv_disp_grph_set_cur_view(void far *view)
  function drv_disp_grph_txt_fit (line 906) | int __pascal drv_disp_grph_txt_fit(int len, char far *str, int maxlen, i...
  function drv_disp_sync (line 938) | int __pascal drv_disp_sync(int a, int b)

FILE: lottypes.h
  type DISPLAYINFO (line 8) | struct DISPLAYINFO
  type BDLHDR (line 23) | struct BDLHDR
  type BDLRECHDR (line 31) | struct BDLRECHDR
  type DEVPRIM (line 37) | struct DEVPRIM
  type DEVPRIM (line 47) | typedef struct DEVPRIM DEVPRIM;
  type POINT (line 49) | struct POINT
  type POINT (line 55) | typedef struct POINT POINT;
  type PATT (line 57) | struct PATT
  type PATT (line 65) | typedef struct PATT PATT;
  type DEVDATA (line 67) | struct DEVDATA
  type GRAPH (line 90) | struct GRAPH
  type FONTINFO (line 110) | struct FONTINFO

FILE: raster.c
  function decode_raster_ops (line 62) | int decode_raster_ops(char far *startaddr, char far *endaddr)

FILE: raster.h
  type DRAWTEXT (line 42) | struct DRAWTEXT {

FILE: snprintf.c
  function asprintf (line 420) | int asprintf(char **ptr, const char *fmt, /*args*/ ...) {
  function vasprintf (line 444) | int vasprintf(char **ptr, const char *fmt, va_list ap) {
  function asnprintf (line 466) | int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
  function vasnprintf (line 494) | int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
  function portable_snprintf (line 526) | int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/...
Condensed preview — 58 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (321K chars).
[
  {
    "path": ".gitignore",
    "chars": 234,
    "preview": "*.obj\n.*.sw?\n*.pdb\n*.tlb\n*.res\n*.exe\n*.manifest\n*.exp\n*.ilk\n*.lib\n*.udb\n*.msi\n*.wixobj\n*.wixpdb\n*.dll\n*.o\n*.core\n*.map\n*"
  },
  {
    "path": "Makefile",
    "chars": 2026,
    "preview": "DFLAGS=-quiet -dumb\nASFLAGS=/m3 /q /z /w0\n#CPPFLAGS=/Icgadraw /I. /DNDEBUG\nCPPFLAGS=/Icgadraw /I.\nWARNLEVEL=4\nCFLAGS=/AL"
  },
  {
    "path": "README.md",
    "chars": 5761,
    "preview": "# Lotus 1-2-3 R4D Display Driver for DOSEMU2\n\nThis is a work-in-progress display driver for Lotus 1-2-3 R4D to enable su"
  },
  {
    "path": "addin/Makefile",
    "chars": 41,
    "preview": "addins: modern.plc\n\ninclude ../Makefile\n\n"
  },
  {
    "path": "addin/lpl.cnf",
    "chars": 36,
    "preview": "-U C:\\123DADK\\INCLUDE\n-U C:\\123R4D\\\n"
  },
  {
    "path": "addin/modern.pl",
    "chars": 2167,
    "preview": "-- vim: set ft=rexx:\n--\n-- This is an attempt to implement some modern @FUNCTIONS in 1-2-3 DOS.\n--\n-- Tavis Ormandy <tav"
  },
  {
    "path": "attr.c",
    "chars": 1524,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n#include <fcntl.h>\n#"
  },
  {
    "path": "attr.h",
    "chars": 713,
    "preview": "#ifndef __ATTR_H\n#define __ATTR_H\n\n// The octal usage here is intentional, doesn't it make the numbers look nice?\n\nexter"
  },
  {
    "path": "bundle.c",
    "chars": 588,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <fcntl.h>\n#include <conio.h>\n#i"
  },
  {
    "path": "bundle.h",
    "chars": 91,
    "preview": "#ifndef __BUNDLE_H\n#define __BUNDLE_H\n\nint ParseConfig(struct BDLHDR far *bdlptr);\n\n#endif\n"
  },
  {
    "path": "cgadraw/COPYING",
    "chars": 562,
    "preview": "\nThe files in this directory are derived from libcaca, which is published under\nthe license below.\n\n        DO WHAT THE "
  },
  {
    "path": "cgadraw/Makefile",
    "chars": 1060,
    "preview": "DFLAGS=-quiet -dumb\nWARNLEVEL=0\nCPPFLAGS=/I.\nCFLAGS=/AL /nologo /NDAAB /Od /G3 /Gs /Gc /Zi /FPi87 /Zp1 /Zl /Gf /f- /W$(W"
  },
  {
    "path": "cgadraw/README.md",
    "chars": 548,
    "preview": "# cgadraw\n\nThis is a stripped down version of libcaca 0.99 used for adding drawing\nprimitives to the CGA framebuffer.\n\nY"
  },
  {
    "path": "cgadraw/attr.c",
    "chars": 16280,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              All "
  },
  {
    "path": "cgadraw/box.c",
    "chars": 5516,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              All "
  },
  {
    "path": "cgadraw/caca.h",
    "chars": 28953,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              All "
  },
  {
    "path": "cgadraw/cacaint.h",
    "chars": 6443,
    "preview": "/*\n *  libcaca       Colour ASCII-Art library\n *  Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>\n *              "
  },
  {
    "path": "cgadraw/cacastub.h",
    "chars": 2092,
    "preview": "/*\n *  libcaca       Colour ASCII-Art library\n *  Copyright (c) 2006-2012 Sam Hocevar <sam@hocevar.net>\n *              "
  },
  {
    "path": "cgadraw/cacatyp.h",
    "chars": 1504,
    "preview": "/*\n *  libcaca       Colour ASCII-Art library\n *  Copyright (c) 2008-2012 Sam Hocevar <sam@hocevar.net>\n *              "
  },
  {
    "path": "cgadraw/canvas.c",
    "chars": 2543,
    "preview": "//\n// This file is derived from libcaca, but modified to add simple drawing\n// primitives to a CGA framebuffer for Lotus"
  },
  {
    "path": "cgadraw/cgadraw.c",
    "chars": 122,
    "preview": "#include \"config.h\"\n#include \"caca.h\"\n#include \"cacaint.h\"\n\nchar const * caca_get_version(void)\n{\n    return \"cgadraw\";\n"
  },
  {
    "path": "cgadraw/charset.c",
    "chars": 12154,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              2007"
  },
  {
    "path": "cgadraw/codec.h",
    "chars": 938,
    "preview": "/*\n *  libcaca       Colour ASCII-Art library\n *  Copyright (c) 2002-2014 Sam Hocevar <sam@hocevar.net>\n *              "
  },
  {
    "path": "cgadraw/config.h",
    "chars": 246,
    "preview": "#define inline\n#define EOVERFLOW E2BIG\n#define ENOSYS EINVAL\n#define HAVE_VSNPRINTF 1\n\n#define __KERNEL__\n\n#include <std"
  },
  {
    "path": "cgadraw/conic.c",
    "chars": 7935,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              All "
  },
  {
    "path": "cgadraw/drawtest.c",
    "chars": 421,
    "preview": "#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <dos.h>\n#include <conio.h>\n#incl"
  },
  {
    "path": "cgadraw/frame.c",
    "chars": 1281,
    "preview": "#include \"config.h\"\n#include \"caca.h\"\n#include \"cacaint.h\"\n\nint caca_get_frame_count(caca_canvas_t const *cv)\n{\n    retu"
  },
  {
    "path": "cgadraw/line.c",
    "chars": 9374,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              All "
  },
  {
    "path": "cgadraw/snprintf.c",
    "chars": 42429,
    "preview": "/*\n * snprintf.c - a portable implementation of snprintf\n *\n * AUTHOR\n *   Mark Martinec <mark.martinec@ijs.si>, April 1"
  },
  {
    "path": "cgadraw/snprintf.h",
    "chars": 313,
    "preview": "#ifndef _PORTABLE_SNPRINTF_H_\n#define _PORTABLE_SNPRINTF_H_\n\nextern int portable_snprintf(char *str, size_t str_m, const"
  },
  {
    "path": "cgadraw/string.c",
    "chars": 2582,
    "preview": "#include <stddef.h>\n#include <string.h>\n#include <stdarg.h>\n#include \"config.h\"\n#include \"snprintf.h\"\n\n#include \"caca.h\""
  },
  {
    "path": "cgadraw/transfrm.c",
    "chars": 20148,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              All "
  },
  {
    "path": "cgadraw/triangle.c",
    "chars": 10983,
    "preview": "/*\n *  libcaca     Colour ASCII-Art library\n *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>\n *              All "
  },
  {
    "path": "config.h",
    "chars": 1498,
    "preview": "#ifndef __CONFIG_H\n#define __CONFIG_H\n\n/* Warnings I don't care about */\n#pragma warning(disable : 4001) // single-line "
  },
  {
    "path": "debug/Makefile",
    "chars": 733,
    "preview": "DFLAGS=-quiet -dumb\nASFLAGS=/m3 /q /z /w0\nCPPFLAGS=/Iinclude\nWARNLEVEL=4\nCFLAGS=/AL /nologo /NDAAA /Od /G3 /Gs /Gc /Zi /"
  },
  {
    "path": "debug/exports.inc",
    "chars": 842,
    "preview": "GLOBAL GetDisplayInfo\nGLOBAL DriverInit\nGLOBAL DriverTerminate\nGLOBAL ResetDisplay\nGLOBAL SetGraphicsMode\nGLOBAL MoveCur"
  },
  {
    "path": "debug/l13vcgad.asm",
    "chars": 2856,
    "preview": "; vim: set ft=tasm:\n\n                version m520\n                .model large,stdcall\n                .486\n\nDOSSEG\nCODE"
  },
  {
    "path": "debug/logcalls.c",
    "chars": 9421,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <fcntl.h>\n#include <conio.h>\n#i"
  },
  {
    "path": "debug/logcbs.c",
    "chars": 8329,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <fcntl.h>\n#include <conio.h>\n#i"
  },
  {
    "path": "debug.c",
    "chars": 2176,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <fcntl.h>\n#i"
  },
  {
    "path": "debug.h",
    "chars": 2608,
    "preview": "#ifndef __DEBUG_H\n#define __DEBUG_H\n\n// We have to do a lot of printf debugging, so a few macros to help.\n#ifndef NDEBUG"
  },
  {
    "path": "draw.c",
    "chars": 1978,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n#include <fcntl.h>\n#"
  },
  {
    "path": "draw.h",
    "chars": 490,
    "preview": "#ifndef __DRAW_H\n#define __DRAW_H\n\nextern void __pascal exprt_scan_linx(int a, int b, int c, int d);\nextern void __pasca"
  },
  {
    "path": "idatypes.h",
    "chars": 143,
    "preview": "#ifndef __IDATYPES_H\n#define __IDATYPES_H\n\n// Compatability with IDA generated code.\ntypedef long __int32;\ntypedef unsig"
  },
  {
    "path": "l13vdemu.asm",
    "chars": 2353,
    "preview": "; vim: set ft=tasm:\nversion m520\n.model large,stdcall\n.486\n\nDOSSEG\nCODESEG\n\nextern drv_disp_info: proc\nextern drv_disp_o"
  },
  {
    "path": "l13vdemu.def",
    "chars": 772,
    "preview": "LIBRARY     L13VDEMU\nDESCRIPTION 'DOSEMU2 DISPLAY DRIVER FOR LOTUS 123R4D'\nHEAPSIZE    0\nSTACKSIZE   0\nDATA MULTIPLE\nEXP"
  },
  {
    "path": "lmbcs.c",
    "chars": 5000,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <fcntl.h>\n#i"
  },
  {
    "path": "lmbcs.h",
    "chars": 221,
    "preview": "#ifndef __LMBCS_H\n#define __LMBCS_H\n\nint translate_lmbcs(const void *src,\n                    unsigned char *dst,\n      "
  },
  {
    "path": "lotcalls.h",
    "chars": 2651,
    "preview": "#ifndef __LOTCALLS_H\n#define __LOTCALLS_H\n\n#pragma pack(1)\n#define __lotapi __pascal __far\n\nstruct LOTUSFUNCS\n{\n    int "
  },
  {
    "path": "lotdemu.c",
    "chars": 26509,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n#include <fcntl.h>\n#"
  },
  {
    "path": "lottypes.h",
    "chars": 2113,
    "preview": "#ifndef __LOTTYPES_H\n#define __LOTTYPES_H\n\n#pragma pack(1)\n\n#include \"idatypes.h\"\n\nstruct DISPLAYINFO\n{\n  int num_text_c"
  },
  {
    "path": "raster.c",
    "chars": 2929,
    "preview": "#include <stddef.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n#include <fcntl.h>\n#"
  },
  {
    "path": "raster.h",
    "chars": 1248,
    "preview": "#ifndef __RASTER_H\n#define __RASTER_H\n\nint decode_raster_ops(char far *startaddr, char far *endaddr);\n\n// I think these "
  },
  {
    "path": "snprintf.c",
    "chars": 42429,
    "preview": "/*\n * snprintf.c - a portable implementation of snprintf\n *\n * AUTHOR\n *   Mark Martinec <mark.martinec@ijs.si>, April 1"
  },
  {
    "path": "snprintf.h",
    "chars": 938,
    "preview": "#ifndef _PORTABLE_SNPRINTF_H_\n#define _PORTABLE_SNPRINTF_H_\n\n#define PORTABLE_SNPRINTF_VERSION_MAJOR 2\n#define PORTABLE_"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the taviso/lotusdrv GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 58 files (298.7 KB), approximately 94.3k tokens, and a symbol index with 258 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!