Module Name: othersrc Committed By: agc Date: Wed Jun 21 23:36:17 UTC 2023
Modified Files: othersrc/external/bsd/elex: TODO othersrc/external/bsd/elex/dist: Makefile agcre.c agcre.h elex.c elex.h main.c othersrc/external/bsd/elex/dist/tests: 28.expected othersrc/external/bsd/elex/lib: Makefile Added Files: othersrc/external/bsd/elex/dist: gap.c gap.h Removed Files: othersrc/external/bsd/elex/dist: striter.c striter.h Log Message: Elex version 20230621 ===================== + agcre - added internal magic numbers to agcre to attempt to catch misbehaving programs overwriting sections of memory (extremely coarse- grained checks here). + agcre - check internal magic numbers before attempting to execute regex programs + agcre - bump agcre magic number in the external structure + elex - remove striter (simple) and move to using buffer gap functions + elex - fix a bug whereby we check if a rule has a return value before attempting to parse that return value. + elex - fix up tests for all of these fixes + elex - error out when reading rules if a bad rule is encountered (as the resulting lexer would be erroneous if we continued) + elex - bump elex version to 20230621 To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 othersrc/external/bsd/elex/TODO cvs rdiff -u -r1.2 -r1.3 othersrc/external/bsd/elex/dist/Makefile \ othersrc/external/bsd/elex/dist/agcre.h cvs rdiff -u -r1.3 -r1.4 othersrc/external/bsd/elex/dist/agcre.c \ othersrc/external/bsd/elex/dist/elex.c \ othersrc/external/bsd/elex/dist/elex.h \ othersrc/external/bsd/elex/dist/main.c cvs rdiff -u -r0 -r1.1 othersrc/external/bsd/elex/dist/gap.c \ othersrc/external/bsd/elex/dist/gap.h cvs rdiff -u -r1.3 -r0 othersrc/external/bsd/elex/dist/striter.c cvs rdiff -u -r1.2 -r0 othersrc/external/bsd/elex/dist/striter.h cvs rdiff -u -r1.3 -r1.4 othersrc/external/bsd/elex/dist/tests/28.expected cvs rdiff -u -r1.2 -r1.3 othersrc/external/bsd/elex/lib/Makefile Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: othersrc/external/bsd/elex/TODO diff -u othersrc/external/bsd/elex/TODO:1.1 othersrc/external/bsd/elex/TODO:1.2 --- othersrc/external/bsd/elex/TODO:1.1 Thu Dec 9 04:15:25 2021 +++ othersrc/external/bsd/elex/TODO Wed Jun 21 23:36:17 2023 @@ -44,3 +44,5 @@ get line number action bookmarks clone read-defs from read-grammar +bug fix - test we have an m[6] match before using it as return value +move from striter to gap functions Index: othersrc/external/bsd/elex/dist/Makefile diff -u othersrc/external/bsd/elex/dist/Makefile:1.2 othersrc/external/bsd/elex/dist/Makefile:1.3 --- othersrc/external/bsd/elex/dist/Makefile:1.2 Tue Apr 25 20:03:39 2023 +++ othersrc/external/bsd/elex/dist/Makefile Wed Jun 21 23:36:17 2023 @@ -1,7 +1,7 @@ PROG= elex SRCS+= agcre.c SRCS+= elex.c -SRCS+= striter.c +SRCS+= gap.c SRCS+= main.c MKMAN= no WARNS= 5 Index: othersrc/external/bsd/elex/dist/agcre.h diff -u othersrc/external/bsd/elex/dist/agcre.h:1.2 othersrc/external/bsd/elex/dist/agcre.h:1.3 --- othersrc/external/bsd/elex/dist/agcre.h:1.2 Wed Feb 22 01:01:39 2023 +++ othersrc/external/bsd/elex/dist/agcre.h Wed Jun 21 23:36:17 2023 @@ -53,7 +53,7 @@ #define REG_SUCCESS AGCRE_REG_SUCCESS #define REG_FAILURE AGCRE_REG_FAILURE #define REG_NOMATCH AGCRE_REG_FAILURE -#define REG_MAGIC AGCRE_MAGIC +#define REG_MAGIC AGCRE_MAGIC2 #define REG_MAX_SUBEXPR AGCRE_MAX_SUBEXPR #define REG_MAX_EXPR_LENGTH AGCRE_MAX_EXPR_LENGTH #define REG_ANCHOR AGCRE_REG_ANCHOR @@ -89,7 +89,7 @@ #define AGCRE_REG_SUCCESS 0 #define AGCRE_REG_FAILURE 1 -#define AGCRE_MAGIC 0x20170801 +#define AGCRE_MAGIC2 0x20230621 /* limits we impose on expressions */ #define AGCRE_MAX_SUBEXPR 100 Index: othersrc/external/bsd/elex/dist/agcre.c diff -u othersrc/external/bsd/elex/dist/agcre.c:1.3 othersrc/external/bsd/elex/dist/agcre.c:1.4 --- othersrc/external/bsd/elex/dist/agcre.c:1.3 Thu Feb 23 19:36:07 2023 +++ othersrc/external/bsd/elex/dist/agcre.c Wed Jun 21 23:36:17 2023 @@ -159,17 +159,26 @@ typedef struct threadlist_t { re_thread_t t[1]; /* the threads */ } threadlist_t; +#define MAGIC1 0xac1deaf0 +#define MAGIC2 0x41525345 +#define MAGIC3 0xd0d0d00d +#define MAGIC4 0x666f7572 + /* regular expression internals */ typedef struct re_t { + uint32_t magic1; /* magic number #1 */ instr_t *prog; /* start of instructions */ uint32_t instrc; /* # of instructions */ uint32_t gen; /* generation number */ uint32_t setc; /* # of sets */ uint32_t maxset; /* allocated # of sets */ + uint32_t magic2; /* magic number #2 */ set_t *sets; /* sets */ uint32_t flags; /* comp/exec flags */ context_t *ctxlist; /* list of contexts */ + uint32_t magic3; /* magic number #3 */ instr_t *pc; /* prog counter */ + uint32_t magic4; /* magic number #4 */ int msgc; /* # of chars in msg buffer */ char msg[256]; /* message buffer */ } re_t; @@ -2669,6 +2678,22 @@ growspace(char **buf, size_t *size, size return 1; } +/* check it was compiled properly */ +static inline int +good_struct(const agcre_regex_t *agcre) +{ + re_t *re; + + if (agcre == NULL || agcre->re_magic != AGCRE_MAGIC2) { + return 0; + } + if ((re = agcre->re_g) == NULL) { + return 0; + } + return re->magic1 = MAGIC1 && re->magic2 == MAGIC2 && + re->magic3 == MAGIC3 && re->magic4 == MAGIC4; +} + /***********************************************************/ /* allocate a new structure and return it */ @@ -2697,7 +2722,13 @@ agcre_regcomp(agcre_regex_t *agcre, cons (agcre_regoff_t)(agcre->re_endp - in.s) : (agcre_regoff_t)strlen(in.s); memset(agcre, 0x0, sizeof(*agcre)); - agcre->re_g = re = in.re = calloc(1, sizeof(*re)); + if ((agcre->re_g = re = in.re = calloc(1, sizeof(*re))) == NULL) { + return AGCRE_REG_FAILURE; + } + re->magic1 = MAGIC1; + re->magic2 = MAGIC2; + re->magic3 = MAGIC3; + re->magic4 = MAGIC4; if (in.eo - in.so > AGCRE_MAX_EXPR_LENGTH) { re->msgc = snprintf(re->msg, sizeof(re->msg), "expression length %llu larger than %u", @@ -2739,7 +2770,7 @@ agcre_regcomp(agcre_regex_t *agcre, cons re->pc->op = OP_MATCH; re->pc += 1; re->instrc = re->pc - re->prog; - agcre->re_magic = AGCRE_MAGIC; + agcre->re_magic = AGCRE_MAGIC2; if (flags & AGCRE_REG_DUMP) { printprog(re); } @@ -2757,7 +2788,7 @@ agcre_regerror(int errcode, const agcre_ re_t *re; USE_ARG(errcode); - if (agcre == NULL || size == 0 || errbuf == NULL) { + if (!good_struct(agcre) || size == 0 || errbuf == NULL) { return 0; } re = agcre->re_g; @@ -2782,15 +2813,15 @@ agcre_regexec(agcre_regex_t *agcre, cons re_t *re; int ret; - if (agcre == NULL || vs == NULL || (matchc > 0 && m == NULL)) { + if (!good_struct(agcre) || vs == NULL || (matchc > 0 && m == NULL)) { return AGCRE_REG_FAILURE; } if ((re = agcre->re_g) == NULL) { return AGCRE_REG_FAILURE; } - if (agcre->re_magic != AGCRE_MAGIC) { + if (agcre->re_magic != AGCRE_MAGIC2) { re->msgc = snprintf(re->msg, sizeof(re->msg), - "bad magic number 0x%x, not 0x%x", agcre->re_magic, AGCRE_MAGIC); + "bad magic number 0x%x, not 0x%x", agcre->re_magic, AGCRE_MAGIC2); return AGCRE_REG_FAILURE; } if (matchc > AGCRE_MAX_SUBEXPR) { @@ -2942,6 +2973,9 @@ agcre_rev_regexec(agcre_regex_t *agcre, int found; int lastmatch; + if (!good_struct(agcre) || vs == NULL || (matchc > 0 && m == NULL)) { + return AGCRE_REG_FAILURE; + } if (flags & AGCRE_REG_STARTEND) { from = m[0].rm_so; to = m[0].rm_eo; @@ -2984,7 +3018,7 @@ agcre_regfree(agcre_regex_t *agcre) uint32_t i; re_t *re; - if (agcre) { + if (agcre && good_struct(agcre)) { if ((re = agcre->re_g) != NULL) { free(re->prog); for (i = 0 ; i < re->setc ; i++) { Index: othersrc/external/bsd/elex/dist/elex.c diff -u othersrc/external/bsd/elex/dist/elex.c:1.3 othersrc/external/bsd/elex/dist/elex.c:1.4 --- othersrc/external/bsd/elex/dist/elex.c:1.3 Thu Feb 23 19:36:07 2023 +++ othersrc/external/bsd/elex/dist/elex.c Wed Jun 21 23:36:17 2023 @@ -34,7 +34,7 @@ #include <unistd.h> #include "agcre.h" -#include "striter.h" +#include "gap.h" #include "elex.h" /* a rule for matching */ @@ -279,9 +279,9 @@ make_new_type(elex_t *elex, const char * } #define RULE_START_PAT "<([^>]+)>[ \t]*(.*)</>[ \t]*" - /*1 2 */ + /*1 1 2 2 */ #define RULE_ACTION "\\{[ \t]*(BEGIN[(]([^)]+)[)];)?[ \t]*(return[ \t]*([^;]+);[ \t]*)?\\}" - /* 3 4 5 6 */ + /* 3 4 4 3 5 6 6 5 */ #define STATE_REGEX "^%(x|state)[ \t]+([a-zA-Z0-9_]+)" #define TYPE_REGEX "^%type[ \t]+([^ \t]+)[ \t]+([a-zA-Z0-9_]+)" #define COMMENT_REGEX "^#[^\n]*" @@ -291,30 +291,39 @@ static int read_defs(elex_t *elex, const char *s, uint64_t len) { agcre_regmatch_t m[10]; - agcre_regex_t rule; - agcre_regex_t state; - agcre_regex_t type; - agcre_regex_t comment; - striter_t *str; - size_t size; + agcre_regex_t comment_regex; + agcre_regex_t rule_regex; + agcre_regex_t state_regex; + agcre_regex_t type_regex; + uint64_t linec; + uint64_t size; + uint64_t i; + gap_t *gap; char *buf; char *startstate; char *newstate; char *pat; - int iret; - - if ((str = striter_new()) == NULL) { - return 0; - } - if (!striter_exec(str, "addtext", s, len)) { - return 0; - } - agcre_regcomp(&rule, RULE_START_PAT RULE_ACTION, AGCRE_REG_EXTENDED); - agcre_regcomp(&state, STATE_REGEX, AGCRE_REG_EXTENDED); - agcre_regcomp(&type, TYPE_REGEX, AGCRE_REG_EXTENDED); - agcre_regcomp(&comment, COMMENT_REGEX, AGCRE_REG_EXTENDED); - while ((buf = striter_exec_mem(str, "getline", &size)) != NULL) { - if (agcre_regexec(&rule, buf, __arraycount(m), m, 0) == 0) { + int ruleret; + int type; + int ok; + + if ((gap = gap_new()) == NULL) { + return 0; + } + if (!gap_exec(gap, "insert", s, len) || + !gap_exec(gap, "move-to-offset", NULL, 0)) { + return 0; + } + agcre_regcomp(&rule_regex, RULE_START_PAT RULE_ACTION, AGCRE_REG_EXTENDED); + agcre_regcomp(&state_regex, STATE_REGEX, AGCRE_REG_EXTENDED); + agcre_regcomp(&type_regex, TYPE_REGEX, AGCRE_REG_EXTENDED); + agcre_regcomp(&comment_regex, COMMENT_REGEX, AGCRE_REG_EXTENDED); + linec = gap_exec(gap, "linec", NULL, 0); + for (ok = 0, i = 0 ; i < linec ; i++) { + buf = gap_exec_mem(gap, "getline", i, &size); + m[0].rm_so = 0; + m[0].rm_eo = size; + if (agcre_regexec(&rule_regex, buf, __arraycount(m), m, AGCRE_REG_STARTEND) == 0) { asprintf(&startstate, "%.*s", (int)(m[1].rm_eo - m[1].rm_so), &buf[m[1].rm_so]); asprintf(&pat, "%.*s", @@ -325,41 +334,49 @@ read_defs(elex_t *elex, const char *s, u } else { newstate = strdup(startstate); } - if ((iret = findtype(elex, &buf[m[6].rm_so], m[6].rm_eo - m[6].rm_so)) >= 0) { - iret = elex->types[iret].val; + if (m[6].rm_so < 0) { + ruleret = 0; + } else if ((type = findtype(elex, &buf[m[6].rm_so], m[6].rm_eo - m[6].rm_so)) >= 0) { + ruleret = elex->types[type].val; } else { - iret = strtol(&buf[m[6].rm_so], NULL, 0); + ruleret = strtol(&buf[m[6].rm_so], NULL, 0); } - if (!elex_make_new_rule(elex, startstate, pat, newstate, iret)) { + if (!elex_make_new_rule(elex, startstate, pat, newstate, ruleret)) { warnx("can't make rule '%s'", buf); + goto bad_rule; } free(startstate); free(newstate); free(pat); - } else if (agcre_regexec(&state, buf, __arraycount(m), m, 0) == 0) { + } else if (agcre_regexec(&state_regex, buf, __arraycount(m), m, 0) == 0) { asprintf(&newstate, "%.*s", (int)(m[2].rm_eo - m[2].rm_so), &buf[m[2].rm_so]); if (!make_new_state(elex, newstate)) { warnx("can't make state '%s'", buf); + goto bad_rule; } free(newstate); - } else if (agcre_regexec(&type, buf, __arraycount(m), m, 0) == 0) { - if ((iret = findtype(elex, &buf[m[2].rm_so], m[2].rm_eo - m[2].rm_so)) >= 0) { - iret = elex->types[iret].val; + } else if (agcre_regexec(&type_regex, buf, __arraycount(m), m, 0) == 0) { + if ((type = findtype(elex, &buf[m[2].rm_so], m[2].rm_eo - m[2].rm_so)) >= 0) { + type = elex->types[type].val; } else { - iret = strtoul(&buf[m[2].rm_so], NULL, 0); + type = strtoul(&buf[m[2].rm_so], NULL, 0); } - make_new_type(elex, &buf[m[1].rm_so], m[1].rm_eo - m[1].rm_so, iret); - } else if (agcre_regexec(&comment, buf, __arraycount(m), m, 0) != 0 && buf[0] != '\n') { + make_new_type(elex, &buf[m[1].rm_so], m[1].rm_eo - m[1].rm_so, type); + } else if (agcre_regexec(&comment_regex, buf, __arraycount(m), m, 0) != 0 && buf[0] != '\n') { warnx("UNRECOGNISED '%s'", buf); + goto bad_rule; } + free(buf); } - agcre_regfree(&comment); - agcre_regfree(&type); - agcre_regfree(&rule); - agcre_regfree(&state); - striter_dispose(&str); - return 1; + ok = 1; +bad_rule: + agcre_regfree(&comment_regex); + agcre_regfree(&type_regex); + agcre_regfree(&rule_regex); + agcre_regfree(&state_regex); + gap_dispose(&gap); + return ok; } /* read and parse the defs file */ @@ -631,6 +648,8 @@ elex_exec(elex_t *elex, const char *info return (cc < 0 || cc >= (int64_t)elex->markc) ? 0 : elex->marks[cc]; case /* "get-rule-count" */ 0x5a55649d: return elex->rulec; + case /* "get-version" */ 0xf2712927: + return ELEX_H_; case /* "get-yyleng" */ 0x8801d0e2: return elex->yyleng; case /* "get-yyline" */ 0x8801e26c: Index: othersrc/external/bsd/elex/dist/elex.h diff -u othersrc/external/bsd/elex/dist/elex.h:1.3 othersrc/external/bsd/elex/dist/elex.h:1.4 --- othersrc/external/bsd/elex/dist/elex.h:1.3 Thu Feb 23 19:36:07 2023 +++ othersrc/external/bsd/elex/dist/elex.h Wed Jun 21 23:36:17 2023 @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ELEX_H_ -#define ELEX_H_ 20230223 +#define ELEX_H_ 20230621 #include <inttypes.h> Index: othersrc/external/bsd/elex/dist/main.c diff -u othersrc/external/bsd/elex/dist/main.c:1.3 othersrc/external/bsd/elex/dist/main.c:1.4 --- othersrc/external/bsd/elex/dist/main.c:1.3 Thu Feb 23 19:36:07 2023 +++ othersrc/external/bsd/elex/dist/main.c Wed Jun 21 23:36:17 2023 @@ -108,7 +108,7 @@ main(int argc, char **argv) while ((i = getopt(argc, argv, "Vf:gi:")) != -1) { switch(i) { case 'V': - printf("elex version " ELEX_VERSION_S(ELEX_VERSION_NUM) "\n"); + printf("main elex version " ELEX_VERSION_S(ELEX_VERSION_NUM) "\n"); exit(EXIT_SUCCESS); case 'f': lexfile = optarg; Index: othersrc/external/bsd/elex/dist/tests/28.expected diff -u othersrc/external/bsd/elex/dist/tests/28.expected:1.3 othersrc/external/bsd/elex/dist/tests/28.expected:1.4 --- othersrc/external/bsd/elex/dist/tests/28.expected:1.3 Thu Feb 23 19:36:08 2023 +++ othersrc/external/bsd/elex/dist/tests/28.expected Wed Jun 21 23:36:17 2023 @@ -1 +1 @@ -elex version 20230223 +main elex version 20230621 Index: othersrc/external/bsd/elex/lib/Makefile diff -u othersrc/external/bsd/elex/lib/Makefile:1.2 othersrc/external/bsd/elex/lib/Makefile:1.3 --- othersrc/external/bsd/elex/lib/Makefile:1.2 Fri Feb 24 23:07:54 2023 +++ othersrc/external/bsd/elex/lib/Makefile Wed Jun 21 23:36:17 2023 @@ -1,7 +1,7 @@ LIB= elex SRCS+= agcre.c SRCS+= elex.c -SRCS+= striter.c +SRCS+= gap.c CPPFLAGS+= -I${DIST} MKMAN= no WARNS= 5 Added files: Index: othersrc/external/bsd/elex/dist/gap.c diff -u /dev/null othersrc/external/bsd/elex/dist/gap.c:1.1 --- /dev/null Wed Jun 21 23:36:17 2023 +++ othersrc/external/bsd/elex/dist/gap.c Wed Jun 21 23:36:17 2023 @@ -0,0 +1,1174 @@ +/*- + * Copyright (c) 2023 Alistair Crooks <a...@netbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "agcre.h" +#include "gap.h" + +#define X 0 +#define Y 1 + +/* maximum screen dimensions and parameters */ +#define MAXROWS 8192 +#define MAXCOLS 16384 +#define MAXTABSIZE 16 +#define DEFAULT_TABSIZE 8 + +/* search params */ +typedef struct reparams_t { + int reverse; /* search backwards */ + int eofstop; /* stop at eof - no wrap */ + int range; /* range in regmatch_t args */ + int lineonly; /* terminate search at the end of line */ + uint32_t flags; /* regex flags */ + uint64_t lhs; /* saved lhs position */ + uint64_t lhsnl; /* saved lhs line position */ +} reparams_t; + +/* line information */ +typedef struct eline_t { + uint64_t len; /* line length in bytes */ + uint64_t state; /* start state for syntax coloring */ + uint64_t width; /* detabbed length of line */ +} eline_t; + +/* buffer gap structure */ +struct gap_t { + char *v; /* buffer gap text */ + uint64_t size; /* size of allocated text */ + uint64_t lhs; /* # of bytes on lhs */ + uint64_t lhsnl; /* # of \n on lhs */ + uint64_t rhs; /* # of bytes on rhs */ + uint64_t rhsnl; /* # of \n on rhs */ + eline_t *line; /* counts per line */ + uint64_t linealloc; /* # of lines allocated */ + char *filename; /* any associated filename */ + uint64_t chgc; /* # of changes made */ + /* regex part */ + agcre_regex_t r; /* regex for searching */ + uint64_t msize; /* allocated size of mv array */ + agcre_regmatch_t *mv; /* match values */ + int compiled; /* regex was previously compiled */ + /* screen handling part */ + uint64_t tabc; /* # of tabs in the buffer */ + uint64_t tabsize; /* # of spaces to expand a tab */ + + uint64_t windim[2]; /* window dimensions */ + uint64_t origin; /* on-screen start offset */ + uint64_t last; /* on-screen end offset */ + uint64_t offM; /* mid-screen offset */ + uint64_t offL; /* last line offset */ + int repaint; /* need to repaint screen */ +}; + +/* find the index on the rhs */ +static inline uint64_t +rhssub(uint64_t n, uint64_t size) +{ + return size - 1 - n; +} + +/* count the ch characters in len bytes of v */ +static inline uint64_t +count(const char *v, uint8_t ch, uint64_t len) +{ + uint64_t nl; + uint64_t i; + + for (nl = 0, i = 0 ; i < len ; i++) { + if (v[i] == ch) { + nl += 1; + } + } + return nl; +} + +/* return the width of a byte at current column */ +static inline uint64_t +bytewidth(gap_t *gap, uint64_t col, char ch) +{ + switch(ch) { + case '\n': + return gap->windim[X] - col; + case '\t': + return ((gap->tabsize - 1) - (col % gap->tabsize)) + 1; + default: + return 1; + } +} + +static const uint32_t maxlen = 32; + +/* hashing function */ +static uint32_t +djbhash(const char *s) +{ + const char *from = s; + uint32_t hash; + + for (hash = 5381; *s && (uint32_t)(s - from) < maxlen ; ) { + hash = hash * 33 + *s++; + } + return hash + (hash >> 5); +} + +/* calculate line lengths */ +static int +calclens(gap_t *gap) +{ + uint64_t len; + uint64_t col; + uint64_t nl; + eline_t *line; + char *p; + + if (gap->lhsnl + gap->rhsnl + 8 > gap->linealloc) { + nl = howmany(gap->lhsnl + gap->rhsnl, 1024) * 1024; + if ((line = realloc(gap->line, sizeof(*line) * nl)) == NULL) { + return 0; + } + memset(&line[gap->linealloc], 0x0, (nl - gap->linealloc) * sizeof(*line)); + gap->line = line; + gap->linealloc = nl; + } + for (nl = 0, col = 0, len = 0, p = gap->v ; (uint64_t)(p - gap->v) < gap->lhs ; p++) { + len += 1; + switch(*p) { + case '\n': + gap->line[nl].width = col; + gap->line[nl].len = len; + len = 0; + col = 0; + nl += 1; + break; + case '\t': + col += ((gap->tabsize - 1) - (col % gap->tabsize)) + 1; + break; + default: + col += 1; + break; + } + } + for (p = &gap->v[rhssub(gap->rhs, gap->size)]; (uint64_t)(p - gap->v) < gap->size ; p++) { + len += 1; + switch(*p) { + case '\n': + gap->line[nl].width = col; + gap->line[nl].len = len; + len = 0; + col = 0; + nl += 1; + break; + case '\t': + col += ((gap->tabsize - 1) - (col % gap->tabsize)) + 1; + break; + default: + col += 1; + break; + } + } + gap->line[nl].width = col; + gap->line[nl].len = len; + return 1; +} + +/********************************************************/ + +/* ensure we can handle an extra add bytes, rounded up to nearest 1K */ +static int +canhandle(gap_t *gap, uint64_t add) +{ + uint64_t newsize; + char *v; + + if (gap->lhs + gap->rhs + 10 + add > gap->size) { + newsize = howmany(gap->size + add, 1024) * 1024; + if ((v = calloc(1, newsize)) == NULL) { + return 0; + } + memcpy(v, gap->v, gap->lhs); + memcpy(&v[rhssub(gap->rhs, newsize)], &gap->v[rhssub(gap->rhs, gap->size)], gap->rhs); + gap->size = newsize; + free(gap->v); + gap->v = v; + } + return 1; +} + +/* insert text at the end of the lhs in the buffer */ +static int +insert(gap_t *gap, const char *s, uint64_t len) +{ + if (!canhandle(gap, len + 10)) { + return 0; + } + if (s == NULL) { + memset(&gap->v[gap->lhs], 0x0, len); + gap->lhs += len; + } else { + memcpy(&gap->v[gap->lhs], s, len); + gap->lhs += len; + gap->lhsnl += count(s, '\n', len); + gap->tabc += count(s, '\t', len); + } + gap->chgc += 1; + return calclens(gap); +} + +/* delete text from the rhs of the gap */ +static int +delete(gap_t *gap, uint64_t n) +{ + if (n > gap->rhs) { + return 0; + } + gap->rhsnl -= count(&gap->v[rhssub(gap->rhs, gap->size)], '\n', n); + gap->tabc -= count(&gap->v[rhssub(gap->rhs, gap->size)], '\t', n); + gap->rhs -= n; + gap->chgc += 1; + return calclens(gap); +} + +/* move n bytes left */ +static int +moveleft(gap_t *gap, uint64_t n) +{ + uint64_t nl; + + if (n > gap->lhs) { + return 0; + } + nl = count(&gap->v[gap->lhs - n], '\n', n); + memmove(&gap->v[rhssub(gap->rhs + n, gap->size)], &gap->v[gap->lhs - n], n); + gap->lhs -= n; + gap->rhs += n; + gap->lhsnl -= nl; + gap->rhsnl += nl; + return 1; +} + +/* move n bytes right */ +static int +moveright(gap_t *gap, uint64_t n) +{ + uint64_t nl; + + if (n > gap->rhs) { + return 0; + } + nl = count(&gap->v[rhssub(gap->rhs, gap->size)], '\n', n); + memmove(&gap->v[gap->lhs], &gap->v[rhssub(gap->rhs, gap->size)], n); + gap->lhs += n; + gap->rhs -= n; + gap->lhsnl += nl; + gap->rhsnl -= nl; + return 1; +} + +/* calculate the offset for the start of the line */ +static uint64_t +line2off(gap_t *gap, uint64_t lineno) +{ + uint64_t off; + uint64_t i; + + for (off = 0, i = 0 ; i < lineno && i < gap->lhsnl + gap->rhsnl ; i++) { + off += gap->line[i].len; + } + return off; +} + +/* calculate the offset for the start of the line */ +static uint64_t +off2line(gap_t *gap, uint64_t off) +{ + uint64_t cc; + uint64_t i; + + for (cc = 0, i = 0 ; cc < off && i < gap->lhsnl + gap->rhsnl ; i++) { + cc += gap->line[i].len; + } + return i; +} + +/* move to an absolute line number */ +static int +move2line(gap_t *gap, uint64_t n) +{ + uint64_t off; + + if (n > gap->lhsnl + gap->rhsnl) { + return 0; + } + if ((off = line2off(gap, n)) < gap->lhs) { + return moveleft(gap, gap->lhs - off); + } + return moveright(gap, off - gap->lhs); +} + +/* move to an absolute offset in the file */ +static int +move2offset(gap_t *gap, uint64_t off) +{ + if (off > gap->lhs + gap->rhs) { + return 0; + } + if (off > gap->lhs) { + return moveright(gap, off - gap->lhs); + } + if (off < gap->lhs) { + return moveleft(gap, gap->lhs - off); + } + return 1; +} + +/* return the detabbed offset in the line */ +static uint64_t +line_detab_offset(gap_t *gap) +{ + uint64_t col; + uint64_t i; + + if (gap->tabsize == 0) { + return 0; + } + for (i = line2off(gap, gap->lhsnl), col = 0 ; i < gap->lhs ; i++) { + col += bytewidth(gap, col, gap->v[i]); + } + return col; +} + +/* return the current screen offset */ +static uint64_t +screen_offset(gap_t *gap) +{ + uint64_t off; + uint64_t i; + + if (gap->windim[X] == 0) { + return 0; + } + for (off = 0, i = off2line(gap, gap->origin); i < gap->lhsnl ; i++) { + off += howmany(gap->line[i].width, gap->windim[X]) * gap->windim[X]; + } + return off + line_detab_offset(gap); +} + +/* move n cols right */ +static int +movecolright(gap_t *gap, uint64_t n) +{ + uint64_t col; + + if (n > gap->rhs) { + return 0; + } + /* still might overshoot */ + for (col = line_detab_offset(gap) ; col < n ; ) { + col += bytewidth(gap, col, gap->v[rhssub(gap->rhs, gap->size)]); + if (!moveright(gap, 1)) { + return 0; + } + } + return 1; +} + +/* read a file, and insert it into the gap */ +static int +readfile(gap_t *gap, const char *file) +{ + struct stat st; + uint64_t bytes; + size_t cc; + size_t rc; + FILE *fp; + char *v; + int allocated; + int ok; + + if ((fp = fopen(file, "r")) == NULL) { + return 0; + } + fstat(fileno(fp), &st); + bytes = st.st_size; + allocated = 0; + if (gap->filename == NULL) { + cc = strlen(file); + allocated = 1; + if ((gap->filename = calloc(1, cc + 1)) == NULL) { + fclose(fp); + return 0; + } + memcpy(gap->filename, file, cc); + } + if ((v = calloc(1, bytes)) == NULL) { + if (allocated) { + free(gap->filename); + gap->filename = NULL; + } + fclose(fp); + return 0; + } + for (cc = 0 ; cc < bytes ; cc += rc) { + if ((rc = fread(&v[cc], 1, bytes - cc, fp)) == 0) { + break; + } + } + fclose(fp); + ok = insert(gap, v, bytes); + free(v); + if (!ok) { + return 0; + } + return moveleft(gap, bytes); +} + +/* make a filename template */ +static int +make_template(char *name, size_t size, const char *base) +{ + struct tm tm; + time_t t; + + t = time(NULL); + localtime_r(&t, &tm); + snprintf(name, size, "%s-%.04d%02d%02d.%02d%02d%02d", + base, + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); + return 1; +} + +/* write file to persistent storage */ +static int +writefile(gap_t *gap, const char *filename) +{ + size_t cc; + size_t wc; + FILE *fp; + char name[1024]; + int fd; + + make_template(name, sizeof(name), (filename) ? filename : (gap->filename) ? gap->filename : "Untitled"); + if ((fd = mkstemp(name)) < 0) { + return 0; + } + fp = fdopen(fd, "w+"); + for (cc = 0 ; cc < gap->lhs ; cc += wc) { + if ((wc = fwrite(&gap->v[cc], 1, gap->lhs - cc, fp)) == 0) { + goto writefile_error; + } + } + for (cc = 0 ; cc < gap->rhs ; cc += wc) { + if ((wc = fwrite(&gap->v[rhssub(gap->rhs - cc, gap->size)], 1, gap->rhs - cc, fp)) == 0) { + goto writefile_error; + } + } + fclose(fp); + if (filename == NULL && gap->filename != NULL) { + /* need to rename file */ + if (rename(name, gap->filename) != 0) { + unlink(name); + return 0; + } + } + return 1; +writefile_error: + fclose(fp); + unlink(name); + return 0; +} + +/* allocate storage, user frees */ +static char * +allocate(const char *s, uint64_t n) +{ + char *v; + + if ((v = calloc(1, n)) == NULL) { + return NULL; + } + memcpy(v, s, n); + return v; +} + +/* search for a regular expression in the gap */ +static int +find_regex(gap_t *gap, const char *pat, reparams_t *params, int rhs, uint64_t from, uint64_t to) +{ + agcre_regmatch_t *newmv; + const char *v; + + if (gap->compiled) { + agcre_regfree(&gap->r); + gap->compiled = 0; + } + if (agcre_regcomp(&gap->r, pat, params->flags) != 0) { + return 0; + } + gap->compiled = 1; + if (gap->r.re_nsub + 1 > gap->msize) { + newmv = realloc(gap->mv, (gap->r.re_nsub + 10) * sizeof(*newmv)); + if (newmv == NULL) { + return 0; + } + gap->mv = newmv; + gap->msize = gap->r.re_nsub + 10; + } + v = (rhs) ? &gap->v[rhssub(gap->rhs, gap->size)] : gap->v; + if (params->reverse) { + gap->mv[0].rm_so = from; + gap->mv[0].rm_eo = to; + if (agcre_rev_regexec(&gap->r, v, gap->msize, gap->mv, AGCRE_REG_STARTEND) != 0) { + return 0; + } + } else { + gap->mv[0].rm_so = from; + gap->mv[0].rm_eo = to; + if (agcre_regexec(&gap->r, v, gap->msize, gap->mv, AGCRE_REG_STARTEND) != 0) { + return 0; + } + } + return (rhs) ? move2offset(gap, gap->lhs + gap->mv[0].rm_so) : move2offset(gap, gap->mv[0].rm_so); +} + +/* calculate a percentage as an integer */ +static inline uint32_t +percentage(uint64_t num, uint64_t denom) +{ + return (denom == 0) ? 0 : (int)(num * (uint64_t)100) / denom; +} + +/* allocate a line and copy contents in without disturbing the buffer */ +static char * +allocline(gap_t *gap, uint64_t lineno, uint64_t *size) +{ + uint64_t off; + uint64_t len; + uint64_t cc; + char *s; + + if (lineno > gap->lhsnl + gap->rhsnl) { + return NULL; + } + len = gap->line[lineno].len; + off = line2off(gap, lineno); + if (off > gap->lhs) { + /* all on rhs */ + return allocate(&gap->v[rhssub(gap->rhs - (off - gap->lhs), gap->size)], *size = len); + } + if (off + len < gap->lhs) { + /* all on lhs */ + return allocate(&gap->v[off], *size = len); + } + /* a bitta both */ + if ((s = calloc(1, *size = gap->line[lineno].len)) == NULL) { + return NULL; + } + memcpy(s, &gap->v[off], cc = gap->lhs - off); + memcpy(&s[cc], &gap->v[rhssub(gap->rhs, gap->size)], len); + return s; +} + +/* clone the original gap */ +static int +clonegap(gap_t *gap, const gap_t *orig) +{ + eline_t *line; + char *v; + + if (gap->linealloc < orig->linealloc) { + if ((line = realloc(gap->line, sizeof(*line) * orig->linealloc)) == NULL) { + return 0; + } + gap->line = line; + gap->linealloc = orig->linealloc; + } + if (gap->size < orig->size) { + if ((v = realloc(gap->v, orig->size)) == NULL) { + return 0; + } + gap->v = v; + gap->size = orig->size; + } + /* copy these carefully, they may be a different size */ + memcpy(gap->v, orig->v, orig->lhs); + memcpy(&gap->v[rhssub(orig->rhs, gap->size)], &orig->v[rhssub(orig->rhs, orig->size)], orig->rhs); + memcpy(gap->line, orig->line, orig->linealloc * sizeof(*gap->line)); + gap->lhs = orig->lhs; + gap->lhsnl = orig->lhsnl; + gap->rhs = orig->rhs; + gap->rhsnl = orig->rhsnl; + gap->tabc = orig->tabc; + gap->chgc = orig->chgc; + return 1; +} + +/* convert all tabs to spaces */ +static char * +detab(gap_t *gap, uint64_t *size) +{ + uint64_t width; + uint32_t col; + char *o; + char *v; + char *out; + + if (gap->tabsize == 0) { + return NULL; + } + if ((out = calloc(1, gap->size + (gap->tabc * gap->tabsize))) == NULL) { + return NULL; + } + move2line(gap, gap->lhsnl); + v = &gap->v[rhssub(gap->rhs, gap->size)]; + for (col = 0, o = out ; (uint64_t)(v - gap->v) < gap->size ; v++) { + switch(*v) { + case '\n': + *o++ = '\n'; + col = 0; + break; + case '\t': + width = ((gap->tabsize - 1) - (col % gap->tabsize)) + 1; + memset(o, ' ', width); + o += width; + col += width; + break; + default: + *o++ = *v; + col += 1; + break; + } + } + *size = (uint64_t)(o - out); + return out; +} + +/* return the whole buffer as a string */ +static char * +getbuffer(gap_t *gap, uint64_t *size) +{ + char *s; + + if ((s = calloc(1, gap->lhs + gap->rhs + 1)) == NULL) { + return NULL; + } + if (gap->lhs > 0) { + memcpy(s, gap->v, gap->lhs); + } + if (gap->rhs > 0) { + memcpy(&s[gap->lhs], &gap->v[rhssub(gap->rhs, gap->size)], gap->rhs); + } + *size = gap->lhs + gap->rhs; + return s; +} + +/* given an origin, calulate the last offset on screen */ +static int +calclast(gap_t *gap, uint64_t origin, uint64_t originnl) +{ + uint64_t x; + uint64_t y; + char *rhs; + char *p; + + gap->origin = gap->offM = gap->offL = origin; + p = rhs = &gap->v[rhssub(gap->rhs, gap->size)]; + for (x = y = 0 ; (uint64_t)(p - rhs) < gap->rhs && y < gap->windim[Y] ; p++) { + x += bytewidth(gap, x, *p); + if (x >= gap->windim[X]) { + x = 0; + y += 1; + if (y == (gap->windim[Y] / 2) - 1) { + gap->offM = origin + (uint64_t)(p - rhs); + } else if (y == gap->windim[Y] - 1) { + gap->offL = origin + (uint64_t)(p - rhs); + } + } + } + gap->last = origin + (uint64_t)(p - rhs); + return 1; +} + +/* refocus the origin, and calculate last */ +static int +refocus(gap_t *gap, int force) +{ + uint64_t was; + uint64_t i; + + if (force || gap->lhs < gap->origin || gap->lhs > gap->last) { + was = gap->lhs; + moveleft(gap, gap->lhs - line2off(gap, gap->lhsnl)); + for (i = gap->lhs ; i < gap->lhs + gap->rhs ; i++) { + calclast(gap, gap->lhs, gap->lhsnl); + if (was >= gap->origin && was <= gap->last) { + break; + } + movecolright(gap, gap->windim[X]); + } + move2offset(gap, was); + } + return 1; +} + +/* return the window's text as a string */ +static char * +get_window_text(gap_t *gap, uint64_t *size) +{ + uint64_t linelen; + uint64_t buflen; + uint64_t i; + uint64_t y; + char *s; + + if (gap->windim[X] == 0 || gap->windim[Y] == 0 || gap->tabsize == 0) { + return 0; + } + refocus(gap, gap->repaint); + for (buflen = 0, y = 0, i = 0 ; i < gap->rhsnl && y < gap->windim[Y] ; i++) { + linelen = gap->line[gap->lhsnl + i].len; + y += (linelen / gap->windim[Y]) + 1; + buflen += linelen; + } + if ((s = calloc(1, buflen)) == NULL) { + return NULL; + } + memcpy(s, &gap->v[rhssub(gap->rhs, gap->size)], *size = buflen); + return s; +} + +/* do the equivalent of memset */ +static uint64_t +memset_in_gap(gap_t *gap, const uint8_t *p, uint64_t len) +{ + uint64_t tab; + uint64_t nl; + char *rhs; + + if (p == NULL || len > gap->rhs) { + return 0; + } + if (len > 0) { + rhs = &gap->v[rhssub(gap->rhs, gap->size)]; + nl = count(rhs, '\n', len); + tab = count(rhs, '\t', len); + gap->rhsnl -= nl; + gap->tabc -= tab; + switch(*p) { + case '\t': + gap->tabc += len; + break; + case '\n': + gap->rhsnl += len; + break; + } + memset(rhs, *p, len); + moveright(gap, len); + gap->chgc += 1; + } + return 1; +} + +/* do an memchr forwards (to the right) */ +static int +memchr_in_gap(gap_t *gap, const char *s, uint64_t n) +{ + uint64_t c; + uint64_t i; + char *p; + + if (gap->rhs > 0) { + for (c = 0, i = 0, p = &gap->v[rhssub(gap->rhs, gap->size)] ; i < gap->rhs ; i++) { + if (*p++ == *s) { + if (++c == n) { + return moveright(gap, i); + } + } + } + } + return 0; +} + +/* do an memrchr backwards (to the left) */ +static int +memrchr_in_gap(gap_t *gap, const char *s, uint64_t n) +{ + uint64_t c; + uint64_t i; + char *p; + + if (gap->lhs > 0) { + for (c = 0, i = 0, p = &gap->v[gap->lhs - 1] ; i < gap->lhs ; i++) { + if (*p-- == *s) { + if (++c == n) { + return moveleft(gap, i); + } + } + } + } + return 0; +} + +/* return from rhs to eol */ +static char * +rhs_to_eol(gap_t *gap, uint64_t *size) +{ + uint64_t cc; + + cc = (gap->rhsnl == 0) ? gap->rhs : line2off(gap, gap->lhsnl + 1) - gap->lhs; + return allocate(&gap->v[rhssub(gap->rhs, gap->size)], *size = cc); +} + +/* move to logical beginning of line */ +static int +lbol(gap_t *gap) +{ + static agcre_regex_t r; + agcre_regmatch_t mv[2]; + static int compiled; + uint64_t off; + + if (!compiled) { + agcre_regcomp(&r, "\\S", AGCRE_REG_EXTENDED); + compiled = 1; + } + if ((off = gap->lhs - line2off(gap, gap->lhsnl)) > 0) { + moveleft(gap, off); + } + mv[0].rm_so = 0; + mv[0].rm_eo = gap->line[gap->lhsnl].len; + if (agcre_regexec(&r, &gap->v[rhssub(gap->rhs, gap->size)], 2, mv, AGCRE_REG_STARTEND) == 0) { + moveright(gap, mv[0].rm_so); + } + return 1; +} + +/* delete n lines */ +static int +delete_lines(gap_t *gap, uint64_t n) +{ + uint64_t cc; + + if (n >= gap->rhsnl) { + return 0; + } + move2line(gap, gap->lhsnl); + cc = line2off(gap, gap->lhsnl + n); + return delete(gap, cc); +} + +/* yank n lines */ +static char * +yank_lines(gap_t *gap, uint64_t n, uint64_t *size) +{ + uint64_t cc; + + if (n >= gap->rhsnl) { + return 0; + } + move2line(gap, gap->lhsnl); + cc = line2off(gap, gap->lhsnl + n); + return allocate(&gap->v[rhssub(gap->rhs, gap->size)], *size = cc); +} + +/********************************************************/ + +/* new buffer gap */ +gap_t * +gap_new(void) +{ + uint64_t n; + gap_t *gap; + + if ((gap = calloc(1, sizeof(*gap))) == NULL) { + return NULL; + } + n = howmany(8192, 1024) * 1024; + if ((gap->v = calloc(1, n)) == NULL) { + free(gap); + return NULL; + } + gap->size = n; + gap->tabsize = DEFAULT_TABSIZE; + return gap; +} + +/* dispose of the gap */ +int +gap_dispose(gap_t **gap) +{ + if (gap && *gap) { + free((*gap)->v); + free(*gap); + *gap = NULL; + return 1; + } + return 0; +} + +/* execute an action, return an int */ +uint64_t +gap_exec(gap_t *gap, const char *action, const void *vs, uint64_t n) +{ + if (gap == NULL || action == NULL) { + return 0; + } + switch(djbhash(action)) { + case /* "bytec" */ 0xfaa3bed: + return gap->lhs + gap->rhs; + case /* "changec" */ 0xc848b36a: + return gap->chgc; + case /* "clone" */ 0xfb57683: + return (vs == NULL) ? 0 : clonegap(gap, vs); + case /* "delete" */ 0x47a09b: + return delete(gap, n); + case /* "delete-lines" */ 0xa11ab5d3: + return delete_lines(gap, n); + case /* "get-cols" */ 0x2be06e6: + return gap->windim[X]; + case /* "get-last" */ 0x2c2e14f: + return gap->last; + case /* "get-L" */ 0xffc336c: + return gap->offL; + case /* "get-M" */ 0xffc336d: + return gap->offM; + case /* "get-origin" */ 0x6f6f52d9: + return gap->origin; + case /* "get-rows" */ 0x2c683d8: + return gap->windim[Y]; + case /* "get-tabsize" */ 0x48e3315e: + return gap->tabsize; + case /* "insert" */ 0x4faa2ae: + return insert(gap, vs, n); + case /* "lhs" */ 0xbe4d08d: + return gap->lhs; + case /* "lhsnl" */ 0x105b3874: + return gap->lhsnl; + case /* "linec" */ 0x105bb20d: + return gap->lhsnl + gap->rhsnl; + case /* "line-lhs" */ 0xc80137d5: + return gap->lhs - line2off(gap, gap->lhsnl); + case /* "line-lhs-detab" */ 0x1a300162: + return line_detab_offset(gap); + case /* "line-rhs" */ 0xc8015227: + return (gap->rhsnl == 0) ? gap->rhs : line2off(gap, gap->lhsnl + 1) - gap->lhs; + case /* "line-to-offset" */ 0xc6c7d98a: + return line2off(gap, n); + case /* "linelength" */ 0x9c3bc7ba: + return (n >= gap->lhsnl + gap->rhsnl) ? 0 : gap->line[n].len; + case /* "linewidth" */ 0x58b5d1f: + return (n >= gap->lhsnl + gap->rhsnl) ? 0 : gap->line[n].width; + case /* "memchr" */ 0xdee8825: + return (vs == NULL) ? 0 : memchr_in_gap(gap, vs, n); + case /* "memrchr" */ 0xc3c7f174: + return (vs == NULL) ? 0 : memrchr_in_gap(gap, vs, n); + case /* "memset" */ 0xdeecdf1: + return memset_in_gap(gap, vs, n); + case /* "move-lbol" */ 0x693036fc: + return lbol(gap); + case /* "move-left" */ 0x693042fb: + return moveleft(gap, n); + case /* "move-left-line" */ 0xb22440bb: + return move2line(gap, gap->lhsnl - n); + case /* "move-right" */ 0x27aae060: + return moveright(gap, n); + case /* "move-right-line" */ 0x216f6cbe: + return move2line(gap, gap->lhsnl + n); + case /* "move-to-bof" */ 0x225a0d4: + return moveleft(gap, gap->lhs); + case /* "move-to-eof" */ 0x225adfd: + return moveright(gap, gap->rhs); + case /* "move-to-eol" */ 0x225ae03: + return moveright(gap, + (gap->rhsnl == 0) ? gap->rhs : line2off(gap, gap->lhsnl + 1) - gap->lhs - 2); + case /* "move-to-line" */ 0x46df4a33: + return move2line(gap, n); + case /* "move-to-offset" */ 0x62d5e227: + return move2offset(gap, n); + case /* "offset-to-line" */ 0x9b4a6ad8: + return off2line(gap, n); + case /* "read-file" */ 0x1ff4ae6f: + return (vs == NULL) ? 0 : readfile(gap, vs); + case /* "refocus" */ 0x402de943: + return refocus(gap, 0); + case /* "reset-changec" */ 0xa9b38cdf: + gap->chgc = 0; + return 1; + case /* "rhs" */ 0xbe4eadf: + return gap->rhs; + case /* "rhsnl" */ 0x10cb3012: + return gap->rhsnl; + case /* "screen-offset" */ 0xa4877a9: + return screen_offset(gap); + case /* "set-cols" */ 0xe6cb146: + if (n >= MAXCOLS) { + return 0; + } + gap->windim[X] = n; + return 1; + case /* "set-origin" */ 0xa17216d2: + if (n >= gap->lhs + gap->rhs) { + return 0; + } + gap->origin = n; + gap->repaint = 1; + return 1; + case /* "set-rows" */ 0xe752e39: + if (n >= MAXROWS) { + return 0; + } + gap->windim[Y] = n; + return 1; + case /* "set-tabsize" */ 0x8b3e7462: + if (n == 0 || n > MAXTABSIZE) { + return 0; + } + gap->tabsize = n; + return 1; + case /* "version" */ 0x76986fad: + return GAP_H_; + case /* "wipe" */ 0x80851f0a: + gap->lhs = gap->rhs = gap->lhsnl = gap->rhsnl = gap->chgc = 0; + return 1; + case /* "write-file" */ 0xb2d1c629: + return writefile(gap, vs); + } + return 0; +} + +/* used to stringify the namespace we're using */ +#define GAP_STRINGIFY(_x) GAP_STRINGIFY2(_x) +#define GAP_STRINGIFY2(_x) #_x + +/* execute an action on the gap, return allocated byte string */ +char * +gap_exec_mem(gap_t *gap, const char *action, uint64_t n, uint64_t *size) +{ + if (gap == NULL || action == NULL || size == NULL) { + return 0; + } + *size = 0; + switch (djbhash(action)) { + case /* "detab" */ 0xfc43e9e: + return detab(gap, size); + case /* "filename" */ 0x357ed0f9: + return (gap->filename == NULL) ? NULL : + allocate(gap->filename, *size = strlen(gap->filename)); + case /* "get-rhs-eol" */ 0xc40b665a: + return rhs_to_eol(gap, size); + case /* "getbuf" */ 0x7838f68: + return getbuffer(gap, size); + case /* "getlhs" */ 0x783b999: + return allocate(gap->v, *size = gap->lhs); + case /* "getline" */ 0xf7faf0e6: + return allocline(gap, n, size); + case /* "getrhs" */ 0x783d3eb: + return allocate(&gap->v[rhssub(gap->rhs, gap->size)], *size = gap->rhs); + case /* "get-window-text" */ 0xb9d5d262: + return get_window_text(gap, size); + case /* "namespace" */ 0x41041c23: + return allocate(GAP_STRINGIFY(LIB_NAMESPACE), + *size = strlen(GAP_STRINGIFY(LIB_NAMESPACE))); + case /* "yank-lines" */ 0x66a66734: + return yank_lines(gap, n, size); + } + return NULL; +} + +#define ARG_LINE_LHS 2 +#define ARG_LINE_RHS 3 +#define ARG_LHS 4 +#define ARG_RHS 5 +#define ARG_ICASE 6 +#define ARG_REVERSE 7 + +/* search for a regexp */ +int +gap_search(gap_t *gap, const char *args, const char *pat, uint64_t mc, void *vmv) +{ + static agcre_regex_t arg; + agcre_regmatch_t *mv = (agcre_regmatch_t *)vmv; + agcre_regmatch_t m[10]; + static int compiled; + reparams_t params; + uint64_t from; + uint64_t to; + int rhs; + + if (gap == NULL || args == NULL || pat == NULL || mc == 0 || mv == NULL) { + return 0; + } + if (!compiled) { + agcre_regcomp(&arg, "((linelhs)|(linerhs)|(lhs)|(rhs))(,icase)?(,reverse)?", AGCRE_REG_EXTENDED); + /* 12 2 3 3 4 4 5 516 6 7 7 */ + compiled = 1; + } + memset(¶ms, 0x0, sizeof(params)); + params.flags = AGCRE_REG_EXTENDED; + params.lhs = gap->lhs; + params.lhsnl = gap->lhsnl; + if (args) { + if (agcre_regexec(&arg, args, __arraycount(m), m, 0) != 0) { + return 0; + } + if (m[ARG_LINE_LHS].rm_so >= 0) { + rhs = 0; + from = line2off(gap, gap->lhsnl); + to = gap->lhs - from; + } else if (m[ARG_LINE_RHS].rm_so >= 0) { + rhs = 1; + from = 1; + to = gap_exec(gap, "line-rhs", NULL, 0); + } else if (m[ARG_LHS].rm_so >= 0) { + rhs = 0; + from = 0; + to = gap->lhs; + } else if (m[ARG_RHS].rm_so >= 0) { + rhs = 1; + from = 1; + to = gap->rhs; + } + if (m[ARG_ICASE].rm_so >= 0) { + params.flags |= AGCRE_REG_ICASE; + } + if (m[ARG_REVERSE].rm_so >= 0) { + params.reverse = 1; + } + } + return find_regex(gap, pat, ¶ms, rhs, from, to); +} Index: othersrc/external/bsd/elex/dist/gap.h diff -u /dev/null othersrc/external/bsd/elex/dist/gap.h:1.1 --- /dev/null Wed Jun 21 23:36:17 2023 +++ othersrc/external/bsd/elex/dist/gap.h Wed Jun 21 23:36:17 2023 @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2023 Alistair Crooks <a...@netbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef GAP_H_ +#define GAP_H_ 20230303 + +#include <inttypes.h> + +#ifdef LIB_NAMESPACE +#define GAP_CONCAT(x, y) x##y +#define GAP_NAMESPACE(x, y) GAP_CONCAT(x, y) +#define gap_t GAP_NAMESPACE(LIB_NAMESPACE, gap_t) +#define gap_new GAP_NAMESPACE(LIB_NAMESPACE, gap_new) +#define gap_dispose GAP_NAMESPACE(LIB_NAMESPACE, gap_dispose) +#define gap_exec GAP_NAMESPACE(LIB_NAMESPACE, gap_exec) +#define gap_exec_mem GAP_NAMESPACE(LIB_NAMESPACE, gap_exec_mem) +#define gap_search GAP_NAMESPACE(LIB_NAMESPACE, gap_search) +#endif + +struct gap_t; +typedef struct gap_t gap_t; + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +gap_t *gap_new(void); +int gap_dispose(gap_t **/*gap*/); +uint64_t gap_exec(gap_t */*gap*/, const char */*action*/, const void */*vs*/, uint64_t /*n*/); +char *gap_exec_mem(gap_t */*gap*/, const char */*action*/, uint64_t /*n*/, uint64_t */*size*/); +int gap_search(gap_t */*gap*/, const char */*params*/, const char */*pat*/, uint64_t /*mc*/, void */*mv*/); + +__END_DECLS + +#endif