Add hl-vt100@e598aeeccac6e28afefa8b5213d35c8e8cfb7d97
This commit is contained in:
parent
0be64ddac3
commit
952a236b32
20 changed files with 2678 additions and 0 deletions
6
hl-vt100/.gitignore
vendored
Normal file
6
hl-vt100/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
*.o
|
||||
*.so
|
||||
parser
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.envrc
|
||||
24
hl-vt100/LICENSE
Normal file
24
hl-vt100/LICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
vt100-emulator is distributed under the following terms:
|
||||
|
||||
Copyright (c) 2016 Palard Julien. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
1
hl-vt100/MANIFEST.in
Normal file
1
hl-vt100/MANIFEST.in
Normal file
|
|
@ -0,0 +1 @@
|
|||
include src/*.h
|
||||
45
hl-vt100/Makefile
Normal file
45
hl-vt100/Makefile
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
##
|
||||
## Makefile for vt100
|
||||
##
|
||||
## Made by julien palard
|
||||
##
|
||||
|
||||
NAME = vt100
|
||||
VERSION = 0
|
||||
MINOR = 0
|
||||
RELEASE = 0
|
||||
|
||||
LINKERNAME = lib$(NAME).so
|
||||
SONAME = $(LINKERNAME).$(VERSION)
|
||||
REALNAME = $(SONAME).$(MINOR).$(RELEASE)
|
||||
|
||||
SRC = src/lw_terminal_parser.c src/lw_terminal_vt100.c src/hl_vt100.c
|
||||
SRC_TEST = src/test.c
|
||||
OBJ = $(SRC:.c=.o)
|
||||
OBJ_TEST = $(SRC_TEST:.c=.o)
|
||||
CC = gcc
|
||||
INCLUDE = src
|
||||
DEFINE = _GNU_SOURCE
|
||||
CFLAGS = -DNDEBUG -g3 -Wextra -Wstrict-prototypes -Wall -ansi -pedantic -fPIC -I$(INCLUDE)
|
||||
LIB = -lutil
|
||||
RM = rm -f
|
||||
|
||||
$(NAME): $(OBJ)
|
||||
$(CC) --shared $(OBJ) $(LIB) -o $(LINKERNAME)
|
||||
|
||||
test: $(OBJ_TEST)
|
||||
$(CC) $(OBJ_TEST) -L . -l$(NAME) -o test
|
||||
|
||||
all:
|
||||
@make $(NAME)
|
||||
|
||||
.c.o:
|
||||
$(CC) -D $(DEFINE) -c $(CFLAGS) $< -o $(<:.c=.o)
|
||||
|
||||
clean:
|
||||
$(RM) $(LINKERNAME) test src/*~ *~ src/\#*\# src/*.o \#*\# *.o *core
|
||||
|
||||
re: clean all
|
||||
|
||||
check-syntax:
|
||||
gcc -Isrc -Wall -Wextra -ansi -pedantic -o /dev/null -S ${CHK_SOURCES}
|
||||
189
hl-vt100/README.md
Normal file
189
hl-vt100/README.md
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
# vt100 emulator
|
||||
|
||||
`vt100-emulator` is a headless
|
||||
[vt100](https://fr.wikipedia.org/wiki/VT100) emulator, a bit like any
|
||||
terminal you may use daily (like urxvt, xterm, ...) but those you're
|
||||
using are NOT headless, they have a graphical interface to interact
|
||||
with you, human). Here, `vt100-emulator` is only the underlying a `C`
|
||||
and `Python` API to an actual emulator, so you can do everything you
|
||||
want with it, like interfacing over TCP, HTTP, automatically testing
|
||||
your implementation `malloc` against `top` while running `top` in the
|
||||
headless terminal, whatever pleases you.
|
||||
|
||||
For copyright information, please see the file LICENSE in this
|
||||
directory or in the files of the source tree.
|
||||
|
||||
|
||||
# INSTALL
|
||||
|
||||
## Python module
|
||||
|
||||
pip install hl-vt100
|
||||
|
||||
|
||||
## Python module from source
|
||||
|
||||
The simpliest way is just to run `pip install .` from within the repo,
|
||||
but if you want build artifacts, you can build one in an isolated
|
||||
environment using:
|
||||
|
||||
pip install build
|
||||
python -m build
|
||||
|
||||
Or just create an `sdist` the quick way:
|
||||
n
|
||||
python setup.py sdist
|
||||
|
||||
In both case it will provide a build artifact in the `dist/` directory
|
||||
that you can also `pip install`.
|
||||
|
||||
|
||||
# Usage using the Python wrapper (same methods in C)
|
||||
|
||||
```python
|
||||
import hl_vt100
|
||||
|
||||
|
||||
def dump(vt100):
|
||||
print("╭" + "─" * vt100.width + "╮")
|
||||
for line in vt100.getlines():
|
||||
print(f"│{line:{vt100.width}}│")
|
||||
print("╰" + "─" * vt100.width + "╯")
|
||||
|
||||
|
||||
def main():
|
||||
vt100 = hl_vt100.vt100_headless()
|
||||
vt100.changed_callback = lambda: dump(vt100)
|
||||
vt100.fork('top', ['top'])
|
||||
vt100.main_loop()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
# Usage using the C library
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "hl_vt100.h"
|
||||
|
||||
|
||||
void changed(struct vt100_headless *vt100)
|
||||
{
|
||||
const char **lines;
|
||||
|
||||
lines = vt100_headless_getlines(vt100);
|
||||
for (unsigned int y = 0; y < vt100->term->height; ++y)
|
||||
{
|
||||
write(1, "|", 1);
|
||||
write(1, lines[y], vt100->term->width);
|
||||
write(1, "|\n", 2);
|
||||
}
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct vt100_headless *vt100;
|
||||
char *argv[] = {"top", NULL};
|
||||
|
||||
vt100 = new_vt100_headless();
|
||||
vt100_headless_fork(vt100, argv[0], argv);
|
||||
vt100->changed = changed;
|
||||
vt100_headless_main_loop(vt100);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
# Code overview
|
||||
|
||||
lw_terminal_parser, lw_terminal_vt100, and hl_vt100 are three modules used to emulate a vt100 terminal:
|
||||
|
||||
```
|
||||
-------------
|
||||
| |
|
||||
| Your Code |
|
||||
| |
|
||||
-------------
|
||||
| ^
|
||||
vt100 = vt100_headless_init() | |
|
||||
vt100->changed = changed; | | hl_vt100 raises 'changed'
|
||||
vt100_headless_fork(vt100, ... | | when the screen has changed.
|
||||
| | You get the content of the screen
|
||||
| | calling vt100_headless_getlines.
|
||||
V |
|
||||
------------- -------------
|
||||
Read from PTY master and write | | | PTY | |
|
||||
to lw_terminal_vt100_read_str | | hl_vt100 |<------------>| Program |
|
||||
V | |Master Slave| |
|
||||
------------- -------------
|
||||
| |^ hl_vt100 gets lw_terminal_vt100's
|
||||
| || lines by calling
|
||||
| || lw_terminal_vt100_getlines
|
||||
| ||
|
||||
| ||
|
||||
V V|
|
||||
----------------------
|
||||
Got data from | | | Recieve data from callbacks
|
||||
lw_terminal_vt100_read_str | | lw_terminal_vt100 | And store an in-memory
|
||||
give it to | | | state of the vt100 terminal
|
||||
lw_terminal_parser_read_strV ----------------------
|
||||
| ^
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| | Callbacks
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
V |
|
||||
----------------------
|
||||
Got data from | |
|
||||
lw_terminal_pasrser_read_str | lw_terminal_parser |
|
||||
parses, and call callbacks | |
|
||||
----------------------
|
||||
```
|
||||
|
||||
## lw_terminal_parser
|
||||
|
||||
`lw_terminal_parser` parses terminal escape sequences, calling callbacks
|
||||
when a sequence is sucessfully parsed, read `example/parse.c`.
|
||||
|
||||
Provides:
|
||||
|
||||
* `struct lw_terminal *lw_terminal_parser_init(void);`
|
||||
* `void lw_terminal_parser_destroy(struct lw_terminal* this);`
|
||||
* `void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *seq, char chr);`
|
||||
* `void lw_terminal_parser_read(struct lw_terminal *this, char c);`
|
||||
* `void lw_terminal_parser_read_str(struct lw_terminal *this, char *c);`
|
||||
|
||||
|
||||
## lw_terminal_vt100
|
||||
|
||||
Hooks into a `lw_terminal_parser` and keep an in-memory state of the
|
||||
screen of a vt100.
|
||||
|
||||
Provides:
|
||||
|
||||
* `struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data, void (*unimplemented)(struct lw_terminal* term_emul, char *seq, char chr));`
|
||||
* `char lw_terminal_vt100_get(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y);`
|
||||
* `const char **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100);`
|
||||
* `void lw_terminal_vt100_destroy(struct lw_terminal_vt100 *this);`
|
||||
* `void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this, char *buffer);`
|
||||
|
||||
|
||||
## hl_vt100
|
||||
|
||||
Forks a program, plug its io to a pseudo terminal and emulate a vt100
|
||||
using `lw_terminal_vt100`.
|
||||
|
||||
Provides:
|
||||
|
||||
* `void vt100_headless_fork(struct vt100_headless *this, const char *progname, char *const argv[]);`
|
||||
* `struct vt100_headless *vt100_headless_init(void);`
|
||||
* `const char **vt100_headless_getlines(struct vt100_headless *this);`
|
||||
76
hl-vt100/doc/vt100_emulator.3
Normal file
76
hl-vt100/doc/vt100_emulator.3
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH lw_terminal_parser 3 2011-09-27
|
||||
.SH NAME
|
||||
lw_terminal_parser_init, lw_terminal_read, lw_terminal_parser_read_str, lw_terminal_destroy \- LW Terminal Parser
|
||||
.SH SYNOPSIS
|
||||
.B #include <lw_terminal_parser.h>
|
||||
.sp
|
||||
.BI "struct lw_terminal *lw_terminal_parser_init(void);"
|
||||
.br
|
||||
.BI "void lw_terminal_read(struct lw_terminal *" this ", char " c ");"
|
||||
.br
|
||||
.BI "void lw_terminal_parser_read_str(struct lw_terminal *" this " , char *" c ");"
|
||||
.br
|
||||
.BI "void lw_terminal_destroy(struct lw_terminal* " this ");"
|
||||
.SH DESCRIPTION
|
||||
lw_terminal_parser is a library to parse escape sequences commonly sent to terminals. The functions in lw_terminal_parser allows you to create, send data, and destroy a terminal parser. The function
|
||||
.BR lw_terminal_parser_init ()
|
||||
allocates and prepare a new struct lw_terminal for you. Once a lw_terminal initialized you should hook your callbacks for escape sequences and write in lw_terminal->callbacks and lw_terminal->write. The you should call
|
||||
.BR lw_terminal_parser_read_str()
|
||||
or
|
||||
.BR lw_terminal_read()
|
||||
to make the terminal parse them.
|
||||
Finally to free the struct terminal, call
|
||||
.BR lw_terminal_destroy().
|
||||
.PP
|
||||
lw_terminal->callback is a structure for you to hook into escape sequences.
|
||||
This struct is broke into substructures for each type of sequencec : esc, csi, hash, and scs.
|
||||
Each substructure is a struct ascii_callback that have one member for each ascii character, in order, starting from 0x30, '0'. Members from '9' to '9' are named "n0" to "n9", letters just have their name, and others characters are of the form hXX where XX is their hexadecimal notation.
|
||||
.PP
|
||||
Here is simple an example on how to hook a callback into a terminal emulator :
|
||||
.nf
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/lw_terminal_parser.h"
|
||||
|
||||
static void vt100_write(struct lw_terminal *term_emul __attribute__((unused)),
|
||||
char c)
|
||||
{
|
||||
printf("Got a char : %c\\n", c);
|
||||
}
|
||||
|
||||
static void csi_f(struct lw_terminal *term_emul)
|
||||
{
|
||||
printf("\\\\033[...f with %d parameters\\n", term_emul->argc);
|
||||
}
|
||||
|
||||
static void csi_K(struct lw_terminal *term_emul)
|
||||
{
|
||||
printf("\\\\033[...K with %d parameters\\n", term_emul->argc);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct lw_terminal *lw_terminal;
|
||||
|
||||
lw_terminal = lw_terminal_parser_init();
|
||||
if (lw_terminal == NULL)
|
||||
return EXIT_FAILURE;
|
||||
lw_terminal->write = vt100_write;
|
||||
lw_terminal->callbacks.csi.f = csi_f;
|
||||
lw_terminal->callbacks.csi.K = csi_K;
|
||||
lw_terminal_parser_read_str(lw_terminal, "\\033[2KHello world !\\033[f");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
.fi
|
||||
|
||||
.br
|
||||
.SH "AUTHOR"
|
||||
lw_terminal_parser was written by Julien Palard.
|
||||
.PP
|
||||
This manual page was written by Julien Palard <julien@palard.fr>,
|
||||
for the Debian project (and may be used by others).
|
||||
33
hl-vt100/example/Makefile
Normal file
33
hl-vt100/example/Makefile
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
##
|
||||
## Makefile for lw_vt100 examples
|
||||
##
|
||||
## Made by julien palard <vt100@mandark.fr>
|
||||
##
|
||||
|
||||
NAME = parser
|
||||
|
||||
SRC = parser.c ../src/lw_terminal_parser.c
|
||||
OBJ = $(SRC:.c=.o)
|
||||
CC = gcc
|
||||
INCLUDE = ../src
|
||||
DEFINE = _GNU_SOURCE
|
||||
CFLAGS = -g3 -Wextra -Wstrict-prototypes -Wall -ansi -pedantic -I$(INCLUDE)
|
||||
LIB = -lutil
|
||||
RM = rm -f
|
||||
|
||||
$(NAME): $(OBJ)
|
||||
$(CC) $(OBJ) $(LIB) -o $(NAME)
|
||||
|
||||
all:
|
||||
@make $(NAME)
|
||||
|
||||
.c.o:
|
||||
$(CC) -D $(DEFINE) -c $(CFLAGS) $< -o $(<:.c=.o)
|
||||
|
||||
clean:
|
||||
$(RM) $(NAME) *~ \#*\# *.o *core
|
||||
|
||||
re: clean all
|
||||
|
||||
check-syntax:
|
||||
gcc -Isrc -Wall -Wextra -ansi -pedantic -o /dev/null -S ${CHK_SOURCES}
|
||||
33
hl-vt100/example/parser.c
Normal file
33
hl-vt100/example/parser.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/lw_terminal_parser.h"
|
||||
|
||||
static void vt100_write(struct lw_terminal *term_emul __attribute__((unused)),
|
||||
char c)
|
||||
{
|
||||
printf("Got a char : %c\n", c);
|
||||
}
|
||||
|
||||
static void csi_f(struct lw_terminal *term_emul)
|
||||
{
|
||||
printf("\\033[...f with %d parameters\n", term_emul->argc);
|
||||
}
|
||||
|
||||
static void csi_K(struct lw_terminal *term_emul)
|
||||
{
|
||||
printf("\\033[...K with %d parameters\n", term_emul->argc);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct lw_terminal *lw_terminal;
|
||||
|
||||
lw_terminal = lw_terminal_parser_init();
|
||||
if (lw_terminal == NULL)
|
||||
return EXIT_FAILURE;
|
||||
lw_terminal->write = vt100_write;
|
||||
lw_terminal->callbacks.csi.f = csi_f;
|
||||
lw_terminal->callbacks.csi.K = csi_K;
|
||||
lw_terminal_parser_read_str(lw_terminal, "\033[2KHello world !\033[f");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
30
hl-vt100/example/top.c
Normal file
30
hl-vt100/example/top.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "hl_vt100.h"
|
||||
|
||||
|
||||
void changed(struct vt100_headless *vt100)
|
||||
{
|
||||
const char **lines;
|
||||
|
||||
lines = vt100_headless_getlines(vt100);
|
||||
for (unsigned int y = 0; y < vt100->term->height; ++y)
|
||||
{
|
||||
write(1, "|", 1);
|
||||
write(1, lines[y], vt100->term->width);
|
||||
write(1, "|\n", 2);
|
||||
}
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct vt100_headless *vt100;
|
||||
char *argv[] = {"top", NULL};
|
||||
|
||||
vt100 = new_vt100_headless();
|
||||
vt100_headless_fork(vt100, argv[0], argv);
|
||||
vt100->changed = changed;
|
||||
vt100_headless_main_loop(vt100);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
19
hl-vt100/example/top.py
Normal file
19
hl-vt100/example/top.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import hl_vt100
|
||||
|
||||
|
||||
def dump(vt100):
|
||||
print("╭" + "─" * vt100.width + "╮")
|
||||
for line in vt100.getlines():
|
||||
print(f"│{line:{vt100.width}}│")
|
||||
print("╰" + "─" * vt100.width + "╯")
|
||||
|
||||
|
||||
def main():
|
||||
vt100 = hl_vt100.vt100_headless()
|
||||
vt100.changed_callback = lambda: dump(vt100)
|
||||
vt100.fork('top', ['top'])
|
||||
vt100.main_loop()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
51
hl-vt100/run_tests.sh
Executable file
51
hl-vt100/run_tests.sh
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2016 Julien Palard.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if [ "$1" = python ]
|
||||
then
|
||||
python -m pip install .
|
||||
cat <<EOF | python
|
||||
import hl_vt100
|
||||
|
||||
print("Starting python test...")
|
||||
vt100 = hl_vt100.vt100_headless()
|
||||
vt100.fork('/usr/bin/top', ['/usr/bin/top', '-n', '1'])
|
||||
vt100.main_loop()
|
||||
print(*vt100.getlines(), sep="\n")
|
||||
EOF
|
||||
exit
|
||||
fi
|
||||
|
||||
make clean
|
||||
|
||||
if [ "$1" = c ]
|
||||
then
|
||||
make && make test
|
||||
LD_LIBRARY_PATH=. ./test /usr/bin/top -n 1
|
||||
exit
|
||||
fi
|
||||
|
||||
$0 python
|
||||
$0 c
|
||||
39
hl-vt100/setup.py
Normal file
39
hl-vt100/setup.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
setup.py file for hl_vt100
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from setuptools import setup, Extension
|
||||
|
||||
|
||||
hl_vt100_module = Extension('hl_vt100',
|
||||
include_dirs=['src'],
|
||||
define_macros=[('NDEBUG', '1')],
|
||||
sources=['src/vt100_module.c',
|
||||
'src/hl_vt100.c',
|
||||
'src/lw_terminal_parser.c',
|
||||
'src/lw_terminal_vt100.c'])
|
||||
|
||||
setup(name='hl_vt100',
|
||||
version='0.2',
|
||||
url='https://github.com/JulienPalard/vt100-emulator',
|
||||
author="Julien Palard",
|
||||
author_email='julien@palard.fr',
|
||||
description="""Headless vt100 emulator""",
|
||||
long_description=(Path(__file__).parent / "README.md").read_text(encoding="UTF-8"),
|
||||
long_description_content_type="text/markdown",
|
||||
ext_modules=[hl_vt100_module],
|
||||
include_package_data=True,
|
||||
py_modules=["hl_vt100"],
|
||||
classifiers=[
|
||||
"Programming Language :: C",
|
||||
"Programming Language :: Python",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"License :: OSI Approved :: BSD License",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: System :: Emulators",
|
||||
"Topic :: Terminals :: Terminal Emulators/X Terminals"
|
||||
])
|
||||
167
hl-vt100/src/hl_vt100.c
Normal file
167
hl-vt100/src/hl_vt100.c
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Julien Palard.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pty.h>
|
||||
#include <stdlib.h>
|
||||
#include "hl_vt100.h"
|
||||
|
||||
struct vt100_headless *new_vt100_headless(void)
|
||||
{
|
||||
return calloc(1, sizeof(struct vt100_headless));
|
||||
}
|
||||
|
||||
void delete_vt100_headless(struct vt100_headless *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void set_non_canonical(struct vt100_headless *this, int fd)
|
||||
{
|
||||
struct termios termios;
|
||||
|
||||
ioctl(fd, TCGETS, &this->backup);
|
||||
ioctl(fd, TCGETS, &termios);
|
||||
termios.c_iflag |= ICANON;
|
||||
termios.c_cc[VMIN] = 1;
|
||||
termios.c_cc[VTIME] = 0;
|
||||
ioctl(fd, TCSETS, &termios);
|
||||
}
|
||||
|
||||
static void restore_termios(struct vt100_headless *this, int fd)
|
||||
{
|
||||
ioctl(fd, TCSETS, &this->backup);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void strdump(char *str)
|
||||
{
|
||||
while (*str != '\0')
|
||||
{
|
||||
if (*str >= ' ' && *str <= '~')
|
||||
fprintf(stderr, "%c", *str);
|
||||
else
|
||||
fprintf(stderr, "\\0%o", *str);
|
||||
str += 1;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
void vt100_headless_stop(struct vt100_headless *this)
|
||||
{
|
||||
this->should_quit = 1;
|
||||
}
|
||||
|
||||
int vt100_headless_main_loop(struct vt100_headless *this)
|
||||
{
|
||||
char buffer[4096];
|
||||
fd_set rfds;
|
||||
int retval;
|
||||
ssize_t read_size;
|
||||
|
||||
while (!this->should_quit)
|
||||
{
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(this->master, &rfds);
|
||||
FD_SET(0, &rfds);
|
||||
retval = select(this->master + 1, &rfds, NULL, NULL, NULL);
|
||||
if (retval == -1)
|
||||
{
|
||||
perror("select()");
|
||||
}
|
||||
if (FD_ISSET(0, &rfds))
|
||||
{
|
||||
read_size = read(0, &buffer, 4096);
|
||||
if (read_size == -1)
|
||||
{
|
||||
perror("read");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
buffer[read_size] = '\0';
|
||||
write(this->master, buffer, read_size);
|
||||
}
|
||||
if (FD_ISSET(this->master, &rfds))
|
||||
{
|
||||
read_size = read(this->master, &buffer, 4096);
|
||||
if (read_size == -1)
|
||||
{
|
||||
perror("read");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
buffer[read_size] = '\0';
|
||||
#ifndef NDEBUG
|
||||
strdump(buffer);
|
||||
#endif
|
||||
lw_terminal_vt100_read_str(this->term, buffer);
|
||||
if (this->changed != NULL)
|
||||
this->changed(this);
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void master_write(void *user_data, void *buffer, size_t len)
|
||||
{
|
||||
struct vt100_headless *this;
|
||||
|
||||
this = (struct vt100_headless*)user_data;
|
||||
write(this->master, buffer, len);
|
||||
}
|
||||
|
||||
const char **vt100_headless_getlines(struct vt100_headless *this)
|
||||
{
|
||||
return lw_terminal_vt100_getlines(this->term);
|
||||
}
|
||||
|
||||
void vt100_headless_fork(struct vt100_headless *this,
|
||||
const char *progname,
|
||||
char **argv)
|
||||
{
|
||||
int child;
|
||||
struct winsize winsize;
|
||||
|
||||
set_non_canonical(this, 0);
|
||||
winsize.ws_row = 24;
|
||||
winsize.ws_col = 80;
|
||||
child = forkpty(&this->master, NULL, NULL, NULL);
|
||||
if (child == CHILD)
|
||||
{
|
||||
setsid();
|
||||
putenv("TERM=vt100");
|
||||
execvp(progname, argv);
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->term = lw_terminal_vt100_init(this, lw_terminal_parser_default_unimplemented);
|
||||
this->term->master_write = master_write;
|
||||
ioctl(this->master, TIOCSWINSZ, &winsize);
|
||||
}
|
||||
restore_termios(this, 0);
|
||||
}
|
||||
54
hl-vt100/src/hl_vt100.h
Normal file
54
hl-vt100/src/hl_vt100.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Julien Palard.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __VT100_HEADLESS_H__
|
||||
#define __VT100_HEADLESS_H__
|
||||
|
||||
#define CHILD 0
|
||||
|
||||
#include <utmp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include "lw_terminal_vt100.h"
|
||||
|
||||
struct vt100_headless
|
||||
{
|
||||
int master;
|
||||
struct termios backup;
|
||||
struct lw_terminal_vt100 *term;
|
||||
int should_quit;
|
||||
void (*changed)(struct vt100_headless *this);
|
||||
};
|
||||
|
||||
|
||||
void vt100_headless_fork(struct vt100_headless *this, const char *progname, char **argv);
|
||||
int vt100_headless_main_loop(struct vt100_headless *this);
|
||||
void delete_vt100_headless(struct vt100_headless *this);
|
||||
struct vt100_headless *new_vt100_headless(void);
|
||||
const char **vt100_headless_getlines(struct vt100_headless *this);
|
||||
void vt100_headless_stop(struct vt100_headless *this);
|
||||
|
||||
#endif
|
||||
228
hl-vt100/src/lw_terminal_parser.c
Normal file
228
hl-vt100/src/lw_terminal_parser.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Julien Palard.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifndef NDEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "lw_terminal_parser.h"
|
||||
|
||||
static void lw_terminal_parser_push(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (this->stack_ptr >= TERM_STACK_SIZE)
|
||||
return ;
|
||||
this->stack[this->stack_ptr++] = c;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_parse_params(struct lw_terminal *this)
|
||||
{
|
||||
unsigned int i;
|
||||
int got_something;
|
||||
|
||||
got_something = 0;
|
||||
this->argc = 0;
|
||||
this->argv[0] = 0;
|
||||
for (i = 0; i < this->stack_ptr; ++i)
|
||||
{
|
||||
if (this->stack[i] >= '0' && this->stack[i] <= '9')
|
||||
{
|
||||
got_something = 1;
|
||||
this->argv[this->argc] = this->argv[this->argc] * 10
|
||||
+ this->stack[i] - '0';
|
||||
}
|
||||
else if (this->stack[i] == ';')
|
||||
{
|
||||
got_something = 0;
|
||||
this->argc += 1;
|
||||
this->argv[this->argc] = 0;
|
||||
}
|
||||
}
|
||||
this->argc += got_something;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_CSI(struct lw_terminal *this, char c)
|
||||
{
|
||||
lw_terminal_parser_parse_params(this);
|
||||
if (((term_action *)&this->callbacks.csi)[c - '0'] == NULL)
|
||||
{
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "CSI", c);
|
||||
goto leave;
|
||||
}
|
||||
((term_action *)&this->callbacks.csi)[c - '0'](this);
|
||||
leave:
|
||||
this->state = INIT;
|
||||
this->flag = '\0';
|
||||
this->stack_ptr = 0;
|
||||
this->argc = 0;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_ESC(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (((term_action *)&this->callbacks.esc)[c - '0'] == NULL)
|
||||
{
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "ESC", c);
|
||||
goto leave;
|
||||
}
|
||||
((term_action *)&this->callbacks.esc)[c - '0'](this);
|
||||
leave:
|
||||
this->state = INIT;
|
||||
this->stack_ptr = 0;
|
||||
this->argc = 0;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_HASH(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (((term_action *)&this->callbacks.hash)[c - '0'] == NULL)
|
||||
{
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "HASH", c);
|
||||
goto leave;
|
||||
}
|
||||
((term_action *)&this->callbacks.hash)[c - '0'](this);
|
||||
leave:
|
||||
this->state = INIT;
|
||||
this->stack_ptr = 0;
|
||||
this->argc = 0;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_GSET(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (c < '0' || c > 'B'
|
||||
|| ((term_action *)&this->callbacks.scs)[c - '0'] == NULL)
|
||||
{
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "GSET", c);
|
||||
goto leave;
|
||||
}
|
||||
((term_action *)&this->callbacks.scs)[c - '0'](this);
|
||||
leave:
|
||||
this->state = INIT;
|
||||
this->stack_ptr = 0;
|
||||
this->argc = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** INIT
|
||||
** \_ ESC "\033"
|
||||
** | \_ CSI "\033["
|
||||
** | | \_ c == '?' : term->flag = '?'
|
||||
** | | \_ c == ';' || (c >= '0' && c <= '9') : term_push
|
||||
** | | \_ else : term_call_CSI()
|
||||
** | \_ HASH "\033#"
|
||||
** | | \_ term_call_hash()
|
||||
** | \_ G0SET "\033("
|
||||
** | | \_ term_call_GSET()
|
||||
** | \_ G1SET "\033)"
|
||||
** | | \_ term_call_GSET()
|
||||
** \_ term->write()
|
||||
*/
|
||||
void lw_terminal_parser_read(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (this->state == INIT)
|
||||
{
|
||||
if (c == '\033')
|
||||
this->state = ESC;
|
||||
else
|
||||
this->write(this, c);
|
||||
}
|
||||
else if (this->state == ESC)
|
||||
{
|
||||
if (c == '[')
|
||||
this->state = CSI;
|
||||
else if (c == '#')
|
||||
this->state = HASH;
|
||||
else if (c == '(')
|
||||
this->state = G0SET;
|
||||
else if (c == ')')
|
||||
this->state = G1SET;
|
||||
else if (c >= '0' && c <= 'z')
|
||||
lw_terminal_parser_call_ESC(this, c);
|
||||
else this->write(this, c);
|
||||
}
|
||||
else if (this->state == HASH)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
lw_terminal_parser_call_HASH(this, c);
|
||||
else
|
||||
this->write(this, c);
|
||||
}
|
||||
else if (this->state == G0SET || this->state == G1SET)
|
||||
{
|
||||
lw_terminal_parser_call_GSET(this, c);
|
||||
}
|
||||
else if (this->state == CSI)
|
||||
{
|
||||
if (c == '?')
|
||||
this->flag = '?';
|
||||
else if (c == ';' || (c >= '0' && c <= '9'))
|
||||
lw_terminal_parser_push(this, c);
|
||||
else if (c >= '?' && c <= 'z')
|
||||
lw_terminal_parser_call_CSI(this, c);
|
||||
else
|
||||
this->write(this, c);
|
||||
}
|
||||
}
|
||||
|
||||
void lw_terminal_parser_read_str(struct lw_terminal *this, char *c)
|
||||
{
|
||||
while (*c)
|
||||
lw_terminal_parser_read(this, *c++);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *seq, char chr)
|
||||
{
|
||||
unsigned int argc;
|
||||
|
||||
fprintf(stderr, "WARNING: UNIMPLEMENTED %s (", seq);
|
||||
for (argc = 0; argc < this->argc; ++argc)
|
||||
{
|
||||
fprintf(stderr, "%d", this->argv[argc]);
|
||||
if (argc != this->argc - 1)
|
||||
fprintf(stderr, ", ");
|
||||
}
|
||||
fprintf(stderr, ")%o\n", chr);
|
||||
}
|
||||
#else
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *seq, char chr)
|
||||
{
|
||||
this = this;
|
||||
seq = seq;
|
||||
chr = chr;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct lw_terminal *lw_terminal_parser_init(void)
|
||||
{
|
||||
return calloc(1, sizeof(struct lw_terminal));
|
||||
}
|
||||
|
||||
void lw_terminal_parser_destroy(struct lw_terminal* this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
227
hl-vt100/src/lw_terminal_parser.h
Normal file
227
hl-vt100/src/lw_terminal_parser.h
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Julien Palard.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __TERMINAL_H__
|
||||
#define __TERMINAL_H__
|
||||
|
||||
/*
|
||||
**
|
||||
** Introduction
|
||||
** ============
|
||||
**
|
||||
** terminal.c is a basic level that parses escape sequences to call
|
||||
** appropriated callbacks permiting you to implement a specific terminal.
|
||||
**
|
||||
** Callbacks
|
||||
** =========
|
||||
**
|
||||
** terminal.c maps sequences to callbacks in this way :
|
||||
** \033... maps to terminal->callbacks->esc
|
||||
** \033[... maps to terminal->callbacks->csi
|
||||
** \033#... maps to terminal->callbacks->hash
|
||||
** and \033( and \033) maps to terminal->callbacks->scs
|
||||
**
|
||||
** In 'callbacks', esc, csi, hash and scs are structs ascii_callbacks
|
||||
** where you can bind your callbacks.
|
||||
**
|
||||
** Typically when terminal parses \033[42;43m
|
||||
** it calls terminal->callbacks->csi->m(terminal);
|
||||
**
|
||||
** Parameters (here 42;43) are stored in terminal->argc and terminal->argv
|
||||
** argv is an array of integers of length argc.
|
||||
**
|
||||
** Public members
|
||||
** ==============
|
||||
**
|
||||
** void *user_data :
|
||||
** A (void *) where your implementation can store whatever you want
|
||||
** to get it back on your callabks.
|
||||
**
|
||||
** void (*write)(struct terminal *, char c) :
|
||||
** Hook for your implementation to recieve chars that are not
|
||||
** escape sequences
|
||||
**
|
||||
** struct term_callbacks callbacks :
|
||||
** Hooks for your callbacks to recieve escape sequences
|
||||
**
|
||||
** enum term_state state :
|
||||
** During a callback, typically a scs, you can read here if it's a
|
||||
** G1SET or a G0SET
|
||||
**
|
||||
** unsigned int argc :
|
||||
** For your callbacks, to know how many parameters are available
|
||||
** in argv.
|
||||
**
|
||||
** unsigned int argv[TERM_STACK_SIZE] :
|
||||
** For your callbacks, parameters of escape sequences are accessible
|
||||
** here.
|
||||
** \033[42;43m will have 2 in argc and argv[0] = 42, argv[1] = 43
|
||||
**
|
||||
** char flag;
|
||||
** Optinal constructor flag present before parameters, like in :
|
||||
** \033[?1049h -> The flag will be '?'
|
||||
** Otherwise the flag is set to '\0'
|
||||
**
|
||||
** void (*unimplemented)(struct terminal*, char *seq, char chr) :
|
||||
** Can be NULL, you can hook here to know where the terminal parses an
|
||||
** escape sequence on which you have not registered a callback.
|
||||
**
|
||||
** Exemple
|
||||
** =======
|
||||
**
|
||||
** See terminal_vt100.c for a working exemple.
|
||||
**
|
||||
*/
|
||||
|
||||
#define TERM_STACK_SIZE 1024
|
||||
|
||||
enum term_state
|
||||
{
|
||||
INIT,
|
||||
ESC,
|
||||
HASH,
|
||||
G0SET,
|
||||
G1SET,
|
||||
CSI
|
||||
};
|
||||
|
||||
struct lw_terminal;
|
||||
|
||||
typedef void (*term_action)(struct lw_terminal *emul);
|
||||
|
||||
struct ascii_callbacks
|
||||
{
|
||||
term_action n0;
|
||||
term_action n1;
|
||||
term_action n2;
|
||||
term_action n3;
|
||||
term_action n4;
|
||||
term_action n5;
|
||||
term_action n6;
|
||||
term_action n7;
|
||||
term_action n8;
|
||||
term_action n9;
|
||||
|
||||
term_action h3A;
|
||||
term_action h3B;
|
||||
term_action h3C;
|
||||
term_action h3D;
|
||||
term_action h3E;
|
||||
term_action h3F;
|
||||
term_action h40;
|
||||
|
||||
term_action A;
|
||||
term_action B;
|
||||
term_action C;
|
||||
term_action D;
|
||||
term_action E;
|
||||
term_action F;
|
||||
term_action G;
|
||||
term_action H;
|
||||
term_action I;
|
||||
term_action J;
|
||||
term_action K;
|
||||
term_action L;
|
||||
term_action M;
|
||||
term_action N;
|
||||
term_action O;
|
||||
term_action P;
|
||||
term_action Q;
|
||||
term_action R;
|
||||
term_action S;
|
||||
term_action T;
|
||||
term_action U;
|
||||
term_action V;
|
||||
term_action W;
|
||||
term_action X;
|
||||
term_action Y;
|
||||
term_action Z;
|
||||
|
||||
term_action h5B;
|
||||
term_action h5C;
|
||||
term_action h5D;
|
||||
term_action h5E;
|
||||
term_action h5F;
|
||||
term_action h60;
|
||||
|
||||
term_action a;
|
||||
term_action b;
|
||||
term_action c;
|
||||
term_action d;
|
||||
term_action e;
|
||||
term_action f;
|
||||
term_action g;
|
||||
term_action h;
|
||||
term_action i;
|
||||
term_action j;
|
||||
term_action k;
|
||||
term_action l;
|
||||
term_action m;
|
||||
term_action n;
|
||||
term_action o;
|
||||
term_action p;
|
||||
term_action q;
|
||||
term_action r;
|
||||
term_action s;
|
||||
term_action t;
|
||||
term_action u;
|
||||
term_action v;
|
||||
term_action w;
|
||||
term_action x;
|
||||
term_action y;
|
||||
term_action z;
|
||||
};
|
||||
|
||||
struct term_callbacks
|
||||
{
|
||||
struct ascii_callbacks esc;
|
||||
struct ascii_callbacks csi;
|
||||
struct ascii_callbacks hash;
|
||||
struct ascii_callbacks scs;
|
||||
};
|
||||
|
||||
struct lw_terminal
|
||||
{
|
||||
unsigned int cursor_pos_x;
|
||||
unsigned int cursor_pos_y;
|
||||
enum term_state state;
|
||||
unsigned int argc;
|
||||
unsigned int argv[TERM_STACK_SIZE];
|
||||
void (*write)(struct lw_terminal *, char c);
|
||||
char stack[TERM_STACK_SIZE];
|
||||
unsigned int stack_ptr;
|
||||
struct term_callbacks callbacks;
|
||||
char flag;
|
||||
void *user_data;
|
||||
void (*unimplemented)(struct lw_terminal*,
|
||||
char *seq, char chr);
|
||||
};
|
||||
|
||||
struct lw_terminal *lw_terminal_parser_init(void);
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *seq, char chr);
|
||||
void lw_terminal_parser_read(struct lw_terminal *this, char c);
|
||||
void lw_terminal_parser_read_str(struct lw_terminal *this, char *c);
|
||||
void lw_terminal_parser_destroy(struct lw_terminal* this);
|
||||
#endif
|
||||
1008
hl-vt100/src/lw_terminal_vt100.c
Normal file
1008
hl-vt100/src/lw_terminal_vt100.c
Normal file
File diff suppressed because it is too large
Load diff
104
hl-vt100/src/lw_terminal_vt100.h
Normal file
104
hl-vt100/src/lw_terminal_vt100.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Julien Palard.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __LW_TERMINAL_VT100_H__
|
||||
#define __LW_TERMINAL_VT100_H__
|
||||
|
||||
#include <pthread.h>
|
||||
#include "lw_terminal_parser.h"
|
||||
|
||||
/*
|
||||
* Source : http://vt100.net/docs/vt100-ug/chapter3.html
|
||||
http://vt100.net/docs/tp83/appendixb.html
|
||||
* It's a vt100 implementation, that implements ANSI control function.
|
||||
*/
|
||||
|
||||
#define SCROLLBACK 3
|
||||
|
||||
#define MASK_LNM 1
|
||||
#define MASK_DECCKM 2
|
||||
#define MASK_DECANM 4
|
||||
#define MASK_DECCOLM 8
|
||||
#define MASK_DECSCLM 16
|
||||
#define MASK_DECSCNM 32
|
||||
#define MASK_DECOM 64
|
||||
#define MASK_DECAWM 128
|
||||
#define MASK_DECARM 256
|
||||
#define MASK_DECINLM 512
|
||||
|
||||
#define LNM 20
|
||||
#define DECCKM 1
|
||||
#define DECANM 2
|
||||
#define DECCOLM 3
|
||||
#define DECSCLM 4
|
||||
#define DECSCNM 5
|
||||
#define DECOM 6
|
||||
#define DECAWM 7
|
||||
#define DECARM 8
|
||||
#define DECINLM 9
|
||||
|
||||
|
||||
#define SET_MODE(vt100, mode) ((vt100)->modes |= get_mode_mask(mode))
|
||||
#define UNSET_MODE(vt100, mode) ((vt100)->modes &= ~get_mode_mask(mode))
|
||||
#define MODE_IS_SET(vt100, mode) ((vt100)->modes & get_mode_mask(mode))
|
||||
|
||||
/*
|
||||
** frozen_screen is the frozen part of the screen
|
||||
** when margins are set.
|
||||
** The top of the frozen_screen holds the top margin
|
||||
** while the bottom holds the bottom margin.
|
||||
*/
|
||||
struct lw_terminal_vt100
|
||||
{
|
||||
struct lw_terminal *lw_terminal;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int saved_x;
|
||||
unsigned int saved_y;
|
||||
unsigned int margin_top;
|
||||
unsigned int margin_bottom;
|
||||
unsigned int top_line; /* Line at the top of the display */
|
||||
char *screen;
|
||||
char *frozen_screen;
|
||||
char *tabulations;
|
||||
unsigned int selected_charset;
|
||||
unsigned int modes;
|
||||
char *lines[80];
|
||||
void (*master_write)(void *user_data, void *buffer, size_t len);
|
||||
void *user_data;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
|
||||
void (*unimplemented)(struct lw_terminal* term_emul,
|
||||
char *seq, char chr));
|
||||
char lw_terminal_vt100_get(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y);
|
||||
const char **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100);
|
||||
void lw_terminal_vt100_destroy(struct lw_terminal_vt100 *this);
|
||||
void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this, char *buffer);
|
||||
|
||||
#endif
|
||||
63
hl-vt100/src/test.c
Normal file
63
hl-vt100/src/test.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Julien Palard.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#include <string.h>
|
||||
#include <pty.h>
|
||||
#include <stdio.h>
|
||||
#include "hl_vt100.h"
|
||||
|
||||
void disp(struct vt100_headless *vt100)
|
||||
{
|
||||
unsigned int y;
|
||||
const char **lines;
|
||||
|
||||
lines = vt100_headless_getlines(vt100);
|
||||
write(1, "\n", 1);
|
||||
for (y = 0; y < vt100->term->height; ++y)
|
||||
{
|
||||
write(1, "|", 1);
|
||||
write(1, lines[y], vt100->term->width);
|
||||
write(1, "|\n", 2);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct vt100_headless *vt100_headless;
|
||||
|
||||
if (ac == 1)
|
||||
{
|
||||
puts("Usage: test PROGNAME");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
vt100_headless = new_vt100_headless();
|
||||
vt100_headless->changed = disp;
|
||||
vt100_headless_fork(vt100_headless, av[1], (av + 1));
|
||||
vt100_headless_main_loop(vt100_headless);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
281
hl-vt100/src/vt100_module.c
Normal file
281
hl-vt100/src/vt100_module.c
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/* This is a Python wrapper of the vt100 headless library */
|
||||
|
||||
/*
|
||||
|
||||
occurrences of 'xx' should be changed to something reasonable for your
|
||||
module. If your module is named foo your sourcefile should be named
|
||||
foomodule.c.
|
||||
|
||||
You will probably want to delete all references to 'x_attr' and add
|
||||
your own types of attributes instead. Maybe you want to name your
|
||||
local variables other than 'self'. If your object type is needed in
|
||||
other files, you'll have to create a file "foobarobject.h"; see
|
||||
floatobject.h for an example. */
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
#include "lw_terminal_vt100.h"
|
||||
#include "hl_vt100.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
struct vt100_headless *obj;
|
||||
PyObject *changed_callback;
|
||||
} VT100Object;
|
||||
|
||||
static PyTypeObject VT100_Type;
|
||||
|
||||
#define VT100Object_Check(v) Py_IS_TYPE(v, &VT100_Type)
|
||||
|
||||
|
||||
VT100Object **allocated;
|
||||
size_t allocated_size;
|
||||
|
||||
/* VT100 methods */
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_fork_doc,
|
||||
"fork(progname, argv)\n\
|
||||
\n\
|
||||
Fork a process in a new PTY handled by an headless VT100 emulator.");
|
||||
|
||||
static PyObject *
|
||||
VT100_fork(VT100Object *self, PyObject *args)
|
||||
{
|
||||
char *progname;
|
||||
PyObject *pyargv;
|
||||
const char **argv;
|
||||
int argc;
|
||||
int i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sO:fork", &progname, &pyargv))
|
||||
return NULL;
|
||||
if (!PyList_Check(pyargv))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "not a list");
|
||||
return NULL;
|
||||
}
|
||||
argc = PyList_Size(pyargv);
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
PyObject *o = PyList_GetItem(pyargv, i);
|
||||
if (!PyUnicode_Check(o))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "argv list must contain strings");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
argv = PyMem_Calloc(argc + 1, sizeof(char *));
|
||||
for (i = 0; i < argc; i++)
|
||||
argv[i] = PyUnicode_AsUTF8(PyList_GetItem(pyargv, i));
|
||||
argv[i] = NULL;
|
||||
vt100_headless_fork(self->obj, progname, (char **)argv);
|
||||
PyMem_Free(argv);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_getlines_doc,
|
||||
"getlines()\n\
|
||||
\n\
|
||||
Get a list of lines as currently seen by the emulator.");
|
||||
|
||||
static PyObject *
|
||||
VT100_getlines(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
const char **lines;
|
||||
PyObject *result;
|
||||
|
||||
lines = vt100_headless_getlines(self->obj);
|
||||
result = PyList_New(0);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
for (unsigned int i = 0; i < self->obj->term->height; i++)
|
||||
PyList_Append(result, PyUnicode_FromStringAndSize(lines[i], self->obj->term->width));
|
||||
return result;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_main_loop_doc,
|
||||
"main_loop()\n\
|
||||
\n\
|
||||
Enter the emulator main loop.");
|
||||
|
||||
static PyObject *
|
||||
VT100_main_loop(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
vt100_headless_main_loop(self->obj);
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_stop_doc,
|
||||
"stop()\n\
|
||||
\n\
|
||||
Stop emulator main loop.");
|
||||
|
||||
static PyObject *
|
||||
VT100_stop(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
vt100_headless_stop(self->obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
vt100_add_to_allocated(VT100Object *obj)
|
||||
{
|
||||
for (size_t i = 0; i < allocated_size; i++)
|
||||
{
|
||||
if (allocated[i] == NULL)
|
||||
{
|
||||
allocated[i] = obj;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Out of allocated memory, realloc. */
|
||||
allocated_size *= 2;
|
||||
allocated = PyMem_Realloc(allocated, allocated_size * sizeof(VT100Object*));
|
||||
if (allocated == NULL)
|
||||
{
|
||||
PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator");
|
||||
return -1;
|
||||
}
|
||||
return vt100_add_to_allocated(obj);
|
||||
}
|
||||
|
||||
static int
|
||||
vt100_del_from_allocated(VT100Object *obj)
|
||||
{
|
||||
for (size_t i = 0; i < allocated_size; i++)
|
||||
{
|
||||
if (allocated[i] == obj)
|
||||
{
|
||||
allocated[i] = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
VT100Object *
|
||||
vt100_find_in_allocated(struct vt100_headless *obj)
|
||||
{
|
||||
for (size_t i = 0; i < allocated_size; i++)
|
||||
if (allocated[i]->obj == obj)
|
||||
return allocated[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
hl_vt100_changed_cb(struct vt100_headless *this)
|
||||
{
|
||||
VT100Object *obj;
|
||||
PyObject *result;
|
||||
|
||||
obj = vt100_find_in_allocated(this);
|
||||
if (obj->changed_callback != NULL && obj->changed_callback != Py_None)
|
||||
{
|
||||
result = PyObject_CallNoArgs(obj->changed_callback);
|
||||
if (result == NULL)
|
||||
this->should_quit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
VT100_init(VT100Object *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
self->obj = new_vt100_headless();
|
||||
vt100_add_to_allocated(self);
|
||||
self->obj->changed = hl_vt100_changed_cb;
|
||||
if (self->obj == NULL)
|
||||
{
|
||||
PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
VT100_getwidth(VT100Object *self, void *closure)
|
||||
{
|
||||
return PyLong_FromUnsignedLong(self->obj->term->width);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
VT100_getheight(VT100Object *self, void *closure)
|
||||
{
|
||||
return PyLong_FromUnsignedLong(self->obj->term->height);
|
||||
}
|
||||
|
||||
static void
|
||||
VT100_dealloc(VT100Object *self)
|
||||
{
|
||||
vt100_del_from_allocated(self);
|
||||
Py_XDECREF(self->changed_callback);
|
||||
delete_vt100_headless(self->obj);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyMethodDef VT100_methods[] = {
|
||||
{"fork", (PyCFunction)VT100_fork, METH_VARARGS, vt100_headless_fork_doc},
|
||||
{"getlines", (PyCFunction)VT100_getlines, METH_NOARGS, vt100_headless_getlines_doc},
|
||||
{"main_loop", (PyCFunction)VT100_main_loop, METH_NOARGS, vt100_headless_main_loop_doc},
|
||||
{"stop", (PyCFunction)VT100_stop, METH_NOARGS, vt100_headless_stop_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
static PyMemberDef VT100_members[] = {
|
||||
{"changed_callback", T_OBJECT_EX, offsetof(VT100Object, changed_callback), 0,
|
||||
"Changed Callback"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyGetSetDef VT100_getsetters[] = {
|
||||
{"width", (getter) VT100_getwidth, NULL, "Terminal width", NULL},
|
||||
{"height", (getter) VT100_getheight, NULL, "Terminal height", NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject VT100_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "hl_vt100.vt100_headless",
|
||||
.tp_basicsize = sizeof(VT100Object),
|
||||
.tp_dealloc = (destructor)VT100_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.tp_methods = VT100_methods,
|
||||
.tp_init = (initproc)VT100_init,
|
||||
.tp_new = PyType_GenericNew,
|
||||
.tp_members = VT100_members,
|
||||
.tp_getset = VT100_getsetters,
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Headless VT100 Terminal Emulator.");
|
||||
|
||||
static struct PyModuleDef hl_vt100_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "hl_vt100",
|
||||
.m_doc = module_doc,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_hl_vt100(void)
|
||||
{
|
||||
PyObject *m;
|
||||
|
||||
m = PyModule_Create(&hl_vt100_module);
|
||||
allocated = PyMem_Calloc(4096, sizeof(VT100Object*));
|
||||
allocated_size = 4096;
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
if (PyModule_AddType(m, &VT100_Type) < 0) {
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
Loading…
Reference in a new issue