├── .cirrus.yml ├── .github └── ci │ ├── before-install.sh │ └── build.sh ├── .gitignore ├── .woodpecker.yaml ├── ChangeLog ├── LICENSE ├── Makefile.am ├── README.md ├── autogen.sh ├── bufio.c ├── bufio.h ├── certs.c ├── certs.h ├── cmd.c ├── cmd.h ├── compat.h ├── compat ├── asprintf.c ├── err.c ├── explicit_bzero.c ├── fgetln.c ├── fmt_scaled.c ├── fparseln.c ├── freezero.c ├── getdtablecount.c ├── getdtablesize.c ├── getprogname.c ├── imsg-buffer.c ├── imsg.c ├── imsg.h ├── memmem.c ├── ohash.c ├── ohash.h ├── queue.h ├── reallocarray.c ├── recallocarray.c ├── setproctitle.c ├── strcasestr.c ├── strlcat.c ├── strlcpy.c ├── strsep.c └── strtonum.c ├── compl.c ├── compl.h ├── configure.ac ├── contrib ├── README.md ├── brutalist.config ├── coccinelle │ └── wrap.cocci ├── dark.config ├── light.config └── xdg-migrate.sh ├── control.c ├── control.h ├── data └── emoji.txt ├── defaults.c ├── defaults.h ├── downloads.c ├── ev.c ├── ev.h ├── exec.c ├── exec.h ├── extra └── about-new.png ├── fs.c ├── fs.h ├── gencmd.awk ├── genemoji.sh ├── help.c ├── hist.c ├── hist.h ├── identity.c ├── imsgev.c ├── imsgev.h ├── iri.c ├── iri.h ├── keymap.c ├── keymap.h ├── keys ├── telescope-0.10.pub ├── telescope-0.11.pub ├── telescope-0.12.pub ├── telescope-0.3.pub ├── telescope-0.4.pub ├── telescope-0.5.pub ├── telescope-0.6.pub ├── telescope-0.7.pub ├── telescope-0.8.pub └── telescope-0.9.pub ├── libgrapheme ├── LICENSE ├── Makefile ├── README ├── benchmark │ ├── case.c │ ├── character.c │ ├── line.c │ ├── sentence.c │ ├── utf8-decode.c │ ├── util.c │ ├── util.h │ └── word.c ├── config.mk ├── configure ├── data │ ├── DerivedCoreProperties.txt │ ├── EastAsianWidth.txt │ ├── GraphemeBreakProperty.txt │ ├── GraphemeBreakTest.txt │ ├── LICENSE │ ├── LineBreak.txt │ ├── LineBreakTest.txt │ ├── SentenceBreakProperty.txt │ ├── SentenceBreakTest.txt │ ├── SpecialCasing.txt │ ├── UnicodeData.txt │ ├── WordBreakProperty.txt │ ├── WordBreakTest.txt │ └── emoji-data.txt ├── gen │ ├── case.c │ ├── character-test.c │ ├── character.c │ ├── line-test.c │ ├── line.c │ ├── sentence-test.c │ ├── sentence.c │ ├── types.h │ ├── util.c │ ├── util.h │ ├── word-test.c │ └── word.c ├── grapheme.h ├── man │ ├── grapheme_decode_utf8.sh │ ├── grapheme_encode_utf8.sh │ ├── grapheme_is_character_break.sh │ ├── grapheme_is_lowercase.sh │ ├── grapheme_is_lowercase_utf8.sh │ ├── grapheme_is_titlecase.sh │ ├── grapheme_is_titlecase_utf8.sh │ ├── grapheme_is_uppercase.sh │ ├── grapheme_is_uppercase_utf8.sh │ ├── grapheme_next_character_break.sh │ ├── grapheme_next_character_break_utf8.sh │ ├── grapheme_next_line_break.sh │ ├── grapheme_next_line_break_utf8.sh │ ├── grapheme_next_sentence_break.sh │ ├── grapheme_next_sentence_break_utf8.sh │ ├── grapheme_next_word_break.sh │ ├── grapheme_next_word_break_utf8.sh │ ├── grapheme_to_lowercase.sh │ ├── grapheme_to_lowercase_utf8.sh │ ├── grapheme_to_titlecase.sh │ ├── grapheme_to_titlecase_utf8.sh │ ├── grapheme_to_uppercase.sh │ ├── grapheme_to_uppercase_utf8.sh │ ├── libgrapheme.sh │ └── template │ │ ├── is_case.sh │ │ ├── next_break.sh │ │ └── to_case.sh ├── src │ ├── case.c │ ├── character.c │ ├── line.c │ ├── sentence.c │ ├── utf8.c │ ├── util.c │ ├── util.h │ └── word.c └── test │ ├── case.c │ ├── character.c │ ├── line.c │ ├── sentence.c │ ├── utf8-decode.c │ ├── utf8-encode.c │ ├── util.c │ ├── util.h │ └── word.c ├── mailcap.c ├── mailcap.h ├── maintenance └── README.md ├── mcache.c ├── mcache.h ├── mime.c ├── minibuffer.c ├── minibuffer.h ├── net.c ├── pagebundler.c ├── pages.h ├── pages ├── about_about.gmi.in ├── about_blank.gmi.in ├── about_crash.gmi.in ├── about_help.gmi.in ├── about_license.gmi.in ├── about_new.gmi.in └── bookmarks.gmi.in ├── parse.y ├── parser.c ├── parser.h ├── parser_gemtext.c ├── parser_gophermap.c ├── parser_textpatch.c ├── parser_textplain.c ├── sandbox.c ├── session.c ├── session.h ├── telescope-identity.1 ├── telescope.1 ├── telescope.c ├── telescope.h ├── test ├── .gitignore ├── Makefile.am ├── evtest.c ├── gm-00 ├── gm-01 ├── gmi-00 ├── gmi-01 ├── gmiparser.c ├── gmparser.c ├── iritest.c ├── mailcap.c ├── mc.exp.empty ├── mc.exp.many ├── mc.exp.simple ├── mc.test.empty ├── mc.test.many ├── mc.test.simple ├── test-gmparser └── test-mailcap ├── tofu.c ├── tofu.h ├── ui.c ├── ui.h ├── utf8.c ├── utf8.h ├── utils.c ├── utils.h ├── wrap.c ├── xwrapper.c └── xwrapper.h /.cirrus.yml: -------------------------------------------------------------------------------- 1 | telescope_ubuntu_task: 2 | container: 3 | image: ubuntu:latest 4 | before_build_script: .github/ci/before-install.sh 5 | build:script: .github/ci/build.sh 6 | test_script: make check 7 | 8 | telescope_alpine_linux_task: 9 | container: 10 | image: alpine:latest 11 | before_build_script: .github/ci/before-install.sh 12 | build:script: .github/ci/build.sh 13 | test_script: make check 14 | 15 | telescope_freebsd_task: 16 | freebsd_instance: 17 | image_family: freebsd-14-2 18 | before_build_script: .github/ci/before-install.sh 19 | build:script: .github/ci/build.sh 20 | test_script: make check 21 | 22 | telescope_macos_task: 23 | macos_instance: 24 | image: ghcr.io/cirruslabs/macos-ventura-base:latest 25 | before_build_script: .github/ci/before-install.sh 26 | build:script: .github/ci/build.sh 27 | test_script: make check 28 | -------------------------------------------------------------------------------- /.github/ci/before-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | case "$(uname)" in 6 | *Linux*) 7 | set +e 8 | ID="$(. /etc/os-release && echo $ID)" 9 | set -e 10 | 11 | case "$ID" in 12 | alpine) 13 | apk update 14 | apk add alpine-sdk autoconf automake pkgconf make byacc \ 15 | libbsd-dev ncurses-dev libretls-dev 16 | ;; 17 | *) 18 | # assume debian-derived. 19 | apt-get update -qq 20 | apt-get --no-install-suggests --no-install-recommends -y install \ 21 | bison \ 22 | autoconf \ 23 | autotools-dev \ 24 | automake \ 25 | libncurses5-dev \ 26 | pkg-config \ 27 | build-essential \ 28 | libssl-dev \ 29 | libbsd-dev \ 30 | libtls-dev 31 | ;; 32 | esac 33 | ;; 34 | 35 | *FreeBSD*) 36 | pkg install -y \ 37 | automake \ 38 | pkgconf \ 39 | git \ 40 | libretls 41 | ;; 42 | 43 | *Darwin*) 44 | brew install autoconf \ 45 | automake \ 46 | bison \ 47 | pkg-config \ 48 | ncurses \ 49 | git \ 50 | libressl \ 51 | libretls 52 | ;; 53 | 54 | *) 55 | echo "unknown operating system $(uname)" >&2 56 | exit 1 57 | ;; 58 | esac 59 | -------------------------------------------------------------------------------- /.github/ci/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./autogen.sh || exit 1 4 | ./configure || exit 1 5 | exec make 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | TAGS 2 | pages/*.gmi 3 | 4 | **/*.o 5 | **/.deps 6 | **/.dirstamp 7 | **/Makefile 8 | **/Makefile.in 9 | **/build 10 | **/etc 11 | **/obj 12 | 13 | aclocal.m4 14 | autom4te.cache 15 | compile 16 | config.* 17 | configure 18 | depcomp 19 | install-sh 20 | missing 21 | stamp-h1 22 | ylwrap 23 | test-driver 24 | 25 | cmd.gen.c 26 | parse.c 27 | pages.c 28 | telescope 29 | pagebundler 30 | telescope-*.tar.gz 31 | u/emoji-matcher.c 32 | 33 | site/gemini 34 | site/www 35 | -------------------------------------------------------------------------------- /.woodpecker.yaml: -------------------------------------------------------------------------------- 1 | matrix: 2 | TELESCOPE_BASE_IMAGE: 3 | - ghcr.io/telescope-browser/tbi-alpine:latest 4 | - ghcr.io/telescope-browser/tbi-debian:latest 5 | 6 | when: 7 | - event: [tag, push, pull_request] 8 | 9 | steps: 10 | - name: build 11 | image: ${TELESCOPE_BASE_IMAGE} 12 | commands: 13 | - ./.github/ci/before-install.sh 14 | - ./autogen.sh 15 | - ./configure 16 | - make 17 | - make check 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021-2024 Omar Polo 2 | 3 | Permission to use, copy, modify, and/or distribute this software for 4 | any purpose with or without fee is hereby granted, provided that the 5 | above copyright notice and this permission notice appear in all 6 | copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 11 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = test 2 | 3 | bin_PROGRAMS = telescope telescope-identity 4 | 5 | EXTRA_telescope_SOURCES = compat/ohash.h compat/queue.h compat/imsg.h contrib \ 6 | keys 7 | 8 | telescope_SOURCES = bufio.c bufio.h certs.c certs.h cmd.c cmd.gen.c cmd.h \ 9 | compat.h compl.c compl.h control.c control.h \ 10 | defaults.c defaults.h downloads.c emoji-matcher.c \ 11 | ev.c ev.h exec.c exec.h fs.c fs.h \ 12 | gencmd.awk genemoji.sh help.c hist.c imsgev.c imsgev.h \ 13 | iri.c iri.h keymap.c keymap.h mailcap.c mailcap.h \ 14 | mcache.c mcache.h mime.c minibuffer.c minibuffer.h \ 15 | net.c pages.c pages.h parse.y parser.c parser.h \ 16 | parser_gemtext.c parser_gophermap.c parser_textpatch.c \ 17 | parser_textplain.c sandbox.c session.c session.h \ 18 | telescope.c telescope.h tofu.c tofu.h ui.c ui.h \ 19 | utf8.c utf8.h utils.c utils.h wrap.c \ 20 | xwrapper.c xwrapper.h 21 | 22 | telescope_identity_SOURCES = certs.c certs.h fs.c fs.h hist.c hist.h \ 23 | identity.c parser.c parser.h xwrapper.c xwrapper.h 24 | 25 | noinst_PROGRAMS = pagebundler 26 | pagebundler_SOURCES = pagebundler.c 27 | 28 | EXCLUDE_FROM_COCCI = bufio.c certs.c cmd-gen.c emoji-matcher.c ev.c hist.c \ 29 | pages.c parse.c xwrapper.c 30 | EXTS = .c .y 31 | 32 | SPATCH_FILES = $(foreach ext,$(EXTS),$(filter %$(ext), \ 33 | $(filter-out $(EXCLUDE_FROM_COCCI), \ 34 | $(telescope_SOURCES), $(telescope_identity_SOURCES), \ 35 | $(wildcard test/*.c)))) 36 | .PHONY: cocci 37 | cocci: 38 | spatch --sp-file ./contrib/coccinelle/wrap.cocci \ 39 | --in-place $(SPATCH_FILES) 40 | 41 | # Override implicit rule since we have to use HOSTCC and not CC. 42 | pagebundler$(EXEEXT): pagebundler.c 43 | $(HOSTCC) $(HOSTCFLAGS) -o $@ $(srcdir)/pagebundler.c 44 | 45 | # ugly; builds bundled libgrapheme if needed 46 | .NOTPARALLEL: 47 | .NOPARALLEL: 48 | $(LIBGRAPHEME): 49 | ${MAKE} -C $(srcdir)/libgrapheme libgrapheme.a 50 | 51 | clean-local: 52 | test -n "$(LIBGRAPHEME)" && ${MAKE} -C libgrapheme clean || true 53 | 54 | BUILT_SOURCES = cmd.gen.c emoji-matcher.c pages.c 55 | 56 | CLEANFILES = cmd.gen.c emoji-matcher.c pages.c parse.c 57 | 58 | LDADD = $(LIBOBJS) $(LIBGRAPHEME) 59 | EXTRA_telescope_DEPENDENCIES = $(LIBGRAPHEME) 60 | 61 | EXTRA_DIST = ChangeLog LICENSE README.md data/emoji.txt \ 62 | libgrapheme pages/*.gmi 63 | 64 | dist_man1_MANS = telescope.1 telescope-identity.1 65 | 66 | cmd.gen.c: $(srcdir)/cmd.h $(srcdir)/gencmd.awk 67 | ${AWK} -f $(srcdir)/gencmd.awk < $(srcdir)/cmd.h > $@ 68 | 69 | emoji-matcher.c: $(srcdir)/data/emoji.txt $(srcdir)/genemoji.sh 70 | $(srcdir)/genemoji.sh $(srcdir)/data/emoji.txt > $@ 71 | 72 | PAGES = $(builddir)/pages/about_about.gmi \ 73 | $(builddir)/pages/about_blank.gmi \ 74 | $(builddir)/pages/about_crash.gmi \ 75 | $(builddir)/pages/about_help.gmi \ 76 | $(builddir)/pages/about_license.gmi \ 77 | $(builddir)/pages/about_new.gmi 78 | pages.c: pagebundler $(srcdir)/pages.h ${PAGES} 79 | echo "#include \"pages.h\"" > $@ 80 | ./pagebundler $(builddir)/pages/about_about.gmi >> $@ 81 | ./pagebundler $(builddir)/pages/about_blank.gmi >> $@ 82 | ./pagebundler $(builddir)/pages/about_crash.gmi >> $@ 83 | ./pagebundler $(builddir)/pages/about_help.gmi >> $@ 84 | ./pagebundler $(builddir)/pages/about_license.gmi >> $@ 85 | ./pagebundler $(builddir)/pages/about_new.gmi >> $@ 86 | ./pagebundler $(builddir)/pages/bookmarks.gmi >> $@ 87 | 88 | # --- maintainer targets --- 89 | 90 | PUBKEY = missing 91 | PRIVKEY = missing 92 | 93 | # Ensure that, before we release, that the files in libgrapheme don't include 94 | # any compiled files, etc. We don't want these as part of a release tarball. 95 | dist-hook: 96 | ${MAKE} -C $(distdir)/libgrapheme clean 97 | 98 | release: dist 99 | sha256 ${distdir}.tar.gz > ${distdir}.tar.gz.sha256 100 | signify -S -e -m ${distdir}.tar.gz.sha256 -s ${PRIVKEY} 101 | signify -C -p ${PUBKEY} -x ${distdir}.tar.gz.sha256.sig 102 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec autoreconf -vfi 4 | -------------------------------------------------------------------------------- /bufio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | struct tls; 27 | 28 | #define BIO_CHUNK 128 29 | struct buf { 30 | uint8_t *buf; 31 | size_t len; 32 | size_t cap; 33 | size_t cur; 34 | }; 35 | 36 | struct bufio { 37 | int fd; 38 | struct tls *ctx; 39 | int wantev; 40 | struct buf wbuf; 41 | struct buf rbuf; 42 | }; 43 | 44 | #define BUFIO_WANT_READ 0x1 45 | #define BUFIO_WANT_WRITE 0x2 46 | 47 | int buf_init(struct buf *); 48 | int buf_has_line(struct buf *, const char *); 49 | char *buf_getdelim(struct buf *, const char *, size_t *); 50 | void buf_drain(struct buf *, size_t); 51 | void buf_drain_line(struct buf *, const char *); 52 | void buf_free(struct buf *); 53 | 54 | int bufio_init(struct bufio *); 55 | void bufio_free(struct bufio *); 56 | int bufio_close(struct bufio *); 57 | int bufio_reset(struct bufio *); 58 | void bufio_set_fd(struct bufio *, int); 59 | int bufio_starttls(struct bufio *, const char *, int, 60 | const uint8_t *, size_t, const uint8_t *, size_t); 61 | int bufio_ev(struct bufio *); 62 | int bufio_handshake(struct bufio *); 63 | ssize_t bufio_read(struct bufio *); 64 | size_t bufio_drain(struct bufio *, void *, size_t); 65 | ssize_t bufio_write(struct bufio *); 66 | const char *bufio_io_err(struct bufio *); 67 | int bufio_compose(struct bufio *, const void *, size_t); 68 | int bufio_compose_str(struct bufio *, const char *); 69 | int bufio_compose_fmt(struct bufio *, const char *, ...) 70 | __attribute__((__format__ (printf, 2, 3))); 71 | void bufio_rewind_cursor(struct bufio *); 72 | 73 | /* callbacks for pdjson */ 74 | int bufio_get_cb(void *); 75 | int bufio_peek_cb(void *); 76 | -------------------------------------------------------------------------------- /certs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2023, 2024 Omar Polo 3 | * Copyright (c) 2019 Renaud Allard 4 | * Copyright (c) 2016 Kristaps Dzonsons 5 | * Copyright (c) 2008 Pierre-Yves Ritschard 6 | * Copyright (c) 2008 Reyk Floeter 7 | * 8 | * Permission to use, copy, modify, and distribute this software for any 9 | * purpose with or without fee is hereby granted, provided that the above 10 | * copyright notice and this permission notice appear in all copies. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | */ 20 | 21 | struct iri; 22 | 23 | /* client certificate */ 24 | struct ccert { 25 | char *host; 26 | char *port; 27 | char *path; 28 | char *cert; 29 | 30 | #define CERT_OK 0x00 31 | #define CERT_TEMP 0x01 32 | #define CERT_TEMP_DEL 0x02 33 | int flags; 34 | }; 35 | 36 | struct cstore { 37 | struct ccert *certs; 38 | size_t len; 39 | size_t cap; 40 | }; 41 | 42 | extern struct cstore cert_store; 43 | extern char **identities; 44 | 45 | int certs_init(const char *); 46 | const char *ccert(const char *); 47 | const char *cert_for(struct iri *, int *); 48 | int cert_save_for(const char *, struct iri *, int); 49 | int cert_delete_for(const char *, struct iri *, int); 50 | int cert_open(const char *); 51 | int cert_new(const char *, const char *, int); 52 | -------------------------------------------------------------------------------- /compat/asprintf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Nicholas Marriott 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "compat.h" 25 | 26 | int 27 | asprintf(char **ret, const char *fmt, ...) 28 | { 29 | va_list ap; 30 | int n; 31 | 32 | va_start(ap, fmt); 33 | n = vasprintf(ret, fmt, ap); 34 | va_end(ap); 35 | 36 | return (n); 37 | } 38 | 39 | int 40 | vasprintf(char **ret, const char *fmt, va_list ap) 41 | { 42 | int n; 43 | va_list ap2; 44 | 45 | va_copy(ap2, ap); 46 | 47 | if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0) 48 | goto error; 49 | 50 | if ((*ret = malloc(n + 1)) == NULL) 51 | goto error; 52 | if ((n = vsnprintf(*ret, n + 1, fmt, ap2)) < 0) { 53 | free(*ret); 54 | goto error; 55 | } 56 | va_end(ap2); 57 | 58 | return (n); 59 | 60 | error: 61 | va_end(ap2); 62 | *ret = NULL; 63 | return (-1); 64 | } 65 | -------------------------------------------------------------------------------- /compat/err.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "compat.h" 24 | 25 | static void vwarn(const char*, va_list); 26 | static void vwarnx(const char*, va_list); 27 | 28 | static void 29 | vwarn(const char *fmt, va_list ap) 30 | { 31 | fprintf(stderr, "%s: ", getprogname()); 32 | vfprintf(stderr, fmt, ap); 33 | fprintf(stderr, ": %s\n", strerror(errno)); 34 | } 35 | 36 | static void 37 | vwarnx(const char *fmt, va_list ap) 38 | { 39 | fprintf(stderr, "%s: ", getprogname()); 40 | vfprintf(stderr, fmt, ap); 41 | fprintf(stderr, "\n"); 42 | } 43 | 44 | void 45 | err(int ret, const char *fmt, ...) 46 | { 47 | va_list ap; 48 | 49 | va_start(ap, fmt); 50 | vwarn(fmt, ap); 51 | va_end(ap); 52 | exit(ret); 53 | } 54 | 55 | void 56 | errx(int ret, const char *fmt, ...) 57 | { 58 | va_list ap; 59 | 60 | va_start(ap, fmt); 61 | vwarnx(fmt, ap); 62 | va_end(ap); 63 | exit(ret); 64 | } 65 | 66 | void 67 | warn(const char *fmt, ...) 68 | { 69 | va_list ap; 70 | 71 | va_start(ap, fmt); 72 | vwarn(fmt, ap); 73 | va_end(ap); 74 | } 75 | 76 | void 77 | warnx(const char *fmt, ...) 78 | { 79 | va_list ap; 80 | 81 | va_start(ap, fmt); 82 | vwarnx(fmt, ap); 83 | va_end(ap); 84 | } 85 | -------------------------------------------------------------------------------- /compat/explicit_bzero.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Public domain. 3 | * Written by Matthew Dempsky. 4 | */ 5 | 6 | #include "compat.h" 7 | 8 | #include 9 | 10 | void 11 | explicit_bzero(void *buf, size_t len) 12 | { 13 | memset(buf, 0, len); 14 | } 15 | -------------------------------------------------------------------------------- /compat/fgetln.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Joerg Jung 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * portable fgetln() version, NOT reentrant 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "compat.h" 26 | 27 | char * 28 | fgetln(FILE *fp, size_t *len) 29 | { 30 | static char *buf = NULL; 31 | static size_t bufsz = 0; 32 | size_t r = 0; 33 | char *p; 34 | int c, e; 35 | 36 | if (!fp || !len) { 37 | errno = EINVAL; 38 | return NULL; 39 | } 40 | if (!buf) { 41 | if (!(buf = calloc(1, BUFSIZ))) 42 | return NULL; 43 | bufsz = BUFSIZ; 44 | } 45 | while ((c = getc(fp)) != EOF) { 46 | buf[r++] = c; 47 | if (r == bufsz) { 48 | if (!(p = reallocarray(buf, 2, bufsz))) { 49 | e = errno; 50 | free(buf); 51 | errno = e; 52 | buf = NULL, bufsz = 0; 53 | return NULL; 54 | } 55 | buf = p, bufsz = 2 * bufsz; 56 | } 57 | if (c == '\n') 58 | break; 59 | } 60 | return (*len = r) ? buf : NULL; 61 | } 62 | -------------------------------------------------------------------------------- /compat/freezero.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "compat.h" 21 | 22 | void 23 | freezero(void *ptr, size_t len) 24 | { 25 | if (ptr == NULL) 26 | return; 27 | 28 | memset(ptr, 0, len); 29 | free(ptr); 30 | } 31 | -------------------------------------------------------------------------------- /compat/getdtablecount.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* XXX: on linux it's possible to glob("/proc/$pid/fd/ *") to know the 18 | * dtablecount. */ 19 | 20 | #include "compat.h" 21 | 22 | int 23 | getdtablecount(void) 24 | { 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /compat/getdtablesize.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | 21 | int 22 | getdtablesize(void) 23 | { 24 | return sysconf(_SC_OPEN_MAX); 25 | } 26 | -------------------------------------------------------------------------------- /compat/getprogname.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME 20 | 21 | #include 22 | 23 | extern char *program_invocation_short_name; 24 | 25 | const char * 26 | getprogname(void) 27 | { 28 | return program_invocation_short_name; 29 | } 30 | 31 | #else 32 | 33 | const char * 34 | getprogname(void) 35 | { 36 | return "telescope"; 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /compat/ohash.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */ 2 | 3 | /* Copyright (c) 1999, 2004 Marc Espie 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef OHASH_H 19 | #define OHASH_H 20 | 21 | /* Open hashing support. 22 | * Open hashing was chosen because it is much lighter than other hash 23 | * techniques, and more efficient in most cases. 24 | */ 25 | 26 | /* user-visible data structure */ 27 | struct ohash_info { 28 | ptrdiff_t key_offset; 29 | void *data; /* user data */ 30 | void *(*calloc)(size_t, size_t, void *); 31 | void (*free)(void *, void *); 32 | void *(*alloc)(size_t, void *); 33 | }; 34 | 35 | struct _ohash_record; 36 | 37 | /* private structure. It's there just so you can do a sizeof */ 38 | struct ohash { 39 | struct _ohash_record *t; 40 | struct ohash_info info; 41 | unsigned int size; 42 | unsigned int total; 43 | unsigned int deleted; 44 | }; 45 | 46 | /* For this to be tweakable, we use small primitives, and leave part of the 47 | * logic to the client application. e.g., hashing is left to the client 48 | * application. We also provide a simple table entry lookup that yields 49 | * a hashing table index (opaque) to be used in find/insert/remove. 50 | * The keys are stored at a known position in the client data. 51 | */ 52 | void ohash_init(struct ohash *, unsigned, struct ohash_info *); 53 | void ohash_delete(struct ohash *); 54 | 55 | unsigned int ohash_lookup_interval(struct ohash *, const char *, 56 | const char *, uint32_t); 57 | unsigned int ohash_lookup_memory(struct ohash *, const char *, 58 | size_t, uint32_t); 59 | void *ohash_find(struct ohash *, unsigned int); 60 | void *ohash_remove(struct ohash *, unsigned int); 61 | void *ohash_insert(struct ohash *, unsigned int, void *); 62 | void *ohash_first(struct ohash *, unsigned int *); 63 | void *ohash_next(struct ohash *, unsigned int *); 64 | unsigned int ohash_entries(struct ohash *); 65 | 66 | void *ohash_create_entry(struct ohash_info *, const char *, const char **); 67 | uint32_t ohash_interval(const char *, const char **); 68 | 69 | unsigned int ohash_qlookupi(struct ohash *, const char *, const char **); 70 | unsigned int ohash_qlookup(struct ohash *, const char *); 71 | #endif 72 | -------------------------------------------------------------------------------- /compat/reallocarray.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $ */ 2 | /* 3 | * Copyright (c) 2008 Otto Moerbeek 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #include "compat.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | /* 26 | * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 27 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 28 | */ 29 | #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 30 | 31 | void * 32 | reallocarray(void *optr, size_t nmemb, size_t size) 33 | { 34 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 35 | nmemb > 0 && SIZE_MAX / nmemb < size) { 36 | errno = ENOMEM; 37 | return NULL; 38 | } 39 | return realloc(optr, size * nmemb); 40 | } 41 | -------------------------------------------------------------------------------- /compat/recallocarray.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: recallocarray.c,v 1.2 2021/03/18 11:16:58 claudio Exp $ */ 2 | /* 3 | * Copyright (c) 2008, 2017 Otto Moerbeek 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #include "compat.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | /* 27 | * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 28 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 29 | */ 30 | #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 31 | 32 | /* 33 | * Even though specified in POSIX, the PAGESIZE and PAGE_SIZE 34 | * macros have very poor portability. Since we only use this 35 | * to avoid free() overhead for small shrinking, simply pick 36 | * an arbitrary number. 37 | */ 38 | #define getpagesize() (1UL << 12) 39 | 40 | void * 41 | recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) 42 | { 43 | size_t oldsize, newsize; 44 | void *newptr; 45 | 46 | if (ptr == NULL) 47 | return calloc(newnmemb, size); 48 | 49 | if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 50 | newnmemb > 0 && SIZE_MAX / newnmemb < size) { 51 | errno = ENOMEM; 52 | return NULL; 53 | } 54 | newsize = newnmemb * size; 55 | 56 | if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 57 | oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { 58 | errno = EINVAL; 59 | return NULL; 60 | } 61 | oldsize = oldnmemb * size; 62 | 63 | /* 64 | * Don't bother too much if we're shrinking just a bit, 65 | * we do not shrink for series of small steps, oh well. 66 | */ 67 | if (newsize <= oldsize) { 68 | size_t d = oldsize - newsize; 69 | 70 | if (d < oldsize / 2 && d < (size_t)getpagesize()) { 71 | memset((char *)ptr + newsize, 0, d); 72 | return ptr; 73 | } 74 | } 75 | 76 | newptr = malloc(newsize); 77 | if (newptr == NULL) 78 | return NULL; 79 | 80 | if (newsize > oldsize) { 81 | memcpy(newptr, ptr, oldsize); 82 | memset((char *)newptr + oldsize, 0, newsize - oldsize); 83 | } else 84 | memcpy(newptr, ptr, newsize); 85 | 86 | explicit_bzero(ptr, oldsize); 87 | free(ptr); 88 | 89 | return newptr; 90 | } 91 | -------------------------------------------------------------------------------- /compat/setproctitle.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Nicholas Marriott 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #if HAVE_PR_SET_NAME 27 | 28 | #include 29 | 30 | void 31 | setproctitle(const char *fmt, ...) 32 | { 33 | char title[16], name[16], *cp; 34 | va_list ap; 35 | int used; 36 | 37 | va_start(ap, fmt); 38 | vsnprintf(title, sizeof title, fmt, ap); 39 | va_end(ap); 40 | 41 | used = snprintf(name, sizeof name, "%s: %s", getprogname(), title); 42 | if (used >= (int)sizeof name) { 43 | cp = strrchr(name, ' '); 44 | if (cp != NULL) 45 | *cp = '\0'; 46 | } 47 | prctl(PR_SET_NAME, name); 48 | } 49 | #else 50 | void 51 | setproctitle(const char *fmt, ...) 52 | { 53 | (void)fmt; 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /compat/strcasestr.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strcasestr.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */ 2 | /* $NetBSD: strcasestr.c,v 1.2 2005/02/09 21:35:47 kleink Exp $ */ 3 | 4 | /*- 5 | * Copyright (c) 1990, 1993 6 | * The Regents of the University of California. All rights reserved. 7 | * 8 | * This code is derived from software contributed to Berkeley by 9 | * Chris Torek. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. Neither the name of the University nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | * SUCH DAMAGE. 34 | */ 35 | 36 | #include 37 | #include 38 | 39 | /* 40 | * Find the first occurrence of find in s, ignore case. 41 | */ 42 | char * 43 | strcasestr(const char *s, const char *find) 44 | { 45 | char c, sc; 46 | size_t len; 47 | 48 | if ((c = *find++) != 0) { 49 | c = (char)tolower((unsigned char)c); 50 | len = strlen(find); 51 | do { 52 | do { 53 | if ((sc = *s++) == 0) 54 | return (NULL); 55 | } while ((char)tolower((unsigned char)sc) != c); 56 | } while (strncasecmp(s, find, len) != 0); 57 | s--; 58 | } 59 | return ((char *)s); 60 | } 61 | -------------------------------------------------------------------------------- /compat/strlcat.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcat.c,v 1.19 2019/01/25 00:19:25 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "compat.h" 23 | 24 | /* 25 | * Appends src to string dst of size dsize (unlike strncat, dsize is the 26 | * full size of dst, not space left). At most dsize-1 characters 27 | * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). 28 | * Returns strlen(src) + MIN(dsize, strlen(initial dst)). 29 | * If retval >= dsize, truncation occurred. 30 | */ 31 | size_t 32 | strlcat(char *dst, const char *src, size_t dsize) 33 | { 34 | const char *odst = dst; 35 | const char *osrc = src; 36 | size_t n = dsize; 37 | size_t dlen; 38 | 39 | /* Find the end of dst and adjust bytes left but don't go past end. */ 40 | while (n-- != 0 && *dst != '\0') 41 | dst++; 42 | dlen = dst - odst; 43 | n = dsize - dlen; 44 | 45 | if (n-- == 0) 46 | return(dlen + strlen(src)); 47 | while (*src != '\0') { 48 | if (n != 0) { 49 | *dst++ = *src; 50 | n--; 51 | } 52 | src++; 53 | } 54 | *dst = '\0'; 55 | 56 | return(dlen + (src - osrc)); /* count does not include NUL */ 57 | } 58 | -------------------------------------------------------------------------------- /compat/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "compat.h" 23 | 24 | /* 25 | * Copy string src to buffer dst of size dsize. At most dsize-1 26 | * chars will be copied. Always NUL terminates (unless dsize == 0). 27 | * Returns strlen(src); if retval >= dsize, truncation occurred. 28 | */ 29 | size_t 30 | strlcpy(char *dst, const char *src, size_t dsize) 31 | { 32 | const char *osrc = src; 33 | size_t nleft = dsize; 34 | 35 | /* Copy as many bytes as will fit. */ 36 | if (nleft != 0) { 37 | while (--nleft != 0) { 38 | if ((*dst++ = *src++) == '\0') 39 | break; 40 | } 41 | } 42 | 43 | /* Not enough room in dst, add NUL and traverse rest of src. */ 44 | if (nleft == 0) { 45 | if (dsize != 0) 46 | *dst = '\0'; /* NUL-terminate dst */ 47 | while (*src++) 48 | ; 49 | } 50 | 51 | return(src - osrc - 1); /* count does not include NUL */ 52 | } 53 | -------------------------------------------------------------------------------- /compat/strsep.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strsep.c,v 1.8 2015/08/31 02:53:57 guenther Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 1990, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | */ 31 | 32 | #include 33 | 34 | #include "compat.h" 35 | 36 | /* 37 | * Get next token from string *stringp, where tokens are possibly-empty 38 | * strings separated by characters from delim. 39 | * 40 | * Writes NULs into the string at *stringp to end tokens. 41 | * delim need not remain constant from call to call. 42 | * On return, *stringp points past the last NUL written (if there might 43 | * be further tokens), or is NULL (if there are definitely no more tokens). 44 | * 45 | * If *stringp is NULL, strsep returns NULL. 46 | */ 47 | char * 48 | strsep(char **stringp, const char *delim) 49 | { 50 | char *s; 51 | const char *spanp; 52 | int c, sc; 53 | char *tok; 54 | 55 | if ((s = *stringp) == NULL) 56 | return (NULL); 57 | for (tok = s;;) { 58 | c = *s++; 59 | spanp = delim; 60 | do { 61 | if ((sc = *spanp++) == c) { 62 | if (c == 0) 63 | s = NULL; 64 | else 65 | s[-1] = 0; 66 | *stringp = s; 67 | return (tok); 68 | } 69 | } while (sc != 0); 70 | } 71 | /* NOTREACHED */ 72 | } 73 | -------------------------------------------------------------------------------- /compat/strtonum.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2004 Ted Unangst and Todd Miller 5 | * All rights reserved. 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "compat.h" 25 | 26 | #define INVALID 1 27 | #define TOOSMALL 2 28 | #define TOOLARGE 3 29 | 30 | long long 31 | strtonum(const char *numstr, long long minval, long long maxval, 32 | const char **errstrp) 33 | { 34 | long long ll = 0; 35 | int error = 0; 36 | char *ep; 37 | struct errval { 38 | const char *errstr; 39 | int err; 40 | } ev[4] = { 41 | { NULL, 0 }, 42 | { "invalid", EINVAL }, 43 | { "too small", ERANGE }, 44 | { "too large", ERANGE }, 45 | }; 46 | 47 | ev[0].err = errno; 48 | errno = 0; 49 | if (minval > maxval) { 50 | error = INVALID; 51 | } else { 52 | ll = strtoll(numstr, &ep, 10); 53 | if (numstr == ep || *ep != '\0') 54 | error = INVALID; 55 | else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) 56 | error = TOOSMALL; 57 | else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) 58 | error = TOOLARGE; 59 | } 60 | if (errstrp != NULL) 61 | *errstrp = ev[error].errstr; 62 | errno = ev[error].err; 63 | if (error) 64 | ll = 0; 65 | 66 | return (ll); 67 | } 68 | -------------------------------------------------------------------------------- /compl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef COMPL_H 18 | #define COMPL_H 19 | 20 | const char *compl_lu(void **, void **, const char **); 21 | const char *compl_eecmd(void **, void **, const char **); 22 | const char *compl_ts(void **, void **, const char **); 23 | const char *compl_ls(void **, void **, const char **); 24 | const char *compl_swiper(void **, void **, const char **); 25 | const char *compl_toc(void **, void **, const char **); 26 | const char *compl_uc(void **, void **, const char **); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /contrib/README.md: -------------------------------------------------------------------------------- 1 | # Contrib 2 | 3 | - `brutalist.config`: a brutalist theme 4 | - `light.config`: an opinionated theme for light terminals. Load it 5 | with `telescope -c contrib/light.config` or copy it to 6 | `~/.config/telescope/config` 7 | - `dark.config`: an opinionated theme for dark terminals. Load it 8 | with `telescope -c contrib/dark.config` or copy it to 9 | `~/.config/telescope/config` 10 | - `xdg-migrate.sh` aids the migration from a monolithic 11 | `~/.telescope` directory to a XDG. 12 | - `coccinelle/` contains cocci scripts used for code transformation. 13 | -------------------------------------------------------------------------------- /contrib/brutalist.config: -------------------------------------------------------------------------------- 1 | style line.link prefix "=> " " " 2 | style line.title1 prefix "# " " " 3 | style line.title2 prefix "## " " " 4 | style line.title3 prefix "### " " " 5 | style line.item prefix "* " " " 6 | style line.quote prefix "> " " " 7 | style line.pre.start prefix "``` " " " 8 | style line.pre.end prefix "```" "```" 9 | -------------------------------------------------------------------------------- /contrib/coccinelle/wrap.cocci: -------------------------------------------------------------------------------- 1 | @@ 2 | expression x, y; 3 | statement S; 4 | @@ 5 | -if ((x = strdup(y)) == NULL) 6 | - S 7 | +x = xstrdup(y); 8 | 9 | @@ 10 | expression x, y; 11 | statement S; 12 | @@ 13 | -x = strdup(y); 14 | -if (x == NULL) 15 | - S 16 | +x = xstrdup(y); 17 | 18 | @@ 19 | expression x, y; 20 | @@ 21 | -x = strdup(y); 22 | +x = xstrdup(y); 23 | 24 | @@ 25 | expression x, y, z; 26 | statement S; 27 | @@ 28 | -if ((x = strndup(y, z)) == NULL) 29 | - S 30 | +x = xstrndup(y, z); 31 | 32 | @@ 33 | expression x, y; 34 | statement S; 35 | @@ 36 | -if ((x = malloc(y)) == NULL) 37 | - S 38 | +x = xmalloc(y); 39 | 40 | @@ 41 | expression x, y, z; 42 | statement S; 43 | @@ 44 | -if ((x = calloc(y, z)) == NULL) 45 | - S 46 | +x = xcalloc(y, z); 47 | 48 | @@ 49 | expression x, y, z; 50 | statement S; 51 | @@ 52 | -if ((x = realloc(y, z)) == NULL) 53 | - S 54 | +x = xrealloc(y, z); 55 | 56 | @@ 57 | expression x, y, z; 58 | statement S; 59 | @@ 60 | -x = realloc(y, z); 61 | - S 62 | +x = xrealloc(y, z); 63 | 64 | @@ 65 | expression w, x, y, z; 66 | statement S; 67 | @@ 68 | -if ((x = reallocarray(w, y, z)) == NULL) 69 | - S 70 | +x = xreallocarray(w, y, z); 71 | 72 | @@ 73 | expression w, x, y, z; 74 | @@ 75 | -x = reallocarray(w, y, z); 76 | +x = xreallocarray(w, y, z); 77 | 78 | @@ 79 | expression fmt; 80 | expression list args; 81 | statement S; 82 | @@ 83 | -if (asprintf(fmt, args) == -1) S 84 | +xasprintf(fmt, args); 85 | 86 | @@ 87 | expression x, fmt; 88 | expression list args; 89 | @@ 90 | -x = asprintf(fmt, args); 91 | +xasprintf(fmt, args); 92 | -------------------------------------------------------------------------------- /contrib/dark.config: -------------------------------------------------------------------------------- 1 | # Break long lines at max at 92 columns 2 | set fill-column = 92 3 | 4 | # Enable colors regardless of the NO_COLOR environment variable 5 | set enable-colors = 1 6 | 7 | # Hide the closing line of preformatted blocks 8 | set hide-pre-closing-line = 1 9 | 10 | # If you have the duckling-proxy installed, decomment the following 11 | # lines to use it for HTTP and HTTPS links. 12 | #proxy "http" via "gemini://localhost:1965" 13 | #proxy "https" via "gemini://localhost:1965" 14 | 15 | # Some opinionated graphical improvements: 16 | 17 | style line.fringe fg color239 18 | 19 | style line.quote attr dim normal 20 | style line.pre.start bg color239 21 | style line.pre bg color239 22 | style line.pre.end bg color239 23 | 24 | style line.link { 25 | fg color81 26 | attr normal 27 | } 28 | 29 | style line.compl.current { 30 | bg color50 31 | fg black 32 | attr normal 33 | } 34 | 35 | style tabline { 36 | bg color233 37 | fg color50 38 | attr normal 39 | } 40 | 41 | style tabline.tab { 42 | bg color233 43 | attr normal 44 | } 45 | 46 | style tabline.current { 47 | bg color241 48 | fg white 49 | } 50 | 51 | style modeline { 52 | bg color237 53 | attr normal 54 | } 55 | 56 | style line.download.ongoing bg color238 57 | style line.download.done bg color238 58 | style line.download.info bg color238 59 | style download bg color238 60 | -------------------------------------------------------------------------------- /contrib/light.config: -------------------------------------------------------------------------------- 1 | # Break long lines at max at 92 columns 2 | set fill-column = 92 3 | 4 | # Enable colors regardless of the NO_COLOR environment variable 5 | set enable-colors = 1 6 | 7 | # Hide the closing line of preformatted blocks 8 | set hide-pre-closing-line = 1 9 | 10 | # If you have the duckling-proxy installed, decomment the following 11 | # lines to use it for HTTP and HTTPS links. 12 | #proxy "http" via "gemini://localhost:1965" 13 | #proxy "https" via "gemini://localhost:1965" 14 | 15 | # Some opinionated graphical improvements: 16 | 17 | style line.fringe fg color250 18 | 19 | style line.link attr normal 20 | style line.quote attr dim normal 21 | style line.pre.start bg color255 22 | style line.pre bg color255 23 | style line.pre.end bg color255 24 | 25 | style line.compl.current { 26 | bg color50 27 | attr normal 28 | } 29 | 30 | style line.download.ongoing bg color254 31 | style line.download.done bg color254 32 | style line.download.info bg color254 33 | style download bg color254 34 | -------------------------------------------------------------------------------- /contrib/xdg-migrate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | old_path="$HOME/.telescope" 4 | 5 | Die() { 6 | printf 'error: %s\n' "$1" 1>&2 7 | exit 1 8 | } 9 | 10 | [ -e "$old_path" ] || Die "$old_path does not exist." 11 | [ -d "$old_path" ] || Die "$old_path is not a directory." 12 | 13 | xdg_config="${XDG_CONFIG_HOME:-$HOME/.config}/telescope" 14 | xdg_data="${XDG_DATA_HOME:-$HOME/.local/share}/telescope" 15 | xdg_cache="${XDG_CACHE_HOME:-$HOME/.cache}/telescope" 16 | 17 | mkdir -p "$xdg_config" "$xdg_data" "$xdg_cache" 18 | 19 | for filepath in \ 20 | "$xdg_config/config" \ 21 | "$xdg_data/pages" \ 22 | "$xdg_data/bookmarks.gmi" \ 23 | "$xdg_data/known_hosts" 24 | do 25 | old_file="$old_path/${filepath##*/}" 26 | [ -e "$old_file" ] && cp -R "$old_file" "filepath" 27 | done 28 | 29 | printf "\ 30 | WARNING: the old ~/.telescope directory will be removed. 31 | 32 | Every file/directory other than the following has not been copied: 33 | - config 34 | - bookmarks.gmi 35 | - known_hosts 36 | - pages/ 37 | 38 | Are you sure? [Y/n] " 39 | 40 | read -r reply 41 | case $reply in 42 | [yY]) rm -r "$old_path" && printf 'done\n' ;; 43 | esac 44 | -------------------------------------------------------------------------------- /control.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: control.h,v 1.1 2021/02/26 16:16:37 florian Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2003, 2004 Henning Brauer 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef SMALL 20 | int control_init(char *); 21 | int control_listen(int); 22 | void control_accept(int, int, void *); 23 | void control_dispatch_imsg(int, int, void *); 24 | #endif /* SMALL */ 25 | -------------------------------------------------------------------------------- /defaults.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DEFAULTS_H 18 | #define DEFAULTS_H 19 | 20 | extern char *default_protocol; 21 | extern char *default_search_engine; 22 | extern char *download_path; 23 | extern char *new_tab_url; 24 | 25 | extern int autosave; 26 | extern int dont_wrap_pre; 27 | extern int dont_apply_styling; 28 | extern int emojify_link; 29 | extern int enable_colors; 30 | extern int fill_column; 31 | extern int fringe_ignore_offset; 32 | extern int hide_pre_blocks; 33 | extern int hide_pre_closing_line; 34 | extern int hide_pre_context; 35 | extern int load_url_use_heuristic; 36 | extern int max_killed_tabs; 37 | extern int olivetti_mode; 38 | extern int set_title; 39 | extern int tab_bar_show; 40 | 41 | extern struct vline fringe; 42 | 43 | struct lineprefix { 44 | const char *prfx1; 45 | const char *prfx2; 46 | }; 47 | 48 | extern struct lineprefix raw_prefixes[]; 49 | extern struct lineprefix line_prefixes[]; 50 | 51 | struct line_face { 52 | int prfx_pair, pair, trail_pair; 53 | int prfx_bg, bg, trail_bg; 54 | int prfx_fg, fg, trail_fg; 55 | int prfx_attr, attr, trail_attr; 56 | 57 | int prefix, text, trail; 58 | }; 59 | extern struct line_face line_faces[]; 60 | 61 | struct tab_face { 62 | int bg_attr, bg_bg, bg_fg; 63 | int t_attr, t_bg, t_fg; 64 | int c_attr, c_bg, c_fg; 65 | 66 | int background, tab, current; 67 | }; 68 | extern struct tab_face tab_face; 69 | 70 | struct body_face { 71 | int lbg, lfg; 72 | int bg, fg; 73 | int rbg, rfg; 74 | 75 | int left, body, right; 76 | }; 77 | extern struct body_face body_face; 78 | 79 | struct download_face { 80 | int bg, fg, attr; 81 | int background; 82 | }; 83 | extern struct download_face download_face; 84 | 85 | struct modeline_face { 86 | int bg, fg, attr; 87 | int background; 88 | }; 89 | extern struct modeline_face modeline_face; 90 | 91 | struct minibuffer_face { 92 | int bg, fg, attr; 93 | int background; 94 | }; 95 | extern struct minibuffer_face minibuffer_face; 96 | 97 | void config_init(void); 98 | int config_setprfx(const char *, const char *, const char *); 99 | int config_setvari(const char *, int); 100 | int config_setvars(const char *, char *); 101 | int config_setvarb(const char *, int); 102 | int config_setcolor(int, const char *, int, int, int); 103 | int config_setattr(const char *, int, int, int); 104 | void config_apply_style(void); 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /downloads.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "telescope.h" 24 | #include "ui.h" 25 | #include "xwrapper.h" 26 | 27 | struct downloads downloads = STAILQ_HEAD_INITIALIZER(downloads); 28 | 29 | static void 30 | no_downloads(void) 31 | { 32 | struct line *l; 33 | 34 | l = xcalloc(1, sizeof(*l)); 35 | 36 | l->type = LINE_DOWNLOAD_INFO; 37 | l->line = xstrdup("No downloads"); 38 | 39 | TAILQ_INSERT_TAIL(&downloadwin.head, l, lines); 40 | } 41 | 42 | void 43 | recompute_downloads(void) 44 | { 45 | struct download *d; 46 | struct line *l; 47 | char buf[FMT_SCALED_STRSIZE]; 48 | 49 | downloadwin.mode = "*Downloads*"; 50 | erase_buffer(&downloadwin); 51 | 52 | if (STAILQ_EMPTY(&downloads)) { 53 | no_downloads(); 54 | goto end; 55 | } 56 | 57 | STAILQ_FOREACH(d, &downloads, entries) { 58 | l = xcalloc(1, sizeof(*l)); 59 | 60 | fmt_scaled(d->bytes, buf); 61 | 62 | l->type = LINE_DOWNLOAD; 63 | if (d->fd == -1) 64 | l->type = LINE_DOWNLOAD_DONE; 65 | 66 | l->line = xstrdup(buf); 67 | l->alt = xstrdup(d->path); 68 | 69 | TAILQ_INSERT_TAIL(&downloadwin.head, l, lines); 70 | } 71 | 72 | end: 73 | /* 74 | * The exact value doesn't matter, as wrap_page only considers 75 | * l->line, which is the human representation of the byte 76 | * counter, and we know for sure is < FMT_SCALED_STRSIZE so it 77 | * fits. 78 | */ 79 | wrap_page(&downloadwin, download_cols, 0); 80 | } 81 | 82 | struct download * 83 | enqueue_download(uint32_t id, const char *path, const char *mime_type) 84 | { 85 | struct download *d; 86 | 87 | d = xcalloc(1, sizeof(*d)); 88 | 89 | d->id = id; 90 | d->fd = -1; 91 | d->path = xstrdup(path); 92 | d->mime_type = xstrdup(mime_type); 93 | 94 | STAILQ_INSERT_HEAD(&downloads, d, entries); 95 | 96 | return d; 97 | } 98 | 99 | struct download * 100 | download_by_id(uint32_t id) 101 | { 102 | struct download *d; 103 | 104 | STAILQ_FOREACH(d, &downloads, entries) { 105 | if (d->id == id) 106 | return d; 107 | } 108 | 109 | return NULL; 110 | } 111 | 112 | void 113 | download_finished(struct download *d) 114 | { 115 | if (d == NULL) 116 | return; 117 | 118 | close(d->fd); 119 | d->fd = -1; 120 | 121 | ui_on_download_refresh(); 122 | ui_prompt_download_cmd(d); 123 | } 124 | -------------------------------------------------------------------------------- /ev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | struct timeval; 27 | 28 | #define EV_READ 0x1 29 | #define EV_WRITE 0x2 30 | #define EV_SIGNAL 0x4 31 | #define EV_TIMEOUT 0x8 32 | 33 | int ev_init(void); 34 | int ev_add(int, int, void(*)(int, int, void *), void *); 35 | int ev_signal(int, void(*)(int, int, void * ), void *); 36 | unsigned int ev_timer(const struct timeval *, void(*)(int, int, void *), 37 | void *); 38 | int ev_timer_pending(unsigned int); 39 | int ev_timer_cancel(unsigned int); 40 | int ev_del(int); 41 | int ev_loop(void); 42 | void ev_break(void); 43 | -------------------------------------------------------------------------------- /exec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "exec.h" 30 | #include "minibuffer.h" 31 | #include "ui.h" 32 | 33 | #define TMPFILE "/tmp/telescope.XXXXXXXXXX" 34 | 35 | int 36 | exec_cmd(char **argv, enum exec_mode mode) 37 | { 38 | char **t; 39 | int s, fd, ret; 40 | pid_t pid; 41 | 42 | if (argv == NULL) 43 | return (-1); 44 | 45 | if (mode == EXEC_FOREGROUND) { 46 | ui_suspend(); 47 | 48 | fprintf(stderr, "%s: running", getprogname()); 49 | for (t = argv; *t; ++t) 50 | fprintf(stderr, " %s", *t); 51 | fprintf(stderr, "\n"); 52 | fflush(NULL); 53 | } 54 | 55 | switch (pid = fork()) { 56 | case -1: 57 | message("failed to fork: %s", strerror(errno)); 58 | return (-1); 59 | case 0: 60 | if (mode == EXEC_BACKGROUND) { 61 | if ((fd = open("/dev/null", O_RDWR)) == -1) { 62 | warn("can't open /dev/null"); 63 | _exit(1); 64 | } 65 | (void)dup2(fd, 0); 66 | (void)dup2(fd, 1); 67 | (void)dup2(fd, 2); 68 | if (fd > 2) 69 | close(fd); 70 | } 71 | execvp(argv[0], argv); 72 | if (mode == EXEC_FOREGROUND) { 73 | warn("can't exec \"%s\"", argv[0]); 74 | fprintf(stderr, "Press enter to continue"); 75 | fflush(stderr); 76 | read(0, &s, 1); 77 | } 78 | _exit(1); 79 | } 80 | 81 | if (mode == EXEC_BACKGROUND) 82 | return (0); 83 | 84 | do { 85 | ret = waitpid(pid, &s, 0); 86 | } while (ret == -1 && errno == EINTR); 87 | 88 | ui_resume(); 89 | 90 | if (WIFSIGNALED(s) || WEXITSTATUS(s) != 0) { 91 | message("%s failed", *argv); 92 | return (-1); 93 | } 94 | 95 | return (0); 96 | } 97 | 98 | FILE * 99 | exec_editor(void *data, size_t len) 100 | { 101 | FILE *fp; 102 | char *editor; 103 | char sfn[sizeof(TMPFILE)]; 104 | char *argv[3]; 105 | int fd; 106 | 107 | strlcpy(sfn, TMPFILE, sizeof(sfn)); 108 | if ((fd = mkstemp(sfn)) == -1) { 109 | message("failed to create a temp file: %s", strerror(errno)); 110 | return (NULL); 111 | } 112 | (void) write(fd, data, len); 113 | close(fd); 114 | 115 | if ((editor = getenv("VISUAL")) == NULL && 116 | (editor = getenv("EDITOR")) == NULL) 117 | editor = (char *)DEFAULT_EDITOR; 118 | 119 | argv[0] = editor; 120 | argv[1] = sfn; 121 | argv[2] = NULL; 122 | 123 | if (exec_cmd(argv, EXEC_FOREGROUND) == -1) { 124 | (void) unlink(sfn); 125 | return (NULL); 126 | } 127 | 128 | if ((fp = fopen(sfn, "r")) == NULL) { 129 | message("can't open temp file!"); 130 | (void) unlink(sfn); 131 | return (NULL); 132 | } 133 | (void) unlink(sfn); 134 | 135 | return (fp); 136 | } 137 | -------------------------------------------------------------------------------- /exec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum exec_mode { 18 | EXEC_FOREGROUND, 19 | EXEC_BACKGROUND, 20 | }; 21 | 22 | int exec_cmd(char **argv, enum exec_mode); 23 | FILE *exec_editor(void *, size_t); 24 | -------------------------------------------------------------------------------- /extra/about-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telescope-browser/telescope/243d6421b25f09e5b22445f2378598da6ba5b110/extra/about-new.png -------------------------------------------------------------------------------- /fs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2022, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef FS_H 18 | #define FS_H 19 | 20 | struct tab; 21 | struct tofu_entry; 22 | 23 | extern char config_path_base[PATH_MAX]; 24 | extern char data_path_base[PATH_MAX]; 25 | extern char cache_path_base[PATH_MAX]; 26 | 27 | extern char ctlsock_path[PATH_MAX]; 28 | extern char config_path[PATH_MAX]; 29 | extern char lockfile_path[PATH_MAX]; 30 | extern char bookmark_file[PATH_MAX]; 31 | extern char known_hosts_file[PATH_MAX], known_hosts_tmp[PATH_MAX]; 32 | extern char crashed_file[PATH_MAX]; 33 | extern char session_file[PATH_MAX], session_file_tmp[PATH_MAX]; 34 | extern char history_file[PATH_MAX], history_file_tmp[PATH_MAX]; 35 | extern char cert_dir[PATH_MAX], cert_dir_tmp[PATH_MAX]; 36 | extern char certs_file[PATH_MAX], certs_file_tmp[PATH_MAX]; 37 | 38 | extern char cwd[PATH_MAX]; 39 | 40 | int fs_init(void); 41 | void fs_load_url(struct tab *, const char *); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /gencmd.awk: -------------------------------------------------------------------------------- 1 | BEGIN { 2 | FS = "[(,)]"; 3 | 4 | print "#include \"compat.h\"" 5 | print "#include \"cmd.h\"" 6 | print "struct cmd cmds[] = {"; 7 | } 8 | 9 | /^CMD/ { 10 | s = $2; 11 | sub("^cmd_", "", s); 12 | gsub("_", "-", s); 13 | printf("\t{ \"%s\", %s, %s },\n", s, $2, $3); 14 | next; 15 | } 16 | 17 | /^DEFALIAS/ { 18 | s = $2; 19 | d = $3; 20 | printf("\t{ \"%s\", %s, NULL },\n", s, d); 21 | next 22 | } 23 | 24 | { 25 | next; 26 | } 27 | 28 | END { 29 | printf("\t{ NULL, NULL, NULL },\n"); 30 | print "};"; 31 | } 32 | -------------------------------------------------------------------------------- /genemoji.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | file="${1:?missing input file}" 4 | 5 | sed -e '/^$/d' \ 6 | -e '/^#/d' \ 7 | -e 's/;.*//' \ 8 | -e 's/[ \t]*$//' \ 9 | -e 's/\.\./ /' \ 10 | "$file" \ 11 | | awk ' 12 | BEGIN { 13 | print "#include \"utf8.h\"" 14 | print "int is_emoji(uint32_t cp) {" 15 | 16 | e="" 17 | } 18 | 19 | { 20 | if (NF == 1) { 21 | printf("%sif (cp == 0x%s)", e, $1); 22 | } else { 23 | printf("%sif (cp >= 0x%s && cp <= 0x%s)", e, $1, $2); 24 | } 25 | 26 | print " return 1;" 27 | 28 | e="else " 29 | } 30 | 31 | END { 32 | print "return 0; }" 33 | } 34 | ' 35 | -------------------------------------------------------------------------------- /help.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "cmd.h" 25 | #include "keymap.h" 26 | #include "telescope.h" 27 | #include "ui.h" 28 | #include "xwrapper.h" 29 | 30 | static void emit_help_item(char *, interactivefn *); 31 | static void rec_compute_help(struct kmap *, char *, size_t); 32 | 33 | static void 34 | emit_help_item(char *prfx, interactivefn *fn) 35 | { 36 | struct line *l; 37 | struct cmd *cmd; 38 | 39 | for (cmd = cmds; cmd->cmd != NULL; ++cmd) { 40 | if (fn == cmd->fn) 41 | break; 42 | } 43 | assert(cmd != NULL); 44 | 45 | l = xcalloc(1, sizeof(*l)); 46 | 47 | l->type = LINE_HELP; 48 | l->line = xstrdup(prfx); 49 | l->alt = (char*)cmd->cmd; 50 | 51 | TAILQ_INSERT_TAIL(&helpwin.head, l, lines); 52 | } 53 | 54 | static void 55 | rec_compute_help(struct kmap *keymap, char *prfx, size_t len) 56 | { 57 | struct keymap *k; 58 | char p[32]; 59 | const char *kn; 60 | 61 | TAILQ_FOREACH(k, &keymap->m, keymaps) { 62 | strlcpy(p, prfx, sizeof(p)); 63 | if (*p != '\0') 64 | strlcat(p, " ", sizeof(p)); 65 | if (k->meta) 66 | strlcat(p, "M-", sizeof(p)); 67 | if ((kn = unkbd(k->key)) != NULL) 68 | strlcat(p, kn, sizeof(p)); 69 | else 70 | strlcat(p, ui_keyname(k->key), sizeof(p)); 71 | 72 | if (k->fn == NULL) 73 | rec_compute_help(&k->map, p, sizeof(p)); 74 | else 75 | emit_help_item(p, k->fn); 76 | } 77 | } 78 | 79 | void 80 | recompute_help(void) 81 | { 82 | static struct kmap *last_active_map = NULL; 83 | char p[32] = { 0 }; 84 | 85 | if (last_active_map != current_map) { 86 | last_active_map = current_map; 87 | 88 | helpwin.mode = "*Help*"; 89 | erase_buffer(&helpwin); 90 | rec_compute_help(current_map, p, sizeof(p)); 91 | wrap_page(&helpwin, help_cols, 0); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /hist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | struct hist; 18 | 19 | #define HIST_LINEAR 0x0 20 | #define HIST_WRAP 0x1 21 | 22 | struct hist *hist_new(int); 23 | void hist_free(struct hist *); 24 | void hist_erase(struct hist *); 25 | 26 | size_t hist_size(struct hist *); 27 | size_t hist_off(struct hist *); 28 | 29 | const char *hist_cur(struct hist *); 30 | int hist_cur_offs(struct hist *, size_t *, size_t *); 31 | 32 | int hist_set_cur(struct hist *, const char *); 33 | int hist_set_offs(struct hist *, size_t, size_t); 34 | 35 | const char *hist_nth(struct hist *, size_t); 36 | const char *hist_prev(struct hist *); 37 | const char *hist_next(struct hist *); 38 | 39 | void hist_seek_start(struct hist *); 40 | 41 | int hist_push(struct hist *, const char *); 42 | int hist_prepend(struct hist *, const char *); 43 | int hist_append(struct hist *, const char *); 44 | 45 | -------------------------------------------------------------------------------- /imsgev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include "ev.h" 20 | #include "imsgev.h" 21 | 22 | void 23 | imsg_event_add(struct imsgev *iev) 24 | { 25 | iev->events = EV_READ; 26 | if (imsgbuf_queuelen(&iev->ibuf)) 27 | iev->events |= EV_WRITE; 28 | 29 | ev_add(iev->ibuf.fd, iev->events, iev->handler, iev); 30 | } 31 | 32 | int 33 | imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 34 | pid_t pid, int fd, const void *data, uint16_t datalen) 35 | { 36 | int ret; 37 | 38 | if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 39 | datalen) != -1)) 40 | imsg_event_add(iev); 41 | 42 | return ret; 43 | } 44 | 45 | int 46 | ibuf_borrow_str(struct ibuf *ibuf, char **data) 47 | { 48 | size_t len; 49 | 50 | if ((*data = ibuf_data(ibuf)) == NULL || 51 | (len = ibuf_size(ibuf)) == 0 || 52 | (*data)[len - 1] != '\0') 53 | return -1; 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /imsgev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | struct imsgev { 18 | struct imsgbuf ibuf; 19 | void (*handler)(int, int, void *); 20 | short events; 21 | }; 22 | 23 | #define IMSG_DATA_SIZE(imsg) ((imsg).hdr.len - IMSG_HEADER_SIZE) 24 | 25 | enum imsg_type { 26 | /* ui <-> net */ 27 | IMSG_GET, /* struct get_req, peerid is the tab id */ 28 | IMSG_ERR, 29 | IMSG_CHECK_CERT, 30 | IMSG_CERT_STATUS, 31 | IMSG_FAULTY_GEMSERVER, 32 | IMSG_REPLY, /* reply code (int) + meta string */ 33 | IMSG_PROCEED, 34 | IMSG_STOP, 35 | IMSG_BUF, 36 | IMSG_EOF, 37 | IMSG_QUIT, 38 | 39 | /* ui <-> ctl */ 40 | IMSG_CTL_OPEN_URL, 41 | }; 42 | 43 | void imsg_event_add(struct imsgev *); 44 | int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, int, const void *, uint16_t); 45 | 46 | int ibuf_borrow_str(struct ibuf *, char **); 47 | -------------------------------------------------------------------------------- /iri.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef IRI_H 18 | #define IRI_H 19 | 20 | struct iri { 21 | char iri_scheme[32]; 22 | char iri_uinfo[254]; 23 | char iri_host[1024]; 24 | char iri_portstr[6]; 25 | uint16_t iri_port; 26 | char iri_path[1024]; 27 | char iri_query[1024]; 28 | char iri_fragment[1024]; 29 | 30 | #define IH_SCHEME 0x01 31 | #define IH_UINFO 0x02 32 | #define IH_HOST 0x04 33 | #define IH_PORT 0x08 34 | #define IH_AUTHORITY (IH_UINFO|IH_HOST|IH_PORT) 35 | #define IH_PATH 0x10 36 | #define IH_QUERY 0x20 37 | #define IH_FRAGMENT 0x40 38 | int iri_flags; 39 | }; 40 | 41 | int iri_parse(const char *, const char *, struct iri *); 42 | int iri_unparse(const struct iri *, char *, size_t); 43 | int iri_human(const struct iri *, char *, size_t); 44 | int iri_setport(struct iri *, const char *); 45 | int iri_setquery(struct iri *, const char *); 46 | 47 | int iri_urlescape(const char *, char *, size_t); 48 | int iri_urlunescape(const char *, char *, size_t); 49 | 50 | #endif /* IRI_H */ 51 | -------------------------------------------------------------------------------- /keymap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef KEYMAP_H 18 | #define KEYMAP_H 19 | 20 | #include 21 | 22 | struct buffer; 23 | 24 | struct kmap { 25 | TAILQ_HEAD(map, keymap) m; 26 | void (*unhandled_input)(void); 27 | }; 28 | extern struct kmap global_map, minibuffer_map; 29 | 30 | typedef void(interactivefn)(struct buffer *); 31 | 32 | struct keymap { 33 | int meta; 34 | int key; 35 | struct kmap map; 36 | interactivefn *fn; 37 | 38 | TAILQ_ENTRY(keymap) keymaps; 39 | }; 40 | 41 | struct thiskey { 42 | short meta; 43 | int key; 44 | uint32_t cp; 45 | }; 46 | 47 | enum { 48 | LK_ADVANCED_MAP, 49 | LK_MATCHED, 50 | LK_UNBOUND, 51 | }; 52 | 53 | int kbd(const char *); 54 | const char *unkbd(int); 55 | int kmap_define_key(struct kmap *, const char *, interactivefn *); 56 | int lookup_key(struct kmap **, struct thiskey *, struct buffer *); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /keys/telescope-0.10.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWRkrb76bmCHNKaMnALGf2UgKgq0d/O/ULTeGq36Dos7MGm79CXoZLWN 3 | -------------------------------------------------------------------------------- /keys/telescope-0.11.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWSGF919QDVYCTrj5kh15ErHwODtLHoXuqwwdT8lhEdLmzGHR8qicwC6 3 | -------------------------------------------------------------------------------- /keys/telescope-0.12.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWSZsqP+8vq1Azefpv6Bfg8zC5VpybsTleSgBwEB7/btdwtbL/8zhbI/ 3 | -------------------------------------------------------------------------------- /keys/telescope-0.3.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWQkOxzgu4+f6owqsHD1cul3xcfMF8bgv+YJIz5uU6tWqA1rzTR7Lfkc 3 | -------------------------------------------------------------------------------- /keys/telescope-0.4.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWQALOsBVh84wzPGTlWFNX42HXATsZNi9tlbUSQB2r3hqn8ZCkhhm26l 3 | -------------------------------------------------------------------------------- /keys/telescope-0.5.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWQC5yctX3piI5UxyMapkd0PPLn96ByENXpR7C3cwUn9Mu901owR1Xsi 3 | -------------------------------------------------------------------------------- /keys/telescope-0.6.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWQ9ejE2t48Rb1ZBgVS95HK2om6TdyzqYT7DDJ0lwZFbqJJYG5WvqRSy 3 | -------------------------------------------------------------------------------- /keys/telescope-0.7.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: telescope 0.7 public key 2 | RWRME/ROrxuxW+J2XSEFsAIU4AO401Ie+JGLqvBpV2ZaPoY/AawATT9J 3 | -------------------------------------------------------------------------------- /keys/telescope-0.8.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWQ12hzRNC/1NhZD56pU1YaRg5AYSEWg9gId5M3e9zwuufmwnbd7WrMb 3 | -------------------------------------------------------------------------------- /keys/telescope-0.9.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: signify public key 2 | RWSmshjFM8Q0IDYUd4I/8G2q9Y0DUaZLac4enOtQh5rzsIcVF+ePXCy7 3 | -------------------------------------------------------------------------------- /libgrapheme/LICENSE: -------------------------------------------------------------------------------- 1 | ISC-License 2 | 3 | Copyright 2019-2022 Laslo Hunhold 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /libgrapheme/README: -------------------------------------------------------------------------------- 1 | libgrapheme 2 | =========== 3 | 4 | libgrapheme is an extremely simple freestanding C99 library providing 5 | utilities for properly handling strings according to the latest Unicode 6 | standard 15.0.0. It offers fully Unicode compliant 7 | 8 | - grapheme cluster (i.e. user-perceived character) segmentation 9 | - word segmentation 10 | - sentence segmentation 11 | - detection of permissible line break opportunities 12 | - case detection (lower-, upper- and title-case) 13 | - case conversion (to lower-, upper- and title-case) 14 | 15 | on UTF-8 strings and codepoint arrays, which both can also be 16 | null-terminated. 17 | 18 | The necessary lookup-tables are automatically generated from the Unicode 19 | standard data (contained in the tarball) and heavily compressed. Over 20 | 10,000 automatically generated conformance tests and over 150 unit tests 21 | ensure conformance and correctness. 22 | 23 | There is no complicated build-system involved and it's all done using one 24 | POSIX-compliant Makefile. All you need is a C99 compiler, given the 25 | lookup-table-generators and compressors are also written in C99. The 26 | resulting library is freestanding and thus not even dependent on a 27 | standard library to be present at runtime, making it a suitable choice 28 | for bare metal applications. 29 | 30 | It is also way smaller and much faster than the other established 31 | Unicode string libraries (ICU, GNU's libunistring, libutf8proc). 32 | 33 | Requirements 34 | ------------ 35 | A C99-compiler and POSIX make. 36 | 37 | Installation 38 | ------------ 39 | Run ./configure, which automatically edits config.mk to match your local 40 | setup. Edit config.mk by hand if necessary or desired for further 41 | customization. 42 | 43 | Afterwards enter the following command to build and install libgrapheme 44 | (if necessary as root): 45 | 46 | make install 47 | 48 | Conformance 49 | ----------- 50 | The libgrapheme library is compliant with the Unicode 15.0.0 51 | specification (September 2022). The tests can be run with 52 | 53 | make test 54 | 55 | to check standard conformance and correctness. 56 | 57 | Usage 58 | ----- 59 | Include the header grapheme.h in your code and link against libgrapheme 60 | with "-lgrapheme" either statically ("-static") or dynamically. 61 | 62 | Author 63 | ------ 64 | Laslo Hunhold 65 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/case.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../grapheme.h" 10 | #include "../gen/word-test.h" 11 | #include "util.h" 12 | 13 | #define NUM_ITERATIONS 10000 14 | 15 | struct break_benchmark_payload { 16 | uint_least32_t *src; 17 | size_t srclen; 18 | uint_least32_t *dest; 19 | size_t destlen; 20 | }; 21 | 22 | void 23 | libgrapheme(const void *payload) 24 | { 25 | const struct break_benchmark_payload *p = payload; 26 | 27 | grapheme_to_uppercase(p->src, p->srclen, p->dest, p->destlen); 28 | } 29 | 30 | int 31 | main(int argc, char *argv[]) 32 | { 33 | struct break_benchmark_payload p; 34 | double baseline = (double)NAN; 35 | 36 | (void)argc; 37 | 38 | if ((p.src = generate_cp_test_buffer(word_break_test, 39 | LEN(word_break_test), 40 | &(p.srclen))) == NULL) { 41 | return 1; 42 | } 43 | if ((p.dest = calloc((p.destlen = 2 * p.srclen), sizeof(*(p.dest)))) == NULL) { 44 | fprintf(stderr, "calloc: Out of memory\n"); 45 | } 46 | 47 | printf("%s\n", argv[0]); 48 | run_benchmark(libgrapheme, &p, "libgrapheme ", NULL, "codepoint", 49 | &baseline, NUM_ITERATIONS, p.srclen - 1); 50 | 51 | free(p.src); 52 | free(p.dest); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/character.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../grapheme.h" 10 | #include "../gen/character-test.h" 11 | #include "util.h" 12 | 13 | #include 14 | 15 | #define NUM_ITERATIONS 100000 16 | 17 | struct break_benchmark_payload { 18 | uint_least32_t *buf; 19 | utf8proc_int32_t *buf_utf8proc; 20 | size_t buflen; 21 | }; 22 | 23 | void 24 | libgrapheme(const void *payload) 25 | { 26 | uint_least16_t state = 0; 27 | const struct break_benchmark_payload *p = payload; 28 | size_t i; 29 | 30 | for (i = 0; i + 1 < p->buflen; i++) { 31 | (void)grapheme_is_character_break(p->buf[i], p->buf[i+1], 32 | &state); 33 | } 34 | } 35 | 36 | void 37 | libutf8proc(const void *payload) 38 | { 39 | utf8proc_int32_t state = 0; 40 | const struct break_benchmark_payload *p = payload; 41 | size_t i; 42 | 43 | for (i = 0; i + 1 < p->buflen; i++) { 44 | (void)utf8proc_grapheme_break_stateful(p->buf_utf8proc[i], 45 | p->buf_utf8proc[i+1], 46 | &state); 47 | } 48 | } 49 | 50 | int 51 | main(int argc, char *argv[]) 52 | { 53 | struct break_benchmark_payload p; 54 | double baseline = (double)NAN; 55 | size_t i; 56 | 57 | (void)argc; 58 | 59 | if ((p.buf = generate_cp_test_buffer(character_break_test, 60 | LEN(character_break_test), 61 | &(p.buflen))) == NULL) { 62 | return 1; 63 | } 64 | if ((p.buf_utf8proc = malloc(p.buflen * sizeof(*(p.buf_utf8proc)))) == NULL) { 65 | fprintf(stderr, "malloc: %s\n", strerror(errno)); 66 | exit(1); 67 | } 68 | for (i = 0; i < p.buflen; i++) { 69 | /* 70 | * there is no overflow, as we know that the maximum 71 | * codepoint is 0x10FFFF, which is way below 2^31 72 | */ 73 | p.buf_utf8proc[i] = (utf8proc_int32_t)p.buf[i]; 74 | } 75 | 76 | printf("%s\n", argv[0]); 77 | run_benchmark(libgrapheme, &p, "libgrapheme ", NULL, "comparison", 78 | &baseline, NUM_ITERATIONS, p.buflen - 1); 79 | run_benchmark(libutf8proc, &p, "libutf8proc ", NULL, "comparison", 80 | &baseline, NUM_ITERATIONS, p.buflen - 1); 81 | 82 | free(p.buf); 83 | free(p.buf_utf8proc); 84 | 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/line.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../grapheme.h" 10 | #include "../gen/line-test.h" 11 | #include "util.h" 12 | 13 | #define NUM_ITERATIONS 10000 14 | 15 | struct break_benchmark_payload { 16 | uint_least32_t *buf; 17 | size_t buflen; 18 | }; 19 | 20 | void 21 | libgrapheme(const void *payload) 22 | { 23 | const struct break_benchmark_payload *p = payload; 24 | size_t off; 25 | 26 | for (off = 0; off < p->buflen; ) { 27 | off += grapheme_next_line_break(p->buf + off, p->buflen - off); 28 | } 29 | } 30 | 31 | int 32 | main(int argc, char *argv[]) 33 | { 34 | struct break_benchmark_payload p; 35 | double baseline = (double)NAN; 36 | 37 | (void)argc; 38 | 39 | if ((p.buf = generate_cp_test_buffer(line_break_test, 40 | LEN(line_break_test), 41 | &(p.buflen))) == NULL) { 42 | return 1; 43 | } 44 | 45 | printf("%s\n", argv[0]); 46 | run_benchmark(libgrapheme, &p, "libgrapheme ", NULL, "codepoint", 47 | &baseline, NUM_ITERATIONS, p.buflen - 1); 48 | 49 | free(p.buf); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/sentence.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../grapheme.h" 10 | #include "../gen/sentence-test.h" 11 | #include "util.h" 12 | 13 | #define NUM_ITERATIONS 100000 14 | 15 | struct break_benchmark_payload { 16 | uint_least32_t *buf; 17 | size_t buflen; 18 | }; 19 | 20 | void 21 | libgrapheme(const void *payload) 22 | { 23 | const struct break_benchmark_payload *p = payload; 24 | size_t off; 25 | 26 | for (off = 0; off < p->buflen; ) { 27 | off += grapheme_next_sentence_break(p->buf + off, p->buflen - off); 28 | } 29 | } 30 | 31 | int 32 | main(int argc, char *argv[]) 33 | { 34 | struct break_benchmark_payload p; 35 | double baseline = (double)NAN; 36 | 37 | (void)argc; 38 | 39 | if ((p.buf = generate_cp_test_buffer(sentence_break_test, 40 | LEN(sentence_break_test), 41 | &(p.buflen))) == NULL) { 42 | return 1; 43 | } 44 | 45 | printf("%s\n", argv[0]); 46 | run_benchmark(libgrapheme, &p, "libgrapheme ", NULL, "codepoint", 47 | &baseline, NUM_ITERATIONS, p.buflen - 1); 48 | 49 | free(p.buf); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/utf8-decode.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../grapheme.h" 10 | #include "../gen/character-test.h" 11 | #include "util.h" 12 | 13 | #include 14 | 15 | #define NUM_ITERATIONS 100000 16 | 17 | struct utf8_benchmark_payload { 18 | char *buf; 19 | utf8proc_uint8_t *buf_utf8proc; 20 | size_t buflen; 21 | }; 22 | 23 | void 24 | libgrapheme(const void *payload) 25 | { 26 | const struct utf8_benchmark_payload *p = payload; 27 | uint_least32_t cp; 28 | size_t ret, off; 29 | 30 | for (off = 0; off < p->buflen; off += ret) { 31 | if ((ret = grapheme_decode_utf8(p->buf + off, 32 | p->buflen - off, &cp)) > 33 | (p->buflen - off)) { 34 | break; 35 | } 36 | (void)cp; 37 | } 38 | } 39 | 40 | void 41 | libutf8proc(const void *payload) 42 | { 43 | const struct utf8_benchmark_payload *p = payload; 44 | utf8proc_int32_t cp; 45 | utf8proc_ssize_t ret; 46 | size_t off; 47 | 48 | for (off = 0; off < p->buflen; off += (size_t)ret) { 49 | if ((ret = utf8proc_iterate(p->buf_utf8proc + off, 50 | (utf8proc_ssize_t)(p->buflen - off), 51 | &cp)) < 0) { 52 | break; 53 | } 54 | (void)cp; 55 | } 56 | } 57 | 58 | int 59 | main(int argc, char *argv[]) 60 | { 61 | struct utf8_benchmark_payload p; 62 | size_t i; 63 | double baseline = (double)NAN; 64 | 65 | (void)argc; 66 | 67 | p.buf = generate_utf8_test_buffer(character_break_test, 68 | LEN(character_break_test), 69 | &(p.buflen)); 70 | 71 | /* convert cp-buffer to stupid custom libutf8proc-uint8-type */ 72 | if ((p.buf_utf8proc = malloc(p.buflen)) == NULL) { 73 | fprintf(stderr, "malloc: %s\n", strerror(errno)); 74 | exit(1); 75 | } 76 | for (i = 0; i < p.buflen; i++) { 77 | /* 78 | * even if char is larger than 8 bit, it will only have 79 | * any of the first 8 bits set (by construction). 80 | */ 81 | p.buf_utf8proc[i] = (utf8proc_uint8_t)p.buf[i]; 82 | } 83 | 84 | printf("%s\n", argv[0]); 85 | run_benchmark(libgrapheme, &p, "libgrapheme ", NULL, 86 | "byte", &baseline, NUM_ITERATIONS, p.buflen); 87 | run_benchmark(libutf8proc, &p, "libutf8proc ", 88 | "but unsafe (does not detect overlong encodings)", 89 | "byte", &baseline, NUM_ITERATIONS, p.buflen); 90 | 91 | free(p.buf); 92 | free(p.buf_utf8proc); 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/util.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../gen/types.h" 8 | #include "../grapheme.h" 9 | #include "util.h" 10 | 11 | uint_least32_t * 12 | generate_cp_test_buffer(const struct break_test *test, size_t testlen, 13 | size_t *buflen) 14 | { 15 | size_t i, j, off; 16 | uint_least32_t *buf; 17 | 18 | /* allocate and generate buffer */ 19 | for (i = 0, *buflen = 0; i < testlen; i++) { 20 | *buflen += test[i].cplen; 21 | } 22 | if (!(buf = calloc(*buflen, sizeof(*buf)))) { 23 | fprintf(stderr, "generate_test_buffer: calloc: Out of memory.\n"); 24 | exit(1); 25 | } 26 | for (i = 0, off = 0; i < testlen; i++) { 27 | for (j = 0; j < test[i].cplen; j++) { 28 | buf[off + j] = test[i].cp[j]; 29 | } 30 | off += test[i].cplen; 31 | } 32 | 33 | return buf; 34 | } 35 | 36 | char * 37 | generate_utf8_test_buffer(const struct break_test *test, size_t testlen, 38 | size_t *buflen) 39 | { 40 | size_t i, j, off, ret; 41 | char *buf; 42 | 43 | /* allocate and generate buffer */ 44 | for (i = 0, *buflen = 0; i < testlen; i++) { 45 | for (j = 0; j < test[i].cplen; j++) { 46 | *buflen += grapheme_encode_utf8(test[i].cp[j], NULL, 0); 47 | } 48 | } 49 | (*buflen)++; /* terminating NUL-byte */ 50 | if (!(buf = malloc(*buflen))) { 51 | fprintf(stderr, "generate_test_buffer: malloc: Out of memory.\n"); 52 | exit(1); 53 | } 54 | for (i = 0, off = 0; i < testlen; i++) { 55 | for (j = 0; j < test[i].cplen; j++, off += ret) { 56 | if ((ret = grapheme_encode_utf8(test[i].cp[j], 57 | buf + off, 58 | *buflen - off)) > 59 | (*buflen - off)) { 60 | /* shouldn't happen */ 61 | fprintf(stderr, "generate_utf8_test_buffer: " 62 | "Buffer too small.\n"); 63 | exit(1); 64 | } 65 | } 66 | } 67 | buf[*buflen - 1] = '\0'; 68 | 69 | return buf; 70 | } 71 | 72 | static double 73 | time_diff(struct timespec *a, struct timespec *b) 74 | { 75 | return (double)(b->tv_sec - a->tv_sec) + 76 | (double)(b->tv_nsec - a->tv_nsec) * 1E-9; 77 | } 78 | 79 | void 80 | run_benchmark(void (*func)(const void *), const void *payload, 81 | const char *name, const char *comment, const char *unit, 82 | double *baseline, size_t num_iterations, 83 | size_t units_per_iteration) 84 | { 85 | struct timespec start, end; 86 | size_t i; 87 | double diff; 88 | 89 | printf("\t%s ", name); 90 | fflush(stdout); 91 | 92 | clock_gettime(CLOCK_MONOTONIC, &start); 93 | for (i = 0; i < num_iterations; i++) { 94 | func(payload); 95 | 96 | if (i % (num_iterations / 10) == 0) { 97 | printf("."); 98 | fflush(stdout); 99 | } 100 | } 101 | clock_gettime(CLOCK_MONOTONIC, &end); 102 | diff = time_diff(&start, &end) / (double)num_iterations / 103 | (double)units_per_iteration; 104 | 105 | if (isnan(*baseline)) { 106 | *baseline = diff; 107 | printf(" avg. %.3es/%s (baseline)\n", diff, unit); 108 | } else { 109 | printf(" avg. %.3es/%s (%.2f%% %s%s%s)\n", diff, unit, 110 | fabs(1.0 - diff / *baseline) * 100, 111 | (diff < *baseline) ? "faster" : "slower", 112 | comment ? ", " : "", 113 | comment ? comment : ""); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/util.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #ifndef UTIL_H 3 | #define UTIL_H 4 | 5 | #include "../gen/types.h" 6 | 7 | #define LEN(x) (sizeof(x) / sizeof(*(x))) 8 | 9 | #ifdef __has_attribute 10 | #if __has_attribute(optnone) 11 | void libgrapheme(const void *) __attribute__((optnone)); 12 | void libutf8proc(const void *) __attribute__((optnone)); 13 | #endif 14 | #endif 15 | 16 | uint_least32_t *generate_cp_test_buffer(const struct break_test *, size_t, 17 | size_t *); 18 | char *generate_utf8_test_buffer(const struct break_test *, size_t, size_t *); 19 | 20 | void run_benchmark(void (*func)(const void *), const void *, const char *, 21 | const char *, const char *, double *, size_t, size_t); 22 | 23 | #endif /* UTIL_H */ 24 | -------------------------------------------------------------------------------- /libgrapheme/benchmark/word.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../grapheme.h" 10 | #include "../gen/word-test.h" 11 | #include "util.h" 12 | 13 | #define NUM_ITERATIONS 10000 14 | 15 | struct break_benchmark_payload { 16 | uint_least32_t *buf; 17 | size_t buflen; 18 | }; 19 | 20 | void 21 | libgrapheme(const void *payload) 22 | { 23 | const struct break_benchmark_payload *p = payload; 24 | size_t off; 25 | 26 | for (off = 0; off < p->buflen; ) { 27 | off += grapheme_next_word_break(p->buf + off, p->buflen - off); 28 | } 29 | } 30 | 31 | int 32 | main(int argc, char *argv[]) 33 | { 34 | struct break_benchmark_payload p; 35 | double baseline = (double)NAN; 36 | 37 | (void)argc; 38 | 39 | if ((p.buf = generate_cp_test_buffer(word_break_test, 40 | LEN(word_break_test), 41 | &(p.buflen))) == NULL) { 42 | return 1; 43 | } 44 | 45 | printf("%s\n", argv[0]); 46 | run_benchmark(libgrapheme, &p, "libgrapheme ", NULL, "codepoint", 47 | &baseline, NUM_ITERATIONS, p.buflen - 1); 48 | 49 | free(p.buf); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /libgrapheme/config.mk: -------------------------------------------------------------------------------- 1 | # Customize below to fit your system (run ./configure for automatic presets) 2 | 3 | # paths (unset $PCPREFIX to not install a pkg-config-file) 4 | DESTDIR = 5 | PREFIX = /usr/local 6 | INCPREFIX = $(PREFIX)/include 7 | LIBPREFIX = $(PREFIX)/lib 8 | MANPREFIX = $(PREFIX)/share/man 9 | PCPREFIX = $(LIBPREFIX)/pkgconfig 10 | 11 | # flags 12 | CPPFLAGS = -D_DEFAULT_SOURCE 13 | CFLAGS = -std=c99 -Os -Wall -Wextra -Wpedantic 14 | LDFLAGS = -s 15 | 16 | BUILD_CPPFLAGS = $(CPPFLAGS) 17 | BUILD_CFLAGS = $(CFLAGS) 18 | BUILD_LDFLAGS = $(LDFLAGS) 19 | 20 | SHFLAGS = -fPIC -ffreestanding 21 | 22 | SOFLAGS = -shared -nostdlib -Wl,--soname=libgrapheme.so.$(VERSION_MAJOR).$(VERSION_MINOR) 23 | SONAME = libgrapheme.so.$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) 24 | SOSYMLINK = true 25 | 26 | # tools (unset $LDCONFIG to not call ldconfig(1) after install/uninstall) 27 | CC = cc 28 | BUILD_CC = $(CC) 29 | AR = ar 30 | RANLIB = ranlib 31 | LDCONFIG = ldconfig 32 | SH = sh 33 | -------------------------------------------------------------------------------- /libgrapheme/configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # See LICENSE file for copyright and license details. 3 | 4 | replace_line() 5 | { 6 | VAR=$1 7 | ALIGNMENT=$2 8 | VALUE=$3 9 | awk "/^${VAR}[ ]*=/ { print \"${VAR}${ALIGNMENT} = ${VALUE}\"; next }; { print; }" config.mk > config.mk.tmp 10 | mv config.mk.tmp config.mk 11 | } 12 | 13 | case $(uname) in 14 | DragonFly|FreeBSD|Linux|MidnightBSD|NetBSD) 15 | # the default 16 | replace_line 'SOFLAGS' ' ' '-shared -nostdlib -Wl,--soname=libgrapheme.so.$(VERSION_MAJOR).$(VERSION_MINOR)' 17 | replace_line 'SONAME' ' ' 'libgrapheme.so.$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)' 18 | replace_line 'SOSYMLINK' '' 'true' 19 | replace_line 'LDCONFIG' '' 'ldconfig' 20 | ;; 21 | OpenBSD) 22 | replace_line 'SOFLAGS' ' ' '-shared -nostdlib' 23 | replace_line 'SONAME' ' ' 'libgrapheme.so.$(VERSION_MAJOR).$(VERSION_MINOR)' 24 | replace_line 'SOSYMLINK' '' 'false' 25 | replace_line 'LDCONFIG' '' '' 26 | ;; 27 | Darwin) 28 | replace_line 'SOFLAGS' ' ' '-dynamiclib -install_name libgrapheme.$(VERSION_MAJOR).dylib -current_version $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) -compatibility_version $(VERSION_MAJOR).$(VERSION_MINOR).0' 29 | replace_line 'SONAME' ' ' 'libgrapheme.$(VERSION_MAJOR).dylib' 30 | replace_line 'SOSYMLINK' '' 'false' 31 | replace_line 'LDCONFIG' '' '' 32 | ;; 33 | *) 34 | echo "Your system does not have a preset. Edit config.mk and send a patch please! :)" 35 | exit 1 36 | ;; 37 | esac 38 | 39 | exit 0 40 | -------------------------------------------------------------------------------- /libgrapheme/data/LICENSE: -------------------------------------------------------------------------------- 1 | UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE 2 | 3 | See Terms of Use 4 | for definitions of Unicode Inc.’s Data Files and Software. 5 | 6 | NOTICE TO USER: Carefully read the following legal agreement. 7 | BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S 8 | DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), 9 | YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE 10 | TERMS AND CONDITIONS OF THIS AGREEMENT. 11 | IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE 12 | THE DATA FILES OR SOFTWARE. 13 | 14 | COPYRIGHT AND PERMISSION NOTICE 15 | 16 | Copyright © 1991-2022 Unicode, Inc. All rights reserved. 17 | Distributed under the Terms of Use in https://www.unicode.org/copyright.html. 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining 20 | a copy of the Unicode data files and any associated documentation 21 | (the "Data Files") or Unicode software and any associated documentation 22 | (the "Software") to deal in the Data Files or Software 23 | without restriction, including without limitation the rights to use, 24 | copy, modify, merge, publish, distribute, and/or sell copies of 25 | the Data Files or Software, and to permit persons to whom the Data Files 26 | or Software are furnished to do so, provided that either 27 | (a) this copyright and permission notice appear with all copies 28 | of the Data Files or Software, or 29 | (b) this copyright and permission notice appear in associated 30 | Documentation. 31 | 32 | THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF 33 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 34 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 35 | NONINFRINGEMENT OF THIRD PARTY RIGHTS. 36 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS 37 | NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL 38 | DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 39 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 40 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 41 | PERFORMANCE OF THE DATA FILES OR SOFTWARE. 42 | 43 | Except as contained in this notice, the name of a copyright holder 44 | shall not be used in advertising or otherwise to promote the sale, 45 | use or other dealings in these Data Files or Software without prior 46 | written authorization of the copyright holder. 47 | -------------------------------------------------------------------------------- /libgrapheme/gen/character-test.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "util.h" 5 | 6 | int 7 | main(int argc, char *argv[]) 8 | { 9 | struct break_test *test = NULL; 10 | size_t testlen = 0; 11 | 12 | (void)argc; 13 | 14 | break_test_list_parse("data/GraphemeBreakTest.txt", &test, &testlen); 15 | break_test_list_print(test, testlen, "character_break_test", argv[0]); 16 | break_test_list_free(test, testlen); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /libgrapheme/gen/character.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "util.h" 5 | 6 | #define FILE_EMOJI "data/emoji-data.txt" 7 | #define FILE_GRAPHEME "data/GraphemeBreakProperty.txt" 8 | 9 | static const struct property_spec char_break_property[] = { 10 | { 11 | .enumname = "OTHER", 12 | .file = NULL, 13 | .ucdname = NULL, 14 | }, 15 | { 16 | .enumname = "CONTROL", 17 | .file = FILE_GRAPHEME, 18 | .ucdname = "Control", 19 | }, 20 | { 21 | .enumname = "CR", 22 | .file = FILE_GRAPHEME, 23 | .ucdname = "CR", 24 | }, 25 | { 26 | .enumname = "EXTEND", 27 | .file = FILE_GRAPHEME, 28 | .ucdname = "Extend", 29 | }, 30 | { 31 | .enumname = "EXTENDED_PICTOGRAPHIC", 32 | .file = FILE_EMOJI, 33 | .ucdname = "Extended_Pictographic", 34 | }, 35 | { 36 | .enumname = "HANGUL_L", 37 | .file = FILE_GRAPHEME, 38 | .ucdname = "L", 39 | }, 40 | { 41 | .enumname = "HANGUL_V", 42 | .file = FILE_GRAPHEME, 43 | .ucdname = "V", 44 | }, 45 | { 46 | .enumname = "HANGUL_T", 47 | .file = FILE_GRAPHEME, 48 | .ucdname = "T", 49 | }, 50 | { 51 | .enumname = "HANGUL_LV", 52 | .file = FILE_GRAPHEME, 53 | .ucdname = "LV", 54 | }, 55 | { 56 | .enumname = "HANGUL_LVT", 57 | .file = FILE_GRAPHEME, 58 | .ucdname = "LVT", 59 | }, 60 | { 61 | .enumname = "LF", 62 | .file = FILE_GRAPHEME, 63 | .ucdname = "LF", 64 | }, 65 | { 66 | .enumname = "PREPEND", 67 | .file = FILE_GRAPHEME, 68 | .ucdname = "Prepend", 69 | }, 70 | { 71 | .enumname = "REGIONAL_INDICATOR", 72 | .file = FILE_GRAPHEME, 73 | .ucdname = "Regional_Indicator", 74 | }, 75 | { 76 | .enumname = "SPACINGMARK", 77 | .file = FILE_GRAPHEME, 78 | .ucdname = "SpacingMark", 79 | }, 80 | { 81 | .enumname = "ZWJ", 82 | .file = FILE_GRAPHEME, 83 | .ucdname = "ZWJ", 84 | }, 85 | }; 86 | 87 | int 88 | main(int argc, char *argv[]) 89 | { 90 | (void)argc; 91 | 92 | properties_generate_break_property(char_break_property, 93 | LEN(char_break_property), 94 | NULL, NULL, "char_break", argv[0]); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /libgrapheme/gen/line-test.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "util.h" 5 | 6 | int 7 | main(int argc, char *argv[]) 8 | { 9 | struct break_test *test = NULL; 10 | size_t testlen = 0; 11 | 12 | (void)argc; 13 | 14 | break_test_list_parse("data/LineBreakTest.txt", &test, &testlen); 15 | break_test_list_print(test, testlen, "line_break_test", argv[0]); 16 | break_test_list_free(test, testlen); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /libgrapheme/gen/sentence-test.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "util.h" 5 | 6 | int 7 | main(int argc, char *argv[]) 8 | { 9 | struct break_test *test = NULL; 10 | size_t testlen = 0; 11 | 12 | (void)argc; 13 | 14 | break_test_list_parse("data/SentenceBreakTest.txt", &test, &testlen); 15 | break_test_list_print(test, testlen, "sentence_break_test", argv[0]); 16 | break_test_list_free(test, testlen); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /libgrapheme/gen/sentence.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "util.h" 3 | 4 | #define FILE_SENTENCE "data/SentenceBreakProperty.txt" 5 | 6 | static const struct property_spec sentence_break_property[] = { 7 | { 8 | .enumname = "OTHER", 9 | .file = NULL, 10 | .ucdname = NULL, 11 | }, 12 | { 13 | .enumname = "CR", 14 | .file = FILE_SENTENCE, 15 | .ucdname = "CR", 16 | }, 17 | { 18 | .enumname = "LF", 19 | .file = FILE_SENTENCE, 20 | .ucdname = "LF", 21 | }, 22 | { 23 | .enumname = "EXTEND", 24 | .file = FILE_SENTENCE, 25 | .ucdname = "Extend", 26 | }, 27 | { 28 | .enumname = "SEP", 29 | .file = FILE_SENTENCE, 30 | .ucdname = "Sep", 31 | }, 32 | { 33 | .enumname = "FORMAT", 34 | .file = FILE_SENTENCE, 35 | .ucdname = "Format", 36 | }, 37 | { 38 | .enumname = "SP", 39 | .file = FILE_SENTENCE, 40 | .ucdname = "Sp", 41 | }, 42 | { 43 | .enumname = "LOWER", 44 | .file = FILE_SENTENCE, 45 | .ucdname = "Lower", 46 | }, 47 | { 48 | .enumname = "UPPER", 49 | .file = FILE_SENTENCE, 50 | .ucdname = "Upper", 51 | }, 52 | { 53 | .enumname = "OLETTER", 54 | .file = FILE_SENTENCE, 55 | .ucdname = "OLetter", 56 | }, 57 | { 58 | .enumname = "NUMERIC", 59 | .file = FILE_SENTENCE, 60 | .ucdname = "Numeric", 61 | }, 62 | { 63 | .enumname = "ATERM", 64 | .file = FILE_SENTENCE, 65 | .ucdname = "ATerm", 66 | }, 67 | { 68 | .enumname = "SCONTINUE", 69 | .file = FILE_SENTENCE, 70 | .ucdname = "SContinue", 71 | }, 72 | { 73 | .enumname = "STERM", 74 | .file = FILE_SENTENCE, 75 | .ucdname = "STerm", 76 | }, 77 | { 78 | .enumname = "CLOSE", 79 | .file = FILE_SENTENCE, 80 | .ucdname = "Close", 81 | }, 82 | }; 83 | 84 | int 85 | main(int argc, char *argv[]) 86 | { 87 | (void)argc; 88 | 89 | properties_generate_break_property(sentence_break_property, 90 | LEN(sentence_break_property), 91 | NULL, NULL, "sentence_break", argv[0]); 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /libgrapheme/gen/types.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #ifndef TYPES_H 3 | #define TYPES_H 4 | 5 | #include 6 | #include 7 | 8 | struct break_test { 9 | uint_least32_t *cp; 10 | size_t cplen; 11 | size_t *len; 12 | size_t lenlen; 13 | char *descr; 14 | }; 15 | 16 | #endif /* TYPES_H */ 17 | -------------------------------------------------------------------------------- /libgrapheme/gen/util.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #ifndef UTIL_H 3 | #define UTIL_H 4 | 5 | #include 6 | #include 7 | 8 | #include "types.h" 9 | 10 | #define LEN(x) (sizeof (x) / sizeof *(x)) 11 | 12 | struct property_spec { 13 | const char *enumname; 14 | const char *file; 15 | const char *ucdname; 16 | }; 17 | 18 | struct properties { 19 | int_least64_t property; 20 | }; 21 | 22 | struct properties_compressed { 23 | size_t *offset; 24 | struct properties *data; 25 | size_t datalen; 26 | }; 27 | 28 | struct properties_major_minor { 29 | size_t *major; 30 | size_t *minor; 31 | size_t minorlen; 32 | }; 33 | 34 | int hextocp(const char *, size_t, uint_least32_t *cp); 35 | 36 | void parse_file_with_callback(const char *, int (*callback)(const char *, 37 | char **, size_t, char *, void *), void *payload); 38 | 39 | void properties_compress(const struct properties *, struct properties_compressed *comp); 40 | double properties_get_major_minor(const struct properties_compressed *, 41 | struct properties_major_minor *); 42 | void properties_print_lookup_table(char *, size_t *, size_t); 43 | void properties_print_derived_lookup_table(char *, char *, size_t *, size_t, 44 | int_least64_t (*get_value)(const struct properties *, 45 | size_t), const void *); 46 | 47 | void properties_generate_break_property(const struct property_spec *, 48 | uint_least8_t, uint_least8_t 49 | (*handle_conflict)(uint_least32_t, 50 | uint_least8_t, uint_least8_t), 51 | uint_least8_t (*post_process) 52 | (uint_least8_t), const char *, 53 | const char *); 54 | 55 | void break_test_list_parse(char *, struct break_test **, size_t *); 56 | void break_test_list_print(const struct break_test *, size_t, 57 | const char *, const char *); 58 | void break_test_list_free(struct break_test *, size_t); 59 | 60 | #endif /* UTIL_H */ 61 | -------------------------------------------------------------------------------- /libgrapheme/gen/word-test.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "util.h" 5 | 6 | int 7 | main(int argc, char *argv[]) 8 | { 9 | struct break_test *test = NULL; 10 | size_t testlen = 0; 11 | 12 | (void)argc; 13 | 14 | break_test_list_parse("data/WordBreakTest.txt", &test, &testlen); 15 | break_test_list_print(test, testlen, "word_break_test", argv[0]); 16 | break_test_list_free(test, testlen); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /libgrapheme/gen/word.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "util.h" 7 | 8 | #define FILE_EMOJI "data/emoji-data.txt" 9 | #define FILE_WORD "data/WordBreakProperty.txt" 10 | 11 | static const struct property_spec word_break_property[] = { 12 | { 13 | .enumname = "OTHER", 14 | .file = NULL, 15 | .ucdname = NULL, 16 | }, 17 | { 18 | .enumname = "ALETTER", 19 | .file = FILE_WORD, 20 | .ucdname = "ALetter", 21 | }, 22 | { 23 | .enumname = "BOTH_ALETTER_EXTPICT", 24 | .file = NULL, 25 | .ucdname = NULL, 26 | }, 27 | { 28 | .enumname = "CR", 29 | .file = FILE_WORD, 30 | .ucdname = "CR", 31 | }, 32 | { 33 | .enumname = "DOUBLE_QUOTE", 34 | .file = FILE_WORD, 35 | .ucdname = "Double_Quote", 36 | }, 37 | { 38 | .enumname = "EXTEND", 39 | .file = FILE_WORD, 40 | .ucdname = "Extend", 41 | }, 42 | { 43 | .enumname = "EXTENDED_PICTOGRAPHIC", 44 | .file = FILE_EMOJI, 45 | .ucdname = "Extended_Pictographic", 46 | }, 47 | { 48 | .enumname = "EXTENDNUMLET", 49 | .file = FILE_WORD, 50 | .ucdname = "ExtendNumLet", 51 | }, 52 | { 53 | .enumname = "FORMAT", 54 | .file = FILE_WORD, 55 | .ucdname = "Format", 56 | }, 57 | { 58 | .enumname = "HEBREW_LETTER", 59 | .file = FILE_WORD, 60 | .ucdname = "Hebrew_Letter", 61 | }, 62 | { 63 | .enumname = "KATAKANA", 64 | .file = FILE_WORD, 65 | .ucdname = "Katakana", 66 | }, 67 | { 68 | .enumname = "LF", 69 | .file = FILE_WORD, 70 | .ucdname = "LF", 71 | }, 72 | { 73 | .enumname = "MIDLETTER", 74 | .file = FILE_WORD, 75 | .ucdname = "MidLetter", 76 | }, 77 | { 78 | .enumname = "MIDNUM", 79 | .file = FILE_WORD, 80 | .ucdname = "MidNum", 81 | }, 82 | { 83 | .enumname = "MIDNUMLET", 84 | .file = FILE_WORD, 85 | .ucdname = "MidNumLet", 86 | }, 87 | { 88 | .enumname = "NEWLINE", 89 | .file = FILE_WORD, 90 | .ucdname = "Newline", 91 | }, 92 | { 93 | .enumname = "NUMERIC", 94 | .file = FILE_WORD, 95 | .ucdname = "Numeric", 96 | }, 97 | { 98 | .enumname = "REGIONAL_INDICATOR", 99 | .file = FILE_WORD, 100 | .ucdname = "Regional_Indicator", 101 | }, 102 | { 103 | .enumname = "SINGLE_QUOTE", 104 | .file = FILE_WORD, 105 | .ucdname = "Single_Quote", 106 | }, 107 | { 108 | .enumname = "WSEGSPACE", 109 | .file = FILE_WORD, 110 | .ucdname = "WSegSpace", 111 | }, 112 | { 113 | .enumname = "ZWJ", 114 | .file = FILE_WORD, 115 | .ucdname = "ZWJ", 116 | }, 117 | }; 118 | 119 | static uint_least8_t 120 | handle_conflict(uint_least32_t cp, uint_least8_t prop1, uint_least8_t prop2) 121 | { 122 | uint_least8_t result; 123 | 124 | (void)cp; 125 | 126 | if ((!strcmp(word_break_property[prop1].enumname, "ALETTER") && 127 | !strcmp(word_break_property[prop2].enumname, "EXTENDED_PICTOGRAPHIC")) || 128 | (!strcmp(word_break_property[prop1].enumname, "EXTENDED_PICTOGRAPHIC") && 129 | !strcmp(word_break_property[prop2].enumname, "ALETTER"))) { 130 | for (result = 0; result < LEN(word_break_property); result++) { 131 | if (!strcmp(word_break_property[result].enumname, 132 | "BOTH_ALETTER_EXTPICT")) { 133 | break; 134 | } 135 | } 136 | if (result == LEN(word_break_property)) { 137 | fprintf(stderr, "handle_conflict: Internal error.\n"); 138 | exit(1); 139 | } 140 | } else { 141 | fprintf(stderr, "handle_conflict: Cannot handle conflict.\n"); 142 | exit(1); 143 | } 144 | 145 | return result; 146 | } 147 | 148 | int 149 | main(int argc, char *argv[]) 150 | { 151 | (void)argc; 152 | 153 | properties_generate_break_property(word_break_property, 154 | LEN(word_break_property), 155 | handle_conflict, NULL, "word_break", 156 | argv[0]); 157 | 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /libgrapheme/grapheme.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #ifndef GRAPHEME_H 3 | #define GRAPHEME_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define GRAPHEME_INVALID_CODEPOINT UINT32_C(0xFFFD) 10 | 11 | size_t grapheme_decode_utf8(const char *, size_t, uint_least32_t *); 12 | size_t grapheme_encode_utf8(uint_least32_t, char *, size_t); 13 | 14 | bool grapheme_is_character_break(uint_least32_t, uint_least32_t, uint_least16_t *); 15 | 16 | bool grapheme_is_lowercase(const uint_least32_t *, size_t, size_t *); 17 | bool grapheme_is_titlecase(const uint_least32_t *, size_t, size_t *); 18 | bool grapheme_is_uppercase(const uint_least32_t *, size_t, size_t *); 19 | 20 | bool grapheme_is_lowercase_utf8(const char *, size_t, size_t *); 21 | bool grapheme_is_titlecase_utf8(const char *, size_t, size_t *); 22 | bool grapheme_is_uppercase_utf8(const char *, size_t, size_t *); 23 | 24 | size_t grapheme_next_character_break(const uint_least32_t *, size_t); 25 | size_t grapheme_next_line_break(const uint_least32_t *, size_t); 26 | size_t grapheme_next_sentence_break(const uint_least32_t *, size_t); 27 | size_t grapheme_next_word_break(const uint_least32_t *, size_t); 28 | 29 | size_t grapheme_next_character_break_utf8(const char *, size_t); 30 | size_t grapheme_next_line_break_utf8(const char *, size_t); 31 | size_t grapheme_next_sentence_break_utf8(const char *, size_t); 32 | size_t grapheme_next_word_break_utf8(const char *, size_t); 33 | 34 | size_t grapheme_to_lowercase(const uint_least32_t *, size_t, uint_least32_t *, size_t); 35 | size_t grapheme_to_titlecase(const uint_least32_t *, size_t, uint_least32_t *, size_t); 36 | size_t grapheme_to_uppercase(const uint_least32_t *, size_t, uint_least32_t *, size_t); 37 | 38 | size_t grapheme_to_lowercase_utf8(const char *, size_t, char *, size_t); 39 | size_t grapheme_to_titlecase_utf8(const char *, size_t, char *, size_t); 40 | size_t grapheme_to_uppercase_utf8(const char *, size_t, char *, size_t); 41 | 42 | #endif /* GRAPHEME_H */ 43 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_decode_utf8.sh: -------------------------------------------------------------------------------- 1 | cat << EOF 2 | .Dd ${MAN_DATE} 3 | .Dt GRAPHEME_DECODE_UTF8 3 4 | .Os suckless.org 5 | .Sh NAME 6 | .Nm grapheme_decode_utf8 7 | .Nd decode first codepoint in UTF-8-encoded string 8 | .Sh SYNOPSIS 9 | .In grapheme.h 10 | .Ft size_t 11 | .Fn grapheme_decode_utf8 "const char *str" "size_t len" "uint_least32_t *cp" 12 | .Sh DESCRIPTION 13 | The 14 | .Fn grapheme_decode_utf8 15 | function decodes the first codepoint in the UTF-8-encoded string 16 | .Va str 17 | of length 18 | .Va len . 19 | If the UTF-8-sequence is invalid (overlong encoding, unexpected byte, 20 | string ends unexpectedly, empty string, etc.) the decoding is stopped 21 | at the last processed byte and the decoded codepoint set to 22 | .Dv GRAPHEME_INVALID_CODEPOINT . 23 | .Pp 24 | If 25 | .Va cp 26 | is not 27 | .Dv NULL 28 | the decoded codepoint is stored in the memory pointed to by 29 | .Va cp . 30 | .Pp 31 | Given NUL has a unique 1 byte representation, it is safe to operate on 32 | NUL-terminated strings by setting 33 | .Va len 34 | to 35 | .Dv SIZE_MAX 36 | (stdint.h is already included by grapheme.h) and terminating when 37 | .Va cp 38 | is 0 (see 39 | .Sx EXAMPLES 40 | for an example). 41 | .Sh RETURN VALUES 42 | The 43 | .Fn grapheme_decode_utf8 44 | function returns the number of processed bytes and 0 if 45 | .Va str 46 | is 47 | .Dv NULL 48 | or 49 | .Va len 50 | is 0. 51 | If the string ends unexpectedly in a multibyte sequence, the desired 52 | length (that is larger than 53 | .Va len ) 54 | is returned. 55 | .Sh EXAMPLES 56 | .Bd -literal 57 | /* cc (-static) -o example example.c -lgrapheme */ 58 | #include 59 | #include 60 | #include 61 | 62 | void 63 | print_cps(const char *str, size_t len) 64 | { 65 | size_t ret, off; 66 | uint_least32_t cp; 67 | 68 | for (off = 0; off < len; off += ret) { 69 | if ((ret = grapheme_decode_utf8(str + off, 70 | len - off, &cp)) > (len - off)) { 71 | /* 72 | * string ended unexpectedly in the middle of a 73 | * multibyte sequence and we have the choice 74 | * here to possibly expand str by ret - len + off 75 | * bytes to get a full sequence, but we just 76 | * bail out in this case. 77 | */ 78 | break; 79 | } 80 | printf("%"PRIxLEAST32"\\\\n", cp); 81 | } 82 | } 83 | 84 | void 85 | print_cps_nul_terminated(const char *str) 86 | { 87 | size_t ret, off; 88 | uint_least32_t cp; 89 | 90 | for (off = 0; (ret = grapheme_decode_utf8(str + off, 91 | SIZE_MAX, &cp)) > 0 && 92 | cp != 0; off += ret) { 93 | printf("%"PRIxLEAST32"\\\\n", cp); 94 | } 95 | } 96 | .Ed 97 | .Sh SEE ALSO 98 | .Xr grapheme_encode_utf8 3 , 99 | .Xr libgrapheme 7 100 | .Sh AUTHORS 101 | .An Laslo Hunhold Aq Mt dev@frign.de 102 | EOF 103 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_encode_utf8.sh: -------------------------------------------------------------------------------- 1 | cat << EOF 2 | .Dd ${MAN_DATE} 3 | .Dt GRAPHEME_ENCODE_UTF8 3 4 | .Os suckless.org 5 | .Sh NAME 6 | .Nm grapheme_encode_utf8 7 | .Nd encode codepoint into UTF-8 string 8 | .Sh SYNOPSIS 9 | .In grapheme.h 10 | .Ft size_t 11 | .Fn grapheme_encode_utf8 "uint_least32_t cp" "char *str" "size_t len" 12 | .Sh DESCRIPTION 13 | The 14 | .Fn grapheme_encode_utf8 15 | function encodes the codepoint 16 | .Va cp 17 | into a UTF-8-string. 18 | If 19 | .Va str 20 | is not 21 | .Dv NULL 22 | and 23 | .Va len 24 | is large enough it writes the UTF-8-string to the memory pointed to by 25 | .Va str . 26 | Otherwise no data is written. 27 | .Sh RETURN VALUES 28 | The 29 | .Fn grapheme_encode_utf8 30 | function returns the length (in bytes) of the UTF-8-string resulting 31 | from encoding 32 | .Va cp , 33 | even if 34 | .Va len 35 | is not large enough or 36 | .Va str 37 | is 38 | .Dv NULL . 39 | .Sh EXAMPLES 40 | .Bd -literal 41 | /* cc (-static) -o example example.c -lgrapheme */ 42 | #include 43 | #include 44 | #include 45 | 46 | size_t 47 | cps_to_utf8(const uint_least32_t *cp, size_t cplen, char *str, size_t len) 48 | { 49 | size_t i, off, ret; 50 | 51 | for (i = 0, off = 0; i < cplen; i++, off += ret) { 52 | if ((ret = grapheme_encode_utf8(cp[i], str + off, 53 | len - off)) > (len - off)) { 54 | /* buffer too small */ 55 | break; 56 | } 57 | } 58 | 59 | return off; 60 | } 61 | 62 | size_t 63 | cps_bytelen(const uint_least32_t *cp, size_t cplen) 64 | { 65 | size_t i, len; 66 | 67 | for (i = 0, len = 0; i < cplen; i++) { 68 | len += grapheme_encode_utf8(cp[i], NULL, 0); 69 | } 70 | 71 | return len; 72 | } 73 | 74 | char * 75 | cps_to_utf8_alloc(const uint_least32_t *cp, size_t cplen) 76 | { 77 | char *str; 78 | size_t len, i, ret, off; 79 | 80 | len = cps_bytelen(cp, cplen); 81 | 82 | if (!(str = malloc(len))) { 83 | return NULL; 84 | } 85 | 86 | for (i = 0, off = 0; i < cplen; i++, off += ret) { 87 | if ((ret = grapheme_encode_utf8(cp[i], str + off, 88 | len - off)) > (len - off)) { 89 | /* buffer too small */ 90 | break; 91 | } 92 | } 93 | str[off] = '\\\\0'; 94 | 95 | return str; 96 | } 97 | .Ed 98 | .Sh SEE ALSO 99 | .Xr grapheme_decode_utf8 3 , 100 | .Xr libgrapheme 7 101 | .Sh AUTHORS 102 | .An Laslo Hunhold Aq Mt dev@frign.de 103 | EOF 104 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_is_character_break.sh: -------------------------------------------------------------------------------- 1 | cat << EOF 2 | .Dd ${MAN_DATE} 3 | .Dt GRAPHEME_IS_CHARACTER_BREAK 3 4 | .Os suckless.org 5 | .Sh NAME 6 | .Nm grapheme_is_character_break 7 | .Nd test for a grapheme cluster break between two codepoints 8 | .Sh SYNOPSIS 9 | .In grapheme.h 10 | .Ft size_t 11 | .Fn grapheme_is_character_break "uint_least32_t cp1" "uint_least32_t cp2" "uint_least16_t *state" 12 | .Sh DESCRIPTION 13 | The 14 | .Fn grapheme_is_character_break 15 | function determines if there is a grapheme cluster break (see 16 | .Xr libgrapheme 7 ) 17 | between the two codepoints 18 | .Va cp1 19 | and 20 | .Va cp2 . 21 | By specification this decision depends on a 22 | .Va state 23 | that can at most be completely reset after detecting a break and must 24 | be reset every time one deviates from sequential processing. 25 | .Pp 26 | If 27 | .Va state 28 | is 29 | .Dv NULL 30 | .Fn grapheme_is_character_break 31 | behaves as if it was called with a fully reset state. 32 | .Sh RETURN VALUES 33 | The 34 | .Fn grapheme_is_character_break 35 | function returns 36 | .Va true 37 | if there is a grapheme cluster break between the codepoints 38 | .Va cp1 39 | and 40 | .Va cp2 41 | and 42 | .Va false 43 | if there is not. 44 | .Sh EXAMPLES 45 | .Bd -literal 46 | /* cc (-static) -o example example.c -lgrapheme */ 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | int 53 | main(void) 54 | { 55 | uint_least16_t state = 0; 56 | uint_least32_t s1[] = ..., s2[] = ...; /* two input arrays */ 57 | size_t i; 58 | 59 | for (i = 0; i + 1 < sizeof(s1) / sizeof(*s1); i++) { 60 | if (grapheme_is_character_break(s[i], s[i + 1], &state)) { 61 | printf("break in s1 at offset %zu\n", i); 62 | } 63 | } 64 | memset(&state, 0, sizeof(state)); /* reset state */ 65 | for (i = 0; i + 1 < sizeof(s2) / sizeof(*s2); i++) { 66 | if (grapheme_is_character_break(s[i], s[i + 1], &state)) { 67 | printf("break in s2 at offset %zu\n", i); 68 | } 69 | } 70 | 71 | return 0; 72 | } 73 | .Ed 74 | .Sh SEE ALSO 75 | .Xr grapheme_next_character_break 3 , 76 | .Xr grapheme_next_character_break_utf8 3 , 77 | .Xr libgrapheme 7 78 | .Sh STANDARDS 79 | .Fn grapheme_is_character_break 80 | is compliant with the Unicode ${UNICODE_VERSION} specification. 81 | .Sh AUTHORS 82 | .An Laslo Hunhold Aq Mt dev@frign.de 83 | EOF 84 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_is_lowercase.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | CASE="lowercase" \ 3 | $SH man/template/is_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_is_lowercase_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | CASE="lowercase" \ 3 | $SH man/template/is_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_is_titlecase.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | CASE="titlecase" \ 3 | $SH man/template/is_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_is_titlecase_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | CASE="titlecase" \ 3 | $SH man/template/is_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_is_uppercase.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | CASE="uppercase" \ 3 | $SH man/template/is_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_is_uppercase_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | CASE="lowercase" \ 3 | $SH man/template/is_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_character_break.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | TYPE="character" \ 3 | REALTYPE="grapheme cluster" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_character_break_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | TYPE="character" \ 3 | REALTYPE="grapheme cluster" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_line_break.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | TYPE="line" \ 3 | REALTYPE="possible line" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_line_break_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | TYPE="line" \ 3 | REALTYPE="possible line" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_sentence_break.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | TYPE="sentence" \ 3 | REALTYPE="sentence" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_sentence_break_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | TYPE="sentence" \ 3 | REALTYPE="sentence" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_word_break.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | TYPE="word" \ 3 | REALTYPE="word" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_next_word_break_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | TYPE="word" \ 3 | REALTYPE="word" \ 4 | $SH man/template/next_break.sh 5 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_to_lowercase.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | CASE="lowercase" \ 3 | $SH man/template/to_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_to_lowercase_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | CASE="lowercase" \ 3 | $SH man/template/to_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_to_titlecase.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | CASE="titlecase" \ 3 | $SH man/template/to_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_to_titlecase_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | CASE="titlecase" \ 3 | $SH man/template/to_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_to_uppercase.sh: -------------------------------------------------------------------------------- 1 | ENCODING="codepoint" \ 2 | CASE="uppercase" \ 3 | $SH man/template/to_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/grapheme_to_uppercase_utf8.sh: -------------------------------------------------------------------------------- 1 | ENCODING="utf8" \ 2 | CASE="lowercase" \ 3 | $SH man/template/to_case.sh 4 | -------------------------------------------------------------------------------- /libgrapheme/man/template/is_case.sh: -------------------------------------------------------------------------------- 1 | if [ "$ENCODING" = "utf8" ]; then 2 | UNIT="byte" 3 | ARRAYTYPE="UTF-8-encoded string" 4 | SUFFIX="_utf8" 5 | ANTISUFFIX="" 6 | DATATYPE="char" 7 | else 8 | UNIT="codepoint" 9 | ARRAYTYPE="codepoint array" 10 | SUFFIX="" 11 | ANTISUFFIX="_utf8" 12 | DATATYPE="uint_least32_t" 13 | fi 14 | 15 | cat << EOF 16 | .Dd ${MAN_DATE} 17 | .Dt GRAPHEME_IS_$(printf "%s%s" "$CASE" "$SUFFIX" | tr [:lower:] [:upper:]) 3 18 | .Os suckless.org 19 | .Sh NAME 20 | .Nm grapheme_is_${CASE}${SUFFIX} 21 | .Nd check if ${ARRAYTYPE} is ${CASE} 22 | .Sh SYNOPSIS 23 | .In grapheme.h 24 | .Ft size_t 25 | .Fn grapheme_is_${CASE}${SUFFIX} "const ${DATATYPE} *str" "size_t len" "size_t *caselen" 26 | .Sh DESCRIPTION 27 | The 28 | .Fn grapheme_is_${CASE}${SUFFIX} 29 | function checks if the ${ARRAYTYPE} 30 | .Va str 31 | is ${CASE} and writes the length of the matching ${CASE}-sequence to the integer pointed to by 32 | .Va caselen , 33 | unless 34 | .Va caselen 35 | is set to 36 | .Dv NULL . 37 | .Pp 38 | If 39 | .Va len 40 | is set to 41 | .Dv SIZE_MAX 42 | (stdint.h is already included by grapheme.h) the ${ARRAYTYPE} 43 | .Va src 44 | is interpreted to be NUL-terminated and processing stops when a 45 | NUL-byte is encountered. 46 | .Pp 47 | For $(if [ "$ENCODING" != "utf8" ]; then printf "UTF-8-encoded"; else printf "non-UTF-8"; fi) input data 48 | .Xr grapheme_is_${CASE}${ANTISUFFIX} 3 49 | can be used instead. 50 | .Sh RETURN VALUES 51 | The 52 | .Fn grapheme_is_${CASE}${SUFFIX} 53 | function returns 54 | .Dv true 55 | if the ${ARRAYTYPE} 56 | .Va str 57 | is ${CASE}, otherwise 58 | .Dv false . 59 | .Sh SEE ALSO 60 | .Xr grapheme_is_${CASE}${ANTISUFFIX} 3 , 61 | .Xr libgrapheme 7 62 | .Sh STANDARDS 63 | .Fn grapheme_is_${CASE}${SUFFIX} 64 | is compliant with the Unicode ${UNICODE_VERSION} specification. 65 | .Sh AUTHORS 66 | .An Laslo Hunhold Aq Mt dev@frign.de 67 | EOF 68 | -------------------------------------------------------------------------------- /libgrapheme/man/template/next_break.sh: -------------------------------------------------------------------------------- 1 | if [ "$ENCODING" = "utf8" ]; then 2 | UNIT="byte" 3 | SUFFIX="_utf8" 4 | ANTISUFFIX="" 5 | else 6 | UNIT="codepoint" 7 | SUFFIX="" 8 | ANTISUFFIX="_utf8" 9 | fi 10 | 11 | cat << EOF 12 | .Dd ${MAN_DATE} 13 | .Dt GRAPHEME_NEXT_$(printf "%s_break%s" "$TYPE" "$SUFFIX" | tr [:lower:] [:upper:]) 3 14 | .Os suckless.org 15 | .Sh NAME 16 | .Nm grapheme_next_${TYPE}_break${SUFFIX} 17 | .Nd determine ${UNIT}-offset to next ${REALTYPE} break 18 | .Sh SYNOPSIS 19 | .In grapheme.h 20 | .Ft size_t 21 | .Fn grapheme_next_${TYPE}_break${SUFFIX} "const $(if [ "$ENCODING" = "utf8" ]; then printf "char"; else printf "uint_least32_t"; fi) *str" "size_t len" 22 | .Sh DESCRIPTION 23 | The 24 | .Fn grapheme_next_${TYPE}_break${SUFFIX} 25 | function computes the offset (in ${UNIT}s) to the next ${REALTYPE} 26 | break (see 27 | .Xr libgrapheme 7 ) 28 | in the $(if [ "$ENCODING" = "utf8" ]; then printf "UTF-8-encoded string"; else printf "codepoint array"; fi) 29 | .Va str 30 | of length 31 | .Va len .$(if [ "$TYPE" != "line" ]; then printf "\nIf a ${REALTYPE} begins at 32 | .Va str 33 | this offset is equal to the length of said ${REALTYPE}."; fi) 34 | .Pp 35 | If 36 | .Va len 37 | is set to 38 | .Dv SIZE_MAX 39 | (stdint.h is already included by grapheme.h) the string 40 | .Va str 41 | is interpreted to be NUL-terminated and processing stops when 42 | a $(if [ "$ENCODING" = "utf8" ]; then printf "NUL-byte"; else printf "codepoint with the value 0"; fi) is encountered. 43 | .Pp 44 | For $(if [ "$ENCODING" != "utf8" ]; then printf "UTF-8-encoded"; else printf "non-UTF-8"; fi) input 45 | data$(if [ "$TYPE" = "character" ] && [ "$ENCODING" = "utf8" ]; then printf "\n.Xr grapheme_is_character_break 3 and"; fi) 46 | .Xr grapheme_next_${TYPE}_break${ANTISUFFIX} 3 47 | can be used instead. 48 | .Sh RETURN VALUES 49 | The 50 | .Fn grapheme_next_${TYPE}_break${SUFFIX} 51 | function returns the offset (in ${UNIT}s) to the next ${REALTYPE} 52 | break in 53 | .Va str 54 | or 0 if 55 | .Va str 56 | is 57 | .Dv NULL . 58 | EOF 59 | 60 | if [ "$ENCODING" = "utf8" ]; then 61 | cat << EOF 62 | .Sh EXAMPLES 63 | .Bd -literal 64 | /* cc (-static) -o example example.c -lgrapheme */ 65 | #include 66 | #include 67 | #include 68 | 69 | int 70 | main(void) 71 | { 72 | /* UTF-8 encoded input */ 73 | char *s = "T\\\\xC3\\\\xABst \\\\xF0\\\\x9F\\\\x91\\\\xA8\\\\xE2\\\\x80\\\\x8D\\\\xF0" 74 | "\\\\x9F\\\\x91\\\\xA9\\\\xE2\\\\x80\\\\x8D\\\\xF0\\\\x9F\\\\x91\\\\xA6 \\\\xF0" 75 | "\\\\x9F\\\\x87\\\\xBA\\\\xF0\\\\x9F\\\\x87\\\\xB8 \\\\xE0\\\\xA4\\\\xA8\\\\xE0" 76 | "\\\\xA5\\\\x80 \\\\xE0\\\\xAE\\\\xA8\\\\xE0\\\\xAE\\\\xBF!"; 77 | size_t ret, len, off; 78 | 79 | printf("Input: \\\\"%s\\\\"\\\\n", s); 80 | 81 | /* print each ${REALTYPE} with byte-length */ 82 | printf("${REALTYPE}s in NUL-delimited input:\\\\n"); 83 | for (off = 0; s[off] != '\\\\0'; off += ret) { 84 | ret = grapheme_next_${TYPE}_break_utf8(s + off, SIZE_MAX); 85 | printf("%2zu bytes | %.*s\\\\n", ret, (int)ret, s + off); 86 | } 87 | printf("\\\\n"); 88 | 89 | /* do the same, but this time string is length-delimited */ 90 | len = 17; 91 | printf("${REALTYPE}s in input delimited to %zu bytes:\\\\n", len); 92 | for (off = 0; off < len; off += ret) { 93 | ret = grapheme_next_${TYPE}_break_utf8(s + off, len - off); 94 | printf("%2zu bytes | %.*s\\\\n", ret, (int)ret, s + off); 95 | } 96 | 97 | return 0; 98 | } 99 | .Ed 100 | EOF 101 | fi 102 | 103 | cat << EOF 104 | .Sh SEE ALSO$(if [ "$TYPE" = "character" ] && [ "$ENCODING" != "utf8" ]; then printf "\n.Xr grapheme_is_character_break 3 ,"; fi) 105 | .Xr grapheme_next_${TYPE}_break${ANTISUFFIX} 3 , 106 | .Xr libgrapheme 7 107 | .Sh STANDARDS 108 | .Fn grapheme_next_${TYPE}_break${SUFFIX} 109 | is compliant with the Unicode ${UNICODE_VERSION} specification. 110 | .Sh AUTHORS 111 | .An Laslo Hunhold Aq Mt dev@frign.de 112 | EOF 113 | -------------------------------------------------------------------------------- /libgrapheme/man/template/to_case.sh: -------------------------------------------------------------------------------- 1 | if [ "$ENCODING" = "utf8" ]; then 2 | UNIT="byte" 3 | ARRAYTYPE="UTF-8-encoded string" 4 | SUFFIX="_utf8" 5 | ANTISUFFIX="" 6 | DATATYPE="char" 7 | else 8 | UNIT="codepoint" 9 | ARRAYTYPE="codepoint array" 10 | SUFFIX="" 11 | ANTISUFFIX="_utf8" 12 | DATATYPE="uint_least32_t" 13 | fi 14 | 15 | cat << EOF 16 | .Dd ${MAN_DATE} 17 | .Dt GRAPHEME_TO_$(printf "%s%s" "$CASE" "$SUFFIX" | tr [:lower:] [:upper:]) 3 18 | .Os suckless.org 19 | .Sh NAME 20 | .Nm grapheme_to_${CASE}${SUFFIX} 21 | .Nd convert ${ARRAYTYPE} to ${CASE} 22 | .Sh SYNOPSIS 23 | .In grapheme.h 24 | .Ft size_t 25 | .Fn grapheme_to_${CASE}${SUFFIX} "const ${DATATYPE} *src" "size_t srclen" "${DATATYPE} *dest" "size_t destlen" 26 | .Sh DESCRIPTION 27 | The 28 | .Fn grapheme_to_${CASE}${SUFFIX} 29 | function converts the ${ARRAYTYPE} 30 | .Va str 31 | to ${CASE} and writes the result to 32 | .Va dest 33 | up to 34 | .Va destlen , 35 | unless 36 | .Va dest 37 | is set to 38 | .Dv NULL . 39 | .Pp 40 | If 41 | .Va srclen 42 | is set to 43 | .Dv SIZE_MAX 44 | (stdint.h is already included by grapheme.h) the ${ARRAYTYPE} 45 | .Va src 46 | is interpreted to be NUL-terminated and processing stops when a 47 | NUL-byte is encountered. 48 | .Pp 49 | For $(if [ "$ENCODING" != "utf8" ]; then printf "UTF-8-encoded"; else printf "non-UTF-8"; fi) input data 50 | .Xr grapheme_to_${CASE}${ANTISUFFIX} 3 51 | can be used instead. 52 | .Sh RETURN VALUES 53 | The 54 | .Fn grapheme_to_${CASE}${SUFFIX} 55 | function returns the number of ${UNIT}s in the array resulting 56 | from converting 57 | .Va src 58 | to ${CASE}, even if 59 | .Va destlen 60 | is not large enough or 61 | .Va dest 62 | is 63 | .Dv NULL . 64 | .Sh SEE ALSO 65 | .Xr grapheme_to_${CASE}${ANTISUFFIX} 3 , 66 | .Xr libgrapheme 7 67 | .Sh STANDARDS 68 | .Fn grapheme_to_${CASE}${SUFFIX} 69 | is compliant with the Unicode ${UNICODE_VERSION} specification. 70 | .Sh AUTHORS 71 | .An Laslo Hunhold Aq Mt dev@frign.de 72 | EOF 73 | -------------------------------------------------------------------------------- /libgrapheme/test/character.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include "../gen/character-test.h" 6 | #include "../grapheme.h" 7 | #include "util.h" 8 | 9 | static const struct unit_test_next_break next_character_break[] = { 10 | { 11 | .description = "NULL input", 12 | .input = { 13 | .src = NULL, 14 | .srclen = 0, 15 | }, 16 | .output = { 0 }, 17 | }, 18 | { 19 | .description = "empty input", 20 | .input = { 21 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 22 | .srclen = 0, 23 | }, 24 | .output = { 0 }, 25 | }, 26 | { 27 | .description = "empty input, null-terminated", 28 | .input = { 29 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 30 | .srclen = SIZE_MAX, 31 | }, 32 | .output = { 0 }, 33 | }, 34 | { 35 | .description = "one character", 36 | .input = { 37 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x2A }, 38 | .srclen = 3, 39 | }, 40 | .output = { 2 }, 41 | }, 42 | { 43 | .description = "one character, null-terminated", 44 | .input = { 45 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x0 }, 46 | .srclen = SIZE_MAX, 47 | }, 48 | .output = { 2 }, 49 | }, 50 | }; 51 | 52 | static const struct unit_test_next_break_utf8 next_character_break_utf8[] = { 53 | { 54 | .description = "NULL input", 55 | .input = { 56 | .src = NULL, 57 | .srclen = 0, 58 | }, 59 | .output = { 0 }, 60 | }, 61 | { 62 | .description = "empty input", 63 | .input = { "", 0 }, 64 | .output = { 0 }, 65 | }, 66 | { 67 | .description = "empty input, NUL-terminated", 68 | .input = { "", SIZE_MAX }, 69 | .output = { 0 }, 70 | }, 71 | { 72 | .description = "one character", 73 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA*", 9 }, 74 | .output = { 8 }, 75 | }, 76 | { 77 | .description = "one character, fragment", 78 | .input = { "\xF0\x9F\x87\xA9\xF0", 5 }, 79 | .output = { 4 }, 80 | }, 81 | { 82 | .description = "one character, NUL-terminated", 83 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA", SIZE_MAX }, 84 | .output = { 8 }, 85 | }, 86 | { 87 | .description = "one character, fragment, NUL-terminated", 88 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F", SIZE_MAX }, 89 | .output = { 4 }, 90 | }, 91 | }; 92 | 93 | static int 94 | unit_test_callback_next_character_break(const void *t, size_t off, 95 | const char *name, 96 | const char *argv0) 97 | { 98 | return unit_test_callback_next_break(t, off, 99 | grapheme_next_character_break, 100 | name, argv0); 101 | } 102 | 103 | static int 104 | unit_test_callback_next_character_break_utf8(const void *t, size_t off, 105 | const char *name, 106 | const char *argv0) 107 | { 108 | return unit_test_callback_next_break_utf8(t, off, 109 | grapheme_next_character_break_utf8, 110 | name, argv0); 111 | } 112 | 113 | int 114 | main(int argc, char *argv[]) 115 | { 116 | (void)argc; 117 | 118 | return run_break_tests(grapheme_next_character_break, 119 | character_break_test, LEN(character_break_test), argv[0]) + 120 | run_unit_tests(unit_test_callback_next_character_break, 121 | next_character_break, LEN(next_character_break), 122 | "grapheme_next_character_break", argv[0]) + 123 | run_unit_tests(unit_test_callback_next_character_break_utf8, 124 | next_character_break_utf8, LEN(next_character_break_utf8), 125 | "grapheme_next_character_break_utf8", argv[0]); 126 | } 127 | -------------------------------------------------------------------------------- /libgrapheme/test/line.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include "../gen/line-test.h" 6 | #include "../grapheme.h" 7 | #include "util.h" 8 | 9 | static const struct unit_test_next_break next_line_break[] = { 10 | { 11 | .description = "NULL input", 12 | .input = { 13 | .src = NULL, 14 | .srclen = 0, 15 | }, 16 | .output = { 0 }, 17 | }, 18 | { 19 | .description = "empty input", 20 | .input = { 21 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 22 | .srclen = 0, 23 | }, 24 | .output = { 0 }, 25 | }, 26 | { 27 | .description = "empty input, null-terminated", 28 | .input = { 29 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 30 | .srclen = SIZE_MAX, 31 | }, 32 | .output = { 0 }, 33 | }, 34 | { 35 | .description = "one opportunity", 36 | .input = { 37 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x20, 0x2A }, 38 | .srclen = 4, 39 | }, 40 | .output = { 3 }, 41 | }, 42 | { 43 | .description = "one opportunity, null-terminated", 44 | .input = { 45 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x20, 0x2A, 0x0 }, 46 | .srclen = SIZE_MAX, 47 | }, 48 | .output = { 3 }, 49 | }, 50 | }; 51 | 52 | static const struct unit_test_next_break_utf8 next_line_break_utf8[] = { 53 | { 54 | .description = "NULL input", 55 | .input = { 56 | .src = NULL, 57 | .srclen = 0, 58 | }, 59 | .output = { 0 }, 60 | }, 61 | { 62 | .description = "empty input", 63 | .input = { "", 0 }, 64 | .output = { 0 }, 65 | }, 66 | { 67 | .description = "empty input, NUL-terminated", 68 | .input = { "", SIZE_MAX }, 69 | .output = { 0 }, 70 | }, 71 | { 72 | .description = "one opportunity", 73 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA *", 10 }, 74 | .output = { 9 }, 75 | }, 76 | { 77 | .description = "one opportunity, fragment", 78 | .input = { "\xF0\x9F\x87\xA9\xF0", 5 }, 79 | .output = { 4 }, 80 | }, 81 | { 82 | .description = "one opportunity, NUL-terminated", 83 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA A", SIZE_MAX }, 84 | .output = { 9 }, 85 | }, 86 | { 87 | .description = "one opportunity, fragment, NUL-terminated", 88 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F", SIZE_MAX }, 89 | .output = { 4 }, 90 | }, 91 | }; 92 | 93 | static int 94 | unit_test_callback_next_line_break(const void *t, size_t off, 95 | const char *name, 96 | const char *argv0) 97 | { 98 | return unit_test_callback_next_break(t, off, 99 | grapheme_next_line_break, 100 | name, argv0); 101 | } 102 | 103 | static int 104 | unit_test_callback_next_line_break_utf8(const void *t, size_t off, 105 | const char *name, 106 | const char *argv0) 107 | { 108 | return unit_test_callback_next_break_utf8(t, off, 109 | grapheme_next_line_break_utf8, 110 | name, argv0); 111 | } 112 | 113 | int 114 | main(int argc, char *argv[]) 115 | { 116 | (void)argc; 117 | 118 | return run_break_tests(grapheme_next_line_break, 119 | line_break_test, LEN(line_break_test), 120 | argv[0]) + 121 | run_unit_tests(unit_test_callback_next_line_break, 122 | next_line_break, LEN(next_line_break), 123 | "grapheme_next_line_break", argv[0]) + 124 | run_unit_tests(unit_test_callback_next_line_break_utf8, 125 | next_line_break_utf8, LEN(next_line_break_utf8), 126 | "grapheme_next_line_break_utf8", argv[0]); 127 | } 128 | -------------------------------------------------------------------------------- /libgrapheme/test/sentence.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include "../gen/sentence-test.h" 6 | #include "../grapheme.h" 7 | #include "util.h" 8 | 9 | static const struct unit_test_next_break next_sentence_break[] = { 10 | { 11 | .description = "NULL input", 12 | .input = { 13 | .src = NULL, 14 | .srclen = 0, 15 | }, 16 | .output = { 0 }, 17 | }, 18 | { 19 | .description = "empty input", 20 | .input = { 21 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 22 | .srclen = 0, 23 | }, 24 | .output = { 0 }, 25 | }, 26 | { 27 | .description = "empty input, null-terminated", 28 | .input = { 29 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 30 | .srclen = SIZE_MAX, 31 | }, 32 | .output = { 0 }, 33 | }, 34 | { 35 | .description = "one sentence", 36 | .input = { 37 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x2E, 0x20, 0x2A }, 38 | .srclen = 5, 39 | }, 40 | .output = { 4 }, 41 | }, 42 | { 43 | .description = "one sentence, null-terminated", 44 | .input = { 45 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x2E, 0x20, 0x2A, 0x0 }, 46 | .srclen = SIZE_MAX, 47 | }, 48 | .output = { 4 }, 49 | }, 50 | }; 51 | 52 | static const struct unit_test_next_break_utf8 next_sentence_break_utf8[] = { 53 | { 54 | .description = "NULL input", 55 | .input = { 56 | .src = NULL, 57 | .srclen = 0, 58 | }, 59 | .output = { 0 }, 60 | }, 61 | { 62 | .description = "empty input", 63 | .input = { "", 0 }, 64 | .output = { 0 }, 65 | }, 66 | { 67 | .description = "empty input, NUL-terminated", 68 | .input = { "", SIZE_MAX }, 69 | .output = { 0 }, 70 | }, 71 | { 72 | .description = "one sentence", 73 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA is the flag of Germany. It", 36 }, 74 | .output = { 34 }, 75 | }, 76 | { 77 | .description = "one sentence, fragment", 78 | .input = { "\xF0\x9F\x87\xA9\xF0", 5 }, 79 | .output = { 4 }, 80 | }, 81 | { 82 | .description = "one sentence, NUL-terminated", 83 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA is the flag of Germany. It", SIZE_MAX }, 84 | .output = { 34 }, 85 | }, 86 | { 87 | .description = "one sentence, fragment, NUL-terminated", 88 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F", SIZE_MAX }, 89 | .output = { 6 }, 90 | }, 91 | }; 92 | 93 | static int 94 | unit_test_callback_next_sentence_break(const void *t, size_t off, 95 | const char *name, 96 | const char *argv0) 97 | { 98 | return unit_test_callback_next_break(t, off, 99 | grapheme_next_sentence_break, 100 | name, argv0); 101 | } 102 | 103 | static int 104 | unit_test_callback_next_sentence_break_utf8(const void *t, size_t off, 105 | const char *name, 106 | const char *argv0) 107 | { 108 | return unit_test_callback_next_break_utf8(t, off, 109 | grapheme_next_sentence_break_utf8, 110 | name, argv0); 111 | } 112 | 113 | int 114 | main(int argc, char *argv[]) 115 | { 116 | (void)argc; 117 | 118 | return run_break_tests(grapheme_next_sentence_break, 119 | sentence_break_test, 120 | LEN(sentence_break_test), argv[0]) + 121 | run_unit_tests(unit_test_callback_next_sentence_break, 122 | next_sentence_break, LEN(next_sentence_break), 123 | "grapheme_next_sentence_break", argv[0]) + 124 | run_unit_tests(unit_test_callback_next_sentence_break_utf8, 125 | next_sentence_break_utf8, LEN(next_sentence_break_utf8), 126 | "grapheme_next_character_break_utf8", argv[0]); 127 | } 128 | -------------------------------------------------------------------------------- /libgrapheme/test/utf8-encode.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../grapheme.h" 8 | #include "util.h" 9 | 10 | static const struct { 11 | uint_least32_t cp; /* input codepoint */ 12 | char *exp_arr; /* expected UTF-8 byte sequence */ 13 | size_t exp_len; /* expected length of UTF-8 sequence */ 14 | } enc_test[] = { 15 | { 16 | /* invalid codepoint (UTF-16 surrogate half) */ 17 | .cp = UINT32_C(0xD800), 18 | .exp_arr = (char *)(unsigned char[]){ 0xEF, 0xBF, 0xBD }, 19 | .exp_len = 3, 20 | }, 21 | { 22 | /* invalid codepoint (UTF-16-unrepresentable) */ 23 | .cp = UINT32_C(0x110000), 24 | .exp_arr = (char *)(unsigned char[]){ 0xEF, 0xBF, 0xBD }, 25 | .exp_len = 3, 26 | }, 27 | { 28 | /* codepoint encoded to a 1-byte sequence */ 29 | .cp = 0x01, 30 | .exp_arr = (char *)(unsigned char[]){ 0x01 }, 31 | .exp_len = 1, 32 | }, 33 | { 34 | /* codepoint encoded to a 2-byte sequence */ 35 | .cp = 0xFF, 36 | .exp_arr = (char *)(unsigned char[]){ 0xC3, 0xBF }, 37 | .exp_len = 2, 38 | }, 39 | { 40 | /* codepoint encoded to a 3-byte sequence */ 41 | .cp = 0xFFF, 42 | .exp_arr = (char *)(unsigned char[]){ 0xE0, 0xBF, 0xBF }, 43 | .exp_len = 3, 44 | }, 45 | { 46 | /* codepoint encoded to a 4-byte sequence */ 47 | .cp = UINT32_C(0xFFFFF), 48 | .exp_arr = (char *)(unsigned char[]){ 0xF3, 0xBF, 0xBF, 0xBF }, 49 | .exp_len = 4, 50 | }, 51 | }; 52 | 53 | int 54 | main(int argc, char *argv[]) 55 | { 56 | size_t i, j, failed; 57 | 58 | (void)argc; 59 | 60 | /* UTF-8 encoder test */ 61 | for (i = 0, failed = 0; i < LEN(enc_test); i++) { 62 | char arr[4]; 63 | size_t len; 64 | 65 | len = grapheme_encode_utf8(enc_test[i].cp, arr, LEN(arr)); 66 | 67 | if (len != enc_test[i].exp_len || 68 | memcmp(arr, enc_test[i].exp_arr, len)) { 69 | fprintf(stderr, "%s, Failed test %zu: " 70 | "Expected (", argv[0], i); 71 | for (j = 0; j < enc_test[i].exp_len; j++) { 72 | fprintf(stderr, "0x%x", 73 | enc_test[i].exp_arr[j]); 74 | if (j + 1 < enc_test[i].exp_len) { 75 | fprintf(stderr, " "); 76 | } 77 | } 78 | fprintf(stderr, "), but got ("); 79 | for (j = 0; j < len; j++) { 80 | fprintf(stderr, "0x%x", arr[j]); 81 | if (j + 1 < len) { 82 | fprintf(stderr, " "); 83 | } 84 | } 85 | fprintf(stderr, ").\n"); 86 | failed++; 87 | } 88 | } 89 | printf("%s: %zu/%zu unit tests passed.\n", argv[0], 90 | LEN(enc_test) - failed, LEN(enc_test)); 91 | 92 | return (failed > 0) ? 1 : 0; 93 | } 94 | -------------------------------------------------------------------------------- /libgrapheme/test/util.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../grapheme.h" 9 | #include "../gen/types.h" 10 | #include "util.h" 11 | 12 | int 13 | run_break_tests(size_t (*next_break)(const uint_least32_t *, size_t), 14 | const struct break_test *test, size_t testlen, const char *argv0) 15 | { 16 | size_t i, j, off, res, failed; 17 | 18 | /* character break test */ 19 | for (i = 0, failed = 0; i < testlen; i++) { 20 | for (j = 0, off = 0; off < test[i].cplen; off += res) { 21 | res = next_break(test[i].cp + off, test[i].cplen - off); 22 | 23 | /* check if our resulting offset matches */ 24 | if (j == test[i].lenlen || 25 | res != test[i].len[j++]) { 26 | fprintf(stderr, "%s: Failed conformance test %zu \"%s\".\n", 27 | argv0, i, test[i].descr); 28 | fprintf(stderr, "J=%zu: EXPECTED len %zu, got %zu\n", j-1, test[i].len[j-1], res); 29 | failed++; 30 | break; 31 | } 32 | } 33 | } 34 | printf("%s: %zu/%zu conformance tests passed.\n", argv0, 35 | testlen - failed, testlen); 36 | 37 | return (failed > 0) ? 1 : 0; 38 | } 39 | 40 | int 41 | run_unit_tests(int (*unit_test_callback)(const void *, size_t, const char *, 42 | const char *), const void *test, size_t testlen, const char *name, 43 | const char *argv0) 44 | { 45 | size_t i, failed; 46 | 47 | for (i = 0, failed = 0; i < testlen; i++) { 48 | failed += (unit_test_callback(test, i, name, argv0) == 0) ? 0 : 1; 49 | } 50 | 51 | printf("%s: %s: %zu/%zu unit tests passed.\n", argv0, name, 52 | testlen - failed, testlen); 53 | 54 | return (failed > 0) ? 1 : 0; 55 | } 56 | 57 | int 58 | unit_test_callback_next_break(const struct unit_test_next_break *t, size_t off, 59 | size_t (*next_break)(const uint_least32_t *, size_t), 60 | const char *name, const char *argv0) 61 | { 62 | const struct unit_test_next_break *test = t + off; 63 | 64 | size_t ret = next_break(test->input.src, test->input.srclen); 65 | 66 | if (ret != test->output.ret) { 67 | goto err; 68 | } 69 | 70 | return 0; 71 | err: 72 | fprintf(stderr, "%s: %s: Failed unit test %zu \"%s\" " 73 | "(returned %zu instead of %zu).\n", argv0, 74 | name, off, test->description, ret, test->output.ret); 75 | return 1; 76 | } 77 | 78 | int 79 | unit_test_callback_next_break_utf8(const struct unit_test_next_break_utf8 *t, 80 | size_t off, 81 | size_t (*next_break_utf8)(const char *, size_t), 82 | const char *name, const char *argv0) 83 | { 84 | const struct unit_test_next_break_utf8 *test = t + off; 85 | 86 | size_t ret = next_break_utf8(test->input.src, test->input.srclen); 87 | 88 | if (ret != test->output.ret) { 89 | goto err; 90 | } 91 | 92 | return 0; 93 | err: 94 | fprintf(stderr, "%s: %s: Failed unit test %zu \"%s\" " 95 | "(returned %zu instead of %zu).\n", argv0, 96 | name, off, test->description, ret, test->output.ret); 97 | return 1; 98 | } 99 | -------------------------------------------------------------------------------- /libgrapheme/test/util.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #ifndef UTIL_H 3 | #define UTIL_H 4 | 5 | #include "../gen/types.h" 6 | #include "../grapheme.h" 7 | 8 | #undef MIN 9 | #define MIN(x,y) ((x) < (y) ? (x) : (y)) 10 | #undef LEN 11 | #define LEN(x) (sizeof(x) / sizeof(*(x))) 12 | 13 | struct unit_test_next_break { 14 | const char *description; 15 | struct { 16 | const uint_least32_t *src; 17 | size_t srclen; 18 | } input; 19 | struct { 20 | size_t ret; 21 | } output; 22 | }; 23 | 24 | struct unit_test_next_break_utf8 { 25 | const char *description; 26 | struct { 27 | const char *src; 28 | size_t srclen; 29 | } input; 30 | struct { 31 | size_t ret; 32 | } output; 33 | }; 34 | 35 | int run_break_tests(size_t (*next_break)(const uint_least32_t *, size_t), 36 | const struct break_test *test, size_t testlen, 37 | const char *); 38 | int run_unit_tests(int (*unit_test_callback)(const void *, size_t, const char *, 39 | const char *), const void *, size_t, const char *, const char *); 40 | 41 | int unit_test_callback_next_break(const struct unit_test_next_break *, size_t, 42 | size_t (*next_break)(const uint_least32_t *, size_t), 43 | const char *, const char *); 44 | int unit_test_callback_next_break_utf8(const struct unit_test_next_break_utf8 *, 45 | size_t, 46 | size_t (*next_break_utf8)(const char *, size_t), 47 | const char *, const char *); 48 | 49 | #endif /* UTIL_H */ 50 | -------------------------------------------------------------------------------- /libgrapheme/test/word.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include "../gen/word-test.h" 6 | #include "../grapheme.h" 7 | #include "util.h" 8 | 9 | static const struct unit_test_next_break next_word_break[] = { 10 | { 11 | .description = "NULL input", 12 | .input = { 13 | .src = NULL, 14 | .srclen = 0, 15 | }, 16 | .output = { 0 }, 17 | }, 18 | { 19 | .description = "empty input", 20 | .input = { 21 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 22 | .srclen = 0, 23 | }, 24 | .output = { 0 }, 25 | }, 26 | { 27 | .description = "empty input, null-terminated", 28 | .input = { 29 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x0 }, 30 | .srclen = SIZE_MAX, 31 | }, 32 | .output = { 0 }, 33 | }, 34 | { 35 | .description = "one word", 36 | .input = { 37 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x20, 0x2A }, 38 | .srclen = 4, 39 | }, 40 | .output = { 2 }, 41 | }, 42 | { 43 | .description = "one word, null-terminated", 44 | .input = { 45 | .src = (uint_least32_t *)(uint_least32_t[]){ 0x1F1E9, 0x1F1EA, 0x20, 0x2A, 0x0 }, 46 | .srclen = SIZE_MAX, 47 | }, 48 | .output = { 2 }, 49 | }, 50 | }; 51 | 52 | static const struct unit_test_next_break_utf8 next_word_break_utf8[] = { 53 | { 54 | .description = "NULL input", 55 | .input = { 56 | .src = NULL, 57 | .srclen = 0, 58 | }, 59 | .output = { 0 }, 60 | }, 61 | { 62 | .description = "empty input", 63 | .input = { "", 0 }, 64 | .output = { 0 }, 65 | }, 66 | { 67 | .description = "empty input, NUL-terminated", 68 | .input = { "", SIZE_MAX }, 69 | .output = { 0 }, 70 | }, 71 | { 72 | .description = "one word", 73 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA is", 11 }, 74 | .output = { 8 }, 75 | }, 76 | { 77 | .description = "one word, fragment", 78 | .input = { "\xF0\x9F\x87\xA9\xF0", 5 }, 79 | .output = { 4 }, 80 | }, 81 | { 82 | .description = "one word, NUL-terminated", 83 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA is", SIZE_MAX }, 84 | .output = { 8 }, 85 | }, 86 | { 87 | .description = "one word, fragment, NUL-terminated", 88 | .input = { "\xF0\x9F\x87\xA9\xF0\x9F", SIZE_MAX }, 89 | .output = { 4 }, 90 | }, 91 | }; 92 | 93 | static int 94 | unit_test_callback_next_word_break(const void *t, size_t off, 95 | const char *name, 96 | const char *argv0) 97 | { 98 | return unit_test_callback_next_break(t, off, 99 | grapheme_next_word_break, 100 | name, argv0); 101 | } 102 | 103 | static int 104 | unit_test_callback_next_word_break_utf8(const void *t, size_t off, 105 | const char *name, 106 | const char *argv0) 107 | { 108 | return unit_test_callback_next_break_utf8(t, off, 109 | grapheme_next_word_break_utf8, 110 | name, argv0); 111 | } 112 | 113 | int 114 | main(int argc, char *argv[]) 115 | { 116 | (void)argc; 117 | 118 | return run_break_tests(grapheme_next_word_break, word_break_test, 119 | LEN(word_break_test), argv[0]) + 120 | run_unit_tests(unit_test_callback_next_word_break, 121 | next_word_break, LEN(next_word_break), 122 | "grapheme_next_word_break", argv[0]) + 123 | run_unit_tests(unit_test_callback_next_word_break_utf8, 124 | next_word_break_utf8, LEN(next_word_break_utf8), 125 | "grapheme_next_word_break_utf8", argv[0]); 126 | } 127 | -------------------------------------------------------------------------------- /mailcap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Thomas Adam 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef MAILCAP_H 18 | #define MAILCAP_H 19 | 20 | struct mailcap { 21 | char *mime_type; 22 | char *cmd; 23 | char **cmd_argv; 24 | int cmd_argc; 25 | 26 | #define MAILCAP_NEEDSTERMINAL 0x1 27 | #define MAILCAP_COPIOUSOUTPUT 0x2 28 | int flags; 29 | 30 | TAILQ_ENTRY(mailcap) mailcaps; 31 | }; 32 | 33 | extern TAILQ_HEAD(mailcaplist, mailcap) mailcaps; 34 | 35 | extern struct mailcaplist mailcaps; 36 | 37 | void init_mailcap(void); 38 | void mailcap_parse(FILE *); 39 | struct mailcap *mailcap_cmd_from_mimetype(char *, char *); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /maintenance/README.md: -------------------------------------------------------------------------------- 1 | # Maintaining telescope 2 | 3 | ## Making releases 4 | 5 | To create a "chain of trust" for signify keys, we when doing the 6 | release N we also generate the keys for N+1 and include the public key 7 | in the repo, under the `keys/` directory. 8 | 9 | Tags should be signed with a known ssh key. We don't usually use GPG 10 | nor sign every commit, as it makes little sense. 11 | 12 | Before making a release it's better to double-check that everything is 13 | in order. The ChangeLog file should be up-to-date and used as a base 14 | to create the release notes. Release notes should be useful both for 15 | the end users and for packagers: breaking changes, new or changed 16 | dependencies, bug fixes and new features needs to be clearly stated. 17 | 18 | It goes without sayng that before making a release all known bugs must 19 | be fixed. 20 | 21 | Every release so far was named after an Italian song. It started by 22 | trying to keep the "space" theme, but then I (op) started to just use 23 | a song I was listening to many times in the release period. There may 24 | or may not be any meaning behind the chosen song. The "limitation" 25 | that songs are from italian groups is not meant to exclude the rest of 26 | the world, it's just an arbitrary choice done by me (op). Other 27 | projects that I maintain (gmid) use song as a release name, so I just 28 | wanted to differentiate a bit (and maybe advertise some Italian indie 29 | music.) 30 | 31 | Minor releases (e.g. 0.10.1) are reserved for bug fixes and inherit the 32 | name of the previous release (e.g. 0.10). 33 | 34 | When everything is in place, remove `-current` from `configure.ac` and 35 | bump the version, then run 36 | 37 | $ make release PUBKEY=... PRIVKEY=... 38 | 39 | signify(1) will then prompt for the password to unlock the private 40 | key. It will also try to check the signed tarball against the public 41 | key, as a safety measure. 42 | 43 | Note to op: on OpenBSD I'm using an `obj` directory for the build, and 44 | `make release` needs to be run after cd'ing there. 45 | 46 | Then upload the tarballs, make the tag (and sign it!), add `-current` 47 | to the version in `configure.ac`, make the release on Codeberg and 48 | GitHub, and remember to upload the generated tarballs there as well. 49 | 50 | Finally, update and publish the website too. 51 | -------------------------------------------------------------------------------- /mcache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef MCACHE_H 18 | #define MCACHE_H 19 | 20 | struct tab; 21 | 22 | void mcache_init(void); 23 | int mcache_tab(struct tab *); 24 | int mcache_lookup(const char *, struct tab *); 25 | void mcache_info(size_t *, size_t *); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /mime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "parser.h" 24 | #include "telescope.h" 25 | #include "utils.h" 26 | 27 | static int check_for_utf8(char*); 28 | 29 | static const struct parser_table { 30 | const char *mediatype; 31 | const struct parser *parser; 32 | } ptable[] = { 33 | { "text/gemini", &gemtext_parser }, 34 | { "text/x-patch", &textpatch_parser }, 35 | { "text/x-diff", &textpatch_parser }, 36 | { "application/x-patch",&textpatch_parser }, 37 | { "text/*", &textplain_parser }, 38 | { NULL, NULL} 39 | }; 40 | 41 | static int 42 | check_for_utf8(char *b) 43 | { 44 | for (;;) { 45 | while (*b != '\0' && isspace(*b)) 46 | b++; 47 | if (*b == '\0') 48 | break; 49 | if (strncmp(b, "charset=", 8) != 0) { 50 | while (*b != '\0' && *b != ';') 51 | b++; 52 | if (*b == '\0') 53 | break; 54 | b++; 55 | continue; 56 | } 57 | 58 | /* is charset= */ 59 | b += strlen("charset="); 60 | /* TODO: improve the matching */ 61 | return !strncmp(b, "ASCII", 5) || !strncmp(b, "ascii", 5) || 62 | !strncmp(b, "UTF-8", 5) || !strncmp(b, "utf-8", 5); 63 | } 64 | 65 | return 1; 66 | } 67 | 68 | int 69 | setup_parser_for(struct tab *tab) 70 | { 71 | char *b, buf[GEMINI_URL_LEN] = {0}; 72 | const struct parser_table *t; 73 | 74 | memcpy(buf, tab->meta, sizeof(tab->meta)); 75 | 76 | for (b = buf; *b != ';' && *b != '\0'; ++b) 77 | ; 78 | 79 | if (*b == ';') { 80 | *b = '\0'; 81 | ++b; 82 | } 83 | 84 | if (!check_for_utf8(b)) 85 | return 0; 86 | 87 | for (t = ptable; t->mediatype != NULL; ++t) { 88 | if (!fnmatch(t->mediatype, buf, 0)) { 89 | parser_init(&tab->buffer, t->parser); 90 | return 1; 91 | } 92 | } 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /pagebundler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2022 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * pagebundler converts the given file into a valid C program that can 19 | * be compiled. The generated code provides a variable that holds the 20 | * content of the original file and a _len variable with the size. 21 | * 22 | * Usage: pagebundler file > outfile 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | static void 35 | setfname(const char *fname, char *buf, size_t siz) 36 | { 37 | const char *c, *d; 38 | size_t len; 39 | 40 | if ((c = strrchr(fname, '/')) != NULL) 41 | c++; 42 | else 43 | c = fname; 44 | 45 | if ((d = strrchr(fname, '.')) == NULL || c > d) 46 | d = strchr(fname, '\0'); 47 | 48 | len = d - c; 49 | if (len >= siz) { 50 | fprintf(stderr, "file name too long: %s\n", fname); 51 | exit(1); 52 | } 53 | 54 | memcpy(buf, c, len); 55 | buf[len] = '\0'; 56 | } 57 | 58 | static int 59 | validc(int c) 60 | { 61 | return isprint(c) && c != '\\' && c != '\'' && c != '\n'; 62 | } 63 | 64 | int 65 | main(int argc, char **argv) 66 | { 67 | size_t r, i, n; 68 | FILE *f; 69 | uint8_t buf[BUFSIZ]; 70 | char varname[PATH_MAX]; 71 | 72 | if (argc != 2) { 73 | fprintf(stderr, "usage: %s file\n", *argv); 74 | return 1; 75 | } 76 | 77 | setfname(argv[1], varname, sizeof(varname)); 78 | 79 | if ((f = fopen(argv[1], "r")) == NULL) { 80 | fprintf(stderr, "%s: can't open %s: %s", 81 | argv[0], argv[1], strerror(errno)); 82 | return 1; 83 | } 84 | 85 | printf("const uint8_t %s[] = {", varname); 86 | 87 | n = 0; 88 | for (;;) { 89 | r = fread(buf, 1, sizeof(buf), f); 90 | 91 | for (i = 0; i < r; ++i, ++n) { 92 | if (n % 12 == 0) 93 | printf("\n\t"); 94 | else 95 | printf(" "); 96 | 97 | if (validc(buf[i])) 98 | printf("'%c',", buf[i]); 99 | else if (buf[i] == '\n') 100 | printf("'\\n',"); 101 | else 102 | printf("0x%x,", buf[i]); 103 | } 104 | printf("\n"); 105 | 106 | if (r != sizeof(buf)) 107 | break; 108 | } 109 | 110 | printf("\t0x0\n"); 111 | printf("}; /* %s */\n", varname); 112 | 113 | fclose(f); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /pages.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef PAGES_H 18 | #define PAGES_H 19 | 20 | #include 21 | #include 22 | 23 | extern const uint8_t about_about[]; 24 | extern size_t about_about_len; 25 | 26 | extern const uint8_t about_blank[]; 27 | extern size_t about_blank_len; 28 | 29 | extern const uint8_t about_crash[]; 30 | extern size_t about_crash_len; 31 | 32 | extern const uint8_t about_help[]; 33 | extern size_t about_help_len; 34 | 35 | extern const uint8_t about_license[]; 36 | extern size_t about_license_len; 37 | 38 | extern const uint8_t about_new[]; 39 | extern size_t about_new_len; 40 | 41 | extern const uint8_t bookmarks[]; 42 | extern size_t bookmarks_len; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /pages/about_about.gmi.in: -------------------------------------------------------------------------------- 1 | # About pages 2 | 3 | Telescope has a number of “special” built-in pages: 4 | 5 | => about:about 6 | => about:blank 7 | => about:bookmarks 8 | => about:crash 9 | => about:help 10 | => about:license 11 | => about:new 12 | -------------------------------------------------------------------------------- /pages/about_blank.gmi.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telescope-browser/telescope/243d6421b25f09e5b22445f2378598da6ba5b110/pages/about_blank.gmi.in -------------------------------------------------------------------------------- /pages/about_crash.gmi.in: -------------------------------------------------------------------------------- 1 | # Oops 2 | 3 | It seems that Telescope crashed last time! Please consider reporting this bug so it can be fixed. 4 | 5 | => mailto:@PACKAGE_BUGREPORT@ @PACKAGE_BUGREPORT@ 6 | 7 | When reporting a bug, please include the following information, otherwise it won’t be very helpful: 8 | 9 | * Operating system 10 | * Telescope version (i.e. @PACKAGE_STRING@) 11 | * how to reproduce the crash, if known 12 | 13 | If possible, a backtrace (the state of the program when it crashed) should be included too, as it contains invaluable data to understand the source of the bug. Obtaining a backtrace is usually simple, but the exact procedure depends on the operating system. 14 | 15 | On most system, after a crash a file named ‘telescope.core’ or ‘.core’ or just ‘core’ should appear in the directory where Telescope was launched (probably your home). 16 | 17 | The shell may have to be configured to allow coredumps. Running 18 | 19 | > $ ulimits -c unlimited 20 | 21 | should enable core dump for the current session on most shells. 22 | 23 | Once the core dump is located, a backtrace may be obtained with the aid of a debugger, like ‘gdb’ (the GNU debugger) or ‘lldb’ (the LLVM debugger): 24 | 25 | > $ gdb telescope path/to/core-file 26 | 27 | On a linux distro with systemd (Arch, Fedora, Debian, ...) ‘coredumpctl’ may be needed to launch the debugger. Please refer to the following Arch wiki page: 28 | 29 | => https://wiki.archlinux.org/title/Core_dump 30 | 31 | in particular the “Examining a core dump” section. 32 | 33 | At this point you should be at the GDB prompt. Just type ‘bt’, press enter and copy all the output in a mail to @PACKAGE_BUGREPORT@. 34 | 35 | > (gdb) bt 36 | > ...lots of useful information... 37 | > (gdb) 38 | 39 | To quit gdb, just type ‘q’ and enter. 40 | 41 | Thank you! 42 | -------------------------------------------------------------------------------- /pages/about_new.gmi.in: -------------------------------------------------------------------------------- 1 | ```Ascii art of the word “Telescope” 2 | _______ __ 3 | |_ _|.-----.| |.-----.-----.----.-----.-----.-----. 4 | | | | -__|| || -__|__ --| __| _ | _ | -__| 5 | |___| |_____||__||_____|_____|____|_____| __|_____| 6 | |__| 7 | ``` 8 | 9 | => gemini://kennedy.gemi.dev/search Gemini Search Engine 10 | => gopher://gopher.floodgap.com/7/v2/vs Gopher Search Engine (Veronica-2) 11 | 12 | => gemini://geminiprotocol.net/ Project Gemini home page 13 | => gopher://gopher.floodgap.com/1/ Floodgap Systems Gopher Server 14 | 15 | => @PACKAGE_URL@ Telescope project page 16 | => about:help Help 17 | => about:about Internal pages 18 | 19 | -- 20 | Version: @VERSION@ 21 | Bug reports to: @PACKAGE_BUGREPORT@ 22 | -------------------------------------------------------------------------------- /pages/bookmarks.gmi.in: -------------------------------------------------------------------------------- 1 | # Bookmarks 2 | 3 | No bookmarks yet! 4 | 5 | Create ~/.local/share/telescope/bookmarks.gmi or use ‘bookmark-page’. 6 | -------------------------------------------------------------------------------- /parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef PARSER_H 18 | #define PARSER_H 19 | 20 | struct buffer; 21 | struct tab; 22 | 23 | struct parser { 24 | const char *name; 25 | int initflags; 26 | 27 | int (*parse)(struct buffer *, const char *, size_t); 28 | int (*parseline)(struct buffer *, const char *, size_t); 29 | int (*free)(struct buffer *); 30 | int (*serialize)(struct buffer *, FILE *); 31 | }; 32 | 33 | void parser_init(struct buffer *, const struct parser *); 34 | int parser_parse(struct buffer *, const char *, size_t); 35 | int parser_parsef(struct buffer *, const char *, ...); 36 | int parser_free(struct tab *); 37 | int parser_serialize(struct buffer *, FILE *); 38 | 39 | extern const struct parser gemtext_parser; 40 | extern const struct parser gophermap_parser; 41 | extern const struct parser textpatch_parser; 42 | extern const struct parser textplain_parser; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /parser_textpatch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * A streaming text/x-patch parser 19 | */ 20 | 21 | #include "compat.h" 22 | 23 | #include 24 | #include 25 | 26 | #include "parser.h" 27 | #include "telescope.h" 28 | #include "utils.h" 29 | #include "xwrapper.h" 30 | 31 | static int tpatch_emit_line(struct buffer *, const char *, size_t); 32 | static int tpatch_parse_line(struct buffer *, const char *, size_t); 33 | 34 | const struct parser textpatch_parser = { 35 | .name = "text/x-patch", 36 | .parseline = &tpatch_parse_line, 37 | .initflags = PARSER_IN_PATCH_HDR, 38 | }; 39 | 40 | static int 41 | tpatch_emit_line(struct buffer *b, const char *line, size_t linelen) 42 | { 43 | struct line *l; 44 | 45 | l = xcalloc(1, sizeof(*l)); 46 | 47 | if (b->parser_flags & PARSER_IN_PATCH_HDR) 48 | l->type = LINE_PATCH_HDR; 49 | else 50 | l->type = LINE_PATCH; 51 | 52 | if (linelen != 0) { 53 | l->line = xcalloc(1, linelen + 1); 54 | 55 | memcpy(l->line, line, linelen); 56 | 57 | if (!(b->parser_flags & PARSER_IN_PATCH_HDR)) 58 | switch (*l->line) { 59 | case '+': 60 | l->type = LINE_PATCH_ADD; 61 | break; 62 | case '-': 63 | l->type = LINE_PATCH_DEL; 64 | break; 65 | case '@': 66 | l->type = LINE_PATCH_HUNK_HDR; 67 | break; 68 | case ' ': 69 | /* context lines */ 70 | break; 71 | default: 72 | /* 73 | * A single patch file can have more 74 | * than one "header" if touches more 75 | * than one file. 76 | */ 77 | l->type = LINE_PATCH_HDR; 78 | b->parser_flags |= PARSER_IN_PATCH_HDR; 79 | break; 80 | } 81 | 82 | if (!strncmp(l->line, "+++", 3)) 83 | b->parser_flags &= ~PARSER_IN_PATCH_HDR; 84 | } 85 | 86 | TAILQ_INSERT_TAIL(&b->head, l, lines); 87 | 88 | return 1; 89 | } 90 | 91 | static int 92 | tpatch_parse_line(struct buffer *b, const char *line, size_t linelen) 93 | { 94 | return tpatch_emit_line(b, line, linelen); 95 | } 96 | -------------------------------------------------------------------------------- /parser_textplain.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * A streaming text/plain "parser." 19 | */ 20 | 21 | #include "compat.h" 22 | 23 | #include 24 | #include 25 | 26 | #include "parser.h" 27 | #include "telescope.h" 28 | #include "xwrapper.h" 29 | 30 | static int textplain_parse_line(struct buffer *, const char *, size_t); 31 | 32 | const struct parser textplain_parser = { 33 | .name = "text/plain", 34 | .parseline = &textplain_parse_line, 35 | }; 36 | 37 | static inline int 38 | emit_line(struct buffer *b, const char *line, size_t len) 39 | { 40 | struct line *l; 41 | 42 | l = xcalloc(1, sizeof(*l)); 43 | 44 | l->type = LINE_TEXT; 45 | 46 | if (len != 0) { 47 | l->line = xcalloc(1, len + 1); 48 | 49 | memcpy(l->line, line, len); 50 | } 51 | 52 | TAILQ_INSERT_TAIL(&b->head, l, lines); 53 | 54 | return 1; 55 | } 56 | 57 | static int 58 | textplain_parse_line(struct buffer *b, const char *line, size_t linelen) 59 | { 60 | return emit_line(b, line, linelen); 61 | } 62 | -------------------------------------------------------------------------------- /session.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef SESSION_H 18 | #define SESSION_H 19 | 20 | struct ohash; 21 | 22 | struct session_tab { 23 | uint32_t flags; 24 | char uri[GEMINI_URL_LEN]; 25 | char title[TITLE_MAX]; 26 | size_t top_line; 27 | size_t current_line; 28 | }; 29 | 30 | struct session_tab_hist { 31 | char uri[GEMINI_URL_LEN]; 32 | int future; 33 | }; 34 | 35 | struct histitem { 36 | time_t ts; 37 | char uri[GEMINI_URL_LEN]; 38 | }; 39 | 40 | struct history_item { 41 | time_t ts; 42 | char *uri; 43 | int dirty; 44 | }; 45 | 46 | #define HISTORY_CAP 1000 47 | struct history { 48 | struct history_item items[HISTORY_CAP]; 49 | size_t len; 50 | size_t dirty; 51 | size_t extra; 52 | }; 53 | extern struct history history; 54 | 55 | void switch_to_tab(struct tab *); 56 | unsigned int tab_new_id(void); 57 | struct tab *new_tab(const char *, const char *base, struct tab *); 58 | void kill_tab(struct tab *, int); 59 | struct tab *unkill_tab(void); 60 | void free_tab(struct tab *); 61 | void stop_tab(struct tab*); 62 | 63 | void save_session(void); 64 | 65 | void history_push(struct histitem *); 66 | void history_sort(void); 67 | void history_add(const char *); 68 | 69 | void autosave_init(void); 70 | void autosave_timer(int, int, void *); 71 | void autosave_hook(void); 72 | 73 | int load_session(struct ohash *); 74 | int lock_session(void); 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /telescope-identity.1: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 2024 Omar Polo 2 | .\" 3 | .\" Permission to use, copy, modify, and distribute this software for any 4 | .\" purpose with or without fee is hereby granted, provided that the above 5 | .\" copyright notice and this permission notice appear in all copies. 6 | .\" 7 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | .Dd $Mdocdate: February 16 2024$ 15 | .Dt TELESCOPE-IDENTITY 1 16 | .Os 17 | .Sh NAME 18 | .Nm telescope-identity 19 | .Nd manage telescope identities 20 | .Sh SYNOPSIS 21 | .Nm 22 | .Bk -words 23 | .Ar command 24 | .Ar args... 25 | .Ek 26 | .Sh DESCRIPTION 27 | .Nm 28 | is an utility to manage 29 | .Xr telescope 1 30 | identities. 31 | Identities are TLS client certificates used for Gemini. 32 | .Pp 33 | The commands for 34 | .Nm 35 | are as follows: 36 | .Bl -tag -width generate 37 | .It Xo 38 | .Cm generate 39 | .Op Fl t Ar type 40 | .Ar name 41 | .Xc 42 | Generate a new keypair under the given 43 | .Ar name . 44 | If 45 | .Ar type 46 | is 47 | .Dq RSA , 48 | an RSA key with 4096 bit will be created. 49 | By default it's an EC key with secp384r1. 50 | .It Cm remove Ar name 51 | Remove the 52 | .Ar name 53 | identity. 54 | .It Cm import Fl C Ar cert Oo Fl K Ar key Oc Ar name 55 | Imports a certificate as 56 | .Ar name . 57 | .Fl C 58 | is the path to the certificate itself. 59 | If the key is on a separate file, it needs to be passed with 60 | .Fl K . 61 | .It Cm export Fl C Ar cert Ar name 62 | Exports the certificate for the identity 63 | .Ar name . 64 | The certificate and the key will be saved at 65 | .Ar cert . 66 | At the moment, it's not possible to export the certificate and the 67 | private key in different files. 68 | .It Cm list 69 | Print one per line the available identities. 70 | .It Cm mappings Op Ar name 71 | Show on which servers and paths the identities are used. 72 | The output consist of the identity name, a tab character, and the the 73 | hostname, optional port number and path under which that identity will 74 | be loaded by 75 | .Xr telescope 1 . 76 | .Pp 77 | If 78 | .Ar name 79 | is given, limit the output only to the instances of that identity. 80 | .It Cm use Ar name Ar host Ns Oo : Ns Ar port Oc Ns Op / Ns Ar path 81 | Save the a new mapping for the given identity 82 | .Ar name . 83 | .It Cm forget Ar name Ar host Ns Oo : Ns Ar port Oc Ns Op / Ns Ar path 84 | Remove the mapping for the given identity 85 | .Ar name . 86 | .El 87 | .Sh SEE ALSO 88 | .Xr telescope 1 89 | .Sh AUTHORS 90 | .An -nosplit 91 | The 92 | .Nm 93 | utility was written by 94 | .An Omar Polo Aq Mt op@omarpolo.com . 95 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.trs 3 | serialized.* 4 | 5 | gmparser 6 | iritest 7 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | check_PROGRAMS = gmparser gmiparser iritest evtest mailcap 2 | 3 | gmparser_SOURCES = gmparser.c \ 4 | $(top_srcdir)/compat.h \ 5 | $(top_srcdir)/hist.c \ 6 | $(top_srcdir)/hist.h \ 7 | $(top_srcdir)/iri.c \ 8 | $(top_srcdir)/iri.h \ 9 | $(top_srcdir)/parser.c \ 10 | $(top_srcdir)/parser.h \ 11 | $(top_srcdir)/parser_gophermap.c \ 12 | $(top_srcdir)/xwrapper.c \ 13 | $(top_srcdir)/xwrapper.h 14 | 15 | gmiparser_SOURCES = gmiparser.c \ 16 | $(top_srcdir)/compat.h \ 17 | $(top_srcdir)/hist.c \ 18 | $(top_srcdir)/hist.h \ 19 | $(top_srcdir)/parser.c \ 20 | $(top_srcdir)/parser.h \ 21 | $(top_srcdir)/parser_gemtext.c \ 22 | $(top_srcdir)/xwrapper.c \ 23 | $(top_srcdir)/xwrapper.h 24 | 25 | iritest_SOURCES = iritest.c \ 26 | $(top_srcdir)/iri.c \ 27 | $(top_srcdir)/iri.h 28 | 29 | evtest_SOURCES = evtest.c \ 30 | $(top_srcdir)/ev.c \ 31 | $(top_srcdir)/ev.h \ 32 | $(top_srcdir)/xwrapper.c \ 33 | $(top_srcdir)/xwrapper.h 34 | 35 | mailcap_SOURCES = $(top_srcdir)/test/mailcap.c \ 36 | $(top_srcdir)/mailcap.c \ 37 | $(top_srcdir)/mailcap.h \ 38 | $(top_srcdir)/xwrapper.c \ 39 | $(top_srcdir)/xwrapper.h 40 | 41 | AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat 42 | 43 | LDADD = $(LIBOBJS) 44 | 45 | EXTRA_DIST = test-gmparser \ 46 | gm-00 \ 47 | gm-01 \ 48 | gmi-00 \ 49 | mc.exp.empty \ 50 | mc.exp.many \ 51 | mc.exp.simple \ 52 | mc.test.empty \ 53 | mc.test.many \ 54 | mc.test.simple 55 | 56 | CLEANFILES = serialized.* 57 | 58 | TESTS = test-gmparser test-mailcap iritest evtest 59 | -------------------------------------------------------------------------------- /test/evtest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #include "compat.h" 27 | 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include "ev.h" 38 | 39 | int fired_a; 40 | int fired_b; 41 | int fired_c; 42 | 43 | struct timeval tv_a = { 0, 250000 }; 44 | struct timeval tv_b = { 0, 300000 }; 45 | struct timeval tv_c = { 0, 350000 }; 46 | 47 | unsigned long tout_a; 48 | unsigned long tout_b; 49 | unsigned long tout_c; 50 | 51 | static void 52 | pipe_ev(int fd, int ev, void *data) 53 | { 54 | warn("shouldn't have happened!"); 55 | abort(); 56 | } 57 | 58 | static void 59 | timeout_cb(int fd, int ev, void *data) 60 | { 61 | int *d = data; 62 | 63 | assert(fd == -1); 64 | *d = 1; 65 | } 66 | 67 | static void 68 | timeout_cancel_b(int fd, int ev, void *data) 69 | { 70 | timeout_cb(fd, ev, data); 71 | ev_timer_cancel(tout_b); 72 | } 73 | 74 | static void 75 | timeout_quit(int fd, int ev, void *data) 76 | { 77 | timeout_cb(fd, ev, data); 78 | ev_break(); 79 | } 80 | 81 | int 82 | main(void) 83 | { 84 | int p[2]; 85 | 86 | alarm(2); /* safety net */ 87 | 88 | /* the ev subsystem needs at least a file descriptor */ 89 | if (pipe(p) == -1) 90 | err(1, "pipe"); 91 | 92 | if (ev_init() == -1) 93 | err(1, "ev_init"); 94 | 95 | if (ev_add(p[0], POLLIN, pipe_ev, NULL) == -1) 96 | err(1, "ev_add"); 97 | 98 | if ((tout_c = ev_timer(&tv_c, timeout_quit, &fired_c)) == 0 || 99 | (tout_b = ev_timer(&tv_b, timeout_cb, &fired_b)) == 0 || 100 | (tout_a = ev_timer(&tv_a, timeout_cancel_b, &fired_a)) == 0) 101 | err(1, "ev_timer"); 102 | 103 | ev_loop(); 104 | 105 | if (fired_a && !fired_b && fired_c) 106 | return 0; 107 | 108 | errx(1, "events fired not as expected: a:%d b:%d c:%d", 109 | fired_a, fired_b, fired_c); 110 | } 111 | -------------------------------------------------------------------------------- /test/gm-00: -------------------------------------------------------------------------------- 1 | i\o/ error.host 1 2 | -------------------------------------------------------------------------------- /test/gm-01: -------------------------------------------------------------------------------- 1 | i\o/ error.host 1 2 | i error.host 1 3 | iServer uptime: error.host 1 4 | i error.host 1 5 | 0gophermap~ 2022-Jan-19 23:31 0.1 KB /gophermap~ localhost 70 6 | 0greetings.txt 2022-Jan-19 23:19 0.0 KB /greetings.txt localhost 70 7 | -------------------------------------------------------------------------------- /test/gmi-00: -------------------------------------------------------------------------------- 1 | * an item 2 | *not an item 3 | 4 | # a title 5 | 6 | some text 7 | 8 | ``` verbatim with alt 9 | \o/ 10 | ``` 11 | 12 | ``` 13 | verbatim without alt description 14 | (the extra space after the marker is there on purpose) 15 | ``` 16 | 17 | > a quote 18 | -------------------------------------------------------------------------------- /test/gmi-01: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telescope-browser/telescope/243d6421b25f09e5b22445f2378598da6ba5b110/test/gmi-01 -------------------------------------------------------------------------------- /test/gmiparser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "hist.h" 24 | #include "parser.h" 25 | #include "telescope.h" 26 | #include "utf8.h" 27 | 28 | /* XXX: needed just to please the linker */ 29 | int hide_pre_context; 30 | int hide_pre_closing_line; 31 | int hide_pre_blocks; 32 | int emojify_link; 33 | int dont_apply_styling; 34 | 35 | int 36 | emojied_line(const char *s, const char **space_ret) 37 | { 38 | return 0; 39 | } 40 | 41 | void 42 | erase_buffer(struct buffer *buffer) 43 | { 44 | return; 45 | } 46 | 47 | int 48 | main(void) 49 | { 50 | FILE *fp; 51 | struct tab tab; 52 | ssize_t r; 53 | size_t blen; 54 | char buf[BUFSIZ], *b; 55 | 56 | memset(&tab, 0, sizeof(tab)); 57 | if ((tab.hist = hist_new(HIST_LINEAR)) == NULL) 58 | err(1, "hist_new"); 59 | if (hist_push(tab.hist, "dummy://address") == -1) 60 | err(1, "hist_push"); 61 | 62 | TAILQ_INIT(&tab.buffer.head); 63 | TAILQ_INIT(&tab.buffer.vhead); 64 | 65 | parser_init(&tab.buffer, &gemtext_parser); 66 | for (;;) { 67 | if ((r = read(0, buf, sizeof(buf))) == -1) 68 | err(1, "read"); 69 | if (r == 0) { 70 | /* 71 | * Force a zero-sized write to also test the 72 | * case of an empty document. 73 | */ 74 | if (!parser_parse(&tab.buffer, buf, 0)) 75 | err(1, "parser_parse"); 76 | break; 77 | } 78 | if (!parser_parse(&tab.buffer, buf, r)) 79 | err(1, "parser_parse"); 80 | } 81 | 82 | if (!parser_free(&tab)) 83 | err(1, "parser_free"); 84 | 85 | if ((fp = open_memstream(&b, &blen)) == NULL) 86 | err(1, "open_memstream"); 87 | 88 | if (parser_serialize(&tab.buffer, fp) == -1) 89 | err(1, "parser_serialize"); 90 | 91 | fclose(fp); 92 | write(1, b, blen); 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /test/gmparser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "hist.h" 24 | #include "parser.h" 25 | #include "telescope.h" 26 | 27 | void 28 | erase_buffer(struct buffer *buffer) 29 | { 30 | return; 31 | } 32 | 33 | int 34 | main(void) 35 | { 36 | FILE *fp; 37 | struct tab tab; 38 | ssize_t r; 39 | size_t blen; 40 | char buf[BUFSIZ], *b; 41 | 42 | memset(&tab, 0, sizeof(tab)); 43 | if ((tab.hist = hist_new(HIST_LINEAR)) == NULL) 44 | err(1, "hist_new"); 45 | if (hist_push(tab.hist, "dummy://address") == -1) 46 | err(1, "hist_push"); 47 | 48 | TAILQ_INIT(&tab.buffer.head); 49 | TAILQ_INIT(&tab.buffer.vhead); 50 | 51 | parser_init(&tab.buffer, &gophermap_parser); 52 | for (;;) { 53 | if ((r = read(0, buf, sizeof(buf))) == -1) 54 | err(1, "read"); 55 | if (r == 0) 56 | break; 57 | if (!parser_parse(&tab.buffer, buf, r)) 58 | err(1, "parser_parse"); 59 | } 60 | 61 | if (!parser_free(&tab)) 62 | err(1, "parser_free"); 63 | 64 | if ((fp = open_memstream(&b, &blen)) == NULL) 65 | err(1, "open_memstream"); 66 | 67 | if (parser_serialize(&tab.buffer, fp) == -1) 68 | err(1, "parser_serialize"); 69 | 70 | fclose(fp); 71 | write(1, b, blen); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /test/mailcap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #include "compat.h" 27 | 28 | #include 29 | #include 30 | 31 | #include "mailcap.h" 32 | 33 | int 34 | main(void) 35 | { 36 | struct mailcap *mc; 37 | 38 | mailcap_parse(stdin); 39 | 40 | TAILQ_FOREACH(mc, &mailcaps, mailcaps) { 41 | printf("%s; %s", mc->mime_type, mc->cmd); 42 | if (mc->flags & MAILCAP_NEEDSTERMINAL) 43 | printf("; needsterminal"); 44 | if (mc->flags & MAILCAP_COPIOUSOUTPUT) 45 | printf("; copiousoutput"); 46 | putchar('\n'); 47 | } 48 | 49 | return (0); 50 | } 51 | -------------------------------------------------------------------------------- /test/mc.exp.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telescope-browser/telescope/243d6421b25f09e5b22445f2378598da6ba5b110/test/mc.exp.empty -------------------------------------------------------------------------------- /test/mc.exp.many: -------------------------------------------------------------------------------- 1 | video/x-youtube; mpv -quiet '%s'; needsterminal 2 | video/*; mpv -quiet '%s'; needsterminal 3 | image/*; xdg-open %s 4 | text/html; mutt-browser '%s'; needsterminal; copiousoutput 5 | -------------------------------------------------------------------------------- /test/mc.exp.simple: -------------------------------------------------------------------------------- 1 | */*; xdg-open %s; needsterminal 2 | -------------------------------------------------------------------------------- /test/mc.test.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telescope-browser/telescope/243d6421b25f09e5b22445f2378598da6ba5b110/test/mc.test.empty -------------------------------------------------------------------------------- /test/mc.test.many: -------------------------------------------------------------------------------- 1 | # text/html; w3m -I %{charset} -T text/html; copiousoutput; 2 | video/x-youtube; mpv -quiet '%s'; needsterminal 3 | video/*; mpv -quiet '%s'; needsterminal 4 | image/*; xdg-open %s 5 | text/html; mutt-browser '%s'; copiousoutput; test=test -n "$DISPLAY"; needsterminal; 6 | -------------------------------------------------------------------------------- /test/mc.test.simple: -------------------------------------------------------------------------------- 1 | */*; xdg-open %s; needsterminal 2 | -------------------------------------------------------------------------------- /test/test-gmparser: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | for f in "$srcdir"/gm-*; do 6 | name=serialized."$(basename "$f")" 7 | ./gmparser < "$f" > "$name" 8 | diff -u "$f" "$name" 9 | done 10 | 11 | for f in "$srcdir"/gmi-*; do 12 | name=serialized."$(basename "$f")" 13 | ./gmiparser < "$f" > "$name" 14 | diff -u "$f" "$name" 15 | done 16 | -------------------------------------------------------------------------------- /test/test-mailcap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | for f in "$srcdir"/mc.test.*; do 6 | name=serialized."$(basename "$f")" 7 | ./mailcap < "$f" > "$name" 8 | 9 | exp="$(basename "$f")" 10 | exp="$srcdir/mc.exp.${exp##mc.test.}" 11 | 12 | diff -u "$exp" "$name" 13 | rm "$name" 14 | done 15 | -------------------------------------------------------------------------------- /tofu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2022, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define TOFU_URL_MAX_LEN (1024 + 1) 18 | 19 | struct tofu_entry { 20 | char domain[TOFU_URL_MAX_LEN]; 21 | 22 | /* 23 | * enough space for ``PROTO:HASH''. probably isn't a good 24 | * idea tho. 25 | */ 26 | char hash[128+1]; 27 | int verified; 28 | }; 29 | 30 | void tofu_init(struct ohash *, unsigned int, ptrdiff_t); 31 | struct tofu_entry *tofu_lookup(struct ohash *, const char *, 32 | const char *); 33 | void tofu_add(struct ohash *, struct tofu_entry *); 34 | int tofu_save(struct ohash *, struct tofu_entry *); 35 | void tofu_update(struct ohash *, struct tofu_entry *); 36 | int tofu_update_persist(struct ohash *, 37 | struct tofu_entry *); 38 | void tofu_temp_trust(struct ohash *, const char *, 39 | const char *, const char *); 40 | -------------------------------------------------------------------------------- /utf8.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef UTF8_H 18 | #define UTF8_H 19 | 20 | #include 21 | #include 22 | 23 | /* utf8.c */ 24 | uint32_t utf8_decode(uint32_t*restrict, uint32_t*restrict, uint8_t); 25 | size_t utf8_snwidth(const char*, size_t, int); 26 | size_t utf8_swidth(const char*, int); 27 | size_t utf8_swidth_between(const char*, const char*, int); 28 | int emojied_line(const char *, const char **); 29 | 30 | /* emoji-matcher.c */ 31 | int is_emoji(uint32_t); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "utils.h" 25 | #include "xwrapper.h" 26 | 27 | int 28 | mark_nonblock_cloexec(int fd) 29 | { 30 | int flags; 31 | 32 | if ((flags = fcntl(fd, F_GETFL)) == -1) 33 | return 0; 34 | if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 35 | return 0; 36 | if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 37 | return 0; 38 | return 1; 39 | } 40 | 41 | int 42 | has_suffix(const char *str, const char *sufx) 43 | { 44 | size_t l, s; 45 | 46 | l = strlen(str); 47 | s = strlen(sufx); 48 | 49 | if (l < s) 50 | return 0; 51 | 52 | return !strcmp(str + (l - s), sufx); 53 | } 54 | 55 | void * 56 | hash_alloc(size_t len, void *d) 57 | { 58 | d = xmalloc(len); 59 | return d; 60 | } 61 | 62 | void * 63 | hash_calloc(size_t nmemb, size_t size, void *d) 64 | { 65 | d = xcalloc(nmemb, size); 66 | return d; 67 | } 68 | 69 | void 70 | hash_free(void *ptr, void *d) 71 | { 72 | free(ptr); 73 | } 74 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, 2024 Omar Polo 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef UTILS_H 18 | #define UTILS_H 19 | 20 | int mark_nonblock_cloexec(int); 21 | 22 | int has_suffix(const char *, const char *); 23 | 24 | void *hash_alloc(size_t, void *); 25 | void *hash_calloc(size_t, size_t, void *); 26 | void hash_free(void *, void *); 27 | 28 | #endif /* UTILS_H */ 29 | -------------------------------------------------------------------------------- /xwrapper.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD$ */ 2 | 3 | /* 4 | * Author: Tatu Ylonen 5 | * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland 6 | * All rights reserved 7 | * Versions of malloc and friends that check their results, and never return 8 | * failure (they call errx if they encounter an error). 9 | * 10 | * As far as I am concerned, the code I have written for this software 11 | * can be used freely for any purpose. Any derived versions of this 12 | * software must be clearly marked as such, and if the derived work is 13 | * incompatible with the protocol description in the RFC file, it must be 14 | * called by a name other than "ssh" or "Secure Shell". 15 | */ 16 | 17 | #include "compat.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "xwrapper.h" 27 | 28 | void * 29 | xmalloc(size_t size) 30 | { 31 | void *ptr; 32 | 33 | if (size == 0) 34 | errx(1, "xmalloc: zero size"); 35 | ptr = malloc(size); 36 | if (ptr == NULL) 37 | errx(1, "xmalloc: allocating %zu bytes: %s", 38 | size, strerror(errno)); 39 | return ptr; 40 | } 41 | 42 | void * 43 | xcalloc(size_t nmemb, size_t size) 44 | { 45 | void *ptr; 46 | 47 | if (size == 0 || nmemb == 0) 48 | errx(1, "xcalloc: zero size"); 49 | ptr = calloc(nmemb, size); 50 | if (ptr == NULL) 51 | errx(1, "xcalloc: allocating %zu * %zu bytes: %s", 52 | nmemb, size, strerror(errno)); 53 | return ptr; 54 | } 55 | 56 | void * 57 | xrealloc(void *ptr, size_t size) 58 | { 59 | return xreallocarray(ptr, 1, size); 60 | } 61 | 62 | void * 63 | xreallocarray(void *ptr, size_t nmemb, size_t size) 64 | { 65 | void *new_ptr; 66 | 67 | if (nmemb == 0 || size == 0) 68 | errx(1, "xreallocarray: zero size"); 69 | new_ptr = reallocarray(ptr, nmemb, size); 70 | if (new_ptr == NULL) 71 | errx(1, "xreallocarray: allocating %zu * %zu bytes: %s", 72 | nmemb, size, strerror(errno)); 73 | return new_ptr; 74 | } 75 | 76 | void * 77 | xrecallocarray(void *ptr, size_t oldnmemb, size_t nmemb, size_t size) 78 | { 79 | void *new_ptr; 80 | 81 | if (nmemb == 0 || size == 0) 82 | errx(1, "xrecallocarray: zero size"); 83 | new_ptr = recallocarray(ptr, oldnmemb, nmemb, size); 84 | if (new_ptr == NULL) 85 | errx(1, "xrecallocarray: allocating %zu * %zu bytes: %s", 86 | nmemb, size, strerror(errno)); 87 | return new_ptr; 88 | } 89 | 90 | char * 91 | xstrdup(const char *str) 92 | { 93 | char *cp; 94 | 95 | if ((cp = strdup(str)) == NULL) 96 | errx(1, "xstrdup: %s", strerror(errno)); 97 | return cp; 98 | } 99 | 100 | char * 101 | xstrndup(const char *str, size_t maxlen) 102 | { 103 | char *cp; 104 | 105 | if ((cp = strndup(str, maxlen)) == NULL) 106 | errx(1, "xstrndup: %s", strerror(errno)); 107 | return cp; 108 | } 109 | 110 | int 111 | xasprintf(char **ret, const char *fmt, ...) 112 | { 113 | va_list ap; 114 | int i; 115 | 116 | va_start(ap, fmt); 117 | i = xvasprintf(ret, fmt, ap); 118 | va_end(ap); 119 | 120 | return i; 121 | } 122 | 123 | int 124 | xvasprintf(char **ret, const char *fmt, va_list ap) 125 | { 126 | int i; 127 | 128 | i = vasprintf(ret, fmt, ap); 129 | 130 | if (i == -1) 131 | errx(1, "xasprintf: %s", strerror(errno)); 132 | 133 | return i; 134 | } 135 | 136 | int 137 | xsnprintf(char *str, size_t len, const char *fmt, ...) 138 | { 139 | va_list ap; 140 | int i; 141 | 142 | va_start(ap, fmt); 143 | i = xvsnprintf(str, len, fmt, ap); 144 | va_end(ap); 145 | 146 | return i; 147 | } 148 | 149 | int 150 | xvsnprintf(char *str, size_t len, const char *fmt, va_list ap) 151 | { 152 | int i; 153 | 154 | if (len > INT_MAX) 155 | errx(1, "xsnprintf: len > INT_MAX"); 156 | 157 | i = vsnprintf(str, len, fmt, ap); 158 | 159 | if (i < 0 || i >= (int)len) 160 | errx(1, "xsnprintf: overflow"); 161 | 162 | return i; 163 | } 164 | -------------------------------------------------------------------------------- /xwrapper.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD$ */ 2 | 3 | /* 4 | * Author: Tatu Ylonen 5 | * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland 6 | * All rights reserved 7 | * Created: Mon Mar 20 22:09:17 1995 ylo 8 | * 9 | * Versions of malloc and friends that check their results, and never return 10 | * failure (they call fatal if they encounter an error). 11 | * 12 | * As far as I am concerned, the code I have written for this software 13 | * can be used freely for any purpose. Any derived versions of this 14 | * software must be clearly marked as such, and if the derived work is 15 | * incompatible with the protocol description in the RFC file, it must be 16 | * called by a name other than "ssh" or "Secure Shell". 17 | */ 18 | 19 | #ifndef XWRAPPER_H 20 | #define XWRAPPER_H 21 | 22 | #if !defined(__bounded__) 23 | #define __bounded__(x, y, z) 24 | #endif 25 | 26 | void *xmalloc(size_t); 27 | void *xcalloc(size_t, size_t); 28 | void *xrealloc(void *, size_t); 29 | void *xreallocarray(void *, size_t, size_t); 30 | void *xrecallocarray(void *, size_t, size_t, size_t); 31 | char *xstrdup(const char *); 32 | char *xstrndup(const char *, size_t); 33 | int xasprintf(char **, const char *, ...) 34 | __attribute__((__format__ (printf, 2, 3))) 35 | __attribute__((__nonnull__ (2))); 36 | int xvasprintf(char **, const char *, va_list) 37 | __attribute__((__format__ (printf, 2, 0))) 38 | __attribute__((__nonnull__ (2))); 39 | int xsnprintf(char *, size_t, const char *, ...) 40 | __attribute__((__format__ (printf, 3, 4))) 41 | __attribute__((__nonnull__ (3))) 42 | __attribute__((__bounded__ (__string__, 1, 2))); 43 | int xvsnprintf(char *, size_t, const char *, va_list) 44 | __attribute__((__format__ (printf, 3, 0))) 45 | __attribute__((__nonnull__ (3))) 46 | __attribute__((__bounded__ (__string__, 1, 2))); 47 | 48 | #endif /* XWRAPPER_H */ 49 | --------------------------------------------------------------------------------