From b8f81236cde10d71b5c684e78ba39eb4e47a9079 Mon Sep 17 00:00:00 2001 From: Charlie Gordon Date: Thu, 15 Sep 2022 11:28:34 +0200 Subject: [PATCH] Split util module - split color/css functions from util.c into color.c - add util.h and color.h for declarations - util.c no longer includes qe.h - move get_clock_ms() and get_clock_usec() to unix.c - remove unused QString functions - bump VERSION to 5.3.4s --- Makefile | 10 +- VERSION | 2 +- color.c | 813 ++++++++++++++++++++++++++++++++++ color.h | 237 ++++++++++ cutils.h | 3 +- display.h | 37 -- libqhtml/Makefile | 4 +- libqhtml/css.h | 16 +- libqhtml/cssparse.c | 6 +- libqhtml/csstoqe.c | 3 +- qe-manual.md | 216 ++++++++- qe.c | 64 ++- qe.h | 714 +----------------------------- unix.c | 40 ++ util.c | 1019 ++++--------------------------------------- util.h | 594 +++++++++++++++++++++++++ 16 files changed, 2045 insertions(+), 1733 deletions(-) create mode 100644 color.c create mode 100644 color.h create mode 100644 util.h diff --git a/Makefile b/Makefile index e16d710..6cd773b 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,7 @@ ifeq (,$(TARGET_OBJ)) TARGET_OBJ:=$(TARGET) endif -OBJS:= qe.o util.o cutils.o charset.o buffer.o search.o input.o display.o \ +OBJS:= qe.o cutils.o util.o color.o charset.o buffer.o search.o input.o display.o \ qescript.o modes/hex.o ifdef TARGET_TINY @@ -229,7 +229,7 @@ endif # TARGET_TINY SRCS:= $(OBJS:.o=.c) -DEPENDS:= qe.h config.h cutils.h display.h qestyles.h variables.h config.mak lang/clang.h +DEPENDS:= qe.h config.h cutils.h util.h display.h qestyles.h variables.h config.mak lang/clang.h DEPENDS:= $(addprefix $(DEPTH)/, $(DEPENDS)) BINDIR:=$(DEPTH)/bin @@ -283,7 +283,7 @@ tqe1: force; $(MAKE) TARGET=tqe TARGET_TINY=1 tqe1$(EXE) else # Amalgation mode produces a larger executable -TSRCS:=qe.c util.c cutils.c charset.c buffer.c search.c input.c display.c \ +TSRCS:=qe.c cutils.c util.c color.c charset.c buffer.c search.c input.c display.c \ modes/hex.c parser.c unix.c tty.c win32.c qeend.c TSRCS+= $(OBJS_DIR)/tqe_modules.c @@ -463,7 +463,7 @@ fbffonts.c: $(BINDIR)/fbftoqe$(EXE) $(FONTS) # # html2png tool (XML/HTML/CSS2 renderer test tool) # -OBJS1=html2png.o util.o cutils.o \ +OBJS1=html2png.o cutils.o util.o color.o \ arabic.o indic.o qfribidi.o display.o unicode_join.o \ charset.o charsetmore.o charsetjis.o \ libfbf.o fbfrender.o cfb.o fbffonts.o @@ -501,7 +501,7 @@ qe-doc.pdf: qe-doc.texi Makefile clean: $(MAKE) -C libqhtml clean rm -f qe-doc.aux qe-doc.info qe-doc.log qe-doc.pdf qe-doc.toc - rm -rf *.dSYM .objs* .tobjs* .xobjs* bin + rm -rf *.dSYM *.gch .objs* .tobjs* .xobjs* bin rm -f *~ *.o *.a *.exe *_g *_debug TAGS gmon.out core *.exe.stackdump \ qe tqe tqe1 xqe qfribidi kmaptoqe ligtoqe html2png cptoqe jistoqe \ fbftoqe fbffonts.c allmodules.txt basemodules.txt '.#'*[0-9] diff --git a/VERSION b/VERSION index 5ad181a..ee286a7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.3.4r +5.3.4s diff --git a/color.c b/color.c new file mode 100644 index 0000000..dcbcf55 --- /dev/null +++ b/color.c @@ -0,0 +1,813 @@ +/* + * Colors for qemacs. + * + * Copyright (c) 2001 Fabrice Bellard. + * Copyright (c) 2002-2022 Charlie Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "cutils.h" +#include "util.h" +#include "color.h" + +#if 1 +/* Should move all this to a separate source file color.c */ + +/* For 8K colors, We use a color system with 7936 colors: + * - 16 standard colors + * - 240 standard palette colors + * - 4096 colors in a 16x16x16 cube + * - a 256 level gray ramp + * - 6 256-level fade to black ramps + * - 6 256-level fade to white ramps + * - a 256 color palette with default xterm values + * - 256 unused slots + */ + +/* Alternately we could use a system with 8157 colors: + * - 2 default color + * - 16 standard colors + * - 256 standard palette colors + * - 6859 colors in a 19x19x19 cube + * with ramp 0,15,31,47,63,79,95,108,121,135, + * 148,161,175,188,201,215,228,241,255 values + * - 256 level gray ramp + * - extra space for 3 256 level ramps or 12 64 level ramps + * - 15 unused slots + */ + +/* Another possible system for 8K colors has 8042+ colors: + * - 2 default color + * - 16 standard colors + * - 24 standard grey scale colors + * - 8000 colors in a 20x20x20 cube + * with ramp 0,13,27,40,54,67,81,95,108,121,135, + * 148,161,175,188,201,215,228,241,255 values + * - extra grey scale colors + * - some unused slots + */ + +static ColorDef const default_colors[] = { + /* From HTML 4.0 spec */ + { "black", QERGB(0x00, 0x00, 0x00) }, + { "green", QERGB(0x00, 0x80, 0x00) }, + { "silver", QERGB(0xc0, 0xc0, 0xc0) }, + { "lime", QERGB(0x00, 0xff, 0x00) }, + + { "gray", QERGB(0xbe, 0xbe, 0xbe) }, + { "olive", QERGB(0x80, 0x80, 0x00) }, + { "white", QERGB(0xff, 0xff, 0xff) }, + { "yellow", QERGB(0xff, 0xff, 0x00) }, + + { "maroon", QERGB(0x80, 0x00, 0x00) }, + { "navy", QERGB(0x00, 0x00, 0x80) }, + { "red", QERGB(0xff, 0x00, 0x00) }, + { "blue", QERGB(0x00, 0x00, 0xff) }, + + { "purple", QERGB(0x80, 0x00, 0x80) }, + { "teal", QERGB(0x00, 0x80, 0x80) }, + { "fuchsia", QERGB(0xff, 0x00, 0xff) }, + { "aqua", QERGB(0x00, 0xff, 0xff) }, + + /* more colors */ + { "cyan", QERGB(0x00, 0xff, 0xff) }, + { "magenta", QERGB(0xff, 0x00, 0xff) }, + { "grey", QERGB(0xbe, 0xbe, 0xbe) }, + { "transparent", COLOR_TRANSPARENT }, +}; +#define nb_default_colors countof(default_colors) + +ColorDef *qe_colors = unconst(ColorDef *)default_colors; +int nb_qe_colors = nb_default_colors; + +#if 0 +static QEColor const tty_full_colors[8] = { + QERGB(0x00, 0x00, 0x00), /* black */ + QERGB(0xff, 0x00, 0x00), /* red */ + QERGB(0x00, 0xff, 0x00), /* lime */ + QERGB(0xff, 0xff, 0x00), /* yellow */ + QERGB(0x00, 0x00, 0xff), /* blue */ + QERGB(0xff, 0x00, 0xff), /* fuchsia */ + QERGB(0x00, 0xff, 0xff), /* aqua */ + QERGB(0xff, 0xff, 0xff), /* white */ +}; +#endif + +QEColor const xterm_colors[256] = { + QERGB(0x00, 0x00, 0x00), /* black */ + QERGB(0xbb, 0x00, 0x00), + QERGB(0x00, 0xbb, 0x00), + QERGB(0xbb, 0xbb, 0x00), + QERGB(0x00, 0x00, 0xbb), + QERGB(0xbb, 0x00, 0xbb), + QERGB(0x00, 0xbb, 0xbb), + QERGB(0xbb, 0xbb, 0xbb), + + QERGB(0x55, 0x55, 0x55), + QERGB(0xff, 0x55, 0x55), + QERGB(0x55, 0xff, 0x55), + QERGB(0xff, 0xff, 0x55), + QERGB(0x55, 0x55, 0xff), + QERGB(0xff, 0x55, 0xff), + QERGB(0x55, 0xff, 0xff), + QERGB(0xff, 0xff, 0xff), /* white */ +#if 1 + /* Extended color palette for xterm 256 color mode */ + + /* From XFree86: xc/programs/xterm/256colres.h, + * v 1.5 2002/10/05 17:57:11 dickey Exp + */ + + /* 216 entry RGB cube with axes 0,95,135,175,215,255 */ + /* followed by 24 entry grey scale 8,18..238 */ + QERGB(0x00, 0x00, 0x00), /* 16: Grey0 */ + QERGB(0x00, 0x00, 0x5f), /* 17: NavyBlue */ + QERGB(0x00, 0x00, 0x87), /* 18: DarkBlue */ + QERGB(0x00, 0x00, 0xaf), /* 19: Blue3 */ + QERGB(0x00, 0x00, 0xd7), /* 20: Blue3 */ + QERGB(0x00, 0x00, 0xff), /* 21: Blue1 */ + QERGB(0x00, 0x5f, 0x00), /* 22: DarkGreen */ + QERGB(0x00, 0x5f, 0x5f), /* 23: DeepSkyBlue4 */ + QERGB(0x00, 0x5f, 0x87), /* 24: DeepSkyBlue4 */ + QERGB(0x00, 0x5f, 0xaf), /* 25: DeepSkyBlue4 */ + QERGB(0x00, 0x5f, 0xd7), /* 26: DodgerBlue3 */ + QERGB(0x00, 0x5f, 0xff), /* 27: DodgerBlue2 */ + QERGB(0x00, 0x87, 0x00), /* 28: Green4 */ + QERGB(0x00, 0x87, 0x5f), /* 29: SpringGreen4 */ + QERGB(0x00, 0x87, 0x87), /* 30: Turquoise4 */ + QERGB(0x00, 0x87, 0xaf), /* 31: DeepSkyBlue3 */ + QERGB(0x00, 0x87, 0xd7), /* 32: DeepSkyBlue3 */ + QERGB(0x00, 0x87, 0xff), /* 33: DodgerBlue1 */ + QERGB(0x00, 0xaf, 0x00), /* 34: Green3 */ + QERGB(0x00, 0xaf, 0x5f), /* 35: SpringGreen3 */ + QERGB(0x00, 0xaf, 0x87), /* 36: DarkCyan */ + QERGB(0x00, 0xaf, 0xaf), /* 37: LightSeaGreen */ + QERGB(0x00, 0xaf, 0xd7), /* 38: DeepSkyBlue2 */ + QERGB(0x00, 0xaf, 0xff), /* 39: DeepSkyBlue1 */ + QERGB(0x00, 0xd7, 0x00), /* 40: Green3 */ + QERGB(0x00, 0xd7, 0x5f), /* 41: SpringGreen3 */ + QERGB(0x00, 0xd7, 0x87), /* 42: SpringGreen2 */ + QERGB(0x00, 0xd7, 0xaf), /* 43: Cyan3 */ + QERGB(0x00, 0xd7, 0xd7), /* 44: DarkTurquoise */ + QERGB(0x00, 0xd7, 0xff), /* 45: Turquoise2 */ + QERGB(0x00, 0xff, 0x00), /* 46: Green1 */ + QERGB(0x00, 0xff, 0x5f), /* 47: SpringGreen2 */ + QERGB(0x00, 0xff, 0x87), /* 48: SpringGreen1 */ + QERGB(0x00, 0xff, 0xaf), /* 49: MediumSpringGreen */ + QERGB(0x00, 0xff, 0xd7), /* 50: Cyan2 */ + QERGB(0x00, 0xff, 0xff), /* 51: Cyan1 */ + QERGB(0x5f, 0x00, 0x00), /* 52: DarkRed */ + QERGB(0x5f, 0x00, 0x5f), /* 53: DeepPink4 */ + QERGB(0x5f, 0x00, 0x87), /* 54: Purple4 */ + QERGB(0x5f, 0x00, 0xaf), /* 55: Purple4 */ + QERGB(0x5f, 0x00, 0xd7), /* 56: Purple3 */ + QERGB(0x5f, 0x00, 0xff), /* 57: BlueViolet */ + QERGB(0x5f, 0x5f, 0x00), /* 58: Orange4 */ + QERGB(0x5f, 0x5f, 0x5f), /* 59: Grey37 */ + QERGB(0x5f, 0x5f, 0x87), /* 60: MediumPurple4 */ + QERGB(0x5f, 0x5f, 0xaf), /* 61: SlateBlue3 */ + QERGB(0x5f, 0x5f, 0xd7), /* 62: SlateBlue3 */ + QERGB(0x5f, 0x5f, 0xff), /* 63: RoyalBlue1 */ + QERGB(0x5f, 0x87, 0x00), /* 64: Chartreuse4 */ + QERGB(0x5f, 0x87, 0x5f), /* 65: DarkSeaGreen4 */ + QERGB(0x5f, 0x87, 0x87), /* 66: PaleTurquoise4 */ + QERGB(0x5f, 0x87, 0xaf), /* 67: SteelBlue */ + QERGB(0x5f, 0x87, 0xd7), /* 68: SteelBlue3 */ + QERGB(0x5f, 0x87, 0xff), /* 69: CornflowerBlue */ + QERGB(0x5f, 0xaf, 0x00), /* 70: Chartreuse3 */ + QERGB(0x5f, 0xaf, 0x5f), /* 71: DarkSeaGreen4 */ + QERGB(0x5f, 0xaf, 0x87), /* 72: CadetBlue */ + QERGB(0x5f, 0xaf, 0xaf), /* 73: CadetBlue */ + QERGB(0x5f, 0xaf, 0xd7), /* 74: SkyBlue3 */ + QERGB(0x5f, 0xaf, 0xff), /* 75: SteelBlue1 */ + QERGB(0x5f, 0xd7, 0x00), /* 76: Chartreuse3 */ + QERGB(0x5f, 0xd7, 0x5f), /* 77: PaleGreen3 */ + QERGB(0x5f, 0xd7, 0x87), /* 78: SeaGreen3 */ + QERGB(0x5f, 0xd7, 0xaf), /* 79: Aquamarine3 */ + QERGB(0x5f, 0xd7, 0xd7), /* 80: MediumTurquoise */ + QERGB(0x5f, 0xd7, 0xff), /* 81: SteelBlue1 */ + QERGB(0x5f, 0xff, 0x00), /* 82: Chartreuse2 */ + QERGB(0x5f, 0xff, 0x5f), /* 83: SeaGreen2 */ + QERGB(0x5f, 0xff, 0x87), /* 84: SeaGreen1 */ + QERGB(0x5f, 0xff, 0xaf), /* 85: SeaGreen1 */ + QERGB(0x5f, 0xff, 0xd7), /* 86: Aquamarine1 */ + QERGB(0x5f, 0xff, 0xff), /* 87: DarkSlateGray2 */ + QERGB(0x87, 0x00, 0x00), /* 88: DarkRed */ + QERGB(0x87, 0x00, 0x5f), /* 89: DeepPink4 */ + QERGB(0x87, 0x00, 0x87), /* 90: DarkMagenta */ + QERGB(0x87, 0x00, 0xaf), /* 91: DarkMagenta */ + QERGB(0x87, 0x00, 0xd7), /* 92: DarkViolet */ + QERGB(0x87, 0x00, 0xff), /* 93: Purple */ + QERGB(0x87, 0x5f, 0x00), /* 94: Orange4 */ + QERGB(0x87, 0x5f, 0x5f), /* 95: LightPink4 */ + QERGB(0x87, 0x5f, 0x87), /* 96: Plum4 */ + QERGB(0x87, 0x5f, 0xaf), /* 97: MediumPurple3 */ + QERGB(0x87, 0x5f, 0xd7), /* 98: MediumPurple3 */ + QERGB(0x87, 0x5f, 0xff), /* 99: SlateBlue1 */ + QERGB(0x87, 0x87, 0x00), /* 100: Yellow4 */ + QERGB(0x87, 0x87, 0x5f), /* 101: Wheat4 */ + QERGB(0x87, 0x87, 0x87), /* 102: Grey53 */ + QERGB(0x87, 0x87, 0xaf), /* 103: LightSlateGrey */ + QERGB(0x87, 0x87, 0xd7), /* 104: MediumPurple */ + QERGB(0x87, 0x87, 0xff), /* 105: LightSlateBlue */ + QERGB(0x87, 0xaf, 0x00), /* 106: Yellow4 */ + QERGB(0x87, 0xaf, 0x5f), /* 107: DarkOliveGreen3 */ + QERGB(0x87, 0xaf, 0x87), /* 108: DarkSeaGreen */ + QERGB(0x87, 0xaf, 0xaf), /* 109: LightSkyBlue3 */ + QERGB(0x87, 0xaf, 0xd7), /* 110: LightSkyBlue3 */ + QERGB(0x87, 0xaf, 0xff), /* 111: SkyBlue2 */ + QERGB(0x87, 0xd7, 0x00), /* 112: Chartreuse2 */ + QERGB(0x87, 0xd7, 0x5f), /* 113: DarkOliveGreen3 */ + QERGB(0x87, 0xd7, 0x87), /* 114: PaleGreen3 */ + QERGB(0x87, 0xd7, 0xaf), /* 115: DarkSeaGreen3 */ + QERGB(0x87, 0xd7, 0xd7), /* 116: DarkSlateGray3 */ + QERGB(0x87, 0xd7, 0xff), /* 117: SkyBlue1 */ + QERGB(0x87, 0xff, 0x00), /* 118: Chartreuse1 */ + QERGB(0x87, 0xff, 0x5f), /* 119: LightGreen */ + QERGB(0x87, 0xff, 0x87), /* 120: LightGreen */ + QERGB(0x87, 0xff, 0xaf), /* 121: PaleGreen1 */ + QERGB(0x87, 0xff, 0xd7), /* 122: Aquamarine1 */ + QERGB(0x87, 0xff, 0xff), /* 123: DarkSlateGray1 */ + QERGB(0xaf, 0x00, 0x00), /* 124: Red3 */ + QERGB(0xaf, 0x00, 0x5f), /* 125: DeepPink4 */ + QERGB(0xaf, 0x00, 0x87), /* 126: MediumVioletRed */ + QERGB(0xaf, 0x00, 0xaf), /* 127: Magenta3 */ + QERGB(0xaf, 0x00, 0xd7), /* 128: DarkViolet */ + QERGB(0xaf, 0x00, 0xff), /* 129: Purple */ + QERGB(0xaf, 0x5f, 0x00), /* 130: DarkOrange3 */ + QERGB(0xaf, 0x5f, 0x5f), /* 131: IndianRed */ + QERGB(0xaf, 0x5f, 0x87), /* 132: HotPink3 */ + QERGB(0xaf, 0x5f, 0xaf), /* 133: MediumOrchid3 */ + QERGB(0xaf, 0x5f, 0xd7), /* 134: MediumOrchid */ + QERGB(0xaf, 0x5f, 0xff), /* 135: MediumPurple2 */ + QERGB(0xaf, 0x87, 0x00), /* 136: DarkGoldenrod */ + QERGB(0xaf, 0x87, 0x5f), /* 137: LightSalmon3 */ + QERGB(0xaf, 0x87, 0x87), /* 138: RosyBrown */ + QERGB(0xaf, 0x87, 0xaf), /* 139: Grey63 */ + QERGB(0xaf, 0x87, 0xd7), /* 140: MediumPurple2 */ + QERGB(0xaf, 0x87, 0xff), /* 141: MediumPurple1 */ + QERGB(0xaf, 0xaf, 0x00), /* 142: Gold3 */ + QERGB(0xaf, 0xaf, 0x5f), /* 143: DarkKhaki */ + QERGB(0xaf, 0xaf, 0x87), /* 144: NavajoWhite3 */ + QERGB(0xaf, 0xaf, 0xaf), /* 145: Grey69 */ + QERGB(0xaf, 0xaf, 0xd7), /* 146: LightSteelBlue3 */ + QERGB(0xaf, 0xaf, 0xff), /* 147: LightSteelBlue */ + QERGB(0xaf, 0xd7, 0x00), /* 148: Yellow3 */ + QERGB(0xaf, 0xd7, 0x5f), /* 149: DarkOliveGreen3 */ + QERGB(0xaf, 0xd7, 0x87), /* 150: DarkSeaGreen3 */ + QERGB(0xaf, 0xd7, 0xaf), /* 151: DarkSeaGreen2 */ + QERGB(0xaf, 0xd7, 0xd7), /* 152: LightCyan3 */ + QERGB(0xaf, 0xd7, 0xff), /* 153: LightSkyBlue1 */ + QERGB(0xaf, 0xff, 0x00), /* 154: GreenYellow */ + QERGB(0xaf, 0xff, 0x5f), /* 155: DarkOliveGreen2 */ + QERGB(0xaf, 0xff, 0x87), /* 156: PaleGreen1 */ + QERGB(0xaf, 0xff, 0xaf), /* 157: DarkSeaGreen2 */ + QERGB(0xaf, 0xff, 0xd7), /* 158: DarkSeaGreen1 */ + QERGB(0xaf, 0xff, 0xff), /* 159: PaleTurquoise1 */ + QERGB(0xd7, 0x00, 0x00), /* 160: Red3 */ + QERGB(0xd7, 0x00, 0x5f), /* 161: DeepPink3 */ + QERGB(0xd7, 0x00, 0x87), /* 162: DeepPink3 */ + QERGB(0xd7, 0x00, 0xaf), /* 163: Magenta3 */ + QERGB(0xd7, 0x00, 0xd7), /* 164: Magenta3 */ + QERGB(0xd7, 0x00, 0xff), /* 165: Magenta2 */ + QERGB(0xd7, 0x5f, 0x00), /* 166: DarkOrange3 */ + QERGB(0xd7, 0x5f, 0x5f), /* 167: IndianRed */ + QERGB(0xd7, 0x5f, 0x87), /* 168: HotPink3 */ + QERGB(0xd7, 0x5f, 0xaf), /* 169: HotPink2 */ + QERGB(0xd7, 0x5f, 0xd7), /* 170: Orchid */ + QERGB(0xd7, 0x5f, 0xff), /* 171: MediumOrchid1 */ + QERGB(0xd7, 0x87, 0x00), /* 172: Orange3 */ + QERGB(0xd7, 0x87, 0x5f), /* 173: LightSalmon3 */ + QERGB(0xd7, 0x87, 0x87), /* 174: LightPink3 */ + QERGB(0xd7, 0x87, 0xaf), /* 175: Pink3 */ + QERGB(0xd7, 0x87, 0xd7), /* 176: Plum3 */ + QERGB(0xd7, 0x87, 0xff), /* 177: Violet */ + QERGB(0xd7, 0xaf, 0x00), /* 178: Gold3 */ + QERGB(0xd7, 0xaf, 0x5f), /* 179: LightGoldenrod3 */ + QERGB(0xd7, 0xaf, 0x87), /* 180: Tan */ + QERGB(0xd7, 0xaf, 0xaf), /* 181: MistyRose3 */ + QERGB(0xd7, 0xaf, 0xd7), /* 182: Thistle3 */ + QERGB(0xd7, 0xaf, 0xff), /* 183: Plum2 */ + QERGB(0xd7, 0xd7, 0x00), /* 184: Yellow3 */ + QERGB(0xd7, 0xd7, 0x5f), /* 185: Khaki3 */ + QERGB(0xd7, 0xd7, 0x87), /* 186: LightGoldenrod2 */ + QERGB(0xd7, 0xd7, 0xaf), /* 187: LightYellow3 */ + QERGB(0xd7, 0xd7, 0xd7), /* 188: Grey84 */ + QERGB(0xd7, 0xd7, 0xff), /* 189: LightSteelBlue1 */ + QERGB(0xd7, 0xff, 0x00), /* 190: Yellow2 */ + QERGB(0xd7, 0xff, 0x5f), /* 191: DarkOliveGreen1 */ + QERGB(0xd7, 0xff, 0x87), /* 192: DarkOliveGreen1 */ + QERGB(0xd7, 0xff, 0xaf), /* 193: DarkSeaGreen1 */ + QERGB(0xd7, 0xff, 0xd7), /* 194: Honeydew2 */ + QERGB(0xd7, 0xff, 0xff), /* 195: LightCyan1 */ + QERGB(0xff, 0x00, 0x00), /* 196: Red1 */ + QERGB(0xff, 0x00, 0x5f), /* 197: DeepPink2 */ + QERGB(0xff, 0x00, 0x87), /* 198: DeepPink1 */ + QERGB(0xff, 0x00, 0xaf), /* 199: DeepPink1 */ + QERGB(0xff, 0x00, 0xd7), /* 200: Magenta2 */ + QERGB(0xff, 0x00, 0xff), /* 201: Magenta1 */ + QERGB(0xff, 0x5f, 0x00), /* 202: OrangeRed1 */ + QERGB(0xff, 0x5f, 0x5f), /* 203: IndianRed1 */ + QERGB(0xff, 0x5f, 0x87), /* 204: IndianRed1 */ + QERGB(0xff, 0x5f, 0xaf), /* 205: HotPink */ + QERGB(0xff, 0x5f, 0xd7), /* 206: HotPink */ + QERGB(0xff, 0x5f, 0xff), /* 207: MediumOrchid1 */ + QERGB(0xff, 0x87, 0x00), /* 208: DarkOrange */ + QERGB(0xff, 0x87, 0x5f), /* 209: Salmon1 */ + QERGB(0xff, 0x87, 0x87), /* 210: LightCoral */ + QERGB(0xff, 0x87, 0xaf), /* 211: PaleVioletRed1 */ + QERGB(0xff, 0x87, 0xd7), /* 212: Orchid2 */ + QERGB(0xff, 0x87, 0xff), /* 213: Orchid1 */ + QERGB(0xff, 0xaf, 0x00), /* 214: Orange1 */ + QERGB(0xff, 0xaf, 0x5f), /* 215: SandyBrown */ + QERGB(0xff, 0xaf, 0x87), /* 216: LightSalmon1 */ + QERGB(0xff, 0xaf, 0xaf), /* 217: LightPink1 */ + QERGB(0xff, 0xaf, 0xd7), /* 218: Pink1 */ + QERGB(0xff, 0xaf, 0xff), /* 219: Plum1 */ + QERGB(0xff, 0xd7, 0x00), /* 220: Gold1 */ + QERGB(0xff, 0xd7, 0x5f), /* 221: LightGoldenrod2 */ + QERGB(0xff, 0xd7, 0x87), /* 222: LightGoldenrod2 */ + QERGB(0xff, 0xd7, 0xaf), /* 223: NavajoWhite1 */ + QERGB(0xff, 0xd7, 0xd7), /* 224: MistyRose1 */ + QERGB(0xff, 0xd7, 0xff), /* 225: Thistle1 */ + QERGB(0xff, 0xff, 0x00), /* 226: Yellow1 */ + QERGB(0xff, 0xff, 0x5f), /* 227: LightGoldenrod1 */ + QERGB(0xff, 0xff, 0x87), /* 228: Khaki1 */ + QERGB(0xff, 0xff, 0xaf), /* 229: Wheat1 */ + QERGB(0xff, 0xff, 0xd7), /* 230: Cornsilk1 */ + QERGB(0xff, 0xff, 0xff), /* 231: Grey100 */ + QERGB(0x08, 0x08, 0x08), /* 232: Grey3 */ + QERGB(0x12, 0x12, 0x12), /* 233: Grey7 */ + QERGB(0x1c, 0x1c, 0x1c), /* 234: Grey11 */ + QERGB(0x26, 0x26, 0x26), /* 235: Grey15 */ + QERGB(0x30, 0x30, 0x30), /* 236: Grey19 */ + QERGB(0x3a, 0x3a, 0x3a), /* 237: Grey23 */ + QERGB(0x44, 0x44, 0x44), /* 238: Grey27 */ + QERGB(0x4e, 0x4e, 0x4e), /* 239: Grey30 */ + QERGB(0x58, 0x58, 0x58), /* 240: Grey35 */ + QERGB(0x62, 0x62, 0x62), /* 241: Grey39 */ + QERGB(0x6c, 0x6c, 0x6c), /* 242: Grey42 */ + QERGB(0x76, 0x76, 0x76), /* 243: Grey46 */ + QERGB(0x80, 0x80, 0x80), /* 244: Grey50 */ + QERGB(0x8a, 0x8a, 0x8a), /* 245: Grey54 */ + QERGB(0x94, 0x94, 0x94), /* 246: Grey58 */ + QERGB(0x9e, 0x9e, 0x9e), /* 247: Grey62 */ + QERGB(0xa8, 0xa8, 0xa8), /* 248: Grey66 */ + QERGB(0xb2, 0xb2, 0xb2), /* 249: Grey70 */ + QERGB(0xbc, 0xbc, 0xbc), /* 250: Grey74 */ + QERGB(0xc6, 0xc6, 0xc6), /* 251: Grey78 */ + QERGB(0xd0, 0xd0, 0xd0), /* 252: Grey82 */ + QERGB(0xda, 0xda, 0xda), /* 253: Grey85 */ + QERGB(0xe4, 0xe4, 0xe4), /* 254: Grey89 */ + QERGB(0xee, 0xee, 0xee), /* 255: Grey93 */ +#endif +}; + +#if 0 +static unsigned char const scale_cube[256] = { + /* This array is used for mapping rgb colors to the standard palette */ + /* 216 entry RGB cube with axes 0,95,135,175,215,255 */ +#define REP5(x) (x), (x), (x), (x), (x) +#define REP10(x) REP5(x), REP5(x) +#define REP20(x) REP10(x), REP10(x) +#define REP40(x) REP20(x), REP20(x) +#define REP25(x) REP5(x), REP5(x), REP5(x), REP5(x), REP5(x) +#define REP47(x) REP10(x), REP10(x), REP10(x), REP10(x), REP5(x), (x), (x) + REP47(0), REP47(1), REP20(1), REP40(2), REP40(3), REP40(4), REP20(5), 5 +}; + +static unsigned char const scale_grey[256] = { + /* This array is used for mapping gray levels to the standard palette */ + /* 232..255: 24 entry grey scale 8,18..238 */ + 16, 16, 16, 16, + REP10(232), REP10(233), REP10(234), REP10(235), + REP10(236), REP10(237), REP10(238), REP10(239), + REP10(240), REP10(241), REP10(242), REP10(243), + REP10(244), REP10(245), REP10(246), REP10(247), + REP10(248), REP10(249), REP10(250), REP10(251), + REP10(252), REP10(253), REP10(254), REP10(255), + 255, 255, 255, + 231, 231, 231, 231, 231, 231, 231, 231, 231 +}; +#endif + +static inline int color_dist(QEColor c1, QEColor c2) { + /* using casts because c1 and c2 are unsigned */ +#if 0 + /* using a quick approximation to give green extra weight */ + return abs((int)((c1 >> 0) & 0xff) - (int)((c2 >> 0) & 0xff)) + + 2 * abs((int)((c1 >> 8) & 0xff) - (int)((c2 >> 8) & 0xff)) + + abs((int)((c1 >> 16) & 0xff) - (int)((c2 >> 16) & 0xff)); +#else + /* using different weights to R, G, B according to luminance levels */ + return 11 * abs((int)((c1 >> 0) & 0xff) - (int)((c2 >> 0) & 0xff)) + + 59 * abs((int)((c1 >> 8) & 0xff) - (int)((c2 >> 8) & 0xff)) + + 30 * abs((int)((c1 >> 16) & 0xff) - (int)((c2 >> 16) & 0xff)); +#endif +} + +/* XXX: should have a more generic API with precomputed mapping scales */ +/* Convert RGB triplet to a composite color */ +unsigned int qe_map_color(QEColor color, QEColor const *colors, int count, int *dist) +{ + int i, cmin, dmin, d; + + color &= 0xFFFFFF; /* mask off the alpha channel */ + + if (count >= 0x1000000) { + cmin = color | 0x1000000; /* force explicit RGB triplet */ + dmin = 0; + } else { + dmin = INT_MAX; + cmin = 0; + if (count <= 16) { + for (i = 0; i < count; i++) { + d = color_dist(color, colors[i]); + if (d < dmin) { + cmin = i; + dmin = d; + } + } + } else { /* if (dmin > 0 && count > 16) */ + unsigned int r = (color >> 16) & 0xff; + unsigned int g = (color >> 8) & 0xff; + unsigned int b = (color >> 0) & 0xff; +#if 0 + if (r == g && g == b) { + i = scale_grey[r]; + d = color_dist(color, colors[i]); + if (d < dmin) { + cmin = i; + dmin = d; + } + } else { + /* XXX: should use more precise projection */ + i = 16 + scale_cube[r] * 36 + + scale_cube[g] * 6 + + scale_cube[b]; + d = color_dist(color, colors[i]); + if (d < dmin) { + cmin = i; + dmin = d; + } + } +#else + if (r == g && g == b) { + /* color is a gray tone: + * map to the closest palette entry + */ + d = color_dist(color, colors[16]); + if (d < dmin) { + cmin = 16; + dmin = d; + } + for (i = 231; i < 256; i++) { + d = color_dist(color, colors[i]); + if (d < dmin) { + cmin = i; + dmin = d; + } + } + } else { + /* general case: try and match a palette entry + * from the 6x6x6 color cube . + */ + /* XXX: this causes gliches on true color terminals + * with a non standard xterm palette, such as iTerm2. + * On true color terminals, we should treat palette + * colors and rgb colors differently in the shell buffer + * terminal emulator. + */ + for (i = 16; i < 232; i++) { + d = color_dist(color, colors[i]); + if (d < dmin) { + cmin = i; + dmin = d; + } + } + } +#endif + if (dmin > 0 && count >= 4096) { + /* 13-bit 7936 color system */ + d = 0; + for (;;) { + if (r == g) { + if (g == b) { /* #xxxxxx */ + i = 0x700 + r; + break; + } + if (r == 0) { /* #0000xx */ + i = 0x100 + b; + break; + } + if (r == 255) { /* #FFFFxx */ + i = 0x800 + 0x100 + b; + break; + } + if (b == 0) { /* #xxxx00 */ + i = 0x600 + r; + break; + } + if (b == 255) { /* #xxxxFF */ + i = 0x800 + 0x600 + r; + break; + } + } else + if (r == b) { + if (r == 0) { /* #00xx00 */ + i = 0x200 + g; + break; + } + if (r == 255) { /* #FFxxFF */ + i = 0x800 + 0x200 + g; + break; + } + if (g == 0) { /* #xx00xx */ + i = 0x500 + r; + break; + } + if (g == 255) { /* #xxFFxx */ + i = 0x800 + 0x500 + r; + break; + } + } else + if (g == b) { + if (g == 0) { /* #xx0000 */ + i = 0x400 + r; + break; + } + if (g == 255) { /* #xxFFFF */ + i = 0x800 + 0x400 + r; + break; + } + if (r == 0) { /* #00xxxx */ + i = 0x300 + g; + break; + } + if (r == 255) { /* #FFxxxx */ + i = 0x800 + 0x300 + g; + break; + } + } + i = 0x1000 | ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4); + d = color_dist(color, (color & 0xF0F0F0) | ((color & 0xF0F0F0) >> 4)); + break; + } + if (d < dmin) { + cmin = i; + dmin = d; + } + } + } + } + if (dist) { + *dist = dmin; + } + return cmin; +} + +/* Convert a composite color to an RGB triplet */ +QEColor qe_unmap_color(int color, int count) { + /* XXX: Should use an 8K array for all colors <= 8192 */ + if (color < 256) { + return xterm_colors[color]; + } + if (color < 8192) { + /* 13-bit 7936 color system */ + if (color & 0x1000) { + /* explicit 12-bit color */ + QEColor rgb = (((color & 0xF00) << 12) | + ((color & 0x0F0) << 4) | + ((color & 0x00F) << 0)); + return rgb | (rgb << 4); + } + if ((color & 0xf00) < 0xf00) { + /* 256 level color ramps */ + /* 0x800 is unused and converts to white */ + int r, g, b; + r = g = b = color & 0xFF; + if (!(color & 0x400)) r = -(color >> 11) & 0xFF; + if (!(color & 0x200)) g = -(color >> 11) & 0xFF; + if (!(color & 0x100)) b = -(color >> 11) & 0xFF; + return QERGB(r, g, b); + } else { + /* 0xf00 indicates the standard xterm color palette */ + return xterm_colors[color & 255]; + } + } + /* explicit RGB color */ + return color & 0xFFFFFF; +} + +static int css_lookup_color(ColorDef const *def, int count, + const char *name) +{ + int i; + + for (i = 0; i < count; i++) { + if (!strxcmp(def[i].name, name)) + return i; + } + return -1; +} + +int css_define_color(const char *name, const char *value) +{ + ColorDef *def; + QEColor color; + int index; + + /* Check color validity */ + if (css_get_color(&color, value)) + return -1; + + /* First color definition: allocate modifiable array */ + if (qe_colors == default_colors) { + qe_colors = qe_malloc_dup(default_colors, sizeof(default_colors)); + } + + /* Make room: reallocate table in chunks of 8 entries */ + if (((nb_qe_colors - nb_default_colors) & 7) == 0) { + if (!qe_realloc(&qe_colors, + (nb_qe_colors + 8) * sizeof(ColorDef))) { + return -1; + } + } + /* Check for redefinition */ + index = css_lookup_color(qe_colors, nb_qe_colors, name); + if (index >= 0) { + qe_colors[index].color = color; + return 0; + } + + def = &qe_colors[nb_qe_colors]; + def->name = qe_strdup(name); + def->color = color; + nb_qe_colors++; + + return 0; +} + +void css_free_colors(void) +{ + if (qe_colors != default_colors) { + while (nb_qe_colors > nb_default_colors) { + nb_qe_colors--; + qe_free(unconst(char **)&qe_colors[nb_qe_colors].name); + } + qe_free(&qe_colors); + qe_colors = unconst(ColorDef *)default_colors; + } +} + +/* XXX: make HTML parsing optional ? */ +int css_get_color(QEColor *color_ptr, const char *p) +{ + ColorDef const *def; + int count, index, len, v, i, n; + unsigned char rgba[4]; + + /* search in tables */ + def = qe_colors; + count = nb_qe_colors; + index = css_lookup_color(def, count, p); + if (index >= 0) { + *color_ptr = def[index].color; + return 0; + } + + rgba[3] = 0xff; + if (qe_isxdigit((unsigned char)*p)) { + goto parse_num; + } else + if (*p == '#') { + /* handle '#' notation */ + p++; + parse_num: + len = strlen(p); + switch (len) { + case 3: + for (i = 0; i < 3; i++) { + v = qe_digit_value(*p++); + rgba[i] = v | (v << 4); + } + break; + case 6: + for (i = 0; i < 3; i++) { + v = qe_digit_value(*p++) << 4; + v |= qe_digit_value(*p++); + rgba[i] = v; + } + break; + default: + /* error */ + return -1; + } + } else + if (strstart(p, "rgb(", &p)) { + n = 3; + goto parse_rgba; + } else + if (strstart(p, "rgba(", &p)) { + /* extension for alpha */ + n = 4; + parse_rgba: + for (i = 0; i < n; i++) { + /* XXX: floats ? */ + qe_skip_spaces(&p); + v = strtol_c(p, &p, 0); + if (*p == '%') { + v = (v * 255) / 100; + p++; + } + rgba[i] = v; + if (qe_skip_spaces(&p) == ',') + p++; + } + } else { + return -1; + } + *color_ptr = (rgba[0] << 16) | (rgba[1] << 8) | + (rgba[2]) | (rgba[3] << 24); + return 0; +} + +/* return 0 if unknown font */ +int css_get_font_family(const char *str) +{ + int v; + + if (!strcasecmp(str, "serif") || + !strcasecmp(str, "times")) + v = QE_FONT_FAMILY_SERIF; + else + if (!strcasecmp(str, "sans") || + !strcasecmp(str, "arial") || + !strcasecmp(str, "helvetica")) + v = QE_FONT_FAMILY_SANS; + else + if (!strcasecmp(str, "fixed") || + !strcasecmp(str, "monospace") || + !strcasecmp(str, "courier")) + v = QE_FONT_FAMILY_FIXED; + else + v = 0; /* inherit */ + return v; +} +#endif /* style stuff */ + +/* scans a comma separated list of entries, return index of match or -1 */ +/* CG: very similar to strfind */ +int css_get_enum(const char *str, const char *enum_str) { + int val, len; + const char *s, *s0; + + len = strlen(str); + s = enum_str; + val = 0; + for (;;) { + for (s0 = s; *s && *s != ','; s++) + continue; + if ((s - s0) == len && !memcmp(s0, str, len)) + return val; + if (!*s) + break; + s++; + val++; + } + return -1; +} + +/* a = a union b */ +void css_union_rect(CSSRect *a, const CSSRect *b) +{ + if (css_is_null_rect(b)) + return; + if (css_is_null_rect(a)) { + *a = *b; + } else { + if (b->x1 < a->x1) + a->x1 = b->x1; + if (b->y1 < a->y1) + a->y1 = b->y1; + if (b->x2 > a->x2) + a->x2 = b->x2; + if (b->y2 > a->y2) + a->y2 = b->y2; + } +} diff --git a/color.h b/color.h new file mode 100644 index 0000000..ae4dea6 --- /dev/null +++ b/color.h @@ -0,0 +1,237 @@ +/* + * Color / CSS Utilities for qemacs. + * + * Copyright (c) 2000-2001 Fabrice Bellard. + * Copyright (c) 2000-2022 Charlie Gordon. + * + * 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. + */ + +#ifndef COLOR_H +#define COLOR_H + +#include + +typedef int (CSSAbortFunc)(void *); + +/* media definitions */ +#define CSS_MEDIA_TTY 0x0001 +#define CSS_MEDIA_SCREEN 0x0002 +#define CSS_MEDIA_PRINT 0x0004 +#define CSS_MEDIA_TV 0x0008 +#define CSS_MEDIA_SPEECH 0x0010 + +#define CSS_MEDIA_ALL 0xffff + +typedef struct CSSRect { + int x1, y1, x2, y2; +} CSSRect; + +typedef unsigned int QEColor; +#define QEARGB(a,r,g,b) (((unsigned int)(a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define QERGB(r,g,b) QEARGB(0xff, r, g, b) +#define QERGB25(r,g,b) QEARGB(1, r, g, b) +#define COLOR_TRANSPARENT 0 +#define QERGB_ALPHA(c) (((c) >> 24) & 255) +#define QERGB_RED(c) (((c) >> 16) & 255) +#define QERGB_GREEN(c) (((c) >> 8) & 255) +#define QERGB_BLUE(c) (((c) >> 0) & 255) + +/* A qemacs style is a named set of attributes including: + * - colors for foreground and background + * - font style bits + * - font style size + * + * Styles are applied to text in successive phases: + * - the current syntax mode computes style numbers for each character + * on the line. These nubers are stored into the high bits of the + * 32-bit code point. + * - these style numbers are then extracted into an array of 32-bit composite + * style values. + * - the styles from the optional style buffer are combined into these style + * values. + * - search matches and selection styles are applied if relevant. + * - the bidirectional algorithm is applied to compute the display order + * - sequences of code-point with the same compsite style are formed into + * display units, ligatures are applied. + * - the composite style is expanded and converted into display attributes + * to trace the display unit on the device surface + */ + +/* Style numbers are limited to 8 bits, the default set has 27 entries */ +/* Composite styles are 32-bit values that specify + * - a style number + * - display attributes for underline, bold, blink + * - text and background colors as either palette numbers or 4096 rgb values + */ + +#if 0 /* 25-bit color for FG and BG */ + +#define QE_TERM_STYLE_BITS 64 +typedef uint64_t QETermStyle; +#define QE_STYLE_NUM 0x00FF +#define QE_STYLE_SEL 0x02000000 /* special selection style (cumulative with another style) */ +#define QE_TERM_COMPOSITE 0x04000000 /* special bit to indicate qe-term composite style */ +/* XXX: reversed as attribute? */ +/* XXX: faint? */ +#define QE_TERM_UNDERLINE 0x08000000 +#define QE_TERM_BOLD 0x10000000 +#define QE_TERM_ITALIC 0x20000000 +#define QE_TERM_BLINK 0x40000000 +#define QE_TERM_BG_BITS 25 +#define QE_TERM_BG_SHIFT 32 +#define QE_TERM_FG_BITS 25 +#define QE_TERM_FG_SHIFT 0 + +#elif 1 /* 8K colors for FG and BG */ + +#define QE_TERM_STYLE_BITS 32 +typedef uint32_t QETermStyle; +#define QE_STYLE_NUM 0x00FF +#define QE_STYLE_SEL 0x02000 /* special selection style (cumulative with another style) */ +#define QE_TERM_COMPOSITE 0x04000 /* special bit to indicate qe-term composite style */ +#define QE_TERM_UNDERLINE 0x08000 +#define QE_TERM_BOLD 0x10000 +#define QE_TERM_ITALIC 0x20000 +#define QE_TERM_BLINK 0x40000 +#define QE_TERM_BG_BITS 13 +#define QE_TERM_BG_SHIFT 19 +#define QE_TERM_FG_BITS 13 +#define QE_TERM_FG_SHIFT 0 + +#elif 1 /* 256 colors for FG and BG */ + +#define QE_TERM_STYLE_BITS 32 +typedef uint32_t QETermStyle; +#define QE_STYLE_NUM 0x00FF +#define QE_STYLE_SEL 0x0100 /* special selection style (cumulative with another style) */ +#define QE_TERM_COMPOSITE 0x0200 /* special bit to indicate qe-term composite style */ +#define QE_TERM_UNDERLINE 0x0400 +#define QE_TERM_BOLD 0x0800 +#define QE_TERM_ITALIC 0x1000 +#define QE_TERM_BLINK 0x2000 +#define QE_TERM_BG_BITS 8 +#define QE_TERM_BG_SHIFT 16 +#define QE_TERM_FG_BITS 8 +#define QE_TERM_FG_SHIFT 0 + +#else /* 16 colors for FG and 16 color BG */ + +#define QE_TERM_STYLE_BITS 16 +typedef uint16_t QETermStyle; +#define QE_STYLE_NUM 0x00FF +#define QE_STYLE_SEL 0x0100 /* special selection style (cumulative with another style) */ +#define QE_TERM_COMPOSITE 0x0200 /* special bit to indicate qe-term composite style */ +#define QE_TERM_UNDERLINE 0x0400 +#define QE_TERM_BOLD 0x0800 +#define QE_TERM_ITALIC 0x1000 +#define QE_TERM_BLINK 0x2000 +#define QE_TERM_BG_BITS 4 +#define QE_TERM_BG_SHIFT 0 +#define QE_TERM_FG_BITS 4 +#define QE_TERM_FG_SHIFT 4 + +#endif + +#define QE_TERM_DEF_FG 7 +#define QE_TERM_DEF_BG 0 +#define QE_TERM_BG_COLORS (1 << QE_TERM_BG_BITS) +#define QE_TERM_FG_COLORS (1 << QE_TERM_FG_BITS) +#define QE_TERM_BG_MASK ((QETermStyle)(QE_TERM_BG_COLORS - 1) << QE_TERM_BG_SHIFT) +#define QE_TERM_FG_MASK ((QETermStyle)(QE_TERM_FG_COLORS - 1) << QE_TERM_FG_SHIFT) +#define QE_TERM_MAKE_COLOR(fg, bg) (((QETermStyle)(fg) << QE_TERM_FG_SHIFT) | ((QETermStyle)(bg) << QE_TERM_BG_SHIFT)) +#define QE_TERM_SET_FG(col, fg) ((col) = ((col) & ~QE_TERM_FG_MASK) | ((QETermStyle)(fg) << QE_TERM_FG_SHIFT)) +#define QE_TERM_SET_BG(col, bg) ((col) = ((col) & ~QE_TERM_BG_MASK) | ((QETermStyle)(bg) << QE_TERM_BG_SHIFT)) +#define QE_TERM_GET_FG(color) (((color) & QE_TERM_FG_MASK) >> QE_TERM_FG_SHIFT) +#define QE_TERM_GET_BG(color) (((color) & QE_TERM_BG_MASK) >> QE_TERM_BG_SHIFT) + +typedef struct ColorDef { + const char *name; + unsigned int color; +} ColorDef; + +extern QEColor const xterm_colors[]; +extern ColorDef *qe_colors; +extern int nb_qe_colors; + +/* XXX: should have a more generic API with precomputed mapping scales */ +/* Convert RGB triplet to a composite color */ +unsigned int qe_map_color(QEColor color, QEColor const *colors, int count, int *dist); +/* Convert a composite color to an RGB triplet */ +QEColor qe_unmap_color(int color, int count); + +int css_define_color(const char *name, const char *value); +int css_get_color(QEColor *color_ptr, const char *p); +void css_free_colors(void); +int css_get_font_family(const char *str); +int css_get_enum(const char *str, const char *enum_str); +void css_union_rect(CSSRect *a, const CSSRect *b); +static inline int css_is_null_rect(const CSSRect *a) { + return (a->x2 <= a->x1 || a->y2 <= a->y1); +} +static inline void css_set_rect(CSSRect *a, int x1, int y1, int x2, int y2) { + a->x1 = x1; + a->y1 = y1; + a->x2 = x2; + a->y2 = y2; +} +/* return true if a and b intersect */ +static inline int css_is_inter_rect(const CSSRect *a, const CSSRect *b) { + return (!(a->x2 <= b->x1 || + a->x1 >= b->x2 || + a->y2 <= b->y1 || + a->y1 >= b->y2)); +} + +/*---- Font definitions ----*/ + +#define QE_FONT_STYLE_NORM 0x0001 +#define QE_FONT_STYLE_BOLD 0x0002 +#define QE_FONT_STYLE_ITALIC 0x0004 +#define QE_FONT_STYLE_UNDERLINE 0x0008 +#define QE_FONT_STYLE_LINE_THROUGH 0x0010 +#define QE_FONT_STYLE_BLINK 0x0020 +#define QE_FONT_STYLE_MASK 0x00ff + +#define NB_FONT_FAMILIES 3 +#define QE_FONT_FAMILY_SHIFT 8 +#define QE_FONT_FAMILY_MASK 0xff00 +#define QE_FONT_FAMILY_FIXED 0x0100 +#define QE_FONT_FAMILY_SERIF 0x0200 +#define QE_FONT_FAMILY_SANS 0x0300 /* sans serif */ + +/* fallback font handling */ +#define QE_FONT_FAMILY_FALLBACK_SHIFT 16 +#define QE_FONT_FAMILY_FALLBACK_MASK 0xff0000 + +typedef struct QEFont { + int refcount; + int ascent; + int descent; + void *priv_data; + int system_font; /* TRUE if system font */ + /* cache data */ + int style; + int size; + int timestamp; +} QEFont; + +typedef struct QECharMetrics { + int font_ascent; /* maximum font->ascent */ + int font_descent; /* maximum font->descent */ + int width; /* sum of glyph widths */ +} QECharMetrics; + +#endif /* COLOR_H */ diff --git a/cutils.h b/cutils.h index d2e4bc9..c58403b 100644 --- a/cutils.h +++ b/cutils.h @@ -22,8 +22,9 @@ #ifndef CUTILS_H #define CUTILS_H -#include #include +#include +#include /* this cast prevents compiler warnings when removing the const qualifier */ #define unconst(t) (t)(uintptr_t) diff --git a/display.h b/display.h index c7fd0d0..83db8b8 100644 --- a/display.h +++ b/display.h @@ -25,43 +25,6 @@ #define MAX_SCREEN_WIDTH 1024 /* in chars */ #define MAX_SCREEN_LINES 256 /* in text lines */ -#define QE_FONT_STYLE_NORM 0x0001 -#define QE_FONT_STYLE_BOLD 0x0002 -#define QE_FONT_STYLE_ITALIC 0x0004 -#define QE_FONT_STYLE_UNDERLINE 0x0008 -#define QE_FONT_STYLE_LINE_THROUGH 0x0010 -#define QE_FONT_STYLE_BLINK 0x0020 -#define QE_FONT_STYLE_MASK 0x00ff - -#define NB_FONT_FAMILIES 3 -#define QE_FONT_FAMILY_SHIFT 8 -#define QE_FONT_FAMILY_MASK 0xff00 -#define QE_FONT_FAMILY_FIXED 0x0100 -#define QE_FONT_FAMILY_SERIF 0x0200 -#define QE_FONT_FAMILY_SANS 0x0300 /* sans serif */ - -/* fallback font handling */ -#define QE_FONT_FAMILY_FALLBACK_SHIFT 16 -#define QE_FONT_FAMILY_FALLBACK_MASK 0xff0000 - -typedef struct QEFont { - int refcount; - int ascent; - int descent; - void *priv_data; - int system_font; /* TRUE if system font */ - /* cache data */ - int style; - int size; - int timestamp; -} QEFont; - -typedef struct QECharMetrics { - int font_ascent; /* maximum font->ascent */ - int font_descent; /* maximum font->descent */ - int width; /* sum of glyph widths */ -} QECharMetrics; - typedef enum QEBitmapFormat { QEBITMAP_FORMAT_1BIT = 0, QEBITMAP_FORMAT_4BIT, diff --git a/libqhtml/Makefile b/libqhtml/Makefile index 8ec7292..4a80058 100644 --- a/libqhtml/Makefile +++ b/libqhtml/Makefile @@ -1,7 +1,7 @@ # Libqhtml tiny HTML/CSS rendering library for QEmacs # # Copyright (c) 2000-2002 Fabrice Bellard. -# Copyright (c) 2000-2021 Charlie Gordon. +# Copyright (c) 2000-2022 Charlie Gordon. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -113,7 +113,7 @@ docbook_style.c: docbook.css $(BINDIR)/csstoqe$(EXE) Makefile $(BINDIR)/csstoqe docbook_style < $< > $@ clean: - rm -rf *.dSYM $(OBJS_DIR) + rm -rf *.dSYM *.gch $(OBJS_DIR) rm -f *~ *.o *.a *.exe *_g TAGS gmon.out core *.exe.stackdump \ csstoqe html_style.c docbook_style.c diff --git a/libqhtml/css.h b/libqhtml/css.h index 06de443..c548418 100644 --- a/libqhtml/css.h +++ b/libqhtml/css.h @@ -22,6 +22,9 @@ #ifndef CSS_H #define CSS_H +#include +#include "color.h" + struct CSSBox; typedef struct CSSBox CSSBox; @@ -564,7 +567,7 @@ typedef struct CSSCounterValue { typedef struct CSSContext { CSSStyleSheet *style_sheet; - QEditScreen *screen; + struct QEditScreen *screen; /* various default settings */ /* XXX: use style sheet ? */ int selection_bgcolor; @@ -572,7 +575,7 @@ typedef struct CSSContext { int default_bgcolor; /* edit buffer */ - EditBuffer *b; + struct EditBuffer *b; /* selection handling */ int selection_start, selection_end; /* private content */ @@ -597,8 +600,8 @@ typedef struct CSSContext { void css_init(void); -CSSContext *css_new_document(QEditScreen *screen, - EditBuffer *b); +CSSContext *css_new_document(struct QEditScreen *screen, + struct EditBuffer *b); void css_delete_document(CSSContext **sp); int css_compute(CSSContext *s, CSSBox *box); @@ -626,7 +629,7 @@ int css_box_iterate(CSSContext *s, CSSBox *box, void *opaque, CSSBox *css_new_box(CSSIdent tag, CSSAttribute *attrs); CSSBox *css_add_box(CSSBox *parent_box, CSSBox *box); void css_delete_box(CSSBox **boxp); -void css_set_text_buffer(CSSBox *box, EditBuffer *b, +void css_set_text_buffer(CSSBox *box, struct EditBuffer *b, int offset1, int offset2, int eol); void css_set_text_string(CSSBox *box, const char *string); void css_make_child_box(CSSBox *box); @@ -639,6 +642,7 @@ void css_dump(CSSBox *box); /* XML parser */ struct XMLState; typedef struct XMLState XMLState; +typedef const struct QECharset QECharset; #define XML_HTML 0x0001 /* enable html tag interpretation which cannot be specified in a stylesheet */ @@ -652,7 +656,7 @@ XMLState *xml_begin(CSSStyleSheet *style_sheet, int flags, int xml_parse(XMLState *s, char *buf, int buf_len); CSSBox *xml_end(XMLState **sp); -CSSBox *xml_parse_buffer(EditBuffer *b, int offset_start, int offset_end, +CSSBox *xml_parse_buffer(struct EditBuffer *b, int offset_start, int offset_end, CSSStyleSheet *style_sheet, int flags, CSSAbortFunc *abort_func, void *abort_opaque); int find_entity(const char *str); diff --git a/libqhtml/cssparse.c b/libqhtml/cssparse.c index 779289b..761069b 100644 --- a/libqhtml/cssparse.c +++ b/libqhtml/cssparse.c @@ -18,8 +18,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "qe.h" -#include "qfribidi.h" +#include + +#include "cutils.h" +#include "util.h" #include "css.h" //#define DEBUG diff --git a/libqhtml/csstoqe.c b/libqhtml/csstoqe.c index c08efc0..b6cd590 100644 --- a/libqhtml/csstoqe.c +++ b/libqhtml/csstoqe.c @@ -3,7 +3,7 @@ * linked with qemacs * * Copyright (c) 2002 Fabrice Bellard. - * Copyright (c) 2007-2017 Charlie Gordon. + * Copyright (c) 2007-2022 Charlie Gordon. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -64,7 +64,6 @@ int main(int argc, char **argv) printf("/* Automatically generated file - do not edit */\n" "\n" - "#include \"qe.h\"\n" "#include \"css.h\"\n" "\n"); printf("const char %s[] = {\n", argv[1]); diff --git a/qe-manual.md b/qe-manual.md index 5af6813..13d4bbc 100644 --- a/qe-manual.md +++ b/qe-manual.md @@ -79,6 +79,137 @@ If the RENAMEFILE argument is not null and starts with 'y', an attempt is made to rename the old visited file to the new name FILENAME. +### `void qe_free(T **pp);` + +Free the allocated memory pointed to by a pointer whose address is passed. + +* argument `pp` the address of a possibly null pointer. This pointer is set +to `NULL` after freeing the memory. If the pointer memory is null, +nothing happens. + +* argument `n` the number of bytes to allocate in addition to the size of type `T`. + +Note: this function is implemented as a macro. + +### `T *qe_malloc(type T);` + +Allocate memory for an object of type `T`. + +* argument `T` the type of the object to allocate. + +Note: this function is implemented as a macro. + +### `T *qe_malloc_array(type T, size_t n);` + +Allocate memory for an array of objects of type `T`. + +* argument `T` the type of the object to allocate. + +* argument `n` the number of elements to allocate. + +Note: this function is implemented as a macro. + +### `void *qe_malloc_bytes(size_t size);` + +Allocate an uninitialized block of memory of a given size in +bytes. + +* argument `size` the number of bytes to allocate. + +Return a pointer to allocated memory, aligned on the maximum +alignment size. + +### `void *qe_malloc_dup(const void *src, size_t size);` + +Allocate a block of memory of a given size in bytes initialized +as a copy of an existing object. + +* argument `src` a valid pointer to the object to duplicate. + +* argument `size` the number of bytes to allocate. + +Return a pointer to allocated memory, aligned on the maximum +alignment size. + +### `T *qe_malloc_hack(type T, size_t n);` + +Allocate memory for an object of type `T` with `n` extra bytes. + +* argument `T` the type of the object to allocate. + +* argument `n` the number of bytes to allocate in addition to the size of type `T`. + +Note: this function is implemented as a macro. + +### `T *qe_mallocz(type T);` + +Allocate memory for an object of type `T`. +The object is initialized to all bits zero. + +* argument `T` the type of the object to allocate. + +Note: this function is implemented as a macro. + +### `T *qe_mallocz_array(type T, size_t n);` + +Allocate memory for an array of objects of type `T`. +The objects are initialized to all bits zero. + +* argument `T` the type of the object to allocate. + +* argument `n` the number of elements to allocate. + +Note: this function is implemented as a macro. + +### `T *qe_mallocz_array(type T, size_t n);` + +Allocate memory for an object of type `T` with `n` extra bytes. +The object and the extra space is initialized to all bits zero. + +* argument `T` the type of the object to allocate. + +* argument `n` the number of bytes to allocate in addition to the size of type `T`. + +Note: this function is implemented as a macro. + +### `void *qe_mallocz_bytes(size_t size);` + +Allocate a block of memory of a given size in bytes initialized +to all bits zero. + +* argument `size` the number of bytes to allocate. + +Return a pointer to allocated memory, aligned on the maximum +alignment size. + +### `void *qe_realloc(void *pp, size_t size);` + +reallocate a block of memory to a different size. + +* argument `pp` the address of a possibly null pointer to a +block to reallocate. `pp` is updated with the new pointer +if reallocation is successful. + +* argument `size` the new size for the object. + +Return a pointer to allocated memory, aligned on the maximum +alignment size. + +Note: this API makes it easier to check for success separately +from modifying the existing pointer, which is unchanged if +reallocation fails. This approach is not strictly conforming, +it assumes all pointers have the same size and representation, +which is mandated by POSIX. + +### `char *qe_strdup(const char *str);` + +Allocate a copy of a string. + +* argument `src` a valid pointer to a string to duplicate. + +Return a pointer to allocated memory, aligned on the maximum +alignment size. + ### `int append_slash(char *buf, int buf_size);` Append a trailing slash to a path if none there already. @@ -316,9 +447,12 @@ Note: truncation cannot be detected reliably. Copy the string pointed by `str` to the destination array `buf`, of length `size` bytes, truncating excess bytes. -@param `buf` destination array, must be a valid pointer. -@param `size` length of destination array. -@param `str` pointer to a source string, must be a valid pointer. + +* argument `buf` destination array, must be a valid pointer. + +* argument `size` length of destination array. + +* argument `str` pointer to a source string, must be a valid pointer. Return a pointer to the destination array. @@ -365,6 +499,31 @@ Return a positive value if the first block compares above the second. Note: this version only handles ASCII. +### `void qe_qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compare)(void *, const void *, const void *));` + +Sort an array using a comparison function with an extra opaque +argument. + +* argument `base` a valid pointer to an array of objects, + +* argument `nmemb` the number of elements in the array, + +* argument `size` the object size in bytes, + +* argument `thunk` the generic argument to pass to the comparison +function, + +* argument `compare` a function pointer for a comparison function +taking 3 arguments: the `thunk` argument and pointers to 2 +objects from the array, returning an integer whose sign indicates +their relative position according to the sort order. + +Note: this function behaves like OpenBSD's `qsort_r()`, the +implementation is non recursive using a combination of quicksort +and insertion sort for small chunks. The GNU lib C on linux also +has a function `qsort_r()` with similar semantics but a different +calling convention. + ### `int qe_skip_spaces(const char **pp);` Skip white space at the beginning of the string pointed to by `*pp`. @@ -439,9 +598,12 @@ Check if `val` is a suffix of `str`. In this case, a pointer to the first character of the suffix in `str` is stored into `ptr` provided `ptr` is not a null pointer. -@param `str` input string, must be a valid pointer. -@param `val` suffix to test, must be a valid pointer. -@param `ptr` updated to the suffix in `str` if there is a match. + +* argument `str` input string, must be a valid pointer. + +* argument `val` suffix to test, must be a valid pointer. + +* argument `ptr` updated to the suffix in `str` if there is a match. Return `true` if there is a match, `false` otherwise. @@ -466,9 +628,12 @@ Leading dots are skipped, they are not considered part of an extension. Test if `val` is a prefix of `str` (case independent). If there is a match, a pointer to the next character after the match in `str` is stored into `ptr` provided `ptr` is not null. -@param `str` valid string pointer, -@param `val` valid string pointer to the prefix to test, -@param `ptr` a possibly null pointer to a `const char *` to set + +* argument `str` valid string pointer, + +* argument `val` valid string pointer to the prefix to test, + +* argument `ptr` a possibly null pointer to a `const char *` to set to point after the prefix in `str` in there is a match. Return `true` if there is a match, `false` otherwise. @@ -482,9 +647,12 @@ in `str` into `ptr` provided `ptr` is not a null pointer. If `val` is not a word prefix of `str`, return `false` and leave `*ptr` unchanged. -@param `str` a valid string pointer. -@param `val` a valid string pointer for the prefix to test. -@param `ptr` updated with a pointer past the prefix in `str` if found. + +* argument `str` a valid string pointer. + +* argument `val` a valid string pointer for the prefix to test. + +* argument `ptr` updated with a pointer past the prefix in `str` if found. Return `true` if there is a match, `false` otherwise. @@ -510,9 +678,12 @@ stored into `ptr` provided `ptr` is not a null pointer. If `val` is not a prefix of `str`, return `0` and leave `*ptr` unchanged. -@param `str` input string, must be a valid pointer. -@param `val` prefix to test, must be a valid pointer. -@param `ptr` updated with a pointer past the prefix if found. + +* argument `str` input string, must be a valid pointer. + +* argument `val` prefix to test, must be a valid pointer. + +* argument `ptr` updated with a pointer past the prefix if found. Return `true` if there is a match, `false` otherwise. @@ -540,8 +711,10 @@ Call this function with a constant string and the address of a `const char *`. Compare strings case independently, also ignoring spaces, dashes and underscores. -@param `str1` a valid string pointer for the left operand. -@param `str2` a valid string pointer for the right operand. + +* argument `str1` a valid string pointer for the left operand. + +* argument `str2` a valid string pointer for the right operand. Return a negative, 0 or positive value reflecting the sign of `str1 <=> str2` @@ -564,9 +737,12 @@ Test if `val` is a prefix of `str` (case independent and ignoring `-`, `_` and spaces). If there is a match, a pointer to the next character after the match in `str` is stored into `ptr`, provided `ptr` is not null. -@param `str` valid string pointer, -@param `val` valid string pointer to the prefix to test, -@param `ptr` a possibly null pointer to a `const char *` to set + +* argument `str` valid string pointer, + +* argument `val` valid string pointer to the prefix to test, + +* argument `ptr` a possibly null pointer to a `const char *` to set to point after the prefix in `str` in there is a match. Return `true` if there is a match, `false` otherwise. diff --git a/qe.c b/qe.c index a870bf1..93e21bf 100644 --- a/qe.c +++ b/qe.c @@ -695,6 +695,24 @@ void do_cd(EditState *s, const char *path) } } +static void color_complete(CompleteState *cp) { + ColorDef const *def; + int count; + + def = qe_colors; + count = nb_qe_colors; + while (count > 0) { + if (strxstart(def->name, cp->current, NULL)) + add_string(&cp->cs, def->name, 0); + def++; + count--; + } +} + +static CompletionDef color_completion = { + "color", color_complete +}; + /* basic editing functions */ void do_bof(EditState *s) @@ -7391,6 +7409,18 @@ static int is_abs_path(const char *path) return 0; } +#ifdef CONFIG_WIN32 +/* convert '\' to '/' */ +static void path_win_to_unix(char *buf) { + char *p; + + for (p = buf; *p; p++) { + if (*p == '\\') + *p = '/'; + } +} +#endif + /* canonicalize the path for a given window and make it absolute */ void canonicalize_absolute_path(EditState *s, char *buf, int buf_size, const char *path1) { @@ -9583,10 +9613,6 @@ static CompletionDef charset_completion = { "charset", charset_complete }; -static CompletionDef color_completion = { - "color", color_complete -}; - /* init function */ static void qe_init(void *opaque) { @@ -9598,9 +9624,12 @@ static void qe_init(void *opaque) EditBuffer *b; QEDisplay *dpy; int i, _optind; -#if !defined(CONFIG_TINY) && !defined(CONFIG_WIN32) +#if !defined(CONFIG_TINY) int session_loaded = 0; #endif +#if defined(CONFIG_ALL_KMAPS) || defined(CONFIG_UNICODE_JOIN) + char filename[MAX_FILENAME_SIZE]; +#endif qs->ec.function = "qe-init"; qs->macro_key_index = -1; /* no macro executing */ @@ -9624,19 +9653,14 @@ static void qe_init(void *opaque) eb_init(); charset_init(); init_input_methods(); + #ifdef CONFIG_ALL_KMAPS - { - char filename[MAX_FILENAME_SIZE]; - if (find_resource_file(filename, sizeof(filename), "kmaps") >= 0) - load_input_methods(filename); - } + if (find_resource_file(filename, sizeof(filename), "kmaps") >= 0) + load_input_methods(filename); #endif #ifdef CONFIG_UNICODE_JOIN - { - char filename[MAX_FILENAME_SIZE]; - if (find_resource_file(filename, sizeof(filename), "ligatures") >= 0) - load_ligatures(filename); - } + if (find_resource_file(filename, sizeof(filename), "ligatures") >= 0) + load_ligatures(filename); #endif /* init basic modules */ @@ -9644,18 +9668,18 @@ static void qe_init(void *opaque) qe_register_commands(NULL, basic_commands, countof(basic_commands)); qe_register_cmd_line_options(cmd_options); - qe_register_completion(&command_completion); + qe_register_completion(&buffer_completion); qe_register_completion(&charset_completion); + qe_register_completion(&color_completion); + qe_register_completion(&command_completion); + qe_register_completion(&file_completion); qe_register_completion(&mode_completion); qe_register_completion(&style_completion); qe_register_completion(&style_property_completion); - qe_register_completion(&file_completion); #ifndef CONFIG_TINY qe_register_completion(&dir_completion); qe_register_completion(&resource_completion); #endif - qe_register_completion(&buffer_completion); - qe_register_completion(&color_completion); minibuffer_init(); list_init(); @@ -9761,7 +9785,7 @@ static void qe_init(void *opaque) do_goto_line(s, line_num, col_num); } -#if !defined(CONFIG_TINY) && !defined(CONFIG_WIN32) +#if !defined(CONFIG_TINY) #if defined(CONFIG_FFMPEG) /* Force is_player if invoked as ffplay */ if (strequal(get_basename(argv[0]), "ffplay")) diff --git a/qe.h b/qe.h index 4ee754e..f3b152c 100644 --- a/qe.h +++ b/qe.h @@ -22,19 +22,19 @@ #ifndef QE_H #define QE_H -#include -#include -#include +#include +#include +#include #include +#include +#include +#include #include #include #include #include -#include #include -#include -#include -#include +#include #include #if 1 //ifdef HAVE_QE_CONFIG_H @@ -51,83 +51,13 @@ #define DEFAULT_FILL_COLUMN 70 #endif -/* OS specific defines */ - -#ifdef CONFIG_WIN32 -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#endif - -#if (defined(__GNUC__) || defined(__TINYC__)) -/* make sure that the keyword is not disabled by glibc (TINYC case) */ -#define qe__attr_printf(a, b) __attribute__((format(printf, a, b))) -#else -#define qe__attr_printf(a, b) -#endif - -#if defined(__GNUC__) && __GNUC__ > 2 -#define qe__attr_nonnull(l) __attribute__((nonnull l)) -#define qe__unused__ __attribute__((unused)) -#else -#define qe__attr_nonnull(l) -#define qe__unused__ -#endif - -#ifndef offsetof -#define offsetof(s,m) ((size_t)(&((s *)0)->m)) -#endif -#ifndef countof -#define countof(a) ((int)(sizeof(a) / sizeof((a)[0]))) -#endif -#ifndef ssizeof -#define ssizeof(a) ((int)(sizeof(a))) -#endif - -#define OWNED /* ptr attribute for allocated data owned by a structure */ - -/* prevent gcc warning about shadowing a global declaration */ -#define index index__ - /************************/ #include "cutils.h" +#include "util.h" /************************/ -/* allocation wrappers and utilities */ -void *qe_malloc_bytes(size_t size); -void *qe_mallocz_bytes(size_t size); -void *qe_malloc_dup(const void *src, size_t size); -char *qe_strdup(const char *str); -void *qe_realloc(void *pp, size_t size); -#define qe_malloc(t) ((t *)qe_malloc_bytes(sizeof(t))) -#define qe_mallocz(t) ((t *)qe_mallocz_bytes(sizeof(t))) -#define qe_malloc_array(t, n) ((t *)qe_malloc_bytes((n) * sizeof(t))) -#define qe_mallocz_array(t, n) ((t *)qe_mallocz_bytes((n) * sizeof(t))) -#define qe_malloc_hack(t, n) ((t *)qe_malloc_bytes(sizeof(t) + (n))) -#define qe_mallocz_hack(t, n) ((t *)qe_mallocz_bytes(sizeof(t) + (n))) - -#if 1 // to test clang -Weverything -#define qe_free(pp) do { void *_ = (pp); (free)(*(void **)_); *(void **)_ = NULL; } while (0) -#elif defined CONFIG_HAS_TYPEOF -#define qe_free(pp) do { typeof(**(pp)) **__ = (pp); (free)(*__); *__ = NULL; } while (0) -#else -#define qe_free(pp) do if (sizeof(**(pp)) >= 0) { void *_ = (pp); (free)(*(void **)_); *(void **)_ = NULL; } while (0) -#endif - -#ifndef free -#define free(p) do_not_use_free!!(p) -#endif -#ifndef malloc -#define malloc(s) do_not_use_malloc!!(s) -#endif -#ifndef realloc -#define realloc(p,s) do_not_use_realloc!!(p,s) -#endif - -/************************/ - -typedef unsigned char u8; typedef struct EditState EditState; typedef struct EditBuffer EditBuffer; typedef struct QEmacsState QEmacsState; @@ -142,15 +72,13 @@ typedef struct InputMethod InputMethod; typedef struct ISearchState ISearchState; typedef struct QEProperty QEProperty; -static inline char *s8(u8 *p) { return (char*)p; } -static inline const char *cs8(const u8 *p) { return (const char*)p; } - #ifndef INT_MAX #define INT_MAX 0x7fffffff #endif #ifndef INT_MIN #define INT_MIN (-0x7fffffff-1) #endif + #define NO_ARG INT_MIN #define HAS_ARG_NUMERIC 0x100 #define HAS_ARG_SIGN 0x200 @@ -179,23 +107,10 @@ void qe_kill_timer(QETimer **tip); /* main loop for Unix programs using liburlio */ void url_main_loop(void (*init)(void *opaque), void *opaque); -/* util.c */ - -/* string arrays */ -typedef struct StringItem { - void *opaque; /* opaque data that the user can use */ - char selected; /* true if selected */ - char group; /* used to group sorted items */ - char str[1]; -} StringItem; - -typedef struct StringArray { - int nb_allocated; - int nb_items; - StringItem **items; -} StringArray; -#define NULL_STRINGARRAY { 0, 0, NULL } +int get_clock_ms(void); +int get_clock_usec(void); +/* extendable completion system */ typedef struct CompleteState { StringArray cs; struct EditState *s; @@ -205,440 +120,12 @@ typedef struct CompleteState { char current[MAX_FILENAME_SIZE]; } CompleteState; -/* media definitions */ -#define CSS_MEDIA_TTY 0x0001 -#define CSS_MEDIA_SCREEN 0x0002 -#define CSS_MEDIA_PRINT 0x0004 -#define CSS_MEDIA_TV 0x0008 -#define CSS_MEDIA_SPEECH 0x0010 - -#define CSS_MEDIA_ALL 0xffff - -typedef struct CSSRect { - int x1, y1, x2, y2; -} CSSRect; - -typedef unsigned int QEColor; -#define QEARGB(a,r,g,b) (((unsigned int)(a) << 24) | ((r) << 16) | ((g) << 8) | (b)) -#define QERGB(r,g,b) QEARGB(0xff, r, g, b) -#define QERGB25(r,g,b) QEARGB(1, r, g, b) -#define COLOR_TRANSPARENT 0 -#define QERGB_ALPHA(c) (((c) >> 24) & 255) -#define QERGB_RED(c) (((c) >> 16) & 255) -#define QERGB_GREEN(c) (((c) >> 8) & 255) -#define QERGB_BLUE(c) (((c) >> 0) & 255) - -/* A qemacs style is a named set of attributes including: - * - colors for foreground and background - * - font style bits - * - font style size - * - * Styles are applied to text in successive phases: - * - the current syntax mode computes style numbers for each character - * on the line. These nubers are stored into the high bits of the - * 32-bit code point. - * - these style numbers are then extracted into an array of 32-bit composite - * style values. - * - the styles from the optional style buffer are combined into these style - * values. - * - search matches and selection styles are applied if relevant. - * - the bidirectional algorithm is applied to compute the display order - * - sequences of code-point with the same compsite style are formed into - * display units, ligatures are applied. - * - the composite style is expanded and converted into display attributes - * to trace the display unit on the device surface - */ - -/* Style numbers are limited to 8 bits, the default set has 27 entries */ -/* Composite styles are 32-bit values that specify - * - a style number - * - display attributes for underline, bold, blink - * - text and background colors as either palette numbers or 4096 rgb values - */ - -#if 0 /* 25-bit color for FG and BG */ - -#define QE_TERM_STYLE_BITS 64 -typedef uint64_t QETermStyle; -#define QE_STYLE_NUM 0x00FF -#define QE_STYLE_SEL 0x02000000 /* special selection style (cumulative with another style) */ -#define QE_TERM_COMPOSITE 0x04000000 /* special bit to indicate qe-term composite style */ -/* XXX: reversed as attribute? */ -/* XXX: faint? */ -#define QE_TERM_UNDERLINE 0x08000000 -#define QE_TERM_BOLD 0x10000000 -#define QE_TERM_ITALIC 0x20000000 -#define QE_TERM_BLINK 0x40000000 -#define QE_TERM_BG_BITS 25 -#define QE_TERM_BG_SHIFT 32 -#define QE_TERM_FG_BITS 25 -#define QE_TERM_FG_SHIFT 0 - -#elif 1 /* 8K colors for FG and BG */ - -#define QE_TERM_STYLE_BITS 32 -typedef uint32_t QETermStyle; -#define QE_STYLE_NUM 0x00FF -#define QE_STYLE_SEL 0x02000 /* special selection style (cumulative with another style) */ -#define QE_TERM_COMPOSITE 0x04000 /* special bit to indicate qe-term composite style */ -#define QE_TERM_UNDERLINE 0x08000 -#define QE_TERM_BOLD 0x10000 -#define QE_TERM_ITALIC 0x20000 -#define QE_TERM_BLINK 0x40000 -#define QE_TERM_BG_BITS 13 -#define QE_TERM_BG_SHIFT 19 -#define QE_TERM_FG_BITS 13 -#define QE_TERM_FG_SHIFT 0 - -#elif 1 /* 256 colors for FG and BG */ - -#define QE_TERM_STYLE_BITS 32 -typedef uint32_t QETermStyle; -#define QE_STYLE_NUM 0x00FF -#define QE_STYLE_SEL 0x0100 /* special selection style (cumulative with another style) */ -#define QE_TERM_COMPOSITE 0x0200 /* special bit to indicate qe-term composite style */ -#define QE_TERM_UNDERLINE 0x0400 -#define QE_TERM_BOLD 0x0800 -#define QE_TERM_ITALIC 0x1000 -#define QE_TERM_BLINK 0x2000 -#define QE_TERM_BG_BITS 8 -#define QE_TERM_BG_SHIFT 16 -#define QE_TERM_FG_BITS 8 -#define QE_TERM_FG_SHIFT 0 - -#else /* 16 colors for FG and 16 color BG */ - -#define QE_TERM_STYLE_BITS 16 -typedef uint16_t QETermStyle; -#define QE_STYLE_NUM 0x00FF -#define QE_STYLE_SEL 0x0100 /* special selection style (cumulative with another style) */ -#define QE_TERM_COMPOSITE 0x0200 /* special bit to indicate qe-term composite style */ -#define QE_TERM_UNDERLINE 0x0400 -#define QE_TERM_BOLD 0x0800 -#define QE_TERM_ITALIC 0x1000 -#define QE_TERM_BLINK 0x2000 -#define QE_TERM_BG_BITS 4 -#define QE_TERM_BG_SHIFT 0 -#define QE_TERM_FG_BITS 4 -#define QE_TERM_FG_SHIFT 4 - -#endif - -#define QE_TERM_DEF_FG 7 -#define QE_TERM_DEF_BG 0 -#define QE_TERM_BG_COLORS (1 << QE_TERM_BG_BITS) -#define QE_TERM_FG_COLORS (1 << QE_TERM_FG_BITS) -#define QE_TERM_BG_MASK ((QETermStyle)(QE_TERM_BG_COLORS - 1) << QE_TERM_BG_SHIFT) -#define QE_TERM_FG_MASK ((QETermStyle)(QE_TERM_FG_COLORS - 1) << QE_TERM_FG_SHIFT) -#define QE_TERM_MAKE_COLOR(fg, bg) (((QETermStyle)(fg) << QE_TERM_FG_SHIFT) | ((QETermStyle)(bg) << QE_TERM_BG_SHIFT)) -#define QE_TERM_SET_FG(col, fg) ((col) = ((col) & ~QE_TERM_FG_MASK) | ((QETermStyle)(fg) << QE_TERM_FG_SHIFT)) -#define QE_TERM_SET_BG(col, bg) ((col) = ((col) & ~QE_TERM_BG_MASK) | ((QETermStyle)(bg) << QE_TERM_BG_SHIFT)) -#define QE_TERM_GET_FG(color) (((color) & QE_TERM_FG_MASK) >> QE_TERM_FG_SHIFT) -#define QE_TERM_GET_BG(color) (((color) & QE_TERM_BG_MASK) >> QE_TERM_BG_SHIFT) - -typedef struct FindFileState FindFileState; - -#define FF_PATH 0x010 /* enumerate path argument */ -#define FF_NODIR 0x020 /* only match regular files */ -#define FF_NOXXDIR 0x040 /* do not match . or .. */ -#define FF_ONLYDIR 0x080 /* do not match non directories */ -#define FF_DEPTH 0x00f /* max recursion depth */ - -FindFileState *find_file_open(const char *path, const char *pattern, int flags); -int find_file_next(FindFileState *s, char *filename, int filename_size_max); -void find_file_close(FindFileState **sp); -int is_directory(const char *path); -int is_filepattern(const char *filespec); -void canonicalize_path(char *buf, int buf_size, const char *path); void canonicalize_absolute_path(EditState *s, char *buf, int buf_size, const char *path1); void canonicalize_absolute_buffer_path(EditBuffer *b, int offset, char *buf, int buf_size, const char *path1); -char *make_user_path(char *buf, int buf_size, const char *path); -char *reduce_filename(char *dest, int size, const char *filename); -char *file_load(const char *filename, int max_size, int *sizep); -int match_extension(const char *filename, const char *extlist); -int match_shell_handler(const char *p, const char *list); -int remove_slash(char *buf); -int append_slash(char *buf, int buf_size); -char *makepath(char *buf, int buf_size, const char *path, const char *filename); -void splitpath(char *dirname, int dirname_size, - char *filename, int filename_size, const char *pathname); -extern unsigned char const qe_digit_value__[128]; -static inline int qe_digit_value(int c) { - return (unsigned int)c < 128 ? qe_digit_value__[c] : 255; -} -static inline int qe_inrange(int c, int a, int b) { - //return c >= a && c <= b; - //CG: assuming a <= b and wrap around semantics for (c - a) and (b - a) - return (unsigned int)(c - a) <= (unsigned int)(b - a); -} -/* character classification tests assume ASCII superset */ -static inline int qe_isspace(int c) { - /* CG: what about \v and \f */ - return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == 160); -} -static inline int qe_isblank(int c) { - return (c == ' ' || c == '\t' || c == 160); -} -static inline int qe_isdigit(int c) { - return qe_inrange(c, '0', '9'); -} -static inline int qe_isdigit_(int c) { - return (qe_inrange(c, '0', '9') || c == '_'); -} -static inline int qe_isupper(int c) { - return qe_inrange(c, 'A', 'Z'); -} -static inline int qe_isupper_(int c) { - return (qe_inrange(c, 'A', 'Z') || c == '_'); -} -static inline int qe_islower(int c) { - return qe_inrange(c, 'a', 'z'); -} -static inline int qe_islower_(int c) { - return (qe_inrange(c, 'a', 'z') || (c == '_')); -} -static inline int qe_isalpha(int c) { - return qe_inrange(c | ('a' - 'A'), 'a', 'z'); -} -static inline int qe_isalpha_(int c) { - return (qe_inrange(c | ('a' - 'A'), 'a', 'z') || c == '_'); -} -static inline int qe_isoctdigit(int c) { - return qe_inrange(c, '0', '7'); -} -static inline int qe_isoctdigit_(int c) { - return qe_inrange(c, '0', '7') || (c == '_'); -} -static inline int qe_isbindigit(int c) { - return qe_inrange(c, '0', '1'); -} -static inline int qe_isbindigit_(int c) { - return qe_inrange(c, '0', '1') || (c == '_'); -} -static inline int qe_isxdigit(int c) { - return qe_digit_value(c) < 16; -} -static inline int qe_isxdigit_(int c) { - return (qe_digit_value(c) < 16) || (c == '_'); -} -static inline int qe_isalnum(int c) { - return qe_digit_value(c) < 36; -} -static inline int qe_isalnum_(int c) { - return (qe_digit_value(c) < 36) || (c == '_'); -} -static inline int qe_isword(int c) { - /* XXX: any unicode char >= 128 is considered as word. */ - return qe_isalnum_(c) || (c >= 128); -} -static inline int qe_toupper(int c) { - return (qe_inrange(c, 'a', 'z') ? c + 'A' - 'a' : c); -} -static inline int qe_tolower(int c) { - return (qe_inrange(c, 'A', 'Z') ? c + 'a' - 'A' : c); -} -static inline int qe_findchar(const char *str, int c) { - return qe_inrange(c, 1, 255) && strchr(str, c) != NULL; -} -static inline int qe_indexof(const char *str, int c) { - if (qe_inrange(c, 1, 255)) { - const char *p = strchr(str, c); - if (p) return (int)(p - str); - } - return -1; -} - -static inline int qe_match2(int c, int c1, int c2) { - return c == c1 || c == c2; -} - -static inline int check_fcall(const unsigned int *str, int i) { - while (str[i] == ' ') - i++; - return str[i] == '('; -} - -int ustr_get_identifier(char *buf, int buf_size, int c, - const unsigned int *str, int i, int n); -int ustr_get_identifier_lc(char *buf, int buf_size, int c, - const unsigned int *str, int i, int n); -int ustr_get_word(char *buf, int buf_size, int c, - const unsigned int *str, int i, int n); - -int qe_strcollate(const char *s1, const char *s2); -int qe_strtobool(const char *s, int def); -void qe_strtolower(char *buf, int buf_size, const char *str); -int qe_skip_spaces(const char **pp); - -static inline int strequal(const char *s1, const char *s2) { - return !strcmp(s1, s2); -} - -int memfind(const char *list, const char *p, int len); -int strfind(const char *list, const char *s); -int strxfind(const char *list, const char *s); -const char *strmem(const char *str, const void *mem, int size); -const void *memstr(const void *buf, int size, const char *str); - -#define stristart(str, val, ptr) qe_stristart(str, val, ptr) -int stristart(const char *str, const char *val, const char **ptr); -int strxstart(const char *str, const char *val, const char **ptr); -int strxcmp(const char *str1, const char *str2); -int strmatchword(const char *str, const char *val, const char **ptr); -int ustrstart(const unsigned int *str, const char *val, int *lenp); -int ustristart(const unsigned int *str, const char *val, int *lenp); -const unsigned int *ustrstr(const unsigned int *str, const char *val); -const unsigned int *ustristr(const unsigned int *str, const char *val); -static inline unsigned int *umemmove(unsigned int *dest, - const unsigned int *src, size_t count) { - return (unsigned int *)memmove(dest, src, count * sizeof(unsigned int)); -} -static inline unsigned int *umemcpy(unsigned int *dest, - const unsigned int *src, size_t count) { - return (unsigned int *)memcpy(dest, src, count * sizeof(unsigned int)); -} -int umemcmp(const unsigned int *s1, const unsigned int *s2, size_t count); -int qe_memicmp(const void *p1, const void *p2, size_t count); -const char *qe_stristr(const char *s1, const char *s2); - -int strsubst(char *buf, int buf_size, const char *from, - const char *s1, const char *s2); -int byte_quote(char *dest, int size, unsigned char c); -int strquote(char *dest, int size, const char *str, int len); -int strunquote(char *dest, int size, const char *str, int len); - -int get_str(const char **pp, char *buf, int buf_size, const char *stop); -int css_get_enum(const char *str, const char *enum_str); - -extern QEColor const xterm_colors[]; -/* XXX: should have a more generic API with precomputed mapping scales */ -/* Convert RGB triplet to a composite color */ -unsigned int qe_map_color(QEColor color, QEColor const *colors, int count, int *dist); -/* Convert a composite color to an RGB triplet */ -QEColor qe_unmap_color(int color, int count); - -void color_complete(CompleteState *cp); -int css_define_color(const char *name, const char *value); -int css_get_color(QEColor *color_ptr, const char *p); -void css_free_colors(void); -int css_get_font_family(const char *str); -void css_union_rect(CSSRect *a, const CSSRect *b); -static inline int css_is_null_rect(const CSSRect *a) { - return (a->x2 <= a->x1 || a->y2 <= a->y1); -} -static inline void css_set_rect(CSSRect *a, int x1, int y1, int x2, int y2) { - a->x1 = x1; - a->y1 = y1; - a->x2 = x2; - a->y2 = y2; -} -/* return true if a and b intersect */ -static inline int css_is_inter_rect(const CSSRect *a, const CSSRect *b) { - return (!(a->x2 <= b->x1 || - a->x1 >= b->x2 || - a->y2 <= b->y1 || - a->y1 >= b->y2)); -} - -int get_clock_ms(void); -int get_clock_usec(void); - -/* Various string packages: should unify these but keep API simple */ - -StringItem *set_string(StringArray *cs, int index, const char *str, int group); -StringItem *add_string(StringArray *cs, const char *str, int group); -void free_strings(StringArray *cs); - -/* simple dynamic strings wrappers. The strings are always terminated - by zero except if they are empty. */ -typedef struct QString { - u8 *data; - int len; /* string length excluding trailing '\0' */ -} QString; - -static inline void qstrinit(QString *q) { - q->data = NULL; - q->len = 0; -} - -static inline void qstrfree(QString *q) { - qe_free(&q->data); -} - -int qmemcat(QString *q, const u8 *data1, int len1); -int qstrcat(QString *q, const char *str); -int qprintf(QString *q, const char *fmt, ...) qe__attr_printf(2,3); - -/* Dynamic buffers with static allocation */ -typedef struct buf_t buf_t; -struct buf_t { - char *buf; - int size, len, pos; -}; - -static inline buf_t *buf_init(buf_t *bp, char *buf, int size) { - if (size > 0) { - bp->buf = buf; - bp->size = size; - *buf = '\0'; - } else { - bp->buf = NULL; - bp->size = 0; - } - bp->len = bp->pos = 0; - return bp; -} -static inline buf_t *buf_attach(buf_t *bp, char *buf, int size, int pos) { - /* assuming 0 <= pos < size */ - // XXX: Does not set a null byte? - bp->buf = buf; - bp->size = size; - bp->len = bp->pos = pos; - return bp; -} -static inline int buf_avail(buf_t *bp) { - return bp->size - bp->pos - 1; -} -static inline int buf_put_byte(buf_t *bp, int c) { - if (bp->len < bp->size - 1) { - bp->buf[bp->len++] = c; - bp->buf[bp->len] = '\0'; - } - return bp->pos++; -} -int buf_write(buf_t *bp, const void *src, int size); -static inline int buf_puts(buf_t *bp, const char *str) { - return buf_write(bp, str, strlen(str)); -} - -int buf_printf(buf_t *bp, const char *fmt, ...) qe__attr_printf(2,3); -int buf_putc_utf8(buf_t *bp, int c); - -/* Bounded constant strings used in various parse functions */ -typedef struct bstr_t { - const char *s; - int len; -} bstr_t; - -static inline bstr_t bstr_make(const char *s) { - bstr_t bs = { s, s ? strlen(s) : 0 }; - return bs; -} - -bstr_t bstr_token(const char *s, int sep, const char **pp); -bstr_t bstr_get_nth(const char *s, int n); - -static inline int bstr_equal(bstr_t s1, bstr_t s2) { - /* NULL and empty strings are equivalent */ - return s1.len == s2.len && !memcmp(s1.s, s2.s, s1.len); -} - -/* our own implementation of qsort_r() */ -void qe_qsort_r(void *base, size_t nmemb, size_t size, void *thunk, - int (*compar)(void *, const void *, const void *)); +#include "color.h" /* Command line options */ enum CmdLineOptionType { @@ -675,78 +162,6 @@ void qe_register_cmd_line_options(CmdLineOptionDef *table); int find_resource_file(char *path, int path_size, const char *pattern); -typedef int (CSSAbortFunc)(void *); - -static inline int max(int a, int b) { - if (a > b) - return a; - else - return b; -} - -static inline int maxp(int *pa, int b) { - int a = *pa; - if (a > b) - return a; - else - return *pa = b; -} - -static inline int max3(int a, int b, int c) { - return max(max(a, b), c); -} - -static inline int min(int a, int b) { - if (a < b) - return a; - else - return b; -} - -static inline int minp(int *pa, int b) { - int a = *pa; - if (a < b) - return a; - else - return *pa = b; -} - -static inline int min3(int a, int b, int c) { - return min(min(a, b), c); -} - -static inline int clamp(int a, int b, int c) { - if (a < b) - return b; - else - if (a > c) - return c; - else - return a; -} - -static inline int clampp(int *pa, int b, int c) { - int a = *pa; - if (a < b) - return *pa = b; - else - if (a > c) - return *pa = c; - else - return a; -} - -static inline int compute_percent(int a, int b) { - return b <= 0 ? 0 : (int)((long long)a * 100 / b); -} - -int compose_keys(unsigned int *keys, int *nb_keys); -int strtokey(const char **pp); -int strtokeys(const char *keystr, unsigned int *keys, int max_keys, const char **endp); -int buf_put_key(buf_t *out, int key); -int buf_put_keys(buf_t *out, unsigned int *keys, int nb_keys); -int buf_encode_byte(buf_t *out, unsigned char ch); - /* charset.c */ /* maximum number of bytes for a character in all the supported charsets */ @@ -823,13 +238,6 @@ int charset_jis_init(void); void qe_register_charset(struct QECharset *charset); -extern unsigned char const utf8_length[256]; -static inline int utf8_is_trailing_byte(int c) { return (c & 0xC0) == 0x80; } -int utf8_encode(char *q, int c); -int utf8_decode(const char **pp); -char *utf8_char_to_string(char *buf, int c); -int utf8_to_unicode(unsigned int *dest, int dest_length, const char *str); - void charset_complete(CompleteState *cp); QECharset *find_charset(const char *str); void charset_decode_init(CharsetDecodeState *s, QECharset *charset, @@ -847,16 +255,6 @@ void decode_8bit_init(CharsetDecodeState *s); int decode_8bit(CharsetDecodeState *s); u8 *encode_8bit(QECharset *charset, u8 *q, int c); -int unicode_tty_glyph_width(unsigned int ucs); - -static inline int qe_isaccent(int c) { - return c >= 0x300 && unicode_tty_glyph_width(c) == 0; -} - -static inline int qe_iswide(int c) { - return c >= 0x01000 && unicode_tty_glyph_width(c) > 1; -} - /* arabic.c */ int arab_join(unsigned int *line, unsigned int *ctog, int len); @@ -884,82 +282,6 @@ enum QEEventType { QE_SELECTION_CLEAR_EVENT, /* request selection clear (X11 type selection) */ }; -#define KEY_CTRL(c) ((c) & 0x001f) -/* allow combinations such as KEY_META(KEY_LEFT) */ -#define KEY_META(c) ((c) | 0xe100) -#define KEY_ESC1(c) ((c) | 0xe200) -#define KEY_IS_ESC1(c) ((c) >= KEY_ESC1(0) && (c) <= KEY_ESC1(0xff)) -#define KEY_IS_SPECIAL(c) ((c) >= 0xe000 && (c) < 0xf000) -#define KEY_IS_CONTROL(c) (((c) >= 0 && (c) < 32) || (c) == 127) - -#define KEY_NONE 0xE000 -#define KEY_DEFAULT 0xE001 /* to handle all non special keys */ -#define KEY_UNKNOWN 0xE002 - -#define KEY_TAB KEY_CTRL('i') -#define KEY_LF KEY_CTRL('j') -#define KEY_RET KEY_CTRL('m') -#define KEY_ESC KEY_CTRL('[') -#define KEY_SPC 0x0020 -#define KEY_DEL 127 // kbs -#define KEY_BS KEY_CTRL('h') // kbs - -#define KEY_UP KEY_ESC1('A') // kcuu1 -#define KEY_DOWN KEY_ESC1('B') // kcud1 -#define KEY_RIGHT KEY_ESC1('C') // kcuf1 -#define KEY_LEFT KEY_ESC1('D') // kcub1 -#define KEY_CTRL_UP KEY_ESC1('a') -#define KEY_CTRL_DOWN KEY_ESC1('b') -#define KEY_CTRL_RIGHT KEY_ESC1('c') -#define KEY_CTRL_LEFT KEY_ESC1('d') -#define KEY_CTRL_END KEY_ESC1('f') -#define KEY_CTRL_HOME KEY_ESC1('h') -#define KEY_CTRL_PAGEUP KEY_ESC1('i') -#define KEY_CTRL_PAGEDOWN KEY_ESC1('j') -#define KEY_SHIFT_UP KEY_ESC1('a'+128) -#define KEY_SHIFT_DOWN KEY_ESC1('b'+128) -#define KEY_SHIFT_RIGHT KEY_ESC1('c'+128) -#define KEY_SHIFT_LEFT KEY_ESC1('d'+128) -#define KEY_SHIFT_END KEY_ESC1('f'+128) -#define KEY_SHIFT_HOME KEY_ESC1('h'+128) -#define KEY_SHIFT_PAGEUP KEY_ESC1('i'+128) -#define KEY_SHIFT_PAGEDOWN KEY_ESC1('j'+128) -#define KEY_CTRL_SHIFT_UP KEY_ESC1('a'+64) -#define KEY_CTRL_SHIFT_DOWN KEY_ESC1('b'+64) -#define KEY_CTRL_SHIFT_RIGHT KEY_ESC1('c'+64) -#define KEY_CTRL_SHIFT_LEFT KEY_ESC1('d'+64) -#define KEY_CTRL_SHIFT_END KEY_ESC1('f'+64) -#define KEY_CTRL_SHIFT_HOME KEY_ESC1('h'+64) -#define KEY_CTRL_SHIFT_PAGEUP KEY_ESC1('i'+64) -#define KEY_CTRL_SHIFT_PAGEDOWN KEY_ESC1('j'+64) -#define KEY_SHIFT_TAB KEY_ESC1('Z') // kcbt -#define KEY_HOME KEY_ESC1(1) // khome -#define KEY_INSERT KEY_ESC1(2) // kich1 -#define KEY_DELETE KEY_ESC1(3) // kdch1 -#define KEY_END KEY_ESC1(4) // kend -#define KEY_PAGEUP KEY_ESC1(5) // kpp -#define KEY_PAGEDOWN KEY_ESC1(6) // knp -#define KEY_F1 KEY_ESC1(11) -#define KEY_F2 KEY_ESC1(12) -#define KEY_F3 KEY_ESC1(13) -#define KEY_F4 KEY_ESC1(14) -#define KEY_F5 KEY_ESC1(15) -#define KEY_F6 KEY_ESC1(17) -#define KEY_F7 KEY_ESC1(18) -#define KEY_F8 KEY_ESC1(19) -#define KEY_F9 KEY_ESC1(20) -#define KEY_F10 KEY_ESC1(21) -#define KEY_F11 KEY_ESC1(23) -#define KEY_F12 KEY_ESC1(24) -#define KEY_F13 KEY_ESC1(25) -#define KEY_F14 KEY_ESC1(26) -#define KEY_F15 KEY_ESC1(28) -#define KEY_F16 KEY_ESC1(29) -#define KEY_F17 KEY_ESC1(31) -#define KEY_F18 KEY_ESC1(32) -#define KEY_F19 KEY_ESC1(33) -#define KEY_F20 KEY_ESC1(34) - typedef struct QEKeyEvent { enum QEEventType type; int key; @@ -2066,14 +1388,6 @@ void unload_input_methods(void); /* the following will be suppressed */ #define LINE_MAX_SIZE 256 -static inline int align(int a, int n) { - return (a / n) * n; -} - -static inline int scale(int a, int b, int c) { - return (a * b + c / 2) / c; -} - /* minibuffer & status */ void minibuffer_init(void); @@ -2467,7 +1781,7 @@ static inline void qe_cfg_swap(QEValue *sp, QEValue *sp1) { *sp1 = tmp; } -/* parser.c */ +/* qescript.c */ int parse_config_file(EditState *s, const char *filename); void do_eval_expression(EditState *s, const char *expression, int argval); diff --git a/unix.c b/unix.c index 986ef13..a4c1183 100644 --- a/unix.c +++ b/unix.c @@ -23,6 +23,7 @@ #ifdef CONFIG_WIN32 #include +#include /* Use a conditional typedef to avoid compilation warning */ typedef u_int fdesc_t; #else @@ -343,3 +344,42 @@ void url_redisplay(void) { url_display_request = 1; } + +int get_clock_ms(void) { +#ifdef CONFIG_WIN32 + struct _timeb tb; + + _ftime(&tb); + return tb.time * 1000 + tb.millitm; +#else + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + (tv.tv_usec / 1000); +#endif +} + +int get_clock_usec(void) { +#ifdef CONFIG_WIN32 + struct _timeb tb; + + _ftime(&tb); + return tb.time * 1000000 + tb.millitm * 1000; +#else + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +#endif +} + +#ifdef __TINYC__ + +/* the glibc folks use wrappers, but forgot to put a compatibility + function for non GCC compilers ! */ +int stat(__const char *__path, + struct stat *__statbuf) +{ + return __xstat(_STAT_VER, __path, __statbuf); +} +#endif diff --git a/util.c b/util.c index 961346b..bacab70 100644 --- a/util.c +++ b/util.c @@ -19,11 +19,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "qe.h" #include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" /* for CONFIG_WIN32 */ +#include "cutils.h" +#include "util.h" #ifdef CONFIG_WIN32 -#include /* XXX: not sufficient, but OK for basic operations */ int fnmatch(const char *pattern, const char *string, int flags) { @@ -54,6 +63,8 @@ int fnmatch(const char *pattern, const char *string, int flags) { #include #endif +#define MAX_FILENAME_SIZE 1024 /* Size for a filename buffer */ + struct FindFileState { char path[MAX_FILENAME_SIZE]; char dirpath[MAX_FILENAME_SIZE]; /* current dir path */ @@ -145,6 +156,7 @@ int find_file_next(FindFileState *s, char *filename, int filename_size_max) { if (s->flags & FF_ONLYDIR) continue; } + // XXX: should use our own fnmatch version if (fnmatch(s->pattern, dirent->d_name, 0) == 0) { makepath(filename, filename_size_max, s->dirpath, dirent->d_name); @@ -174,19 +186,6 @@ void find_file_close(FindFileState **sp) { } } -#ifdef CONFIG_WIN32 -/* convert '\' to '/' */ -static void path_win_to_unix(char *buf) -{ - char *p; - - for (p = buf; *p; p++) { - if (*p == '\\') - *p = '/'; - } -} -#endif - int is_directory(const char *path) { /*@API utils Check if the string pointed to by `path` is the name of a @@ -1137,13 +1136,12 @@ int ustr_get_word(char *buf, int buf_size, int c, int get_str(const char **pp, char *buf, int buf_size, const char *stop) { char *q; const char *p; - int c; qe_skip_spaces(pp); p = *pp; q = buf; for (;;) { - c = *p; + u8 c = *p; /* Stop on spaces and eat them */ if (c == '\0' || qe_isspace(c) || strchr(stop, c)) break; @@ -1157,33 +1155,7 @@ int get_str(const char **pp, char *buf, int buf_size, const char *stop) { return q - buf; } -/* scans a comma separated list of entries, return index of match or -1 */ -/* CG: very similar to strfind */ -int css_get_enum(const char *str, const char *enum_str) -{ - int val, len; - const char *s, *s1; - - s = enum_str; - val = 0; - len = strlen(str); - for (;;) { - s1 = strchr(s, ','); - if (s1) { - if (len == (s1 - s) && !memcmp(s, str, len)) - return val; - s = s1 + 1; - } else { - if (strequal(s, str)) - return val; - else - break; - } - val++; - } - return -1; -} - +/* should move to a separate module */ static unsigned short const keycodes[] = { KEY_SPC, KEY_DEL, KEY_RET, KEY_LF, KEY_ESC, KEY_TAB, KEY_SHIFT_TAB, KEY_CTRL(' '), KEY_CTRL('@'), KEY_DEL, KEY_CTRL('\\'), @@ -1382,832 +1354,6 @@ unsigned char const qe_digit_value__[128] = { 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, }; -#if 1 -/* Should move all this to a separate source file color.c */ - -/* For 8K colors, We use a color system with 7936 colors: - * - 16 standard colors - * - 240 standard palette colors - * - 4096 colors in a 16x16x16 cube - * - a 256 level gray ramp - * - 6 256-level fade to black ramps - * - 6 256-level fade to white ramps - * - a 256 color palette with default xterm values - * - 256 unused slots - */ - -/* Alternately we could use a system with 8157 colors: - * - 2 default color - * - 16 standard colors - * - 256 standard palette colors - * - 6859 colors in a 19x19x19 cube - * with ramp 0,15,31,47,63,79,95,108,121,135, - * 148,161,175,188,201,215,228,241,255 values - * - 256 level gray ramp - * - extra space for 3 256 level ramps or 12 64 level ramps - * - 15 unused slots - */ - -/* Another possible system for 8K colors has 8042+ colors: - * - 2 default color - * - 16 standard colors - * - 24 standard grey scale colors - * - 8000 colors in a 20x20x20 cube - * with ramp 0,13,27,40,54,67,81,95,108,121,135, - * 148,161,175,188,201,215,228,241,255 values - * - extra grey scale colors - * - some unused slots - */ - -typedef struct ColorDef { - const char *name; - unsigned int color; -} ColorDef; - -static ColorDef const default_colors[] = { - /* From HTML 4.0 spec */ - { "black", QERGB(0x00, 0x00, 0x00) }, - { "green", QERGB(0x00, 0x80, 0x00) }, - { "silver", QERGB(0xc0, 0xc0, 0xc0) }, - { "lime", QERGB(0x00, 0xff, 0x00) }, - - { "gray", QERGB(0xbe, 0xbe, 0xbe) }, - { "olive", QERGB(0x80, 0x80, 0x00) }, - { "white", QERGB(0xff, 0xff, 0xff) }, - { "yellow", QERGB(0xff, 0xff, 0x00) }, - - { "maroon", QERGB(0x80, 0x00, 0x00) }, - { "navy", QERGB(0x00, 0x00, 0x80) }, - { "red", QERGB(0xff, 0x00, 0x00) }, - { "blue", QERGB(0x00, 0x00, 0xff) }, - - { "purple", QERGB(0x80, 0x00, 0x80) }, - { "teal", QERGB(0x00, 0x80, 0x80) }, - { "fuchsia", QERGB(0xff, 0x00, 0xff) }, - { "aqua", QERGB(0x00, 0xff, 0xff) }, - - /* more colors */ - { "cyan", QERGB(0x00, 0xff, 0xff) }, - { "magenta", QERGB(0xff, 0x00, 0xff) }, - { "grey", QERGB(0xbe, 0xbe, 0xbe) }, - { "transparent", COLOR_TRANSPARENT }, -}; -#define nb_default_colors countof(default_colors) - -static ColorDef *qe_colors = unconst(ColorDef *)default_colors; -static int nb_qe_colors = nb_default_colors; - -#if 0 -static QEColor const tty_full_colors[8] = { - QERGB(0x00, 0x00, 0x00), /* black */ - QERGB(0xff, 0x00, 0x00), /* red */ - QERGB(0x00, 0xff, 0x00), /* lime */ - QERGB(0xff, 0xff, 0x00), /* yellow */ - QERGB(0x00, 0x00, 0xff), /* blue */ - QERGB(0xff, 0x00, 0xff), /* fuchsia */ - QERGB(0x00, 0xff, 0xff), /* aqua */ - QERGB(0xff, 0xff, 0xff), /* white */ -}; -#endif - -QEColor const xterm_colors[256] = { - QERGB(0x00, 0x00, 0x00), /* black */ - QERGB(0xbb, 0x00, 0x00), - QERGB(0x00, 0xbb, 0x00), - QERGB(0xbb, 0xbb, 0x00), - QERGB(0x00, 0x00, 0xbb), - QERGB(0xbb, 0x00, 0xbb), - QERGB(0x00, 0xbb, 0xbb), - QERGB(0xbb, 0xbb, 0xbb), - - QERGB(0x55, 0x55, 0x55), - QERGB(0xff, 0x55, 0x55), - QERGB(0x55, 0xff, 0x55), - QERGB(0xff, 0xff, 0x55), - QERGB(0x55, 0x55, 0xff), - QERGB(0xff, 0x55, 0xff), - QERGB(0x55, 0xff, 0xff), - QERGB(0xff, 0xff, 0xff), /* white */ -#if 1 - /* Extended color palette for xterm 256 color mode */ - - /* From XFree86: xc/programs/xterm/256colres.h, - * v 1.5 2002/10/05 17:57:11 dickey Exp - */ - - /* 216 entry RGB cube with axes 0,95,135,175,215,255 */ - /* followed by 24 entry grey scale 8,18..238 */ - QERGB(0x00, 0x00, 0x00), /* 16: Grey0 */ - QERGB(0x00, 0x00, 0x5f), /* 17: NavyBlue */ - QERGB(0x00, 0x00, 0x87), /* 18: DarkBlue */ - QERGB(0x00, 0x00, 0xaf), /* 19: Blue3 */ - QERGB(0x00, 0x00, 0xd7), /* 20: Blue3 */ - QERGB(0x00, 0x00, 0xff), /* 21: Blue1 */ - QERGB(0x00, 0x5f, 0x00), /* 22: DarkGreen */ - QERGB(0x00, 0x5f, 0x5f), /* 23: DeepSkyBlue4 */ - QERGB(0x00, 0x5f, 0x87), /* 24: DeepSkyBlue4 */ - QERGB(0x00, 0x5f, 0xaf), /* 25: DeepSkyBlue4 */ - QERGB(0x00, 0x5f, 0xd7), /* 26: DodgerBlue3 */ - QERGB(0x00, 0x5f, 0xff), /* 27: DodgerBlue2 */ - QERGB(0x00, 0x87, 0x00), /* 28: Green4 */ - QERGB(0x00, 0x87, 0x5f), /* 29: SpringGreen4 */ - QERGB(0x00, 0x87, 0x87), /* 30: Turquoise4 */ - QERGB(0x00, 0x87, 0xaf), /* 31: DeepSkyBlue3 */ - QERGB(0x00, 0x87, 0xd7), /* 32: DeepSkyBlue3 */ - QERGB(0x00, 0x87, 0xff), /* 33: DodgerBlue1 */ - QERGB(0x00, 0xaf, 0x00), /* 34: Green3 */ - QERGB(0x00, 0xaf, 0x5f), /* 35: SpringGreen3 */ - QERGB(0x00, 0xaf, 0x87), /* 36: DarkCyan */ - QERGB(0x00, 0xaf, 0xaf), /* 37: LightSeaGreen */ - QERGB(0x00, 0xaf, 0xd7), /* 38: DeepSkyBlue2 */ - QERGB(0x00, 0xaf, 0xff), /* 39: DeepSkyBlue1 */ - QERGB(0x00, 0xd7, 0x00), /* 40: Green3 */ - QERGB(0x00, 0xd7, 0x5f), /* 41: SpringGreen3 */ - QERGB(0x00, 0xd7, 0x87), /* 42: SpringGreen2 */ - QERGB(0x00, 0xd7, 0xaf), /* 43: Cyan3 */ - QERGB(0x00, 0xd7, 0xd7), /* 44: DarkTurquoise */ - QERGB(0x00, 0xd7, 0xff), /* 45: Turquoise2 */ - QERGB(0x00, 0xff, 0x00), /* 46: Green1 */ - QERGB(0x00, 0xff, 0x5f), /* 47: SpringGreen2 */ - QERGB(0x00, 0xff, 0x87), /* 48: SpringGreen1 */ - QERGB(0x00, 0xff, 0xaf), /* 49: MediumSpringGreen */ - QERGB(0x00, 0xff, 0xd7), /* 50: Cyan2 */ - QERGB(0x00, 0xff, 0xff), /* 51: Cyan1 */ - QERGB(0x5f, 0x00, 0x00), /* 52: DarkRed */ - QERGB(0x5f, 0x00, 0x5f), /* 53: DeepPink4 */ - QERGB(0x5f, 0x00, 0x87), /* 54: Purple4 */ - QERGB(0x5f, 0x00, 0xaf), /* 55: Purple4 */ - QERGB(0x5f, 0x00, 0xd7), /* 56: Purple3 */ - QERGB(0x5f, 0x00, 0xff), /* 57: BlueViolet */ - QERGB(0x5f, 0x5f, 0x00), /* 58: Orange4 */ - QERGB(0x5f, 0x5f, 0x5f), /* 59: Grey37 */ - QERGB(0x5f, 0x5f, 0x87), /* 60: MediumPurple4 */ - QERGB(0x5f, 0x5f, 0xaf), /* 61: SlateBlue3 */ - QERGB(0x5f, 0x5f, 0xd7), /* 62: SlateBlue3 */ - QERGB(0x5f, 0x5f, 0xff), /* 63: RoyalBlue1 */ - QERGB(0x5f, 0x87, 0x00), /* 64: Chartreuse4 */ - QERGB(0x5f, 0x87, 0x5f), /* 65: DarkSeaGreen4 */ - QERGB(0x5f, 0x87, 0x87), /* 66: PaleTurquoise4 */ - QERGB(0x5f, 0x87, 0xaf), /* 67: SteelBlue */ - QERGB(0x5f, 0x87, 0xd7), /* 68: SteelBlue3 */ - QERGB(0x5f, 0x87, 0xff), /* 69: CornflowerBlue */ - QERGB(0x5f, 0xaf, 0x00), /* 70: Chartreuse3 */ - QERGB(0x5f, 0xaf, 0x5f), /* 71: DarkSeaGreen4 */ - QERGB(0x5f, 0xaf, 0x87), /* 72: CadetBlue */ - QERGB(0x5f, 0xaf, 0xaf), /* 73: CadetBlue */ - QERGB(0x5f, 0xaf, 0xd7), /* 74: SkyBlue3 */ - QERGB(0x5f, 0xaf, 0xff), /* 75: SteelBlue1 */ - QERGB(0x5f, 0xd7, 0x00), /* 76: Chartreuse3 */ - QERGB(0x5f, 0xd7, 0x5f), /* 77: PaleGreen3 */ - QERGB(0x5f, 0xd7, 0x87), /* 78: SeaGreen3 */ - QERGB(0x5f, 0xd7, 0xaf), /* 79: Aquamarine3 */ - QERGB(0x5f, 0xd7, 0xd7), /* 80: MediumTurquoise */ - QERGB(0x5f, 0xd7, 0xff), /* 81: SteelBlue1 */ - QERGB(0x5f, 0xff, 0x00), /* 82: Chartreuse2 */ - QERGB(0x5f, 0xff, 0x5f), /* 83: SeaGreen2 */ - QERGB(0x5f, 0xff, 0x87), /* 84: SeaGreen1 */ - QERGB(0x5f, 0xff, 0xaf), /* 85: SeaGreen1 */ - QERGB(0x5f, 0xff, 0xd7), /* 86: Aquamarine1 */ - QERGB(0x5f, 0xff, 0xff), /* 87: DarkSlateGray2 */ - QERGB(0x87, 0x00, 0x00), /* 88: DarkRed */ - QERGB(0x87, 0x00, 0x5f), /* 89: DeepPink4 */ - QERGB(0x87, 0x00, 0x87), /* 90: DarkMagenta */ - QERGB(0x87, 0x00, 0xaf), /* 91: DarkMagenta */ - QERGB(0x87, 0x00, 0xd7), /* 92: DarkViolet */ - QERGB(0x87, 0x00, 0xff), /* 93: Purple */ - QERGB(0x87, 0x5f, 0x00), /* 94: Orange4 */ - QERGB(0x87, 0x5f, 0x5f), /* 95: LightPink4 */ - QERGB(0x87, 0x5f, 0x87), /* 96: Plum4 */ - QERGB(0x87, 0x5f, 0xaf), /* 97: MediumPurple3 */ - QERGB(0x87, 0x5f, 0xd7), /* 98: MediumPurple3 */ - QERGB(0x87, 0x5f, 0xff), /* 99: SlateBlue1 */ - QERGB(0x87, 0x87, 0x00), /* 100: Yellow4 */ - QERGB(0x87, 0x87, 0x5f), /* 101: Wheat4 */ - QERGB(0x87, 0x87, 0x87), /* 102: Grey53 */ - QERGB(0x87, 0x87, 0xaf), /* 103: LightSlateGrey */ - QERGB(0x87, 0x87, 0xd7), /* 104: MediumPurple */ - QERGB(0x87, 0x87, 0xff), /* 105: LightSlateBlue */ - QERGB(0x87, 0xaf, 0x00), /* 106: Yellow4 */ - QERGB(0x87, 0xaf, 0x5f), /* 107: DarkOliveGreen3 */ - QERGB(0x87, 0xaf, 0x87), /* 108: DarkSeaGreen */ - QERGB(0x87, 0xaf, 0xaf), /* 109: LightSkyBlue3 */ - QERGB(0x87, 0xaf, 0xd7), /* 110: LightSkyBlue3 */ - QERGB(0x87, 0xaf, 0xff), /* 111: SkyBlue2 */ - QERGB(0x87, 0xd7, 0x00), /* 112: Chartreuse2 */ - QERGB(0x87, 0xd7, 0x5f), /* 113: DarkOliveGreen3 */ - QERGB(0x87, 0xd7, 0x87), /* 114: PaleGreen3 */ - QERGB(0x87, 0xd7, 0xaf), /* 115: DarkSeaGreen3 */ - QERGB(0x87, 0xd7, 0xd7), /* 116: DarkSlateGray3 */ - QERGB(0x87, 0xd7, 0xff), /* 117: SkyBlue1 */ - QERGB(0x87, 0xff, 0x00), /* 118: Chartreuse1 */ - QERGB(0x87, 0xff, 0x5f), /* 119: LightGreen */ - QERGB(0x87, 0xff, 0x87), /* 120: LightGreen */ - QERGB(0x87, 0xff, 0xaf), /* 121: PaleGreen1 */ - QERGB(0x87, 0xff, 0xd7), /* 122: Aquamarine1 */ - QERGB(0x87, 0xff, 0xff), /* 123: DarkSlateGray1 */ - QERGB(0xaf, 0x00, 0x00), /* 124: Red3 */ - QERGB(0xaf, 0x00, 0x5f), /* 125: DeepPink4 */ - QERGB(0xaf, 0x00, 0x87), /* 126: MediumVioletRed */ - QERGB(0xaf, 0x00, 0xaf), /* 127: Magenta3 */ - QERGB(0xaf, 0x00, 0xd7), /* 128: DarkViolet */ - QERGB(0xaf, 0x00, 0xff), /* 129: Purple */ - QERGB(0xaf, 0x5f, 0x00), /* 130: DarkOrange3 */ - QERGB(0xaf, 0x5f, 0x5f), /* 131: IndianRed */ - QERGB(0xaf, 0x5f, 0x87), /* 132: HotPink3 */ - QERGB(0xaf, 0x5f, 0xaf), /* 133: MediumOrchid3 */ - QERGB(0xaf, 0x5f, 0xd7), /* 134: MediumOrchid */ - QERGB(0xaf, 0x5f, 0xff), /* 135: MediumPurple2 */ - QERGB(0xaf, 0x87, 0x00), /* 136: DarkGoldenrod */ - QERGB(0xaf, 0x87, 0x5f), /* 137: LightSalmon3 */ - QERGB(0xaf, 0x87, 0x87), /* 138: RosyBrown */ - QERGB(0xaf, 0x87, 0xaf), /* 139: Grey63 */ - QERGB(0xaf, 0x87, 0xd7), /* 140: MediumPurple2 */ - QERGB(0xaf, 0x87, 0xff), /* 141: MediumPurple1 */ - QERGB(0xaf, 0xaf, 0x00), /* 142: Gold3 */ - QERGB(0xaf, 0xaf, 0x5f), /* 143: DarkKhaki */ - QERGB(0xaf, 0xaf, 0x87), /* 144: NavajoWhite3 */ - QERGB(0xaf, 0xaf, 0xaf), /* 145: Grey69 */ - QERGB(0xaf, 0xaf, 0xd7), /* 146: LightSteelBlue3 */ - QERGB(0xaf, 0xaf, 0xff), /* 147: LightSteelBlue */ - QERGB(0xaf, 0xd7, 0x00), /* 148: Yellow3 */ - QERGB(0xaf, 0xd7, 0x5f), /* 149: DarkOliveGreen3 */ - QERGB(0xaf, 0xd7, 0x87), /* 150: DarkSeaGreen3 */ - QERGB(0xaf, 0xd7, 0xaf), /* 151: DarkSeaGreen2 */ - QERGB(0xaf, 0xd7, 0xd7), /* 152: LightCyan3 */ - QERGB(0xaf, 0xd7, 0xff), /* 153: LightSkyBlue1 */ - QERGB(0xaf, 0xff, 0x00), /* 154: GreenYellow */ - QERGB(0xaf, 0xff, 0x5f), /* 155: DarkOliveGreen2 */ - QERGB(0xaf, 0xff, 0x87), /* 156: PaleGreen1 */ - QERGB(0xaf, 0xff, 0xaf), /* 157: DarkSeaGreen2 */ - QERGB(0xaf, 0xff, 0xd7), /* 158: DarkSeaGreen1 */ - QERGB(0xaf, 0xff, 0xff), /* 159: PaleTurquoise1 */ - QERGB(0xd7, 0x00, 0x00), /* 160: Red3 */ - QERGB(0xd7, 0x00, 0x5f), /* 161: DeepPink3 */ - QERGB(0xd7, 0x00, 0x87), /* 162: DeepPink3 */ - QERGB(0xd7, 0x00, 0xaf), /* 163: Magenta3 */ - QERGB(0xd7, 0x00, 0xd7), /* 164: Magenta3 */ - QERGB(0xd7, 0x00, 0xff), /* 165: Magenta2 */ - QERGB(0xd7, 0x5f, 0x00), /* 166: DarkOrange3 */ - QERGB(0xd7, 0x5f, 0x5f), /* 167: IndianRed */ - QERGB(0xd7, 0x5f, 0x87), /* 168: HotPink3 */ - QERGB(0xd7, 0x5f, 0xaf), /* 169: HotPink2 */ - QERGB(0xd7, 0x5f, 0xd7), /* 170: Orchid */ - QERGB(0xd7, 0x5f, 0xff), /* 171: MediumOrchid1 */ - QERGB(0xd7, 0x87, 0x00), /* 172: Orange3 */ - QERGB(0xd7, 0x87, 0x5f), /* 173: LightSalmon3 */ - QERGB(0xd7, 0x87, 0x87), /* 174: LightPink3 */ - QERGB(0xd7, 0x87, 0xaf), /* 175: Pink3 */ - QERGB(0xd7, 0x87, 0xd7), /* 176: Plum3 */ - QERGB(0xd7, 0x87, 0xff), /* 177: Violet */ - QERGB(0xd7, 0xaf, 0x00), /* 178: Gold3 */ - QERGB(0xd7, 0xaf, 0x5f), /* 179: LightGoldenrod3 */ - QERGB(0xd7, 0xaf, 0x87), /* 180: Tan */ - QERGB(0xd7, 0xaf, 0xaf), /* 181: MistyRose3 */ - QERGB(0xd7, 0xaf, 0xd7), /* 182: Thistle3 */ - QERGB(0xd7, 0xaf, 0xff), /* 183: Plum2 */ - QERGB(0xd7, 0xd7, 0x00), /* 184: Yellow3 */ - QERGB(0xd7, 0xd7, 0x5f), /* 185: Khaki3 */ - QERGB(0xd7, 0xd7, 0x87), /* 186: LightGoldenrod2 */ - QERGB(0xd7, 0xd7, 0xaf), /* 187: LightYellow3 */ - QERGB(0xd7, 0xd7, 0xd7), /* 188: Grey84 */ - QERGB(0xd7, 0xd7, 0xff), /* 189: LightSteelBlue1 */ - QERGB(0xd7, 0xff, 0x00), /* 190: Yellow2 */ - QERGB(0xd7, 0xff, 0x5f), /* 191: DarkOliveGreen1 */ - QERGB(0xd7, 0xff, 0x87), /* 192: DarkOliveGreen1 */ - QERGB(0xd7, 0xff, 0xaf), /* 193: DarkSeaGreen1 */ - QERGB(0xd7, 0xff, 0xd7), /* 194: Honeydew2 */ - QERGB(0xd7, 0xff, 0xff), /* 195: LightCyan1 */ - QERGB(0xff, 0x00, 0x00), /* 196: Red1 */ - QERGB(0xff, 0x00, 0x5f), /* 197: DeepPink2 */ - QERGB(0xff, 0x00, 0x87), /* 198: DeepPink1 */ - QERGB(0xff, 0x00, 0xaf), /* 199: DeepPink1 */ - QERGB(0xff, 0x00, 0xd7), /* 200: Magenta2 */ - QERGB(0xff, 0x00, 0xff), /* 201: Magenta1 */ - QERGB(0xff, 0x5f, 0x00), /* 202: OrangeRed1 */ - QERGB(0xff, 0x5f, 0x5f), /* 203: IndianRed1 */ - QERGB(0xff, 0x5f, 0x87), /* 204: IndianRed1 */ - QERGB(0xff, 0x5f, 0xaf), /* 205: HotPink */ - QERGB(0xff, 0x5f, 0xd7), /* 206: HotPink */ - QERGB(0xff, 0x5f, 0xff), /* 207: MediumOrchid1 */ - QERGB(0xff, 0x87, 0x00), /* 208: DarkOrange */ - QERGB(0xff, 0x87, 0x5f), /* 209: Salmon1 */ - QERGB(0xff, 0x87, 0x87), /* 210: LightCoral */ - QERGB(0xff, 0x87, 0xaf), /* 211: PaleVioletRed1 */ - QERGB(0xff, 0x87, 0xd7), /* 212: Orchid2 */ - QERGB(0xff, 0x87, 0xff), /* 213: Orchid1 */ - QERGB(0xff, 0xaf, 0x00), /* 214: Orange1 */ - QERGB(0xff, 0xaf, 0x5f), /* 215: SandyBrown */ - QERGB(0xff, 0xaf, 0x87), /* 216: LightSalmon1 */ - QERGB(0xff, 0xaf, 0xaf), /* 217: LightPink1 */ - QERGB(0xff, 0xaf, 0xd7), /* 218: Pink1 */ - QERGB(0xff, 0xaf, 0xff), /* 219: Plum1 */ - QERGB(0xff, 0xd7, 0x00), /* 220: Gold1 */ - QERGB(0xff, 0xd7, 0x5f), /* 221: LightGoldenrod2 */ - QERGB(0xff, 0xd7, 0x87), /* 222: LightGoldenrod2 */ - QERGB(0xff, 0xd7, 0xaf), /* 223: NavajoWhite1 */ - QERGB(0xff, 0xd7, 0xd7), /* 224: MistyRose1 */ - QERGB(0xff, 0xd7, 0xff), /* 225: Thistle1 */ - QERGB(0xff, 0xff, 0x00), /* 226: Yellow1 */ - QERGB(0xff, 0xff, 0x5f), /* 227: LightGoldenrod1 */ - QERGB(0xff, 0xff, 0x87), /* 228: Khaki1 */ - QERGB(0xff, 0xff, 0xaf), /* 229: Wheat1 */ - QERGB(0xff, 0xff, 0xd7), /* 230: Cornsilk1 */ - QERGB(0xff, 0xff, 0xff), /* 231: Grey100 */ - QERGB(0x08, 0x08, 0x08), /* 232: Grey3 */ - QERGB(0x12, 0x12, 0x12), /* 233: Grey7 */ - QERGB(0x1c, 0x1c, 0x1c), /* 234: Grey11 */ - QERGB(0x26, 0x26, 0x26), /* 235: Grey15 */ - QERGB(0x30, 0x30, 0x30), /* 236: Grey19 */ - QERGB(0x3a, 0x3a, 0x3a), /* 237: Grey23 */ - QERGB(0x44, 0x44, 0x44), /* 238: Grey27 */ - QERGB(0x4e, 0x4e, 0x4e), /* 239: Grey30 */ - QERGB(0x58, 0x58, 0x58), /* 240: Grey35 */ - QERGB(0x62, 0x62, 0x62), /* 241: Grey39 */ - QERGB(0x6c, 0x6c, 0x6c), /* 242: Grey42 */ - QERGB(0x76, 0x76, 0x76), /* 243: Grey46 */ - QERGB(0x80, 0x80, 0x80), /* 244: Grey50 */ - QERGB(0x8a, 0x8a, 0x8a), /* 245: Grey54 */ - QERGB(0x94, 0x94, 0x94), /* 246: Grey58 */ - QERGB(0x9e, 0x9e, 0x9e), /* 247: Grey62 */ - QERGB(0xa8, 0xa8, 0xa8), /* 248: Grey66 */ - QERGB(0xb2, 0xb2, 0xb2), /* 249: Grey70 */ - QERGB(0xbc, 0xbc, 0xbc), /* 250: Grey74 */ - QERGB(0xc6, 0xc6, 0xc6), /* 251: Grey78 */ - QERGB(0xd0, 0xd0, 0xd0), /* 252: Grey82 */ - QERGB(0xda, 0xda, 0xda), /* 253: Grey85 */ - QERGB(0xe4, 0xe4, 0xe4), /* 254: Grey89 */ - QERGB(0xee, 0xee, 0xee), /* 255: Grey93 */ -#endif -}; - -#if 0 -static unsigned char const scale_cube[256] = { - /* This array is used for mapping rgb colors to the standard palette */ - /* 216 entry RGB cube with axes 0,95,135,175,215,255 */ -#define REP5(x) (x), (x), (x), (x), (x) -#define REP10(x) REP5(x), REP5(x) -#define REP20(x) REP10(x), REP10(x) -#define REP40(x) REP20(x), REP20(x) -#define REP25(x) REP5(x), REP5(x), REP5(x), REP5(x), REP5(x) -#define REP47(x) REP10(x), REP10(x), REP10(x), REP10(x), REP5(x), (x), (x) - REP47(0), REP47(1), REP20(1), REP40(2), REP40(3), REP40(4), REP20(5), 5 -}; - -static unsigned char const scale_grey[256] = { - /* This array is used for mapping gray levels to the standard palette */ - /* 232..255: 24 entry grey scale 8,18..238 */ - 16, 16, 16, 16, - REP10(232), REP10(233), REP10(234), REP10(235), - REP10(236), REP10(237), REP10(238), REP10(239), - REP10(240), REP10(241), REP10(242), REP10(243), - REP10(244), REP10(245), REP10(246), REP10(247), - REP10(248), REP10(249), REP10(250), REP10(251), - REP10(252), REP10(253), REP10(254), REP10(255), - 255, 255, 255, - 231, 231, 231, 231, 231, 231, 231, 231, 231 -}; -#endif - -static inline int color_dist(QEColor c1, QEColor c2) { - /* using casts because c1 and c2 are unsigned */ -#if 0 - /* using a quick approximation to give green extra weight */ - return abs((int)((c1 >> 0) & 0xff) - (int)((c2 >> 0) & 0xff)) + - 2 * abs((int)((c1 >> 8) & 0xff) - (int)((c2 >> 8) & 0xff)) + - abs((int)((c1 >> 16) & 0xff) - (int)((c2 >> 16) & 0xff)); -#else - /* using different weights to R, G, B according to luminance levels */ - return 11 * abs((int)((c1 >> 0) & 0xff) - (int)((c2 >> 0) & 0xff)) + - 59 * abs((int)((c1 >> 8) & 0xff) - (int)((c2 >> 8) & 0xff)) + - 30 * abs((int)((c1 >> 16) & 0xff) - (int)((c2 >> 16) & 0xff)); -#endif -} - -/* XXX: should have a more generic API with precomputed mapping scales */ -/* Convert RGB triplet to a composite color */ -unsigned int qe_map_color(QEColor color, QEColor const *colors, int count, int *dist) -{ - int i, cmin, dmin, d; - - color &= 0xFFFFFF; /* mask off the alpha channel */ - - if (count >= 0x1000000) { - cmin = color | 0x1000000; /* force explicit RGB triplet */ - dmin = 0; - } else { - dmin = INT_MAX; - cmin = 0; - if (count <= 16) { - for (i = 0; i < count; i++) { - d = color_dist(color, colors[i]); - if (d < dmin) { - cmin = i; - dmin = d; - } - } - } else { /* if (dmin > 0 && count > 16) */ - unsigned int r = (color >> 16) & 0xff; - unsigned int g = (color >> 8) & 0xff; - unsigned int b = (color >> 0) & 0xff; -#if 0 - if (r == g && g == b) { - i = scale_grey[r]; - d = color_dist(color, colors[i]); - if (d < dmin) { - cmin = i; - dmin = d; - } - } else { - /* XXX: should use more precise projection */ - i = 16 + scale_cube[r] * 36 + - scale_cube[g] * 6 + - scale_cube[b]; - d = color_dist(color, colors[i]); - if (d < dmin) { - cmin = i; - dmin = d; - } - } -#else - if (r == g && g == b) { - /* color is a gray tone: - * map to the closest palette entry - */ - d = color_dist(color, colors[16]); - if (d < dmin) { - cmin = 16; - dmin = d; - } - for (i = 231; i < 256; i++) { - d = color_dist(color, colors[i]); - if (d < dmin) { - cmin = i; - dmin = d; - } - } - } else { - /* general case: try and match a palette entry - * from the 6x6x6 color cube . - */ - /* XXX: this causes gliches on true color terminals - * with a non standard xterm palette, such as iTerm2. - * On true color terminals, we should treat palette - * colors and rgb colors differently in the shell buffer - * terminal emulator. - */ - for (i = 16; i < 232; i++) { - d = color_dist(color, colors[i]); - if (d < dmin) { - cmin = i; - dmin = d; - } - } - } -#endif - if (dmin > 0 && count >= 4096) { - /* 13-bit 7936 color system */ - d = 0; - for (;;) { - if (r == g) { - if (g == b) { /* #xxxxxx */ - i = 0x700 + r; - break; - } - if (r == 0) { /* #0000xx */ - i = 0x100 + b; - break; - } - if (r == 255) { /* #FFFFxx */ - i = 0x800 + 0x100 + b; - break; - } - if (b == 0) { /* #xxxx00 */ - i = 0x600 + r; - break; - } - if (b == 255) { /* #xxxxFF */ - i = 0x800 + 0x600 + r; - break; - } - } else - if (r == b) { - if (r == 0) { /* #00xx00 */ - i = 0x200 + g; - break; - } - if (r == 255) { /* #FFxxFF */ - i = 0x800 + 0x200 + g; - break; - } - if (g == 0) { /* #xx00xx */ - i = 0x500 + r; - break; - } - if (g == 255) { /* #xxFFxx */ - i = 0x800 + 0x500 + r; - break; - } - } else - if (g == b) { - if (g == 0) { /* #xx0000 */ - i = 0x400 + r; - break; - } - if (g == 255) { /* #xxFFFF */ - i = 0x800 + 0x400 + r; - break; - } - if (r == 0) { /* #00xxxx */ - i = 0x300 + g; - break; - } - if (r == 255) { /* #FFxxxx */ - i = 0x800 + 0x300 + g; - break; - } - } - i = 0x1000 | ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4); - d = color_dist(color, (color & 0xF0F0F0) | ((color & 0xF0F0F0) >> 4)); - break; - } - if (d < dmin) { - cmin = i; - dmin = d; - } - } - } - } - if (dist) { - *dist = dmin; - } - return cmin; -} - -/* Convert a composite color to an RGB triplet */ -QEColor qe_unmap_color(int color, int count) { - /* XXX: Should use an 8K array for all colors <= 8192 */ - if (color < 256) { - return xterm_colors[color]; - } - if (color < 8192) { - /* 13-bit 7936 color system */ - if (color & 0x1000) { - /* explicit 12-bit color */ - QEColor rgb = (((color & 0xF00) << 12) | - ((color & 0x0F0) << 4) | - ((color & 0x00F) << 0)); - return rgb | (rgb << 4); - } - if ((color & 0xf00) < 0xf00) { - /* 256 level color ramps */ - /* 0x800 is unused and converts to white */ - int r, g, b; - r = g = b = color & 0xFF; - if (!(color & 0x400)) r = -(color >> 11) & 0xFF; - if (!(color & 0x200)) g = -(color >> 11) & 0xFF; - if (!(color & 0x100)) b = -(color >> 11) & 0xFF; - return QERGB(r, g, b); - } else { - /* 0xf00 indicates the standard xterm color palette */ - return xterm_colors[color & 255]; - } - } - /* explicit RGB color */ - return color & 0xFFFFFF; -} - -void color_complete(CompleteState *cp) -{ - ColorDef const *def; - int count; - - def = qe_colors; - count = nb_qe_colors; - while (count > 0) { - if (strxstart(def->name, cp->current, NULL)) - add_string(&cp->cs, def->name, 0); - def++; - count--; - } -} - -static int css_lookup_color(ColorDef const *def, int count, - const char *name) -{ - int i; - - for (i = 0; i < count; i++) { - if (!strxcmp(def[i].name, name)) - return i; - } - return -1; -} - -int css_define_color(const char *name, const char *value) -{ - ColorDef *def; - QEColor color; - int index; - - /* Check color validity */ - if (css_get_color(&color, value)) - return -1; - - /* First color definition: allocate modifiable array */ - if (qe_colors == default_colors) { - qe_colors = qe_malloc_dup(default_colors, sizeof(default_colors)); - } - - /* Make room: reallocate table in chunks of 8 entries */ - if (((nb_qe_colors - nb_default_colors) & 7) == 0) { - if (!qe_realloc(&qe_colors, - (nb_qe_colors + 8) * sizeof(ColorDef))) { - return -1; - } - } - /* Check for redefinition */ - index = css_lookup_color(qe_colors, nb_qe_colors, name); - if (index >= 0) { - qe_colors[index].color = color; - return 0; - } - - def = &qe_colors[nb_qe_colors]; - def->name = qe_strdup(name); - def->color = color; - nb_qe_colors++; - - return 0; -} - -void css_free_colors(void) -{ - if (qe_colors != default_colors) { - while (nb_qe_colors > nb_default_colors) { - nb_qe_colors--; - qe_free(unconst(char **)&qe_colors[nb_qe_colors].name); - } - qe_free(&qe_colors); - qe_colors = unconst(ColorDef *)default_colors; - } -} - -/* XXX: make HTML parsing optional ? */ -int css_get_color(QEColor *color_ptr, const char *p) -{ - ColorDef const *def; - int count, index, len, v, i, n; - unsigned char rgba[4]; - - /* search in tables */ - def = qe_colors; - count = nb_qe_colors; - index = css_lookup_color(def, count, p); - if (index >= 0) { - *color_ptr = def[index].color; - return 0; - } - - rgba[3] = 0xff; - if (qe_isxdigit((unsigned char)*p)) { - goto parse_num; - } else - if (*p == '#') { - /* handle '#' notation */ - p++; - parse_num: - len = strlen(p); - switch (len) { - case 3: - for (i = 0; i < 3; i++) { - v = qe_digit_value(*p++); - rgba[i] = v | (v << 4); - } - break; - case 6: - for (i = 0; i < 3; i++) { - v = qe_digit_value(*p++) << 4; - v |= qe_digit_value(*p++); - rgba[i] = v; - } - break; - default: - /* error */ - return -1; - } - } else - if (strstart(p, "rgb(", &p)) { - n = 3; - goto parse_rgba; - } else - if (strstart(p, "rgba(", &p)) { - /* extension for alpha */ - n = 4; - parse_rgba: - for (i = 0; i < n; i++) { - /* XXX: floats ? */ - qe_skip_spaces(&p); - v = strtol_c(p, &p, 0); - if (*p == '%') { - v = (v * 255) / 100; - p++; - } - rgba[i] = v; - if (qe_skip_spaces(&p) == ',') - p++; - } - } else { - return -1; - } - *color_ptr = (rgba[0] << 16) | (rgba[1] << 8) | - (rgba[2]) | (rgba[3] << 24); - return 0; -} - -/* return 0 if unknown font */ -int css_get_font_family(const char *str) -{ - int v; - - if (!strcasecmp(str, "serif") || - !strcasecmp(str, "times")) - v = QE_FONT_FAMILY_SERIF; - else - if (!strcasecmp(str, "sans") || - !strcasecmp(str, "arial") || - !strcasecmp(str, "helvetica")) - v = QE_FONT_FAMILY_SANS; - else - if (!strcasecmp(str, "fixed") || - !strcasecmp(str, "monospace") || - !strcasecmp(str, "courier")) - v = QE_FONT_FAMILY_FIXED; - else - v = 0; /* inherit */ - return v; -} -#endif /* style stuff */ - -/* a = a union b */ -void css_union_rect(CSSRect *a, const CSSRect *b) -{ - if (css_is_null_rect(b)) - return; - if (css_is_null_rect(a)) { - *a = *b; - } else { - if (b->x1 < a->x1) - a->x1 = b->x1; - if (b->y1 < a->y1) - a->y1 = b->y1; - if (b->x2 > a->x2) - a->x2 = b->x2; - if (b->y2 > a->y2) - a->y2 = b->y2; - } -} - -#ifdef __TINYC__ - -/* the glibc folks use wrappers, but forgot to put a compatibility - function for non GCC compilers ! */ -int stat(__const char *__path, - struct stat *__statbuf) -{ - return __xstat(_STAT_VER, __path, __statbuf); -} -#endif - -int get_clock_ms(void) -{ -#ifdef CONFIG_WIN32 - struct _timeb tb; - - _ftime(&tb); - return tb.time * 1000 + tb.millitm; -#else - struct timeval tv; - - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + (tv.tv_usec / 1000); -#endif -} - -int get_clock_usec(void) -{ -#ifdef CONFIG_WIN32 - struct _timeb tb; - - _ftime(&tb); - return tb.time * 1000000 + tb.millitm * 1000; -#else - struct timeval tv; - - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000 + tv.tv_usec; -#endif -} - /* set one string. */ StringItem *set_string(StringArray *cs, int index, const char *str, int group) { @@ -2255,63 +1401,7 @@ void free_strings(StringArray *cs) memset(cs, 0, sizeof(StringArray)); } -/** - * Add a memory region to a dynamic string. In case of allocation - * failure, the data is not added. The dynamic string is guaranteed to - * be 0 terminated, although it can be longer if it contains zeros. - * - * @return 0 if OK, -1 if allocation error. - */ -int qmemcat(QString *q, const unsigned char *data1, int len1) -{ - int new_len, len, alloc_size; - - len = q->len; - new_len = len + len1; - /* see if we got a new power of two */ - /* NOTE: we got this trick from the excellent 'links' browser */ - if ((len ^ new_len) >= len) { - /* find immediately bigger 2^n - 1 */ - alloc_size = new_len; - alloc_size |= (alloc_size >> 1); - alloc_size |= (alloc_size >> 2); - alloc_size |= (alloc_size >> 4); - alloc_size |= (alloc_size >> 8); - alloc_size |= (alloc_size >> 16); - /* allocate one more byte for end of string marker */ - if (!qe_realloc(&q->data, alloc_size + 1)) - return -1; - } - memcpy(q->data + len, data1, len1); - q->data[new_len] = '\0'; /* we force a trailing '\0' */ - q->len = new_len; - return 0; -} - -/* - * add a string to a dynamic string - */ -int qstrcat(QString *q, const char *str) -{ - return qmemcat(q, (const unsigned char *)str, strlen(str)); -} - -/* XXX: we use a fixed size buffer */ -int qprintf(QString *q, const char *fmt, ...) -{ - char buf[4096]; - va_list ap; - int len, ret; - - va_start(ap, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, ap); - /* avoid problems for non C99 snprintf() which can return -1 if overflow */ - if (len < 0) - len = strlen(buf); - ret = qmemcat(q, (unsigned char *)buf, len); - va_end(ap); - return ret; -} +/*---- Dynamic buffers with static allocation ----*/ int buf_write(buf_t *bp, const void *src, int size) { @@ -2457,29 +1547,53 @@ int buf_encode_byte(buf_t *out, unsigned char ch) { /*---------------- allocation routines ----------------*/ -void *qe_malloc_bytes(size_t size) -{ +void *qe_malloc_bytes(size_t size) { + /*@API memory + Allocate an uninitialized block of memory of a given size in + bytes. + @argument `size` the number of bytes to allocate. + @return a pointer to allocated memory, aligned on the maximum + alignment size. + */ return (malloc)(size); } -void *qe_mallocz_bytes(size_t size) -{ +void *qe_mallocz_bytes(size_t size) { + /*@API memory + Allocate a block of memory of a given size in bytes initialized + to all bits zero. + @argument `size` the number of bytes to allocate. + @return a pointer to allocated memory, aligned on the maximum + alignment size. + */ void *p = (malloc)(size); if (p) memset(p, 0, size); return p; } -void *qe_malloc_dup(const void *src, size_t size) -{ +void *qe_malloc_dup(const void *src, size_t size) { + /*@API memory + Allocate a block of memory of a given size in bytes initialized + as a copy of an existing object. + @argument `src` a valid pointer to the object to duplicate. + @argument `size` the number of bytes to allocate. + @return a pointer to allocated memory, aligned on the maximum + alignment size. + */ void *p = (malloc)(size); if (p) memcpy(p, src, size); return p; } -char *qe_strdup(const char *str) -{ +char *qe_strdup(const char *str) { + /*@API memory + Allocate a copy of a string. + @argument `src` a valid pointer to a string to duplicate. + @return a pointer to allocated memory, aligned on the maximum + alignment size. + */ size_t size = strlen(str) + 1; char *p = (malloc)(size); @@ -2488,8 +1602,21 @@ char *qe_strdup(const char *str) return p; } -void *qe_realloc(void *pp, size_t size) -{ +void *qe_realloc(void *pp, size_t size) { + /*@API memory + reallocate a block of memory to a different size. + @argument `pp` the address of a possibly null pointer to a + block to reallocate. `pp` is updated with the new pointer + if reallocation is successful. + @argument `size` the new size for the object. + @return a pointer to allocated memory, aligned on the maximum + alignment size. + @note this API makes it easier to check for success separately + from modifying the existing pointer, which is unchanged if + reallocation fails. This approach is not strictly conforming, + it assumes all pointers have the same size and representation, + which is mandated by POSIX. + */ void *p = (realloc)(*(void **)pp, size); if (p || !size) *(void **)pp = p; @@ -2627,6 +1754,24 @@ static inline void *med3_r(void *a, void *b, void *c, void *thunk, void qe_qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compare)(void *, const void *, const void *)) { + /*@API utils + Sort an array using a comparison function with an extra opaque + argument. + @argument `base` a valid pointer to an array of objects, + @argument `nmemb` the number of elements in the array, + @argument `size` the object size in bytes, + @argument `thunk` the generic argument to pass to the comparison + function, + @argument `compare` a function pointer for a comparison function + taking 3 arguments: the `thunk` argument and pointers to 2 + objects from the array, returning an integer whose sign indicates + their relative position according to the sort order. + @note this function behaves like OpenBSD's `qsort_r()`, the + implementation is non recursive using a combination of quicksort + and insertion sort for small chunks. The GNU lib C on linux also + has a function `qsort_r()` with similar semantics but a different + calling convention. + */ struct { unsigned char *base; size_t count; diff --git a/util.h b/util.h new file mode 100644 index 0000000..02771b1 --- /dev/null +++ b/util.h @@ -0,0 +1,594 @@ +/* + * Utilities for qemacs. + * + * Copyright (c) 2000-2001 Fabrice Bellard. + * Copyright (c) 2000-2022 Charlie Gordon. + * + * 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. + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include + +/* OS specific defines */ + +#ifdef CONFIG_WIN32 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif + +#if (defined(__GNUC__) || defined(__TINYC__)) +/* make sure that the keyword is not disabled by glibc (TINYC case) */ +#define qe__attr_printf(a, b) __attribute__((format(printf, a, b))) +#else +#define qe__attr_printf(a, b) +#endif + +#if defined(__GNUC__) && __GNUC__ > 2 +#define qe__attr_nonnull(l) __attribute__((nonnull l)) +#define qe__unused__ __attribute__((unused)) +#else +#define qe__attr_nonnull(l) +#define qe__unused__ +#endif + +#ifndef offsetof +#define offsetof(s,m) ((size_t)(&((s *)0)->m)) +#endif +#ifndef countof +#define countof(a) ((int)(sizeof(a) / sizeof((a)[0]))) +#endif +#ifndef ssizeof +#define ssizeof(a) ((int)(sizeof(a))) +#endif + +#define OWNED /* ptr attribute for allocated data owned by a structure */ + +/* prevent gcc warning about shadowing a global declaration */ +#define index index__ + +typedef unsigned char u8; + +static inline char *s8(u8 *p) { return (char*)p; } +static inline const char *cs8(const u8 *p) { return (const char*)p; } + +/* string arrays */ +typedef struct StringItem { + void *opaque; /* opaque data that the user can use */ + char selected; /* true if selected */ + char group; /* used to group sorted items */ + char str[1]; +} StringItem; + +typedef struct StringArray { + int nb_allocated; + int nb_items; + StringItem **items; +} StringArray; +#define NULL_STRINGARRAY { 0, 0, NULL } + +typedef struct FindFileState FindFileState; + +#define FF_PATH 0x010 /* enumerate path argument */ +#define FF_NODIR 0x020 /* only match regular files */ +#define FF_NOXXDIR 0x040 /* do not match . or .. */ +#define FF_ONLYDIR 0x080 /* do not match non directories */ +#define FF_DEPTH 0x00f /* max recursion depth */ + +FindFileState *find_file_open(const char *path, const char *pattern, int flags); +int find_file_next(FindFileState *s, char *filename, int filename_size_max); +void find_file_close(FindFileState **sp); +int is_directory(const char *path); +int is_filepattern(const char *filespec); +void canonicalize_path(char *buf, int buf_size, const char *path); +char *make_user_path(char *buf, int buf_size, const char *path); +char *reduce_filename(char *dest, int size, const char *filename); +char *file_load(const char *filename, int max_size, int *sizep); +int match_extension(const char *filename, const char *extlist); +int match_shell_handler(const char *p, const char *list); +int remove_slash(char *buf); +int append_slash(char *buf, int buf_size); +char *makepath(char *buf, int buf_size, const char *path, const char *filename); +void splitpath(char *dirname, int dirname_size, + char *filename, int filename_size, const char *pathname); + +extern unsigned char const qe_digit_value__[128]; +static inline int qe_digit_value(int c) { + return (unsigned int)c < 128 ? qe_digit_value__[c] : 255; +} +static inline int qe_inrange(int c, int a, int b) { + //return c >= a && c <= b; + //CG: assuming a <= b and wrap around semantics for (c - a) and (b - a) + return (unsigned int)(c - a) <= (unsigned int)(b - a); +} +/* character classification tests assume ASCII superset */ +static inline int qe_isspace(int c) { + /* CG: what about \v and \f */ + return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == 160); +} +static inline int qe_isblank(int c) { + return (c == ' ' || c == '\t' || c == 160); +} +static inline int qe_isdigit(int c) { + return qe_inrange(c, '0', '9'); +} +static inline int qe_isdigit_(int c) { + return (qe_inrange(c, '0', '9') || c == '_'); +} +static inline int qe_isupper(int c) { + return qe_inrange(c, 'A', 'Z'); +} +static inline int qe_isupper_(int c) { + return (qe_inrange(c, 'A', 'Z') || c == '_'); +} +static inline int qe_islower(int c) { + return qe_inrange(c, 'a', 'z'); +} +static inline int qe_islower_(int c) { + return (qe_inrange(c, 'a', 'z') || (c == '_')); +} +static inline int qe_isalpha(int c) { + return qe_inrange(c | ('a' - 'A'), 'a', 'z'); +} +static inline int qe_isalpha_(int c) { + return (qe_inrange(c | ('a' - 'A'), 'a', 'z') || c == '_'); +} +static inline int qe_isoctdigit(int c) { + return qe_inrange(c, '0', '7'); +} +static inline int qe_isoctdigit_(int c) { + return qe_inrange(c, '0', '7') || (c == '_'); +} +static inline int qe_isbindigit(int c) { + return qe_inrange(c, '0', '1'); +} +static inline int qe_isbindigit_(int c) { + return qe_inrange(c, '0', '1') || (c == '_'); +} +static inline int qe_isxdigit(int c) { + return qe_digit_value(c) < 16; +} +static inline int qe_isxdigit_(int c) { + return (qe_digit_value(c) < 16) || (c == '_'); +} +static inline int qe_isalnum(int c) { + return qe_digit_value(c) < 36; +} +static inline int qe_isalnum_(int c) { + return (qe_digit_value(c) < 36) || (c == '_'); +} +static inline int qe_isword(int c) { + /* XXX: any unicode char >= 128 is considered as word. */ + return qe_isalnum_(c) || (c >= 128); +} +static inline int qe_toupper(int c) { + return (qe_inrange(c, 'a', 'z') ? c + 'A' - 'a' : c); +} +static inline int qe_tolower(int c) { + return (qe_inrange(c, 'A', 'Z') ? c + 'a' - 'A' : c); +} +static inline int qe_findchar(const char *str, int c) { + return qe_inrange(c, 1, 255) && strchr(str, c) != NULL; +} +static inline int qe_indexof(const char *str, int c) { + if (qe_inrange(c, 1, 255)) { + const char *p = strchr(str, c); + if (p) return (int)(p - str); + } + return -1; +} + +static inline int qe_match2(int c, int c1, int c2) { + return c == c1 || c == c2; +} + +static inline int check_fcall(const unsigned int *str, int i) { + while (str[i] == ' ') + i++; + return str[i] == '('; +} + +int ustr_get_identifier(char *buf, int buf_size, int c, + const unsigned int *str, int i, int n); +int ustr_get_identifier_lc(char *buf, int buf_size, int c, + const unsigned int *str, int i, int n); +int ustr_get_word(char *buf, int buf_size, int c, + const unsigned int *str, int i, int n); + +int qe_strcollate(const char *s1, const char *s2); +int qe_strtobool(const char *s, int def); +void qe_strtolower(char *buf, int buf_size, const char *str); +int qe_skip_spaces(const char **pp); + +static inline int strequal(const char *s1, const char *s2) { + return !strcmp(s1, s2); +} + +int memfind(const char *list, const char *p, int len); +int strfind(const char *list, const char *s); +int strxfind(const char *list, const char *s); +const char *strmem(const char *str, const void *mem, int size); +const void *memstr(const void *buf, int size, const char *str); + +#define stristart(str, val, ptr) qe_stristart(str, val, ptr) +int stristart(const char *str, const char *val, const char **ptr); +int strxstart(const char *str, const char *val, const char **ptr); +int strxcmp(const char *str1, const char *str2); +int strmatchword(const char *str, const char *val, const char **ptr); +int ustrstart(const unsigned int *str, const char *val, int *lenp); +int ustristart(const unsigned int *str, const char *val, int *lenp); +const unsigned int *ustrstr(const unsigned int *str, const char *val); +const unsigned int *ustristr(const unsigned int *str, const char *val); +static inline unsigned int *umemmove(unsigned int *dest, + const unsigned int *src, size_t count) { + return (unsigned int *)memmove(dest, src, count * sizeof(unsigned int)); +} +static inline unsigned int *umemcpy(unsigned int *dest, + const unsigned int *src, size_t count) { + return (unsigned int *)memcpy(dest, src, count * sizeof(unsigned int)); +} +int umemcmp(const unsigned int *s1, const unsigned int *s2, size_t count); +int qe_memicmp(const void *p1, const void *p2, size_t count); +const char *qe_stristr(const char *s1, const char *s2); + +int strsubst(char *buf, int buf_size, const char *from, + const char *s1, const char *s2); +int byte_quote(char *dest, int size, unsigned char c); +int strquote(char *dest, int size, const char *str, int len); +int strunquote(char *dest, int size, const char *str, int len); +int get_str(const char **pp, char *buf, int buf_size, const char *stop); + +/* allocation wrappers and utilities */ +void *qe_malloc_bytes(size_t size); +void *qe_mallocz_bytes(size_t size); +void *qe_malloc_dup(const void *src, size_t size); +char *qe_strdup(const char *str); +void *qe_realloc(void *pp, size_t size); + +#if 0 +/* Documentation prototypes */ +T *qe_malloc(type T); +/*@API memory + Allocate memory for an object of type `T`. + @argument `T` the type of the object to allocate. + @note this function is implemented as a macro. + */ +T *qe_mallocz(type T); +/*@API memory + Allocate memory for an object of type `T`. + The object is initialized to all bits zero. + @argument `T` the type of the object to allocate. + @note this function is implemented as a macro. + */ +T *qe_malloc_array(type T, size_t n); +/*@API memory + Allocate memory for an array of objects of type `T`. + @argument `T` the type of the object to allocate. + @argument `n` the number of elements to allocate. + @note this function is implemented as a macro. + */ +T *qe_mallocz_array(type T, size_t n); +/*@API memory + Allocate memory for an array of objects of type `T`. + The objects are initialized to all bits zero. + @argument `T` the type of the object to allocate. + @argument `n` the number of elements to allocate. + @note this function is implemented as a macro. + */ +T *qe_malloc_hack(type T, size_t n); +/*@API memory + Allocate memory for an object of type `T` with `n` extra bytes. + @argument `T` the type of the object to allocate. + @argument `n` the number of bytes to allocate in addition to the size of type `T`. + @note this function is implemented as a macro. + */ +T *qe_mallocz_array(type T, size_t n); +/*@API memory + Allocate memory for an object of type `T` with `n` extra bytes. + The object and the extra space is initialized to all bits zero. + @argument `T` the type of the object to allocate. + @argument `n` the number of bytes to allocate in addition to the size of type `T`. + @note this function is implemented as a macro. + */ +void qe_free(T **pp); +/*@API memory + Free the allocated memory pointed to by a pointer whose address is passed. + @argument `pp` the address of a possibly null pointer. This pointer is set + to `NULL` after freeing the memory. If the pointer memory is null, + nothing happens. + @argument `n` the number of bytes to allocate in addition to the size of type `T`. + @note this function is implemented as a macro. + */ +#endif +#define qe_malloc(t) ((t *)qe_malloc_bytes(sizeof(t))) +#define qe_mallocz(t) ((t *)qe_mallocz_bytes(sizeof(t))) +#define qe_malloc_array(t, n) ((t *)qe_malloc_bytes((n) * sizeof(t))) +#define qe_mallocz_array(t, n) ((t *)qe_mallocz_bytes((n) * sizeof(t))) +#define qe_malloc_hack(t, n) ((t *)qe_malloc_bytes(sizeof(t) + (n))) +#define qe_mallocz_hack(t, n) ((t *)qe_mallocz_bytes(sizeof(t) + (n))) + +#if 1 // to test clang -Weverything +#define qe_free(pp) do { void *_ = (pp); (free)(*(void **)_); *(void **)_ = NULL; } while (0) +#elif defined CONFIG_HAS_TYPEOF +#define qe_free(pp) do { typeof(**(pp)) **__ = (pp); (free)(*__); *__ = NULL; } while (0) +#else +#define qe_free(pp) do if (sizeof(**(pp)) >= 0) { void *_ = (pp); (free)(*(void **)_); *(void **)_ = NULL; } while (0) +#endif + +/* prevent the use of regular malloc and free functions */ +#ifndef free +#define free(p) do_not_use_free!!(p) +#endif +#ifndef malloc +#define malloc(s) do_not_use_malloc!!(s) +#endif +#ifndef realloc +#define realloc(p,s) do_not_use_realloc!!(p,s) +#endif + +/*---- Various string packages: should unify these but keep API simple ----*/ + +StringItem *set_string(StringArray *cs, int index, const char *str, int group); +StringItem *add_string(StringArray *cs, const char *str, int group); +void free_strings(StringArray *cs); + +/*---- Dynamic buffers with static allocation ----*/ + +typedef struct buf_t buf_t; +struct buf_t { + char *buf; + int size, len, pos; +}; + +static inline buf_t *buf_init(buf_t *bp, char *buf, int size) { + if (size > 0) { + bp->buf = buf; + bp->size = size; + *buf = '\0'; + } else { + bp->buf = NULL; + bp->size = 0; + } + bp->len = bp->pos = 0; + return bp; +} + +static inline buf_t *buf_attach(buf_t *bp, char *buf, int size, int pos) { + /* assuming 0 <= pos < size */ + // XXX: Does not set a null byte? + bp->buf = buf; + bp->size = size; + bp->len = bp->pos = pos; + return bp; +} +static inline int buf_avail(buf_t *bp) { + return bp->size - bp->pos - 1; +} +static inline int buf_put_byte(buf_t *bp, int c) { + if (bp->len < bp->size - 1) { + bp->buf[bp->len++] = c; + bp->buf[bp->len] = '\0'; + } + return bp->pos++; +} +int buf_write(buf_t *bp, const void *src, int size); +static inline int buf_puts(buf_t *bp, const char *str) { + return buf_write(bp, str, strlen(str)); +} + +int buf_printf(buf_t *bp, const char *fmt, ...) qe__attr_printf(2,3); +int buf_putc_utf8(buf_t *bp, int c); + +/*---- Bounded constant strings used in various parse functions ----*/ +typedef struct bstr_t { + const char *s; + int len; +} bstr_t; + +static inline bstr_t bstr_make(const char *s) { + bstr_t bs = { s, s ? strlen(s) : 0 }; + return bs; +} + +bstr_t bstr_token(const char *s, int sep, const char **pp); +bstr_t bstr_get_nth(const char *s, int n); + +static inline int bstr_equal(bstr_t s1, bstr_t s2) { + /* NULL and empty strings are equivalent */ + return s1.len == s2.len && !memcmp(s1.s, s2.s, s1.len); +} + +/* our own implementation of qsort_r() */ +void qe_qsort_r(void *base, size_t nmemb, size_t size, void *thunk, + int (*compar)(void *, const void *, const void *)); + +/* various arithmetic functions */ +static inline int max(int a, int b) { + if (a > b) + return a; + else + return b; +} + +static inline int maxp(int *pa, int b) { + int a = *pa; + if (a > b) + return a; + else + return *pa = b; +} + +static inline int max3(int a, int b, int c) { + return max(max(a, b), c); +} + +static inline int min(int a, int b) { + if (a < b) + return a; + else + return b; +} + +static inline int minp(int *pa, int b) { + int a = *pa; + if (a < b) + return a; + else + return *pa = b; +} + +static inline int min3(int a, int b, int c) { + return min(min(a, b), c); +} + +static inline int clamp(int a, int b, int c) { + if (a < b) + return b; + else + if (a > c) + return c; + else + return a; +} + +static inline int clampp(int *pa, int b, int c) { + int a = *pa; + if (a < b) + return *pa = b; + else + if (a > c) + return *pa = c; + else + return a; +} + +static inline int compute_percent(int a, int b) { + return b <= 0 ? 0 : (int)((long long)a * 100 / b); +} + +static inline int align(int a, int n) { + return (a / n) * n; +} + +static inline int scale(int a, int b, int c) { + return (a * b + c / 2) / c; +} + +/*---------------- key definitions ----------------*/ + +int compose_keys(unsigned int *keys, int *nb_keys); +int strtokey(const char **pp); +int strtokeys(const char *keystr, unsigned int *keys, int max_keys, const char **endp); +int buf_put_key(buf_t *out, int key); +int buf_put_keys(buf_t *out, unsigned int *keys, int nb_keys); +int buf_encode_byte(buf_t *out, unsigned char ch); + +#define KEY_CTRL(c) ((c) & 0x001f) +/* allow combinations such as KEY_META(KEY_LEFT) */ +#define KEY_META(c) ((c) | 0xe100) +#define KEY_ESC1(c) ((c) | 0xe200) +#define KEY_IS_ESC1(c) ((c) >= KEY_ESC1(0) && (c) <= KEY_ESC1(0xff)) +#define KEY_IS_SPECIAL(c) ((c) >= 0xe000 && (c) < 0xf000) +#define KEY_IS_CONTROL(c) (((c) >= 0 && (c) < 32) || (c) == 127) + +#define KEY_NONE 0xE000 +#define KEY_DEFAULT 0xE001 /* to handle all non special keys */ +#define KEY_UNKNOWN 0xE002 + +#define KEY_TAB KEY_CTRL('i') +#define KEY_LF KEY_CTRL('j') +#define KEY_RET KEY_CTRL('m') +#define KEY_ESC KEY_CTRL('[') +#define KEY_SPC 0x0020 +#define KEY_DEL 127 // kbs +#define KEY_BS KEY_CTRL('h') // kbs + +#define KEY_UP KEY_ESC1('A') // kcuu1 +#define KEY_DOWN KEY_ESC1('B') // kcud1 +#define KEY_RIGHT KEY_ESC1('C') // kcuf1 +#define KEY_LEFT KEY_ESC1('D') // kcub1 +#define KEY_CTRL_UP KEY_ESC1('a') +#define KEY_CTRL_DOWN KEY_ESC1('b') +#define KEY_CTRL_RIGHT KEY_ESC1('c') +#define KEY_CTRL_LEFT KEY_ESC1('d') +#define KEY_CTRL_END KEY_ESC1('f') +#define KEY_CTRL_HOME KEY_ESC1('h') +#define KEY_CTRL_PAGEUP KEY_ESC1('i') +#define KEY_CTRL_PAGEDOWN KEY_ESC1('j') +#define KEY_SHIFT_UP KEY_ESC1('a'+128) +#define KEY_SHIFT_DOWN KEY_ESC1('b'+128) +#define KEY_SHIFT_RIGHT KEY_ESC1('c'+128) +#define KEY_SHIFT_LEFT KEY_ESC1('d'+128) +#define KEY_SHIFT_END KEY_ESC1('f'+128) +#define KEY_SHIFT_HOME KEY_ESC1('h'+128) +#define KEY_SHIFT_PAGEUP KEY_ESC1('i'+128) +#define KEY_SHIFT_PAGEDOWN KEY_ESC1('j'+128) +#define KEY_CTRL_SHIFT_UP KEY_ESC1('a'+64) +#define KEY_CTRL_SHIFT_DOWN KEY_ESC1('b'+64) +#define KEY_CTRL_SHIFT_RIGHT KEY_ESC1('c'+64) +#define KEY_CTRL_SHIFT_LEFT KEY_ESC1('d'+64) +#define KEY_CTRL_SHIFT_END KEY_ESC1('f'+64) +#define KEY_CTRL_SHIFT_HOME KEY_ESC1('h'+64) +#define KEY_CTRL_SHIFT_PAGEUP KEY_ESC1('i'+64) +#define KEY_CTRL_SHIFT_PAGEDOWN KEY_ESC1('j'+64) +#define KEY_SHIFT_TAB KEY_ESC1('Z') // kcbt +#define KEY_HOME KEY_ESC1(1) // khome +#define KEY_INSERT KEY_ESC1(2) // kich1 +#define KEY_DELETE KEY_ESC1(3) // kdch1 +#define KEY_END KEY_ESC1(4) // kend +#define KEY_PAGEUP KEY_ESC1(5) // kpp +#define KEY_PAGEDOWN KEY_ESC1(6) // knp +#define KEY_F1 KEY_ESC1(11) +#define KEY_F2 KEY_ESC1(12) +#define KEY_F3 KEY_ESC1(13) +#define KEY_F4 KEY_ESC1(14) +#define KEY_F5 KEY_ESC1(15) +#define KEY_F6 KEY_ESC1(17) +#define KEY_F7 KEY_ESC1(18) +#define KEY_F8 KEY_ESC1(19) +#define KEY_F9 KEY_ESC1(20) +#define KEY_F10 KEY_ESC1(21) +#define KEY_F11 KEY_ESC1(23) +#define KEY_F12 KEY_ESC1(24) +#define KEY_F13 KEY_ESC1(25) +#define KEY_F14 KEY_ESC1(26) +#define KEY_F15 KEY_ESC1(28) +#define KEY_F16 KEY_ESC1(29) +#define KEY_F17 KEY_ESC1(31) +#define KEY_F18 KEY_ESC1(32) +#define KEY_F19 KEY_ESC1(33) +#define KEY_F20 KEY_ESC1(34) + +extern unsigned char const utf8_length[256]; +static inline int utf8_is_trailing_byte(int c) { return (c & 0xC0) == 0x80; } +int utf8_encode(char *q, int c); +int utf8_decode(const char **pp); +char *utf8_char_to_string(char *buf, int c); +int utf8_to_unicode(unsigned int *dest, int dest_length, const char *str); + +int unicode_tty_glyph_width(unsigned int ucs); + +static inline int qe_isaccent(int c) { + return c >= 0x300 && unicode_tty_glyph_width(c) == 0; +} + +static inline int qe_iswide(int c) { + return c >= 0x01000 && unicode_tty_glyph_width(c) > 1; +} + +#endif /* UTIL_H */