Skip to content

Commit

Permalink
Squashed 'libreadtags/' changes from 53b7e27ab..4eee45ec6
Browse files Browse the repository at this point in the history
4eee45ec6 Merge pull request universal-ctags#48 from masatake/unescaping-input-field-only-when-slash
15b9503ba Read the input field with unescaping if TAG_OUTPUT_MODE is "u-ctags" and TAG_OUTPUT_FILESEP is "slash"
93e0c73d4 Merge pull request universal-ctags#47 from masatake/unescaping-input-field
687f3d9ad Read the input field with unescaping if TAG_OUTPUT_MODE is "u-ctags"
3517d2e68 Use smaller data types for some members in tagFile
93bdb3226 Add a helper function for unescaping
3fb676fde Make macros for comparing field values reusable

git-subtree-dir: libreadtags
git-subtree-split: 4eee45ec6f4fedb506a9a14b33e97904ec1f09d8
  • Loading branch information
masatake committed Dec 17, 2022
1 parent 15e0582 commit 4f606bd
Show file tree
Hide file tree
Showing 16 changed files with 768 additions and 68 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,8 @@ tests/test-api-tagsSetSortType
tests/test-fix-large-tags
tests/test-fix-null-deref
tests/test-fix-unescaping
tests/test-fix-unescaping-input-fields
tests/test-fix-unescaping-input-fields-exuberant
tests/test-fix-unescaping-input-fields-no-mode
tests/test-fix-unescaping-input-fields-backslash
tests/test-fix-unescaping-input-fields-no-filesep
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Version ???

- read input fields, values at the second column in a tag file, with
unescaping if !_TAG_OUTPUT_MODE is "u-ctags" and
!_TAG_OUTPUT_FILESEP is "slash" in the tag file.

- LT_VERSION ?:?:?

# Version 0.2.1

- use "m" mode flag of fopen only when compiling with glibc 2.3 or higher.
Expand Down
88 changes: 63 additions & 25 deletions readtags.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ typedef off_t rt_off_t;
/* Information about current tag file */
struct sTagFile {
/* has the file been opened and this structure initialized? */
short initialized;
unsigned char initialized;
/* format of tag file */
short format;
unsigned char format;
/* 1 "u-ctags" is set to !_TAG_OUTPUT_MODE pseudo tag
* and "slash" is set to !_TAG_OUTPUT_FILESEP
* pseudo tag in the tags file. */
unsigned char inputUCtagsMode;
/* how is the tag file sorted? */
tagSortType sortMethod;
/* pointer to file structure */
Expand Down Expand Up @@ -519,26 +523,15 @@ static unsigned int countContinuousBackslashesBackward(const char *from,
return counter;
}

static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err)
/* When unescaping, the input string becomes shorter.
* e.g. \t occupies two bytes on the tag file.
* It is converted to 0x9 and occupies one byte.
* memmove called here for shortening the line
* buffer. */
static char *unescapeInPlace (char *q, char **tab, size_t *p_len)
{
int i;
char *p = file->line.buffer;
size_t p_len = strlen (p);
char *tab = strchr (p, TAB);
char *p = q;

memset(entry, 0, sizeof(*entry));

entry->name = p;
if (tab != NULL)
{
*tab = '\0';
}

/* When unescaping, the input string becomes shorter.
* e.g. \t occupies two bytes on the tag file.
* It is converted to 0x9 and occupies one byte.
* memmove called here for shortening the line
* buffer. */
while (*p != '\0')
{
const char *next = p;
Expand All @@ -547,21 +540,50 @@ static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err)

*p = (char) ch;
p++;
p_len -= skip;
*p_len -= skip;
if (skip > 1)
{
/* + 1 is for moving the area including the last '\0'. */
memmove (p, next, p_len + 1);
if (tab)
tab -= skip - 1;
memmove (p, next, *p_len + 1);
if (*tab)
*tab -= skip - 1;
}
}

return p;
}

static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err)
{
int i;
char *p = file->line.buffer;
size_t p_len = strlen (p);
char *tab = strchr (p, TAB);

memset(entry, 0, sizeof(*entry));

entry->name = p;
if (tab != NULL)
{
*tab = '\0';
}

p = unescapeInPlace (p, &tab, &p_len);

if (tab != NULL)
{
p = tab + 1;
entry->file = p;
tab = strchr (p, TAB);
if (file->inputUCtagsMode)
{
if (tab != NULL)
{
*tab = '\0';
}
p = unescapeInPlace (p, &tab, &p_len);
}

if (tab != NULL)
{
int fieldsPresent;
Expand Down Expand Up @@ -670,6 +692,8 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info)
int err = 0;
tagResult result = TagSuccess;
const size_t prefixLength = strlen (PseudoTagPrefix);
int tag_output_mode_u_ctags = 0;
int tag_output_filesep_slash = 0;

info->file.format = 1;
info->file.sort = TAG_UNSORTED;
Expand Down Expand Up @@ -717,7 +741,7 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info)
err = TagErrnoUnexpectedFormat;
break;
}
file->format = (short) m;
file->format = (unsigned char) m;
}
else if (strcmp (key, "TAG_PROGRAM_AUTHOR") == 0)
{
Expand Down Expand Up @@ -755,6 +779,16 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info)
break;
}
}
else if (strcmp (key, "TAG_OUTPUT_MODE") == 0)
{
if (strcmp (value, "u-ctags") == 0)
tag_output_mode_u_ctags = 1;
}
else if (strcmp (key, "TAG_OUTPUT_FILESEP") == 0)
{
if (strcmp (value, "slash") == 0)
tag_output_filesep_slash = 1;
}

info->file.format = file->format;
info->file.sort = file->sortMethod;
Expand All @@ -764,6 +798,10 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info)
info->program.version = file->program.version;
}
}

if (tag_output_mode_u_ctags && tag_output_filesep_slash)
file->inputUCtagsMode = 1;

if (fsetpos (file->fp, &startOfLine) < 0)
err = errno;

Expand Down
32 changes: 31 additions & 1 deletion tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ TESTS = \
test-fix-unescaping \
test-fix-null-deref \
test-fix-large-tags \
test-fix-unescaping-input-fields \
test-fix-unescaping-input-fields-exuberant \
test-fix-unescaping-input-fields-no-mode \
test-fix-unescaping-input-fields-backslash \
test-fix-unescaping-input-fields-no-filesep \
\
$(NULL)

Expand All @@ -27,10 +32,15 @@ check_PROGRAMS = \
test-fix-unescaping \
test-fix-null-deref \
test-fix-large-tags \
test-fix-unescaping-input-fields \
test-fix-unescaping-input-fields-exuberant \
test-fix-unescaping-input-fields-no-mode \
test-fix-unescaping-input-fields-backslash \
test-fix-unescaping-input-fields-no-filesep \
\
$(NULL)

EXTRA_DIST =
EXTRA_DIST = test-fields.h

AM_CPPFLAGS = -I $(top_srcdir) -DTAG_NO_COMPAT_SORT_TYPE
AM_CFLAGS = $(GCOV_CFLAGS)
Expand Down Expand Up @@ -90,3 +100,23 @@ EXTRA_DIST += null-deref.tags

test_fix_large_tags = test-fix-large-tags.c
test_fix_large_tags_DEPENDENCIES = $(DEPS)

test_fix_unescaping_input_fields = test-fix-unescaping-input-fields.c
test_fix_unescaping_input_fields_DEPENDENCIES = $(DEPS)
EXTRA_DIST += unescaping-input-fields.tags

test_fix_unescaping_input_fields_exuberant = test-fix-unescaping-input-fields-exuberant.c
test_fix_unescaping_input_fields_exuberant_DEPENDENCIES = $(DEPS)
EXTRA_DIST += unescaping-input-fields-exuberant.tags

test_fix_unescaping_input_fields_no_mode = test-fix-unescaping-input-fields-no-mode.c
test_fix_unescaping_input_fields_no_mode_DEPENDENCIES = $(DEPS)
EXTRA_DIST += unescaping-input-fields-no-mode.tags

test_fix_unescaping_input_fields_backslash = test-fix-unescaping-input-fields-backslash.c
test_fix_unescaping_input_fields_backslash_DEPENDENCIES = $(DEPS)
EXTRA_DIST += unescaping-input-fields-backslash.tags

test_fix_unescaping_input_fields_no_filesep = test-fix-unescaping-input-fields-no-filesep.c
test_fix_unescaping_input_fields_no_filesep_DEPENDENCIES = $(DEPS)
EXTRA_DIST += unescaping-input-fields-no-filesep.tags
64 changes: 64 additions & 0 deletions tests/test-fields.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2022, Masatake YAMATO
*
* This source code is released into the public domain.
*
* Testing the fix for handling unescaping
*/

#ifndef TEST_FIELDS_H
#define TEST_FIELDS_H

#define NEXT() \
r = tagsNext (t, &e); \
if (r != TagSuccess) \
{ \
fprintf (stderr, "error in tagsNext\n"); \
return 1; \
} \
do {} while (0)

#define CHECK(EXP,FIELD) \
if (strcmp (EXP, e.FIELD) != 0) \
{ \
fprintf (stderr, "unexpected " #FIELD "(expected: %s, actual: %s) in tagsFirst\n", \
EXP, e.FIELD); \
return 1; \
} \
do {} while (0)

#define CHECK_X(FIELD,EXP) \
{ \
unsigned short i; \
for (i = 0; i < e.fields.count; i++) \
{ \
if (strcmp (e.fields.list [i].key, FIELD) == 0) \
{ \
if (strcmp(e.fields.list [i].value, EXP) == 0) \
break; \
else \
{ \
fprintf (stderr, "unexpected " #FIELD "(expected: %s, actual: %s) in tagsFirst\n", \
EXP, e.fields.list [i].value); \
return 1; \
} \
} \
} \
if (i >= e.fields.count) \
{ \
fprintf (stderr, "unexpected " #FIELD " field is not found in tagsFirst (count: %u)\n", \
e.fields.count); \
return 1; \
} \
}

#define CHECK3(NAME,FILE,PAT) \
CHECK ((NAME), name); \
CHECK ((FILE), file); \
CHECK ((PAT), address.pattern)

#define NEXT_CHECK3(NAME,FILE,PAT) \
NEXT (); \
CHECK3 (NAME,FILE,PAT)

#endif /* !TEST_FIELDS_H */
94 changes: 94 additions & 0 deletions tests/test-fix-unescaping-input-fields-backslash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2022, Masatake YAMATO
*
* This source code is released into the public domain.
*
* Testing the fix for handling unescaping
*/

#include "readtags.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "test-fields.h"


#define CHECK3(NAME,FILE,PAT) \
CHECK ((NAME), name); \
CHECK ((FILE), file); \
CHECK ((PAT), address.pattern)

#define NEXT_CHECK3(NAME,FILE,PAT) \
NEXT (); \
CHECK3 (NAME,FILE,PAT)

int
main (void)
{
char *srcdir = getenv ("srcdir");
if (srcdir)
{
if (chdir (srcdir) == -1)
{
perror ("chdir");
return 99;
}
}

tagFile *t;
tagFileInfo info;

const char *tags0 = "./unescaping-input-fields-backslash.tags";
t = tagsOpen (tags0, &info);
if (t == NULL
|| info.status.opened == 0)
{
fprintf (stderr, "unexpected result (t: %p, opened: %d)\n",
t, info.status.opened);
return 1;
}
fprintf (stderr, "ok\n");

tagEntry e;
tagResult r;

r = tagsFirst (t, &e);
if (r != TagSuccess)
{
fprintf (stderr, "error in tagsFirst\n");
return 1;
}

CHECK3 ("tab0", "\\tabc", "/^tab0$/");
NEXT_CHECK3 ("tab1", "a\\tbc", "/^tab1$/");
NEXT_CHECK3 ("tab2", "ab\\tc", "/^tab2$/");
NEXT_CHECK3 ("tab3", "abc\\t", "/^tab3$/");
NEXT_CHECK3 ("tab4", "\\\\abc", "/^tab4$/");
NEXT_CHECK3 ("tab5", "a\\\\bc", "/^tab5$/");
NEXT_CHECK3 ("tab6", "ab\\\\c", "/^tab6$/");
NEXT_CHECK3 ("tab7", "abc\\\\", "/^tab7$/");
NEXT_CHECK3 ("tab8", "\\nabc", "/^tab8$/");
NEXT_CHECK3 ("tab9", "a\\nbc", "/^tab9$/");
NEXT_CHECK3 ("taba", "ab\\nc", "/^taba$/");
NEXT_CHECK3 ("tabb", "abc\\n", "/^tabb$/");
NEXT_CHECK3 ("tabc", "\\n\\\\abc", "/^tabc$/");
NEXT_CHECK3 ("tabd", "\\\\\\nabc", "/^tabd$/");
NEXT_CHECK3 ("tabe", "a\\n\\\\bc", "/^tabe$/");
NEXT_CHECK3 ("tabf", "a\\\\\\nbc", "/^tabf$/");
NEXT_CHECK3 ("tabg", "abc\\n\\\\", "/^tabg$/");
NEXT_CHECK3 ("tabh", "abc\\\\\\n", "/^tabh$/");
NEXT_CHECK3 ("tabi", "\\t\\\\\\n", "/^tabi$/");
NEXT_CHECK3 ("tabj", "ab\\t\\\\\\nc", "/^tabj$/");

r = tagsClose(t);
if (r != TagSuccess)
{
fprintf (stderr, "error in tagsClose\n");
return 1;
}

return 0;
}
Loading

0 comments on commit 4f606bd

Please sign in to comment.