pax_global_header00006660000000000000000000000064136467751750014537gustar00rootroot0000000000000052 comment=576bf6aa5c148b79325bfe299b20ea031f3c2ee4 termrec-0.19/000077500000000000000000000000001364677517500131315ustar00rootroot00000000000000termrec-0.19/.gitignore000066400000000000000000000010151364677517500151160ustar00rootroot00000000000000aclocal.m4 autom4te.cache *.coff config.guess config.h config.h.in config.log config.status config.status.lineno config.sub configure configure.lineno VERSION DEADJOE depcomp .deps .dirstamp *.exe *.exe.stackdump install-sh compile Makefile Makefile.in missing libtool ltmain.sh m4/libtool.m4 m4/lt*.m4 ar-lib *.nh *.nh.bz2 proxyrec stamp-h1 stamp-h.in _stdint.h svn-commit*.tmp termplay termrec termtime termcat *.1 *.3 termrec-*.tar.xz *.ttyrec *.ttyrec.bz2 *.ttyrec.gz ttyrecord *.txt.bz2 *.o *.a *.lo *.la *.loT .libs *~ termrec-0.19/.gitmodules000066400000000000000000000001431364677517500153040ustar00rootroot00000000000000[submodule "win32/lib"] path = win32/lib url = https://github.com/kilobyte/termrec-win32libs.git termrec-0.19/.mailmap000066400000000000000000000001241364677517500145470ustar00rootroot00000000000000Adam Borowski termrec-0.19/.travis.yml000066400000000000000000000017111364677517500152420ustar00rootroot00000000000000language: c matrix: include: - name: "Ubuntu amd64" os: linux dist: bionic addons: apt: packages: - libz-dev - libbz2-dev - liblzma-dev - libzstd-dev - libcurl4-gnutls-dev script: ./autogen.sh && ./configure && make check after_failure: cat tests/testsuite.log - name: "OSX" os: osx before_install: brew update && brew install libtool script: ./autogen.sh && ./configure && make check after_failure: cat tests/testsuite.log - name: "Windows i386" os: linux dist: bionic before_install: - sudo apt-get update -qq - sudo apt-get install g++-mingw-w64-i686 addons: apt: packages: - g++-mingw-w64-i686 env: WCC: i686-w64-mingw32-gcc script: ./autogen.sh && ./configure --host=i686-w64-mingw32 CC=$WCC && make after_failure: cat config.log termrec-0.19/BUGS000066400000000000000000000014741364677517500136220ustar00rootroot00000000000000* win32/play: constant full-screen redraw * win32/play: full prefetch * win32/play: ugly cursor * win32/rec: on Win95/98/ME, scrolling does a full screen dump * win32/play: no way to select the plugin except for file extensions * replay_export(): should record UTF-8ness and add an option to dump the initial screen * tty: not all control sequences are supported. It'd be nice to have a good subset of http://invisible-island.net/xterm/ctlseqs/ctlseqs.html implemented. * win32/play: font selection being hidden in the window's sysmenu is unobvious, and can't be accessed under Wine at all. * win32/play: no glyph-borrowing limits displayable characters to the selected font only * win32/play: no combining characters; pointless to even think about them without using some modern text display functions... termrec-0.19/COPYING.LIB000066400000000000000000000167431364677517500146040ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. termrec-0.19/ChangeLog000066400000000000000000000033311364677517500147030ustar00rootroot000000000000000.19 * Fix build failure with gcc-10 (-fno-common). * A bunch of minor and warning fixes. 0.18 * library API is now declared stable, ABI at soname 1. + include file is (not ) * identifier prefixes are tty_ not vt100_ * asciicast support (v1 and v2). * .zst compression. * fetching (and not very useful putting) via CURL. * drop proxyrec. * tty emulation improvements: + CJK full(double)width + combining characters * overstrike (\e[9m) * 24-bit color + many ANSI codes + store the window title * license is now LGPL2+. 0.17 * Support for 256 colour codes. * .xz support. * Major portability/bit rot fixes. * Assorted fixes. 0.16 * --append * Protocols: tcp:// (rw), telnet:// (r), termcast:// (r). 0.15 * A total reorganization, with refactoring of most parts. * Library. * New utilities: termcat and termtime. * Unix termplay is finally usable. * Loading the data in a background thread actually works (not on win32). * proxyrec defaults to --raw and -f ansi. * Bugfixes in vt100 interpretation. * New format: DosRecorder (read-only). 0.14 * Moved win32 crap to a dir on its own. * proxyrec: IPv6 support for outgoing connections. * If you specify a format, you need to append requested compression type to it (like, .nh.gz). This allows disabling compression, before it was always .bz2 unless a file name was explicitly set. 0.13 * New format: RealLogs (write-only). 0.12 * termplay/win32: exporting a part of a replay. 0.11 * Fixed a race condition in termplay/win32 that often caused crashes if the file to replay was specified on the command line. * Done proxyrec/unix -- it's untested on anything but Debian/unstable/i386, though. * Made some preliminary code for termrec/unix. It's still buggy. termrec-0.19/INSTALL000066400000000000000000000031421364677517500141620ustar00rootroot00000000000000The instructions below assume you're building from the tarball. If you're pulling the sources from git, you need to install libtool, automake and autoconf then run ./autogen.sh prior to running ./configure. Unix ==== On an Unix system, do: + apt-get install libz-dev libbz2-dev liblzma-dev libzstd-dev libcurl4-gnutls-dev Or equivalent. If you skip this step, the .gz/.bz2/.xz/.zst support won't get compiled in. Without libcurl, http/https/gopher/... URLs won't be available. + ./configure + make Windows ======= Building the Windows version from source is more tricky. To compile it, you need a way to run the GNU configure. It can be done by: * getting MinGW and MSYS + download them from http://mingw.org + ./configure + make * using Cygwin for cygwin: + ./configure + make for mingw: + CC=/cygdrive/c/MinGW/bin/gcc ./configure + make * cross-compiling from an Unix platform + ./configure --host i586-mingw32msvc + make For the compression plugins, you'll need to grab zlib, libbz2 and/or lzma. If you're building for Cygwin (but not just on Cygwin), please install them from Cygwin's repositories. For native win32, it's easiest to do so by cloning the submodule: + git submodule update --init If you're putting them together by hand, put the files into win32/lib/ : * zlib: + zconf.h + zlib.h + libz.dll.a + zlib1.dll * bzlib: + bzlib.h + libbz2.dll.a + bzip2.dll * lzma: + lzma.h + lzma/*.h + liblzma.a + liblzma.dll * zstd: + zstd.h + libzstd.dll.a + libzstd.dll termrec-0.19/Makefile.am000066400000000000000000000012161364677517500151650ustar00rootroot00000000000000if WIN32 SUBDIRS = win32/icons . tests else SUBDIRS = . tests endif EXTRA_DIST= BUGS autogen.sh gettext.h export.h win32/termrec.iss \ VERSION get_version DISTCLEANFILES = _stdint.h ACLOCAL_AMFLAGS = -I m4 CLEANFILES = AM_CFLAGS = -I${srcdir}/sys -I${srcdir}/libtty -I${srcdir}/common -Wno-parentheses include sys/Makefile.am include libstream/Makefile.am include libtty/Makefile.am include common/Makefile.am if WIN32 include win32/Makefile.am else include rec/Makefile.am include play/Makefile.am include time/Makefile.am include cat/Makefile.am endif include doc/Makefile.am VERSION: FORCE [ ! -d .git ] || $(srcdir)/get_version >VERSION FORCE: termrec-0.19/README000066400000000000000000000005771364677517500140220ustar00rootroot00000000000000The library consists of two parts: * pseudo-terminal handling (as in "vt100-like", not in "pty") These parts are documented in "man libtty". * ttyrec files For documentation, look at "man libttyrec". The utilities are: * termrec * termplay * termtime * termcat License: LGPL-2 -- or, at your option, any higher version other than any licenses from the Affero branch. termrec-0.19/acinclude.m4000066400000000000000000000006341364677517500153250ustar00rootroot00000000000000m4_include([m4/ax_create_stdint_h.m4]) m4_include([m4/ac_ptyranges.m4]) m4_include([m4/ac_check_win32.m4]) m4_include([m4/ac_shipped_lib.m4]) m4_include([m4/ax_pthread.m4]) m4_include([m4/ac_decl_or_zero.m4]) m4_include([m4/ac_visibility.m4]) m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_lib_socket_nsl.m4]) m4_include([m4/ac_sco.m4]) m4_include([m4/ac_c_try_flag.m4]) m4_include([m4/ac_zstd.m4]) termrec-0.19/autogen.sh000077500000000000000000000002431364677517500151310ustar00rootroot00000000000000#!/bin/sh set -e if which glibtoolize >/dev/null then glibtoolize --automake else libtoolize --automake fi aclocal autoheader automake --add-missing autoconf termrec-0.19/cat/000077500000000000000000000000001364677517500137005ustar00rootroot00000000000000termrec-0.19/cat/Makefile.am000066400000000000000000000001371364677517500157350ustar00rootroot00000000000000bin_PROGRAMS += termcat termcat_SOURCES = cat/termcat.c termcat_LDADD = libutils.la libtty.la termrec-0.19/cat/termcat.c000066400000000000000000000015371364677517500155110ustar00rootroot00000000000000#include #include #include #include #include "sys/error.h" #include "gettext.h" static struct timeval tt; static recorder rec; static void delay(const struct timeval *tm, void *arg) { tadd(tt, *tm); } static void print(const char *buf, int len, void *arg) { ttyrec_w_write(rec, &tt, buf, len); } int main(int argc, char **argv) { int i; int any=0; if (argc<3) die("%s termcat <%s> ... \n", _("Usage:"), _("filename")); tt.tv_sec=tt.tv_usec=0; if (!(rec=ttyrec_w_open(-1, 0, argv[argc-1], 0))) die("Failed to open destination file"); for (i=1;i #include #include "sys/error.h" #include "gettext.h" #include "ttyrec.h" #include "common.h" extern char *optarg; void get_w_format(const char **format) { int i; const char *fn, *fe; if (*format) die(_("You can use only one format at a time.\n")); if (!(*format=ttyrec_w_find_format(optarg, 0, 0))) { fprintf(stderr, _("No such format: %s\n"), optarg); fprintf(stderr, _("Valid formats:\n")); for (i=0;(fn=ttyrec_w_get_format_name(i));i++) if ((fe=ttyrec_w_get_format_ext(fn))) fprintf(stderr, " %-15s (%s)\n", fn, fe); else fprintf(stderr, " %-15s\n", fn); exit(1); } } void get_r_format(const char **format) { int i; const char *fn, *fe; if (*format) die(_("You can use only one format at a time.\n")); if (!(*format=ttyrec_r_find_format(optarg, 0, 0))) { fprintf(stderr, _("No such format: %s\n"), optarg); fprintf(stderr, _("Valid formats:\n")); for (i=0;(fn=ttyrec_r_get_format_name(i));i++) if ((fe=ttyrec_r_get_format_ext(fn))) fprintf(stderr, " %-15s (%s)\n", fn, fe); else fprintf(stderr, " %-15s\n", fn); exit(1); } } termrec-0.19/common/common.h000066400000000000000000000003461364677517500160650ustar00rootroot00000000000000void get_w_format(const char **format); // get it or die noisily void get_r_format(const char **format); // uhm... just like above int open_out(char **file_name, const char *format_ext, int append); // find a name if not provided termrec-0.19/common/open_out.c000066400000000000000000000045471364677517500164270ustar00rootroot00000000000000#include "config.h" #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "error.h" #include "compat.h" #include "ttyrec.h" #include "gettext.h" #include "common.h" #if (defined HAVE_LIBBZ2) || (defined SHIPPED_LIBBZ2) #define comp_ext ".bz2" #else # if (defined HAVE_LIBZ) || (defined SHIPPED_LIBZ) #define comp_ext ".gz" # else #define comp_ext "" # endif #endif // Generate the next name in the sequence: "", a, b, ... z, aa, ab, ... static void nameinc(char *add) { char *ae,*ai; ae=add; while (*ae) ae++; ai=ae; // start at the end of the string while (1) { if (--ai #include #include #include #include #include #include #include #include #include #include "error.h" #include "compat.h" #include "ttyrec.h" #include "rec_args.h" #include "gettext.h" #include "common.h" const char *command, *format, *format_ext; int lport,rport; char *record_name; int raw; int append; #ifdef HAVE_GETOPT_LONG static struct option rec_opts[]={ {"format", 1, 0, 'f'}, {"exec", 1, 0, 'e'}, {"raw", 0, 0, 'r'}, {"append", 0, 0, 'a'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0}, }; #endif static const char *comp_ext; void get_rec_parms(int argc, char **argv) { format=0; command=0; record_name=0; raw=0; append=0; #if (defined HAVE_LIBBZ2) || (defined SHIPPED_LIBBZ2) comp_ext=".bz2"; #elif (defined HAVE_LIBZ) || (defined SHIPPED_LIBZ) comp_ext=".gz"; #elif (defined HAVE_LIBLZMA) || (defined SHIPPED_LIBLZMA) comp_ext=".xz"; #elif (defined HAVE_LIBZSTD) || (defined SHIPPED_LIBZSTD) comp_ext=".zst"; #else comp_ext=""; #endif while (1) { #ifdef HAVE_GETOPT_LONG switch (getopt_long(argc, argv, "f:e:rah", rec_opts, 0)) #else switch (getopt(argc, argv, "f:e:rah")) #endif { case -1: goto finish_args; case ':': case '?': exit(1); case 'f': get_w_format(&format); break; case 'e': if (command) die(_("You can specify -e only once.\n")); command=optarg; break; case 'r': raw=1; break; case 'a': append=1; break; case 'h': printf( "%stermrec [-f format] [-e command] [file]\n" " %s" "-f, --format X %s\n" "-e, --exec X %s\n" "-r, --raw %s\n" "-a, --append %s\n" "-h, --help %s\n" "%s%s%s", _("Usage: "), _("Records the output of a console session to a file, including timing data.\n"), _("set output format to X (-f whatever for the list)"), _("execute command X instead of spawning a shell"), _("don't record UTFness or terminal size"), _("append to an existing file"), _("show this usage message"), _("If no filename is given, a name will be generated using the current date\n" " and the given format.\n"), _("If no format is given, it will be set according to the extension of the\n" " filename, or default to ttyrec if nothing is given.\n"), _("You can specify compression by appending .gz, .xz or .bz2 to the file name.\n")); exit(0); } } finish_args: if (optind$@ .pod.3: $(QUIET_POD)d=`git log -1 --pretty="format:%ct" $<|cut -f 1 -d ' '`;\ if test -n "$$d";then perl -e "utime undef,$$d,'$<'";fi;\ pod2man -c termrec -s 3 -n `basename "$@"|sed 's/\.[0-9]$$//'|tr a-z A-Z` -r "$(VERSION)" $< >$@ CLEANFILES += $(dist_man_MANS) else .pod.1: @echo "No pod2man -> not building" $< .pod.3: @echo "No pod2man -> not building" $< endif termrec-0.19/doc/libtty.pod000066400000000000000000000121631364677517500157140ustar00rootroot00000000000000=encoding utf8 =head1 NAME libtty - a library for handling vt100-like pseudo-terminals =head1 SYNOPSIS B<#include Etty.hE> Link with I<-ltty>. =head1 DESCRIPTION =head2 Functions: =over =item BIB<, int >IB<, int >IB<);> Creates a new vt100 terminal, of size IEI. If you want user input to be allowed to change that size, set I to non-zero. =item BIB<, int >IB<, int >IB<);> Resizes the I to IEI. This works even on terminals marked as non-resizable since that prevents only user input from resizing, not you. =item BIB<);> Clears the screen and attributes. =item BIB<);> Deallocates the I and all its internal structures. =item BIB<, const char *>IB<, int >IB<);> Writes I bytes into the terminal, parsing them as vt100 codes. =item BIB<, const char *>IB<, >I<...>B<);> Does a B into the terminal. =item BIB<);> Allocates a new vt100 terminal, making it an exact copy of an existing one, including its internal state. Attached event callbacks are not copied. =item BIB<, uint32_t >IB<);> Converts color values between modes: VT100_COLOR_OFF, VT100_COLOR_16, VT100_COLOR_256, VT100_COLOR_RGB. =back =head2 Inside the terminal You'll most likely be interested in the following fields of the structure: =over =item tty { =item int I,I; // screen size =item int I,I; // cursor position =item attrchar *I; // screen buffer =item int I; // current attribute =item char *I; // window title =back I<scr> is an array of character/attribute pairs, more exactly, each element is a struct C<{ ucs ch; int attr; }>. The array is a flat one of I<vt>B<-E<gt>>I<sx>*I<vt>B<-E<gt>>I<sy> elements, arranged row by row. A screen coordinate I<x>,I<y> is stored at I<x>+I<y>*I<vt>B<-E<gt>>I<sy>. For other fields, please RTFS the header itself: B<tty.h> =head2 TTY event callbacks Well, you have written some data to the terminal. Now you probably want to put it somewhere. What now? The tty structure has a number of I<event hooks> that you can attach your functions to. These hooks are callbacks inside the B<tty> structure that you can set. The callback fields are: =over =item B<void *l_data;> it's a place to put your private data in =item B<void (*l_char)(tty >I<vt>B<, int >I<x>B<, int >I<y>B<, ucs >I<ch>B<, int >I<attr>B<, int >I<width>B<);> after a character has been written to the screen; the cursor advances by I<width> which might be 1 (regular) or 2 (CJK "fullwidth") =item B<void (*l_cursor)(tty >I<vt>B<, int >I<x>B<, int >I<y>B<);> after the cursor has moved =item B<void (*l_clear)(tty >I<vt>B<, int >I<x>B<, int >I<y>B<, int >I<len>B<);> after a chunk of screen has been cleared If an endpoint spills outside of the current line, it will go all the way to an end of screen. If the cursor moves, you'll get a separate I<l_cursor>, although it is already in place during the I<l_clear> call. =item B<void (*l_scroll)(tty >I<vt>B<, int >I<nl>B<);> after the region s1<=y<s2 is scrolled nl lines (nl<0 -> backwards, nl>0 -> forward). There's no separare I<l_cursor> event, I<cx> and I<cy> are already updated. =item B<void (*l_flag)(tty >I<vt>B<, int >I<f>B<, int >I<v>B<);> when a flag changes to I<v>. Flags that are likely to be of interest to you are: =over =item * B<VT100_FLAG_CURSOR> cursor visibility =item * B<VT100_FLAG_KPAD> application keypad mode (more detailed codes for keypad arrow keys) =back =item B<void (*l_osc)(tty >I<vt>B<, int >I<cmd>B<, const char *>I<str>B<);> when a string command has been issued; most commands alter a color palette, but the most interesting one is B<0>: "set window title" =item B<void (*l_resize)(tty >I<vt>B<, int >I<sx>B<, int >I<sy>B<);> after the terminal has been resized =item B<void (*l_flush)(tty >I<vt>B<);> when a write chunk ends =item B<void (*l_bell)(tty >I<vt>B<);> upon a beep =item B<void (*l_free)(tty >I<vt>B<);> before the terminal is destroyed =back =head2 Vt-on-vt redirection For the case when you want the output go to a real terminal, there are: =over =item B<void vtvt_attach(tty >I<vt>B<, FILE *>I<f>B<, int >I<dump>B<);> Attaches the FILE stream I<f> to terminal I<vt>. Usually, I<f> will be B<stdout>. Whenever the contents of I<vt> changes, appropriate data will be written to the stream as well. If I<dump> is non-zero, the current state will be drawn, otherwise, only subsequent changes will be shown. The redirection will last until the terminal is destroyed by B<tty_free()>. =item B<void vtvt_resize(tty >I<vt>B<, int >I<sx>B<, int >I<sy>B<);> Tells libtty that the B<real> terminal has been resized (for resizing the virtual one, please use B<tty_resize()>). =item B<void vtvt_dump(tty >I<vt>B<);> Forces a full-screen redraw of the current contents of I<vt>. =back =head1 SEE ALSO L<libttyrec(3)> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/doc/libttyrec.pod����������������������������������������������������������������������0000664�0000000�0000000�00000014143�13646775175�0016406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������=head1 NAME libttyrec - a library for handling ttyrec files =head1 SYNOPSIS B<#include E<lt>ttyrec.hE<gt>> Link with I<-ltty>. =head1 DESCRIPTION =head2 Helper stream function: =over =item B<int open_stream(int >I<fd>B<, const char* >I<url>B<, int >I<mode>B<, const char **>I<error>B<);> This function opens a stream designated by the I<url>. If the given url ends in ".gz", ".xz", ".bz2" or ".zst"), the stream is assumed to be compressed and gets passed through the appropriate [un]packer. If the I<fd> is not -1, it is the descriptor you already opened; if it is -1, the file is opened. The I<mode> can be: =over =item SM_READ =item SM_WRITE =item SM_REPREAD =item SM_APPEND =back On error, -1 is returned. If you want the message, pass a non-null pointer I<error>, it will be filled in. =back =head2 Format encoders: =over =item B<const char* ttyrec_w_find_format(const char *>I<format>B<, const char *>I<filename>B<, const char *>I<fallback>B<);> This function searches for a format that would fit the I<filename> provided -- that is, abc.ttyrec.gz returns "ttyrec". If no known extension is found, the function returns whatever you gave as I<fallback>. You can force a I<format> yourself, in this case, it is only validated and if invalid, 0 is returned regardless of the other two arguments. =item B<recorder ttyrec_w_open(int >I<fd>B<, const char *>I<format>B<, const char *>I<filename>B<, const struct timeval *>I<ts>B<);> A recorder is opened, writing to the file I<fd>; if it's not given (=-1), the function calls B<open_stream()>. Recording is done in the given I<format>, if not provided, the format is guessed based on the I<filename>. If you provide a timestamp I<ts>, it becomes date of the recording. =item B<int ttyrec_w_write(recorder >I<r>B<, const struct timeval *tm, const char *>I<data>B<, int >I<len>B<);> A chunk of data of length I<len> is written to recorder I<r>, with timestamp I<tm>. Returns 1 if some sort of write error happened. =item B<int ttyrec_w_close(recorder >I<r>B<);> All pending data is flushed, recorder closed and its memory freed. Returns 1 if there's some kind of failure. =item B<const char* ttyrec_w_get_format_name(int >I<i>B<);> You can use this function to enumerate known write formats by calling it with I<i> being subsequent numbers starting at 0. An invalid I<i> will return a null pointer. =item B<const char* ttyrec_w_get_format_ext(const char *>I<format>B<);> If the given write I<format> is associated with a file extension, it is returned. =back =head2 Format decoders: =over =item B<const char* ttyrec_r_find_format(const char *>I<format>B<, const char *>I<filename>B<, const char *>I<fallback>B<);> See the _w_ function, except that read formats are searched instead. =item B<const char* ttyrec_r_get_format_name(int >I<i>B<);> ditto =item B<const char* ttyrec_r_get_format_ext(const char *>I<format>B<);> ditto =item B<int ttyrec_r_play(int >I<fd>B<, const char *>I<format>B<, const char *>I<filename>B<, void (*>I<synch_init_wait>B<)(const struct timeval *ts, void *>I<arg>B<), void (*>I<synch_wait>B<)(const struct timeval *>I<delay>B<, void *>I<arg>B<), void (*>I<synch_print>B<)(const char *>I<data>B<, int >I<len>B<, void *>I<arg>B<), void *>I<arg>B<);> This function decodes the file I<fd> (opening I<filename> if I<fd>=-1). If its contents contain the date of the recording, you'll receive it through the callback I<synch_init_wait>. Between frames, the delay is passed through I<synch_wait>. The actual frame data goes through I<synch_print>. Note that in some formats, two or more consecutive delays or two consecutive frames can happen one after another. If you provide an arbitrary I<arg>, it will be passed to all callbacks. The function doesn't return until the end of input data. Returns 1 on success, 0 on failure. =back =head2 The following functions deal with in-memory ttyrecs: =over =item B<ttyrec ttyrec_init(tty >I<vt>B<);> An empty one is allocated. If a I<vt> is provided, it becomes the screen that the ttyrec is internally played on; otherwise, a blank 80x25 one is allocated. The I<vt> is consumed. =item B<ttyrec ttyrec_load(int >I<fd>B<, const char *>I<format>B<, const char *>I<filename>B<, tty >I<vt>B<);> This function will load a ttyrec from the file designated with I<fd>. If it's not open yet (I<fd>=-1), it will be opened with B<open_stream>. The ttyrec is played on the I<vt> you provide -- or on a new 80x25 one. =item B<void ttyrec_free(ttyrec >I<tr>B<);> Destroys the in-memory ttyrec, freeing its memory. =back You can read the ttyrec's data while it's being read; all functions are thread-safe with regard to reading. The frames are stored in structures like this: typedef struct { struct timeval t; int len; char *data; } *ttyrec_frame; =over =item B<ttyrec_frame ttyrec_seek(ttyrec >I<tr>B<, const struct timeval *>I<t>B<, tty *>I<vt>B<);> Finds the frame that should be shown at time I<*t>, or the first frame if I<t> is null. If I<vt> is not-null, it will receive a terminal containing the screen at that frame. =item B<ttyrec_frame ttyrec_next_frame(ttyrec >I<tr>B<, ttyrec_frame >I<tfv>B<);> Returns the next frame after frame I<tfv>, or null if I<tfv> was the last. =item B<void ttyrec_add_frame(ttyrec >I<tr>B<, const struct timeval *>I<delay>B<, const char *>I<data>B<, int >I<len>B<);> Creates a new frame and appends it to ttyrec I<tr>. =item B<int ttyrec_save(ttyrec >I<tr>B<, int >I<fd>B<, const char *>I<format>B<, const char *>I<filename>B<, const struct timeval *>I<selstart>B<, const struct timeval *>I<selend>B<);> Exports the ttyrec to a new file. If I<selstart> and/or I<selend> are given, they designate the part that should be exported -- if not, the whole is. =back =head2 B<struct timeval> arithmetics: A handful of macros for operating on timeval values: =over =item B<tadd(t, d)> t+=d; =item B<tsub(t, d)> t-=d; =item B<tmul1000(t, m)> t*=m/1000; =item B<tdiv1000(t, m)> t/=m/1000; =item B<tcmp(t1, t2)> If t1E<lt>t2, -1. If t1E<gt>t2, +1. 0 otherwise. =back =head1 SEE ALSO L<libtty(3)> =cut �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/doc/termcat.pod������������������������������������������������������������������������0000664�0000000�0000000�00000001143�13646775175�0016040�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������=head1 NAME termcat - convert and/or join ttyrec recordings =head1 SYNOPSIS B<termcat> I<file1> I<[file2] ...> I<outfile> =head1 DESCRIPTION B<Termcat> takes all the input recordings, concatenates them together then writes to the target file in a format you choose. For example: =over 8 termcat 1.nh.gz 2.ttyrec.bz2 combined.ttyrec.bz2 termcat telnet://towel.blinkenlights.nl starwars.ttyrec.bz2 =back Note that unlike B<cat>, the last file is output, not one of components. If you really want to send ttyrec data to stdout, use "-". =head1 SEE ALSO L<termrec(1)>, L<termplay(1)>, L<termtime(1)>. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/doc/termplay.pod�����������������������������������������������������������������������0000664�0000000�0000000�00000004170�13646775175�0016241�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������=head1 NAME termplay - replay a ttyrec "video" =head1 SYNOPSIS B<termplay> I<file> =head1 DESCRIPTION B<Termplay> can play back ttyrec recordings, like those produced by B<termrec>, B<ttyrec>, services like nethack.alt.org or crawl.akrasiacs.org and so on. Certain non-file streams can be played as well, such as: =over =item file:// =item tcp:// =item telnet:// (e.g. telnet://towel.blinkenlights.nl) =item termcast:// (e.g. termcast://termcast.org/SplatTV) =item anything directly downloadable via CURL (https://, etc) =back =head2 Keys available during replay: =over =item B<space> pause/resume =item B<enter> advance by a single frame =item B<->, B<S> slow down (by half) =item B<+>, B<F> speed up (2x, then 4x, ...) =item B<1> reset speed to 1.0 =item B<left arrow>/B<down arrow>/B<PgDn> rewind by 10sec/1min/10min =item B<right arrow>/B<up arrow>/B<PgUp> skip 10sec/1min/10min =item B<R> rewind to beginning =item B<Q> quit B<termplay> =back =head2 Options: =over =item B<-f> I<format>, B<--format> Here you specify the format. Those available are: =over =item baudrate The data will be replayed at 2400 baud. =item ttyrec Compatible with B<ttyrec> by Satoru Takabayashi. =item nh-recorder Compatible with B<nh-recorder> by Helge Dennhardt. =item dosrecorder Compatible with B<DosRecorder>. =item asciicast Compatible with B<asciinema> by Marcin Kulik, formats v1 and v2. =item live The data is assumed to be played at the same timing as it arrives. This is useful for watching termcasts, etc -- giving you the ability to rewind to an interesting moment. Trying to use this on a real file will blast its whole contents right into your face, beware! =item auto (default) This pseudo-format will make B<termplay> try to guess the format, currently only between B<ttyrec>, B<asciicast> and B<live>. Caveats about B<live> blasting the whole file right away apply! =back =item B<-s> I<X>, B<--speed> Sets the initial speed to X, a real number between 0.001 and 1000.0. =item B<-h>, B<--help> Shows a short explanation of parameters. =back =head1 SEE ALSO L<termrec(1)>, L<termcat(1)>, L<termtime(1)>. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/doc/termrec.pod������������������������������������������������������������������������0000664�0000000�0000000�00000003607�13646775175�0016051�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������=head1 NAME termrec - a tty recorder =head1 SYNOPSIS B<termrec> [B<-f> I<format>] [B<-e> I<command>] [I<outfile>] =head1 DESCRIPTION B<Termrec> is a tty recorder; it can record the output of any text mode program which you can then replay with B<termplay>, B<ttyplay>, B<ipbt>, B<ttyplayer>, B<nh-recorder>, B<asciinema> or similar. If I<outfile> ends in B<.gz>, B<.xz>, B<.bz2> or B<.zst>, the data will be appropriately compressed. If no I<outfile> is given, B<termrec> will produce a name like 2008-11-27.13-02-42.ttyrec.bz2 You can write directly to some remote URLs, such as B<tcp://>I<host>B<:>I<port> but that's usually of little use. =head2 Options: =over =item B<-f> I<format>, B<--format> You can specify a format other than ttyrec. Those available are: =over =item ansi No timing data. This is same as the output of L<script(1)>. =item ttyrec Compatible with B<ttyrec> by Satoru Takabayashi. =item nh-recorder Compatible with B<nh-recorder> by Helge Dennhardt. =item asciicast Compatible with B<asciinema> by Marcin Kulik; format v2. =item asciicast-v1 Likewise, format v1. =back =item B<-e> I<command>, B<--exec> Runs a I<command> instead of spawning a shell and records its output. =item B<-r>, B<--raw> Inhibits noting info about your terminal size and UTFness. This data is usually a good thing, but can confuse some programs. Also note that none of the formats provides a way to mark which exactly charset you use -- only if it's UTF-8 or one of ancient ones. =item B<-a>, B<--append> If the output file exists, it will be appended instead being overwritten. =item B<-h>, B<--help> Shows a short explanation of parameters. =back =head1 ENVIRONMENT =over =item SHELL Unless B<-e> is given, this will be the shell spawned, falling back to B</bin/sh> if not set. On Windows, COMSPEC is used instead. =back =head1 SEE ALSO L<termplay(1)>, L<termtime(1)>, L<termcat(1)>. �������������������������������������������������������������������������������������������������������������������������termrec-0.19/doc/termtime.pod�����������������������������������������������������������������������0000664�0000000�0000000�00000000513�13646775175�0016227�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������=head1 NAME termtime - determine the length of a ttyrec file =head1 SYNOPSIS B<termtime> I<file...> =head1 DESCRIPTION B<Termtime> tells you the length of recorded data in a ttyrec file(s). All formats and compressions supported by L<termplay(1)> are available. =head1 SEE ALSO L<termrec(1)>, L<termplay(1)>, L<termcat(1)>. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/export.h�������������������������������������������������������������������������������0000664�0000000�0000000�00000000737�13646775175�0014632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef WIN32 # define export __declspec(dllexport) # define VISIBILITY_ENABLE # define VISIBILITY_DISABLE #else #ifdef GCC_VISIBILITY # define export __attribute__ ((visibility ("default"))) # pragma GCC visibility push(hidden) # define VISIBILITY_ENABLE _Pragma("GCC visibility push(default)") # define VISIBILITY_DISABLE _Pragma("GCC visibility push(hidden)") #else # define export // we'll leak symbols... # define VISIBILITY_ENABLE # define VISIBILITY_DISABLE #endif #endif ���������������������������������termrec-0.19/get_version����������������������������������������������������������������������������0000775�0000000�0000000�00000000403�13646775175�0015400�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh v=`git describe 2>/dev/null` test -n "$v" || v=`cat VERSION 2>/dev/null` test -n "$v" || v=UNKNOWN [ ! -d .git ] || ! which git >/dev/null || { git diff-index --quiet HEAD -- || v="$v-dirty"; } [ "$1" = "-n" ] || n='\n' printf '%s'"$n" "${v##v}" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/gettext.h������������������������������������������������������������������������������0000664�0000000�0000000�00000000017�13646775175�0014764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define _(x) x �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0015113�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/Makefile.am������������������������������������������������������������������0000664�0000000�0000000�00000000402�13646775175�0017143�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBSTREAM = libstream/compress.c \ libstream/compress.h \ libstream/stream.c \ libstream/stream.h \ libstream/url_curl.c \ libstream/url_file.c \ libstream/url_tcp.c \ libstream/url_telnet.c \ libstream/url_termcast.c \ libstream/prefix.c ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/compress.c�������������������������������������������������������������������0000664�0000000�0000000�00000021476�13646775175�0017124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Compression/decompression routines #include "config.h" #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #ifdef HAVE_BZLIB_H # include <bzlib.h> #else # ifdef SHIPPED_LIBBZ2 # include SHIPPED_LIBBZ2_H # endif #endif #ifdef HAVE_ZLIB_H # include <zlib.h> #else # ifdef SHIPPED_LIBZ # include SHIPPED_LIBZ_H # endif #endif #ifdef HAVE_LZMA_H # include <lzma.h> #else # ifdef SHIPPED_LIBLZMA # include SHIPPED_LIBLZMA_H # endif #endif #ifdef HAVE_ZSTD_H # include <zstd.h> #else # ifdef SHIPPED_LIBZSTD # include SHIPPED_LIBZSTD_H # endif #endif #include "export.h" #include "compress.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE #include "stream.h" #include "error.h" #include "gettext.h" #define ERRORMSG(x) do if (write(fd,(x),strlen(x))) {} while(0) #define BUFFER_SIZE 32768 #if (defined HAVE_LIBBZ2) || (defined SHIPPED_LIBBZ2) static void read_bz2(int f, int fd, const char *arg) { BZFILE* b; int nBuf; char buf[BUFFER_SIZE]; int bzerror; b = BZ2_bzReadOpen(&bzerror, fdopen(f,"rb"), 0, 0, NULL, 0); if (bzerror != BZ_OK) { BZ2_bzReadClose(&bzerror, b); // error ERRORMSG(_("Invalid/corrupt .bz2 file.\n")); close(fd); return; } bzerror = BZ_OK; while (bzerror == BZ_OK) { nBuf = BZ2_bzRead(&bzerror, b, buf, BUFFER_SIZE); if (write(fd, buf, nBuf)!=nBuf) { BZ2_bzReadClose(&bzerror, b); close(fd); return; } } if (bzerror != BZ_STREAM_END) { BZ2_bzReadClose(&bzerror, b); // error ERRORMSG("\033[0m"); ERRORMSG(_("bzip2: Error during decompression.\n")); } else BZ2_bzReadClose(&bzerror, b); close(fd); } static void write_bz2(int f, int fd, const char *arg) { BZFILE* b; int nBuf; char buf[BUFFER_SIZE]; int bzerror; b = BZ2_bzWriteOpen(&bzerror, fdopen(f,"wb"), 9, 0, 0); if (bzerror != BZ_OK) { BZ2_bzWriteClose(&bzerror, b, 0,0,0); // error // the writer will get smitten with sigpipe close(fd); return; } bzerror = BZ_OK; while ((nBuf=read(fd, buf, BUFFER_SIZE))>0) { BZ2_bzWrite(&bzerror, b, buf, nBuf); if (bzerror!=BZ_OK) { BZ2_bzWriteClose(&bzerror, b, 0,0,0); close(fd); return; } } BZ2_bzWriteClose(&bzerror, b, 0,0,0); close(fd); } #endif #if (defined HAVE_LIBZ) || (SHIPPED_LIBZ) static void read_gz(int f, int fd, const char *arg) { gzFile g; int nBuf; char buf[BUFFER_SIZE]; g=gzdopen(f, "rb"); if (!g) { ERRORMSG(_("Invalid/corrupt .gz file.\n")); close(f); close(fd); return; } while ((nBuf=gzread(g, buf, BUFFER_SIZE))>0) { if (write(fd, buf, nBuf)!=nBuf) { gzclose(g); close(fd); return; } } if (nBuf) { ERRORMSG("\033[0m"); ERRORMSG(_("gzip: Error during decompression.\n")); } gzclose(g); close(fd); } static void write_gz(int f, int fd, const char *arg) { gzFile g; int nBuf; char buf[BUFFER_SIZE]; g=gzdopen(f, "wb9"); if (!g) { close(f); close(fd); return; } while ((nBuf=read(fd, buf, BUFFER_SIZE))>0) { if (gzwrite(g, buf, nBuf)!=nBuf) { gzclose(g); close(fd); return; } } gzclose(g); close(fd); } #endif #if (defined HAVE_LIBLZMA) || (defined SHIPPED_LIBLZMA) static void read_xz(int f, int fd, const char *arg) { uint8_t inbuf[BUFFER_SIZE], outbuf[BUFFER_SIZE]; lzma_stream xz = LZMA_STREAM_INIT; if (lzma_stream_decoder(&xz, UINT64_MAX, LZMA_CONCATENATED) != LZMA_OK) goto xz_read_end; xz.avail_in = 0; while (xz.avail_in || (xz.avail_in = read(f, (uint8_t*)(xz.next_in = inbuf), BUFFER_SIZE)) > 0) { xz.next_out = outbuf; xz.avail_out = sizeof(outbuf); if (lzma_code(&xz, LZMA_RUN) != LZMA_OK) goto xz_read_lzma_end; if (write(fd, outbuf, xz.next_out - outbuf) != xz.next_out - outbuf) goto xz_read_lzma_end; } // Flush the stream lzma_ret ret; do { xz.next_out = outbuf; xz.avail_out = sizeof(outbuf); ret = lzma_code(&xz, LZMA_FINISH); if (write(fd, outbuf, xz.next_out - outbuf) != xz.next_out - outbuf) goto xz_read_lzma_end; } while (ret == LZMA_OK); xz_read_lzma_end: lzma_end(&xz); xz_read_end: close(f); close(fd); } static void write_xz(int f, int fd, const char *arg) { uint8_t inbuf[BUFFER_SIZE], outbuf[BUFFER_SIZE]; lzma_stream xz = LZMA_STREAM_INIT; if (lzma_easy_encoder(&xz, 6, LZMA_CHECK_CRC64) != LZMA_OK) goto xz_write_end; xz.avail_in = 0; while (xz.avail_in || (xz.avail_in = read(fd, (uint8_t*)(xz.next_in = inbuf), BUFFER_SIZE)) > 0) { xz.next_out = outbuf; xz.avail_out = sizeof(outbuf); if (lzma_code(&xz, LZMA_RUN) != LZMA_OK) goto xz_write_lzma_end; if (write(f, outbuf, xz.next_out - outbuf) != xz.next_out - outbuf) goto xz_write_lzma_end; } // Flush the stream lzma_ret ret; do { xz.next_out = outbuf; xz.avail_out = sizeof(outbuf); ret = lzma_code(&xz, LZMA_FINISH); if (write(f, outbuf, xz.next_out - outbuf) != xz.next_out - outbuf) goto xz_write_lzma_end; } while (ret == LZMA_OK); xz_write_lzma_end: lzma_end(&xz); xz_write_end: close(f); close(fd); } #endif #ifdef WORKING_ZSTD static void read_zstd(int f, int fd, const char *arg) { ZSTD_inBuffer zin; ZSTD_outBuffer zout; size_t const inbufsz = ZSTD_DStreamInSize(); zin.src = malloc(inbufsz); zout.size = ZSTD_DStreamOutSize(); zout.dst = malloc(zout.size); if (!zin.src || !zout.dst) goto zstd_r_no_stream; ZSTD_DStream* const stream = ZSTD_createDStream(); if (!stream) goto zstd_r_no_stream; if (ZSTD_isError(ZSTD_initDStream(stream))) goto zstd_r_error; size_t s; while ((s = read(f, (void*)zin.src, inbufsz)) > 0) { zin.size = s; zin.pos = 0; while (zin.pos < zin.size) { zout.pos = 0; size_t w = ZSTD_decompressStream(stream, &zout, &zin); if (ZSTD_isError(w)) goto zstd_r_error; if (write(fd, zout.dst, zout.pos) != (ssize_t)zout.pos) goto zstd_r_error; } } zstd_r_error: ZSTD_freeDStream(stream); zstd_r_no_stream: free((void*)zin.src); free(zout.dst); close(f); close(fd); } static void write_zstd(int f, int fd, const char *arg) { ZSTD_inBuffer zin; ZSTD_outBuffer zout; size_t const inbufsz = ZSTD_CStreamInSize(); zin.src = malloc(inbufsz); zout.size = ZSTD_CStreamOutSize(); zout.dst = malloc(zout.size); if (!zin.src || !zout.dst) goto zstd_w_no_stream; ZSTD_CStream* const stream = ZSTD_createCStream(); if (!stream) goto zstd_w_no_stream; if (ZSTD_isError(ZSTD_initCStream(stream, 3))) goto zstd_w_error; size_t s; while ((s = read(fd, (void*)zin.src, inbufsz)) > 0) { zin.size = s; zin.pos = 0; while (zin.pos < zin.size) { zout.pos = 0; size_t w = ZSTD_compressStream(stream, &zout, &zin); if (ZSTD_isError(w)) goto zstd_w_error; if (write(f, zout.dst, zout.pos) != (ssize_t)zout.pos) goto zstd_w_error; } } zout.pos = 0; ZSTD_endStream(stream, &zout); // no way to handle an error here write(f, zout.dst, zout.pos); zstd_w_error: ZSTD_freeCStream(stream); zstd_w_no_stream: free((void*)zin.src); free(zout.dst); close(f); close(fd); } #endif compress_info compressors[]={ #if (defined HAVE_LIBZ) || (SHIPPED_LIBZ) {"gzip", ".gz", write_gz}, #endif #if (defined HAVE_LIBBZ2) || (defined SHIPPED_LIBBZ2) {"bzip2", ".bz2", write_bz2}, #endif #if (defined HAVE_LIBLZMA) || (defined SHIPPED_LIBLZMA) {"xz", ".xz", write_xz}, #endif #ifdef WORKING_ZSTD {"zstd", ".zst", write_zstd}, #endif {0, 0, 0}, }; compress_info decompressors[]={ #if (defined HAVE_LIBZ) || (SHIPPED_LIBZ) {"gzip", ".gz", read_gz}, #endif #if (defined HAVE_LIBBZ2) || (defined SHIPPED_LIBBZ2) {"bzip2", ".bz2", read_bz2}, #endif #if (defined HAVE_LIBLZMA) || (defined SHIPPED_LIBLZMA) {"xz", ".xz", read_xz}, #endif #ifdef WORKING_ZSTD {"zstd", ".zst", read_zstd}, #endif {0, 0, 0}, }; compress_info *comp_from_ext(const char *name, compress_info *ci) { for (;ci->name;ci++) if (match_suffix(name, ci->ext, 0)) return ci; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/compress.h�������������������������������������������������������������������0000664�0000000�0000000�00000000500�13646775175�0017112�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������typedef void(compress_func)(int,int,const char*); typedef struct { const char *name; const char *ext; compress_func *comp; } compress_info; extern compress_info compressors[]; extern compress_info decompressors[]; compress_info *comp_from_ext(const char *name, compress_info *ci); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/prefix.c���������������������������������������������������������������������0000664�0000000�0000000�00000000653�13646775175�0016560�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <strings.h> #include <string.h> #include "export.h" #include "stream.h" int match_suffix(const char *txt, const char *ext, int skip) { int tl,el; tl=strlen(txt); el=strlen(ext); if (tl-el-skip<0) return 0; txt+=tl-el-skip; return !strncasecmp(txt, ext, el); } int match_prefix(const char *txt, const char *ext) { return !strncasecmp(txt, ext, strlen(ext)); } �������������������������������������������������������������������������������������termrec-0.19/libstream/stream.c���������������������������������������������������������������������0000664�0000000�0000000�00000006710�13646775175�0016556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string.h> #include <unistd.h> #include "config.h" #include "compat.h" #include "error.h" #include "threads.h" #include "export.h" #include "compress.h" #include "stream.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE // disabled: #ifdef HAVE_FORK #if 0 int filter(void func(int,int,const char*), int fd, int wr, const char *arg, const char **error) { int p[2]; if (pipe(p)) { close(fd); return -1; } switch (fork()) { case -1: *error="fork() failed"; close(fd); close(p[0]); close(p[1]); return -1; case 0: close(p[wr]); func(fd, p[!wr], arg); exit(0); default: close(p[!wr]); } return p[wr]; } #else struct filterdata { int fdin, fdout; void (*func)(int,int,const char*); const char *arg; }; static int nstreams=-1; static cond_t exitcond; static mutex_t nsm; static void filterthr(struct filterdata *args) { int fdin, fdout; void (*func)(int,int,const char*); const char *arg; fdin=args->fdin; fdout=args->fdout; func=args->func; arg=args->arg; free(args); func(fdin, fdout, arg); mutex_lock(nsm); if (!--nstreams) cond_wake(exitcond); mutex_unlock(nsm); } static void finish_up(void) { mutex_lock(nsm); while (nstreams) { cond_wait(exitcond, nsm); } mutex_unlock(nsm); } #ifdef IS_WIN32 // Because of a bug in Windows' atexit, we need to export this function // then call it manually from users. export void reap_streams(void) { finish_up(); } #endif int filter(void func(int,int,const char*), int fd, int wr, const char *arg, const char **error) { int p[2]; struct filterdata *fdata; thread_t th; if (pipe(p)) goto failpipe; if (!(fdata=malloc(sizeof(struct filterdata)))) goto failfdata; fdata->fdin=fd; fdata->fdout=p[!wr]; fdata->func=func; fdata->arg=arg; if (nstreams==-1) { mutex_init(nsm); cond_init(exitcond); nstreams=0; atexit(finish_up); } mutex_lock(nsm); if (thread_create_detached(&th, filterthr, fdata)) goto failthread; nstreams++; mutex_unlock(nsm); return p[wr]; failthread: *error="Couldn't create thread"; mutex_unlock(nsm); free(fdata); failfdata: close(p[0]); close(p[1]); failpipe: close(fd); return -1; } #endif export int open_stream(int fd, const char* url, int mode, const char **error) { int wr= !!(mode&SM_WRITE); compress_info *ci; const char *dummy; if (fd==-1) { if (!url) return -1; if (!error) error=&dummy; if (!strcmp(url, "-")) fd=dup(wr? 1 : 0); else if (match_prefix(url, "file://")) fd=open_file(url+7, mode, error); else if (match_prefix(url, "tcp://")) fd=open_tcp(url+6, mode, error); else if (match_prefix(url, "telnet://")) fd=open_telnet(url+9, mode, error); else if (match_prefix(url, "termcast://")) fd=open_termcast(url+11, mode, error); #ifdef HAVE_CURL_CURL_H else if (strstr(url, "://")) fd=open_curl(url, mode, error); #endif else fd=open_file(url, mode, error); } if (fd==-1) return -1; ci=comp_from_ext(url, wr? compressors : decompressors); if (!ci) return fd; return filter(ci->comp, fd, wr, 0, error); } ��������������������������������������������������������termrec-0.19/libstream/stream.h���������������������������������������������������������������������0000664�0000000�0000000�00000001302�13646775175�0016553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������int open_curl(const char* url, int mode, const char **error); int open_file(const char* url, int mode, const char **error); int open_tcp(const char* url, int mode, const char **error); int open_telnet(const char* url, int mode, const char **error); int open_termcast(const char* url, int mode, const char **error); int match_suffix(const char *txt, const char *ext, int skip); int match_prefix(const char *txt, const char *ext); int filter(void func(int,int,const char*), int fd, int wr, const char *arg, const char **error); int connect_tcp(const char *url, int port, const char **rest, const char **error); void telnet(int sock, int fd, const char *arg); #ifdef IS_WIN32 void reap_streams(void); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/url_curl.c�������������������������������������������������������������������0000664�0000000�0000000�00000004113�13646775175�0017105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #ifdef HAVE_CURL_CURL_H #include <unistd.h> #include <curl/curl.h> #include "export.h" #include "stream.h" #include "compat.h" #include "gettext.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE #define USER_AGENT "libtermrec/"PACKAGE_VERSION static void curl_r(int in, int out, const char *arg) { CURL *curl_handle; CURLcode res; FILE *f = fdopen(out, "w"); if (!f) return close(out), (void)0; curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_URL, arg); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)f); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, USER_AGENT); res = curl_easy_perform(curl_handle); if (res != CURLE_OK) fprintf(f, "CURL failed: %s\n", curl_easy_strerror(res)); curl_easy_cleanup(curl_handle); fclose(f); } static void curl_w(int in, int out, const char *arg) { CURL *curl_handle; CURLcode res; FILE *f = fdopen(out, "r"); if (!f) return close(out), (void)0; curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_URL, arg); curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, 1); curl_easy_setopt(curl_handle, CURLOPT_READDATA, (void *)f); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, USER_AGENT); res = curl_easy_perform(curl_handle); if (res != CURLE_OK) fprintf(f, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); curl_easy_cleanup(curl_handle); fclose(f); } int open_curl(const char* url, int mode, const char **error) { if (mode == SM_REPREAD) { *error = "Watching CURL URLs is not (yet?) supported."; return -1; } else if (mode == SM_APPEND) { // There's CURLOPT_APPEND but it says it's for FTP only, FTP is dead. *error = "Appending via CURL is not (yet?) supported."; return -1; } if (mode&SM_WRITE) return filter(curl_w, -1, 1, url, error); else return filter(curl_r, -1, 0, url, error); } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/url_file.c�������������������������������������������������������������������0000664�0000000�0000000�00000001525�13646775175�0017063�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include "error.h" #include "export.h" #include "stream.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE #include "compat.h" int open_file(const char* url, int mode, const char **error) { int fmode, fd; switch (mode) { case SM_READ: fmode=O_RDONLY; break; case SM_WRITE: fmode=O_WRONLY|O_CREAT|O_TRUNC; break; case SM_REPREAD: fmode=O_RDONLY; break; case SM_APPEND: fmode=O_WRONLY|O_APPEND|O_CREAT; break; default: *error="unknown file mode in open_stream(file://)"; return -1; } if ((fd=open(url, fmode|O_BINARY, 0666))==-1) *error=strerror(errno); return fd; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/url_tcp.c��������������������������������������������������������������������0000664�0000000�0000000�00000007416�13646775175�0016737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #ifdef HAVE_NETDB_H # include <netdb.h> #endif #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif #include <string.h> #include <errno.h> #include "export.h" #include "stream.h" #include "compat.h" #include "gettext.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE // The "host" arg will be modified! // "port" can be overridden with : // Returns: error message, 0 on success. static const char *resolve_host(char *host, int port, struct addrinfo **ai) { long i; char *cp; int err; struct addrinfo hints; char portstr[10]; // free the hostname from IPv6-style trappings: [::1] -> ::1 if (*host=='[') { host++; cp=strchr(host, ']'); if (!cp) return _("Unmatched [ in the host part."); *cp++=0; if (*cp) { if (*cp==':') goto getrport; else return _("Cruft after the [host name]."); // IPv6-style host name } } // extract :port if ((cp=strrchr(host, ':'))) { getrport: *cp=0; cp++; i=strtoul(cp, &cp, 10); if (*cp || !i || i>65535) return _("Invalid port number"); port=i; } else if (port<=0) return _("No port number given"); memset(&hints, 0, sizeof(hints)); hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; hints.ai_flags=AI_ADDRCONFIG|AI_NUMERICSERV; sprintf(portstr, "%u", port); if ((err=getaddrinfo(host, portstr, &hints, ai))) { if (err==EAI_NONAME) return _("No such host"); else return gai_strerror(err); } return 0; } static int connect_out(struct addrinfo *ai) { struct addrinfo *addr; int sock; for (addr=ai; addr; addr=addr->ai_next) { if ((sock=socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol))==-1) continue; intr: if ((connect(sock, addr->ai_addr, addr->ai_addrlen))) if (errno == EINTR) goto intr; else continue; return sock; } return -1; // errno will be valid here } #if IS_WIN32 // workaround socket!=file brain damage static void sock2file(int sock, int file, const char *arg) { char buf[BUFSIZ]; int len; if (arg) { while ((len=read(file, buf, BUFSIZ))>0) if (send(sock, buf, len, 0)!=len) break; } else { while ((len=recv(sock, buf, BUFSIZ, 0))>0) if (write(file, buf, len)!=len) break; } closesocket(sock); close(file); } #endif int connect_tcp(const char *url, int port, const char **rest, const char **error) { char host[128], *cp; struct addrinfo *ai; int fd; if ((cp=strchr(url, '/'))) { snprintf(host, sizeof(host), "%.*s", (int)(cp-url), url); *rest=cp; } else { snprintf(host, sizeof(host), "%s", url); *rest=""; } if ((*error=resolve_host(host, port, &ai))) return -1; if ((fd=connect_out(ai))==-1) *error=strerror(errno); freeaddrinfo(ai); return fd; } int open_tcp(const char* url, int mode, const char **error) { int fd; const char *rest; if ((fd=connect_tcp(url, 0, &rest, error))==-1) return -1; // we may write the rest of the URL to the socket here ... // no bidi streams if (mode&SM_WRITE) shutdown(fd, SHUT_RD); else shutdown(fd, SHUT_WR); #ifdef IS_WIN32 fd=filter(sock2file, fd, !!(mode&SM_WRITE), (mode&SM_WRITE)?"":0, error); #endif return fd; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libstream/url_telnet.c�����������������������������������������������������������������0000664�0000000�0000000�00000011757�13646775175�0017447�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <unistd.h> #include <sys/types.h> #ifdef HAVE_NETDB_H # include <netdb.h> #endif #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif #include "export.h" #include "stream.h" #include "gettext.h" #include "compat.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE #define EOR 239 // End of Record #define SE 240 // subnegotiation end #define NOP 241 // no operation #define DM 242 // Data Mark #define BRK 243 // Break #define IP 244 // interrupt process #define AO 245 // abort output #define AYT 246 // Are you there? #define EC 247 // erase character #define EL 248 // erase line #define GA 249 // go ahead #define SB 250 // subnegotiations #define WILL 251 #define WONT 252 #define DO 253 #define DONT 254 #define IAC 255 // interpret as command #define ECHO 1 #define SUPPRESS_GO_AHEAD 3 #define STATUS 5 #define TERMINAL_TYPE 24 #define END_OF_RECORD 25 #define NAWS 31 #define IS 0 #define SEND 1 void telnet(int sock, int fd, const char *arg) { int state,will=0 /*lint food*/,sublen=0; ssize_t cnt; unsigned char buf[BUFSIZ],out[BUFSIZ],*bp,*op,neg[3]; neg[0]=IAC; state=0; while ((cnt=recv(sock, (char*)buf, BUFSIZ, 0))>0) { bp=buf; op=out; while (cnt--) { switch (state) { default: // normal switch (*bp) { case IAC: // IAC = start a TELNET sequence bp++; state=1; break; default: *op++=*bp++; } break; case 1: // IAC switch (*bp) { case IAC: // IAC IAC = literal 255 byte bp++; *op++=255; state=0; break; case WILL: case WONT: case DO: case DONT: // IAC WILL/WONT/DO/DONT x = negotiating option x will=*bp; bp++; state=2; break; case SB: // IAC SB x = subnegotiations of option x bp++; state=3; break; default: bp++; state=0; } break; case 2: // IAC WILL/WONT/DO/DONT neg[2]=*bp; switch (*bp) { case ECHO: switch (will) { case WILL: neg[1]=DO; break; // makes servers happy case DO: neg[1]=WONT; break; case WONT: neg[1]=DONT; break; case DONT: neg[1]=WONT; break; } break; case SUPPRESS_GO_AHEAD: switch (will) { case WILL: neg[1]=DO; break; case DO: neg[1]=WILL; break; case WONT: neg[1]=DONT; break; case DONT: neg[1]=WONT; break; } break; default: switch (will) { case WILL: neg[1]=DONT; break; case DO: neg[1]=WONT; break; case WONT: neg[1]=DONT; break; case DONT: neg[1]=WONT; break; } } send(sock, (char*)neg, 3, 0); bp++; state=0; break; case 3: // IAC SB bp++; state=4; sublen=0; break; case 4: // IAC SB x ... if (*bp++==IAC) state=5; else if (sublen++>=64) // probably an unterminated sequence state=0; else state=4; break; case 5: // IAC SB x ... IAC if (*bp++==SE) state=0; else state=4; } } if (write(fd, (char*)out, op-out)!=op-out) break; } close(sock); close(fd); } int open_telnet(const char* url, int mode, const char **error) { int fd; const char *rest; if (mode&SM_WRITE) { *error="Writing to telnet streams is not supported (yet?)"; return -1; } fd=connect_tcp(url, 23, &rest, error); if (fd==-1) return -1; // we may write the rest of the URL to the socket here ... return filter(telnet, fd, !!(mode&SM_WRITE), 0, error); } �����������������termrec-0.19/libstream/url_termcast.c���������������������������������������������������������������0000664�0000000�0000000�00000007615�13646775175�0017774�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "export.h" #include "stream.h" #include "gettext.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE #define EAT_COLOUR \ if (*rp=='\e') \ { \ rp++; \ if (*rp++!='[') \ return 0; \ while ((*rp>='0' && *rp<='9') || *rp==';') \ rp++; \ if (*rp++!='m') \ return 0; \ } static int match(const char *rp, const char *rest) { // pattern is /\r\n\e\[\d+d ([a-z])\) $rest (\e\[[0-9;]*m)?\(/ char res; if (*rp++!='\r') return 0; if (*rp++!='\n') return 0; if (*rp++!='\e') return 0; if (*rp++!='[') return 0; while (*rp>='0' && *rp<='9') rp++; if (*rp++!='d') return 0; if (*rp==' ') rp++; res=*rp++; if (*rp++!=')') return 0; if (*rp++!=' ') return 0; EAT_COLOUR; while (*rest) if (*rp++!=*rest++) return 0; EAT_COLOUR; if (*rp++!=' ') return 0; EAT_COLOUR; if (*rp++!='(') return 0; return res; } struct filterarg { int sock; char *rest; }; static void termcast(int in, int out, const char *arg) { char buf[BUFSIZ+64], *cp, ses; char *rp; // potential \r int len, inbuf; int sock=((struct filterarg *)arg)->sock; char *rest=((struct filterarg *)arg)->rest; free((char*)arg); inbuf=0; rp=buf; while (1) { if (rp!=buf) { memmove(buf, rp, buf-rp+inbuf); inbuf-=rp-buf; rp=buf; } else if (inbuf>BUFSIZ/2) { memcpy(buf, buf+(inbuf+1)/2, inbuf/2); inbuf/=2; } len=read(in, buf+inbuf, BUFSIZ-inbuf); if (len<=0) { if (len<0 && errno) len=snprintf(buf, BUFSIZ, "\e[0m%s\n", strerror(errno)); else len=snprintf(buf, BUFSIZ, "\e[0m%s\n", _("Input terminated.")); if (write(out, buf, len)) {}; // ignore the result, we're failing already free(rest); goto end; } if (write(out, buf+inbuf, len) != len) { free(rest); goto end; } inbuf+=len; memset(buf+inbuf, 0, 64); // try screen-scraping cp=rp; do if ((ses=match(cp, rest))) goto found; while ((cp=strchr((rp=cp)+1, '\r'))); // TODO: press space every some time } found: free(rest); if (write(sock, &ses, 1) != 1) return; while ((len=read(in, buf, BUFSIZ))>0) if (write(out, buf, len)!=len) break;; // Alas, there's no real way to detect when the session ends, other // than a server disconnect. end: close(sock); close(out); } int open_termcast(const char* url, int mode, const char **error) { int fd, fdmid; const char *rest; if (mode&SM_WRITE) { *error="Writing to termcast streams is not supported (yet?)"; return -1; } if ((fd=connect_tcp(url, 23, &rest, error))==-1) return -1; if (!rest || *rest++!='/' || !*rest) { close(fd); *error=_("What termcast session to look for?"); return -1; } if ((fdmid=filter(telnet, fd, !!(mode&SM_WRITE), 0, error))==-1) return -1; struct filterarg *fa = malloc(sizeof(struct filterarg)); fa->sock=fd; fa->rest=strdup(rest); return filter(termcast, fdmid, !!(mode&SM_WRITE), (const char*)fa, error); } �������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/��������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014440�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/Makefile.am���������������������������������������������������������������������0000664�0000000�0000000�00000001143�13646775175�0016473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������lib_LTLIBRARIES = libtty.la libtty_la_SOURCES = $(LIBSTREAM) \ libtty/tty.c \ libtty/charsets.c \ libtty/charsets.h \ libtty/wcwidth.c \ libtty/wcwidth.h \ libtty/colors.c \ libtty/formats.c \ libtty/formats.h \ libtty/timeline.c \ libtty/files.c \ libtty/vtredir.c \ libtty/asciicast.c \ libtty/dosrecorder.c libtty_la_LIBADD = libcompat.la libttyutils.la @LIBBZ2@ @LIBZ@ @LIBLZMA@ @LIBZSTD@ libtty_la_LDFLAGS = -no-undefined -version-info 1 #disabled: if !HAVE_FORK libtty_la_LIBADD += @PTHREAD_LIBS@ libtty_la_LDFLAGS += @PTHREAD_CFLAGS@ #endif include_HEADERS = libtty/tty.h libtty/ttyrec.h �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/asciicast.c���������������������������������������������������������������������0000664�0000000�0000000�00000033626�13646775175�0016561�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include "_stdint.h" #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "gettext.h" #include "tty.h" #include "ttyrec.h" #include "formats.h" #include "export.h" /*******************/ /***** reading *****/ /*******************/ // Blasting many pages in a single frame is borderline legitimate, but let's // have a sanity limit -- data that was actually recorded into separate // frames with tiny but non-zero delays. // Incidentally, this also allows avoiding managing a dynamic buffer. // 1M is way too high but userspace stack is aplenty. #define BUFFER_SIZE 1048576 // Reimplement stdio's FILE with only getc() and ungetc() methods -- all this // needed only because multiple ungetcs don't work, especially not if the file // had been read() before. #define NIH_FILE_BUFFER 4096 #define NIH_NO_UNGET -2 struct nih_file { int fd; int unget; int pos; int len; char buf[NIH_FILE_BUFFER]; }; typedef struct nih_file NIH_FILE; static int nih_getc(NIH_FILE *f) { if (f->unget != NIH_NO_UNGET) { int c = f->unget; f->unget = NIH_NO_UNGET; return c; } if (f->pos>=f->len) { f->len = read(f->fd, f->buf, NIH_FILE_BUFFER); if (f->len<=0) return EOF; f->pos = 0; } return (unsigned char)f->buf[f->pos++]; } static void nih_ungetc(int c, NIH_FILE *f) { f->unget = c; } #undef getc #undef ungetc #define getc(f) nih_getc(f) #define ungetc(c,f) nih_ungetc(c,f) #define EAT(x) do c=getc(f); while (c==' ' || c=='\t' || c=='\r' || c=='\n' x) static bool eat_colon(NIH_FILE *f) { int c; EAT(); if (c != ':') return false; EAT(); ungetc(c, f); return true; } static int64_t eat_int(NIH_FILE *f) { int64_t x=0; while (1) { int c=getc(f); if (c>='0' && c<='9') x=x*10+c-'0'; else { ungetc(c, f); return x; } } } // *1000000 static int64_t eat_float(NIH_FILE *f) { int c; int64_t x=0; c=getc(f); while (c>='0' && c<='9') x=x*10+c-'0', c=getc(f); x*=1000000; if (c=='.') { int y=1000000; c=getc(f); while (c>='0' && c<='9') x+= (c-'0')*(y/=10), c=getc(f); } if (c=='e' || c=='E') { bool minus=false; c=getc(f); if (c=='+') c=getc(f); else if (c=='-') c=getc(f), minus=true; int e=0; while (c>='0' && c<='9') e=e*10+c-'0', c=getc(f); if (minus) while (e-->0) x/=10; else while (e-->0) x*=10; } ungetc(c, f); return x; } static int eat_hexdigit(NIH_FILE *f) { int c=getc(f); if (c>='0' && c<='9') return c-'0'; if (c>='a' && c<='f') return c+10-'a'; if (c>='A' && c<='F') return c+10-'A'; ungetc(c, f); return -1; } #define OUT(x) do if (--spc) *buf++=(x); else goto end; while (0) static char* eat_string(NIH_FILE *f, char *buf) { int spc=BUFFER_SIZE; uint16_t surrogate=0; while (1) { int c=getc(f); if (c==EOF || c=='"') break; if (c!='\\') OUT(c); else switch (c=getc(f)) { case 'b': OUT('\b'); break; case 'f': OUT('\f'); break; case 'n': OUT('\n'); break; case 'r': OUT('\r'); break; case 't': OUT('\t'); break; case 'u': c = eat_hexdigit(f)<<12 | eat_hexdigit(f)<<8 | eat_hexdigit(f)<<4 | eat_hexdigit(f); if (c < 0) // not a valid 16-bit hex value break; if (c < 0x80) OUT(c); else if (c < 0x800) { OUT(0xc0|c>>6); OUT(0x80|c&0x3f); } else if (c < 0xD800 || c > 0xDFFF) { OUT(0xe0|c>>12); OUT(0x80|c>>6&0x3f); OUT(0x80|c&0x3f); } // Note: we allow erroneous surrogate pairs separated by // something, silently ignore lone lead or trailing ones. else if (c < 0xDC00) surrogate = c; else if (surrogate) { c=((uint32_t)surrogate)<<10&0xffc00|c&0x3ff; c+=0x10000; OUT(0xf0|c>>18); OUT(0x80|c>>12&0x3f); OUT(0x80|c>>6&0x3f); OUT(0x80|c&0x3f); surrogate=0; } break; case '"': case '\\': case '/': default: OUT(c); break; } } end: *buf=0; return buf; } #define FAIL(x) do {const char* t=(x);return synch_print(t, strlen(t), arg);} while (0) void do_play_asciicast(int fd, const char *obuf, int olen, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { NIH_FILE nih_f, *f=&nih_f; nih_f.fd=fd; nih_f.unget=NIH_NO_UNGET; nih_f.pos=nih_f.len=0; if (obuf) { memcpy(nih_f.buf, obuf, olen); nih_f.len = olen; } char buf[BUFFER_SIZE]; int bracket_level = 0; int version = -1; int c; int sx=80, sy=25; struct timeval tv; tv.tv_sec = tv.tv_usec = 0; EAT(); if (c != '{') FAIL("Not an asciicast: doesn't start with a JSON object.\n"); // Read the header. while (1) { expect_field: switch (c = getc(f)) { case EOF: FAIL("Not an asciicast: end of file within header.\n"); case ' ': case '\t': case '\r': case '\n': continue; case '"': eat_string(f, buf); if (!eat_colon(f)) FAIL("Not an asciicast: no colon after field name.\n"); if (bracket_level) { skip_field: EAT(); if (c==EOF) FAIL("Not an asciicast: end of file within header.\n"); else if (c=='"') eat_string(f, buf); else if (c>='0' && c<='9') ungetc(c, f), eat_float(f); else if (c=='{') { bracket_level++; goto expect_field; } else if (c=='n' && (c=getc(f))=='u' && (c=getc(f))=='l' && (c=getc(f))=='l') {} else FAIL("Not an asciicast: junk within header.\n"); } else if (!strcmp(buf, "version")) { int64_t v = eat_int(f); if (v == 1 || v == 2) version = v; else FAIL("Unsupported asciicast version.\n"); } else if (!strcmp(buf, "width")) sx = eat_int(f); else if (!strcmp(buf, "height")) sy = eat_int(f); else if (!strcmp(buf, "timestamp")) { int64_t v = eat_float(f); tv.tv_sec = v/1000000; tv.tv_usec = v%1000000; } else if (version == 1 && !strcmp(buf, "stdout")) { if (getc(f) != '[') FAIL("Not an asciicast: v1 stdout not an array.\n"); goto body; } else goto skip_field; EAT(); if (c == '}') { bracket_level--; EAT(); } if (c == '}') { ungetc(c, f); goto expect_field; } if (c == '[' && bracket_level == -1) { ungetc(c, f); goto body; } if (c != ',') FAIL("Not an asciicast: junk after a JSON field.\n"); break; case '}': if (version == 2 && !bracket_level) goto body; bracket_level--; break; default: FAIL("Not an asciicast: bad header.\n"); } } /* not reached */ body: synch_init_wait(&tv, arg); synch_print(buf, sprintf(buf, "\e%%G\e[8;%d;%dt", sy, sx), arg); uint64_t old_delay = 0; while (1) { EAT(|| c==','); if (c == EOF || c == '}' || c == ']') return; if (c != '[') FAIL("Malformed asciicast: frame not an array.\n"); EAT(); if (c>='0' && c<='9') ungetc(c, f); else FAIL("Malformed asciicast: expected duration.\n"); int64_t delay = eat_float(f); if (version == 2) { delay -= old_delay; old_delay += delay; } tv.tv_sec = delay/1000000; tv.tv_usec = delay%1000000; synch_wait(&tv, arg); EAT(); if (c != ',') FAIL("Malformed asciicast: no comma after duration.\n"); if (version == 2) { EAT(); if (c != '"') FAIL("Malformed asciicast: expected event type.\n"); eat_string(f, buf); EAT(); if (c != ',') FAIL("Malformed asciicast: no comma after event type.\n"); } EAT(); if (c !='"') FAIL("Malformed asciicast: expected even-data string.\n"); synch_print(buf, eat_string(f, buf) - buf, arg); EAT(); if (c !=']') FAIL("Malformed asciicast: event not terminated.\n"); } } void play_asciicast(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { do_play_asciicast(fileno(f), 0, 0, synch_init_wait, synch_wait, synch_print, arg, cont); } /*******************/ /***** writing *****/ /*******************/ struct ac_state { bool head_done; bool need_comma; char version; char putf[4]; struct timeval ts; }; void* record_asciicast_init(FILE *f, const struct timeval *tm) { struct ac_state *as = malloc(sizeof(struct ac_state)); as->head_done = false; as->need_comma = false; if (tm) as->ts = *tm; else as->ts.tv_sec=as->ts.tv_usec = 0; as->putf[0] = 0; as->version = 2; return as; } #define WANT(x) if (!len-- || *b++!=(x)) return 0 static int skip_utf_term_size(const char *b, int len) { const char *buf0 = b; WANT('\e'); WANT('%'); WANT('G'); WANT('\e'); WANT('['); WANT('8'); WANT(';'); while (len && *b>='0' && *b<='9') len--, b++; WANT(';'); while (len && *b>='0' && *b<='9') len--, b++; WANT('t'); return b-buf0; } #undef WANT static int skip_partial_utf(const char *b, int len) { int part=0; while (part<4 && part<len && ((unsigned char)b[len-part-1])>=0x80 && ((unsigned char)b[len-part-1])<0xc0) part++; if (part>=len) return 0; char c = b[len-++part]; if ((c&0xe0)==0xc0 && part<2) return part; if ((c&0xf0)==0xe0 && part<3) return part; if ((c&0xf8)==0xf0 && part<4) return part; return 0; } void record_asciicast(FILE *f, void* state, const struct timeval *tm, const char *buf, int len) { struct ac_state *as = state; if (!as->head_done) { // need to play first frame to fetch screen size tty vt = tty_init(80, 25, 1); tty_write(vt, buf, len); fprintf(f, "{\"version\":%d, \"width\":%d, \"height\":%d", as->version, vt->sx, vt->sy); if (as->ts.tv_sec) fprintf(f, ", \"timestamp\":%ld", as->ts.tv_sec); if (as->version == 1) fprintf(f, ", \"stdout\":[\n"); else fprintf(f, "}\n"); tty_free(vt); as->head_done = true; int skip = skip_utf_term_size(buf, len); buf+=skip; if (!(len-=skip)) return; } char *buf2 = 0; int skip = strlen(as->putf); if (skip) if ((buf2 = malloc(skip + len))) { memcpy(buf2, as->putf, skip); memcpy(buf2+skip, buf, len); buf = buf2; len+=skip; } else return; skip = skip_partial_utf(buf, len); len-=skip; memcpy(as->putf, buf+len, skip); as->putf[skip]=0; if (!len) return; if (as->version == 1) { if (as->need_comma) fprintf(f, ",\n"); else as->need_comma = true; struct timeval ts = *tm; if (as->ts.tv_sec || as->ts.tv_usec) tsub(ts, as->ts); else ts.tv_sec = ts.tv_usec = 0; as->ts = *tm; fprintf(f, "[%f, \"", ts.tv_sec+ts.tv_usec*0.000001); } else fprintf(f, "[%f, \"o\", \"", tm->tv_sec-as->ts.tv_sec+tm->tv_usec*0.000001); while (len-->0) { if (((unsigned char)*buf)<' ') if (*buf=='\r') fputs("\\r", f); else if (*buf=='\n') fputs("\\n", f); else fprintf(f, "\\u%04x", *buf); else if (*buf=='"') fputs("\\\"", f); else fputc(*buf, f); buf++; } fprintf(f, as->version==1? "\"]" : "\"]\n"); if (buf2) free(buf2); } void record_asciicast_finish(FILE *f, void* state) { struct ac_state *as = state; if (as->version == 1) fprintf(f, "\n]}\n"); free(state); } void* record_asciicast_v1_init(FILE *f, const struct timeval *tm) { struct ac_state *as = record_asciicast_init(f, tm); as->version=1; return as; } ����������������������������������������������������������������������������������������������������������termrec-0.19/libtty/charsets.c����������������������������������������������������������������������0000664�0000000�0000000�00000006521�13646775175�0016424�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include "export.h" #include "charsets.h" unsigned short charset_vt100[128] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f, 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0, 0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020, }; unsigned short charset_cp437[256] = { 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0, }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/charsets.h����������������������������������������������������������������������0000664�0000000�0000000�00000003611�13646775175�0016426�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������extern unsigned short charset_vt100[128]; extern unsigned short charset_cp437[256]; // TF8, the "tf" in "utf8" #define TF8(vb, uv) do \ { \ if ((uv)<0x80) \ { \ *(vb)++=(uv); \ } \ else if ((uv) < 0x800) { \ *(vb)++ = ( (uv) >> 6) | 0xc0; \ *(vb)++ = ( (uv) & 0x3f) | 0x80; \ } \ else if ((uv) < 0x10000) { \ *(vb)++ = ( (uv) >> 12) | 0xe0; \ *(vb)++ = (((uv) >> 6) & 0x3f) | 0x80; \ *(vb)++ = ( (uv) & 0x3f) | 0x80; \ } \ else /*if ((uv) < 0x200000)*/ { \ *(vb)++ = ( (uv) >> 18) | 0xf0; \ *(vb)++ = (((uv) >> 12) & 0x3f) | 0x80; \ *(vb)++ = (((uv) >> 6) & 0x3f) | 0x80; \ *(vb)++ = ( (uv) & 0x3f) | 0x80; \ } \ } while (0) #if 0 // we do only Unicode, not full TF8 else if ((uv) < 0x4000000) { \ *(vb)++ = ( (uv) >> 24) | 0xf8; \ *(vb)++ = (((uv) >> 18) & 0x3f) | 0x80; \ *(vb)++ = (((uv) >> 12) & 0x3f) | 0x80; \ *(vb)++ = (((uv) >> 6) & 0x3f) | 0x80; \ *(vb)++ = ( (uv) & 0x3f) | 0x80; \ } \ else if ((uv) < 0x80000000) { \ *(vb)++ = ( (uv) >> 30) | 0xfc; \ *(vb)++ = (((uv) >> 24) & 0x3f) | 0x80; \ *(vb)++ = (((uv) >> 18) & 0x3f) | 0x80; \ *(vb)++ = (((uv) >> 12) & 0x3f) | 0x80; \ *(vb)++ = (((uv) >> 6) & 0x3f) | 0x80; \ *(vb)++ = ( (uv) & 0x3f) | 0x80; \ } #endif �����������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/colors.c������������������������������������������������������������������������0000664�0000000�0000000�00000005771�13646775175�0016117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include "tty.h" #include "export.h" #define R(x) ((uint8_t)((x)>>16)) #define G(x) ((uint8_t)((x)>> 8)) #define B(x) ((uint8_t) (x) ) static uint32_t col256_to_rgb(uint32_t i) { i &= 0xff; // Standard colours. if (i < 16) { if (i == 3) return 0xaa5500; // real CGA/VGA special-cases brown int c = (i&1 ? 0xaa0000 : 0x000000) | (i&2 ? 0x00aa00 : 0x000000) | (i&4 ? 0x0000aa : 0x000000); return (i >= 8) ? c + 0x555555 : c; } // 6x6x6 colour cube. else if (i < 232) { i -= 16; int r = i / 36, g = i / 6 % 6, b = i % 6; return (r ? r * 0x280000 + 0x370000 : 0) | (g ? g * 0x002800 + 0x003700 : 0) | (b ? b * 0x000028 + 0x000037 : 0); } // Grayscale ramp. else // i < 256 return (i * 10 - 2312) * 0x010101; } static int sqrd(unsigned char a, unsigned char b) { int _ = ((int)a) - ((int)b); return (_>=0)?_:-_;; } #if 0 // brightness formula static uint32_t rgb_diff(uint32_t x, uint32_t y) { return 2*sqrd(R(x), R(y)) + 3*sqrd(G(x), G(y)) + 1*sqrd(B(x), B(y)); } #else // Riermersma's formula static uint32_t rgb_diff(uint32_t x, uint32_t y) { int rm = (R(x)+R(y))/2; return 2*sqrd(R(x), R(y)) + 4*sqrd(G(x), G(y)) + 3*sqrd(B(x), B(y)) + rm*(sqrd(R(x), R(y))-sqrd(B(x), B(y)))/256; } #endif static uint32_t rgb_to_16(uint32_t c) { uint8_t max = R(c); if (max < G(c)) max = G(c); if (max < B(c)) max = B(c); uint8_t hue = 0; if (R(c) > max/2+32) hue|=1; if (G(c) > max/2+32) hue|=2; if (B(c) > max/2+32) hue|=4; if (hue == 7 && max <= 0x70) return 8; return (max > 0xc0) ? hue|8 : hue; } static uint32_t m6(uint32_t x) { x = (x+5)/40; return x? x-1 : 0; } static uint32_t rgb_to_color_cube(uint32_t c) { return 16 + m6(R(c))*36 + m6(G(c))*6 + m6(B(c)); } static uint32_t rgb_to_grayscale_gradient(uint32_t c) { int x = 232 + (R(c)*2 + G(c)*3 + B(c)) / 60; return (x > 255)? 255 : x; } static uint32_t rgb_to_256(uint32_t c) { uint32_t c1 = rgb_to_16(c); uint32_t bd = rgb_diff(c, col256_to_rgb(c1)); uint32_t res = c1; uint32_t c2 = rgb_to_color_cube(c); uint32_t d = rgb_diff(c, col256_to_rgb(c2)); if (d < bd) bd = d, res = c2; uint32_t c3 = rgb_to_grayscale_gradient(c); d = rgb_diff(c, col256_to_rgb(c3)); if (d < bd) res = c3; return res; } export uint32_t tty_color_convert(uint32_t c, uint32_t to) { if (!to) return 0; uint32_t from = (c&VT100_ATTR_COLOR_TYPE)>>24; if (to > 3) to>>=24; if (from == to) return c; if (from==1 && to==2) return c; if (from==1 || from==2) c = col256_to_rgb(c); switch (to) { case 1: return rgb_to_16(c); case 2: return rgb_to_256(c); case 3: return c; default: return 0; } } �������termrec-0.19/libtty/dosrecorder.c�������������������������������������������������������������������0000664�0000000�0000000�00000012607�13646775175�0017125�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #ifdef HAVE_ZLIB_H # include <zlib.h> #else # ifdef SHIPPED_LIBZ # include SHIPPED_LIBZ_H # endif #endif #include <string.h> #include <stdio.h> #include <unistd.h> #include "_stdint.h" #include "gettext.h" #include "export.h" #include "formats.h" #include "charsets.h" #if (defined HAVE_LIBZ) || (SHIPPED_LIBZ) // format: dosrecorder #define MAXSCREENS 256 typedef struct { char c,a; } attrchar, screen[25][80]; static char rgbbgr[8]="04261537"; #define bp (*b) static inline void setattr(attrchar *ch, int *oattr, char **b) { if (*oattr!=ch->a) { *oattr=ch->a; *bp++='\e', *bp++='[', *bp++='0'; if (ch->a&0x80) // blink *bp++=';', *bp++='5'; *bp++=';', *bp++='4', *bp++=rgbbgr[(ch->a>>4)&7]; // background if (ch->a&0x08) // brightness *bp++=';', *bp++='1'; *bp++=';', *bp++='3', *bp++=rgbbgr[ch->a&7]; // foreground *bp++='m'; } } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" #ifdef __clang__ # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif static inline void wrchar(attrchar *ch, char **b) { // Unicode is 32-bit, charset_cp437[] only 16-bit as all its entries fit // into the range. Thus, hush the compiler warning. TF8(bp, charset_cp437[(unsigned char)ch->c]); } #pragma GCC diagnostic pop #undef bp static inline int cnt_spaces(attrchar *ch, int a, int max) { int i=0; while (ch->c==' ' && ch->a==a && max--) i++, ch++; return i; } #define BUFFER_SIZE 65536 /* Max frame size is 34166: 25*80 cells of an UTF-8 char (max 3 bytes) and attrs (max 14 bytes), plus cursor movements, one per line plus one per >=10 symbols skipped. Rounding up to 64KB just to be safe. */ #define MINJUMP 10 // when to jump instead of overwriting same text #define MINCL 20 // when to prefer clears over writing spaces static int scrdiff(screen *vt, screen *scr, char *buf) { char *bp=buf; int x,y; int cx=-1,cy=-1; int attr=-1; int sp; for (y=0; y<25; y++) for (x=0; x<80; x++) if (vt[y][x]!=scr[y][x]) { if (y!=cy || cx+MINJUMP<x) bp+=sprintf(bp, "\e[%d;%df", (cy=y)+1, cx=x+1); else { while (cx<x) { setattr(&(*scr)[y][cx], &attr, &bp); wrchar(&(*scr)[y][cx], &bp); cx++; } cx++; } setattr(&(*scr)[y][x], &attr, &bp); if (cx>80-MINCL || (sp=cnt_spaces(&(*scr)[y][x], attr, 80-cx))<MINCL) wrchar(&(*scr)[y][x], &bp); else { bp+=sprintf(bp, "\e[%dX", sp); x+=sp-1; } } return bp-buf; } void play_dosrecorder(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { gzFile g; screen vt, scr, screens[MAXSCREENS]; int i, x, y, note; #pragma pack(push) #pragma pack(1) struct ch { uint16_t pos,len; } chs[25*80]; struct { unsigned char w, h, x, y; unsigned char titlelen; char attr; char flags; } nh; struct { uint32_t delay; unsigned char cx, cy; unsigned char sscr, dscr; uint16_t nchunks; } fh; #pragma pack(pop) char buf[BUFFER_SIZE], *bp; struct timeval tv; if (!(g=gzdopen(dup(fileno(f)), "rb"))) { synch_print(buf, snprintf(buf, BUFFER_SIZE, _("Not a DosRecorder recording!")), arg); return; } memset(vt, 0, sizeof(screen)); for (i=0; i<MAXSCREENS; i++) for (y=0; y<25; y++) for (x=0; x<80; x++) screens[i][y][x].c=' ', screens[i][y][x].a=7; bp=buf+sprintf(buf, "\ec\e%%G\e[8;25;80t"); while (gzread(g, &fh, sizeof(fh))==sizeof(fh)) { note=fh.nchunks&0x8000; memcpy(&scr, &screens[fh.sscr], sizeof(screen)); if ((fh.nchunks&=0x7fff)>25*80) goto end; // corrupted file -- too many chunks if (gzread(g, chs, fh.nchunks*sizeof(struct ch)) !=(int)(fh.nchunks*sizeof(struct ch))) goto end; for (i=0; i<fh.nchunks; i++) { if (chs[i].pos>=25*80 || chs[i].len+chs[i].pos>25*80) goto end; // corrupted file gzread(g, &scr[0][0]+chs[i].pos, chs[i].len*sizeof(attrchar)); } memcpy(&screens[fh.dscr], &scr, sizeof(screen)); if (note) { if (gzread(g, &nh, sizeof(nh)!=sizeof(nh))) goto end; for (i=0; i<nh.h; i++) gzread(g, &scr[nh.y+i][nh.x], nh.w*sizeof(attrchar)); if (nh.titlelen>80) goto end; *bp++='\e', *bp++=']', *bp++='0', *bp++=';'; gzread(g, bp, nh.titlelen); bp+=nh.titlelen; *bp++=7; } bp+=scrdiff(&vt, &scr, bp); tv.tv_sec=fh.delay/1000; tv.tv_usec=(fh.delay-tv.tv_sec*1000)*1000; synch_wait(&tv, arg); synch_print(buf, bp-buf, arg); bp=buf; } end: gzclose(g); } #endif �������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/files.c�������������������������������������������������������������������������0000664�0000000�0000000�00000012330�13646775175�0015705�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <assert.h> #include "export.h" #include "formats.h" #include "libstream/compress.h" #include "libstream/stream.h" VISIBILITY_ENABLE #include "ttyrec.h" VISIBILITY_DISABLE typedef struct TTYRecRecorder { recorder_info *format; void *state; FILE *f; } *recorder; /************************/ /* writing ttyrec files */ /************************/ static int find_w_format(const char *format, const char *filename, const char *fallback) { int nf; // given explicitly if (format) { for (nf=0; rec[nf].name; nf++) if (!strcasecmp(format, rec[nf].name)) return nf; return -1; // no fallback to default } // guess from the filename else if (filename) { compress_info *ci; int skip; ci=comp_from_ext(filename, compressors); if (ci) skip=strlen(ci->ext); else skip=0; for (nf=0; rec[nf].name; nf++) if (rec[nf].ext && match_suffix(filename, rec[nf].ext, skip)) return nf; } // is the default valid? if (fallback) for (nf=0; rec[nf].name; nf++) if (!strcasecmp(fallback, rec[nf].name)) return nf; return -1; } export const char* ttyrec_w_find_format(const char *format, const char *filename, const char *fallback) { int nf=find_w_format(format, filename, fallback); return (nf==-1) ? 0 : rec[nf].name; } export recorder ttyrec_w_open(int fd, const char *format, const char *filename, const struct timeval *tm) { int nf; recorder r; nf=find_w_format(format, filename, "ansi"); if (nf==-1) { close(fd); return 0; } if (fd==-1) fd=open_stream(fd, filename, SM_WRITE, 0); if (fd==-1) return 0; r=malloc(sizeof(struct TTYRecRecorder)); if (!r) { close(fd); return 0; } r->format=&rec[nf]; r->f=fdopen(fd, "wb"); assert(r->f); r->state=(r->format)->init(r->f, tm); return r; } export int ttyrec_w_write(recorder r, const struct timeval *tm, const char *buf, int len) { assert(r); assert(r->f); r->format->write(r->f, r->state, tm, buf, len); return !ferror(r->f); } export int ttyrec_w_close(recorder r) { assert(r); assert(r->f); r->format->finish(r->f, r->state); int ok=!ferror(r->f); ok&=!fclose(r->f); free(r); return ok; } export const char* ttyrec_w_get_format_name(int i) { if (i<0 || i>=rec_n) return 0; return rec[i].name; } export const char* ttyrec_w_get_format_ext(const char *format) { int i = find_w_format(format, 0, 0); if (i<0 || i>=rec_n) return 0; return rec[i].ext; } /************************/ /* reading ttyrec files */ /************************/ static int find_r_format(const char *format, const char *filename, const char *fallback) { int nf; // given explicitly if (format) { for (nf=0; play[nf].name; nf++) if (!strcasecmp(format, play[nf].name)) return nf; return -1; // no fallback to default } // guess from the filename else if (filename) { compress_info *ci; int skip; ci=comp_from_ext(filename, decompressors); if (ci) skip=strlen(ci->ext); else skip=0; for (nf=0; play[nf].name; nf++) if (play[nf].ext && match_suffix(filename, play[nf].ext, skip)) return nf; } // is the default valid? if (fallback) for (nf=0; play[nf].name; nf++) if (!strcasecmp(fallback, play[nf].name)) return nf; return -1; } export const char* ttyrec_r_find_format(const char *format, const char *filename, const char *fallback) { int nf=find_r_format(format, filename, fallback); return (nf==-1) ? 0 : play[nf].name; } export const char* ttyrec_r_get_format_name(int i) { if (i<0 || i>=play_n) return 0; return play[i].name; } export const char* ttyrec_r_get_format_ext(const char *format) { int i = find_r_format(format, 0, 0); if (i<0 || i>=play_n) return 0; return play[i].ext; } static void dummyfunc(void) {} export int ttyrec_r_play(int fd, const char *format, const char *filename, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg) { int nf; FILE *f; nf=find_r_format(format, filename, "auto"); if (nf==-1) { if (fd!=-1) close(fd); return 0; } if (fd==-1) fd=open_stream(fd, filename, SM_READ, 0); if (fd==-1) return 0; if (!synch_init_wait) synch_init_wait=(void*)dummyfunc; if (!synch_wait) synch_wait=(void*)dummyfunc; if (!synch_print) synch_print=(void*)dummyfunc; f=fdopen(fd, "rb"); assert(f); (*play[nf].play)(f, synch_init_wait, synch_wait, synch_print, arg, 0); fclose(f); return 1; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/formats.c�����������������������������������������������������������������������0000664�0000000�0000000�00000034423�13646775175�0016265�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file defines the "plugins". There is no need to provide both recorder and a player. Read-only or write-only plugins are fine. To create one, implement: + player: void play_xxx(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont); You are guaranteed to be running in a thread-equivalent on your own. *f is the file you're reading from, don't expect it to be seekable. void synch_init_wait(const struct timeval *ts, void *arg); you may call this to mark the starting time of the stream. It's purely optional, and its only use is to mention the date of the recording, if known. void synch_wait(const struct timeval *tv, void *arg); call this to convey timing information. The value given is the _delay_ since the last call, not the absolute time. void synch_print(const char *buf, int len, void *arg); call this to write the actual output. void *arg please pass it to each of the functions you call. + recorder: void* record_xxx_init(FILE *f, const struct timeval *tm); Will be called exactly once per stream. *f is the file you're supposed to write the stream to. Don't expect it to be seekable. *tm is the date of the recording, if known. tm will be a null pointer if this information is not available -- in this case, all timing data will be relative to 0:0. You may allocate some memory for keeping track of the state. In this case, return the pointer to that memory, it will be passed in every subsequent call. It may be arbitrary data, and is never used outside your code. void record_xxx(FILE *f, void* state, const struct timeval *tm, const char *buf, int len); Will be called every time a new chunk of input comes. *f is the file we're recording to. *state is the pointer returned by record_xxx_init(). *tm is the "current" time of the chunk, as an absolute value (_not_ the delay since the last call). It usually will be measured as the real time since the Epoch, but in some cases, it may start at 0:0. *buf is the chunk to be written. It won't be terminated with a \0. len is the length of the chunk. void record_xxx_finish(FILE *f, void* state); Will be called when the recording ends. *f is the file we're recording to. *state is the pointer returned by record_xxx_init(). At this point, you need to free any memory you've allocated. */ #include "config.h" #ifdef HAVE_SYS_TIME_H # include <sys/time.h> #endif #include "_stdint.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "export.h" #include "formats.h" #include "compat.h" // ttyrec checks the byte sex on runtime, during _every_ swap. Uh oh. #ifdef WORDS_BIGENDIAN # define little_endian(x) ((uint32_t) ( \ (((uint32_t) (x) & (uint32_t) 0x000000ffU) << 24) | \ (((uint32_t) (x) & (uint32_t) 0x0000ff00U) << 8) | \ (((uint32_t) (x) & (uint32_t) 0x00ff0000U) >> 8) | \ (((uint32_t) (x) & (uint32_t) 0xff000000U) >> 24))) #else # define little_endian(x) ((uint32_t)(x)) #endif #define tadd(t, d) {if (((t).tv_usec+=(d).tv_usec)>1000000) \ (t).tv_usec-=1000000, (t).tv_sec++; \ (t).tv_sec+=(d).tv_sec; \ } #define tsub(t, d) {if ((signed)((t).tv_usec-=(d).tv_usec)<0) \ (t).tv_usec+=1000000, (t).tv_sec--; \ (t).tv_sec-=(d).tv_sec; \ } #define BUFFER_SIZE 32768 /********************/ /* format: baudrate */ /********************/ static void play_baudrate(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { char buf[BUFFER_SIZE]; size_t b; struct timeval tv; tv.tv_sec=0; tv.tv_usec=200000; while ((b=fread(buf, 1, 60, f))>0) // 2400 baud { synch_print(buf, b, arg); synch_wait(&tv, arg); } } static void* record_baudrate_init(FILE *f, const struct timeval *tm) { return 0; } static void record_baudrate(FILE *f, void* state, const struct timeval *tm, const char *buf, int len) { fwrite(buf, 1, len, f); } static void record_baudrate_finish(FILE *f, void* state) { } /***********************/ /* pseudo-format: live */ /***********************/ static void play_live(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { struct timeval tv, tp, tm; char buf[BUFFER_SIZE]; int len; if (cont) tp=*cont; else { gettimeofday(&tp, 0); synch_init_wait(&tp, arg); } // using read() not fread(), we need unbuffered IO while ((len=read(fileno(f), buf, BUFFER_SIZE))>0) { gettimeofday(&tv, 0); tm=tv; tsub(tm, tp); synch_wait(&tm, arg); tp=tv; synch_print(buf, len, arg); } } static void* record_live_init(FILE *f, const struct timeval *tm) { struct timeval *tv; tv=malloc(sizeof(struct timeval)); gettimeofday(tv, 0); if (tm) tsub(*tv, *tm); return tv; } static void record_live(FILE *f, void* state, const struct timeval *tm, const char *buf, int len) { struct timeval tv, wall; gettimeofday(&wall, 0); tv=*tm; tadd(tv, *((struct timeval*)state)); tsub(tv, wall); if (tv.tv_sec>=0 && (tv.tv_sec || tv.tv_usec)) // can't go back in time select(0, 0, 0, 0, &tv); else tsub(*(struct timeval*)state, tv); // move the origin by the (negative) time skipped fwrite(buf, 1, len, f); fflush(f); } static void record_live_finish(FILE *f, void* state) { free(state); } /******************/ /* format: ttyrec */ /******************/ struct ttyrec_header { uint32_t sec; uint32_t usec; uint32_t len; }; static void play_ttyrec(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { char buf[BUFFER_SIZE]; size_t b,w; struct timeval tv,tl; int first=1; struct ttyrec_header head; if (cont) { tv=*cont; first=0; } while (fread(&head, 1, sizeof(struct ttyrec_header), f) ==sizeof(struct ttyrec_header)) { b=little_endian(head.len); /* printf("b=%u, time=%i.%09i\n", b, little_endian(head.sec), little_endian(head.usec)); */ // pre-read the first block to make the timing more accurate if (b>BUFFER_SIZE) w=BUFFER_SIZE; else w=b; if (fread(buf, 1, w, f)<w) goto the_end; b-=w; if (first) { tv.tv_sec=little_endian(head.sec); tv.tv_usec=little_endian(head.usec); synch_init_wait(&tv, arg); first=0; } else { tl=tv; tv.tv_sec=little_endian(head.sec); tv.tv_usec=little_endian(head.usec); tl.tv_sec=tv.tv_sec-tl.tv_sec; if ((tl.tv_usec=tv.tv_usec-tl.tv_usec)<0) { tl.tv_usec+=1000000; tl.tv_sec--; } synch_wait(&tl, arg); } while (w>0) { synch_print(buf, w, arg); if (!b) break; if (b>BUFFER_SIZE) w=BUFFER_SIZE; else w=b; if (fread(buf, 1, w, f)<w) goto the_end; b-=w; } } the_end:; } static void* record_ttyrec_init(FILE *f, const struct timeval *tm) { return 0; } static void record_ttyrec(FILE *f, void* state, const struct timeval *tm, const char *buf, int len) { struct ttyrec_header h; h.sec=little_endian(tm->tv_sec); h.usec=little_endian(tm->tv_usec); h.len=little_endian(len); fwrite(&h, 1, sizeof(h), f); fwrite(buf, 1, len, f); } static void record_ttyrec_finish(FILE *f, void* state) { } /***********************/ /* format: nh_recorder */ /***********************/ static uint32_t get_u32(const void *mem) { typedef struct __attribute__((__packed__)) { uint32_t v; } u32_unal; uint32_t bad_endian = ((u32_unal*)mem)->v; return little_endian(bad_endian); } static void play_nh_recorder(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { char buf[BUFFER_SIZE]; int b,i,i0; struct timeval tv; uint32_t t,tp; t=0; i=b=0; while ((b=fread(buf+b-i, 1, BUFFER_SIZE-(b-i), f))>0) { i0=0; for (i=0;i<b;i++) if (!buf[i]) { if (i0<i) synch_print(buf+i0, i-i0, arg); if (i+4>b) // timestamp happened on a block boundary { if (b<5) // incomplete last timestamp return; memmove(buf+i, buf, b-i); goto block_end; } else { tp=t; t=get_u32(buf+i+1); i0=i+5; i+=4; tv.tv_sec=(t-tp)/100; tv.tv_usec=(t-tp)%100*10000; synch_wait(&tv, arg); } } if (i0<i) synch_print(buf+i0, i-i0, arg); block_end:; // FIXME: frames shouldn't get split just because not being aligned // to our read block } } static void* record_nh_recorder_init(FILE *f, const struct timeval *tm) { struct timeval *tv; tv=malloc(sizeof(struct timeval)); if (tm) *tv=*tm; else tv->tv_sec=tv->tv_usec=0; fwrite("\0\0\0\0\0", 1, 5, f); return tv; } static void record_nh_recorder(FILE *f, void* state, const struct timeval *tm, const char *buf, int len) { int32_t i; i=(tm->tv_sec-((struct timeval*)state)->tv_sec)*100+ (tm->tv_usec-((struct timeval*)state)->tv_usec)/10000; fwrite(buf, 1, len, f); fwrite("\0", 1, 1, f); fwrite(&i, 1, 4, f); } static void record_nh_recorder_finish(FILE *f, void* state) { free(state); } /***********************/ /* pseudo-format: auto */ /***********************/ #define WANT(x) if (!len--) return 1; if (*buf++!=(x)) return 0; #define SPACE while (1) { if (!len--) return 1; \ if (*buf!=' '&&*buf!='\t'&&*buf!='\n'&&*buf!='\r') break; \ buf++; } static int is_asciicast(const char *buf) { int len=12; WANT('{') SPACE WANT('"') WANT('v') WANT('e') WANT('r') WANT('s') WANT('i') WANT('o') WANT('n') WANT('"') SPACE WANT(':') SPACE return (!len || *buf=='1' || *buf=='2'); } #undef WANT #undef SPACE static void play_auto(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont) { struct ttyrec_header tth; int len, got; char buf[BUFFER_SIZE]; struct timeval tv; // first, grab 12 bytes and see if it looks like a ttyrec header got=0; do { // must use unbuffered I/O here, to not spoil it for play_live() if ((len=read(fileno(f), ((char*)&tth)+got, 12-got))<=0) return; got+=len; } while (got<12); if (little_endian(tth.usec)<1000000 && little_endian(tth.len)>0 && little_endian(tth.len)<65536) { tv.tv_sec=little_endian(tth.sec); tv.tv_usec=little_endian(tth.usec); synch_init_wait(&tv, arg); got=little_endian(tth.len); while (got>0) { if ((len=fread(buf, 1, (got>BUFFER_SIZE)?BUFFER_SIZE:got, f))<=0) return; synch_print(buf, len, arg); got-=len; } play_ttyrec(f, 0, synch_wait, synch_print, arg, &tv); return; } if (is_asciicast((const char*)&tth)) { do_play_asciicast(fileno(f), (const char*)&tth, 12, synch_init_wait, synch_wait, synch_print, arg, &tv); return; } // fall back to "live" gettimeofday(&tv, 0); synch_init_wait(&tv, arg); synch_print((char*)&tth, 12, arg); play_live(f, 0, synch_wait, synch_print, arg, &tv); } /****************/ /* format: null */ /****************/ static void* record_null_init(FILE *f, const struct timeval *tm) { return 0; } static void record_null(FILE *f, void* state, const struct timeval *tm, const char *buf, int len) { } static void record_null_finish(FILE *f, void* state) { } recorder_info rec[]={ {"ansi",".txt",record_baudrate_init,record_baudrate,record_baudrate_finish}, {"ttyrec",".ttyrec",record_ttyrec_init,record_ttyrec,record_ttyrec_finish}, {"nh_recorder",".nh",record_nh_recorder_init,record_nh_recorder,record_nh_recorder_finish}, {"asciicast",".cast",record_asciicast_init,record_asciicast,record_asciicast_finish}, {"asciicast-v1",".cast-v1",record_asciicast_v1_init,record_asciicast,record_asciicast_finish}, {"live", 0, record_live_init, record_live, record_live_finish}, {"null",0,record_null_init,record_null,record_null_finish}, {0, 0, 0, 0, 0}, }; player_info play[]={ {"baudrate",".txt",play_baudrate}, {"ttyrec",".ttyrec",play_ttyrec}, {"nh_recorder",".nh",play_nh_recorder}, #if (defined HAVE_LIBZ) || (SHIPPED_LIBZ) {"dosrecorder",".dm2",play_dosrecorder}, #endif {"asciicast",".cast",play_asciicast}, {"live",0,play_live}, {"auto",0,play_auto}, {0, 0, 0}, }; #ifndef ARRAYSIZE # define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #endif int rec_n=ARRAYSIZE(rec)-1; int play_n=ARRAYSIZE(play)-1; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/formats.h�����������������������������������������������������������������������0000664�0000000�0000000�00000004427�13646775175�0016273�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #if TIME_WITH_SYS_TIME # include <sys/time.h> # include <time.h> #else # if HAVE_SYS_TIME_H # include <sys/time.h> # else # include <time.h> # endif #endif typedef void play_func(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont); typedef void *(record_func_init)(FILE *f, const struct timeval *tm); typedef void (record_func)(FILE *f, void* state, const struct timeval *tm, const char *buf, int len); typedef void (record_func_finish)(FILE *f, void* state); typedef struct { const char *name; const char *ext; record_func_init *init; record_func *write; record_func_finish *finish; } recorder_info; typedef struct { const char *name; const char *ext; play_func *play; } player_info; extern recorder_info rec[]; extern player_info play[]; extern int rec_n, play_n; void play_dosrecorder(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont); void play_asciicast(FILE *f, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont); void* record_asciicast_init(FILE *f, const struct timeval *tm); void record_asciicast(FILE *f, void* state, const struct timeval *tm, const char *buf, int len); void record_asciicast_finish(FILE *f, void* state); void* record_asciicast_v1_init(FILE *f, const struct timeval *tm); void record_asciicast_v1(FILE *f, void* state, const struct timeval *tm, const char *buf, int len); void record_asciicast_v1_finish(FILE *f, void* state); void do_play_asciicast(int fd, const char *obuf, int olen, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *tv, void *arg), void (*synch_print)(const char *buf, int len, void *arg), void *arg, const struct timeval *cont); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/timeline.c����������������������������������������������������������������������0000664�0000000�0000000�00000010615�13646775175�0016415�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdlib.h> #include <string.h> #include <sys/time.h> #include "error.h" #include "tty.h" typedef struct {} *recorder; struct ttyrec_frame { struct timeval t; int len; char *data; tty snapshot; struct ttyrec_frame *next; }; typedef struct ttyrec_frame *ttyrec_frame; typedef struct ttyrec { struct ttyrec_frame *tev_head, *tev_tail; tty tev_vt; int nchunk; struct timeval ndelay; } *ttyrec; #define _TTYREC_H_NO_TYPES #include "ttyrec.h" #include "export.h" #define SNAPSHOT_CHUNK 65536 #define tr ((ttyrec)arg) static void synch_init_wait(const struct timeval *ts, void *arg) { tr->tev_head->t=*ts; } static const struct timeval maxd = {5,0}; static void synch_wait(const struct timeval *tv, void *arg) { if (tv->tv_sec>=maxd.tv_sec || tv->tv_sec<0) tadd(tr->ndelay, maxd); else tadd(tr->ndelay, *tv); } static void synch_print(const char *buf, int len, void *arg) { struct ttyrec_frame *nf; if (!(nf=malloc(sizeof(struct ttyrec_frame)))) return; if (!(nf->data=malloc(len))) { free(nf); return; } nf->len=len; memcpy(nf->data, buf, len); nf->t=tr->tev_tail->t; tadd(nf->t, tr->ndelay); tr->ndelay.tv_sec=tr->ndelay.tv_usec=0; nf->snapshot=0; nf->next=0; tr->tev_tail->next=nf; tr->tev_tail=nf; tty_write(tr->tev_vt, buf, len); if ((tr->nchunk+=len)>=SNAPSHOT_CHUNK) // do a snapshot every 64KB of data { nf->snapshot=tty_copy(tr->tev_vt); tr->nchunk=0; } } #undef tr export ttyrec ttyrec_init(tty vt) { ttyrec tr = malloc(sizeof(struct ttyrec)); if (!tr) return NULL; memset(tr, 0, sizeof(struct ttyrec)); tr->tev_head = malloc(sizeof(struct ttyrec_frame)); memset(tr->tev_head, 0, sizeof(struct ttyrec_frame)); tr->tev_tail=tr->tev_head; tr->nchunk=SNAPSHOT_CHUNK; tr->tev_vt = vt? vt : tty_init(80, 25, 1); tr->tev_head->snapshot = tty_copy(tr->tev_vt); return tr; } export void ttyrec_free(ttyrec tr) { struct ttyrec_frame *tev_tail, *tc; if (!tr) return; tev_tail=tr->tev_head; while (tev_tail) { tc=tev_tail; tev_tail=tev_tail->next; free(tc->data); if (tc->snapshot) tty_free(tc->snapshot); free(tc); } tty_free(tr->tev_vt); free(tr); } export ttyrec ttyrec_load(int fd, const char *format, const char *filename, tty vt) { ttyrec tr; if (!(tr=ttyrec_init(vt))) return 0; if (!ttyrec_r_play(fd, format, filename, synch_init_wait, synch_wait, synch_print, tr)) { ttyrec_free(tr); return 0; } return tr; } export struct ttyrec_frame* ttyrec_seek(const ttyrec tr, const struct timeval *t, tty *vt) { struct ttyrec_frame *tfv, *tfs; if (!tr) return 0; tfv = tr->tev_head; tfs = 0; if (t) while (tfv->next && tcmp(tfv->next->t, *t)<=0) { tfv=tfv->next; if (tfv->snapshot) tfs=tfv; } else if (tfv->next) tfv=tfv->next; if (tfv->snapshot) tfs=tfv; if (vt) { tty_free(*vt); if (tfs) *vt=tty_copy(tfs->snapshot); else { tfs=tr->tev_head; *vt=tty_init(80, 25, 1); } if (!*vt) return 0; while (tfs!=tfv) { tfs = tfs->next; if (tfs->data) tty_write(*vt, tfs->data, tfs->len); }; } return tfv; } export struct ttyrec_frame* ttyrec_next_frame(ttyrec tr, struct ttyrec_frame *tfv) { if (!tfv) return 0; return tfv->next; } export void ttyrec_add_frame(ttyrec tr, const struct timeval *delay, const char *data, int len) { if (delay) synch_wait(delay, tr); synch_print(data, len, tr); } export int ttyrec_save(ttyrec tr, int fd, const char *format, const char *filename, const struct timeval *selstart, const struct timeval *selend) { struct ttyrec_frame *fr; recorder rec; fr=ttyrec_seek(tr, selstart, 0); if (!(rec=ttyrec_w_open(fd, format, filename, &fr->t))) return 0; while (fr) { if (selend && tcmp(fr->t, *selend)>0) break; ttyrec_w_write(rec, &fr->t, fr->data, fr->len); fr=ttyrec_next_frame(tr, fr); } return ttyrec_w_close(rec); } �������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/tty.c���������������������������������������������������������������������������0000664�0000000�0000000�00000111346�13646775175�0015432�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//#define VT100_DEBUG #include "config.h" #define _GNU_SOURCE #include "tty.h" #include "charsets.h" #include <string.h> #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <assert.h> #include "export.h" #include "compat.h" #include "wcwidth.h" #if defined __GNUC__ && (__GNUC__ >= 7) #define FALLTHRU __attribute__((fallthrough)) #else #define FALLTHRU #endif #ifndef VT100_DEBUG #define debuglog(...) {} #endif #define CJK_DAMAGED ' ' #define MAXOSC 4096 #define SX vt->sx #define SY vt->sy #define CX vt->cx #define CY vt->cy #define FREECOMB vt->combs[0].next #define NCOMBS vt->combs[0].ch typedef struct { uint32_t fg; uint32_t bg; } fb_fields; #define FG(t,x) vt->attr=vt->attr&~VT100_ATTR_COLOR_MASK|VT100_COLOR_##t<<24|(x)&0xffffff #define BG(t,x) vt->attr=vt->attr&~0x3ffffff00000000|((uint64_t)VT100_COLOR_##t<<24|(x)&0xffffff)<<32 enum { ESnormal, ESesc, ESgetpars, ESsquare, ESques, ESsetG0, ESsetG1, ESpercent, ESosc, ESoscstr }; static void tty_kill_comb(tty vt, attrchar *ac) { // Must have been initialized before. if (!ac->comb) return; uint32_t i=ac->comb; ac->comb=0; while (i) { assert(i < NCOMBS); uint32_t j = vt->combs[i].next; vt->combs[i].next = FREECOMB; FREECOMB = i; i=j; } } static void tty_add_comb(tty vt, attrchar *ac, ucs ch) { if (!vt->combs || FREECOMB >= NCOMBS) { uint32_t oldn = vt->combs? NCOMBS : 0; uint32_t newn = oldn? oldn*2 : 32; debuglog("Reallocating combs from %u to %u\n", oldn, newn); combc *newcombs = realloc(vt->combs, newn*sizeof(combc)); if (!newcombs) return; for (uint32_t i=oldn; i<newn; i++) newcombs[i].next=i+1; vt->combs=newcombs; NCOMBS=newn; } int clen=0; uint32_t *cc=&ac->comb; while (*cc) { assert(*cc<NCOMBS); if (++clen>=4) return; // ignore if too many marks in one cell cc=&vt->combs[*cc].next; } uint32_t new=*cc=FREECOMB; FREECOMB=vt->combs[new].next; vt->combs[new].next=0; vt->combs[new].ch=ch; if (vt->l_comb) vt->l_comb(vt, (ac-vt->scr)%SX, (ac-vt->scr)/SX, ch, ac->attr); } export tty tty_init(int sx, int sy, int resizable) { tty vt; vt=malloc(sizeof(struct tty)); if (!vt) return 0; memset(vt, 0, sizeof(struct tty)); vt->allow_resize=resizable; tty_reset(vt); if (sx && sy) tty_resize(vt, sx, sy); return vt; } export int tty_resize(tty vt, int nsx, int nsy) { int x,y; attrchar *nscr; if (nsx==SX && nsy==SY) return 0; debuglog("Resize from %dx%d to %dx%d\n", SX, SY, nsx, nsy); nscr=malloc(nsx*nsy*sizeof(attrchar)); if (!nscr) return 0; for (y=0;y<nsy;y++) for (x=0;x<nsx;x++) { nscr[y*nsx+x].ch=' '; nscr[y*nsx+x].comb=0; nscr[y*nsx+x].attr=vt->attr; } if (vt->scr) { for (y=nsy;y<SY;y++) for (x=0;x<SX;x++) tty_kill_comb(vt, &vt->scr[y*SX+x]); for (y=0;y<SY;y++) for (x=nsx;x<SX;x++) tty_kill_comb(vt, &vt->scr[y*SX+x]); if (nsx<SX) for (y=0;y<SY;y++) if (vt->scr[y*SX+nsx].ch==VT100_CJK_RIGHT) { vt->scr[y*SX+nsx-1].ch=' '; vt->scr[y*SX+nsx-1].attr&=~VT100_ATTR_CJK; } for (y=0;y<SY && y<nsy;y++) for (x=0;x<SX && x<nsx;x++) nscr[y*nsx+x]=vt->scr[y*SX+x]; free(vt->scr); } vt->scr=nscr; SX=nsx; SY=nsy; vt->s1=0; vt->s2=nsy; if (CX>nsx) CX=nsx; if (CY>=nsy) CY=nsy-1; if (vt->save_cx>nsx) vt->save_cx=nsx; if (vt->save_cy>=nsy) vt->save_cy=nsy-1; return 1; } export void tty_free(tty vt) { if (!vt) return; if (vt->l_free) vt->l_free(vt); free(vt->scr); free(vt->combs); free(vt->title); free(vt->oscbuf); free(vt); } export tty tty_copy(tty vt) { tty nvt=malloc(sizeof(struct tty)); if (!nvt) return 0; memcpy(nvt, vt, sizeof(struct tty)); if (!(nvt->scr=malloc(SX*SY*sizeof(attrchar)))) goto drop_nvt; memcpy(nvt->scr, vt->scr, SX*SY*sizeof(attrchar)); if (vt->combs) { if (!(nvt->combs=malloc(NCOMBS*sizeof(combc)))) goto drop_scr; memcpy(nvt->combs, vt->combs, NCOMBS*sizeof(combc)); } nvt->title=vt->title? strdup(vt->title) : 0; if (vt->oscbuf) if ((nvt->oscbuf=malloc(MAXOSC))) memcpy(nvt->oscbuf, vt->oscbuf, vt->osclen); return nvt; drop_scr: free(nvt->scr); drop_nvt: free(nvt); return 0; } static void tty_clear_region(tty vt, int st, int l, bool killcomb) { attrchar *c, blank; assert(st>=0); assert(l>=0); assert(st+l<=SX*SY); blank.ch=' '; blank.comb=0; blank.attr=vt->attr; c=vt->scr+st; while (l--) { if (killcomb) tty_kill_comb(vt, c); *c++=blank; } } static void tty_kill_comb_region(tty vt, int st, int l) { attrchar *c; assert(st>=0); assert(l>=0); assert(st+l<=SX*SY); c=vt->scr+st; while (l--) tty_kill_comb(vt, c++); } export void tty_reset(tty vt) { tty_clear_region(vt, 0, SX*SY, true); CX=CY=vt->save_cx=vt->save_cy=0; vt->s1=0; vt->s2=SY; vt->attr=0; vt->state=ESnormal; vt->opt_auto_wrap=1; vt->opt_cursor=1; vt->opt_kpad=0; vt->G=vt->save_G=1<<1; // G0: normal, G1: vt100 graphics vt->curG=vt->save_curG=0; vt->utf_count=0; } static void tty_scroll(tty vt, int nl) { int s; assert(vt->s1<vt->s2); if ((s=vt->s2-vt->s1-abs(nl))<=0) { tty_clear_region(vt, vt->s1*SX, (vt->s2-vt->s1)*SX, true); return; } if (nl<0) { tty_kill_comb_region(vt, (vt->s2+nl)*SX, -nl*SX); memmove(vt->scr+(vt->s1-nl)*SX, vt->scr+vt->s1*SX, s*SX*sizeof(attrchar)); tty_clear_region(vt, vt->s1*SX, -nl*SX, false); } else { tty_kill_comb_region(vt, vt->s1*SX, nl*SX); memmove(vt->scr+vt->s1*SX, vt->scr+(vt->s1+nl)*SX, s*SX*sizeof(attrchar)); tty_clear_region(vt, (vt->s2-nl)*SX, nl*SX, false); } } static void osc(tty vt) { if (vt->tok[0] == 0xffffffff) return; if (vt->oscbuf) vt->oscbuf[vt->osclen]=0; if (vt->tok[0]==0) { free(vt->title); vt->title=vt->oscbuf? strdup(vt->oscbuf) : 0; } // Other terminals don't distinguish between lack of the string (\e]0\e\\) // and an empty string (\e]0;\e\\) thus let's do the same. if (vt->l_osc) vt->l_osc(vt, vt->tok[0], vt->oscbuf? vt->oscbuf : ""); if (vt->oscbuf) free(vt->oscbuf), vt->oscbuf=0; } static void set_charset(tty vt, int g, char x) { debuglog("Changing charset G%d to %c.\n", g, x); switch (x) { case '0': vt->G|=1<<g; break; // case 'A': UK hash-less -- go away, bad thing. case 'B': case 'U': vt->G&=~(1<<g); break; default: debuglog("Unknown charset: %c\n", x); return; } } static void cjk_damage_left(tty vt, int x, bool notify) { if (x<=0) return; assert(CY<SY); assert(x<SX); attrchar *ca = &vt->scr[CY*SX+x]; if (!(ca->attr & VT100_ATTR_CJK)) return; if (ca->ch != VT100_CJK_RIGHT) return; if (!x) return; // shouldn't happen --ca; --x; ca->ch=CJK_DAMAGED; ca->attr&=~VT100_ATTR_CJK; tty_kill_comb(vt, ca); if (notify && vt->l_char) vt->l_char(vt, x, CY, CJK_DAMAGED, ca->attr, 1); } static void cjk_damage_right(tty vt, int x, bool notify) { if (x+1>=SX) return; attrchar *ca = &vt->scr[CY*SX+x]; if (!(ca->attr & VT100_ATTR_CJK)) return; if (mk_wcwidth(ca->ch) != 2) return; // shouldn't happen ++ca; ++x; ca->ch=CJK_DAMAGED; ca->attr&=~VT100_ATTR_CJK; tty_kill_comb(vt, ca); if (notify && vt->l_char) vt->l_char(vt, x, CY, CJK_DAMAGED, ca->attr, 1); } #define L_CURSOR {if (vt->l_cursor) vt->l_cursor(vt, CX, CY);} #define FLAG(opt,f,v) \ { \ vt->opt=v; \ if (vt->l_flag) \ vt->l_flag(vt, f, v); \ } #define SCROLL(nl) \ { \ tty_scroll(vt, nl); \ if (vt->l_scroll) \ vt->l_scroll(vt, nl); \ } #define CLEAR(x,y,l) \ { \ tty_clear_region(vt, y*SX+x, l, true); \ if (vt->l_clear) \ vt->l_clear(vt, x, y, l); \ } static inline void tty_write_char(tty vt, ucs c) { int w=mk_wcwidth(c); if (w<0) return; else if (!w) { if (!CX) return; // combining are illegal at left edge of the screen // on CJK, attach to left side not to the fillet int cjk=(vt->scr[CY*SX+CX-1].ch==VT100_CJK_RIGHT); return tty_add_comb(vt, &vt->scr[CY*SX+CX-1-cjk], c); } if (c<128 && vt->G&(1<<vt->curG)) c=charset_vt100[c]; if (CX+w>SX) { if (vt->opt_auto_wrap) { CX=0; CY++; if (CY>=vt->s2) { CY=vt->s2-1; SCROLL(1); } } else CX=SX-w; } // check for damage to existent CJK characters // * overwriting half-aligned trailing half cjk_damage_left(vt, CX, true); // * overwriting 2-width with 1-width, or half-aligned with 2-width cjk_damage_right(vt, CX+w-1, false); vt->scr[CY*SX+CX].ch=c; vt->scr[CY*SX+CX].attr=vt->attr | (w==2?VT100_ATTR_CJK:0); tty_kill_comb(vt, &vt->scr[CY*SX+CX]); if (w==2) { vt->scr[CY*SX+CX+1].ch=VT100_CJK_RIGHT; vt->scr[CY*SX+CX+1].attr=vt->attr|VT100_ATTR_CJK; tty_kill_comb(vt, &vt->scr[CY*SX+CX+1]); } CX+=w; if (vt->l_char) vt->l_char(vt, CX-w, CY, c, vt->attr, w); } export void tty_write(tty vt, const char *buf, int len) { int i; ucs c; buf--; while (len--) { switch (*++buf) { case 0: case 5: // ENQ -> ask for terminal's name continue; case 7: // BEL -> beep; also terminates OSC if (vt->state == ESosc || vt->state == ESoscstr) osc(vt), vt->state = ESnormal; else if (vt->l_bell) vt->l_bell(vt); continue; case 8: // backspace if (CX) CX--; L_CURSOR; continue; case 9: // tab if (CX>=SX) continue; cjk_damage_left(vt, CX, true); if ((CX|7) < SX) cjk_damage_right(vt, CX|7, false); do { vt->scr[CY*SX+CX].attr=vt->attr; vt->scr[CY*SX+CX].ch=' '; tty_kill_comb(vt, &vt->scr[CY*SX+CX]); CX++; if (vt->l_char) vt->l_char(vt, CX-1, CY, ' ', vt->attr, 1); } while (CX<SX && CX&7); continue; case 10: // LF (newline) CX=0; FALLTHRU; case 11: // VT (vertical tab) newline: CY++; if (CY==vt->s2) { CY=vt->s2-1; SCROLL(1); } else { if (CY>=SY) CY=SY-1; L_CURSOR; } continue; case 12: // Form Feed CX=CY=0; CLEAR(0, 0, SX*SY); L_CURSOR; continue; case 13: // CR CX=0; L_CURSOR; continue; case 14: // S0 -> select character set vt->curG=1; continue; case 15: // S1 -> select character set vt->curG=0; continue; case 24: // ??? case 26: // ??? vt->state=ESnormal; continue; case 27: // ESC if (vt->state==ESosc || vt->state==ESoscstr) osc(vt); vt->state=ESesc; continue; case 127: continue; } switch (vt->state) { error: #ifdef VT100_DEBUG switch (vt->state) { case ESnormal: debuglog("Unknown code 0x%2x\n", *buf); break; case ESesc: debuglog("Unknown code ESC %c\n", *buf); break; case ESsquare: case ESgetpars: case ESques: case ESpercent: debuglog("Unknown code ESC"); switch (vt->state) { case ESgetpars: case ESsquare: debuglog(" ["); break; case ESques: debuglog(" [ ?"); break; case ESpercent: debuglog(" %%"); break; } for (i=0;i<=vt->ntok;i++) debuglog("%c%u%s", i?';':' ', vt->tok[i], vt->tok[i]?"":"?"); debuglog(" %c\n", *buf); break; default: debuglog("Unknown state %d\n", vt->state); } #endif vt->state=ESnormal; break; #define ic ((unsigned char)*buf) #define tc (vt->utf_char) #define cnt (vt->utf_count) case ESnormal: if (vt->cp437) c=charset_cp437[ic]; else if (ic<0x80) cnt=0, c=ic; else if (cnt>0 && (ic&0xc0)==0x80) { tc=(tc<<6) | (ic&0x3f); if (!--cnt) c=tc; else continue; if (c<0xA0) // underlong or C1 controls c=0xFFFD; if (c==0xFFEF) // BOM continue; /* The following code deals with malformed UTF-16 * surrogates encoded in UTF-8 text. While the * standard explicitly forbids this, some (usually * Windows) programs generate them, and thus we'll * better support such encapsulation anyway. * We don't go out of our way to detect unpaired * surrogates, though. */ if (c>=0xD800 && c<=0xDFFF) // UTF-16 surrogates { if (c<0xDC00) // lead surrogate { vt->utf_surrogate=c; continue; } else if (vt->utf_surrogate) // trailing surrogate { c=(vt->utf_surrogate<<10)+c+ (0x10000 - (0xD800 << 10) - 0xDC00); vt->utf_surrogate=0; } else c=0xFFFD; // unpaired trailing } if (c>0x10FFFF) // outside Unicode c=0xFFFD; else if ((c&0xFFFF)>=0xFFFE || c>=0xFDD0 && c<0xFDF0) c=0xFFFD; // non-characters } else { if ((ic&0xe0)==0xc0) cnt=1, tc=ic&0x1f; else if ((ic&0xf0)==0xe0) cnt=2, tc=ic&0x0f; else if ((ic&0xf8)==0xf0) cnt=3, tc=ic&0x07; else if ((ic&0xfc)==0xf8) cnt=4, tc=ic&0x03; else if ((ic&0xfe)==0xfc) cnt=5, tc=ic&0x01; else cnt=0; continue; } tty_write_char(vt, c); break; #undef ic #undef tc #undef cnt case ESesc: // ESC switch (*buf) { case '[': vt->state=ESsquare; vt->ntok=0; vt->tok[0]=0; break; case ']': vt->state=ESosc; vt->tok[0]=0; break; case '(': vt->state=ESsetG0; break; case ')': vt->state=ESsetG1; break; case '%': vt->state=ESpercent; break; case '7': // ESC 7 -> save cursor position vt->save_cx=CX; vt->save_cy=CY; vt->save_attr=vt->attr; vt->save_G=vt->G; vt->save_curG=vt->curG; vt->state=ESnormal; break; case '8': // ESC 8 -> restore cursor position CX=vt->save_cx; CY=vt->save_cy; vt->attr=vt->save_attr; vt->G=vt->save_G; vt->curG=vt->save_curG; L_CURSOR; vt->state=ESnormal; break; case 'D': // ESC D -> newline vt->state=ESnormal; goto newline; case 'E': // ESC E -> newline+cr vt->state=ESnormal; CX=0; goto newline; case 'M': // ESC M -> reverse newline CY--; if (CY==vt->s1-1) { CY=vt->s1; SCROLL(-1); } else { if (CY<0) CY=0; L_CURSOR; } vt->state=ESnormal; break; case '=': // ESC = -> application keypad mode FLAG(opt_kpad, VT100_FLAG_KPAD, 1); vt->state=ESnormal; break; case '>': // ESC > -> numeric keypad mode FLAG(opt_kpad, VT100_FLAG_KPAD, 0); vt->state=ESnormal; break; default: goto error; } break; case ESsquare: // ESC [, immediately if (*buf=='?') { vt->state=ESques; break; } else vt->state=ESgetpars; // fallthru case ESgetpars: // ESC [, with params switch (*buf) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': vt->tok[vt->ntok]=vt->tok[vt->ntok]*10+*buf-'0'; break; case ';': if (++vt->ntok>=VT100_MAXTOK) goto error; vt->tok[vt->ntok]=0; break; case 'm': // ESC[m -> change color/attribs for (i=0;i<=vt->ntok;i++) switch (vt->tok[i]) { case 0: vt->attr=0; break; case 1: vt->attr|=VT100_ATTR_BOLD; vt->attr&=~VT100_ATTR_DIM; break; case 2: vt->attr|=VT100_ATTR_DIM; vt->attr&=~VT100_ATTR_BOLD; break; case 3: vt->attr|=VT100_ATTR_ITALIC; break; case 4: vt->attr|=VT100_ATTR_UNDERLINE; break; case 5: vt->attr|=VT100_ATTR_BLINK; break; case 7: vt->attr|=VT100_ATTR_INVERSE; break; case 9: vt->attr|=VT100_ATTR_STRIKE; break; case 21: vt->attr&=~(VT100_ATTR_BOLD|VT100_ATTR_DIM); break; case 22: vt->attr&=~(VT100_ATTR_BOLD|VT100_ATTR_DIM); break; case 23: vt->attr&=~VT100_ATTR_ITALIC; break; case 24: vt->attr&=~VT100_ATTR_UNDERLINE; break; case 25: vt->attr&=~VT100_ATTR_BLINK; break; case 27: vt->attr&=~VT100_ATTR_INVERSE; break; case 29: vt->attr&=~VT100_ATTR_STRIKE; break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: FG(16, vt->tok[i]-30); break; case 38: if (i>=VT100_MAXTOK-1) break; switch (vt->tok[++i]) { case 5: if (i>=VT100_MAXTOK-1) break; FG(256, vt->tok[++i]); break; case 2: if (i>=VT100_MAXTOK-3) break; FG(RGB, (vt->tok[i+1]&0xff)<<16 | (vt->tok[i+2]&0xff)<<8 | (vt->tok[i+3]&0xff)); // fallthru case 3: i+=3; break; case 4: i+=4; } break; case 39: FG(OFF, 0); break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: BG(16, vt->tok[i]-40); break; case 48: if (i>=VT100_MAXTOK-1) break; switch (vt->tok[++i]) { case 5: if (i>=VT100_MAXTOK-1) break; BG(256, vt->tok[++i]); break; case 2: if (i>=VT100_MAXTOK-3) break; BG(RGB, (vt->tok[i+1]&0xff)<<16 | (vt->tok[i+2]&0xff)<<8 | (vt->tok[i+3]&0xff)); // fallthru case 3: i+=3; break; case 4: i+=4; } break; case 49: BG(OFF, 0); break; case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: FG(256, 8|(vt->tok[i]-90)); break; case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: BG(256, 8|(vt->tok[i]-100)); break; } vt->state=ESnormal; break; case 'D': // ESC[D -> move cursor left i=vt->tok[0]; if (i<1) i=1; if (CX>i) CX-=i; else CX=0; L_CURSOR; vt->state=ESnormal; break; case 'C': case 'a': // ESC[C -> move cursor right i=vt->tok[0]; if (i<1) i=1; if (i<SX-CX) CX+=i; else CX=SX; L_CURSOR; vt->state=ESnormal; break; case 'F': // ESC[F -> move cursor up and home, no scrolling CX=0; FALLTHRU; case 'A': // ESC[A -> move cursor up, no scrolling i=vt->tok[0]; if (i<1) i=1; if (CY>i) CY-=i; else CY=0; L_CURSOR; vt->state=ESnormal; break; case 'E': // ESC[E -> move cursor down and home, no scrolling CX=0; FALLTHRU; case 'B': // ESC[B -> move cursor down, no scrolling i=vt->tok[0]; if (i<1) i=1; if (i<SY-CY) CY+=i; else CY=SY-1; L_CURSOR; vt->state=ESnormal; break; case 'r': // ESC[r -> set scrolling region if (!vt->tok[0]) vt->tok[0]=1; if (!vt->ntok) vt->tok[1]=0; if (!vt->tok[1]) vt->tok[1]=SY; if (vt->tok[1]<=SY && vt->tok[0]<vt->tok[1]) { vt->s1=vt->tok[0]-1; vt->s2=vt->tok[1]; CX=0; CY=vt->s1; } vt->state=ESnormal; break; case 'J': // ESC[J -> erase screen switch (vt->tok[0]) { case 0: // from cursor if (CX<SX) cjk_damage_left(vt, CX, true); CLEAR(CX, CY, SX*SY-(CY*SX+CX)); break; case 1: // to cursor if (CX>0) cjk_damage_right(vt, CX-1, true); CLEAR(0, 0, CY*SX+CX); break; case 2: // whole screen CLEAR(0, 0, SX*SY); } vt->state=ESnormal; break; case 'K': // ESC[K -> erase line switch (vt->tok[0]) { case 0: // from cursor if (CX>=SX) break; cjk_damage_left(vt, CX, true); CLEAR(CX, CY, SX-CX); break; case 1: // to cursor if (CX<=0) break; cjk_damage_right(vt, CX-1, true); CLEAR(0, CY, CX); break; case 2: // whole line CLEAR(0, CY, SX); } vt->state=ESnormal; break; case 'L': // ESC[L -> insert line if (vt->s1>CY || vt->s2<=CY) { vt->state=ESnormal; break; } vt->tok[1]=vt->s1; vt->s1=CY; i=vt->tok[0]; if (i<=0) i=1; SCROLL(-i); vt->s1=vt->tok[1]; vt->state=ESnormal; break; case 'M': // ESC[M -> delete line if (vt->s1>CY || vt->s2<=CY) { vt->state=ESnormal; break; } vt->tok[1]=vt->s1; vt->s1=CY; i=vt->tok[0]; if (i<=0) i=1; SCROLL(i); vt->s1=vt->tok[1]; vt->state=ESnormal; break; case '@': // ESC[@ -> insert spaces i=vt->tok[0]; if (i<=0) i=1; if (i>SX-CX) i=SX-CX; if (i<=0) break; cjk_damage_left(vt, CX, true); if (vt->scr[CY*SX+CX].ch==VT100_CJK_RIGHT) { vt->scr[CY*SX+CX].ch=CJK_DAMAGED; vt->scr[CY*SX+CX].attr&=~VT100_ATTR_CJK; tty_kill_comb(vt, &vt->scr[CY*SX+CX]); } cjk_damage_left(vt, SX-i, true); // pushed off screen tty_kill_comb_region(vt, CY*SX+SX-i, i); for (int j=SX-CX-i-1;j>=0;j--) vt->scr[CY*SX+CX+j+i]=vt->scr[CY*SX+CX+j]; tty_clear_region(vt, CY*SX+CX, i, false); if (vt->l_char) for (int j=CX;j<SX;j++) vt->l_char(vt, j, CY, vt->scr[CY*SX+j].ch, vt->scr[CY*SX+j].attr, mk_wcwidth(vt->scr[CY*SX+j].ch)); vt->state=ESnormal; break; case 'P': // ESC[P -> delete characters i=vt->tok[0]; if (i<=0) i=1; if (i>SX-CX) i=SX-CX; if (i<=0) break; cjk_damage_left(vt, CX, true); cjk_damage_right(vt, CX+i-1, true); tty_kill_comb_region(vt, CY*SX+CX, i); for (int j=CX+i;j<SX;j++) { vt->scr[CY*SX+j-i]=vt->scr[CY*SX+j]; if (vt->l_char) { vt->l_char(vt, j-i, CY, vt->scr[CY*SX+j].ch, vt->scr[CY*SX+j].attr, mk_wcwidth(vt->scr[CY*SX+j].ch)); } } tty_clear_region(vt, CY*SX+SX-i, i, false); vt->state=ESnormal; break; case 'X': // ESC[X -> erase to the right i=vt->tok[0]; if (i<=0) i=1; if (i>SX-CX) i=SX-CX; if (!i) break; cjk_damage_left(vt, CX, true); cjk_damage_right(vt, CX+i-1, true); CLEAR(CX, CY, i); vt->state=ESnormal; break; case 'f': case 'H': // ESC[f, ESC[H -> move cursor CY=vt->tok[0]-1; if (CY<0) CY=0; else if (CY>=SY) CY=SY-1; if (!vt->ntok) CX=0; else CX=vt->tok[1]-1; if (CX<0) CX=0; else if (CX>=SX) CX=SX-1; L_CURSOR; vt->state=ESnormal; break; case 'G': case '`': // ESC[G, ESC[` -> move cursor horizontally CX=vt->tok[0]-1; if (CX<0) CX=0; else if (CX>=SX) CX=SX-1; L_CURSOR; vt->state=ESnormal; break; case 'd': // ESC[d -> move cursor vertically CY=vt->tok[0]-1; if (CY<0) CY=0; else if (CY>=SY) CY=SY-1; L_CURSOR; vt->state=ESnormal; break; case 'c': // ESC[c -> reset to power-on defaults tty_reset(vt); if (vt->l_clear) vt->l_clear(vt, 0, 0, SX*SY); L_CURSOR; break; case 't': // ESC[t -> window manipulation vt->state=ESnormal; switch (vt->tok[0]) { case 8: // ESC[8;<h>;<w>t -> resize if (!vt->allow_resize) break; while (vt->ntok<2) vt->tok[++vt->ntok]=0; if (vt->tok[1]>256 || vt->tok[2]>512) // arbitrary break; // sanity check if (vt->tok[1]<=0) vt->tok[1]=SY; if (vt->tok[2]<=0) vt->tok[2]=SX; if (vt->tok[1]<1 || vt->tok[2]<2) // CJK needs 2 cells break; tty_resize(vt, vt->tok[2], vt->tok[1]); if (vt->l_resize) vt->l_resize(vt, vt->tok[2], vt->tok[1]); break; default: debuglog("Unknown extended window manipulation: %d\n", vt->tok[0]); } break; default: goto error; } break; case ESques: // ESC [ ? switch (*buf) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': vt->tok[vt->ntok]=vt->tok[vt->ntok]*10+*buf-'0'; break; case ';': if (++vt->ntok>=VT100_MAXTOK) goto error; vt->tok[vt->ntok]=0; break; case 'h': for (i=0;i<=vt->ntok;i++) switch (vt->tok[i]) { case 7: vt->opt_auto_wrap=1; break; case 25: FLAG(opt_cursor, VT100_FLAG_CURSOR, 1); break; default: debuglog("Unknown option: ?%u\n", vt->tok[i]); } vt->state=ESnormal; break; case 'l': for (i=0;i<=vt->ntok;i++) switch (vt->tok[i]) { case 7: vt->opt_auto_wrap=0; break; case 25: FLAG(opt_cursor, VT100_FLAG_CURSOR, 0); break; default: debuglog("Unknown option: ?%u\n", vt->tok[i]); } vt->state=ESnormal; break; default: goto error; } break; case ESsetG0: // ESC ( -> set G0 charset set_charset(vt, 0, *buf); vt->state=ESnormal; break; case ESsetG1: // ESC ) -> set G1 charset set_charset(vt, 1, *buf); vt->state=ESnormal; break; case ESpercent: // ESC % switch (*buf) { case '@': // ESC % @ -> disable UTF-8 vt->cp437=1; debuglog("Disabling UTF-8.\n"); break; case '8': // ESC % 8, ESC % G -> enable UTF-8 case 'G': vt->cp437=0; debuglog("Enabling UTF-8.\n"); break; default: goto error; } vt->state=ESnormal; break; case ESosc: if (*buf>='0' && *buf<='9') vt->tok[0]=vt->tok[0]*10+*buf-'0'; else if (*buf==';') { vt->oscbuf=malloc(MAXOSC); vt->osclen=0; vt->state=ESoscstr; } else { vt->tok[0]=-1; // mark as invalid vt->state=ESoscstr; } break; case ESoscstr: if (vt->oscbuf && vt->osclen<MAXOSC-1) vt->oscbuf[vt->osclen++]=*buf; break; default: goto error; } } if (vt->l_flush) vt->l_flush(vt); } #define BUFFER_SIZE 16384 export void tty_printf(tty vt, const char *fmt, ...) { va_list ap; char buf[BUFFER_SIZE], *bigstr; int len; va_start(ap, fmt); len=vsnprintf(buf, BUFFER_SIZE, fmt, ap); va_end(ap); if (len<=0) { va_start(ap, fmt); len=vasprintf(&bigstr, fmt, ap); va_end(ap); if (len<=0 || !bigstr) return; tty_write(vt, buf, len); free(bigstr); } else if (len>=BUFFER_SIZE) { if (!(bigstr=malloc(len+1))) return; va_start(ap, fmt); len=vsnprintf(bigstr, len+1, fmt, ap); va_end(ap); tty_write(vt, buf, len); free(bigstr); } else tty_write(vt, buf, len); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/tty.h���������������������������������������������������������������������������0000664�0000000�0000000�00000010575�13646775175�0015441�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _VT100_H #define _VT100_H #include <stdio.h> #include <stdint.h> typedef uint32_t ucs; typedef struct { ucs ch; uint32_t comb; uint64_t attr; } attrchar; typedef struct { ucs ch; uint32_t next; } combc; #define VT100_MAXTOK 16 enum { VT100_FLAG_CURSOR, // visible cursor VT100_FLAG_KPAD, // application keypad mode VT100_FLAG_AUTO_WRAP, // auto wrap at right margin }; #define VT100_CJK_RIGHT 0xffffffff /* ch value of right-half of a CJK char */ #define VT100_ATTR_COLOR_MASK 0x3ffffff #define VT100_ATTR_COLOR_TYPE 0x3000000 #define VT100_COLOR_OFF 0 #define VT100_COLOR_16 1 #define VT100_COLOR_256 2 #define VT100_COLOR_RGB 3 #define VT100_ATTR_BOLD 0x04000000 #define VT100_ATTR_DIM 0x08000000 #define VT100_ATTR_ITALIC 0x10000000 #define VT100_ATTR_UNDERLINE 0x20000000 #define VT100_ATTR_STRIKE 0x40000000 #define VT100_ATTR_INVERSE 0x0400000000000000 #define VT100_ATTR_BLINK 0x0800000000000000 #define VT100_ATTR_CJK 0x8000000000000000 typedef struct tty { /*=[ basic data ]=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ int sx,sy; // screen size int cx,cy; // cursor position attrchar *scr; // screen buffer combc *combs; // combining character chains uint64_t attr; // current attribute char *title; // window title /*=[ internal vt state ]=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ int s1,s2; // scrolling region int save_cx,save_cy; // saved cursor position uint64_t save_attr; // saved attribute unsigned int G:2; // bitfield: do G0 and G1 use vt100 graphics? unsigned int curG:1; // current G charset unsigned int save_G:2; // saved G, curG unsigned int save_curG:1; // flags int cp437 :1; // non-UTF-8 int allow_resize :1; // is input allowed to resize? int opt_auto_wrap :1; // ?7: auto wrap at right margin int opt_cursor :1; // ?25: show/hide cursor int opt_kpad :1; // keypad: application/numeric // UTF-8 state ucs utf_char; ucs utf_surrogate; int utf_count; // parser state int state; int ntok; uint32_t tok[VT100_MAXTOK]; char *oscbuf; int osclen; // length of current osc command /*=[ listeners ]=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ void *l_data; // any private data void (*l_char)(struct tty *vt, int x, int y, ucs ch, uint64_t attr, int width); // after a character has been written to the screen void (*l_comb)(struct tty *vt, int x, int y, ucs ch, uint64_t attr); // after a combining character has been added void (*l_cursor)(struct tty *vt, int x, int y); // after the cursor has moved void (*l_clear)(struct tty *vt, int x, int y, int len); // after a chunk of screen has been cleared // If an endpoint spills outside of the current line, it // must go all the way to an end of screen. // If the cursor moves, you'll get a separate l_cursor, although // it is already in place during the l_clear call. void (*l_scroll)(struct tty *vt, int nl); // after the region s1<=y<s2 is scrolled nl lines // * nl<0 -> scrolling backwards // * nl>0 -> scrolling forwards // The cursor is already moved. void (*l_flag)(struct tty *vt, int f, int v); // when a flag changes to v void (*l_osc)(struct tty *vt, int cmd, const char *str); // string command (window title, etc) void (*l_resize)(struct tty *vt, int sx, int sy); // after the terminal has been resized void (*l_flush)(struct tty *vt); // when a write chunk ends void (*l_bell)(struct tty *vt); // when an \a is received void (*l_free)(struct tty *vt); // before the terminal is destroyed } *tty; tty tty_init(int sx, int sy, int resizable); int tty_resize(tty vt, int nsx, int nsy); void tty_reset(tty vt); void tty_free(tty vt); void tty_write(tty vt, const char *buf, int len); void tty_printf(tty vt, const char *fmt, ...) \ __attribute__((format (printf, 2, 3))); tty tty_copy(tty vt); uint32_t tty_color_convert(uint32_t c, uint32_t to); void vtvt_dump(tty vt); void vtvt_resize(tty vt, int sx, int sy); void vtvt_attach(tty vt, FILE *f, int dump); #endif �����������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/ttyrec.h������������������������������������������������������������������������0000664�0000000�0000000�00000010530�13646775175�0016122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _TTYREC_H #define _TTYREC_H #include <sys/time.h> #include <tty.h> #ifndef _TTYREC_H_NO_TYPES typedef struct TTYRecRecorder *recorder; typedef struct TTYRec *ttyrec; typedef struct { struct timeval t; int len; char *data; } *ttyrec_frame; #endif #define SM_READ 0 #define SM_WRITE 1 #define SM_REPREAD 2 #define SM_APPEND 3 int open_stream(int fd, const char* url, int mode, const char **error); const char* ttyrec_w_find_format(const char *format, const char *filename, const char *fallback); recorder ttyrec_w_open(int fd, const char *format, const char *filename, const struct timeval *ts); int ttyrec_w_write(recorder r, const struct timeval *tm, const char *data, int len); int ttyrec_w_close(recorder r); const char* ttyrec_w_get_format_name(int i); const char* ttyrec_w_get_format_ext(const char *format); const char* ttyrec_r_find_format(const char *format, const char *filename, const char *fallback); const char* ttyrec_r_get_format_name(int i); const char* ttyrec_r_get_format_ext(const char *format); int ttyrec_r_play(int fd, const char *format, const char *filename, void (*synch_init_wait)(const struct timeval *ts, void *arg), void (*synch_wait)(const struct timeval *delay, void *arg), void (*synch_print)(const char *data, int len, void *arg), void *arg); ttyrec ttyrec_init(tty vt); ttyrec ttyrec_load(int fd, const char *format, const char *filename, tty vt); void ttyrec_free(ttyrec tr); ttyrec_frame ttyrec_seek(ttyrec tr, const struct timeval *t, tty *vt); ttyrec_frame ttyrec_next_frame(ttyrec tr, ttyrec_frame tfv); void ttyrec_add_frame(ttyrec tr, const struct timeval *delay, const char *data, int len); int ttyrec_save(ttyrec tr, int fd, const char *format, const char *filename, const struct timeval *selstart, const struct timeval *selend); #define tadd(t, d) do \ {if (((t).tv_usec+=(d).tv_usec)>=1000000) \ (t).tv_usec-=1000000, (t).tv_sec++; \ (t).tv_sec+=(d).tv_sec; \ } while (0) #define tsub(t, d) do \ {if ((signed)((t).tv_usec-=(d).tv_usec)<0) \ (t).tv_usec+=1000000, (t).tv_sec--; \ (t).tv_sec-=(d).tv_sec; \ } while (0) #define tmul1000(t, m) do \ {long long v; \ v=((long long)(t).tv_usec)*(m)/1000+ \ ((long long)(t).tv_sec)*(m)*1000; \ (t).tv_usec=v%1000000; \ (t).tv_sec=v/1000000; \ if ((t).tv_usec<0) \ (t).tv_usec+=1000000, (t).tv_sec--; \ } while (0) #define tdiv1000(t, m) do \ {long long v; \ v=((long long)(t).tv_sec)*1000000+(t).tv_usec; \ v*=1000; \ v/=m; \ (t).tv_usec=v%1000000; \ (t).tv_sec=v/1000000; \ if ((t).tv_usec<0) \ (t).tv_usec+=1000000, (t).tv_sec--; \ } while (0) #define tcmp(t1, t2) (((t1).tv_sec>(t2).tv_sec)?1: \ ((t1).tv_sec<(t2).tv_sec)?-1: \ ((t1).tv_usec>(t2).tv_usec)?1: \ ((t1).tv_usec<(t2).tv_usec)?-1:0) #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/vtredir.c�����������������������������������������������������������������������0000664�0000000�0000000�00000013566�13646775175�0016276�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include "tty.h" #include "sys/ttysize.h" #include "export.h" #include "charsets.h" #include "wcwidth.h" struct vtvt_data { FILE *f; int sx,sy; uint64_t attr; int cx,cy; }; #define DATA ((struct vtvt_data*)(vt->l_data)) #define SX DATA->sx #define SY DATA->sy #define CX DATA->cx #define CY DATA->cy static void print_color(FILE *f, uint32_t c, int bg) { switch (c&VT100_ATTR_COLOR_TYPE) { case 1<<24: if (c&8) fprintf(f, ";%d%u", 9+bg, c&7); else fprintf(f, ";%d%u", 3+bg, c&7); break; case 2<<24: fprintf(f, ";%d8;5;%u", 3+bg, c&0xff); break; case 3<<24: fprintf(f, ";%d8;2;%u;%u;%u", 3+bg, (c>>16)&0xff, (c>>8)&0xff, c&0xff); } } static void setattr(tty vt, uint64_t attr) { if (DATA->attr==attr) return; DATA->attr=attr; fprintf(DATA->f, "\e[0"); if (attr&VT100_ATTR_BOLD) fprintf(DATA->f, ";1"); if (attr&VT100_ATTR_DIM) fprintf(DATA->f, ";2"); if (attr&VT100_ATTR_ITALIC) fprintf(DATA->f, ";3"); if (attr&VT100_ATTR_UNDERLINE) fprintf(DATA->f, ";4"); if (attr&VT100_ATTR_BLINK) fprintf(DATA->f, ";5"); if (attr&VT100_ATTR_INVERSE) fprintf(DATA->f, ";7"); if (attr&VT100_ATTR_STRIKE) fprintf(DATA->f, ";9"); print_color(DATA->f, attr, 0); print_color(DATA->f, attr>>32, 1); fprintf(DATA->f, "m"); } static void vtvt_cursor(tty vt, int x, int y) { if (x==CX && y==CY) return; fprintf(DATA->f, "\e[%d;%df", y+1, x+1); CX=x; CY=y; } #define MAXVT100GRAPH 0x2666 // biggest codepoint is U+2666 BLACK DIAMOND static char *vt100graph = 0; static void build_vt100graph(void) { int i; /* the reverse mapping Unicode->tty_graphic takes a chunk of memory, so build it only on demand. This won't happen most of the time. */ if (!(vt100graph=malloc(MAXVT100GRAPH+1))) abort(); memset(vt100graph, 0, MAXVT100GRAPH+1); for (i=32; i<127; i++) if (charset_vt100[i]<=MAXVT100GRAPH) vt100graph[charset_vt100[i]]=i; } static void vtvt_char(tty vt, int x, int y, ucs ch, uint64_t attr, int width) { if (x>=SX || y>SY) return; if (x!=CX || y!=CY) vtvt_cursor(vt, x, y); setattr(vt, attr); if (fprintf(DATA->f, "%lc", ch)<0) { clearerr(DATA->f); // required on BSD if (width==2) fprintf(DATA->f, "??"); // nothing is wide in cp437 else if (vt->cp437) { if (!vt100graph) build_vt100graph(); if (ch<=MAXVT100GRAPH && vt100graph[ch]) fprintf(DATA->f, "\016%c\017", vt100graph[ch]); else fprintf(DATA->f, "?"); } else fprintf(DATA->f, "?"); } CX++; } static void vtvt_comb(tty vt, int x, int y, ucs ch, uint64_t attr) { if (x>=SX || y>SY) return; if (x+1!=CX || y!=CY) // cursor should be _after_ the glyph vtvt_cursor(vt, x+1, y); setattr(vt, attr); if (fprintf(DATA->f, "%lc", ch)<0) clearerr(DATA->f); // No fallback, just ignore. } export void vtvt_dump(tty vt) { int x,y; attrchar *ch; ch=vt->scr; for (y=0; y<vt->sy; y++) { for (x=0; x<vt->sx; x++) { if (ch->ch != VT100_CJK_RIGHT) vtvt_char(vt, x, y, ch->ch, ch->attr, mk_wcwidth(ch->ch)); ch++; } } vtvt_cursor(vt, vt->cx, vt->cy); } static void vtvt_clear(tty vt, int x, int y, int len) { int c; setattr(vt, vt->attr); if (x==0 && y==0 && len==SX*SY) fprintf(DATA->f, "\e[2J"); else if (x==0 && y==0 && len==CY*SX+CX) fprintf(DATA->f, "\e[1J"); else if (x==CX && y==CY && len==SX*SY-CY*SX-CX) fprintf(DATA->f, "\e[0J"); else if (x==0 && y==CY && len==SX) fprintf(DATA->f, "\e[2K"); else if (x==0 && y==CY && len==CX) fprintf(DATA->f, "\e[1K"); else if (x==CX && y==CY && len==SX-CX) fprintf(DATA->f, "\e[0K"); else while (len) { vtvt_cursor(vt, x, y); c=(len>SX-x)? SX-x : len; fprintf(DATA->f, "\e[%dX", c); len-=c; x=0; y++; } vtvt_cursor(vt, vt->cx, vt->cy); } static void vtvt_scroll(tty vt, int nl) { if (nl>0) fprintf(DATA->f, "\e[0m\e[%d;%dr\e[%d;1f\e[%dM\e[r", vt->s1+1, vt->s2, vt->s1+1, nl); else if (nl<0) fprintf(DATA->f, "\e[0m\e[%d;%dr\e[%d;1f\e[%dL\e[r", vt->s1+1, vt->s2, vt->s1+1, -nl); CX=CY=-1; DATA->attr=0; // vtvt_dump(vt); } static void vtvt_flag(tty vt, int f, int v) { // TODO: invisible cursor } static void vtvt_osc(tty vt, int cmd, const char *str) { // don't passthrough unknown commands if (cmd==0) // set window title fprintf(DATA->f, "\e]0;%s\e\\", str); } static void vtvt_resized(tty vt, int sx, int sy) { fprintf(DATA->f, "\e[8;%u;%ut", sy, sx); } static void vtvt_flush(tty vt) { fflush(DATA->f); } static void vtvt_bell(tty vt) { putc('\a', DATA->f); } static void vtvt_free(tty vt) { free(vt->l_data); } export void vtvt_resize(tty vt, int sx, int sy) { SX=sx; SY=sy; } export void vtvt_attach(tty vt, FILE *f, int dump) { vt->l_data=malloc(sizeof(struct vtvt_data)); CX=CY=-1; DATA->attr=-1; DATA->f=f; SX=80; SY=25; get_tty_size(fileno(f), &SX, &SY); vt->l_char=vtvt_char; vt->l_comb=vtvt_comb; vt->l_cursor=vtvt_cursor; vt->l_clear=vtvt_clear; vt->l_scroll=vtvt_scroll; vt->l_flag=vtvt_flag; vt->l_osc=vtvt_osc; vt->l_resize=vtvt_resized; vt->l_flush=vtvt_flush; vt->l_bell=vtvt_bell; vt->l_free=vtvt_free; if (dump) { fprintf(DATA->f, "\ec"); vtvt_dump(vt); fflush(stdout); } } ������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/wcwidth.c�����������������������������������������������������������������������0000664�0000000�0000000�00000022257�13646775175�0016265�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include "export.h" #include "wcwidth.h" /* * This is an implementation of wcwidth() and wcswidth() (defined in * IEEE Std 1002.1-2001) for Unicode. * * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html * * In fixed-width output devices, Latin characters all occupy a single * "cell" position of equal width, whereas ideographic CJK characters * occupy two such cells. Interoperability between terminal-line * applications and (teletype-style) character terminals using the * UTF-8 encoding requires agreement on which character should advance * the cursor by how many cell positions. No established formal * standards exist at present on which Unicode character shall occupy * how many cell positions on character terminals. These routines are * a first attempt of defining such behavior based on simple rules * applied to data provided by the Unicode Consortium. * * For some graphical characters, the Unicode standard explicitly * defines a character-cell width via the definition of the East Asian * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. * In all these cases, there is no ambiguity about which width a * terminal shall use. For characters in the East Asian Ambiguous (A) * class, the width choice depends purely on a preference of backward * compatibility with either historic CJK or Western practice. * Choosing single-width for these characters is easy to justify as * the appropriate long-term solution, as the CJK practice of * displaying these characters as double-width comes from historic * implementation simplicity (8-bit encoded characters were displayed * single-width and 16-bit ones double-width, even for Greek, * Cyrillic, etc.) and not any typographic considerations. * * Much less clear is the choice of width for the Not East Asian * (Neutral) class. Existing practice does not dictate a width for any * of these characters. It would nevertheless make sense * typographically to allocate two character cells to characters such * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be * represented adequately with a single-width glyph. The following * routines at present merely assign a single-cell width to all * neutral characters, in the interest of simplicity. This is not * entirely satisfactory and should be reconsidered before * establishing a formal standard in this area. At the moment, the * decision which Not East Asian (Neutral) characters should be * represented by double-width glyphs cannot yet be answered by * applying a simple rule from the Unicode database content. Setting * up a proper standard for the behavior of UTF-8 character terminals * will require a careful analysis not only of each Unicode character, * but also of each presentation form, something the author of these * routines has avoided to do so far. * * http://www.unicode.org/unicode/reports/tr11/ * * Markus Kuhn -- 2007-05-26 (Unicode 5.0) * * Permission to use, copy, modify, and distribute this software * for any purpose and without fee is hereby granted. The author * disclaims all warranties with regard to this software. * * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c */ struct interval { uint32_t first; uint32_t last; }; /* auxiliary function for binary search in interval table */ static int bisearch(uint32_t ucs, const struct interval *table, uint32_t max) { uint32_t min = 0; uint32_t mid; if (ucs < table[0].first || ucs > table[max].last) return 0; while (max >= min) { mid = (min + max) / 2; if (ucs > table[mid].last) min = mid + 1; else if (ucs < table[mid].first) max = mid - 1; else return 1; } return 0; } /* The following two functions define the column width of an ISO 10646 * character as follows: * * - The null character (U+0000) has a column width of 0. * * - Other C0/C1 control characters and DEL will lead to a return * value of -1. * * - Non-spacing and enclosing combining characters (general * category code Mn or Me in the Unicode database) have a * column width of 0. * * - SOFT HYPHEN (U+00AD) has a column width of 1. * * - Other format characters (general category code Cf in the Unicode * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. * * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) * have a column width of 0. * * - Spacing characters in the East Asian Wide (W) or East Asian * Full-width (F) category as defined in Unicode Technical * Report #11 have a column width of 2. * * - All remaining characters (including all printable * ISO 8859-1 and WGL4 characters, Unicode control characters, * etc.) have a column width of 1. * * This implementation assumes that wchar_t characters are encoded * in ISO 10646. */ int mk_wcwidth(uint32_t ucs) { /* sorted list of non-overlapping intervals of non-spacing characters */ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ static const struct interval combining[] = { { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, { 0xE0100, 0xE01EF } }; /* test for 8-bit control characters */ if (ucs == 0) return 0; if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return -1; /* binary search in table of non-spacing characters */ if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1)) return 0; /* if we arrive here, ucs is not a combining or C0/C1 control character */ return 1 + (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ ucs == 0x2329 || ucs == 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd))); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/libtty/wcwidth.h�����������������������������������������������������������������������0000664�0000000�0000000�00000000061�13646775175�0016257�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdint.h> int mk_wcwidth(uint32_t u); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0013451�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_c_try_flag.m4��������������������������������������������������������������������0000664�0000000�0000000�00000000633�13646775175�0016471�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl =========================================================================== dnl check compiler flags AC_DEFUN([AC_C_TRY_FLAG], [ AC_MSG_CHECKING([whether $CC supports $1]) ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_COMPILE_IFELSE([AC_LANG_SOURCE([ ])], [ac_c_flag=yes], [ac_c_flag=no]) if test "x$ac_c_flag" = "xno"; then CFLAGS="$ac_save_CFLAGS" fi AC_MSG_RESULT([$ac_c_flag]) ]) �����������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_check_win32.m4�������������������������������������������������������������������0000664�0000000�0000000�00000003223�13646775175�0016455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl Check for WIN32, without needing all the config.guess bulkiness. AC_DEFUN([AC_CHECK_WIN32], [ AC_CACHE_CHECK([for Win32], [ac_cv_is_win32], [ ac_check_win32_save_LIBS=$LIBS LIBS=-lgdi32 AC_LINK_IFELSE([AC_LANG_SOURCE([ #include <windows.h> int main(){TextOutW(0,0,0,0,0);return 0;}])], [ac_cv_is_win32=yes], [ac_cv_is_win32=no]) LIBS=$ac_check_win32_save_LIBS ]) if test $ac_cv_is_win32 = yes; then AC_DEFINE([IS_WIN32], 1, [Define if you're a Bill worshipper.]) fi ]) dnl Add WinSock if it's present. AC_DEFUN([AC_LIB_WINSOCK2], [ AC_MSG_CHECKING([for WinSock2]) ac_lib_ws2_save_LIBS=$LIBS LIBS="-lws2_32" AC_LINK_IFELSE([AC_LANG_SOURCE([ #include "windows.h" int main(){WSACleanup();return 0;}])], [ LIBS="$ac_lib_ws2_save_LIBS -lws2_32" AC_MSG_RESULT([yes]) ], [ LIBS=$ac_lib_ws2_save_LIBS AC_MSG_RESULT([no]) ]) ]) dnl Check if gai_strerror is #defined (like in new MINGW headers). AC_DEFUN([AC_FUNC_WIN32_GAI_STERRROR], [ AC_MSG_CHECKING([if gai_strerror is a winsock macro]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include <winsock2.h> #include <windows.h> #include <ws2tcpip.h> int main(){gai_strerror(0);return 0;}])], [ AC_DEFINE([HAVE_WIN32_GAI_STRERROR], [1], [Define if a macro]) AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) ]) ]) dnl Check if getaddrinfo is #defined (like in MINGW-W64 headers). AC_DEFUN([AC_FUNC_WIN32_GETADDRINFO], [ AC_MSG_CHECKING([for winsock getaddrinfo]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include <winsock2.h> #include <windows.h> #include <ws2tcpip.h> int main(){getaddrinfo(0,0,0,0);return 0;}])], [ AC_DEFINE([HAVE_WIN32_GETADDRINFO], [1], [Define if available]) AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) ]) ]) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_decl_or_zero.m4������������������������������������������������������������������0000664�0000000�0000000�00000001032�13646775175�0017020�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl *************************************** dnl *** AC_DECL_OR_ZERO(symbol, header) *** dnl *************************************** dnl dnl Checks if the given symbol (rvalue) is defined in the given header dnl -- if not, #defines it to 0. AC_DEFUN([AC_DECL_OR_ZERO], [ AC_MSG_CHECKING([for $1]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([#include <$2> int main() { char *p=(char*)$1; return !p; } ])], [AC_MSG_RESULT([yes])], [ AC_MSG_RESULT([no, defining as 0]) AC_DEFINE([$1], [0], [Set to 0 if not supported]) ]) ]) ]) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_ptyranges.m4���������������������������������������������������������������������0000664�0000000�0000000�00000002046�13646775175�0016374�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl check for valid pty ranges, stolen from screen sources dnl Note: this does break cross-compiling. AC_DEFUN([AC_PTYRANGES], [ AC_MSG_CHECKING(ptyranges) if test -d /dev/ptym ; then pdir='/dev/ptym' else pdir='/dev' fi dnl SCO uses ptyp%d AC_EGREP_CPP(yes, [#ifdef M_UNIX yes; #endif ], ptys=`echo /dev/ptyp??`, ptys=`echo $pdir/pty??`) dnl if test -c /dev/ptyp19; then dnl ptys=`echo /dev/ptyp??` dnl else dnl ptys=`echo $pdir/pty??` dnl fi if test "$ptys" != "$pdir/pty??" ; then p0=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\).$/\1/g' | sort -u | tr -d '\012'` p1=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\)$/\1/g' | sort -u | tr -d '\012'` AC_DEFINE_UNQUOTED(PTYRANGE0,"$p0",[The range of Xes in /dev/ptyXY]) AC_DEFINE_UNQUOTED(PTYRANGE1,"$p1",[The range of Ys in /dev/ptyXY]) AC_MSG_RESULT([$p0,$p1]) else AC_MSG_RESULT([]) fi ]) AC_DEFUN([AC_DEV_PTMX], [ AC_MSG_CHECKING(for /dev/ptmx) if test -c /dev/ptmx then AC_DEFINE([HAVE_DEV_PTMX], [1], [Define if you have /dev/ptmx]) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi ]) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_sco.m4���������������������������������������������������������������������������0000664�0000000�0000000�00000000274�13646775175�0015145�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������AC_DEFUN([AC_SCO], [ AC_MSG_CHECKING([for SCO's intellectual property]) case `uname -s`X in SCO_*) AC_MSG_RESULT([nope, it belongs to Novell]) ;; *) AC_MSG_RESULT([not found]) esac ]) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_shipped_lib.m4�������������������������������������������������������������������0000664�0000000�0000000�00000001342�13646775175�0016640�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl Check if our static copy of library works. AC_DEFUN([AC_SHIPPED_LIB], [ AC_MSG_CHECKING([whether our shipped $2 works]) baselib=`echo "$1"|tr A-Z a-z` ac_shipped_lib_save_LIBS=$LIBS LIBS="-L$5lib -l${baselib#lib}" AC_LINK_IFELSE([AC_LANG_SOURCE([ #include "$5lib/$3" int main(){$4;return 0;}])], [ AC_DEFINE([SHIPPED_$1], [1], [Define if shipped $2 works.]) AC_DEFINE([SHIPPED_$1_H], ["$5lib/$3"], [Set to your custom $3]) $1="-L`pwd`/$5lib -l${baselib#lib}" AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])]) LIBS=$ac_shipped_lib_save_LIBS ]) dnl Tell autoconf we have lib$1 but don't add it to LIBS. AC_DEFUN([AC_HAVE_LIB], [ LIB$2=-l$1 AC_DEFINE([HAVE_LIB$2], [1], [Define to 1 if you have the `$1' library (-l$1).]) ]) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_visibility.m4��������������������������������������������������������������������0000664�0000000�0000000�00000000616�13646775175�0016550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl can we block unwanted symbols? AC_DEFUN([AC_VISIBILITY], [ AC_MSG_CHECKING([for GCC visibility attr]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ # define export __attribute__ ((visibility ("default"))) # pragma GCC visibility push(hidden) ])], [AC_DEFINE([GCC_VISIBILITY], [1], [Define to 1 if the compiler uses GCC's visibility __attribute__s.]) AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])]) ]) ������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ac_zstd.m4��������������������������������������������������������������������������0000664�0000000�0000000�00000000754�13646775175�0015350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl Ancient versions of zstd lack interfaces we use. AC_DEFUN([AC_ZSTD], [ AC_MSG_CHECKING([for working zstd]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([#include <zstd.h> int main() { size_t const inbufsz = ZSTD_DStreamInSize(); ZSTD_DStream* const stream = ZSTD_createDStream(); ZSTD_freeDStream(stream); return inbufsz; } ])], [AC_MSG_RESULT([yes]) AC_DEFINE([WORKING_ZSTD], [1], [Set to 1 if new enough])], [ AC_MSG_RESULT([no, missing or no good]) ]) ]) ]) ��������������������termrec-0.19/m4/ax_check_compile_flag.m4������������������������������������������������������������0000664�0000000�0000000�00000006411�13646775175�0020163�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> # Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # 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 GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see <http://www.gnu.org/licenses/>. # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ax_create_stdint_h.m4���������������������������������������������������������������0000664�0000000�0000000�00000061564�13646775175�0017556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_create_stdint_h.html # =========================================================================== # # SYNOPSIS # # AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] # # DESCRIPTION # # the "ISO C9X: 7.18 Integer types <stdint.h>" section requires the # existence of an include file <stdint.h> that defines a set of typedefs, # especially uint8_t,int32_t,uintptr_t. Many older installations will not # provide this file, but some will have the very same definitions in # <inttypes.h>. In other environments we can use the inet-types in # <sys/types.h> which would define the typedefs int8_t and u_int8_t # respectively. # # This macros will create a local "_stdint.h" or the headerfile given as # an argument. In many cases that file will just "#include <stdint.h>" or # "#include <inttypes.h>", while in other environments it will provide the # set of basic 'stdint's definitions/typedefs: # # int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t # int_least32_t.. int_fast32_t.. intmax_t # # which may or may not rely on the definitions of other files, or using # the AC_CHECK_SIZEOF macro to determine the actual sizeof each type. # # if your header files require the stdint-types you will want to create an # installable file mylib-int.h that all your other installable header may # include. So if you have a library package named "mylib", just use # # AX_CREATE_STDINT_H(mylib-int.h) # # in configure.ac and go to install that very header file in Makefile.am # along with the other headers (mylib.h) - and the mylib-specific headers # can simply use "#include <mylib-int.h>" to obtain the stdint-types. # # Remember, if the system already had a valid <stdint.h>, the generated # file will include it directly. No need for fuzzy HAVE_STDINT_H things... # (oops, GCC 4.2.x has deliberately disabled its stdint.h for non-c99 # compilation and the c99-mode is not the default. Therefore this macro # will not use the compiler's stdint.h - please complain to the GCC # developers). # # LICENSE # # Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 3 of the License, or (at your # option) any later version. # # 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 GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see <http://www.gnu.org/licenses/>. # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 10 AC_DEFUN([AX_CHECK_DATA_MODEL],[ AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(void*) ac_cv_char_data_model="" ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char" ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short" ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int" ac_cv_long_data_model="" ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int" ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long" ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp" AC_MSG_CHECKING([data model]) case "$ac_cv_char_data_model/$ac_cv_long_data_model" in 122/242) ac_cv_data_model="IP16" ; n="standard 16bit machine" ;; 122/244) ac_cv_data_model="LP32" ; n="standard 32bit machine" ;; 122/*) ac_cv_data_model="i16" ; n="unusual int16 model" ;; 124/444) ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;; 124/488) ac_cv_data_model="LP64" ; n="standard 64bit unixish" ;; 124/448) ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;; 124/*) ac_cv_data_model="i32" ; n="unusual int32 model" ;; 128/888) ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;; 128/*) ac_cv_data_model="i64" ; n="unusual int64 model" ;; 222/*2) ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;; 333/*3) ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;; 444/*4) ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;; 666/*6) ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;; 888/*8) ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;; 222/*|333/*|444/*|666/*|888/*) : ac_cv_data_model="iDSP" ; n="unusual dsptype" ;; *) ac_cv_data_model="none" ; n="very unusual model" ;; esac AC_MSG_RESULT([$ac_cv_data_model ($ac_cv_long_data_model, $n)]) ]) dnl AX_CHECK_HEADER_STDINT_X([HEADERLIST][,ACTION-IF]) AC_DEFUN([AX_CHECK_HEADER_STDINT_X],[ AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) AC_MSG_RESULT([(..)]) for i in m4_ifval([$1],[$1],[stdint.h inttypes.h sys/inttypes.h sys/types.h]) do unset ac_cv_type_uintptr_t unset ac_cv_type_uint64_t AC_CHECK_TYPE(uintptr_t,[ac_cv_header_stdint_x=$i],continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) m4_ifvaln([$2],[$2]) break done AC_MSG_CHECKING([for stdint uintptr_t]) ]) ]) AC_DEFUN([AX_CHECK_HEADER_STDINT_O],[ AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) AC_MSG_RESULT([(..)]) for i in m4_ifval([$1],[$1],[inttypes.h sys/inttypes.h sys/types.h stdint.h]) do unset ac_cv_type_uint32_t unset ac_cv_type_uint64_t AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) m4_ifvaln([$2],[$2]) break break; done AC_MSG_CHECKING([for stdint uint32_t]) ]) ]) AC_DEFUN([AX_CHECK_HEADER_STDINT_U],[ AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) AC_MSG_RESULT([(..)]) for i in m4_ifval([$1],[$1],[sys/types.h inttypes.h sys/inttypes.h]) ; do unset ac_cv_type_u_int32_t unset ac_cv_type_u_int64_t AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],continue,[#include <$i>]) AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) m4_ifvaln([$2],[$2]) break break; done AC_MSG_CHECKING([for stdint u_int32_t]) ]) ]) AC_DEFUN([AX_CREATE_STDINT_H], [# ------ AX CREATE STDINT H ------------------------------------- AC_MSG_CHECKING([for stdint types]) ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` # try to shortcircuit - if the default include path of the compiler # can find a "stdint.h" header then we assume that all compilers can. AC_CACHE_VAL([ac_cv_header_stdint_t],[ old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" old_CFLAGS="$CFLAGS" ; CFLAGS="" AC_TRY_COMPILE([#include <stdint.h>],[int_least32_t v = 0;], [ac_cv_stdint_result="(assuming C99 compatible system)" ac_cv_header_stdint_t="stdint.h"; ], [ac_cv_header_stdint_t=""]) if test "$GCC" = "yes" && test ".$ac_cv_header_stdint_t" = "."; then CFLAGS="-std=c99" AC_TRY_COMPILE([#include <stdint.h>],[int_least32_t v = 0;], [AC_MSG_WARN(your GCC compiler has a defunct stdint.h for its default-mode)]) fi CXXFLAGS="$old_CXXFLAGS" CPPFLAGS="$old_CPPFLAGS" CFLAGS="$old_CFLAGS" ]) v="... $ac_cv_header_stdint_h" if test "$ac_stdint_h" = "stdint.h" ; then AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) elif test "$ac_stdint_h" = "inttypes.h" ; then AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) elif test "_$ac_cv_header_stdint_t" = "_" ; then AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) else ac_cv_header_stdint="$ac_cv_header_stdint_t" AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) fi if test "_$ac_cv_header_stdint_t" = "_" ; then # cannot shortcircuit.. dnl .....intro message done, now do a few system checks..... dnl btw, all old CHECK_TYPE macros do automatically "DEFINE" a type, dnl therefore we use the autoconf implementation detail CHECK_TYPE_NEW dnl instead that is triggered with 3 or more arguments (see types.m4) inttype_headers=`echo $2 | sed -e 's/,/ /g'` ac_cv_stdint_result="(no helpful system typedefs seen)" AX_CHECK_HEADER_STDINT_X(dnl stdint.h inttypes.h sys/inttypes.h $inttype_headers, ac_cv_stdint_result="(seen uintptr_t$and64 in $i)") if test "_$ac_cv_header_stdint_x" = "_" ; then AX_CHECK_HEADER_STDINT_O(dnl, inttypes.h sys/inttypes.h stdint.h $inttype_headers, ac_cv_stdint_result="(seen uint32_t$and64 in $i)") fi if test "_$ac_cv_header_stdint_x" = "_" ; then if test "_$ac_cv_header_stdint_o" = "_" ; then AX_CHECK_HEADER_STDINT_U(dnl, sys/types.h inttypes.h sys/inttypes.h $inttype_headers, ac_cv_stdint_result="(seen u_int32_t$and64 in $i)") fi fi dnl if there was no good C99 header file, do some typedef checks... if test "_$ac_cv_header_stdint_x" = "_" ; then AC_MSG_CHECKING([for stdint datatype model]) AC_MSG_RESULT([(..)]) AX_CHECK_DATA_MODEL fi if test "_$ac_cv_header_stdint_x" != "_" ; then ac_cv_header_stdint="$ac_cv_header_stdint_x" elif test "_$ac_cv_header_stdint_o" != "_" ; then ac_cv_header_stdint="$ac_cv_header_stdint_o" elif test "_$ac_cv_header_stdint_u" != "_" ; then ac_cv_header_stdint="$ac_cv_header_stdint_u" else ac_cv_header_stdint="stddef.h" fi AC_MSG_CHECKING([for extra inttypes in chosen header]) AC_MSG_RESULT([($ac_cv_header_stdint)]) dnl see if int_least and int_fast types are present in _this_ header. unset ac_cv_type_int_least32_t unset ac_cv_type_int_fast32_t AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) fi # shortcircut to system "stdint.h" # ------------------ PREPARE VARIABLES ------------------------------ if test "$GCC" = "yes" ; then ac_cv_stdint_message="using gnu compiler "`$CC --version | head -1` else ac_cv_stdint_message="using $CC" fi AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl $ac_cv_stdint_result]) dnl ----------------------------------------------------------------- # ----------------- DONE inttypes.h checks START header ------------- AC_CONFIG_COMMANDS([$ac_stdint_h],[ AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) ac_stdint=$tmp/_stdint.h echo "#ifndef" $_ac_stdint_h >$ac_stdint echo "#define" $_ac_stdint_h "1" >>$ac_stdint echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint if test "_$ac_cv_header_stdint_t" != "_" ; then echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint echo "#include <stdint.h>" >>$ac_stdint echo "#endif" >>$ac_stdint echo "#endif" >>$ac_stdint else cat >>$ac_stdint <<STDINT_EOF /* ................... shortcircuit part ........................... */ #if defined HAVE_STDINT_H || defined _STDINT_HAVE_STDINT_H #include <stdint.h> #else #include <stddef.h> /* .................... configured part ............................ */ STDINT_EOF echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint if test "_$ac_cv_header_stdint_x" != "_" ; then ac_header="$ac_cv_header_stdint_x" echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint else echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint fi echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint if test "_$ac_cv_header_stdint_o" != "_" ; then ac_header="$ac_cv_header_stdint_o" echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint else echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint fi echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint if test "_$ac_cv_header_stdint_u" != "_" ; then ac_header="$ac_cv_header_stdint_u" echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint else echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint fi echo "" >>$ac_stdint if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then echo "#include <$ac_header>" >>$ac_stdint echo "" >>$ac_stdint fi fi echo "/* which 64bit typedef has been found */" >>$ac_stdint if test "$ac_cv_type_uint64_t" = "yes" ; then echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint else echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint fi if test "$ac_cv_type_u_int64_t" = "yes" ; then echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint else echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint fi echo "" >>$ac_stdint echo "/* which type model has been detected */" >>$ac_stdint if test "_$ac_cv_char_data_model" != "_" ; then echo "#define _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint echo "#define _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint else echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint fi echo "" >>$ac_stdint echo "/* whether int_least types were detected */" >>$ac_stdint if test "$ac_cv_type_int_least32_t" = "yes"; then echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint else echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint fi echo "/* whether int_fast types were detected */" >>$ac_stdint if test "$ac_cv_type_int_fast32_t" = "yes"; then echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint else echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint fi echo "/* whether intmax_t type was detected */" >>$ac_stdint if test "$ac_cv_type_intmax_t" = "yes"; then echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint else echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint fi echo "" >>$ac_stdint cat >>$ac_stdint <<STDINT_EOF /* .................... detections part ............................ */ /* whether we need to define bitspecific types from compiler base types */ #ifndef _STDINT_HEADER_INTPTR #ifndef _STDINT_HEADER_UINT32 #ifndef _STDINT_HEADER_U_INT32 #define _STDINT_NEED_INT_MODEL_T #else #define _STDINT_HAVE_U_INT_TYPES #endif #endif #endif #ifdef _STDINT_HAVE_U_INT_TYPES #undef _STDINT_NEED_INT_MODEL_T #endif #ifdef _STDINT_CHAR_MODEL #if _STDINT_CHAR_MODEL+0 == 122 || _STDINT_CHAR_MODEL+0 == 124 #ifndef _STDINT_BYTE_MODEL #define _STDINT_BYTE_MODEL 12 #endif #endif #endif #ifndef _STDINT_HAVE_INT_LEAST32_T #define _STDINT_NEED_INT_LEAST_T #endif #ifndef _STDINT_HAVE_INT_FAST32_T #define _STDINT_NEED_INT_FAST_T #endif #ifndef _STDINT_HEADER_INTPTR #define _STDINT_NEED_INTPTR_T #ifndef _STDINT_HAVE_INTMAX_T #define _STDINT_NEED_INTMAX_T #endif #endif /* .................... definition part ............................ */ /* some system headers have good uint64_t */ #ifndef _HAVE_UINT64_T #if defined _STDINT_HAVE_UINT64_T || defined HAVE_UINT64_T #define _HAVE_UINT64_T #elif defined _STDINT_HAVE_U_INT64_T || defined HAVE_U_INT64_T #define _HAVE_UINT64_T typedef u_int64_t uint64_t; #endif #endif #ifndef _HAVE_UINT64_T /* .. here are some common heuristics using compiler runtime specifics */ #if defined __STDC_VERSION__ && defined __STDC_VERSION__ >= 199901L #define _HAVE_UINT64_T #define _HAVE_LONGLONG_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #elif !defined __STRICT_ANSI__ #if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ #define _HAVE_UINT64_T typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ /* note: all ELF-systems seem to have loff-support which needs 64-bit */ #if !defined _NO_LONGLONG #define _HAVE_UINT64_T #define _HAVE_LONGLONG_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #endif #elif defined __alpha || (defined __mips && defined _ABIN32) #if !defined _NO_LONGLONG typedef long int64_t; typedef unsigned long uint64_t; #endif /* compiler/cpu type to define int64_t */ #endif #endif #endif #if defined _STDINT_HAVE_U_INT_TYPES /* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ typedef u_int8_t uint8_t; typedef u_int16_t uint16_t; typedef u_int32_t uint32_t; /* glibc compatibility */ #ifndef __int8_t_defined #define __int8_t_defined #endif #endif #ifdef _STDINT_NEED_INT_MODEL_T /* we must guess all the basic types. Apart from byte-adressable system, */ /* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ /* (btw, those nibble-addressable systems are way off, or so we assume) */ dnl /* have a look at "64bit and data size neutrality" at */ dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ dnl /* (the shorthand "ILP" types always have a "P" part) */ #if defined _STDINT_BYTE_MODEL #if _STDINT_LONG_MODEL+0 == 242 /* 2:4:2 = IP16 = a normal 16-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef long int32_t; #endif #elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 /* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ /* 4:4:4 = ILP32 = a normal 32-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef int int32_t; #endif #elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 /* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ /* 4:8:8 = LP64 = a normal 64-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef int int32_t; #endif /* this system has a "long" of 64bit */ #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef unsigned long uint64_t; typedef long int64_t; #endif #elif _STDINT_LONG_MODEL+0 == 448 /* LLP64 a 64-bit system derived from a 32-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef int int32_t; #endif /* assuming the system has a "long long" */ #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T #define _HAVE_LONGLONG_UINT64_T typedef unsigned long long uint64_t; typedef long long int64_t; #endif #else #define _STDINT_NO_INT32_T #endif #else #define _STDINT_NO_INT8_T #define _STDINT_NO_INT32_T #endif #endif /* * quote from SunOS-5.8 sys/inttypes.h: * Use at your own risk. As of February 1996, the committee is squarely * behind the fixed sized types; the "least" and "fast" types are still being * discussed. The probability that the "fast" types may be removed before * the standard is finalized is high enough that they are not currently * implemented. */ #if defined _STDINT_NEED_INT_LEAST_T typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; #ifdef _HAVE_UINT64_T typedef int64_t int_least64_t; #endif typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; #ifdef _HAVE_UINT64_T typedef uint64_t uint_least64_t; #endif /* least types */ #endif #if defined _STDINT_NEED_INT_FAST_T typedef int8_t int_fast8_t; typedef int int_fast16_t; typedef int32_t int_fast32_t; #ifdef _HAVE_UINT64_T typedef int64_t int_fast64_t; #endif typedef uint8_t uint_fast8_t; typedef unsigned uint_fast16_t; typedef uint32_t uint_fast32_t; #ifdef _HAVE_UINT64_T typedef uint64_t uint_fast64_t; #endif /* fast types */ #endif #ifdef _STDINT_NEED_INTMAX_T #ifdef _HAVE_UINT64_T typedef int64_t intmax_t; typedef uint64_t uintmax_t; #else typedef long intmax_t; typedef unsigned long uintmax_t; #endif #endif #ifdef _STDINT_NEED_INTPTR_T #ifndef __intptr_t_defined #define __intptr_t_defined /* we encourage using "long" to store pointer values, never use "int" ! */ #if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 typedef unsigned int uintptr_t; typedef int intptr_t; #elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 typedef unsigned long uintptr_t; typedef long intptr_t; #elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T typedef uint64_t uintptr_t; typedef int64_t intptr_t; #else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ typedef unsigned long uintptr_t; typedef long intptr_t; #endif #endif #endif /* The ISO C99 standard specifies that in C++ implementations these should only be defined if explicitly requested. */ #if !defined __cplusplus || defined __STDC_CONSTANT_MACROS #ifndef UINT32_C /* Signed. */ # define INT8_C(c) c # define INT16_C(c) c # define INT32_C(c) c # ifdef _HAVE_LONGLONG_UINT64_T # define INT64_C(c) c ## L # else # define INT64_C(c) c ## LL # endif /* Unsigned. */ # define UINT8_C(c) c ## U # define UINT16_C(c) c ## U # define UINT32_C(c) c ## U # ifdef _HAVE_LONGLONG_UINT64_T # define UINT64_C(c) c ## UL # else # define UINT64_C(c) c ## ULL # endif /* Maximal type. */ # ifdef _HAVE_LONGLONG_UINT64_T # define INTMAX_C(c) c ## L # define UINTMAX_C(c) c ## UL # else # define INTMAX_C(c) c ## LL # define UINTMAX_C(c) c ## ULL # endif /* literalnumbers */ #endif #endif /* These limits are merily those of a two complement byte-oriented system */ /* Minimum of signed integral types. */ # define INT8_MIN (-128) # define INT16_MIN (-32767-1) # define INT32_MIN (-2147483647-1) # define INT64_MIN (-__INT64_C(9223372036854775807)-1) /* Maximum of signed integral types. */ # define INT8_MAX (127) # define INT16_MAX (32767) # define INT32_MAX (2147483647) # define INT64_MAX (__INT64_C(9223372036854775807)) /* Maximum of unsigned integral types. */ # define UINT8_MAX (255) # define UINT16_MAX (65535) # define UINT32_MAX (4294967295U) # define UINT64_MAX (__UINT64_C(18446744073709551615)) /* Minimum of signed integral types having a minimum size. */ # define INT_LEAST8_MIN INT8_MIN # define INT_LEAST16_MIN INT16_MIN # define INT_LEAST32_MIN INT32_MIN # define INT_LEAST64_MIN INT64_MIN /* Maximum of signed integral types having a minimum size. */ # define INT_LEAST8_MAX INT8_MAX # define INT_LEAST16_MAX INT16_MAX # define INT_LEAST32_MAX INT32_MAX # define INT_LEAST64_MAX INT64_MAX /* Maximum of unsigned integral types having a minimum size. */ # define UINT_LEAST8_MAX UINT8_MAX # define UINT_LEAST16_MAX UINT16_MAX # define UINT_LEAST32_MAX UINT32_MAX # define UINT_LEAST64_MAX UINT64_MAX /* shortcircuit*/ #endif /* once */ #endif #endif STDINT_EOF fi if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then AC_MSG_NOTICE([$ac_stdint_h is unchanged]) else ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` AS_MKDIR_P(["$ac_dir"]) rm -f $ac_stdint_h mv $ac_stdint $ac_stdint_h fi ],[# variables for create stdint.h replacement PACKAGE="$PACKAGE" VERSION="$VERSION" ac_stdint_h="$ac_stdint_h" _ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) ac_cv_stdint_message="$ac_cv_stdint_message" ac_cv_header_stdint_t="$ac_cv_header_stdint_t" ac_cv_header_stdint_x="$ac_cv_header_stdint_x" ac_cv_header_stdint_o="$ac_cv_header_stdint_o" ac_cv_header_stdint_u="$ac_cv_header_stdint_u" ac_cv_type_uint64_t="$ac_cv_type_uint64_t" ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" ac_cv_char_data_model="$ac_cv_char_data_model" ac_cv_long_data_model="$ac_cv_long_data_model" ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" ac_cv_type_intmax_t="$ac_cv_type_intmax_t" ]) ]) ��������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/m4/ax_lib_socket_nsl.m4����������������������������������������������������������������0000664�0000000�0000000�00000002636�13646775175�0017404�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_lib_socket_nsl.html # =========================================================================== # # SYNOPSIS # # AX_LIB_SOCKET_NSL # # DESCRIPTION # # This macro figures out what libraries are required on this platform to # link sockets programs. # # The common cases are not to need any extra libraries, or to need # -lsocket and -lnsl. We need to avoid linking with libnsl unless we need # it, though, since on some OSes where it isn't necessary it will totally # break networking. Unisys also includes gethostbyname() in libsocket but # needs libnsl for socket(). # # LICENSE # # Copyright (c) 2008 Russ Allbery <rra@stanford.edu> # Copyright (c) 2008 Stepan Kasal <kasal@ucw.cz> # Copyright (c) 2008 Warren Young <warren@etr-usa.com> # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AU_ALIAS([LIB_SOCKET_NSL], [AX_LIB_SOCKET_NSL]) AC_DEFUN([AX_LIB_SOCKET_NSL], [ AC_SEARCH_LIBS([gethostbyname], [nsl]) AC_SEARCH_LIBS([socket], [socket], [], [ AC_CHECK_LIB([socket], [socket], [LIBS="-lsocket -lnsl $LIBS"], [], [-lnsl])]) ]) ��������������������������������������������������������������������������������������������������termrec-0.19/m4/ax_pthread.m4�����������������������������������������������������������������������0000664�0000000�0000000�00000031267�13646775175�0016043�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu> # Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG> # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # 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 GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see <http://www.gnu.org/licenses/>. # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 20 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) AC_MSG_RESULT($ax_pthread_ok) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h> static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($ax_pthread_ok) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], ax_cv_PTHREAD_PRIO_INHERIT, [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/play/����������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014076�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/play/Makefile.am�����������������������������������������������������������������������0000664�0000000�0000000�00000000317�13646775175�0016133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������bin_PROGRAMS += termplay termplay_SOURCES = play/termplay.c play/player.h play/player.c termplay_LDADD = libutils.la libcommon.la libtty.la @PTHREAD_LIBS@ termplay_LDFLAGS = @PTHREAD_CFLAGS@ libttyutils.la �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/play/player.c��������������������������������������������������������������������������0000664�0000000�0000000�00000013746�13646775175�0015551�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <tty.h> #include <ttyrec.h> #include <stdio.h> #include <time.h> #include <string.h> #include "error.h" #include "gettext.h" #include "sys/threads.h" #include "play/player.h" static ttyrec_frame fr; static struct timeval t0, tc; ttyrec tr; int speed; tty term; int waiting, loaded; mutex_t waitm; cond_t waitc; static void waitm_unlock(void *arg) { mutex_unlock(waitm); } static int player(void *arg) { ttyrec_frame nf; struct timeval tt, wall; do { while ((nf=ttyrec_next_frame(tr, fr))) { tt=nf->t; tdiv1000(tt, speed); tadd(tt, t0); gettimeofday(&wall, 0); tsub(tt, wall); if (tt.tv_sec>0 || tt.tv_usec>0) select(0, 0, 0, 0, &tt); else if (tt.tv_sec<-1) // if not a minimal skip, slow down the clock tsub(t0, tt); // (tt is negative) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); fr=nf; tty_write(term, fr->data, fr->len); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); } mutex_lock(waitm); if (!(nf=ttyrec_next_frame(tr, fr)) && !loaded) waiting=1; if (waiting) { pthread_cleanup_push(waitm_unlock, 0); cond_wait(waitc, waitm); pthread_cleanup_pop(0); nf=ttyrec_next_frame(tr, fr); } mutex_unlock(waitm); } while (nf || !loaded); return 0; } static thread_t playth; static int play_state; static void replay_start(void) { if (play_state) return; play_state=1; gettimeofday(&t0, 0); tdiv1000(tc, speed); tsub(t0, tc); if (thread_create_joinable(&playth, player, 0)) die("Cannot create thread"); } static void replay_stop(void) { if (!play_state) return; gettimeofday(&tc, 0); // calc where we stopped tsub(tc, t0); tmul1000(tc, speed); play_state=0; pthread_cancel(playth); thread_join(playth); if (loaded && !ttyrec_next_frame(tr, fr)) tc=fr->t; // no stopping past the end } static void adjust_pos(int diff) { int old_state=play_state; replay_stop(); tc.tv_sec+=diff; if (tc.tv_sec<0) tc.tv_sec=tc.tv_usec=0; fr=ttyrec_seek(tr, &tc, &term); vtvt_attach(term, stdout, 1); if (old_state) replay_start(); } static void adjust_speed(int dir) { int old_state=play_state; replay_stop(); switch (dir) { case 0: speed=1000; break; case -1: if ((speed/=2)==0) speed=1; break; case +1: if ((speed*=2)>1000000) speed=1000000; break; } if (old_state) replay_start(); } static void replay_toggle(int dummy) { if (play_state) replay_stop(); else replay_start(); } static void replay_rewind(int dummy) { replay_stop(); tc.tv_sec=tc.tv_usec=0; } static void adv_frame(int dummy) { ttyrec_frame nf; replay_stop(); if (!(nf=ttyrec_next_frame(tr, fr))) return; tc=nf->t; tty_write(term, nf->data, nf->len); fr=nf; } static struct bind { const char *keycode; void(*func)(int); int arg; } binds[]= { {"q",0/*quit*/,0}, // q/Q -> quit {"Q",0/*quit*/,0}, {" ",replay_toggle,0}, // space -> play/pause {"\e[D",adjust_pos,-10},// left arrow -> -10sec {"\eOD",adjust_pos,-10}, {"\eOt",adjust_pos,-10}, {"\e[C",adjust_pos,+10},// right arrow -> +10sec {"\eOC",adjust_pos,+10}, {"\eOv",adjust_pos,+10}, {"\e[B",adjust_pos,-60},// down arrow -> -1min {"\eOB",adjust_pos,-60}, {"\eOr",adjust_pos,-60}, {"\e[A",adjust_pos,+60},// up arrow -> +1min {"\eOA",adjust_pos,+60}, {"\eOx",adjust_pos,+60}, {"\e[6~",adjust_pos,-600}, // PgDn -> -10min {"\eOs", adjust_pos,-600}, {"\e[5~",adjust_pos,+600}, // PgUp -> +10min {"\eOy", adjust_pos,+600}, {"r",replay_rewind,0}, // r/R -> rewind {"R",replay_rewind,0}, {"1",adjust_speed,0}, // 1 -> speed 1.0 {"s",adjust_speed,-1}, // s/S/- -> slow down {"S",adjust_speed,-1}, {"-",adjust_speed,-1}, {"f",adjust_speed,+1}, // f/F/+ -> speed up {"F",adjust_speed,+1}, {"+",adjust_speed,+1}, {"\n",adv_frame,+1}, // Enter -> next frame {"\r",adv_frame,+1}, {"\eOM",adv_frame,+1}, {0,0,0}, }; static char keycode[10]; #define GETKEY \ if ((ch=getchar())==EOF)\ goto end; \ *kptr++=ch; \ switch (ch) void replay(void) { char *kptr; int ch; struct bind *bp; play_state=0; tc.tv_sec=tc.tv_usec=0; fr=ttyrec_seek(tr, 0, &term); vtvt_attach(term, stdout, 1); replay_start(); while (1) { kptr=keycode; GETKEY { case 27: GETKEY { case 'O': GETKEY{} // ESC O A break; case '[': GETKEY { case 'O': GETKEY{} // ESC [ O A break; case '[': GETKEY{} // ESC [ [ A break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': while (ch>='0' && ch<='9' && kptr-keycode<6) { GETKEY{} // ESC [ 11 ~ } break; // ESC [ A } break; } break; } *kptr=0; for (bp=binds; bp->keycode; bp++) if (!strcmp(bp->keycode, keycode)) { if (bp->func) bp->func(bp->arg); else goto end; } } end: replay_stop(); tty_printf(term, "\e[f\e[200B"); tty_free(term); } ��������������������������termrec-0.19/play/player.h��������������������������������������������������������������������������0000664�0000000�0000000�00000000222�13646775175�0015537�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������extern ttyrec tr; extern int speed; extern tty term; extern int waiting, loaded; extern mutex_t waitm; extern cond_t waitc; void replay(void); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/play/termplay.c������������������������������������������������������������������������0000664�0000000�0000000�00000011502�13646775175�0016076�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define _GNU_SOURCE #include "config.h" #include <tty.h> #include <ttyrec.h> #include <stdio.h> #include <getopt.h> #include <stdlib.h> #include <locale.h> #if HAVE_TERMIOS_H # include <termios.h> # include <unistd.h> #endif #include "_stdint.h" #include "gettext.h" #include "common.h" #include "sys/threads.h" #include "sys/ttysize.h" #include "sys/utils.h" #include "play/player.h" #ifdef HAVE_GETOPT_LONG static struct option play_opts[]={ {"format", 1, 0, 'f'}, {"speed", 1, 0, 's'}, {"follow", 0, 0, 'p'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0}, }; #endif static const char *play_name, *format; static int follow; static void get_play_parms(int argc, char **argv) { char *ep; play_name=0; follow=0; speed=1000; int opt; #ifdef HAVE_GETOPT_LONG while ((opt = getopt_long(argc, argv, "f:s:ph", play_opts, 0)) != -1) #else while ((opt = getopt(argc, argv, "f:s:ph")) != -1) #endif { switch (opt) { case ':': case '?': exit(1); case 'f': get_r_format(&format); break; case 's': speed=strtof(optarg, &ep)*1000; if (*ep || ep==optarg || speed<=0 || speed>1000000) die(_("Please provide a valid number <=1000 after -s.\n")); break; case 'p': follow=1; break; case 'h': printf( "%stermplay [-f format] [file]\n" " %s" "-f, --format X %s\n" "-s, --speed X %s\n" "-p, --follow %s\n" "-h, --help %s\n" "%s%s", _("Usage: "), _("Replays a console session from a file.\n"), _("set input format to X (-f whatever for the list)"), _("set initial speed to X (default is 1.0)"), _("keep trying to read a growing file (like tail -f)"), _("show this usage message"), _("If no format is given, it will be set according to the extension of the\n" " filename.\n"), _("You don't have to uncompress .gz, .bz2 and .xz files first.\n")); exit(0); } } if (optind<argc) play_name=argv[optind++]; else die("%s termplay <%s>\n", _("Usage:"), _("filename")); if (optind<argc) die(_("You specified the file to play multiple times.\n")); if (!format) format=ttyrec_r_find_format(0, play_name, "auto"); } static void loader_end(void *arg) { mutex_lock(waitm); loaded=1; if (waiting) { waiting=0; cond_wake(waitc); } mutex_unlock(waitm); } static struct timeval lt; static void loader_init_wait(const struct timeval *ts, void *arg) { // lt=*ts; } static void loader_wait(const struct timeval *delay, void *arg) { tadd(lt, *delay); } static void loader_print(const char *data, int len, void *arg) { ttyrec_add_frame(tr, <, data, len); lt.tv_sec=lt.tv_usec=0; mutex_lock(waitm); if (waiting) { waiting=0; cond_wake(waitc); } mutex_unlock(waitm); } static int loader(void *arg) { pthread_cleanup_push(loader_end, 0); ttyrec_r_play((intptr_t)arg, format, play_name, loader_init_wait, loader_wait, loader_print, 0); pthread_cleanup_pop(1); return 1; } static struct termios old_tattr; static void kbd_raw(void) { struct termios tattr; if (!isatty(0)) return; tcgetattr(0,&old_tattr); tattr=old_tattr; // cfmakeraw(&tattr); tattr.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); tattr.c_oflag &= ~OPOST; tattr.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); tattr.c_cflag &= ~(CSIZE|PARENB); tattr.c_cflag |= CS8; #ifndef IGNORE_INT tattr.c_lflag|=ISIG; // allow C-c, C-\ and C-z #endif tattr.c_cc[VMIN]=1; tattr.c_cc[VTIME]=0; tcsetattr(0,TCSANOW,&tattr); } static void kbd_restore(void) { tcdrain(0); tcsetattr(0,TCSADRAIN,&old_tattr); } int main(int argc, char **argv) { int fd; thread_t loadth; const char *error; int sx, sy; setlocale(LC_CTYPE, ""); get_play_parms(argc, argv); if ((fd=open_stream(-1, play_name, follow?SM_REPREAD:SM_READ, &error))==-1) die("%s: %s\n", play_name, error); sx=80; sy=25; get_tty_size(1, &sx, &sy); tr=ttyrec_init(tty_init(sx, sy, 1)); mutex_init(waitm); cond_init(waitc); waiting=0; loaded=0; kbd_raw(); if (thread_create_joinable(&loadth, loader, (intptr_t)fd)) die("Cannot create thread"); replay(); pthread_cancel(loadth); thread_join(loadth); ttyrec_free(tr); kbd_restore(); // Need to kill termcast/etc threads. _exit(0); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/rec/�����������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0013702�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/rec/Makefile.am������������������������������������������������������������������������0000664�0000000�0000000�00000000362�13646775175�0015737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������bin_PROGRAMS += termrec termrec_SOURCES = rec/termrec.c rec/pty.c rec/pty.h termrec_LDADD = libutils.la libcommon.la libtty.la if WIN32 termrec_LDADD += win32/icons/termrec.coff termrec_LDFLAGS = -Xlinker --subsystem -Xlinker windows endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/rec/pty.c������������������������������������������������������������������������������0000664�0000000�0000000�00000011442�13646775175�0014664�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define _GNU_SOURCE #include "pty.h" #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STRING_H # include <string.h> #else # ifdef HAVE_STRINGS_H # include <strings.h> # endif #endif #include <stdlib.h> #include <signal.h> #include <stdio.h> #include <sys/ioctl.h> #ifdef HAVE_PTY_H # include <pty.h> #endif #if defined(HAVE_FORKPTY) && defined(HAVE_LIBUTIL_H) # include <libutil.h> #endif extern char **environ; #ifndef HAVE_FORKPTY # if !(defined(HAVE__GETPTY) || defined(HAVE_GRANTPT) \ && (defined(HAVE_GETPT) || defined(HAVE_DEV_PTMX) \ || defined(HAVE_POSIX_OPENPT))) // if no PTYRANGE[01] is in the config file, we pick a default # ifndef PTYRANGE0 # define PTYRANGE0 "qpr" # endif # ifndef PTYRANGE1 # define PTYRANGE1 "0123456789abcdef" # endif # ifdef M_UNIX static char PtyProto[] = "/dev/ptypXY"; static char TtyProto[] = "/dev/ttypXY"; # else static char PtyProto[] = "/dev/ptyXY"; static char TtyProto[] = "/dev/ttyXY"; # endif # endif int forkpty(int *amaster,char *dummy,struct termios *termp, struct winsize *wp) { int master,slave; int pid; #ifdef HAVE__GETPTY int filedes[2]; char *line; line = _getpty(&filedes[0], O_RDWR|O_NDELAY, 0600, 0); if (0 == line) return -1; if (0 > (filedes[1] = open(line, O_RDWR))) { close(filedes[0]); return -1; } master=filedes[0]; slave=filedes[1]; #elif defined(HAVE_GRANTPT) && (defined(HAVE_GETPT) || defined(HAVE_DEV_PTMX) || defined(HAVE_POSIX_OPENPT)) # ifdef HAVE_PTSNAME char *name; # else char name[80]; # endif # ifdef HAVE_GETPT master=getpt(); # elif HAVE_POSIX_OPENPT master=posix_openpt(O_RDWR); # else master=open("/dev/ptmx", O_RDWR); # endif if (master<0) return -1; if (grantpt(master)<0||unlockpt(master)<0) goto close_master; # ifdef HAVE_PTSNAME if (!(name=ptsname(master))) goto close_master; # else if (ptsname_r(master,name,80)) goto close_master; # endif slave=open(name,O_RDWR); if (slave==-1) goto close_master; # ifdef HAVE_STROPTS_H if (isastream(slave)) if (ioctl(slave, I_PUSH, "ptem")<0 ||ioctl(slave, I_PUSH, "ldterm")<0) goto close_slave; # endif goto ok; //close_slave: close (slave); close_master: close (master); return -1; ok: #else char *p, *q, *l, *d; char PtyName[32], TtyName[32]; strcpy(PtyName, PtyProto); strcpy(TtyName, TtyProto); for (p = PtyName; *p != 'X'; p++) ; for (q = TtyName; *q != 'X'; q++) ; for (l = PTYRANGE0; (*p = *l) != '\0'; l++) { for (d = PTYRANGE1; (p[1] = *d) != '\0'; d++) { // tintin_printf(0,"OpenPTY tries '%s'", PtyName); if ((master = open(PtyName, O_RDWR | O_NOCTTY)) == -1) continue; q[0] = *l; q[1] = *d; if (access(TtyName, R_OK | W_OK)) { close(master); continue; } if ((slave=open(TtyName, O_RDWR|O_NOCTTY))==-1) { close(master); continue; } goto ok; } } return -1; ok: #endif if (termp) tcsetattr(master, TCSANOW, termp); if (wp) ioctl(master,TIOCSWINSZ,wp); // let's ignore errors on this ioctl silently pid=fork(); switch (pid) { case -1: close(master); close(slave); return -1; case 0: close(master); setsid(); dup2(slave,0); dup2(slave,1); dup2(slave,2); close(slave); return 0; default: close(slave); *amaster=master; return pid; } } #endif void pty_makeraw(struct termios *ta) { memset(ta, 0, sizeof(*ta)); ta->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); ta->c_oflag &= ~OPOST; ta->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); ta->c_cflag &= ~(CSIZE|PARENB); ta->c_cflag |= CS8; ta->c_cc[VMIN]=1; ta->c_cc[VTIME]=0; } int run(const char *command, int sx, int sy) { int fd; struct winsize ws; ws.ws_row=sy; ws.ws_col=sx; ws.ws_xpixel=0; ws.ws_ypixel=0; switch (forkpty(&fd,0,0,(sx&&sy)?&ws:0)) { case -1: return -1; case 0: { const char *argv[4]; char *cmd; if (asprintf(&cmd, "exec %s", command) == -1) abort(); argv[0]="sh"; argv[1]="-c"; argv[2]=cmd; argv[3]=0; execve("/bin/sh",(char*const*)argv,environ); fprintf(stderr,"#ERROR: Couldn't exec `%s'\n",command); exit(127); } default: return fd; } return -1; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/rec/pty.h������������������������������������������������������������������������������0000664�0000000�0000000�00000000724�13646775175�0014672�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #ifdef HAVE_CONFIG_H # include "config.h" #endif #if HAVE_TERMIOS_H # include <termios.h> #endif #ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> #endif #ifdef HAVE_GRANTPT # ifdef HAVE_STROPTS_H # include <stropts.h> # endif #endif #ifndef HAVE_FORKPTY extern int forkpty(int *amaster,char *dummy,struct termios *termp, struct winsize *wp); #endif extern int run(const char *command, int sx, int sy); extern void pty_makeraw(struct termios *ta); ��������������������������������������������termrec-0.19/rec/termrec.c��������������������������������������������������������������������������0000664�0000000�0000000�00000010375�13646775175�0015515�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <unistd.h> #ifdef HAVE_SYS_SELECT_H # include <sys/select.h> #endif #ifdef HAVE_STRING_H # include <string.h> #else # ifdef HAVE_STRINGS_H # include <strings.h> # endif #endif #include <sys/time.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> #include <signal.h> #include <locale.h> #include <langinfo.h> #include "pty.h" #include "compat.h" #include "utils.h" #include "ttyrec.h" #include "common.h" #include "rec_args.h" static volatile int need_resize; static int need_utf; static struct termios ta; static int ptym; static int sx, sy; static int record_f; static recorder rec; static void sigwinch(int s) { need_resize=1; } static void sigpass(int s) { kill(ptym, s); } static void tty_restore(void); static void sigpipe(int s) { tty_restore(); fprintf(stderr, "Broken pipe. Disk full?\n"); exit(0); } static void setsignals(void) { struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags=SA_RESTART; act.sa_handler=sigwinch; if (sigaction(SIGWINCH,&act,0)) die("sigaction SIGWINCH"); act.sa_handler=sigpass; if (sigaction(SIGINT,&act,0)) die("sigaction SIGINT"); if (sigaction(SIGHUP,&act,0)) die("sigaction SIGHUP"); if (sigaction(SIGQUIT,&act,0)) die("sigaction SIGQUIT"); if (sigaction(SIGTERM,&act,0)) die("sigaction SIGTERM"); if (sigaction(SIGTSTP,&act,0)) die("sigaction SIGTSTP"); act.sa_handler=sigpipe; if (sigaction(SIGPIPE,&act,0)) die("sigaction SIGPIPE"); } static void tty_get_size(void) { struct winsize ts; if (ioctl(1,TIOCGWINSZ,&ts)) return; if (!ts.ws_row || !ts.ws_col) return; if (ptym!=-1) ioctl(ptym,TIOCSWINSZ,&ts); sx=ts.ws_col; sy=ts.ws_row; } static void record_size(void) { struct timeval tv; char buf[20], *bp; if (raw) return; bp = buf; if (need_utf) bp+=sprintf(bp, "\e%%G"), need_utf=0; if (sx && sy) bp+=sprintf(bp, "\e[8;%d;%dt", sy, sx); if (buf==bp) return; gettimeofday(&tv, 0); ttyrec_w_write(rec, &tv, buf, bp-buf); } static void tty_raw(void) { struct termios rta; memset(&ta, 0, sizeof(ta)); tcgetattr(0, &ta); rta=ta; pty_makeraw(&rta); tcsetattr(0, TCSADRAIN, &rta); } static void tty_restore(void) { tcsetattr(0, TCSADRAIN, &ta); } #define BS 65536 int main(int argc, char **argv) { fd_set rfds; char buf[BS]; int r; struct timeval tv; setlocale(LC_CTYPE, ""); get_rec_parms(argc, argv); record_f=open_out(&record_name, format_ext, append); if (record_f==-1) { fprintf(stderr, "Can't open %s\n", record_name); return 1; } if (!command) command=getenv("SHELL"); if (!command) command="/bin/sh"; ptym=-1; sx=sy=0; tty_get_size(); if ((ptym=run(command, sx, sy))==-1) { fprintf(stderr, "Couldn't allocate pty.\n"); return 1; } gettimeofday(&tv, 0); rec=ttyrec_w_open(record_f, format, record_name, &tv); need_utf=!strcmp(nl_langinfo(CODESET), "UTF-8"); record_size(); setsignals(); tty_raw(); while (1) { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(ptym, &rfds); r=select(ptym+1, &rfds, 0, 0, 0); if (need_resize) { need_resize=0; tty_get_size(); record_size(); } switch (r) { case 0: continue; case -1: if (errno==EINTR) continue; tty_restore(); die("select()"); } if (FD_ISSET(0, &rfds)) { r=read(0, buf, BS); if (r<=0) break; if (write(ptym, buf, r) != r) break; } if (FD_ISSET(ptym, &rfds)) { r=read(ptym, buf, BS); if (r<=0) break; gettimeofday(&tv, 0); ttyrec_w_write(rec, &tv, buf, r); if (write(1, buf, r) != r) break; } } close(ptym); int err=!ttyrec_w_close(rec); tty_restore(); wait(0); return err; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/�����������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0013747�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/Makefile.am������������������������������������������������������������������������0000664�0000000�0000000�00000001224�13646775175�0016002�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������noinst_LTLIBRARIES = libcompat.la libutils.la libttyutils.la libcompat_la_SOURCES = sys/asprintf.c sys/threads.h sys/compat.h libutils_la_SOURCES = sys/utils.h sys/error.h sys/debuglog.c libttyutils_la_SOURCES = sys/ttysize.h libutils_la_LIBADD = libcompat.la if WIN32 libcompat_la_SOURCES += sys/win32/threads.h sys/win32/compat.c libutils_la_SOURCES += sys/win32/winutils.c sys/win32/winutils.h libttyutils_la_SOURCES += sys/win32/conssize.c else libcompat_la_SOURCES += sys/unix/threads.h libutils_la_SOURCES += sys/unix/utils.c libttyutils_la_SOURCES += sys/unix/ttysize.c endif if WIN32NET libcompat_la_SOURCES += sys/win32/net.c sys/win32/net.h endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/asprintf.c�������������������������������������������������������������������������0000664�0000000�0000000�00000003401�13646775175�0015737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #ifndef HAVE_ASPRINTF int asprintf(char **sptr, const char *fmt, ...) { // Guess we need no more than 100 bytes. int n, size = 64; char *p; va_list ap; if ((p = malloc (size)) == NULL) { *sptr=0; return -1; } while (1) { // Try to print in the allocated space. va_start(ap, fmt); n = vsnprintf (p, size, fmt, ap); va_end(ap); // If that worked, return the string. if (n > -1 && n < size) { *sptr=p; return n; } // Else try again with more space. if (n > -1) // glibc 2.1 size = n+1; // precisely what is needed else // glibc 2.0 size *= 2; // twice the old size if ((p = realloc (p, size)) == NULL) { *sptr=0; return -1; } } } int vasprintf(char **sptr, const char *fmt, va_list ap) { // Guess we need no more than 100 bytes. int n, size = 64; char *p; if ((p = malloc (size)) == NULL) { *sptr=0; return -1; } while (1) { // Try to print in the allocated space. n = vsnprintf (p, size, fmt, ap); // If that worked, return the string. if (n > -1 && n < size) { *sptr=p; return n; } // Else try again with more space. if (n > -1) // glibc 2.1 size = n+1; // precisely what is needed else // glibc 2.0 size *= 2; // twice the old size if ((p = realloc (p, size)) == NULL) { *sptr=0; return -1; } } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/compat.h���������������������������������������������������������������������������0000664�0000000�0000000�00000001212�13646775175�0015377�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _COMPAT_H #define _COMPAT_H #include "config.h" #ifdef WIN32 # include "win32/net.h" #else # define closesocket(x) close(x) #endif #ifndef HAVE_ASPRINTF int asprintf(char **sptr, const char *fmt, ...); int vasprintf(char **sptr, const char *fmt, va_list ap); #endif #ifndef HAVE_GETTIMEOFDAY void gettimeofday(struct timeval *tv, void * dummy); #endif #ifndef HAVE_USLEEP void usleep(unsigned int usec); #endif #ifndef HAVE_PIPE int pipe(int pipefd[2]); #endif #ifndef HAVE_SELECT // for now, select() _only_ as microsecond sleep() # define select(d1,d2,d3,d4,timeout) uselect(timeout) int uselect(struct timeval *timeout); #endif #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/debuglog.c�������������������������������������������������������������������������0000664�0000000�0000000�00000000575�13646775175�0015712�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <stdio.h> #include <stdarg.h> #include "utils.h" #ifdef IS_WIN32 # define DEBUGLOG "log.txt" #else # define DEBUGLOG "log" #endif static int once=0; void debuglog(const char *txt, ...) { va_list ap; FILE *f; f=fopen(DEBUGLOG, once?"a":"w"); once=1; va_start(ap, txt); vfprintf(f, txt, ap); va_end(ap); fclose(f); } �����������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/error.h����������������������������������������������������������������������������0000664�0000000�0000000�00000000147�13646775175�0015253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������void die(const char *txt, ...) __attribute__((format (printf, 1, 2))) __attribute__((nonnull(1))); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/threads.h��������������������������������������������������������������������������0000664�0000000�0000000�00000000146�13646775175�0015553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #ifdef WIN32 # include "win32/threads.h" #else # include "unix/threads.h" #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/ttysize.h��������������������������������������������������������������������������0000664�0000000�0000000�00000000054�13646775175�0015632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������int get_tty_size(int fd, int *sx, int *sy); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/unix/������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014732�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/unix/threads.h���������������������������������������������������������������������0000664�0000000�0000000�00000002213�13646775175�0016533�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" # include <pthread.h> # include <unistd.h> # include <stdlib.h> #define mutex_t pthread_mutex_t #define mutex_lock(x) pthread_mutex_lock(&x) #define mutex_unlock(x) pthread_mutex_unlock(&x) #define mutex_init(x) pthread_mutex_init(&x, 0); #define mutex_destroy(x) pthread_mutex_destroy(&x); #define thread_t pthread_t #define thread_create_joinable(th,start,arg) \ (unix_pthread_create(th, PTHREAD_CREATE_JOINABLE, (start), (void*)(arg))) #define thread_join(th) pthread_join(th, 0) #define thread_create_detached(th,start,arg) \ (unix_pthread_create(th, PTHREAD_CREATE_DETACHED, (start), (void*)(arg))) static inline int unix_pthread_create(pthread_t *th, int det, void *start, void *arg) { pthread_attr_t attr; int ret; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, det); ret=pthread_create(th, &attr, start, arg); pthread_attr_destroy(&attr); return ret; } #define cond_t pthread_cond_t #define cond_init(x) pthread_cond_init(&x, 0) #define cond_destroy(x) pthread_cond_destroy(&x) #define cond_wait(x,m) pthread_cond_wait(&x, &m) #define cond_wake(x) pthread_cond_signal(&x) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/unix/ttysize.c���������������������������������������������������������������������0000664�0000000�0000000�00000000676�13646775175�0016622�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <unistd.h> #if HAVE_TERMIOS_H # include <termios.h> #endif #ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> #endif #include "export.h" #include "ttysize.h" int get_tty_size(int fd, int *x, int *y) { struct winsize ts; if (!isatty(fd)) return 0; if (!ioctl(fd,TIOCGWINSZ,&ts) && ts.ws_row>0 && ts.ws_col>0) { *x=ts.ws_col; *y=ts.ws_row; return 1; } return 0; } ������������������������������������������������������������������termrec-0.19/sys/unix/utils.c�����������������������������������������������������������������������0000664�0000000�0000000�00000000743�13646775175�0016242�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <errno.h> #include "error.h" void die(const char *txt, ...) { va_list ap; char *nl; int err=errno; va_start(ap, txt); vfprintf(stderr, txt, ap); va_end(ap); nl=strrchr(txt, '\n'); if (!nl || nl[1]) { if (err) fprintf(stderr, ": %s\n", strerror(err)); else fprintf(stderr, ": unknown error\n"); } exit(1); } �����������������������������termrec-0.19/sys/utils.h����������������������������������������������������������������������������0000664�0000000�0000000�00000000320�13646775175�0015253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include "sys/error.h" #ifdef WIN32 # include "sys/win32/winutils.h" #endif #ifndef ARRAYSIZE # define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #endif void debuglog(const char *txt, ...); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/win32/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014711�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/win32/compat.c���������������������������������������������������������������������0000664�0000000�0000000�00000001547�13646775175�0016347�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include "compat.h" #include <windows.h> #include <io.h> #include <sys/time.h> #ifndef HAVE_GETTIMEOFDAY void gettimeofday(struct timeval *tv, void * dummy) { ULARGE_INTEGER t; GetSystemTimeAsFileTime((LPFILETIME)(void*)&t); t.QuadPart/=10; tv->tv_sec=t.QuadPart/1000000; tv->tv_usec=t.QuadPart%1000000; } #endif #ifndef HAVE_USLEEP void usleep(unsigned int usec) { if (usec<0) return; Sleep(usec/1000); } #endif #ifndef HAVE_PIPE int pipe(int p[2]) { if (!CreatePipe((PHANDLE)p, (PHANDLE)p+1, 0, 0)) return -1; p[0]=_open_osfhandle(p[0],0); p[1]=_open_osfhandle(p[1],0); return 0; } #endif #ifndef HAVE_USELECT int uselect(struct timeval *timeout) { if (!timeout || timeout->tv_sec<0) return 0; Sleep(timeout->tv_sec*1000+timeout->tv_usec/1000); return 0; } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/win32/conssize.c�������������������������������������������������������������������0000664�0000000�0000000�00000000640�13646775175�0016712�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <windows.h> #include <io.h> #include "export.h" #include "ttysize.h" int get_tty_size(int fd, int *x, int *y) { CONSOLE_SCREEN_BUFFER_INFO bi; HANDLE h; if (!(h=(HANDLE)_get_osfhandle(fd))) return 0; if (!GetConsoleScreenBufferInfo(h, &bi)) return 0; *x=bi.srWindow.Right-bi.srWindow.Left; *y=bi.srWindow.Bottom-bi.srWindow.Top; return 1; } ������������������������������������������������������������������������������������������������termrec-0.19/sys/win32/net.c������������������������������������������������������������������������0000664�0000000�0000000�00000005157�13646775175�0015653�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "net.h" #ifndef HAVE_WIN32_GETADDRINFO static void* LoadFunc(char *dll, char *name) { HMODULE hdll; hdll=LoadLibrary(dll); if (!hdll) return 0; return GetProcAddress(hdll, name); } typedef int (WINAPI *PGETADDRINFO) ( IN const char *nodename, IN const char *servname, IN const struct addrinfo *hints, OUT struct addrinfo **res); static PGETADDRINFO pgetaddrinfo; static int initialized=0; static void sockets_init() { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); if (!(pgetaddrinfo=LoadFunc("ws2_32", "getaddrinfo"))) // WinXP+ pgetaddrinfo=LoadFunc("wship6", "getaddrinfo"); // Win2K } // Try the real stuff first; if not available, emulate it with BSD IPv4 int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct hostent *hp; struct sockaddr_in *sin; if (!initialized) sockets_init(); if (pgetaddrinfo) return (*pgetaddrinfo)(node, service, hints, res); if (!(hp=gethostbyname(node))) { switch (h_errno) { case HOST_NOT_FOUND: return EAI_NONAME; case NO_DATA: return EAI_NODATA; case NO_RECOVERY: return EAI_FAIL; case TRY_AGAIN: return EAI_AGAIN; } return -1; // ? } *res=malloc(sizeof(struct addrinfo)); memset(*res, 0, sizeof(struct addrinfo)); (*res)->ai_family=AF_INET; (*res)->ai_socktype=SOCK_STREAM; (*res)->ai_protocol=IPPROTO_TCP; (*res)->ai_addrlen=sizeof(struct sockaddr_in); sin=malloc(sizeof(struct sockaddr_in)); (*res)->ai_addr=(struct sockaddr *)sin; sin->sin_family=AF_INET; memcpy((char *)&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr)); sin->sin_port=htons(atoi(service)); return 0; } void freeaddrinfo(struct addrinfo *res) { // not used, we need the info till the end } #endif #ifndef HAVE_WIN32_GAI_STRERROR const char *gai_strerror(int err) { DWORD dwMsgLen; static char buff[1024 + 1]; dwMsgLen = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS |FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)buff, 1024, NULL); return buff; } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/win32/net.h������������������������������������������������������������������������0000664�0000000�0000000�00000000703�13646775175�0015650�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <winsock2.h> #include <windows.h> #include <ws2tcpip.h> #include "config.h" #define SHUT_RD SD_RECEIVE #define SHUT_WR SD_SEND #ifndef HAVE_WIN32_GETADDRINFO int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); void freeaddrinfo(struct addrinfo *res); #endif #ifndef HAVE_WIN32_GAI_STRERROR const char *gai_strerror(int errcode); #endif �������������������������������������������������������������termrec-0.19/sys/win32/threads.h��������������������������������������������������������������������0000664�0000000�0000000�00000002375�13646775175�0016523�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <windows.h> #include <errno.h> #define mutex_t CRITICAL_SECTION #define mutex_lock(x) EnterCriticalSection(&x) #define mutex_unlock(x) LeaveCriticalSection(&x) #define mutex_init(x) InitializeCriticalSection(&x); #define mutex_destroy(x) DeleteCriticalSection(&x); #define thread_t HANDLE #define thread_create_joinable(th,start,arg) \ (!(*th=CreateThread(0, 4096, (LPTHREAD_START_ROUTINE)(start), (void*)(arg), 0, (LPDWORD)th))) #define thread_join(th) \ { \ WaitForSingleObject(th, INFINITE); \ CloseHandle(th); \ } #define thread_create_detached(th,start,arg) \ (win32_thread_create_detached(th, (LPTHREAD_START_ROUTINE)(start), (void*)(arg))) static inline int win32_thread_create_detached(thread_t *th, LPTHREAD_START_ROUTINE start, void *arg) { DWORD dummy; if (!(*th=CreateThread(0, 0/*4096*/, start, arg, 0, &dummy))) return EAGAIN; CloseHandle(*th); return !*th; } #define cond_t HANDLE #define cond_init(x) {(x)=CreateEvent(0, 0, 0, 0);} #define cond_destroy(x) CloseHandle(x); #define cond_wait(x,m) {mutex_unlock(m);WaitForSingleObject(x, 500);mutex_lock(m);} #define cond_wake(x) PulseEvent(x) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/win32/winutils.c�������������������������������������������������������������������0000664�0000000�0000000�00000003115�13646775175�0016733�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <windows.h> #include <stdio.h> #include "error.h" #include "winutils.h" #define BUFFER_SIZE 1024 void die(const char *txt, ...) { va_list ap; char buf[BUFFER_SIZE]; const char *errstr; int len; DWORD err=GetLastError(); va_start(ap, txt); len=vsnprintf(buf, BUFFER_SIZE, txt, ap); va_end(ap); if (len && buf[len-1]!='\n') { FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPTSTR) &errstr, 0, NULL); if (!err) errstr="unknown error"; snprintf(buf+len, BUFFER_SIZE-len, ": %s\n", errstr); } MessageBox(0, buf, "TermRec", MB_ICONERROR); exit(1); } // Returns -1 for WM_QUIT or the index into the Objects array. int message_loop(HANDLE* lphObjects, int cObjects) { while (TRUE) { DWORD result; MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) return -1; DispatchMessage(&msg); } // Wait for any message sent or posted to this queue // or for one of the passed handles be set to signaled. result = MsgWaitForMultipleObjects(cObjects, lphObjects, FALSE, INFINITE, QS_ALLINPUT); if (result == (WAIT_OBJECT_0 + cObjects)) { // New messages have arrived. continue; } else { // One of the handles became signaled. return result-WAIT_OBJECT_0; } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/sys/win32/winutils.h�������������������������������������������������������������������0000664�0000000�0000000�00000000156�13646775175�0016742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <windows.h> int message_loop(HANDLE* lphObjects, int cObjects); #undef stderr #define stderr stdout ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/���������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014273�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/.gitignore�����������������������������������������������������������������������0000664�0000000�0000000�00000000154�13646775175�0016263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������atconfig atlocal package.m4 testsuite testsuite.log testsuite.dir seeks tarith loadsave rec vt vtmir vtgen ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/Makefile.am����������������������������������������������������������������������0000664�0000000�0000000�00000002736�13646775175�0016337�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������check_PROGRAMS = seeks tarith loadsave rec vt vtmir vtgen AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libtty/ LDADD = -L.. -ltty ../libutils.la vtmir_LDFLAGS = @PTHREAD_CFLAGS@ vtmir_LDADD = $(LDADD) @PTHREAD_LIBS@ vt_LDADD = $(LDADD) ../libtty/wcwidth.o EXTRA_DIST = $(TESTSUITE_AT) testsuite.at testsuite package.m4 unescape DISTCLEANFILES = atconfig $(check_SCRIPTS) MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE) package.m4 dist-hook: for x in vt.in vt.out rec.in rec.out misc.out; do mkdir -p $(distdir)/$$x; \ cp -p $(srcdir)/$$x/* $(distdir)/$$x; done ## ------------ ## ## package.m4. ## ## ------------ ## $(srcdir)/package.m4: $(top_srcdir)/configure.ac { \ echo '# Signature of the current package.'; \ echo 'm4_define([AT_PACKAGE_NAME], [@PACKAGE_NAME@])'; \ echo 'm4_define([AT_PACKAGE_TARNAME], [@PACKAGE_TARNAME@])'; \ echo 'm4_define([AT_PACKAGE_VERSION], [@PACKAGE_VERSION@])'; \ echo 'm4_define([AT_PACKAGE_STRING], [@PACKAGE_STRING@])'; \ echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \ echo 'm4_define([AT_TESTS], [$(TESTSUITE_AT)])'; \ } >$(srcdir)/package.m4 # TESTSUITE = $(srcdir)/testsuite check-local: atconfig atlocal $(TESTSUITE) $(SHELL) $(TESTSUITE) clean-local: [ ! -x $(TESTSUITE) ] || $(SHELL) $(TESTSUITE) --clean AUTOTEST = $(AUTOM4TE) --language=autotest $(TESTSUITE): package.m4 testsuite.at $(TESTSUITE_AT) $(AUTOTEST) -I $(srcdir) $@.at -o $@.tmp mv $@.tmp $@ TESTSUITE_AT = ����������������������������������termrec-0.19/tests/atlocal.in�����������������������������������������������������������������������0000664�0000000�0000000�00000000105�13646775175�0016236�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PATH=@abs_builddir@:@abs_top_builddir@/src:$top_srcdir:$srcdir:$PATH �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/loadsave.c�����������������������������������������������������������������������0000664�0000000�0000000�00000000640�13646775175�0016235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <ttyrec.h> #include "config.h" #include "sys/error.h" int main(int argc, char **argv) { ttyrec tr; if (argc!=3) die("Usage: loadsave f1 f2\n"); if (!(tr=ttyrec_load(-1, 0, argv[1], 0))) die("Can't read the ttyrec from %s\n", argv[1]); if (!ttyrec_save(tr, -1, 0, argv[2], 0, 0)) die("Can't write the ttyrec to %s\n", argv[2]); ttyrec_free(tr); return 0; } ������������������������������������������������������������������������������������������������termrec-0.19/tests/misc.out/������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0016034�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/misc.out/splitutf.cast�����������������������������������������������������������0000664�0000000�0000000�00000000227�13646775175�0020563�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":2, "width":80, "height":25} [0.000000, "o", "a"] [0.020000, "o", "а"] [0.050000, "o", "a"] [0.090000, "o", "𝚊"] [0.100000, "o", "\n"] �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.c����������������������������������������������������������������������������0000664�0000000�0000000�00000001220�13646775175�0015203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <ttyrec.h> #include <time.h> #include "config.h" #include "sys/error.h" int main(int argc, char **argv) { recorder r; struct timeval tv; if (argc!=2) die("Usage: rec outfile\n"); tv.tv_sec=20; tv.tv_usec=10; if (!(r=ttyrec_w_open(-1, 0, argv[1], &tv))) die("Can't write the ttyrec to %s\n", argv[1]); ttyrec_w_write(r, &tv, "Abc", 3); tv.tv_sec++; ttyrec_w_write(r, &tv, "D", 1); tv.tv_sec++; ttyrec_w_write(r, &tv, "Ef", 2); tv.tv_sec++; ttyrec_w_write(r, &tv, "G", 1); tv.tv_sec++; ttyrec_w_write(r, &tv, "Hij\n", 4); tv.tv_sec++; return !ttyrec_w_close(r); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.in/��������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0015451�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.in/asciicast-escapes.cast����������������������������������������������������0000664�0000000�0000000�00000000143�13646775175�0021707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version": 2, "width": 20, "height": 5, } [0.000000, "o", "\u0041\u00a1\u16a0\uffed\ud83d\udca9"] �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.in/asciicast-v1.cast���������������������������������������������������������0000664�0000000�0000000�00000000543�13646775175�0020616�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "version": 1, "width": 80, "height": 24, "duration": 1.515658, "command": "/bin/zsh", "title": "", "env": { "TERM": "xterm-256color", "SHELL": "/bin/zsh" }, "stdout": [ [ 0.248848, "\u001b[1;31mHello \u001b[32mWorld!\u001b[0m\n" ], [ 1.001376, "I am \rThis is on the next line." ] ] } �������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.in/asciicast-v2.cast���������������������������������������������������������0000664�0000000�0000000�00000000452�13646775175�0020616�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version": 2, "width": 80, "height": 24, "timestamp": 1504467315, "title": "Demo", "env": {"TERM": "xterm-256color", "SHELL": "/bin/zsh"}} [0.248848, "o", "\u001b[1;31mHello \u001b[32mWorld!\u001b[0m\n"] [1.001376, "o", "That was ok\rThis is better."] [2.143733, "o", " "] [6.541828, "o", "Bye!"] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.in/splitutf.nh���������������������������������������������������������������0000664�0000000�0000000�00000000075�13646775175�0017654�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������a��������������������������������� ���� ��� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.out/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0015652�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.out/asciicast-escapes��������������������������������������������������������0000664�0000000�0000000�00000000266�13646775175�0021165�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |A[00A1][16A0][FFED][1F4A9] | | | | | | | | | +-[ cursor at 5,0 ]--+ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.out/asciicast-v1�������������������������������������������������������������0000664�0000000�0000000�00000004214�13646775175�0020065�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+================================================================================+ |{bold fg=red}Hello {bold fg=green}World!{} | |This is on the next line. | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +-[ cursor at 25,1 ]-------------------------------------------------------------+ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.out/asciicast-v2�������������������������������������������������������������0000664�0000000�0000000�00000004214�13646775175�0020066�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+================================================================================+ |{bold fg=red}Hello {bold fg=green}World!{} | |This is better. Bye! | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +-[ cursor at 20,1 ]-------------------------------------------------------------+ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/rec.out/splitutf�����������������������������������������������������������������0000664�0000000�0000000�00000000274�13646775175�0017452�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |a[0430]{cjk}[FF41][CJK]{}[1D68A] | | | | | | | | | +-[ cursor at 0,1 ]--+ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/seeks.c��������������������������������������������������������������������������0000664�0000000�0000000�00000002424�13646775175�0015553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <string.h> #include <ttyrec.h> #include "sys/error.h" ttyrec tr; #define BUFFER_SIZE 64 static void sub(int t1, int t2, const char *exp) { char buf[BUFFER_SIZE], *bptr; ttyrec_frame fr; struct timeval tv; printf("Exp: [%s]\n", exp); tv.tv_sec=t1; tv.tv_usec=0; fr=ttyrec_seek(tr, (t1!=-1)?&tv:0, 0); bptr=buf; while (fr && (t2==-1 || fr->t.tv_sec<=t2)) { if (bptr+10>buf+BUFFER_SIZE) die("Buffer overflow!\n"); if (bptr!=buf) *bptr++=' '; bptr+=snprintf(bptr, 8, "%.*s", fr->len, fr->data); fr=ttyrec_next_frame(tr, fr); } printf("Got: [%s]\n", buf); if (strcmp(buf, exp)) die(" `-- mismatch!\n"); } int main(void) { struct timeval tv; int i; char word[2]="x"; tr=ttyrec_init(0); if (!tr) die("ttyrec_init() failed"); tv.tv_sec=1; tv.tv_usec=0; for (i=1;i<=10;i++) { word[0]=i+'A'-1; ttyrec_add_frame(tr, &tv, word, 1); } sub( 1,10, "A B C D E F G H I J"); sub(-1,10, "A B C D E F G H I J"); sub( 1,-1, "A B C D E F G H I J"); sub(-1,-1, "A B C D E F G H I J"); sub( 2, 3, "B C"); sub( 9,-1, "I J"); sub( 0, 1, "A"); ttyrec_free(tr); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/tarith.c�������������������������������������������������������������������������0000664�0000000�0000000�00000003221�13646775175�0015730�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <ttyrec.h> #include "sys/error.h" static long long ax, bx; static struct timeval a, b, c; static void conv(long long x, struct timeval *t) { t->tv_sec=x/1000000; if (x<0 && x%1000000) t->tv_sec--; t->tv_usec=x-t->tv_sec*1000000; } static void gen(void) { ax=rand()%10000000-2000000; conv(ax, &a); bx=rand()%10000000-2000000; conv(bx, &b); } static void cmp(long long cx, const char *opname) { conv(cx, &c); if (a.tv_sec!=c.tv_sec || labs(a.tv_usec-c.tv_usec)>1) // round-off error die("Mismatch in %s\n", opname); } int main(void) { int i; for (i=0;i<1000;i++) { gen(); //printf("%3d:%09u + %3d:%09u = ", a.tv_sec, a.tv_usec, b.tv_sec, b.tv_usec); tadd(a, b); //printf("%3d:%09u\n", a.tv_sec, a.tv_usec); cmp(ax+bx, "tadd"); } for (i=0;i<1000;i++) { gen(); tsub(a, b); cmp(ax-bx, "tsub"); } for (i=0;i<1000;i++) { gen(); b.tv_usec/=100; //printf("%3d:%06u * %4d = ", a.tv_sec, a.tv_usec, b.tv_usec); tmul1000(a, b.tv_usec); //printf("%3d:%06u vs %lld\n", a.tv_sec, a.tv_usec, ax*b.tv_usec/1000); cmp(ax*b.tv_usec/1000, "tmul1000"); } for (i=0;i<1000;i++) { gen(); b.tv_usec/=100; if (b.tv_usec<=0) continue; //printf("%3d:%06u / %4d = ", a.tv_sec, a.tv_usec, b.tv_usec); tdiv1000(a, b.tv_usec); //printf("%3d:%06u vs %lld\n", a.tv_sec, a.tv_usec, ax*(long long)1000/b.tv_usec); cmp(ax*(long long)1000/b.tv_usec, "tdiv1000"); } return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/testsuite.at���������������������������������������������������������������������0000664�0000000�0000000�00000006570�13646775175�0016662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������AT_INIT AT_COLOR_TESTS AT_SETUP([seeks]) AT_CHECK([seeks],,[ignore]) AT_CLEANUP AT_SETUP([timeval arithmetics]) AT_CHECK([tarith]) AT_CLEANUP AT_SETUP([recording]) AT_CHECK([rec test.ttyrec]) AT_CHECK([rec test.ttyrec.bz2]) AT_CLEANUP AT_SETUP([loading and saving ttyrecs to/from memory]) AT_CHECK([rec test.ttyrec && loadsave test.ttyrec out.ttyrec && cmp test.ttyrec out.ttyrec]) AT_CLEANUP AT_SETUP([loading and saving asciicasts to/from memory]) AT_CHECK([rec test.cast && loadsave test.cast out.cast && cmp test.cast out.cast]) AT_CLEANUP AT_SETUP([loading and saving v1 asciicasts to/from memory]) AT_CHECK([rec test.cast-v1 && loadsave test.cast-v1 out.cast-v1 && cmp test.cast-v1 out.cast-v1]) AT_CLEANUP AT_SETUP([loading and saving ttyrecs to memory (.gz)]) AT_SKIP_IF([! grep -q "^#define \\(HAVE_ZLIB_H\\|SHIPPED_LIBZ\\) 1" $abs_top_builddir/config.h]) AT_CHECK([rec test.ttyrec.gz && loadsave test.ttyrec.gz out.ttyrec.gz && cmp test.ttyrec.gz out.ttyrec.gz]) AT_CLEANUP AT_SETUP([loading and saving ttyrecs to memory (.bz2)]) AT_SKIP_IF([! grep -q "^#define \\(HAVE_BZLIB_H\\|SHIPPED_LIBBZ2\\) 1" $abs_top_builddir/config.h]) AT_CHECK([rec test.ttyrec.bz2 && loadsave test.ttyrec.bz2 out.ttyrec.bz2 && cmp test.ttyrec.bz2 out.ttyrec.bz2]) AT_CLEANUP AT_SETUP([loading and saving ttyrecs to memory (.xz)]) AT_SKIP_IF([! grep -q "^#define \\(HAVE_LZMA_H\\|SHIPPED_LIBLZMA\\) 1" $abs_top_builddir/config.h]) AT_CHECK([rec test.ttyrec.xz && loadsave test.ttyrec.xz out.ttyrec.xz && cmp test.ttyrec.xz out.ttyrec.xz]) AT_CLEANUP AT_SETUP([loading and saving ttyrecs to memory (.zst)]) AT_SKIP_IF([! grep -q "^#define WORKING_ZSTD 1" $abs_top_builddir/config.h]) AT_CHECK([rec test.ttyrec.zst && loadsave test.ttyrec.zst out.ttyrec.zst && cmp test.ttyrec.zst out.ttyrec.zst]) AT_CLEANUP AT_SETUP([split UTF-8 for asciicast]) cp "$top_srcdir/tests/misc.out/splitutf.cast" expout AT_CHECK([termcat ]"$top_srcdir/tests/rec.in/splitutf.nh"[ out.cast && cat out.cast],,[expout]) AT_CLEANUP AT_SETUP([vt100 sequences]) for x in "$top_srcdir/tests/vt.in/"* do if echo "$x"|grep -vq '/[[a-zA-Z0-9_-]]*$'; then continue; fi unescape <"$x" >stdin y="$(echo "$x"|sed 's/vt\.in/vt.out/')" cat "$y" >expout AT_CHECK([vt -d <stdin],,[expout]) done AT_CLEANUP AT_SETUP([long vt100 writes]) for a in 1 2 3 4 5;do for b in 1 2 3 4 5;do for c in 1 2 3 4 5;do for d in 1 2 3 4 5; do for e in 1 2 3 4;do echo "foo bar baz quux";done;done;done;done;done >stdin cp "$top_srcdir/tests/vt.out/longwrite" expout AT_CHECK([vt -d <stdin],,[expout]) AT_CLEANUP AT_SETUP([vt-on-vt]) for x in "$top_srcdir/tests/vt.in/"* do if echo "$x"|grep -vq '/[[a-zA-Z0-9_-]]*$'; then continue; fi [if LC_ALL=C grep -q '[^[:cntrl:] -~]' "$x"] then echo "Skipping $x" dnl # skip Unicode tests, LC_ALL=C breaks that and there is nothing not dnl # already tested by the "vt100 sequences" series of tests else echo "Checking $x" unescape <"$x" >stdin AT_CHECK([vtmir <stdin]) fi done AT_CLEANUP AT_SETUP([replayed onto vt]) for x in "$top_srcdir/tests/rec.in/"* do if echo "$x"|grep -vq '/[[a-zA-Z0-9_.-]]*$'; then continue; fi y="$(echo "$x"|sed 's/rec\.in/rec.out/;s:\.[[^.]]*$::')" cat "$y" >expout AT_CHECK([termcat "$x" -|vt -d],,[expout]) done AT_CLEANUP AT_SETUP([fuzzing vt]) AT_CHECK([vtgen|dd bs=1048576 count=1 2>/dev/null|vt],,[]) AT_CLEANUP ����������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/unescape�������������������������������������������������������������������������0000775�0000000�0000000�00000000524�13646775175�0016025�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl use warnings; use Encode qw(encode_utf8); while(<>) { chomp; s/^#.*//; s/\\b/\b/g; s/\\n/\n/g; s/\\e/\e/g; s/\\a/\a/g; s/\\t/\t/g; s/\\u([0-9a-fA-F]{4})/encode_utf8(sprintf('%c',hex($1)))/ge; s/\\U([0-9a-fA-F]{6})/encode_utf8(sprintf('%c',hex($1)))/ge; s/\\\\/\\/g; print; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.c�����������������������������������������������������������������������������0000664�0000000�0000000�00000017634�13646775175�0015103�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdarg.h> #include <wchar.h> #include <unistd.h> #include <stdlib.h> #include <stdbool.h> #include "tty.h" #include "wcwidth.h" static const char* color_names[16]= { "black", "red", "green", "brown", "blue", "magenta", "cyan", "lt.gray", "dk.gray", "lt.red", "lime", "yellow", "lt.blue", "pink", "aqua", "white", }; static int describe_color(char *b, uint32_t c) { switch (c&VT100_ATTR_COLOR_TYPE) { case 1<<24: return sprintf(b, "%s", color_names[c&0xf]); case 2<<24: return sprintf(b, "C%u", c&0xff); case 3<<24: return sprintf(b, "#%06x", c&0xffffff); default: return sprintf(b, "bad_color:%x", c&VT100_ATTR_COLOR_MASK); } } static const char* describe_attr(uint64_t attr) { static char buf[128]; char *b = buf; *buf=0; #define A(f, name) if (attr&VT100_ATTR_##f) b+=sprintf(b, " " name); A(BOLD, "bold"); A(DIM, "dim"); A(ITALIC, "italic"); A(UNDERLINE, "underline"); A(BLINK, "blink"); A(INVERSE, "inverse"); A(STRIKE, "strike"); A(CJK, "cjk"); #undef A if (attr & VT100_ATTR_COLOR_MASK) b+=sprintf(b, " fg="), b+=describe_color(b, attr); if (attr>>32 & VT100_ATTR_COLOR_MASK) b+=sprintf(b, " bg="), b+=describe_color(b, attr>>32); #define INVALID_ATTRS 0x7000000080000000 if (attr & INVALID_ATTRS) b+=sprintf(b, "bad_attr:%lx", attr & INVALID_ATTRS); return *buf? buf+1 : buf; } static void tl_char(tty vt, int x, int y, ucs ch, uint64_t attr, int width) { if (width == 1) printf("== char U+%04X attr=%s at %d,%d\n", ch, describe_attr(attr), x, y); else if (width == 2) printf("== char U+%04X attr=%s at %d,%d, CJK\n", ch, describe_attr(attr), x, y); else printf("== char U+%04X attr=%s at %d,%d, bad width %d!\n", ch, describe_attr(attr), x, y, width); } static void tl_comb(tty vt, int x, int y, ucs ch, uint64_t attr) { printf("== comb U+%04X attr=%s at %d,%d\n", ch, describe_attr(attr), x, y); } static void tl_cursor(tty vt, int x, int y) { printf("== cursor to %d,%d\n", x, y); } static void tl_clear(tty vt, int x, int y, int len) { printf("== clear from %d,%d len %d\n", x, y, len); } static void tl_scroll(tty vt, int nl) { printf("== scroll by %d lines\n", nl); } static void tl_flag(tty vt, int f, int v) { printf("== flag %d (%s) set to %d\n", f, (v==VT100_FLAG_CURSOR)?"cursor visibility": (v==VT100_FLAG_KPAD)?"keypad mode": "unknown", v); } static void tl_osc(tty vt, int cmd, const char *str) { printf("== osc %d: \"%s\"\n", cmd, str); } static void tl_resize(tty vt, int sx, int sy) { printf("== resize to %dx%d\n", sx, sy); } static void tl_bell(tty vt) { printf("== bell\n"); } static void tl_free(tty vt) { printf("== free\n"); } static void dump(tty vt) { int x,y; uint64_t attr; if (vt->title) x=vt->sx-printf("+===[%s]", vt->title); else x=vt->sx-printf("+"); while (x-->=0) putchar('='); printf("+\n"); attr=0; for (y=0; y<vt->sy; y++) { printf("|"); for (x=0; x<vt->sx; x++) { #define SCR vt->scr[x+y*vt->sx] if (SCR.attr!=attr) printf("{%s}", describe_attr(attr=SCR.attr)); if (SCR.ch>=' ' && SCR.ch<127) printf("%c", SCR.ch); else if (SCR.ch == VT100_CJK_RIGHT) printf("[CJK]"); else printf("[%04X]", SCR.ch); if (SCR.comb) { int ci=SCR.comb; char pref='<'; while (ci) { printf("%c%04X", pref, vt->combs[ci].ch); pref=' '; ci=vt->combs[ci].next; } printf(">"); } } printf("|\n"); } x=vt->sx-printf("+-[ cursor at %d,%d ]", vt->cx, vt->cy); while (x-->=0) putchar('-'); printf("+\n"); } #define SX vt->sx #define SY vt->sy #define CX vt->cx #define CY vt->cy #define FREECOMB vt->combs[0].next #define NCOMBS vt->combs[0].ch static const char* validate(tty vt) { if (SX<2 || SY<1) return "screen too small"; if (CX<0 || CX>SX || CY<0 || CY>=SY) return "cursor out of bounds"; int SS=SX*SY; if (!vt->combs) { for (int i=0;i<SS;i++) if (vt->scr[i].comb) return "combining when there should be none"; } else { uint8_t *tc=calloc(NCOMBS, 1); uint32_t j; if (!tc) return "OUT OF MEMORY"; tc[0]=1; // check used chains for (int i=0;i<SS;i++) for (j=vt->scr[i].comb; j; j=vt->combs[j].next) { if (j>=NCOMBS) return free(tc), "combining out of table"; if (tc[j]) return free(tc), "combining chain loop"; tc[j]=1; } // check free space for (j=FREECOMB; j<NCOMBS; j=vt->combs[j].next) { if (tc[j]) return free(tc), "free combining used or looped"; tc[j]=1; } if (j!=NCOMBS) return free(tc), "bad termination of free combining chain"; for (j=0; j<NCOMBS; j++) if (!tc[j]) return free(tc), "combining slot neither used nor free"; free(tc); } for (int y=0;y<SY;y++) for (int x=0;x<SX;x++) { attrchar *ac = &vt->scr[y*SX+x]; switch (mk_wcwidth(ac->ch)) { case 0: if (ac->ch) return "width 0 character as primary"; break; case 1: if (ac->ch == VT100_CJK_RIGHT) { if (!(ac->attr & VT100_ATTR_CJK)) return "right half but attr says not CJK"; if (x<=0) return "right half at left edge of screen"; if (!(ac[-1].attr & VT100_ATTR_CJK)) return "right half but prev attr not CJK"; } else if (ac->attr & VT100_ATTR_CJK) return "width 1 but attr says CJK"; break; case 2: if (!(ac->attr & VT100_ATTR_CJK)) return "width 2 but attr says not CJK"; if (x+1>=SX) return "width 2 at right edge of screen"; if (ac[1].ch != VT100_CJK_RIGHT) return "width 2 but no right half"; break; default: return "control character on screen"; } } return 0; } #define BUFFER_SIZE 65536 int main(int argc, char **argv) { tty vt; char buf[BUFFER_SIZE]; int len; bool dump_flag=false; bool abort_flag=false; vt = tty_init(20, 5, 1); while (1) switch (getopt(argc, argv, "eda")) { case -1: goto run; case ':': case '?': exit(1); case 'e': vt->l_char=tl_char; vt->l_comb=tl_comb; vt->l_cursor=tl_cursor; vt->l_clear=tl_clear; vt->l_scroll=tl_scroll; vt->l_flag=tl_flag; vt->l_osc=tl_osc; vt->l_resize=tl_resize; vt->l_bell=tl_bell; vt->l_free=tl_free; break; case 'd': dump_flag=true; break; case 'a': abort_flag=true; } run: while ((len=read(0, buf, BUFFER_SIZE))>0) { tty_write(vt, buf, len); const char *inv=validate(vt); if (inv) { printf("!!! tty invalid: %s !!!\n", inv); if (abort_flag) abort(); break; } } if (dump_flag) dump(vt); tty_free(vt); return 0; } ����������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0015331�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/1��������������������������������������������������������������������������0000664�0000000�0000000�00000000067�13646775175�0015417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������abc\n def\n ghi\n \e[4;20fblah\e[5;1fabc\n def\n ghi\n �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/badchar��������������������������������������������������������������������0000664�0000000�0000000�00000000362�13646775175�0016641�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������￾🿾𯿾𿿾񏿾񟿾񯿾񿿾򏿾򟿾򯿾򿿾󏿾󟿾󯿾󿿾􏿾\n ￿🿿𯿿𿿿񏿿񟿿񯿿񿿿򏿿򟿿򯿿򿿿󏿿󟿿󯿿󿿿􏿿\n ﷐﷑﷒﷓﷔﷕﷖﷗﷘﷙﷚﷛﷜﷝﷞﷟\n ﷠﷡﷢﷣﷤﷥﷦﷧﷨﷩﷪﷫﷬﷭﷮﷯\n ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/badscroll������������������������������������������������������������������0000664�0000000�0000000�00000000113�13646775175�0017214�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������\e[1;1fline 1 \e[2;1fline 2 \e[3;1fline 3 \e[4;1fline 4 \e[2;3r\e[4;1f\e[M �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/cjk-comb�������������������������������������������������������������������0000664�0000000�0000000�00000000012�13646775175�0016732�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������a\u0300 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/cjk1�����������������������������������������������������������������������0000664�0000000�0000000�00000000065�13646775175�0016105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������0123456789\e[10D ABC\e[5D\u4567\n @\e[19C! ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/cjk2�����������������������������������������������������������������������0000664�0000000�0000000�00000000232�13646775175�0016102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������\e[8;6;20t @.....@,,,,\e[99D\e[C\t\n ...@...\e[4D\e[0K\n ...@...\e[4D\e[1K\n ...@...\e[4D\e[@\n ...@#...\e[6D\e[2P\n ...@#...\e[6D\e[2X ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/combining������������������������������������������������������������������0000664�0000000�0000000�00000000114�13646775175�0017215�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������a\u0300\u0301\u0302 b\u0304 c\u0300\u0301\u0302\u0303\u0304 \n a\u0300\e[Db ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/csi_@����������������������������������������������������������������������0000664�0000000�0000000�00000000076�13646775175�0016274�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������abcdefghijklmnopqrst\n 01234567890123456789\n \e[2A\e[3C\e[2@ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/csi_E_F��������������������������������������������������������������������0000664�0000000�0000000�00000000027�13646775175�0016542�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������abc \e[2E def \e[F ghi ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/csi_P����������������������������������������������������������������������0000664�0000000�0000000�00000000021�13646775175�0016302�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������abcdef\e[3D\e[2P ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/osc������������������������������������������������������������������������0000664�0000000�0000000�00000000033�13646775175�0016034�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������a \e]0\a b \e]0foo\e\\ c d �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/t416_overflow��������������������������������������������������������������0000664�0000000�0000000�00000003753�13646775175�0017705�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Requires -fsanitize=bounds for actual error detection. \e[38;5;85mc \e[0;38;5;85md \e[0;0;38;5;85me \e[0;0;0;38;5;85mf \e[0;0;0;0;38;5;85mg \e[0;0;0;0;0;38;5;85mh \e[0;0;0;0;0;0;38;5;85mi \e[0;0;0;0;0;0;0;38;5;85mj \e[0;0;0;0;0;0;0;0;38;5;85mk \e[0;0;0;0;0;0;0;0;0;38;5;85ml \e[0;0;0;0;0;0;0;0;0;0;38;5;85mm \e[0;0;0;0;0;0;0;0;0;0;0;38;5;85mn \e[0;0;0;0;0;0;0;0;0;0;0;0;38;5;85mo \e[0;0;0;0;0;0;0;0;0;0;0;0;0;38;5;85mp \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;38;5mq \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;38mr \n \e[38;2;64;128;192me \e[0;38;2;64;128;192mf \e[0;0;38;2;64;128;192mg \e[0;0;0;38;2;64;128;192mh \e[0;0;0;0;38;2;64;128;192mi \e[0;0;0;0;0;38;2;64;128;192mj \e[0;0;0;0;0;0;38;2;64;128;192mk \e[0;0;0;0;0;0;0;38;2;64;128;192ml \e[0;0;0;0;0;0;0;0;38;2;64;128;192mm \e[0;0;0;0;0;0;0;0;0;38;2;64;128;192mn \e[0;0;0;0;0;0;0;0;0;0;38;2;64;128;192mo \e[0;0;0;0;0;0;0;0;0;0;0;38;2;64;128;192mp \e[0;0;0;0;0;0;0;0;0;0;0;0;38;2;64;128mq \e[0;0;0;0;0;0;0;0;0;0;0;0;0;38;2;64mr \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;38;2ms \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;38mt \n \e[48;5;85mc \e[0;48;5;85md \e[0;0;48;5;85me \e[0;0;0;48;5;85mf \e[0;0;0;0;48;5;85mg \e[0;0;0;0;0;48;5;85mh \e[0;0;0;0;0;0;48;5;85mi \e[0;0;0;0;0;0;0;48;5;85mj \e[0;0;0;0;0;0;0;0;48;5;85mk \e[0;0;0;0;0;0;0;0;0;48;5;85ml \e[0;0;0;0;0;0;0;0;0;0;48;5;85mm \e[0;0;0;0;0;0;0;0;0;0;0;48;5;85mn \e[0;0;0;0;0;0;0;0;0;0;0;0;48;5;85mo \e[0;0;0;0;0;0;0;0;0;0;0;0;0;48;5;85mp \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;48;5mq \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;48mr \n \e[48;2;64;128;192me \e[0;48;2;64;128;192mf \e[0;0;48;2;64;128;192mg \e[0;0;0;48;2;64;128;192mh \e[0;0;0;0;48;2;64;128;192mi \e[0;0;0;0;0;48;2;64;128;192mj \e[0;0;0;0;0;0;48;2;64;128;192mk \e[0;0;0;0;0;0;0;48;2;64;128;192ml \e[0;0;0;0;0;0;0;0;48;2;64;128;192mm \e[0;0;0;0;0;0;0;0;0;48;2;64;128;192mn \e[0;0;0;0;0;0;0;0;0;0;48;2;64;128;192mo \e[0;0;0;0;0;0;0;0;0;0;0;48;2;64;128;192mp \e[0;0;0;0;0;0;0;0;0;0;0;0;48;2;64;128mq \e[0;0;0;0;0;0;0;0;0;0;0;0;0;48;2;64mr \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;48;22ms \e[0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;48mt ���������������������termrec-0.19/tests/vt.in/title����������������������������������������������������������������������0000664�0000000�0000000�00000000016�13646775175�0016372�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������\e]0;meow\e\\ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/unicode��������������������������������������������������������������������0000664�0000000�0000000�00000000052�13646775175�0016677�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������\e%Gabcąęśćdefабцдефгхий☠ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.in/vt100graph�����������������������������������������������������������������0000664�0000000�0000000�00000000137�13646775175�0017151�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Only in cp437 mode -- autotest forces LC_ALL=C, breaking Unicode vtredir. \e%@\e(0opqrs\e(B. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/��������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0015532�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/1�������������������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0015612�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ | b| |abc | |def | |ghi | | | +-[ cursor at 0,4 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/badchar�������������������������������������������������������������������0000664�0000000�0000000�00000000753�13646775175�0017046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |[FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD] | |[FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD] | |[FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD] | |[FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD][FFFD] | | | +-[ cursor at 0,4 ]--+ ���������������������termrec-0.19/tests/vt.out/badscroll�����������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0017417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |line 1 | |line 2 | |line 3 | |line 4 | | | +-[ cursor at 0,3 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/cjk-comb������������������������������������������������������������������0000664�0000000�0000000�00000000267�13646775175�0017147�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |{cjk}[FF41]<0300>[CJK]{} | | | | | | | | | +-[ cursor at 2,0 ]--+ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/cjk1����������������������������������������������������������������������0000664�0000000�0000000�00000000341�13646775175�0016303�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ | {cjk}[4567][CJK]{} {cjk}[FF23][CJK]{}6789 | |{cjk}[FF20][CJK]{} | |{cjk}[FF01][CJK]{} | | | | | +-[ cursor at 2,2 ]--+ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/cjk2����������������������������������������������������������������������0000664�0000000�0000000�00000000270�13646775175�0016305�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ | ,,,, | |... | | ... | |... ... | |... ... | |... ... | +-[ cursor at 4,5 ]--+ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/combining�����������������������������������������������������������������0000664�0000000�0000000�00000000314�13646775175�0017420�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |a<0300 0301 0302>b<0304>c<0300 0301 0302 0303> | |b | | | | | | | +-[ cursor at 1,1 ]--+ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/csi_@���������������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0016467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |abc defghijklmnopqr| |01234567890123456789| | | | | | | +-[ cursor at 3,0 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/csi_E_F�������������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0016741�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |abc | |ghi | |def | | | | | +-[ cursor at 3,1 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/csi_P���������������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0016507�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |abcf | | | | | | | | | +-[ cursor at 3,0 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/longwrite�����������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0017464�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |foo bar baz quux | |foo bar baz quux | |foo bar baz quux | |foo bar baz quux | | | +-[ cursor at 0,4 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/osc�����������������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0016236�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |abcd | | | | | | | | | +-[ cursor at 4,0 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/t416_overflow�������������������������������������������������������������0000664�0000000�0000000�00000000321�13646775175�0020072�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |{fg=C85}cdefghijklmnop{}qr | |{fg=#4080c0}efghijklmnop{}qrst | |{bg=C85}cdefghijklmnop{}qr | |{bg=#4080c0}efghijklmnop{}qrst | | | +-[ cursor at 16,3 ]-+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/title���������������������������������������������������������������������0000664�0000000�0000000�00000000241�13646775175�0016573�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+===[meow]===========+ | | | | | | | | | | +-[ cursor at 0,0 ]--+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/unicode�������������������������������������������������������������������0000664�0000000�0000000�00000000354�13646775175�0017105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |abc[0105][0119][015B][0107]def[0430][0431][0446][0434][0435][0444][0433][0445][0438][0439]| |[2620] | | | | | | | +-[ cursor at 1,1 ]--+ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vt.out/vt100graph����������������������������������������������������������������0000664�0000000�0000000�00000000272�13646775175�0017352�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������+====================+ |[23BA][23BB][2500][23BC][23BD]. | | | | | | | | | +-[ cursor at 6,0 ]--+ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vtgen.c��������������������������������������������������������������������������0000664�0000000�0000000�00000002042�13646775175�0015560�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <string.h> static int rnd(int x) { if (x<=1) return 0; return rand()%x; } static char rndchar(const char *s) { return s[rnd(strlen(s))]; } #define ARRAYSZ(x) (sizeof(x)/sizeof(x[0])) static const char *misc[]= { "\n", "\r", "\b", "\x0c", "\t", "\e[?7h", "\e[?7l", "\e(0", "\e)0", "\e(B", "\e)B", "\x0e", "\x0f", }; int main(void) { while (1) { switch (rnd(4)) { case 0: printf("a"); break; case 1: printf("@"); break; case 2: printf("\xcc\x80"); break; case 3: switch (rnd(12)) { case 0: printf("\e%c", rndchar("78DEM")); break; case 1: case 2: case 3: puts(misc[rnd(ARRAYSZ(misc))]); break; default: printf("\e[%d;%d%c", rnd(5), rnd(5), rndchar("mDCFAEBrJKLM@PXfGdc")); } } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/tests/vtmir.c��������������������������������������������������������������������������0000664�0000000�0000000�00000002640�13646775175�0015602�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "config.h" #include <tty.h> #include <stdio.h> #include "sys/compat.h" #include "sys/threads.h" #include "sys/error.h" #include "_stdint.h" #include <unistd.h> static tty vt1, vt2; #define BUFFER_SIZE 128 static void copier(void *args) { int fd=(intptr_t)args; char buf[BUFFER_SIZE]; int len; while ((len=read(fd, buf, BUFFER_SIZE))>0) tty_write(vt2, buf, len); } static void dump(tty vt) { int x,y,c; for (y=0;y<vt->sy;y++) { for (x=0;x<vt->sx;x++) { c=vt->scr[y*vt->sx+x].ch; printf((c>=32 && c<127)?"%lc":"[U+%04X]", c); } printf("|\n"); } printf("===================='\n"); } #define BUF2 42 int main(void) { thread_t cop; int p[2]; FILE *f; char buf[BUF2]; int len, i; vt1=tty_init(20, 5, 0); vt2=tty_init(20, 5, 0); if (pipe(p)) die("pipe()"); if (thread_create_joinable(&cop, copier, (void*)(intptr_t)p[0])) die("thread creation"); f=fdopen(p[1], "w"); vtvt_attach(vt1, f, 0); while ((len=read(0, buf, BUF2))>0) tty_write(vt1, buf, len); fclose(f); thread_join(cop); for (i=0; i<vt1->sx*vt1->sy; i++) if (vt1->scr[i].ch!=vt2->scr[i].ch || vt1->scr[i].attr!=vt2->scr[i].attr) { printf("Mismatch! Dumps:\n"); dump(vt1); dump(vt2); return 1; } return 0; } ������������������������������������������������������������������������������������������������termrec-0.19/time/����������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014067�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/time/Makefile.am�����������������������������������������������������������������������0000664�0000000�0000000�00000000144�13646775175�0016122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������bin_PROGRAMS += termtime termtime_SOURCES = time/termtime.c termtime_LDADD = libutils.la libtty.la ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/time/termtime.c������������������������������������������������������������������������0000664�0000000�0000000�00000001323�13646775175�0016060�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <ttyrec.h> #include <errno.h> #include <string.h> #include "sys/error.h" #include "gettext.h" static struct timeval tt; static void delay(const struct timeval *tm, void *arg) { tadd(tt, *tm); } int main(int argc, char **argv) { int i; int any=0; if (argc<2) die("%s termtime <%s> ...\n", _("Usage:"), _("filename")); for (i=1;i<argc;i++) { tt.tv_sec=tt.tv_usec=0; if (ttyrec_r_play(-1, 0, argv[i], 0, delay, 0, 0)) { printf("%7ld.%06ld\t%s\n", (long)tt.tv_sec, (long)tt.tv_usec, argv[i]); any=1; } else fprintf(stderr, "%s: %s\n", argv[i], strerror(errno)); } return !any; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/���������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014073�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/Makefile.am����������������������������������������������������������������������0000664�0000000�0000000�00000000631�13646775175�0016127�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������bin_PROGRAMS += termrec termplay termplay_SOURCES = win32/term.c win32/draw.c win32/draw.h termplay_LDFLAGS = -Xlinker --subsystem -Xlinker windows termrec_SOURCES = win32/winrec.c termplay_LDADD = libutils.la libtty.la -lcomdlg32 -lcomctl32 -lgdi32 win32/icons/termplay.coff @LIBBZ2@ @LIBZ@ @LIBZSTD@ @PTHREAD_LIBS@ libttyutils.la termrec_LDADD = libcommon.la libutils.la libtty.la win32/icons/termrec.coff �������������������������������������������������������������������������������������������������������termrec-0.19/win32/draw.c���������������������������������������������������������������������������0000664�0000000�0000000�00000011236�13646775175�0015177�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <windows.h> #include <stdbool.h> #include "tty.h" #include "draw.h" static HFONT fonts[2][2]; /* underline, strikethrough */ static HBRUSH bg_brush; int chx, chy; #define ATTR_ALT_FONT (VT100_ATTR_UNDERLINE|VT100_ATTR_STRIKE) // win32 has a big endian byte order here! static int rgb_bgr(int c) { union {color p;int v;} x; x.v = c; unsigned char t=x.p.r; x.p.r=x.p.b; x.p.b=t; x.p.a=0; return x.v; } static void draw_line(HDC dc, int x, int y, wchar_t *txt, int cnt, uint64_t attr) { union {color p;int v;} fg,bg,t; if (attr&VT100_ATTR_COLOR_TYPE == VT100_COLOR_16<<24 && attr&VT100_ATTR_BOLD) attr|=8; // bold = bright if (attr&VT100_ATTR_COLOR_TYPE) fg.v=rgb_bgr(tty_color_convert(attr, VT100_COLOR_RGB)); else fg.v=attr&VT100_ATTR_BOLD? 0xFFFFFF : 0xAAAAAA; bg.v=rgb_bgr(tty_color_convert(attr>>32, VT100_COLOR_RGB)); if (attr&VT100_ATTR_DIM) { fg.p.r/=2; fg.p.g/=2; fg.p.b/=2; } if (attr&VT100_ATTR_BLINK) { bg.p.r=(((unsigned int)bg.p.r)+0x80)/2; bg.p.g=(((unsigned int)bg.p.g)+0x80)/2; bg.p.b=(((unsigned int)bg.p.b)+0x80)/2; fg.p.r=(((unsigned int)fg.p.r)+0x80)/2; fg.p.g=(((unsigned int)fg.p.g)+0x80)/2; fg.p.b=(((unsigned int)fg.p.b)+0x80)/2; } if (attr&VT100_ATTR_INVERSE) { t=fg; fg=bg; bg=t; } if (attr&ATTR_ALT_FONT) SelectObject(dc, fonts[!!(attr&VT100_ATTR_UNDERLINE)][!!(attr&VT100_ATTR_STRIKE)]); SetTextColor(dc, fg.v); SetBkColor(dc, bg.v); TextOutW(dc, x, y, txt, cnt); if (attr&ATTR_ALT_FONT) SelectObject(dc, fonts[0][0]); } void draw_vt(HDC dc, int px, int py, tty vt) { int x,y,x0; uint64_t attr; wchar_t linebuf[512*2]; // same as the max in tty.c int cnt; attrchar *ch; RECT r; HFONT oldfont; oldfont=SelectObject(dc, fonts[0][0]); ch=vt->scr; cnt=0; for (y=0;y<vt->sy;y++) { cnt=0; x0=x=0; attr=ch->attr; while (1) { if (x>=vt->sx || attr!=ch->attr || ch->ch==VT100_CJK_RIGHT) { draw_line(dc, x0*chx, y*chy, linebuf, cnt, attr); cnt=0; x0=x; if (x>=vt->sx) break; attr=ch->attr; } if (ch->ch==VT100_CJK_RIGHT) x0=x+1; else if (ch->ch>0xffff) // UTF-16 surrogates { linebuf[cnt++]=0xD800-(0x10000>>10)+(ch->ch>>10); linebuf[cnt++]=0xDC00+(ch->ch&0x3FF); } else linebuf[cnt++]=ch->ch; x++; ch++; } } x=vt->cx; y=vt->cy; if (x>=vt->sx) x=vt->sx-1; if (vt->opt_cursor) { r.left=x*chx; r.top=y*chy+chy-2; r.right=x*chx+chx; r.bottom=y*chy+chy; DrawFocusRect(dc, &r); } /* r.left=chx*vt->sx; r.top=0; r.right=px; r.bottom=chy*vt->sy; FillRect(dc, &r, bg_brush); r.left=0; r.top=r.bottom; r.bottom=py; FillRect(dc, &r, bg_brush); */ SelectObject(dc, oldfont); } void draw_init(LOGFONT *df) { HDC dc; LOGFONT lf; HFONT oldfont; SIZE sf; dc=GetDC(0); memset(&lf,0,sizeof(LOGFONT)); lf.lfHeight=df->lfHeight; strcpy(lf.lfFaceName, df->lfFaceName); lf.lfWeight=df->lfWeight; lf.lfItalic=df->lfItalic; lf.lfPitchAndFamily=FIXED_PITCH; lf.lfQuality=ANTIALIASED_QUALITY; lf.lfOutPrecision=OUT_TT_ONLY_PRECIS; fonts[0][0]=CreateFontIndirect(&lf); oldfont=SelectObject(dc, fonts[0][0]); GetTextExtentPoint(dc, "W", 1, &sf); chx=sf.cx; chy=sf.cy; SelectObject(dc, oldfont); lf.lfUnderline=1; fonts[1][0]=CreateFontIndirect(&lf); lf.lfStrikeOut=1; lf.lfUnderline=0; fonts[0][1]=CreateFontIndirect(&lf); lf.lfUnderline=1; fonts[1][1]=CreateFontIndirect(&lf); ReleaseDC(0, dc); bg_brush=GetStockObject(BLACK_BRUSH); } void draw_free(void) { DeleteObject(fonts[0][0]); DeleteObject(fonts[1][0]); DeleteObject(fonts[0][1]); DeleteObject(fonts[1][1]); DeleteObject(bg_brush); } void draw_border(HDC dc, tty vt) { int sx,sy; HPEN pen, oldpen; sx=vt->sx*chx; sy=vt->sy*chy; pen=CreatePen(PS_SOLID, 0, clWoodenDown); oldpen=SelectObject(dc, pen); MoveToEx(dc, sx, 0, 0); LineTo(dc, sx, sy); LineTo(dc, -1, sy); pen=CreatePen(PS_SOLID, 0, clWoodenMid); DeleteObject(SelectObject(dc, pen)); MoveToEx(dc, sx+1, 0, 0); LineTo(dc, sx+1, sy+1); LineTo(dc, -1, sy+1); DeleteObject(SelectObject(dc, oldpen)); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/draw.h���������������������������������������������������������������������������0000664�0000000�0000000�00000000547�13646775175�0015207�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������typedef struct { unsigned char r,g,b,a; } color; extern void draw_vt(HDC dc, int px, int py, tty vt); extern void draw_init(LOGFONT *df); extern void draw_free(void); extern void draw_border(HDC dc, tty vt); extern int chx,chy; #define clWoodenBurn 0x000F1728 #define clWoodenDown 0x004B5E6B #define clWoodenMid 0x008ba9c3 #define clWoodenUp 0x009ECCE2 ���������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0015206�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/Makefile.am����������������������������������������������������������������0000664�0000000�0000000�00000001035�13646775175�0017241�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������all-local: termplay.coff termrec.coff termplay_RES = termplay.rc termplay.ico termplay.manifest open.bmp rewind.bmp pause.bmp play.bmp wood1.bmp selstart.bmp selend.bmp export.bmp termrec_RES = termrec.rc termrec.ico EXTRA_DIST= ${termplay_RES} ${termrec_RES} CLEANFILES = termplay.coff termrec.coff termplay.coff: ${termplay_RES} builddir=`pwd` && cd $(srcdir) && \ $(WINDRES) termplay.rc "$$builddir/termplay.coff" termrec.coff: ${termrec_RES} builddir=`pwd` && cd $(srcdir) && \ $(WINDRES) termrec.rc "$$builddir/termrec.coff" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/export.bmp�����������������������������������������������������������������0000664�0000000�0000000�00000000366�13646775175�0017234�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM�������v���(������������������� �� ����������������������������������������������� 3� 3� 3� 3 333333 33 :���� :���� :���� :���� :���� :���� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/open.bmp�������������������������������������������������������������������0000664�0000000�0000000�00000000366�13646775175�0016654�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM�������v���(�����������������������������,7:�:ML�az{�g�r�z��'*������������������fffffR�3 D ʪ:�ꪪ�ꪪ�ꫩp� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/pause.bmp������������������������������������������������������������������0000664�0000000�0000000�00000000366�13646775175�0017030�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM�������v���(������������������K��K���������p������������������""@2" P p��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/play.bmp�������������������������������������������������������������������0000664�0000000�0000000�00000000366�13646775175�0016660�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM�������v���(������������������;��;���������v�w�����������������@������a`�����A����#���������ݲ=�q`ݸِ�ڛ��ۚ���ݙ����ݘ��������� ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/rewind.bmp�����������������������������������������������������������������0000664�0000000�0000000�00000000366�13646775175�0017203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM�������v���(������������������K��K���������r������������������R#�����qʢ����ʢ���zʢ��Iʢ� Hʢ�uʢʡzʦڪʢʢ�ݪʢ� ۪ʢ�� 몢ʢ���ڢʢ�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/selend.bmp�����������������������������������������������������������������0000664�0000000�0000000�00000000366�13646775175�0017165�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM�������v���(�������������������;��;���������}����m�������������""5`��������������������� ������ ������ ������ ������ ������ ������ ������ ������ ������ ���"!J ���p���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/selstart.bmp���������������������������������������������������������������0000664�0000000�0000000�00000000366�13646775175�0017554�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM�������v���(�������������������:��:���������|�����v�ý�����������C33������������ ������ ������������ ������������ ������������������ ������ ������������ ""��� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/termplay.ico���������������������������������������������������������������0000664�0000000�0000000�00000002066�13646775175�0017543�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������&��������(����(��� ���@�������������������������������fL�K^k���"�[P������������������������������������UUUUUUUUUU�����eQUUUQU�����ewwqWqWq�����ewwqWwWqw�����ewwqWwuWwwu�����ewwqWwUWuwU�����ewwuWuUWUuU�����eUUUUUUUUUU�����ffffffffff`�����������������""""""""""""""��3333333333332��2�� ����������2�� ����������2�� ����������2�� ����������2�� ����������2�� ����������2�� ����������2�� ����������2�� @�D@������2�� ���������2�� �@��������2�� ���������2�� @���������2�� ����������2��""""""""""""2��3333333333332�������������������������������������@�������������������������������������������������������������(������ ���������������������������K^k�����fL������pa���������������������������������wwr""w"wqDDBtB'DDBtD"wDDBtDGwDDBtDwqDDAAw������333333ccUcQccc333333qw3��!��� ��0!��0#�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/termplay.manifest����������������������������������������������������������0000664�0000000�0000000�00000001030�13646775175�0020565�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="termplay" type="win32" /> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/termplay.rc����������������������������������������������������������������0000664�0000000�0000000�00000000333�13646775175�0017370�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������0 ICON termplay.ico //1 24 termplay.manifest 100 BITMAP open.bmp 101 BITMAP rewind.bmp 102 BITMAP pause.bmp 103 BITMAP play.bmp 104 BITMAP selstart.bmp 105 BITMAP selend.bmp 106 BITMAP export.bmp wood1 BITMAP wood1.bmp �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/termrec.ico����������������������������������������������������������������0000664�0000000�0000000�00000002066�13646775175�0017347�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(��&��� �������N��(������ �����������������������������������K^k��g34�fg��eh��������������333;39қ<9&m<9қ<9&b39Ҕ 3339&m �� ҕ �� &m �q � ���� ����� UUUUUU ���������������������������������������������������(��� ���@������������������������������������Z]��w��K^k��fg���q�����������������������333������������UU�� ���=���"""""���;3���"""""�=�"LB";3�$"[=ہ�,"];3ӽ�,"[=ہ�,"];3ӽ�b$"h[UU;ہ�"LB"x]333�"""""UUUUUUQ�"""""�`������ۀ�v��`��������v��`����������v��`����������v��`����������v��`����������v��`����������v��`�������v��` ���������v��`���������v��` ���������v��`���������v��`����������v��ffffffffffffv��wwwwwwwwwwwwv�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/termrec.rc�����������������������������������������������������������������0000664�0000000�0000000�00000000023�13646775175�0017170�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������0 ICON termrec.ico �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/icons/wood1.bmp������������������������������������������������������������������0000664�0000000�0000000�00000024016�13646775175�0016742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM(��������(���`���`����������$�� �� ��������FQd�HWh�KWh�RZj�K[k�M\n�M^k�R]m�M_o�Pao�Obo�Vap�Qar�Sbr�Vcp�Qcr�Qbt�Wbs�Rcu�Qer�\ds�Wes�Teu�Tfu�Yev�Wex�[gu�Ygv�Wis�Zht�Wgx�\gw�_gv�Ziv�Wix�Wjx�[iy�^ix�[kw�Yjz�[lw�\ky�Zly�^kz�]ly�Xl{�`ly�\l|�dlz�\m|�bm{�\n|�]m~�^oz�Zo}�]n~�^pz�ao}�cp|�^p~�ap}�bq{�_q}�[q�^q�^p�bp�cq�iq~�bs}�`r�cs~�hr�`s�cs�cr�bt�hs�cu~�cs�_u�ht�hs�gu�eu�ht�gv�au�dt�ev�`v�dw�gu�iv�ev�iw�fw�hx�pv�ix�gw�kw�ey�ox�hy�ky�cz�jz�l{�fz�iy�ly�j{�py�l|�iz�lz�k{�n|�l}�p|�n}�m{�k}�k~�q|�o}�l}�v|�o�o~�p�l~�m�v}�t}�o�o}�m~�q~�p�s~�n�t�r�p�q�q�q�q�r�u�p�s�v�s�q�u�s�v�q�t�t�u�s�r�u�x�v�u�w�u�t�w�u�x�v�u�y�x�x�v�u�y�y�z�x�y�w�y�|�|�w�z�x�z�y�{�y�{�{�y��~�}�{�|�}��~��|���~�}��~�����������������������������d^^J""1^^OC"C;I@sdtzTJ@JI`f{uW^hhh^J,:<R9),JJ^~iteCU\e}teiyteJOtk{`}uth^etJ/"JotJ39"O^shthhte^J*3^ds`^^^stuT5)/ "<@>C*#>`uJC`~E^^^h`J5Ji~i^~TeTTue^eJ\eeC"/'OCOthh^hto\C^O^dzmi`^^``iutuiJJu`JJJ%)2/<Jh~uztuuJ\oddt]tieJe]e^^J1tJ1)/;;zthu~^JCe]JJ<C\^hiv~tuh`h`qH2%2Rt^tC"Oddd\d^`Ctq9<etCci"CC,/C\X^hhui<Jt:=gcccQGEGG]icG59J<),Ji``i@I@J3) )<\oB/OOd\OOJJ]tt}e<,)e <ihd^Why]_J9")<hu@^h~e]H5$4/$-3F^dz~t<<e<),]iee])i^Fhk`Ⱥͼů~i>GGG8,1C\^^``xt_e^C%+22:9:Jet\/")3Jhtztii^xJGTii}i< <]^ti`iuzhhsuuDz@Ykppk`Ivv~iJi~^FFI^")))519BCO^P`f>@@^huh`Ltt^^JG*GJQ~ř5))eietee\eethǫ~`^*#^huu~xv]!<9//K\zdX^;J-J``^``^u^^dtiTYtJ~e<)%9)H<qJ``ut^Ldt`uǦ#")3e^-^i@J3-9)<)Je<Cto\\C7''7std^^3;^u>OC^~o<,2,:U]q~tiuuu5):]]<:</1Cuۢ`YŢG1zzo\C971'1;CCt119CC3Je~ttd^dz^C\O<Rt~e~~~~Tti~tJ])<2 �   )B11\xJ,)<e-J^\/)/R;oddC"B7ozd^ittittdO;R)9eo^Ji^]<ei:_b0 0 ]MgD0eeeO",CJe\R91"'/9BBB/C^\Khz7'4O^J^`i~ztJ\~~~iT^T<>^`~uk~u{~`LJLL`ii>*#CotJ)C1CJC)7<>JJ;1BKC^\^C<O^^tt~uiJ35*,J3GJ<G]_Ykk|iiY>kuk`*@Y`k`GYt~h^3,"##3;^^e^J11--Jd^3 "`^67OJJ391#J@_TJi^<3<JT~ȧ`33^ukNaYE`}t %  Hq\;JJ1",<J;JJ11e~```^^d>C)<JkG>J3#htuȲyccVNQ<<<QT_iC1Ct~^\\P??>Z`#z\7CJC3,B9\\CC9Ohzt1IufY`>)/<^tuttCB//Fhhh~<,R)\e^t~uiukv{ue9/ );;A^//9<C</)$\u;#J^eo6@G>><CqtJ9/9e]tu3!R`^^``J>-&=YxuiL`ŠuT""<]qtqJod^O^KO\C)$$zo^^C^C-1^^J^uȭ~~R)//"9]2 Cto1"#?fhJJuŰ`~`<3,<9/!9C;;;'4BB\zC;J<""1"tutu^tiucJG<!,q\RC^C<C9toeo7hd;^ftettQGG!(5&<:58EkeJ<oeJt^J;;zo^OB//B,^tzt#JJ3J`hYuu~<!!)<ett^ozoC7OX7W?d^ii\<,9H<<:>5cř`ik~iJ]eiettzz^IJOJO^ete<")3<^~t^LLJ "),<~tii^33-@OdssW?h~])))Hexe~x^]<JxŽ~xii~~~iut`^;@>>@J@;CO<C\J<1! <uL^JOo^^`k{k``i 9^tut`\de\ouu3>~tJ"";J^u^@I!))]tt^*-3#&@^thnsz{{ͻǴG.:HM9_^^`^J3@``~d7KI`u^:55),5JTit``hukhGCzt^^Odtddd-;F6FIk~QJE5<><)5exqitiu`ieLJO^^\\)ikO3CѲѐ:.2%1/1C</Cout< Azd;''Oz\OO^^<1^tzoot~~teit~`^`_`cLG^<i^tt^uttJC9]CJi~~iJJ^ҰcVySGQ}}<eC<Otzt`mothOzO/;OOtҋR+/R<<znO4/4e\C\^^JJ`u~`utetzth~u^1)/BJx_c]R<5_ŏ)]1ddIdh-"3C1^^"dCezz, Ht{dC7--'O1)/C^\;;ie_~ҙiotz~~ex~<MHҹt>,),q}tztd;F6-Jh`\J!)JeiJCJJutqt`@-uut@'-R1BJ^CJ\}< <o\eUCJC^<<<i~ig,:!!Q=.:::<&5u~]<JJO;'";hhFJ3" 5<U]Jeet~~Y>*-@hkuȭkL<9<B9<Co +t] )/Ce\t~xTJcvxv⹚cȹůtitJ"J^zt#!,c< )itJi``h~~i^<J]<))<<x<!<^h~eeU<<!5<G5:::,:cvV8=(NkEYG5`xT3*JTt{t~e)_tki_S],it^L``kc~tU,9;3eiHH2%#<ei^^hh<),]tq}ŲՐѦѦ~Ji`GuiT>,!2g=xcitC&)U]UJik#3J>Jiiettieoivac:!%]<e^`^Jt`~kwȹǰtJ99ȹ~ii2)~Y~ti~~cit]eeJ3^GGiGvtJe)C"J3hthz^e^tuۙ~Źŧx~Ѳ`5))Juuuuuii~~i~tztt\~~etit~~viG85J]oz`JeJyͺiJ_^<^kh~~~ktioi~tzttt^Jt^euti<9CoeeeiikvTx~tetuik~ѹG3,"^>u^tt~~ic`J^^JJetietoet~ϒui^~iie</<Cez͹~w\t~~kt^tuJ>JTJG;ev~u^i>Gttie~xv~t}tteJ<JNjiuv~iTGJ<;<eut`^eTJ\h^J``i~~^L~kʲ֭ͦuuȠ{kvyԮǦJetdCCJ<itt~řTOt~~~hs`~ɑp–ͼѫw^JiikkYiiv}ycYuk~vvk~3/4^z~~`Couۤuŋte )te^Jt~iΪ~kצԮѹkѡy;;;Ϥu{Ⱥu~kci_tiܰѵvcǦ_(5u~~tѵȩztt`t`uYuu~ůϭu~J1"9<_vʲȺѹγûԻ&Szzhtu`hu^LӺh`YxY5J~JJiuаۢk~avܻǫeJJ~şxqU{^dXdd^z`Tt^u@1utJřii~tteo_55<<Jciiu~䫴ب˳~iYkt^uhJzzOu`h^3*hzztTJJ>3^~u`3J۰ҭ׺ǦӺȰźtǤu^h_ti<<outzd"^h~uJt~^Ji~~aůǣǻǮγ׼ή^`>>i~~^hF';^t~zuuYh~͵uڻװ߰¤{m{{ |˜׼צӵǦ°uff{f |ff¦ûλλǦݰkP`u|kk{uݵ͑pڦwîήӶ¶Ӡ|óԻλΔ{EE@>@@-fuf`YL`hL@`uPLP`{u{{kJ>kukk`tu~༻ǫǻ׫j|u~uuww¶Ӷ竼ήμݵμ׻ͼpp|sss͖Y|Ǽͼyk[kuu{{uJ@PI`kYIhzYpuhWu-^~uhu^[׮p{k[wλבuϘ|w| k|`h`k{L>J7OO4;^^O37FI@@?uh^F;@"-h`J^vYpͼ͡yyp[kķ¶{szsddhdFYLƊFukvku~hh`hOJhhhhmuu`h^hdhŵplͼÔצlNY`YYE``h^^@^`uuukYu|~k~~c`it~`YkiuhIF@uumumumIhhuuikșvk`JC[YaakYҙh^dfmh׵ѹݹװwÛ̲wklwۡ>EvvG*Ttt\C\^J{u^;;F---@II`hh`^`G>YpwͦǰLjdzOC~ϯDzT><G`k`i_>55i~tJJCCO;;^GLJ@""'';>6@^`uhuuu``Y{iYv~kup{iȵ͵Ǵδӯϒ۹y[cYc3khtI>3#""-1;J^hzsthzL`ºuk{`h`^`CJtrlY88GN8>EEYYYaakY>NkkNavYp`dO7'''""'3<31,##''"<@^uu@8Yu``Y|uLiJ@`Jul͵ǡǖףѫwǡѡkNYkSvoBK9!/$"/C1BC"'^^h131JC;Cduuuuuǵuuu`tGJ<v_:\9,<JJ^zuET~wNu~d\Xttuttttzzzhfmh`dWd^@*JJ"#>u|kaYYYYYa```Lv_~y~wyyyyykkӺnF6;@^L^`u^@^PP@Z^^O^6dhhuӰͺﺱuuukk5( 8Vaary͹vvv`J3FO^z`@3//)J6I6@hh^OOKFA5`[uu{GYNTiY><J`u`iuLkkуw׵YkkEGkvpkka{vkv~vTt^oodez~~T<3f`;\//$9Ce^ddt°™ͺaLj~{~~uukikuu`JJ31<JJ3J^5*5JJJ3<%%)';6I$$"Y||~kLu`*>3*3Lihu{Lu3^`{ku[{wkkkY|~i``uhhuuuuu~u^hfPI@O1B4K1-#(>L`LukuuJ^J^^JJJJik{kkJ`-Jskpwppu`iu^^t`@3Ihhhdukku{f`Phf`huf`mWZWFWhu`^^`ͤs^{u||ڮpp`J@`h`dhsh^dI^hmzzmh`huhfXFddF''7O@@Yu{{usIFAFsh{u``uhᢢ~zt^d`t~3CJ~^^^huzhzhsuhhmhhddsssthͰu^@h`tzh``{k`~k~kuu^>J@^uothdO^^@uutut~thhh`h^ttt`^^^zudhhu~װ{k`5#8Yܔ|Yi>Tc~G,i~`h`^;;@^J;,33t"';@^Ihut~~ut`L^huǹwV88!!&(cȹזȰ¡!5<<thm~uzhJztCh@I-sum@L^iJJ3@"#---;^dJ^^TYykVwѭǹvciuuk]J^u~`;"-;hh^^hJh^;J^ddhhh^u~tu^hhtuhumhhtkk^z^hLu`{k|u’_!TTu~utzzhO^^^;F;^hh^^^@66;^^^OI@hhhhh^I`huuuuuuѹiu{`hd;F;^@u`u`Pf^J::TiTJ''7;F-;6^^uz^O3-@hhhhhdhddI-@@Ih`hIdII^d@O^J@@^L@>>N[kykYcii~kpk`uh^CdCxujPfi.(=T``^OX^Fhd6^F\''AFd^FO`dOOOFJ;F;^zoztddzh^^O6@^`^1/7C^huuu`{[S5!$/RReJ9CC/'/CCCC1)-1"/1COdd^^O3"--JJh^^`^TY`;@^^6-I^-OsdF6huȰo/@iu`Ȉx^C91J\J^<H/) 79/17C;CA7-7;\d^\J\J\^o~u^^`@@@-Idddd^II3<3*3>J>iuts^^\O;;JkͰtJ<JJit~tiJJJ<ieioeC9/)""CCKO\O1'\CC\Jet`T^^`J#7''4;F66\\\C^ith^t~i~k^`CO^d^;TkuuJuTEY`tiLiicki``^J^]^^et~ztttzte1) /Jett^iteCO^C/'"7$$/;ot`-Otk{uYJEky`uu`i{``3Gc~~YTT`iut`t^TJ;3CC)")<d^e]CC77'//BCdd^uJ""-O^ti~u`^`uuuuuu°{`k```^33-h^^FJ^d1  /]\OF;F;-1#Tkuk~k^^`hh\7)3Ti~vyGJL````\^\^J^tuywu^--@Wm^6FhIJ<. /C6A@;O^C3-JJThttz`J@O^JC3&c``k`ŧtuuhI^hh^3#-3Ytmsszu~°t;BCO^uhssd^;"),<1C^t~ukuuuJ",O\O^{kvcvyccv|vuTthd``hti^^^hsdhuu~u`LC"/\OduudXddm^9<)],3<J^tut^1"Ad`uu~kTL~h^J`tuu`i`^J3)";@J`^`hm`^^3)9O^hhWXWmJJ,,1<GJ^eihz~e/"7uuuu~kiectu~~ut^;;^`tu~iC91<C^\@Odhuzt]9!)6FhmhdXfshtt9!<]iviuxztzu^t\9C^JJJJ^iuti~~~~tsu;;@dtuhJtte^eC13Odhdhhht^<,)7@hsmsddZhu`t~<,J~~~itdhthh`hJ^tt]et~t~t`t`--ieJ^`^hh;;C^^^^^uut`TJ<JJJ;;J^``uu`^<31<@WhushWOuh`J<),<>i~ut`L`^^^d``ux`^J#uut^J;>3*3J^^^JO;;'"3^h@F^JCJ^^@^hd^^iu`@-3@F`ufh^dh^tT^J))C`^^^``^Iu`^`^i~{YLc:5cuhiuuJ*<^i^O;;-'-C^d^F;-#-<`I^hkY`G--Fds{juII`hhe!",,e`^@J^h{uhiuG8vvVV*_ck~~`uut<������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/lib/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13646775175�0014641�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/term.c���������������������������������������������������������������������������0000664�0000000�0000000�00000072341�13646775175�0015215�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define _WIN32_IE 0x400 #include <windows.h> #include <stdio.h> #include <commctrl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include "config.h" #include "_stdint.h" #include "sys/utils.h" #include "tty.h" #include "draw.h" #include "ttyrec.h" #include "gettext.h" #undef THREADED #define BUT_OPEN 100 #define BUT_REWIND 101 #define BUT_PAUSE 102 #define BUT_PLAY 103 #define BUT_SELSTART 104 #define BUT_SELEND 105 #define BUT_EXPORT 106 #define BUT_FONT 200 HINSTANCE inst; HWND wndMain, termwnd, wndTB, ssProg, wndProg, ssSpeed, wndSpeed; int tsx,tsy; HANDLE pth; LOGFONT df; ttyrec ttr; ttyrec_frame tev_cur; struct timeval t0, // adjusted wall time at t=0 tr; // current point of replay int tev_curlp; // amount of data already played from the current block int speed; fpos_t lastp; int play_state; // 0: not loaded, 1: paused, 2: playing, 3: waiting for input struct timeval t0,tdate,tmax,selstart,selend; int progmax,progdiv,progval; int defsx, defsy; tty vt; int play_f; const char *play_format, *play_filename; HANDLE pth_sem; CRITICAL_SECTION vt_mutex; int tev_done; HANDLE timer; int button_state; #define MAXFILENAME 256 char filename[MAXFILENAME]; LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT APIENTRY TermWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static void do_replay(void); static void load_font(void); static void win32_init(void) { WNDCLASS wc; INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_BAR_CLASSES; InitCommonControlsEx(&icex); wc.style = 0; wc.lpfnWndProc = (WNDPROC) MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = inst; wc.hIcon = LoadIcon(inst, MAKEINTRESOURCE(0)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); if (!(wc.hbrBackground = CreatePatternBrush(LoadBitmap(inst, "wood1")))) wc.hbrBackground=CreateSolidBrush(clWoodenDown); wc.lpszMenuName = 0; wc.lpszClassName = "MainWindow"; if (!RegisterClass(&wc)) die("RegisterClass"); wc.style = 0; wc.lpfnWndProc = (WNDPROC) TermWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = inst; wc.hIcon = 0; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground=0; wc.lpszMenuName = 0; wc.lpszClassName = "Term"; if (!RegisterClass(&wc)) die("RegisterClass"); load_font(); draw_init(&df); InitializeCriticalSection(&vt_mutex); if (!(timer=CreateWaitableTimer(0, 0, 0))) die("CreateWaitableTimer"); } static void create_window(int nCmdShow) { wndMain = CreateWindow( "MainWindow", "TermPlay", WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 80*chx, 25*chy, NULL, NULL, inst, NULL); if (nCmdShow==SW_SHOWDEFAULT) nCmdShow=SW_MAXIMIZE; ShowWindow(wndMain, nCmdShow); UpdateWindow(wndMain); } #define TERMBORDER 2 static HWND create_term(HWND wnd) { RECT rect; rect.left=0; rect.top=0; rect.right=chx*80+TERMBORDER; rect.bottom=chy*25+TERMBORDER; AdjustWindowRect(&rect, WS_CHILD|WS_BORDER|WS_TABSTOP, 0); termwnd = CreateWindow( "Term", 0, WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE, 0, 0, rect.right-rect.left, rect.bottom-rect.top, wnd, NULL, inst, NULL); return termwnd; } static void create_sysmenu(HWND wnd) { HMENU sysmenu=GetSystemMenu(wnd, 0); AppendMenu(sysmenu, MF_SEPARATOR, 0, 0); AppendMenu(sysmenu, MF_STRING, BUT_FONT, "Choose &font"); } static int speeds[]={100,500,1000,2000,5000,10000,25000,100000}; //{250,500,1000,2000,4000,8000,16000}; static int bcd(int a, int b) { int c; while (a>1 && b>1) { if (a>b) c=a%b, a=b, b=c; else c=b%a, b=a, b=c; } if (a>b) return a; else return b; } static void vulgar_fraction(char *buf, int x) { int d; d=bcd(x, 1000); x/=d; d=1000/d; if (d>1) sprintf(buf, "%d/%d", x, d); else sprintf(buf, "%d", x); } static void set_button_state(int id, int onoff) { TBBUTTONINFO bi; bi.cbSize=sizeof(TBBUTTONINFO); bi.dwMask=TBIF_COMMAND|TBIF_STATE; bi.idCommand=id; bi.fsState=TBSTATE_ENABLED|(onoff?TBSTATE_CHECKED:0); SendMessage(wndTB, TB_SETBUTTONINFO, (WPARAM)id, (LPARAM)&bi); } static void create_button(TBBUTTON *tb, int id, const char *caption) { TBADDBITMAP tab; tab.hInst=inst; tab.nID=id; tb->iBitmap = SendMessage(wndTB, TB_ADDBITMAP, 1, (LPARAM)&tab); tb->idCommand = id; tb->fsState = 0; tb->fsStyle = TBSTYLE_BUTTON; tb->dwData = 0; tb->iString = SendMessage(wndTB, TB_ADDSTRING, 0, (LPARAM)(LPSTR)caption); } static int create_toolbar(HWND wnd) { int height; TBBUTTON tbb[9]; RECT rc; LOGFONT lf; HFONT font; memset(&lf, 0, sizeof(lf)); lf.lfQuality=ANTIALIASED_QUALITY; lf.lfHeight=-9; strcpy(lf.lfFaceName, "Microsoft Sans Serif"); font=CreateFontIndirect(&lf); // The toolbar. wndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL, WS_CHILD|WS_VISIBLE|CCS_BOTTOM|WS_CLIPSIBLINGS|TBSTYLE_CUSTOMERASE, 0, 0, 0, 0, wnd, NULL, inst, NULL); SendMessage(wndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); create_button(&tbb[0], BUT_OPEN, "Open"); tbb[0].fsState = TBSTATE_ENABLED; tbb[1].iBitmap = 175; tbb[1].fsState = 0; tbb[1].fsStyle = TBSTYLE_SEP; tbb[1].dwData = 0; create_button(&tbb[2], BUT_REWIND, "Restart"); create_button(&tbb[3], BUT_PAUSE, "Pause"); tbb[3].fsStyle = TBSTYLE_CHECK; create_button(&tbb[4], BUT_PLAY, "Play"); tbb[4].fsStyle = TBSTYLE_CHECK; tbb[5].iBitmap = 150; tbb[5].fsState = 0; tbb[5].fsStyle = TBSTYLE_SEP; tbb[5].dwData = 0; create_button(&tbb[6], BUT_SELSTART, "SelStart"); create_button(&tbb[7], BUT_SELEND, "SelEnd"); create_button(&tbb[8], BUT_EXPORT, "Export"); SendMessage(wndTB, TB_ADDBUTTONS, (WPARAM) ARRAYSIZE(tbb), (LPARAM) (LPTBBUTTON) &tbb); SendMessage(wndTB, TB_AUTOSIZE, 0, 0); button_state=0; // The progress bar. SendMessage(wndTB, TB_GETITEMRECT, 5, (LPARAM)&rc); wndProg = CreateWindowEx( 0, // no extended styles TRACKBAR_CLASS, // class name "Progress", // title (caption) WS_CHILD | WS_VISIBLE | WS_DISABLED | TBS_NOTICKS | TBS_ENABLESELRANGE | TBS_FIXEDLENGTH, // style rc.left+5, rc.top+5, rc.right-rc.left-10, rc.bottom-rc.top-10, wnd, // parent window NULL, // control identifier inst, // instance NULL // no WM_CREATE parameter ); // SendMessage(wndProg, TBM_SETPAGESIZE, // 0, (LPARAM) 4); // new page size SetParent(wndProg, wndTB); SendMessage(wndTB, TB_GETITEMRECT, 1, (LPARAM)&rc); ssSpeed = CreateWindowEx(0, "STATIC", "Speed: x1", WS_CHILD|WS_VISIBLE|SS_LEFTNOWORDWRAP|WS_DISABLED, rc.left+5, rc.top+10, 55, rc.bottom-rc.top-15, wndTB, 0, inst, NULL); SendMessage(ssSpeed, WM_SETFONT, (WPARAM)font, 0); // The speed bar. wndSpeed = CreateWindowEx( 0, // no extended styles TRACKBAR_CLASS, // class name "Speed", // title (caption) WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |WS_DISABLED, rc.left+70, rc.top+3, rc.right-rc.left-75, rc.bottom-rc.top-3, wnd, // parent window (HMENU)104, // control identifier inst, // instance NULL // no WM_CREATE parameter ); speed=1000; SendMessage(wndSpeed, TBM_SETRANGE, 0, MAKELONG(0,ARRAYSIZE(speeds)-1)); SendMessage(wndSpeed, TBM_SETPOS, 1, 2); SetParent(wndSpeed, wndTB); SetFocus(wndProg); GetWindowRect(wndTB, &rc); height=rc.bottom-rc.top; height+=25*chy; rc.right-=rc.left; if (rc.right<80*chx) rc.right=80*chx; rc.bottom=height; rc.left=0; rc.top=0; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, 0); SetWindowPos(wnd, 0, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE|SWP_NOREPOSITION); return 1; } static void set_toolbar_state(int onoff) { SendMessage(wndTB, TB_ENABLEBUTTON, BUT_REWIND, onoff); SendMessage(wndTB, TB_ENABLEBUTTON, BUT_PAUSE, onoff); SendMessage(wndTB, TB_ENABLEBUTTON, BUT_PLAY, onoff); EnableWindow(wndSpeed, onoff); EnableWindow(ssSpeed, onoff); SendMessage(wndTB, TB_ENABLEBUTTON, BUT_SELSTART, onoff); SendMessage(wndTB, TB_ENABLEBUTTON, BUT_SELEND, onoff); SendMessage(wndTB, TB_ENABLEBUTTON, BUT_EXPORT, onoff); } static void set_buttons(int force) { if (play_state==button_state && !force) return; set_button_state(BUT_PAUSE, play_state==1); set_button_state(BUT_PLAY, play_state>1); } static void set_prog_max(void) { EnableWindow(wndProg, 0); SendMessage(wndProg, TBM_CLEARSEL, 0, 0); SendMessage(wndProg, TBM_SETRANGEMAX, 0, (LPARAM)progmax); EnableWindow(wndProg, 1); } static void set_prog(void) { int t=tr.tv_sec*(1000000/progdiv)+tr.tv_usec/progdiv; if (t!=progval) { progval=t; SendMessage(wndProg, TBM_SETPOS, 1, (LPARAM)t); } } static void get_pos(void) { if (play_state==2) { gettimeofday(&tr, 0); tsub(tr, t0); tmul1000(tr, speed); } } static void set_prog_sel(void) { int t1=selstart.tv_sec*(1000000/progdiv)+selstart.tv_usec/progdiv; int t2=selend.tv_sec*(1000000/progdiv)+selend.tv_usec/progdiv; SendMessage(wndProg, TBM_SETSEL, 1, (LPARAM)MAKELONG(t1,t2)); SendMessage(wndTB, TB_ENABLEBUTTON, BUT_EXPORT, tcmp(selstart, selend)<0); } static void draw_size(void) { if (vt->sx==tsx && vt->sy==tsy) return; RECT r; r.left=0; r.top=0; r.right=(tsx=vt->sx)*chx+TERMBORDER; r.bottom=(tsy=vt->sy)*chy+TERMBORDER; AdjustWindowRect(&r, GetWindowLong(termwnd, GWL_STYLE), 0); SetWindowPos(termwnd, 0, 0, 0, r.right, r.bottom, SWP_NOACTIVATE| SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); } static void playfile(tty tev_vt) { char buf[1024]; ttr=ttyrec_load(play_f, play_format, play_filename, tev_vt); if (!ttr) return; ttyrec_add_frame(ttr, 0, buf, snprintf(buf, sizeof(buf), "\e[0m%s", _("End of recording."))); } static void replay_pause(void) { switch (play_state) { case 0: default: case 1: break; case 2: gettimeofday(&tr, 0); tsub(tr, t0); tmul1000(tr, speed); case 3: play_state=1; } } static void replay_resume(void) { struct timeval t; switch (play_state) { case 0: default: case 1: gettimeofday(&t0, 0); t=tr; tdiv1000(t, speed); tsub(t0, t); play_state=2; break; case 2: case 3: break; } } static int replay_play(struct timeval *delay) { // structures touched: tev, vt struct timeval tr1; ttyrec_frame fn; switch (play_state) { case 0: default: case 1: return 0; case 2: gettimeofday(&tr, 0); tsub(tr, t0); tmul1000(tr, speed); tr1=tr; tadd(tr1, tdate); if (tev_cur && tev_cur->len>tev_curlp) { tty_write(vt, tev_cur->data+tev_curlp, tev_cur->len-tev_curlp); tev_curlp=tev_cur->len; } while ((fn=ttyrec_next_frame(ttr, tev_cur)) && tcmp(fn->t, tr1)==-1) { tev_cur=fn; if (tev_cur->data) tty_write(vt, tev_cur->data, tev_cur->len); tev_curlp=tev_cur->len; } if ((fn=ttyrec_next_frame(ttr, tev_cur))) { *delay=fn->t; tsub(*delay, tdate); tsub(*delay, tr); tdiv1000(*delay, speed); return 1; } play_state=tev_done?0:3; case 3: return 0; } } // find the frame containing time "tr", update "t0" static void replay_seek(void) { struct timeval t; t=tr; tadd(t, tdate); tev_cur=ttyrec_seek(ttr, &t, &vt); tev_curlp=0; gettimeofday(&t0, 0); tdiv1000(tr, speed); tsub(t0, tr); } static void replay_start(void) { tty tev_vt; ttyrec_frame tev_tail; struct timeval doomsday; ttyrec_free(ttr); tev_vt=tty_init(defsx, defsy, 1); tev_vt->cp437=1; tty_printf(tev_vt, "\e[36m"); tty_printf(tev_vt, _("Termplay v%s\n\n"), "\e[36;1m"PACKAGE_VERSION"\e[0;36m"); tty_printf(tev_vt, "\e[0m"); tr.tv_sec=tr.tv_usec=0; tev_done=0; tmax.tv_sec=tmax.tv_usec=0; progmax=0; progdiv=1000000; progval=-1; // TODO: re-enable threading #ifdef THREADED pth=CreateThread(0, 0, (LPTHREAD_START_ROUTINE)playfile, (LPDWORD)0, 0, 0); #else // printf("Buffering: started.\n"); playfile(tev_vt); // printf("Buffering: done.\n"); tev_done=1; tev_cur=ttyrec_seek(ttr, 0, 0); tdate=tev_cur->t; replay_seek(); doomsday.tv_sec=1ULL<<(sizeof(doomsday.tv_sec)*8-1)-1; doomsday.tv_usec=0; tev_tail=ttyrec_seek(ttr, &doomsday, 0); tmax=tev_tail->t; tsub(tmax, tdate); if (tmax.tv_sec<100) progdiv=10000; else progdiv=1000000; selstart.tv_sec=0; selstart.tv_usec=0; selend=tmax; progmax=tmax.tv_sec*(1000000/progdiv)+tmax.tv_usec/progdiv; set_prog_max(); set_prog(); #endif } static void replay_abort(void) { #ifdef THREADED WaitForSingleObject(pth, INFINITE); #endif } static int start_file(char *name) { char buf[MAXFILENAME+20]; int fd; if (play_f!=-1) { replay_abort(); close(play_f); play_f=-1; CancelWaitableTimer(timer); replay_pause(); set_buttons(0); } fd=open_stream(-1, name, SM_READ, 0); if (fd==-1) return 0; play_f=fd; play_format=ttyrec_r_find_format(0, name, "baudrate"); play_filename=name; replay_start(); snprintf(buf, sizeof(buf), "Termplay: %s (%s)", filename, play_format); SetWindowText(wndMain, buf); set_toolbar_state(1); play_state=2; do_replay(); return 1; } static void open_file(void) { char fn[MAXFILENAME]; OPENFILENAME dlg; memset(&dlg, 0, sizeof(dlg)); dlg.lStructSize=sizeof(dlg); dlg.hwndOwner=wndMain; dlg.lpstrFilter="all known formats\000" "*.ttyrec;*.ttyrec.gz;*.ttyrec.bz2;*.ttyrec.xz;*.ttyrec.zst;" "*.nh;*.nh.gz;*.nh.bz2;*.nh.xz;*.nh.zst;" "*.dm2;" "*.cast;*.cast.gz;*.cast.bz2;*.cast.xz;*.cast.zst;" "*.txt;*.txt.gz;*.txt.bz2;*.txt.xz;*.txt.zst\000" "ttyrec videos (*.ttyrec, *.ttyrec.[gz|bz2|xz|zst])\000" "*.ttyrec;*.ttyrec.gz;*.ttyrec.bz2;*.ttyrec.xz;*.ttyrec.zst\000" "nh-recorder videos (*.nh, *.nh.[gz|bz2|xz|zst])\000" "*.nh;*.nh.gz;*.nh.bz2;*.nh.xz;*.nh.zst\000" "DosRecorder videos (*.dm2)\000" "*.dm2\000" "asciicast videos (*.cast, *.cast.[gz|bz2|xz|zst])\000" "*.cast;*.cast.gz;*.cast.bz2;*.cast.xz;*.cast.zst\000" "ANSI logs (*.txt, *.txt.[gz|bz2|xz|zst])\000" "*.txt;*.txt.gz;*.txt.bz2;*.txt.xz;*.txt.zst\000" "all files\000*\000" "\000\000"; dlg.nFilterIndex=1; dlg.lpstrFile=fn; dlg.nMaxFile=MAXFILENAME; dlg.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_LONGNAMES; *fn=0; if (!GetOpenFileName(&dlg)) return; strncpy(filename, fn, MAXFILENAME); start_file(filename); } static void replay_speed(int x) { if (play_state==-1) { speed=x; return; } replay_pause(); speed=x; replay_resume(); do_replay(); } static void print_banner(void) { int i; const char *pn; tty_printf(vt, "\e[?25l\e[36mTermplay v\e[1m"PACKAGE_VERSION"\e[0m\n"); tty_printf(vt, "\e[33mTerminal size: \e[1m%d\e[21mx\e[1m%d\e[0m\n", vt->sx, vt->sy); tty_printf(vt, "\e[34;1m\e%%G\xd0\xa1\xd0\xb4\xd0\xb5\xd0\xbb\xd0\xb0\xd0\xbd\xd0\xbe by KiloByte (kilobyte@angband.pl)\e[0m\n"); tty_printf(vt, "Compression plugins:\n"); #if (defined HAVE_LIBZ) || (SHIPPED_LIBZ) tty_printf(vt, "* gzip\n"); #endif #if (defined HAVE_LIBBZ2) || (defined SHIPPED_LIBBZ2) tty_printf(vt, "* bzip2\n"); #endif #if (defined HAVE_LIBLZMA) || (defined SHIPPED_LIBLZMA) tty_printf(vt, "* xz\n"); #endif #if (defined HAVE_LIBZSTD) || (defined SHIPPED_LIBZSTD) tty_printf(vt, "* zstd\n"); #endif tty_printf(vt, "Replay plugins:\n"); for (i=0;(pn=ttyrec_r_get_format_name(i));i++) if (strcmp(pn, "live")) tty_printf(vt, "* %s\n", pn); } static void paint(HWND hwnd) { HDC dc; PAINTSTRUCT paints; if (!(dc=BeginPaint(hwnd,&paints))) return; EnterCriticalSection(&vt_mutex); draw_vt(dc, paints.rcPaint.right, paints.rcPaint.bottom, vt); draw_border(dc, vt); LeaveCriticalSection(&vt_mutex); EndPaint(hwnd,&paints); } static void do_replay(void) { HDC dc; struct timeval delay = {}; LARGE_INTEGER del; again: if (play_state!=2) { set_buttons(0); CancelWaitableTimer(timer); return; } EnterCriticalSection(&vt_mutex); replay_play(&delay); draw_size(); dc=GetDC(termwnd); draw_vt(dc, chx*vt->sx, chy*vt->sy, vt); ReleaseDC(termwnd, dc); LeaveCriticalSection(&vt_mutex); set_prog(); if (play_state!=2) { set_buttons(1); // finished return; } del.QuadPart=delay.tv_sec; del.QuadPart*=1000000; del.QuadPart+=delay.tv_usec; if (del.QuadPart<=0) goto again; del.QuadPart*=-10; SetWaitableTimer(timer, &del, 0, 0, 0, 0); set_buttons(0); } static void speed_scrolled(void) { char buf[32]; int pos=SendMessage(wndSpeed, TBM_GETPOS, 0, 0); if (pos<0) pos=0; if (pos>=ARRAYSIZE(speeds)) pos=ARRAYSIZE(speeds)-1; if (speed==speeds[pos]) return; replay_speed(speeds[pos]); vulgar_fraction(buf+sprintf(buf, "Speed: x"), speed); SetWindowText(ssSpeed, buf); GetWindowText(ssSpeed, buf, sizeof(buf)); } static void adjust_speed(int dir) { int pos=SendMessage(wndSpeed, TBM_GETPOS, 0, 0); SendMessage(wndSpeed, TBM_SETPOS, 1, pos+dir); speed_scrolled(); } static void redraw_term(void) { HDC dc; EnterCriticalSection(&vt_mutex); draw_size(); dc=GetDC(termwnd); draw_vt(dc, chx*vt->sx, chy*vt->sy, vt); ReleaseDC(termwnd, dc); LeaveCriticalSection(&vt_mutex); } static void prog_scrolled(void) { uint64_t v; int oldstate=play_state; int pos=SendMessage(wndProg, TBM_GETPOS, 0, 0); if (pos<0) pos=0; replay_pause(); v=pos; v*=progdiv; tr.tv_sec=v/1000000; tr.tv_usec=v%1000000; replay_seek(); play_state=oldstate; redraw_term(); do_replay(); } static void adjust_pos(int d) { int oldstate=play_state; if (play_state==-1) return; replay_pause(); tr.tv_sec+=d; if (tr.tv_sec<0) tr.tv_sec=tr.tv_usec=0; if (tcmp(tr, tmax)==1) tr=tmax; replay_seek(); play_state=oldstate; redraw_term(); set_prog(); do_replay(); } static void get_def_size(int nx, int ny) { RECT r; GetWindowRect(wndTB, &r); defsx=nx/chx; defsy=(ny+r.top-r.bottom)/chy; } static void constrain_size(RECT *r) { RECT wr,cr,tbr; int fx,fy; GetWindowRect(wndMain,&wr); GetClientRect(wndMain,&cr); GetWindowRect(wndTB, &tbr); fx=(wr.right-wr.left)-(cr.right-cr.left); fy=(wr.bottom-wr.top)-(cr.bottom-cr.top); fx+=80*chx; fy+=25*chy+tbr.bottom-tbr.top; if (r->right-r->left<fx) r->right=r->left+fx; if (r->bottom-r->top<fy) r->bottom=r->top+fy; } static void export_file(void) { char fn[MAXFILENAME],errmsg[MAXFILENAME+20+128]; OPENFILENAME dlg; int record_f; const char *format; struct timeval sel1, sel2; memset(&dlg, 0, sizeof(dlg)); dlg.lStructSize=sizeof(dlg); dlg.hwndOwner=wndMain; dlg.lpstrFilter= "ttyrec videos (*.ttyrec, *.ttyrec.[gz|bz2|xz|zst])\000*.ttyrec;*.ttyrec.gz;*.ttyrec.bz2;*.ttyrec.xz;*.ttyrec.zst\000" "nh-recorder videos (*.nh, *.nh.[gz|bz2|xz|zst])\000*.nh;*.nh.gz;*.nh.bz2;*.nh.xz;*.nh.zst\000" "asciinema videos (*.cast, *.cast.[gz|bz2|xz|zst])\000*.cast;*.cast.gz;*.cast.bz2;*.cast.xz;*.cast.zst\000" "ANSI logs (*.txt, *.txt.[gz|bz2|xz|zst])\000*.txt;*.txt.gz;*.txt.bz2;*.txt.xz;*.txt.zst\000" "all files\000*\000" "\000\000"; dlg.nFilterIndex=1; dlg.lpstrFile=fn; dlg.nMaxFile=MAXFILENAME; dlg.Flags=OFN_HIDEREADONLY|OFN_LONGNAMES; dlg.lpstrDefExt="ttyrec.bz2"; *fn=0; if (!GetSaveFileName(&dlg)) return; format=ttyrec_w_find_format(0, fn, "ansi"); if ((record_f=open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0666))==-1) { sprintf(errmsg, "Can't write to %s: %s", fn, strerror(errno)); MessageBox(wndMain, errmsg, "Write error", MB_ICONERROR); return; } record_f=open_stream(record_f, fn, SM_WRITE, 0); sel1=selstart; tadd(sel1, tdate); sel2=selend; tadd(sel2, tdate); ttyrec_save(ttr, record_f, format, filename, &sel1, &sel2); } void load_font(void) { HKEY reg; int i; DWORD len; memset(&df, 0, sizeof(LOGFONT)); df.lfHeight=16; strcpy(df.lfFaceName, "Courier New"); if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\1KB\\termrec", 0, KEY_READ, ®)) return; len=LF_FACESIZE; RegQueryValueEx(reg, "FontName", 0, 0, (BYTE*)df.lfFaceName, &len); len=sizeof(i); if (!RegQueryValueEx(reg, "FontHeight", 0, 0, (BYTE*)&i, &len)) df.lfHeight=i; len=sizeof(i); if (!RegQueryValueEx(reg, "FontWeight", 0, 0, (BYTE*)&i, &len)) df.lfWeight=i; len=sizeof(i); if (!RegQueryValueEx(reg, "FontItalic", 0, 0, (BYTE*)&i, &len)) df.lfItalic=i; RegCloseKey(reg); } static void save_font(void) { HKEY reg; int i; if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\1KB\\termrec", 0, 0, 0, KEY_WRITE, 0, ®, 0)) return; RegSetValueEx(reg, "FontName", 0, REG_SZ, (BYTE*)df.lfFaceName, strlen(df.lfFaceName)+1); i=df.lfHeight; RegSetValueEx(reg, "FontHeight", 0, REG_DWORD, (BYTE*)&i, sizeof(i)); i=df.lfWeight; RegSetValueEx(reg, "FontWeight", 0, REG_DWORD, (BYTE*)&i, sizeof(i)); i=df.lfItalic; RegSetValueEx(reg, "FontItalic", 0, REG_DWORD, (BYTE*)&i, sizeof(i)); RegCloseKey(reg); } static void choose_font(void) { CHOOSEFONT cf; memset(&cf, 0, sizeof(CHOOSEFONT)); cf.lStructSize=sizeof(CHOOSEFONT); cf.hwndOwner=wndMain; cf.Flags=CF_FIXEDPITCHONLY|CF_NOSCRIPTSEL|CF_SCREENFONTS|CF_INITTOLOGFONTSTRUCT; cf.lpLogFont=&df; if (!ChooseFont(&cf)) return; save_font(); draw_free(); draw_init(&df); InvalidateRect(termwnd, 0, 1); } LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: create_toolbar(hwnd); create_term(hwnd); create_sysmenu(hwnd); return 0; case WM_SIZE: SendMessage(wndTB, TB_AUTOSIZE, 0, 0); get_def_size(LOWORD(lParam), HIWORD(lParam)); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case BUT_OPEN: open_file(); break; case BUT_REWIND: but_rewind: if (play_state==-1) break; EnterCriticalSection(&vt_mutex); replay_pause(); tr.tv_sec=0; tr.tv_usec=0; set_prog(); replay_seek(); LeaveCriticalSection(&vt_mutex); play_state=1; replay_resume(); do_replay(); break; case BUT_PAUSE: if (play_state==1) goto but_unpause; but_pause: CancelWaitableTimer(timer); replay_pause(); set_buttons(1); break; case BUT_PLAY: if (play_state>1) goto but_pause; but_unpause: replay_resume(); do_replay(); set_buttons(1); break; case BUT_SELSTART: if (play_state==-1) break; get_pos(); selstart=tr; set_prog_sel(); break; case BUT_SELEND: if (play_state==-1) break; selend=tr; set_prog_sel(); break; case BUT_EXPORT: if (play_state==-1) break; if (tcmp(selstart, selend)>=0) break; export_file(); break; } return 0; case WM_SYSCOMMAND: switch (LOWORD(wParam)) { default: return DefWindowProc(hwnd, uMsg, wParam, lParam); case BUT_FONT: choose_font(); } return 0; case WM_HSCROLL: if ((HANDLE)lParam==wndSpeed) speed_scrolled(); else if ((HANDLE)lParam==wndProg) prog_scrolled(); return 0; case WM_KEYDOWN: switch (wParam) { case 'F': if (GetKeyState(VK_CONTROL)&0x8000) { choose_font(); break; } case VK_ADD: adjust_speed(+1); break; case VK_SUBTRACT: case 'S': adjust_speed(-1); break; case '1': SendMessage(wndSpeed, TBM_SETPOS, 1, 2); speed_scrolled(); break; case 'Q': DestroyWindow(wndMain); break; case 'O': open_file(); break; case VK_SPACE: switch (play_state) { case -1: open_file(); break; case 0: play_state=2; goto but_rewind; case 1: goto but_unpause; case 2: case 3: goto but_pause; } break; case 'R': goto but_rewind; break; case VK_RIGHT: adjust_pos(+10); break; case VK_LEFT: adjust_pos(-10); break; case VK_UP: adjust_pos(+60); break; case VK_DOWN: adjust_pos(-60); break; case VK_PRIOR: adjust_pos(+600); break; case VK_NEXT: adjust_pos(-600); break; } return 0; case WM_SIZING: constrain_size((LPRECT)lParam); return 1; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } LRESULT APIENTRY TermWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_PAINT: paint(hwnd); return 0; case WM_LBUTTONDOWN: SetFocus(wndMain); return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } int APIENTRY WinMain(HINSTANCE instance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { inst = instance; win32_init(); speed=1000; play_f=-1; play_state=-1; tsx=tsy=0; defsx=80; defsy=25; vt=tty_init(defsx, defsy, 1); vt->cp437=1; if (*lpCmdLine=='"') // FIXME: proper parsing { strncpy(filename, lpCmdLine+1, MAXFILENAME-1); filename[strlen(filename)-1]=0; } else strncpy(filename, lpCmdLine, MAXFILENAME-1); filename[MAXFILENAME-1]=0; create_window(nCmdShow); print_banner(); draw_size(); UpdateWindow(wndMain); ttr=0; if (*filename) if (!start_file(filename)) { tty_printf(vt, "\n\e[41;1mFile not found: %s\e[0m\n", filename); *filename=0; redraw_term(); } while (message_loop(&timer, 1)==0) do_replay(); return 0; UNREFERENCED_PARAMETER(hPrevInstance); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/termrec.iss����������������������������������������������������������������������0000664�0000000�0000000�00000003173�13646775175�0016260�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Files] Source: lib/bzip2.dll; DestDir: {app} Source: ../.libs/libtty-0.dll; DestDir: {app}; Flags: ignoreversion Source: ../.libs/termplay.exe; DestDir: {app}; Flags: ignoreversion Source: ../.libs/termrec.exe; DestDir: {app}; Flags: ignoreversion Source: lib/zlib1.dll; DestDir: {app} Source: lib/liblzma.dll; DestDir: {app} [_ISTool] UseAbsolutePaths=false [Setup] OutputBaseFilename=termrec-0.15 SolidCompression=true PrivilegesRequired=none DefaultDirName={pf}\termrec DefaultGroupName=termrec AppName=termrec ChangesAssociations=true AppVerName=termrec 0.15 [Registry] Root: HKCR; SubKey: .ttyrec; ValueType: string; ValueData: ttyrec; Flags: uninsdeletekey Root: HKCR; SubKey: ttyrec; ValueType: string; ValueData: ttyrec replay; Flags: uninsdeletekey Root: HKCR; SubKey: ttyrec\Shell\Open\Command; ValueType: string; ValueData: """{app}\termplay.exe"" ""%1"""; Flags: uninsdeletevalue Root: HKCR; Subkey: ttyrec\DefaultIcon; ValueType: string; ValueData: {app}\termplay.exe; Flags: uninsdeletevalue Root: HKCR; SubKey: .ttyrec.bz2; ValueType: string; ValueData: ttyrec; Flags: uninsdeletekey Root: HKCR; SubKey: .ttyrec.gz; ValueType: string; ValueData: ttyrec; Flags: uninsdeletekey Root: HKCR; SubKey: .ttyrec.xz; ValueType: string; ValueData: ttyrec; Flags: uninsdeletekey Root: HKCR; SubKey: .dm2; ValueType: string; ValueData: ttyrec; Flags: uninsdeletekey [Icons] Name: {group}\ttyrec player; Filename: {app}\termplay.exe; WorkingDir: {userdocs}; IconIndex: 0 Name: {group}\ttyrec recorder; Filename: {app}\termrec.exe; WorkingDir: {userdocs} Name: {group}\{cm:UninstallProgram, termrec}; Filename: {uninstallexe} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������termrec-0.19/win32/winrec.c�������������������������������������������������������������������������0000664�0000000�0000000�00000040466�13646775175�0015540�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Termrec uses "MSAA" ("Microsoft Active Accessability"), it's present on WinXP and some regional (Japanese, ...) versions of Win2K and Win98. If that API is not there, termrec will fall back to polling the screen 50 times per second, possibly losing some of fast-scrolled text. Even MSAA is not atomic, too. Due to the unholy mess of code pages (on Polish version, there are 3 non-compatible pages and Unicode), termrec will use UTF-8 where available. This means, on NT-based versions of Windows. If you're on Win95/98/ME, your mileage will vary according to the program you use -- termplay is hard-coded for CP437, fit for NetHack. */ #define WINVER 0x501 #define _WIN32_WINDOWS 0x501 #define _WIN32_WINNT 0x501 #include <windows.h> #include <stdio.h> #include <stdarg.h> #include "sys/utils.h" #include "ttyrec.h" #include "common.h" #include "rec_args.h" //#define EVDEBUG recorder rec; #ifdef EVDEBUG FILE *evlog; # define EVLOG(...) do {fprintf(evlog, __VA_ARGS__); fflush(evlog);} while(0) #else # define EVLOG(...) #endif HANDLE con,proch; DWORD proc; UINT_PTR timer; int vtrec_cursor; int vtrec_cx,vtrec_cy; // the vt100 cursor int vtrec_wx,vtrec_wy; // the win32 cursor int vtrec_x1,vtrec_y1,vtrec_x2,vtrec_y2; int vtrec_rows,vtrec_cols; int utf8; short vtrec_attr; typedef CHAR_INFO SCREEN[0x10000]; // the SDK says we can't even think of bigger consoles SCREEN cscr; char vtrec_buf[0x10000], *vb; static void vtrec_commit(void) { struct timeval tv; if (vb==vtrec_buf) return; gettimeofday(&tv, 0); ttyrec_w_write(rec, &tv, vtrec_buf, vb-vtrec_buf); vb=vtrec_buf; } void vtrec_printf(const char *fmt, ...) __attribute__((format (printf, 1, 2))); void vtrec_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vb+=vsprintf(vb,fmt,ap); va_end(ap); } // FIXME: make it damn sure we don't have any buffer overflows static inline void vtrec_utf8(unsigned short uv) { // Larry Wall style. The similarities in formatting are, uhm, // purely accidental. if (uv<0x80) { *vb++=uv; return; } if (uv < 0x800) { *vb++ = ( uv >> 6) | 0xc0; *vb++ = ( uv & 0x3f) | 0x80; return; } #ifdef FULL_UNICODE if (uv < 0x10000) { #endif *vb++ = ( uv >> 12) | 0xe0; *vb++ = ((uv >> 6) & 0x3f) | 0x80; *vb++ = ( uv & 0x3f) | 0x80; #ifdef FULL_UNICODE return; } if (uv < 0x200000) { *vb++ = ( uv >> 18) | 0xf0; *vb++ = ((uv >> 12) & 0x3f) | 0x80; *vb++ = ((uv >> 6) & 0x3f) | 0x80; *vb++ = ( uv & 0x3f) | 0x80; return; } if (uv < 0x4000000) { *vb++ = ( uv >> 24) | 0xf8; *vb++ = ((uv >> 18) & 0x3f) | 0x80; *vb++ = ((uv >> 12) & 0x3f) | 0x80; *vb++ = ((uv >> 6) & 0x3f) | 0x80; *vb++ = ( uv & 0x3f) | 0x80; return; } if (uv < 0x80000000) { *vb++ = ( uv >> 30) | 0xfc; *vb++ = ((uv >> 24) & 0x3f) | 0x80; *vb++ = ((uv >> 18) & 0x3f) | 0x80; *vb++ = ((uv >> 12) & 0x3f) | 0x80; *vb++ = ((uv >> 6) & 0x3f) | 0x80; *vb++ = ( uv & 0x3f) | 0x80; return; } #endif } static void vtrec_init(void) { vtrec_cursor=1; vtrec_cx=vtrec_wx=0; vtrec_cy=vtrec_wy=0; vtrec_cols=-1; vtrec_rows=-1; // try to force a resize vb=vtrec_buf; vtrec_printf("\e[c\e%%%c\e[f\e[?7l", utf8?'G':'@'); } static char VT_COLORS[]="04261537"; static void vtrec_realize_attr(void) { vtrec_printf("\e[0;3%c;4%c%s%sm", VT_COLORS[vtrec_attr&7], VT_COLORS[(vtrec_attr>>4)&7], vtrec_attr&8?";1":"", vtrec_attr&0x80?";5":""); } #define is_printable(x) (((x)>=32 && (x)<127) || ((signed char)(x)<0)) static inline void vtrec_outchar(CHAR_INFO c) { if (utf8) vtrec_utf8(c.Char.UnicodeChar); else if (is_printable(c.Char.AsciiChar)) *vb++=c.Char.AsciiChar; else *vb++='?'; vtrec_cx++; } static void vtrec_char(int x, int y, CHAR_INFO c) { #ifdef EVDEBUG if (x<0 || x>=vtrec_cols || y<0 || y>=vtrec_rows) EVLOG("Out of bounds: %d,%d\n", x, y); #endif if (x!=vtrec_cx || y!=vtrec_cy) { if (y==vtrec_cy && vtrec_cx<x && vtrec_cx+10>=x) { // On small skips, it's better to rewrite instead of jumping, // especially considering that our algorithm produces a lot of // such skips if the new text has a single matching letter in // the same place as the old one. int z; CHAR_INFO *sp; sp=cscr+vtrec_cy*vtrec_cols+vtrec_cx; for (z=vtrec_cx;z<x;z++) if (sp++->Attributes!=vtrec_attr) goto jump; sp=cscr+vtrec_cy*vtrec_cols+vtrec_cx; for (z=vtrec_cx;z<x;z++) vtrec_outchar(*sp++); } else { jump: vtrec_printf("\e[%d;%df", (vtrec_cy=y)+1, (vtrec_cx=x)+1); } } if (c.Attributes!=vtrec_attr) { vtrec_attr=c.Attributes; vtrec_realize_attr(); } vtrec_outchar(c); } static void vtrec_realize_cursor(void) { if (!vtrec_cursor) // cursor hidden -- its position is irrelevant return; if (vtrec_cx==vtrec_wx && vtrec_wy==vtrec_cy) return; vtrec_printf("\e[%d;%dH", vtrec_wy+1, vtrec_wx+1); vtrec_cx=vtrec_wx; vtrec_cy=vtrec_wy; } static void vtrec_dump(int full) { CONSOLE_SCREEN_BUFFER_INFO cbi; SCREEN scr; CHAR_INFO *sp,*cp; SMALL_RECT reg; COORD sz,org; int x,y; GetConsoleScreenBufferInfo(con, &cbi); vtrec_x1=cbi.srWindow.Left; vtrec_y1=cbi.srWindow.Top; vtrec_x2=cbi.srWindow.Right; vtrec_y2=cbi.srWindow.Bottom; if (vtrec_cols!=vtrec_x2-vtrec_x1+1 ||vtrec_rows!=vtrec_y2-vtrec_y1+1) { vtrec_cols=vtrec_x2-vtrec_x1+1; vtrec_rows=vtrec_y2-vtrec_y1+1; full=1; vtrec_printf("\e[8;%d;%dt\e[1;%dr", vtrec_rows, vtrec_cols, vtrec_rows); } if (vtrec_rows*vtrec_cols>0x10000) return; vtrec_wx=cbi.dwCursorPosition.X-vtrec_x1; vtrec_wy=cbi.dwCursorPosition.Y-vtrec_y1; EVLOG("===dump%s===\n", full?" (full)":""); reg=cbi.srWindow; sz.X=vtrec_cols; sz.Y=vtrec_rows; org.X=0; org.Y=0; if (utf8) { if (ReadConsoleOutputW(con, scr, sz, org, ®)) goto dump_ok; if (ReadConsoleOutputA(con, scr, sz, org, ®)) { EVLOG("Disabling Unicode\n"); vtrec_printf("\e%%@"); utf8=0; goto dump_ok; } } else if (ReadConsoleOutputA(con, scr, sz, org, ®)) goto dump_ok; EVLOG("DUMP FAILED!!\n"); return; dump_ok: // FIXME: the region could have changed between the calls, resulting in // garbage in the output. if (full) { sp=scr; for (y=0;y<vtrec_rows;y++) { for (x=0;x<vtrec_cols;x++) vtrec_char(x,y,*sp++); } memcpy(cscr, scr, vtrec_rows*vtrec_cols*sizeof(CHAR_INFO)); } else { sp=scr; cp=cscr; for (y=0;y<vtrec_rows;y++) { for (x=0;x<vtrec_cols;x++) { if (sp->Char.UnicodeChar!=cp->Char.UnicodeChar || sp->Attributes!=cp->Attributes) vtrec_char(x,y,*sp); *cp++=*sp++; } } } vtrec_realize_cursor(); vtrec_commit(); } // For any non-base-ASCII chars, the 16 bit value given is neither the local // win codepage value nor Unicode. Ghrmblah. static void vtrec_dump_char(int wx, int wy, DWORD ch) { CHAR_INFO c; SMALL_RECT reg; COORD sz,org; sz.X=1; sz.Y=1; org.X=0; org.Y=0; reg.Left=reg.Right=wx; reg.Top=reg.Bottom=wy; if ((LOWORD(ch)>=32 && LOWORD(ch)<127) || !(utf8?ReadConsoleOutputW(con, &c, sz, org, ®): ReadConsoleOutputA(con, &c, sz, org, ®))) { // last resort c.Char.UnicodeChar=LOWORD(ch); c.Attributes=HIWORD(ch); } wx-=vtrec_x1; wy-=vtrec_y1; vtrec_char(wx, wy, c); cscr[wy*vtrec_cols+wx]=c; vtrec_commit(); } static void vtrec_scroll(int d) { CONSOLE_SCREEN_BUFFER_INFO cbi; CHAR_INFO *cp; int x,h=abs(d); if (h>=vtrec_rows) { vtrec_dump(1); return; } GetConsoleScreenBufferInfo(con, &cbi); vtrec_attr=cbi.wAttributes; vtrec_realize_attr(); x=vtrec_cols*h; if (d<0) { memmove(cscr, cscr+h*vtrec_cols, (vtrec_cols*(vtrec_rows-h))*sizeof(CHAR_INFO)); cp=cscr+(vtrec_cols*(vtrec_rows-h)); vtrec_printf("\e[%df", vtrec_rows); while (h--) vtrec_printf("\eD"); } else { memmove(cscr+h*vtrec_cols, cscr, (vtrec_cols*(vtrec_rows-h))*sizeof(CHAR_INFO)); cp=cscr; vtrec_printf("\e[f"); while (h--) vtrec_printf("\eM"); } while (x--) { cp->Char.UnicodeChar=' '; cp->Attributes=vtrec_attr; cp++; } vtrec_x1=cbi.srWindow.Left; vtrec_y1=cbi.srWindow.Top; vtrec_x2=cbi.srWindow.Right; vtrec_y2=cbi.srWindow.Bottom; vtrec_wx=cbi.dwCursorPosition.X-vtrec_x1; vtrec_wy=cbi.dwCursorPosition.Y-vtrec_y1; vtrec_realize_cursor(); vtrec_commit(); } int vtrec_dirty=0; int vtrec_reent=0; #ifdef EVDEBUG static char *evnames[]={ 0, "EVENT_CONSOLE_CARET", "EVENT_CONSOLE_UPDATE_REGION", "EVENT_CONSOLE_UPDATE_SIMPLE", "EVENT_CONSOLE_UPDATE_SCROLL", "EVENT_CONSOLE_LAYOUT", "EVENT_CONSOLE_START_APPLICATION", "EVENT_CONSOLE_END_APPLICATION"}; #endif static VOID CALLBACK WinEventProc( HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime ) { #ifdef EVDEBUG if (event>0x4000 && event<=0x4007) EVLOG("%s: %d(%d,%d), %d(%d,%d)\n", evnames[event-0x4000], (int)idObject, (short int)LOWORD(idObject), (short int)HIWORD(idObject), (int)idChild, (short int)LOWORD(idChild), (short int)HIWORD(idChild)); #endif if (timer) // If events work, let's disable polling. { if (timer!=(UINT_PTR)(-1)) // magic cookie for Win95/98/ME KillTimer(0, timer); timer=0; } if (vtrec_reent) { vtrec_dirty=1; return; } vtrec_reent=1; if (vtrec_dirty) { vtrec_dirty=0; vtrec_dump(0); vtrec_reent=0; return; } switch (event) { case EVENT_CONSOLE_CARET: if (vtrec_cursor!=!!(idObject&CONSOLE_CARET_VISIBLE)) { vtrec_cursor=!vtrec_cursor; vtrec_printf("\e[?4%c", vtrec_cursor?'h':'l'); } if (LOWORD(idChild)+vtrec_x1!=vtrec_wx || HIWORD(idChild)+vtrec_y1!=vtrec_wy) { vtrec_wx=LOWORD(idChild)-vtrec_x1; vtrec_wy=HIWORD(idChild)-vtrec_y1; vtrec_realize_cursor(); } vtrec_commit(); break; case EVENT_CONSOLE_LAYOUT: vtrec_dump(0); break; case EVENT_CONSOLE_UPDATE_REGION: vtrec_dump(0); break; case EVENT_CONSOLE_UPDATE_SIMPLE: vtrec_dump_char(LOWORD(idObject), HIWORD(idObject), idChild); break; case EVENT_CONSOLE_UPDATE_SCROLL: if (idObject) vtrec_dump(1); else if (idChild) vtrec_scroll(idChild); break; #if 0 case EVENT_CONSOLE_END_APPLICATION: // doesn't work on Win98 -- replaced by MsgWait if (idObject==proc) PostQuitMessage(0); #endif } vtrec_reent=0; } // Work around in Windows' (but not Cygwin's) bug in atexit. extern void reap_streams(void); static void finish_up(void) { vtrec_printf("\e[?7h\e[?4h"); vtrec_commit(); ttyrec_w_close(rec); EVLOG("*** THE END ***\n"); reap_streams(); } static VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { if (vtrec_reent) return; vtrec_reent=1; vtrec_dump(0); vtrec_reent=0; } static BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: return 1; case CTRL_CLOSE_EVENT: case CTRL_SHUTDOWN_EVENT: finish_up(); exit(0); return 1; case CTRL_LOGOFF_EVENT: default: return 0; } } static int check_console(void) { CONSOLE_SCREEN_BUFFER_INFO cbi; if (!(con=GetStdHandle(STD_OUTPUT_HANDLE)) || con==INVALID_HANDLE_VALUE) return 0; if (!GetConsoleScreenBufferInfo(con, &cbi)) return 0; printf("termrec version " PACKAGE_VERSION "\n" "Recording through %s to %s.\n" "Console size: %dx%d.\n", format, record_name, cbi.srWindow.Right-cbi.srWindow.Left+1, cbi.srWindow.Bottom-cbi.srWindow.Top+1); return 1; } static int create_console(void) { HANDLE fd; SECURITY_ATTRIBUTES sec; FreeConsole(); AllocConsole(); SetConsoleTitle("termrec"); sec.nLength=sizeof(SECURITY_ATTRIBUTES); sec.lpSecurityDescriptor=0; sec.bInheritHandle=1; fd=CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE, &sec, OPEN_EXISTING, 0, 0); if (fd==INVALID_HANDLE_VALUE) return 0; SetStdHandle(STD_INPUT_HANDLE, fd); fd=CreateFile("CONOUT$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE, &sec, OPEN_EXISTING, 0, 0); if (fd==INVALID_HANDLE_VALUE) return 0; SetStdHandle(STD_OUTPUT_HANDLE, fd); SetStdHandle(STD_ERROR_HANDLE, fd); return 1; } static void set_event_hook(void) { typedef HWINEVENTHOOK (WINAPI* SWEH)(UINT,UINT,HMODULE,WINEVENTPROC,DWORD,DWORD,UINT); HMODULE dll; SWEH sweh; if ((dll=LoadLibrary("user32"))) if ((sweh=(SWEH)GetProcAddress(dll,"SetWinEventHook"))) sweh(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, 0, (WINEVENTPROC)WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); /* If the above fails -- we just fall back to the polling scheme. * Actually, we start polling by default, and just disable it when * we get the first event. */ } static void spawn_process(void) { STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(si)); si.cb=sizeof(STARTUPINFO); memset(&pi, 0, sizeof(pi)); if (!command) command=getenv("COMSPEC"); if (!command) { fprintf(stderr, "No command given and no COMSPEC set, aborting.\n"); finish_up(); exit(1); } printf("Trying to spawn [%s]\n", command); // CAVEAT: if this ever uses CreateProcessW, that function does modify its // "command" argument. CreateProcessA does not. if (!CreateProcess(0, (char*)command, 0, 0, 0, CREATE_DEFAULT_ERROR_MODE, 0, 0, &si, &pi)) { fprintf(stderr, "Can't spawn child process.\n"); finish_up(); exit(1); } proc=pi.dwProcessId; proch=pi.hProcess; } int main(int argc, char **argv) { struct timeval tv; int record_f; #ifdef EVDEBUG evlog=fopen("evlog", "w"); #endif get_rec_parms(argc, argv); record_f=open_out(&record_name, format_ext, append); if (record_f==-1) { fprintf(stderr, "Can't open %s\n", record_name); return 1; } utf8=1; if (!check_console()) if (!create_console() || !check_console()) { die("Not on a console. My attempts failed"); return 1; } vtrec_init(); proc=0; proch=0; timer=(UINT_PTR)(-1); vtrec_reent=0; vtrec_dirty=0; gettimeofday(&tv, 0); rec=ttyrec_w_open(record_f, format, record_name, &tv); vtrec_dump(1); SetConsoleCtrlHandler(CtrlHandler,1); set_event_hook(); spawn_process(); vtrec_dump(0); if (timer==(UINT_PTR)(-1)) { if (!(timer=SetTimer(0,0,20 /* poll 50 times per second */,TimerProc))) { fprintf(stderr, "Failed to set up pollination.\n"); finish_up(); return 1; } } message_loop(&proch, 1); finish_up(); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������