diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2020-03-13 17:31:45 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2020-03-13 17:31:45 +0200 |
commit | c00b37f20d3a43ab6718275fe94951557158c96a (patch) | |
tree | eab81b14c3da082e0dce9b2a50c9168335d07607 /tests | |
parent | c047ed856d6d23137ef1df01c1297db36bad3f8c (diff) | |
download | wydawca-c00b37f20d3a43ab6718275fe94951557158c96a.tar.gz wydawca-c00b37f20d3a43ab6718275fe94951557158c96a.tar.bz2 |
Fix the push/pop dir test.
The test failed on machines where $(pwd -P) != $(pwd -L).
* tests/Makefile.am: Add cwdrepl.c
* tests/cwdrepl.c: New file.
* tests/pushdir.at: Use cwdrepl to filter the output.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/cwdrepl.c | 294 | ||||
-rw-r--r-- | tests/pushdir.at | 24 |
3 files changed, 307 insertions, 13 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index d258768..c45b0b9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -80,7 +80,7 @@ check-local: atconfig atlocal $(TESTSUITE) #installcheck-local: # $(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin -check_PROGRAMS = pushck bkupname +check_PROGRAMS = pushck bkupname cwdrepl AM_CPPFLAGS = \ @GRECS_INCLUDES@ \ -I$(top_srcdir)/include\ diff --git a/tests/cwdrepl.c b/tests/cwdrepl.c new file mode 100644 index 0000000..31cf305 --- /dev/null +++ b/tests/cwdrepl.c @@ -0,0 +1,294 @@ +/* + +NAME + + cwdrepl - replace occurrences of CWD with . + +SYNOPSIS + + COMMAND | cwdrepl [DIR REPL]... + +DESCRIPTION + + Some testcases operate programs that produce full file names as part + of their output. To make this output independent of the actual file + location, this tool replaces every occurrence of the current working + directory with a dot. Both logical (as given by the PWD environment + variable) and physical (as returned by getcwd(3)) locations are replaced. + + The same effect could have been achieved by using "pwd -P", "pwd -L" + and sed, but this would pose portability problems. + + Additionally, any number of DIR REPL pairs can be supplied in the command + line. Each pair instructs the tool to replace every occurrence of DIR + with REPL on output. Note that these pairs take precedence over the + default ones, so running "cwdrepl $PWD 'PWD'" will replace occurrences + of the logical current working directory name with the string PWD, instead + of the default dot. + +HISTORY + + 2017-06-07 The program appeared in the GNU mailutils testsuite (see + commit 453cd17f7a4be5ceaa8411a8a3ebd9fddd88df8e). + 2019-11-29 Make sure the longest possible match is replaced. + (ibid., commit 5ccef4cfd1eb3252430f04fa8418268a93ff8b08). + 2020-03-13 Port to standard libc for use in other projects. + +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <unistd.h> +#include <ctype.h> + +struct dirtrans { + char *dir; + size_t dirlen; + char const *trans; + ssize_t translen; + struct dirtrans *next; +}; + +struct dirtrans *dir_head, *dir_tail; +size_t dir_count; + +static int +dirtranscmp(struct dirtrans const *trans1, struct dirtrans const *trans2) +{ + size_t l1 = strlen (trans1->dir); + size_t l2 = strlen (trans2->dir); + if (l1 < l2) + return 1; + else if (l1 > l2) + return -1; + return strcmp(trans2->dir, trans1->dir); +} + +static struct dirtrans * +dirtrans_alloc(char const *dir, char const *trans) +{ + size_t dirlen = strlen(dir); + size_t translen = strlen(trans); + struct dirtrans *dt = malloc(sizeof *dt); + + assert(dt!=NULL); + + while (dirlen > 0 && dir[dirlen-1] == '/') + dirlen--; + + dt->dir = malloc(dirlen + 1); + assert(dt->dir != NULL); + memcpy(dt->dir, dir, dirlen); + dt->dir[dirlen] = 0; + dt->dirlen = dirlen; + dt->trans = trans; + dt->translen = translen; + dt->next = NULL; + + return dt; +} + +static void +dirtrans_free(struct dirtrans *dt) +{ + if (dt) { + free(dt->dir); + free(dt); + } +} + +static void +newdir(char const *dir, char const *trans) +{ + struct dirtrans *l, *m, *dt; + size_t i, n, count; + + dt = dirtrans_alloc(dir, trans); + + l = dir_head; + if (l) { + if (dirtranscmp(l, dt) > 0) { + l = NULL; + } else if (dirtranscmp(dir_tail, dt) < 0) { + l = dir_tail; + } else { + count = dir_count; + while (count) { + int c; + + n = count / 2; + for (m = l, i = 0; i < n; m = m->next, i++) + ; + + c = dirtranscmp(m, dt); + if (c == 0) { + dirtrans_free(dt); + return; + } else if (n == 0) { + break; + } else if (c < 0) { + l = m; + count -= n; + } else { + count = n; + } + } + } + } + + if (!l) { + if (dir_head == NULL) + dir_head = dir_tail = dt; + else { + dt->next = dir_head; + dir_head = dt; + } + } else { + while (l->next && dirtranscmp(l->next, dt) < 0) + l = l->next; + + dt->next = l->next; + l->next = dt; + if (!dt->next) + dir_tail = dt; + } + dir_count++; +} + +static char * +bufrealloc(char *buf, size_t *psize) +{ + size_t size = *psize; + + if (size == 0) { + size = 64; + buf = malloc(64); + } else { + if ((size_t) -1 / 3 * 2 <= size) { + errno = ENOMEM; + return NULL; + } + size += (size + 1) / 2; + buf = realloc(buf, size); + } + *psize = size; + return buf; +} + +static char * +getcwd_alloc(void) +{ + size_t size = 0; + char *buf = NULL; + char *p; + + do { + buf = bufrealloc(buf, &size); + if (!buf) { + perror("getcwd_alloc"); + abort(); + } + } while ((p = getcwd(buf, size)) == NULL && errno == ERANGE); + return buf; +} + +ssize_t +input(char **pbuf, size_t *psize) +{ + char *buf = *pbuf; + size_t size = *psize; + ssize_t off = 0; + + do { + if (size == 0 || off + 1 == size) { + buf = bufrealloc(buf, &size); + if (!buf) { + perror("input"); + abort(); + } + + } + if (!fgets(buf + off, size - off, stdin)) { + if (off == 0) + return -1; + break; + } + off += strlen(buf + off); + } while (buf[off - 1] != '\n'); + + buf[--off] = 0; + *pbuf = buf; + *psize = size; + + return off; +} + +static inline int +isbnd(int c) +{ + return iscntrl(c) || ispunct(c) || isspace(c); +} + +int +main(int argc, char **argv) +{ + size_t i; + char *buf = NULL; + size_t size = 0; + ssize_t n; + + assert(argc % 2 != 0); + for (i = 1; i < argc; i += 2) + newdir(argv[i], argv[i + 1]); + + newdir(getenv("PWD"), "."); + newdir (getcwd_alloc(), "."); + + while ((n = input(&buf, &size)) >= 0) { + struct dirtrans *dt; + + for (dt = dir_head; dt; dt = dt->next) { + size_t start = 0; + char *p; + + while ((p = strstr(buf + start, dt->dir))) { + if (isbnd(p[dt->dirlen])) { + size_t off = p - buf; + size_t rest = n - start; + ssize_t d = (ssize_t) dt->translen - dt->dirlen; + + if (d > 0) { + if (n + d + 1 > size) { + size = n + d + 1; + buf = realloc(buf, size); + assert(buf != NULL); + p = buf + off; + } + } + + memmove(p + dt->translen, p + dt->dirlen, + rest - dt->dirlen + 1); + memcpy(p, dt->trans, dt->translen); + + n += d; + start = off + dt->translen; + } else + start++; + } + } + fwrite(buf, n, 1, stdout); + putchar('\n'); + } + return 0; +} + +/* Local Variables: */ +/* mode: c */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/tests/pushdir.at b/tests/pushdir.at index 849edf2..7b061c5 100644 --- a/tests/pushdir.at +++ b/tests/pushdir.at @@ -20,20 +20,20 @@ AT_KEYWORDS([dir pushdir]) AT_CHECK([ install-sh -d a/b/c/d/e >/dev/null || exit 1 cwd=`pwd` -pushck a b c d e | sed 's|'"$cwd"'||' +pushck a b c d e | cwdrepl ], [0], -[+/a -+/a/b -+/a/b/c -+/a/b/c/d -+/a/b/c/d/e --/a/b/c/d/e --/a/b/c/d --/a/b/c --/a/b --/a -- +[+./a ++./a/b ++./a/b/c ++./a/b/c/d ++./a/b/c/d/e +-./a/b/c/d/e +-./a/b/c/d +-./a/b/c +-./a/b +-./a +-. ]) AT_CLEANUP |