summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING339
-rw-r--r--Makefile21
-rw-r--r--alloc.c37
-rw-r--r--ascii.c106
-rw-r--r--comb.c196
-rw-r--r--dblbuf.c220
-rw-r--r--dblbuf.h29
-rw-r--r--fbcon.c219
-rw-r--r--main.c96
-rw-r--r--refresh.c45
-rw-r--r--term.c501
-rw-r--r--tty.c63
-rw-r--r--uuterm.h100
13 files changed, 1972 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6dd74b2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+# uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only
+
+
+SRCS = main.c term.c comb.c tty.c alloc.c refresh.c ascii.c fbcon.c dblbuf.c
+OBJS = $(SRCS:.c=.o)
+
+CFLAGS = -O2 -s #-g
+LDFLAGS = -s
+
+-include config.mak
+
+all: uuterm
+
+$(OBJS): uuterm.h
+
+uuterm: $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS)
+
+clean:
+ rm -f $(OBJS) uuterm
+
diff --git a/alloc.c b/alloc.c
new file mode 100644
index 0000000..34058b3
--- /dev/null
+++ b/alloc.c
@@ -0,0 +1,37 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#include "uuterm.h"
+
+void *uuterm_alloc(size_t len)
+{
+#ifdef MAP_ANONYMOUS
+ size_t *mem = mmap(0, len+sizeof(size_t),
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ if (mem == MAP_FAILED) return 0;
+ *mem++ = len;
+ return mem;
+#else
+ return malloc(len);
+#endif
+}
+
+void uuterm_free(void *buf)
+{
+#ifdef MAP_ANONYMOUS
+ size_t *mem = buf;
+ mem--;
+ munmap(mem, *mem);
+#else
+ free(buf);
+#endif
+}
+
+void *uuterm_buf_alloc(int w, int h)
+{
+ /* FIXME: do we care about overflows? */
+ return uuterm_alloc(UU_BUF_SIZE(w, h));
+}
diff --git a/ascii.c b/ascii.c
new file mode 100644
index 0000000..8082e4e
--- /dev/null
+++ b/ascii.c
@@ -0,0 +1,106 @@
+/* Standard ASCII console font. If you want to pretend there's a copyright
+ * on this you'll just be making a fool of yourself. Public domain. */
+
+static const unsigned char ascii[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3c,0x3c,0x3c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0x6c,0x6c,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00,
+0x00,0x10,0x10,0x7c,0xd6,0xd0,0xd0,0x7c,0x16,0x16,0xd6,0x7c,0x10,0x10,0x00,0x00,
+0x00,0x00,0x00,0x00,0xc2,0xc6,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6c,0x6c,0x38,0x76,0xdc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0c,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x30,0x18,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x18,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0xc0,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xce,0xce,0xd6,0xd6,0xe6,0xe6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc6,0xfe,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0x06,0x06,0x3c,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0c,0x1c,0x3c,0x6c,0xcc,0xfe,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xfc,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x60,0xc0,0xc0,0xfc,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfe,0xc6,0x06,0x06,0x0c,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7c,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x06,0x0c,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x60,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xc6,0x0c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xde,0xde,0xde,0xdc,0xc0,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x66,0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00,
+0x00,0x00,0xf8,0x6c,0x66,0x66,0x66,0x66,0x66,0x66,0x6c,0xf8,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xde,0xc6,0xc6,0x66,0x3a,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0xe6,0x66,0x66,0x6c,0x78,0x78,0x6c,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+0x00,0x00,0xf0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc6,0xee,0xfe,0xfe,0xd6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xd6,0xde,0x7c,0x0c,0x0e,0x00,0x00,
+0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x6c,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7c,0xc6,0xc6,0x64,0x38,0x0c,0x06,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7e,0x7e,0x5a,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x6c,0x38,0x10,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xd6,0xd6,0xd6,0xfe,0xee,0x6c,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc6,0xc6,0x6c,0x7c,0x38,0x38,0x7c,0x6c,0xc6,0xc6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x66,0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfe,0xc6,0x86,0x0c,0x18,0x30,0x60,0xc2,0xc6,0xfe,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3c,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xc0,0x60,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00,0x00,0x00,0x00,
+0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,
+0x00,0x30,0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0xe0,0x60,0x60,0x78,0x6c,0x66,0x66,0x66,0x66,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc0,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1c,0x0c,0x0c,0x3c,0x6c,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0xcc,0x78,0x00,
+0x00,0x00,0xe0,0x60,0x60,0x6c,0x76,0x66,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x06,0x06,0x00,0x0e,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00,
+0x00,0x00,0xe0,0x60,0x60,0x66,0x6c,0x78,0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xec,0xfe,0xd6,0xd6,0xd6,0xd6,0xc6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x1e,0x00,
+0x00,0x00,0x00,0x00,0x00,0xdc,0x76,0x66,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0x60,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x10,0x30,0x30,0xfc,0x30,0x30,0x30,0x30,0x36,0x1c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xd6,0xd6,0xd6,0xfe,0x6c,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xc6,0x6c,0x38,0x38,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00,
+0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
+const void *ascii_get_glyph(unsigned c)
+{
+ if (c - 32 < 95) return ascii + 16*(c-32);
+ else return ascii;
+}
diff --git a/comb.c b/comb.c
new file mode 100644
index 0000000..c1d6ea3
--- /dev/null
+++ b/comb.c
@@ -0,0 +1,196 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#define R(a,b) { (a), (b)-(a) }
+
+static const unsigned short common[][2] = {
+ R( 0x300, 0x341 ),
+ R( 0x346, 0x362 ),
+ R( 0x200B, 0x200F ),
+ R( 0x202A, 0x202E ),
+ R( 0x2060, 0x206F ),
+ R( 0x20D0, 0x20EA ),
+ { 0, 0 }
+};
+
+static const unsigned short latin[][2] = {
+ R( 0x363, 0x36F ),
+ { 0, 0 }
+};
+
+static const unsigned short greek[][2] = {
+ R( 0x342, 0x345 ),
+ { 0, 0 }
+};
+
+static const unsigned short cyrillic[][2] = {
+ R( 0x483, 0x489 ),
+ { 0, 0 }
+};
+
+static const unsigned short hebrew[][2] = {
+ R( 0x591, 0x5C4 ),
+ { 0, 0 }
+};
+
+static const unsigned short arabic[][2] = {
+ R( 0x600, 0x603 ),
+ R( 0x610, 0x615 ),
+ R( 0x64B, 0x658 ),
+ R( 0x670, 0x670 ),
+ R( 0x6D6, 0x6ED ),
+ { 0, 0 }
+};
+
+static const unsigned short syriac[][2] = {
+ R( 0x70F, 0x711 ),
+ R( 0x730, 0x74A ),
+ { 0, 0 }
+};
+
+static const unsigned short thaana[][2] = {
+ R( 0x7A6, 0x7B0 ),
+ { 0, 0 }
+};
+
+static const unsigned short devanagari[][2] = {
+ R( 0x901, 0x902 ),
+ R( 0x93C, 0x963 ),
+ { 0, 0 }
+};
+
+static const unsigned short bengali[][2] = {
+ R( 0x981, 0x981 ),
+ R( 0x9BC, 0x9E3 ),
+ { 0, 0 }
+};
+
+static const unsigned short gurmukhi[][2] = {
+ R( 0xA01, 0xA02 ),
+ R( 0xA3C, 0xA4D ),
+ R( 0xA70, 0xA71 ),
+ { 0, 0 }
+};
+
+static const unsigned short gujarati[][2] = {
+ R( 0xA81, 0xA82 ),
+ R( 0xABC, 0xAE3 ),
+ { 0, 0 }
+};
+
+static const unsigned short oriya[][2] = {
+ R( 0xB01, 0xB01 ),
+ R( 0xB3C, 0xB4D ),
+ R( 0xB56, 0xB56 ),
+ { 0, 0 }
+};
+
+static const unsigned short tamil[][2] = {
+ R( 0xB82, 0xB82 ),
+ R( 0xBC0, 0xBCD ),
+ { 0, 0 }
+};
+
+static const unsigned short telugu[][2] = {
+ R( 0xC3E, 0xC56 ),
+ { 0, 0 }
+};
+
+static const unsigned short kannada[][2] = {
+ R( 0xCBC, 0xCCD ),
+ { 0, 0 }
+};
+
+static const unsigned short malayalam[][2] = {
+ R( 0xD41, 0xD4D ),
+ { 0, 0 }
+};
+
+static const unsigned short sinhala[][2] = {
+ R( 0xDCA, 0xDD6 ),
+ { 0, 0 }
+};
+
+static const unsigned short thai[][2] = {
+ R( 0xE31, 0xE3A ),
+ R( 0xE47, 0xE4E ),
+ { 0, 0 }
+};
+
+static const unsigned short lao[][2] = {
+ R( 0xEB1, 0xECD ),
+ { 0, 0 }
+};
+
+static const unsigned short tibetan[][2] = {
+ R( 0xF18, 0xF19 ),
+ R( 0xF35, 0xF35 ),
+ R( 0xF39, 0xF39 ),
+ R( 0xF71, 0xF84 ),
+ R( 0xF90, 0xFBC ),
+ R( 0xFC6, 0xFC6 ),
+ { 0, 0 }
+};
+
+static const unsigned short burmese[][2] = {
+ R( 0x102D, 0x1039 ),
+ R( 0x1058, 0x1059 ),
+ { 0, 0 }
+};
+
+static const unsigned short misc_scripts[][2] = {
+ R( 0x1732, 0x1734 ), /* hanunoo */
+ R( 0x1752, 0x1753 ), /* buhid */
+ R( 0x17B4, 0x17BD ), /* khmer */
+ R( 0x17C6, 0x17D3 ),
+ R( 0x17DD, 0x17DD ),
+ R( 0x18A9, 0x18A9 ), /* mongolian */
+ R( 0x1920, 0x193B ), /* limbu (can be broken down more) */
+ { 0, 0 }
+};
+
+#undef R
+#define R(a,b,s) { (a), (b)-(a), (s) }
+
+static const struct {
+ unsigned a, l;
+ const unsigned short (*r)[2];
+} scripts[] = {
+ R( 0x400, 0x52F, cyrillic ),
+ R( 0x590, 0x5FF, hebrew ),
+ R( 0x600, 0x6FF, arabic ),
+ R( 0x700, 0x74F, syriac ),
+ R( 0x780, 0x7B1, thaana ),
+ R( 0x900, 0x97F, devanagari ),
+ R( 0x980, 0x9FF, bengali ),
+ R( 0xA00, 0xA7F, gurmukhi ),
+ R( 0xA80, 0xAFF, gujarati ),
+ R( 0xB00, 0xB7F, oriya ),
+ R( 0xB80, 0xBFF, tamil ),
+ R( 0xC00, 0xC7F, telugu ),
+ R( 0xC80, 0xCFF, kannada ),
+ R( 0xD00, 0xD7F, malayalam ),
+ R( 0xD80, 0xDFF, sinhala ),
+ R( 0xF00, 0xFFF, tibetan ),
+ R( 0x1000, 0x108F, burmese ),
+ R( 0x1720, 0x19FF, misc_scripts ),
+ R( 0x1D2B, 0x1D2B, cyrillic ),
+ R( 0x0000, 0x10FFFF, common ),
+ { }
+};
+
+#undef R
+
+int uu_combine_involution(unsigned b, unsigned c)
+{
+ int i;
+ unsigned code = 1;
+ const unsigned short (*r)[2];
+ for (i=0; scripts[i].l; i++)
+ if (b - scripts[i].a <= scripts[i].l)
+ for (r = scripts[i].r; r[0][0]; code += r++[0][1])
+ if (c - r[0][0] <= r[0][1])
+ return c - r[0][0] + code;
+ else if (c - code <= r[0][1])
+ return c + r[0][0] - code;
+ return 0;
+}
diff --git a/dblbuf.c b/dblbuf.c
new file mode 100644
index 0000000..ad70576
--- /dev/null
+++ b/dblbuf.c
@@ -0,0 +1,220 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include "uuterm.h"
+#include "dblbuf.h"
+
+#if 0
+static void blitline8_crap(unsigned char *dest, unsigned char *src, unsigned char *colors, int w, int cw)
+{
+ int cs = (cw+7)>>3;
+ int skip = (-cw)&7;
+ int x, i, j;
+ signed char b;
+ for (x=0; x<w; x++) {
+ j=skip;
+ b=*src++<<skip;
+ for (i=0; ; i++) {
+ for (; j<8; j++, b<<=1)
+ //*dest++ = 7 & (b>>7);
+ *dest++ = (*colors&15&(b>>7)) | (*colors>>4&~(b>>7));
+ if (i >= cs) break;
+ b=*src++;
+ j=0;
+ }
+ colors++;
+ }
+}
+
+static void blitline8_2(unsigned char *dest, unsigned char *src, unsigned char *colors, int w, int cw)
+{
+ int cs = (cw+7)>>3;
+ int skip = (-cw)&7;
+ int x, i, j;
+ signed char b;
+ unsigned char fg, bg;
+
+ for (x=0; x<w; x++) {
+ j=skip;
+ b=*src++<<skip;
+ fg = *colors & 15;
+ bg = *colors++ >> 4;
+ for (i=0; ; i++) {
+ for (; j<8; j++, b<<=1)
+ *dest++ = (fg&(b>>7)) | (bg&~(b>>7));
+ if (i >= cs) break;
+ b=*src++;
+ j=0;
+ }
+ }
+}
+#endif
+
+#ifdef HAVE_I386_ASM
+
+#define BLIT_PIXEL_8 \
+ "add %%al,%%al \n\t" \
+ "sbb %%dl,%%dl \n\t" \
+ "and %%bh,%%dl \n\t" \
+ "mov %%bl,%%dh \n\t" \
+ "add %%dl,%%dh \n\t" \
+ "mov %%dh,(%%edi) \n\t" \
+ "inc %%edi \n\t" \
+
+static void blitline8(unsigned char *dest, unsigned char *src, unsigned char *colors, int w, int cw)
+{
+ __asm__ __volatile__(
+ "push %%ebp \n\t"
+ "mov %%ebx, %%ebp \n\t"
+ "\n1: \n\t"
+ "mov (%%esi), %%al \n\t"
+ "inc %%esi \n\t"
+ "mov (%%ecx), %%bl \n\t"
+ "inc %%ecx \n\t"
+ "mov %%bl, %%bh \n\t"
+ "shr $4, %%bl \n\t"
+ "and $15, %%bh \n\t"
+ "sub %%bl, %%bh \n\t"
+ BLIT_PIXEL_8
+ BLIT_PIXEL_8
+ BLIT_PIXEL_8
+ BLIT_PIXEL_8
+ BLIT_PIXEL_8
+ BLIT_PIXEL_8
+ BLIT_PIXEL_8
+ BLIT_PIXEL_8
+ "dec %%ebp \n\t"
+ "jnz 1b \n\t"
+ "pop %%ebp \n\t"
+ : "=S"(src), "=D"(dest), "=c"(colors), "=b"(w)
+ : "S"(src), "D"(dest), "c"(colors), "b"(w)
+ : "memory" );
+}
+#else
+static void blitline8(unsigned char *dest, unsigned char *src, unsigned char *colors, int w, int cw)
+{
+ int x;
+ unsigned char b;
+ unsigned char c[2];
+
+ for (x=0; x<w; x++) {
+ b=*src++;
+ c[1] = *colors & 15;
+ c[0] = *colors++ >> 4;
+ dest[0] = c[b>>7]; b<<=1;
+ dest[1] = c[b>>7]; b<<=1;
+ dest[2] = c[b>>7]; b<<=1;
+ dest[3] = c[b>>7]; b<<=1;
+ dest[4] = c[b>>7]; b<<=1;
+ dest[5] = c[b>>7]; b<<=1;
+ dest[6] = c[b>>7]; b<<=1;
+ dest[7] = c[b>>7]; b<<=1;
+ dest += 8;
+ }
+}
+#endif
+
+static void blit_slice(struct uudisp *d, int idx, int x1, int x2)
+{
+ struct dblbuf *b = (void *)&d->priv;
+ int cs = (d->cell_w+7)>>3;
+ int y = b->slices[idx].y;
+ int w = x2 - x1 + 1;
+ int s = d->w * cs;
+ int i;
+
+ unsigned char *dest = b->vidmem + y*b->row_stride
+ + x1*d->cell_w*b->bytes_per_pixel;
+ unsigned char *src = b->slices[idx].bitmap + x1*cs;
+ unsigned char *colors = b->slices[idx].colors + x1;
+
+ for (i=0; i<d->cell_h; i++) {
+ blitline8(dest, src, colors, w, d->cell_w);
+ dest += b->line_stride;
+ src += s;
+ }
+}
+
+void clear_cells(struct uudisp *d, int idx, int x1, int x2)
+{
+ struct dblbuf *b = (void *)&d->priv;
+ int i;
+ int cs = d->cell_w+7 >> 3;
+ int cnt = (x2 - x1 + 1) * cs;
+ int stride = d->w * cs;
+ unsigned char *dest = b->slices[idx].bitmap + x1 * cs;
+
+ memset(b->slices[idx].colors + x1, 0, x2-x1+1);
+ for (i=d->cell_h; i; i--, dest += stride)
+ memset(dest, 0, cnt);
+}
+
+void uudisp_draw_glyph(struct uudisp *d, int idx, int x, const void *glyph, int color)
+{
+ struct dblbuf *b = (void *)&d->priv;
+ int i;
+ int cs = d->cell_w+7 >> 3;
+ int stride = d->w * cs;
+ unsigned char *src = (void *)glyph;
+ unsigned char *dest = b->slices[idx].bitmap + cs * x;
+
+ b->slices[idx].colors[x] = color;
+ for (i=d->cell_h; i; i--, dest += stride)
+ *dest |= *src++;
+}
+
+void uudisp_refresh(struct uudisp *d, struct uuterm *t)
+{
+ struct dblbuf *b = (void *)&d->priv;
+ int h = t->h < d->h ? t->h : d->h;
+ int y;
+
+ /* Clean up cursor first.. */
+ blit_slice(d, t->rows[b->curs_y]->idx, b->curs_x, b->curs_x);
+ //printf("--- %d\r\n", b->slices[t->rows[b->curs_y]->idx].y);
+
+ for (y=0; y<h; y++) {
+ int idx = t->rows[y]->idx;
+ int x1 = t->rows[y]->x1;
+ int x2 = t->rows[y]->x2;
+ if (x2 >= x1) {
+ clear_cells(d, idx, x1, x2);
+ uuterm_refresh_row(d, t->rows[y], x1, x2);
+ t->rows[y]->x1 = t->w;
+ t->rows[y]->x2 = -1;
+ }
+ if (b->slices[idx].y != y) {
+ b->slices[idx].y = y;
+ x1 = 0;
+ x2 = d->w-1;
+ } else if (x2 < x1) continue;
+ blit_slice(d, idx, x1, x2);
+ }
+
+ if (d->blink & 1) {
+ int idx = t->rows[t->y]->idx;
+ b->slices[idx].colors[t->x] ^= 0xff;
+ blit_slice(d, idx, t->x, t->x);
+ b->slices[idx].colors[t->x] ^= 0xff;
+ }
+ b->curs_x = t->x;
+ b->curs_y = t->y;
+ //printf("+++ %d\r\n", b->slices[t->rows[b->curs_y]->idx].y);
+}
+
+struct slice *dblbuf_setup_buf(int w, int h, int cs, int ch, unsigned char *mem)
+{
+ struct slice *slices = (void *)mem;
+ int i;
+
+ mem += sizeof(slices[0]) * h;
+
+ for (i=0; i<h; i++, mem += w) {
+ slices[i].y = -1;
+ slices[i].colors = mem;
+ }
+ w *= cs * ch;
+ for (i=0; i<h; i++, mem += w)
+ slices[i].bitmap = mem;
+
+ return slices;
+}
diff --git a/dblbuf.h b/dblbuf.h
new file mode 100644
index 0000000..aa2dc47
--- /dev/null
+++ b/dblbuf.h
@@ -0,0 +1,29 @@
+
+
+
+struct slice
+{
+ int y;
+ unsigned char *colors;
+ unsigned char *bitmap;
+};
+
+struct dblbuf
+{
+ struct slice *slices;
+ unsigned cs, ch;
+
+ unsigned curs_x;
+ unsigned curs_y;
+
+ unsigned char *vidmem;
+ unsigned row_stride;
+ unsigned line_stride;
+ unsigned bytes_per_pixel;
+};
+
+#define SLICE_BUF_SIZE(w, h, cs, ch) \
+ ( (h)*(sizeof(struct slice) + (w)*(1 + (cs)*(ch))) )
+
+struct slice *dblbuf_setup_buf(int, int, int, int, unsigned char *);
+
diff --git a/fbcon.c b/fbcon.c
new file mode 100644
index 0000000..6d6bfa9
--- /dev/null
+++ b/fbcon.c
@@ -0,0 +1,219 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <sys/kd.h>
+#include <linux/fb.h>
+
+#include "uuterm.h"
+#include "dblbuf.h"
+
+struct priv
+{
+ /* common to all double buffered fb targets */
+ struct dblbuf b;
+ /* fbcon-specific */
+ int fb;
+ int kb;
+ int ms;
+ struct termios tio;
+ int kbmode;
+ int mod;
+ int xres, yres;
+ void *buf_mem;
+};
+
+static int get_fb_size(struct uudisp *d)
+{
+ struct priv *p = (struct priv *)&d->priv;
+ struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
+
+ if (ioctl(p->fb, FBIOGET_FSCREENINFO, &fix) < 0
+ || ioctl(p->fb, FBIOGET_VSCREENINFO, &var) < 0
+ || fix.type != FB_TYPE_PACKED_PIXELS)
+ return -1;
+
+ p->b.bytes_per_pixel = (var.bits_per_pixel+7)>>3;
+ p->b.line_stride = fix.line_length;
+ p->b.row_stride = fix.line_length * d->cell_h;
+
+ if (var.xres != p->xres || var.yres != p->yres) {
+ int w = var.xres / d->cell_w;
+ int h = var.yres / d->cell_h;
+ void *buf = uuterm_alloc(SLICE_BUF_SIZE(w, h, (d->cell_w+7)/8, d->cell_h));
+ if (!buf) return -1;
+ if (p->buf_mem) uuterm_free(p->buf_mem);
+ p->buf_mem = buf;
+ p->b.slices = dblbuf_setup_buf(w, h, (d->cell_w+7)/8, d->cell_h, buf);
+ p->xres = var.xres;
+ p->yres = var.yres;
+ d->w = w;
+ d->h = h;
+ }
+
+ return 0;
+}
+
+static void dummy(int x)
+{
+}
+
+static int mapkey(unsigned *m, unsigned k, unsigned char *s)
+{
+#define LSHIFT "\200"
+#define LCTRL "\201"
+#define LALT "\202"
+#define RSHIFT "\203"
+#define RCTRL "\204"
+#define RALT "\205"
+#define CAPSLK "\206"
+#define NUMLK "\207"
+#define SCRLK "\210"
+#define WTF "\377"
+ static const unsigned char keymap[] =
+ "\0\033" "1234567890-=\177"
+ "\t" "qwertyuiop[]\r"
+ LCTRL "asdfghjkl;'`"
+ LSHIFT "\\zxcvbnm,./" RSHIFT "*"
+ LALT " " CAPSLK
+ "\301\302\303\304\305\306\307\310\311\312"
+ NUMLK SCRLK;
+ static const unsigned char keymap_sh[] =
+ "\0\033" "!@#$%^&*()_+\177"
+ "\t" "QWERTYUIOP{}\r"
+ LCTRL "ASDFGHJKL:\"~"
+ LSHIFT "|ZXCVBNM<>?" RSHIFT "*"
+ LALT " " CAPSLK
+ "\301\302\303\304\305\306\307\310\311\312"
+ NUMLK SCRLK;
+ //71...
+ static const unsigned char keypad[] = "789-456+1230.";
+ //64..95 useless
+ //96...
+ static const unsigned char keypad2[] = "\r" RCTRL WTF "/" RALT WTF;
+ //102...
+ static const unsigned char cursblk[] = "1A5DC4B623";
+
+ unsigned c;
+ unsigned rel = k & 0x80;
+ int i = 0;
+
+ k &= 0x7f;
+ if (k < sizeof(keymap)) {
+ c = keymap[k];
+ if (c-0200 < 6) {
+ c &= 15;
+ if (rel) *m &= ~(1<<c);
+ else *m |= 1<<c;
+ return 0;
+ }
+ if (rel || c > 0x80) return 0;
+ if (*m & 1) c = keymap_sh[k];
+ if (*m & 2) {
+ c &= 0x1f;
+ //if (c >= '@') c &= 0x1f;
+ //else if (keymap_sh[k] >= '@') c = keymap_sh[k] & 0x1f;
+ }
+ if (*m & 4) {
+ s[i++] = '\033';
+ }
+ s[i++] = c;
+ return i;
+ }
+ if (k-102 < sizeof(cursblk)) {
+ if (rel) return 0;
+ s[i++] = '\033';
+ s[i++] = '[';
+ c = cursblk[k-102];
+ s[i++] = c;
+ if (c < 'A') s[i++] = '~';
+ return i;
+ }
+ return 0;
+}
+
+int uudisp_open(struct uudisp *d)
+{
+ struct priv *p = (void *)&d->priv;
+ struct fb_fix_screeninfo fix;
+ struct termios tio;
+
+ p->fb = p->kb = p->ms = -1;
+ p->b.vidmem = MAP_FAILED;
+
+ if ((p->fb = open("/dev/fb0", O_RDWR)) < 0 || get_fb_size(d) < 0
+ || ioctl(p->fb, FBIOGET_FSCREENINFO, &fix) < 0)
+ goto error;
+
+ p->b.vidmem = mmap(0, fix.smem_len, PROT_WRITE|PROT_READ, MAP_SHARED, p->fb, 0);
+ if (p->b.vidmem == MAP_FAILED)
+ goto error;
+
+ if ((p->kb = open("/dev/tty", O_RDONLY)) < 0
+ || ioctl(p->kb, KDGKBMODE, &p->kbmode) < 0
+ || ioctl(p->kb, KDSKBMODE, K_MEDIUMRAW) < 0)
+ goto error;
+
+ /* If the above succeeds, the below cannot fail */
+ ioctl(p->kb, KDSETMODE, KD_GRAPHICS);
+ tcgetattr(p->kb, &p->tio);
+ tio = p->tio;
+ tio.c_cflag = B38400 | CS8 | CLOCAL | CREAD;
+ tio.c_iflag = 0;
+ tio.c_oflag = 0;
+ tio.c_lflag = 0;
+ tcsetattr(p->kb, TCSANOW, &tio);
+
+ signal(SIGWINCH, dummy); /* just to interrupt select! */
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+
+ return 0;
+error:
+ if (p->b.vidmem != MAP_FAILED) munmap(p->b.vidmem, fix.smem_len);
+ close(p->fb);
+ close(p->kb);
+ close(p->ms);
+ return -1;
+}
+
+int uudisp_fd_set(struct uudisp *d, int tty, void *fds)
+{
+ struct priv *p = (struct priv *)&d->priv;
+ if (p->ms >= 0) FD_SET(p->ms, (fd_set *)fds);
+ FD_SET(p->kb, (fd_set *)fds);
+ return p->kb > tty ? p->kb+1 : tty+1;
+}
+
+void uudisp_next_event(struct uudisp *d, void *fds)
+{
+ struct priv *p = (struct priv *)&d->priv;
+ unsigned char b;
+
+ get_fb_size(d);
+
+ d->inlen = 0;
+ d->intext = d->inbuf;
+
+ if (FD_ISSET(p->kb, (fd_set *)fds) && read(p->kb, &b, 1) == 1)
+ d->inlen = mapkey(&p->mod, b, d->intext);
+}
+
+void uudisp_close(struct uudisp *d)
+{
+ struct priv *p = (struct priv *)&d->priv;
+ tcsetattr(p->kb, TCSANOW, &p->tio);
+ ioctl(p->kb, KDSKBMODE, p->kbmode);
+ ioctl(p->kb, KDSETMODE, KD_TEXT);
+ close(p->fb);
+ close(p->kb);
+ close(p->ms);
+}
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..8a8fd31
--- /dev/null
+++ b/main.c
@@ -0,0 +1,96 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <locale.h>
+#include <sys/select.h>
+#include <sys/time.h> /* for broken systems */
+
+#include "uuterm.h"
+
+int main(int argc, char *argv[])
+{
+ struct uuterm t = { };
+ struct uudisp d = { };
+ int tty, max;
+ int i, l;
+ unsigned char b[128];
+ fd_set fds;
+ struct timeval tv;
+ void *buf;
+
+ setlocale(LC_CTYPE, "");
+
+ d.cell_w = 8;
+ d.cell_h = 16;
+
+ if (uudisp_open(&d) < 0)
+ return 1;
+
+ for (i=1; i<argc; i++)
+ argv[i-1] = argv[i];
+ argv[i-1] = NULL;
+
+ if ((tty = uutty_open(argc > 1 ? argv : NULL, d.w, d.h)) < 0)
+ return 1;
+
+ signal(SIGHUP, SIG_IGN);
+
+ if (!(buf = uuterm_buf_alloc(d.w, d.h))) {
+ uudisp_close(&d);
+ return 1;
+ }
+ uuterm_replace_buffer(&t, d.w, d.h, buf);
+ uuterm_reset(&t);
+
+ for (;;) {
+ /* Setup fd_set containing fd's used by display and our tty */
+ FD_ZERO(&fds);
+ FD_SET(tty, &fds);
+ max = uudisp_fd_set(&d, tty, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
+ if (select(max, &fds, NULL, NULL, &tv) == 0)
+ d.blink++;
+
+ /* Process input from the tty, up to buffer size */
+ if (FD_ISSET(tty, &fds)) {
+ if ((l = read(tty, b, sizeof b)) <= 0)
+ break;
+ for (i=0; i<l; i++) {
+ uuterm_stuff_byte(&t, b[i]);
+ if (t.reslen) write(tty, t.res, t.reslen);
+ }
+ }
+
+ /* Look for events from the display */
+ uudisp_next_event(&d, &fds);
+
+ if (d.w != t.w || d.h != t.h) {
+ void *newbuf = uuterm_buf_alloc(d.w, d.h);
+ if (newbuf) {
+ uuterm_replace_buffer(&t, d.w, d.h, newbuf);
+ uuterm_free(buf);
+ buf = newbuf;
+ uutty_resize(tty, d.w, d.h);
+ }
+ }
+ if (d.inlen) {
+ write(tty, d.intext, d.inlen);
+ d.blink = 1;
+ }
+
+ /* If no more input is pending, refresh display */
+ FD_ZERO(&fds);
+ FD_SET(tty, &fds);
+ tv.tv_sec = tv.tv_usec = 0;
+ select(max, &fds, NULL, NULL, &tv);
+ if (!FD_ISSET(tty, &fds))
+ uudisp_refresh(&d, &t);
+ }
+
+ uudisp_close(&d);
+
+ return 0;
+}
diff --git a/refresh.c b/refresh.c
new file mode 100644
index 0000000..b1766d2
--- /dev/null
+++ b/refresh.c
@@ -0,0 +1,45 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include "uuterm.h"
+
+static void extract_cell(unsigned *ch, struct uucell *cell)
+{
+ int i;
+ unsigned b;
+ for (b=i=0; i<3; i++) b |= cell->c[i] << 8*i;
+ ch[0] = b;
+ ch -= 2;
+ for (; i<sizeof(cell->c)+1 && cell->c[i]; i++)
+ ch[i] = uu_combine_involution(b, cell->c[i]);
+ if (cell->a & UU_ATTR_UL)
+ ch[i++] = '_'; //0x0332;
+ for (; i<sizeof(cell->c)+1; i++)
+ ch[i] = 0;
+}
+
+const void *ascii_get_glyph(unsigned);
+
+static const void *lookup_glyph(unsigned *this, int i, unsigned *prev, unsigned *next)
+{
+ return ascii_get_glyph(this[i]);
+}
+
+void uuterm_refresh_row(struct uudisp *d, struct uurow *row, int x1, int x2)
+{
+ unsigned ch[4][sizeof(row->cells[0].c)+1];
+ int x, i;
+
+ if (x1) extract_cell(ch[(x1-1)&3], &row->cells[x1-1]);
+ else memset(ch[3], 0, sizeof(ch[3]));
+ extract_cell(ch[x1&3], &row->cells[x1]);
+
+ for (x=x1; x<=x2; x++) {
+ extract_cell(ch[(x+1)&3], &row->cells[x+1]);
+ for (i=0; i<sizeof(ch[0]) && ch[x&3][i]; i++) {
+ const void *glyph = lookup_glyph(ch[x&3], i, ch[(x+3)&3], ch[(x+1)&3]);
+ uudisp_draw_glyph(d, row->idx, x, glyph, row->cells[x].a);
+ }
+ }
+}
+
+
diff --git a/term.c b/term.c
new file mode 100644
index 0000000..cf57560
--- /dev/null
+++ b/term.c
@@ -0,0 +1,501 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include <wchar.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include "uuterm.h"
+
+#define isdigit(x) ((unsigned)x-'0' < 10)
+
+static void process_char(struct uuterm *t, unsigned c);
+
+static void scroll(struct uuterm *t, int y1, int y2, int rev)
+{
+ int fwd = 1-rev;
+ struct uurow *new = t->rows[(y1&-fwd)|(y2&-rev)];
+ memset(new->cells, 0, t->w * sizeof(struct uucell));
+ new->x1 = 0;
+ new->x2 = t->w-1;
+ memmove(&t->rows[y1+rev], &t->rows[y1+fwd], (y2-y1) * sizeof(struct uurow *));
+ t->rows[(y2&-fwd)|(y1&-rev)] = new;
+}
+
+static void dirty(struct uuterm *t, int y, int x1, int len)
+{
+ int x2 = x1 + len - 1;
+ struct uurow *r = t->rows[y];
+ //r->x1 += (x1 - r->x1) & (x1 - r->x1)>>8*sizeof(int)-1;
+ //r->x2 += (x2 - r->x2) & (r->x2 - x2)>>8*sizeof(int)-1;
+ if (x1 < r->x1) r->x1 = x1;
+ if (x2 > r->x2) r->x2 = x2;
+}
+
+static void bell(struct uuterm *t)
+{
+}
+
+static void erase_line(struct uuterm *t, int dir)
+{
+ int start[3] = { t->x, 0, 0 };
+ int len[3] = { t->w-t->x, t->x+1, t->w };
+ if ((unsigned)dir > 2) return;
+ memset(t->rows[t->y]->cells+start[dir], 0, len[dir] * sizeof(struct uucell));
+ dirty(t, t->y, start[dir], len[dir]);
+}
+
+static void erase_display(struct uuterm *t, int dir)
+{
+ int i;
+ int start[3] = { t->y+1, 0, 0 };
+ int stop[3] = { t->h, t->y, t->h };
+ if ((unsigned)dir > 2) return;
+ erase_line(t, dir);
+ for (i=start[dir]; i<stop[dir]; i++) {
+ memset(t->rows[i]->cells, 0, t->w * sizeof(struct uucell));
+ dirty(t, i, 0, t->w);
+ }
+}
+
+static void reset(struct uuterm *t)
+{
+ /* cheap trick */
+ memset(&t->reset, 0, sizeof *t - offsetof(struct uuterm, reset));
+ t->attr = 7;
+ t->sr_y2 = t->h - 1;
+ erase_display(t, 2);
+}
+
+static void ins_del_char(struct uuterm *t, unsigned n, int ins)
+{
+ int del = 1-ins;
+ struct uucell *base;
+ if (n >= t->w - t->x) {
+ erase_line(t, 0);
+ return;
+ }
+ base = t->rows[t->y]->cells + t->x;
+ memmove(base+(n&-ins), base+(n&-del), (t->w-t->x-n) * sizeof(struct uucell));
+ memset(base+((t->w-t->x-n)&-del), 0, n * sizeof(struct uucell));
+ dirty(t, t->y, t->x, t->w - t->x);
+}
+
+static void ins_del_lines(struct uuterm *t, int n, int ins)
+{
+ if ((unsigned)t->y - t->sr_y1 > t->sr_y2 - t->sr_y1) return;
+ while (n--) scroll(t, t->y, t->sr_y2, ins);
+}
+
+static void newline(struct uuterm *t)
+{
+ process_char(t, '\r');
+ process_char(t, '\n');
+}
+
+static int itoa(char *s, unsigned n)
+{
+ // FIXME!!
+ *s = '1';
+ return 1;
+}
+
+#define CSI '['
+#define OSC ']'
+#define IGNORE1 2
+#define ID_STRING "\033[?6c"
+#define OK_STRING "\033[0n"
+#define PRIVATE ((unsigned)-1)
+
+static void csi(struct uuterm *t, unsigned c)
+{
+ int i;
+ int ins=0;
+ if (c == '?') {
+ t->param[t->nparam] = PRIVATE;
+ if (++t->nparam != 16) return;
+ }
+ if (isdigit(c)) {
+ t->param[t->nparam] = 10*t->param[t->nparam] + c - '0';
+ return;
+ }
+ if (c == ';' && ++t->nparam != 16)
+ return;
+ t->esc = 0;
+ t->nparam++;
+ if (strchr("@ABCDEFGHLMPXaefr`", c) && !t->param[0])
+ t->param[0]++;
+ switch (c) {
+ case 'F':
+ process_char(t, '\r');
+ case 'A':
+ t->y -= t->param[0];
+ break;
+ case 'E':
+ process_char(t, '\r');
+ case 'e':
+ case 'B':
+ t->y += t->param[0];
+ break;
+ case 'a':
+ case 'C':
+ t->x += t->param[0];
+ break;
+ case 'D':
+ t->x -= t->param[0];
+ break;
+ case '`':
+ case 'G':
+ t->x = t->param[0]-1;
+ break;
+ case 'f':
+ case 'H':
+ if (!t->param[1]) t->param[1]++;
+ t->y = t->param[0]-1;
+ t->x = t->param[1]-1;
+ break;
+ case 'J':
+ erase_display(t, t->param[0]);
+ break;
+ case 'K':
+ erase_line(t, t->param[0]);
+ break;
+ case 'L':
+ ins=1;
+ case 'M':
+ ins_del_lines(t, t->param[0], ins);
+ break;
+ case '@':
+ ins=1;
+ case 'P':
+ ins_del_char(t, t->param[0], ins);
+ break;
+ case 'd':
+ t->y = t->param[0]-1;
+ break;
+ case 'h':
+ case 'l':
+ i = c=='h';
+ switch (t->param[0]) {
+ case PRIVATE:
+ switch(t->param[1]) {
+ case 1:
+ t->ckp = i;
+ break;
+ }
+ break;
+ case 4:
+ t->ins = i;
+ break;
+ }
+ break;
+ case 'm':
+ for (i=0; i<t->nparam; i++) {
+ static const unsigned char cmap[] = {
+ 0, 4, 2, 6, 1, 5, 3, 7
+ };
+ static const unsigned short attr[] = {
+ UU_ATTR_BOLD, UU_ATTR_DIM, 0,
+ UU_ATTR_UL, UU_ATTR_BLINK, 0,
+ UU_ATTR_REV
+ };
+ if (t->param[i] == 39) t->param[i] = 37;
+ if (t->param[i] == 49) t->param[i] = 40;
+ if (!t->param[i]) {
+ t->attr = 7;
+ } else if (t->param[i] < 8) {
+ t->attr |= attr[t->param[i]-1];
+ } else if (t->param[i]-21 < 7) {
+ t->attr &= ~attr[t->param[i]-21];
+ } else if (t->param[i]-30 < 8) {
+ t->attr &= ~UU_ATTR_FG;
+ t->attr |= cmap[(t->param[i] - 30)];
+ } else if (t->param[i]-40 < 8) {
+ t->attr &= ~UU_ATTR_BG;
+ t->attr |= cmap[(t->param[i] - 40)] << 4;
+ }
+ }
+ break;
+ case 'n':
+ switch (t->param[0]) {
+ case 5:
+ strcpy(t->res, OK_STRING);
+ t->reslen = sizeof(OK_STRING)-1;
+ break;
+ case 6:
+ t->res[0] = 033;
+ t->res[1] = '[';
+ i=2+itoa(t->res+2, t->x+1);
+ t->res[i++] = ';';
+ i+=itoa(t->res+i, t->y+1);
+ t->res[i++] = 'R';
+ t->reslen = i;
+ break;
+ }
+ break;
+ case 'r':
+ if (!t->param[1]) t->param[1] = t->h;
+ t->sr_y1 = t->param[0]-1;
+ t->sr_y2 = t->param[1]-1;
+ if (t->sr_y1 < 0) t->sr_y1 = 0;
+ if (t->sr_y2 >= t->h) t->sr_y2 = t->h-1;
+ if (t->sr_y1 > t->sr_y2) {
+ t->sr_y1 = 0;
+ t->sr_y2 = t->h-1;
+ }
+ break;
+ case 's':
+ t->save_x = t->x;
+ t->save_y = t->y;
+ break;
+ case 'u':
+ t->x = t->save_x;
+ t->y = t->save_y;
+ break;
+ case '[':
+ t->esc = IGNORE1;
+ break;
+ }
+ if ((unsigned)t->y >= t->h) {
+ if (t->y < 0) t->y = 0;
+ else t->y = t->h-1;
+ }
+ if ((unsigned)t->x >= t->w) {
+ if (t->x < 0) t->x = 0;
+ else t->x = t->w-1;
+ }
+}
+
+static void escape(struct uuterm *t, unsigned c)
+{
+ int rev=0;
+ if ((c & ~2) == 030) {
+ t->esc = 0;
+ return;
+ }
+ if (t->esc == CSI) {
+ csi(t, c);
+ return;
+ } else if (t->esc == OSC) {
+ //FIXME
+ t->esc = 0;
+ return;
+ } else if (t->esc == IGNORE1) {
+ t->esc = 0;
+ return;
+ }
+ t->esc = 0;
+ switch (c) {
+ case 'c':
+ reset(t);
+ break;
+ case 'D':
+ process_char(t, '\n');
+ break;
+ case 'E':
+ newline(t);
+ break;
+ case 'M':
+ if (t->y == t->sr_y1) scroll(t, t->sr_y1, t->sr_y2, 1);
+ else if (t->y > 0) t->y--;
+ break;
+ case 'Z':
+ strcpy(t->res, ID_STRING);
+ t->reslen = sizeof(ID_STRING)-1;
+ break;
+ case '7':
+ t->save_attr = t->attr;
+ t->save_x = t->x;
+ t->save_y = t->y;
+ break;
+ case '8':
+ t->attr = t->save_attr;
+ t->x = t->save_x;
+ t->y = t->save_y;
+ break;
+ case '[':
+ t->esc = CSI;
+ t->nparam = 0;
+ memset(t->param, 0, sizeof t->param);
+ break;
+ case '>':
+ t->kp = 0;
+ break;
+ case '=':
+ t->kp = 1;
+ break;
+ case ']':
+ t->esc = OSC;
+ t->nparam = 0;
+ memset(t->param, 0, sizeof t->param);
+ break;
+ }
+}
+
+static void setchar(struct uucell *cell, unsigned c, unsigned a)
+{
+ int i;
+ if (a & UU_ATTR_REV)
+ cell->a = (a & ~(0xff))
+ | ((a & 0x0f) << 4)
+ | ((a & 0xf0) >> 4);
+ else
+ cell->a = a;
+ for (i=0; i<sizeof(cell->c); i++, c>>=8)
+ cell->c[i] = c;
+}
+
+static void addchar(struct uucell *cell, unsigned c)
+{
+ int i;
+ unsigned b;
+
+ for (i=b=0; i<3; i++) b |= cell->c[i] << 8*i;
+ if (b == 0 || b == ' ' || b == 0xa0) {
+ setchar(cell, c, cell->a);
+ return;
+ }
+ if (!(c = uu_combine_involution(b, c))) return;
+ for (; i<sizeof(cell->c); i++) {
+ if (!cell->c[i]) {
+ cell->c[i] = c;
+ break;
+ }
+ }
+}
+
+static void process_char(struct uuterm *t, unsigned c)
+{
+ int x, y, w;
+ t->reslen = 0; // default no response
+ if (c - 0x80 < 0x20) {
+ /* C1 control codes */
+ process_char(t, 033);
+ process_char(t, c-0x40);
+ return;
+ }
+ if (t->esc) {
+ escape(t, c);
+ return;
+ }
+ switch(w=wcwidth(c)) {
+ case -1:
+ switch (c) {
+ case 033:
+ t->esc = 1;
+ break;
+ case '\r':
+ t->x = 0;
+ break;
+ case '\n':
+ if (t->y == t->sr_y2) scroll(t, t->sr_y1, t->sr_y2, 0);
+ else if (t->y < t->h-1) t->y++;
+ break;
+ case '\t':
+ t->x = (t->x + 8) & ~7;
+ if (t->x >= t->w) t->x = t->w - 1;
+ break;
+ case '\b':
+ if (!t->am && t->x) t->x--;
+ break;
+ case '\a':
+ bell(t);
+ break;
+ default:
+ process_char(t, 0xfffd);
+ break;
+ }
+ t->am = 0;
+ break;
+ case 0:
+ y = t->y;
+ x = t->x;
+ if (!x--) {
+ /* nothing to combine at home position */
+ if (!y--) return;
+ x = 0;
+ }
+
+ addchar(&t->rows[y]->cells[x], c);
+ dirty(t, y, x, 1);
+ break;
+ case 1:
+ case 2:
+ if (t->ins) ins_del_char(t, w, 1);
+ while (w--) {
+ if (t->am) newline(t); // kills am flag
+ dirty(t, t->y, t->x, 1);
+ setchar(&t->rows[t->y]->cells[t->x++], w?UU_FULLWIDTH:c, t->attr);
+ if (t->x == t->w) {
+ t->x--;
+ t->am=1;
+ }
+ }
+ break;
+ }
+}
+
+#define BAD_CHAR 0xffff
+
+void uuterm_stuff_byte(struct uuterm *t, unsigned char b)
+{
+ int i, l;
+ wchar_t wc;
+ mbstate_t init_mbs = { };
+
+ for (i=0; i<2; i++) {
+ l = mbrtowc(&wc, &b, 1, &t->mbs);
+ if (l >= 0) {
+ if (wc) process_char(t, wc);
+ return;
+ } else if (l == -2) return;
+
+ if (!i) process_char(t, BAD_CHAR);
+ t->mbs = init_mbs;
+ }
+}
+
+void uuterm_replace_buffer(struct uuterm *t, int w, int h, void *buf)
+{
+ int i;
+ char *p = buf;
+ struct uurow **rows;
+ int wmin = w < t->w ? w : t->w;
+
+ // keep the cursor on the screen after resizing
+ if (t->y >= h) {
+ int n = t->y - h + 1;
+ t->y -= n;
+ t->sr_y1 -= n;
+ t->sr_y2 -= n;
+ if (t->sr_y1 < 0) t->sr_y1 = 0;
+ if (t->sr_y2 < 0) t->sr_y2 = 0;
+ while (n--) scroll(t, 0, t->h-1, 0);
+ }
+
+ memset(p, 0, UU_BUF_SIZE(w, h));
+
+ rows = (void *)p;
+ p += h*sizeof(struct uurow *);
+
+ for (i=0; i<h; i++, p+=UU_ROW_SIZE(w)) {
+ rows[i] = (void *)p;
+ if (i < t->h)
+ memcpy(rows[i], t->rows[i], UU_ROW_SIZE(wmin));
+ rows[i]->idx = i;
+ rows[i]->x1 = 0;
+ rows[i]->x2 = w-1;
+ }
+
+ t->w = w;
+ t->h = h;
+ t->rows = rows;
+
+ if (t->x >= t->w) t->x = t->w - 1;
+ if (t->sr_y1 >= t->h) t->sr_y1 = t->h - 1;
+ if (t->sr_y2 >= t->h) t->sr_y2 = t->h - 1;
+}
+
+void uuterm_reset(struct uuterm *t)
+{
+ reset(t);
+}
diff --git a/tty.c b/tty.c
new file mode 100644
index 0000000..8a2ccda
--- /dev/null
+++ b/tty.c
@@ -0,0 +1,63 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+void uutty_resize(int fd, int w, int h)
+{
+#ifdef TIOCSWINSZ
+ struct winsize ws = { };
+ ws.ws_col = w;
+ ws.ws_row = h;
+ ioctl(fd, TIOCSWINSZ, &ws);
+#endif
+}
+
+/* #define posix_openpt(x) open("/dev/ptmx", x) */
+
+int uutty_open(char **cmd, int w, int h)
+{
+ int ptm, pts;
+ struct stat st;
+
+ if (!cmd || !cmd[0] || stat(cmd[0], &st) < 0
+ || !S_ISCHR(st.st_mode)
+ || (ptm = open(cmd[0], O_RDWR|O_NOCTTY)) < 0
+ || (isatty(ptm) ? 0 : (close(ptm),1)) ) {
+
+ if ((ptm = posix_openpt(O_RDWR|O_NOCTTY)) < 0)
+ return -1;
+ if (grantpt(ptm) < 0 || unlockpt(ptm) < 0) {
+ close(ptm);
+ return -1;
+ }
+
+ switch(fork()) {
+ case -1:
+ close(ptm);
+ return -1;
+ case 0:
+ setsid();
+ pts = open(ptsname(ptm), O_RDWR);
+ close(ptm);
+ dup2(pts, 0);
+ dup2(pts, 1);
+ dup2(pts, 2);
+ if (pts > 2) close(pts);
+ // FIXME............................
+ if (cmd) execvp(cmd[0], cmd);
+ else execl("/bin/sh", "-sh", (char *)0);
+ return 1;
+ }
+
+ uutty_resize(ptm, w, h);
+ }
+
+ fcntl(ptm, F_SETFL, fcntl(ptm, F_GETFL)|O_NONBLOCK);
+
+ return ptm;
+}
diff --git a/uuterm.h b/uuterm.h
new file mode 100644
index 0000000..f392bda
--- /dev/null
+++ b/uuterm.h
@@ -0,0 +1,100 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include <stddef.h>
+#include <wchar.h> /* for mbstate_t... */
+
+struct uucell
+{
+ unsigned short a;
+ unsigned char c[8];
+};
+
+struct uurow
+{
+ int idx;
+ int x1, x2; /* dirty region */
+ struct uucell cells[1];
+};
+
+#define UU_ATTR_DIM 0x0100
+#define UU_ATTR_UL 0x0200
+#define UU_ATTR_REV 0x0400
+
+#define UU_ATTR_BOLD 0x0008
+#define UU_ATTR_FG 0x0007
+
+#define UU_ATTR_BLINK 0x0080
+#define UU_ATTR_BG 0x0070
+
+struct uuterm
+{
+ struct uurow **rows;
+ int w, h;
+
+ // all members past this point are zero-filled on reset!
+ int reset;
+
+ // output state
+ int x, y;
+ int attr;
+ int sr_y1, sr_y2;
+ int ins :1;
+ int am :1;
+ int noam :1;
+
+ // input state
+ int ckp :1;
+ int kp :1;
+ char reslen;
+ char res[16];
+
+ // saved state
+ int save_x, save_y;
+ int save_attr, save_fg, save_bg;
+
+ // escape sequence processing
+ int esc;
+ unsigned param[16];
+ int nparam;
+
+ // multibyte parsing
+ mbstate_t mbs;
+};
+
+struct uudisp
+{
+ int cell_w, cell_h;
+ int w, h;
+ int inlen;
+ unsigned char *intext;
+ unsigned char inbuf[16];
+ int blink;
+ long priv[64];
+};
+
+#define UU_FULLWIDTH 0xfffe
+
+#define UU_ROW_SIZE(w) (sizeof(struct uurow) + (w)*sizeof(struct uucell))
+#define UU_BUF_SIZE(w, h) ( (h) * (sizeof(struct uurow *) * UU_ROW_SIZE((w))) )
+
+void uuterm_reset(struct uuterm *);
+void uuterm_replace_buffer(struct uuterm *, int, int, void *);
+void uuterm_stuff_byte(struct uuterm *, unsigned char);
+
+void uuterm_refresh_row(struct uudisp *, struct uurow *, int, int);
+
+int uu_combine_involution(unsigned, unsigned);
+
+int uudisp_open(struct uudisp *);
+int uudisp_fd_set(struct uudisp *, int, void *);
+void uudisp_next_event(struct uudisp *, void *);
+void uudisp_close(struct uudisp *);
+void uudisp_refresh(struct uudisp *, struct uuterm *);
+void uudisp_draw_glyph(struct uudisp *, int, int, const void *, int);
+
+void *uuterm_alloc(size_t);
+void uuterm_free(void *);
+void *uuterm_buf_alloc(int, int);
+
+void uutty_resize(int, int, int);
+int uutty_open(char **, int, int);