Skip to content

Commit 93e0c73

Browse files
authored
Merge pull request #47 from masatake/unescaping-input-field
Unescaping input field only when !_TAG_OUTPUT_MODE is "u-ctags" See universal-ctags/ctags#3559 (comment) especially universal-ctags/ctags#3559 (comment) .
2 parents 53b7e27 + 687f3d9 commit 93e0c73

12 files changed

Lines changed: 496 additions & 68 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,6 @@ tests/test-api-tagsSetSortType
4141
tests/test-fix-large-tags
4242
tests/test-fix-null-deref
4343
tests/test-fix-unescaping
44+
tests/test-fix-unescaping-input-fields
45+
tests/test-fix-unescaping-input-fields-exuberant
46+
tests/test-fix-unescaping-input-fields-no-mode

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# Version ???
2+
3+
- read input fields, values at the second column in a tag file, with
4+
unescaping if !_TAG_OUTPUT_MODE in the tag file is "u-ctags".
5+
6+
- LT_VERSION ?:?:?
7+
18
# Version 0.2.1
29

310
- use "m" mode flag of fopen only when compiling with glibc 2.3 or higher.

readtags.c

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,12 @@ typedef off_t rt_off_t;
4242
/* Information about current tag file */
4343
struct sTagFile {
4444
/* has the file been opened and this structure initialized? */
45-
short initialized;
45+
unsigned char initialized;
4646
/* format of tag file */
47-
short format;
47+
unsigned char format;
48+
/* 1 "u-ctags" is set to !_TAG_OUTPUT_MODE pseudo tag
49+
* in the tags file. */
50+
unsigned char inputUCtagsMode;
4851
/* how is the tag file sorted? */
4952
tagSortType sortMethod;
5053
/* pointer to file structure */
@@ -519,26 +522,15 @@ static unsigned int countContinuousBackslashesBackward(const char *from,
519522
return counter;
520523
}
521524

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

529-
memset(entry, 0, sizeof(*entry));
530-
531-
entry->name = p;
532-
if (tab != NULL)
533-
{
534-
*tab = '\0';
535-
}
536-
537-
/* When unescaping, the input string becomes shorter.
538-
* e.g. \t occupies two bytes on the tag file.
539-
* It is converted to 0x9 and occupies one byte.
540-
* memmove called here for shortening the line
541-
* buffer. */
542534
while (*p != '\0')
543535
{
544536
const char *next = p;
@@ -547,21 +539,50 @@ static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err)
547539

548540
*p = (char) ch;
549541
p++;
550-
p_len -= skip;
542+
*p_len -= skip;
551543
if (skip > 1)
552544
{
553545
/* + 1 is for moving the area including the last '\0'. */
554-
memmove (p, next, p_len + 1);
555-
if (tab)
556-
tab -= skip - 1;
546+
memmove (p, next, *p_len + 1);
547+
if (*tab)
548+
*tab -= skip - 1;
557549
}
558550
}
559551

552+
return p;
553+
}
554+
555+
static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err)
556+
{
557+
int i;
558+
char *p = file->line.buffer;
559+
size_t p_len = strlen (p);
560+
char *tab = strchr (p, TAB);
561+
562+
memset(entry, 0, sizeof(*entry));
563+
564+
entry->name = p;
565+
if (tab != NULL)
566+
{
567+
*tab = '\0';
568+
}
569+
570+
p = unescapeInPlace (p, &tab, &p_len);
571+
560572
if (tab != NULL)
561573
{
562574
p = tab + 1;
563575
entry->file = p;
564576
tab = strchr (p, TAB);
577+
if (file->inputUCtagsMode)
578+
{
579+
if (tab != NULL)
580+
{
581+
*tab = '\0';
582+
}
583+
p = unescapeInPlace (p, &tab, &p_len);
584+
}
585+
565586
if (tab != NULL)
566587
{
567588
int fieldsPresent;
@@ -717,7 +738,7 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info)
717738
err = TagErrnoUnexpectedFormat;
718739
break;
719740
}
720-
file->format = (short) m;
741+
file->format = (unsigned char) m;
721742
}
722743
else if (strcmp (key, "TAG_PROGRAM_AUTHOR") == 0)
723744
{
@@ -755,6 +776,11 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info)
755776
break;
756777
}
757778
}
779+
else if (strcmp (key, "TAG_OUTPUT_MODE") == 0)
780+
{
781+
if (strcmp (value, "u-ctags") == 0)
782+
file->inputUCtagsMode = 1;
783+
}
758784

759785
info->file.format = file->format;
760786
info->file.sort = file->sortMethod;

tests/Makefile.am

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ TESTS = \
1111
test-fix-unescaping \
1212
test-fix-null-deref \
1313
test-fix-large-tags \
14+
test-fix-unescaping-input-fields \
15+
test-fix-unescaping-input-fields-exuberant \
16+
test-fix-unescaping-input-fields-no-mode \
1417
\
1518
$(NULL)
1619

@@ -27,10 +30,13 @@ check_PROGRAMS = \
2730
test-fix-unescaping \
2831
test-fix-null-deref \
2932
test-fix-large-tags \
33+
test-fix-unescaping-input-fields \
34+
test-fix-unescaping-input-fields-exuberant \
35+
test-fix-unescaping-input-fields-no-mode \
3036
\
3137
$(NULL)
3238

33-
EXTRA_DIST =
39+
EXTRA_DIST = test-fields.h
3440

3541
AM_CPPFLAGS = -I $(top_srcdir) -DTAG_NO_COMPAT_SORT_TYPE
3642
AM_CFLAGS = $(GCOV_CFLAGS)
@@ -90,3 +96,15 @@ EXTRA_DIST += null-deref.tags
9096

9197
test_fix_large_tags = test-fix-large-tags.c
9298
test_fix_large_tags_DEPENDENCIES = $(DEPS)
99+
100+
test_fix_unescaping_input_fields = test-fix-unescaping-input-fields.c
101+
test_fix_unescaping_input_fields_DEPENDENCIES = $(DEPS)
102+
EXTRA_DIST += unescaping-input-fields.tags
103+
104+
test_fix_unescaping_input_fields_exuberant = test-fix-unescaping-input-fields-exuberant.c
105+
test_fix_unescaping_input_fields_exuberant_DEPENDENCIES = $(DEPS)
106+
EXTRA_DIST += unescaping-input-fields-exuberant.tags
107+
108+
test_fix_unescaping_input_fields_no_mode = test-fix-unescaping-input-fields-no-mode.c
109+
test_fix_unescaping_input_fields_no_mode_DEPENDENCIES = $(DEPS)
110+
EXTRA_DIST += unescaping-input-fields-no-mode.tags

tests/test-fields.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2022, Masatake YAMATO
3+
*
4+
* This source code is released into the public domain.
5+
*
6+
* Testing the fix for handling unescaping
7+
*/
8+
9+
#ifndef TEST_FIELDS_H
10+
#define TEST_FIELDS_H
11+
12+
#define NEXT() \
13+
r = tagsNext (t, &e); \
14+
if (r != TagSuccess) \
15+
{ \
16+
fprintf (stderr, "error in tagsNext\n"); \
17+
return 1; \
18+
} \
19+
do {} while (0)
20+
21+
#define CHECK(EXP,FIELD) \
22+
if (strcmp (EXP, e.FIELD) != 0) \
23+
{ \
24+
fprintf (stderr, "unexpected " #FIELD "(expected: %s, actual: %s) in tagsFirst\n", \
25+
EXP, e.FIELD); \
26+
return 1; \
27+
} \
28+
do {} while (0)
29+
30+
#define CHECK_X(FIELD,EXP) \
31+
{ \
32+
unsigned short i; \
33+
for (i = 0; i < e.fields.count; i++) \
34+
{ \
35+
if (strcmp (e.fields.list [i].key, FIELD) == 0) \
36+
{ \
37+
if (strcmp(e.fields.list [i].value, EXP) == 0) \
38+
break; \
39+
else \
40+
{ \
41+
fprintf (stderr, "unexpected " #FIELD "(expected: %s, actual: %s) in tagsFirst\n", \
42+
EXP, e.fields.list [i].value); \
43+
return 1; \
44+
} \
45+
} \
46+
} \
47+
if (i >= e.fields.count) \
48+
{ \
49+
fprintf (stderr, "unexpected " #FIELD " field is not found in tagsFirst (count: %u)\n", \
50+
e.fields.count); \
51+
return 1; \
52+
} \
53+
}
54+
55+
#define CHECK3(NAME,FILE,PAT) \
56+
CHECK ((NAME), name); \
57+
CHECK ((FILE), file); \
58+
CHECK ((PAT), address.pattern)
59+
60+
#define NEXT_CHECK3(NAME,FILE,PAT) \
61+
NEXT (); \
62+
CHECK3 (NAME,FILE,PAT)
63+
64+
#endif /* !TEST_FIELDS_H */
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2022, Masatake YAMATO
3+
*
4+
* This source code is released into the public domain.
5+
*
6+
* Testing the fix for handling unescaping
7+
*/
8+
9+
#include "readtags.h"
10+
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
#include <unistd.h>
15+
16+
#include "test-fields.h"
17+
18+
19+
int
20+
main (void)
21+
{
22+
char *srcdir = getenv ("srcdir");
23+
if (srcdir)
24+
{
25+
if (chdir (srcdir) == -1)
26+
{
27+
perror ("chdir");
28+
return 99;
29+
}
30+
}
31+
32+
tagFile *t;
33+
tagFileInfo info;
34+
35+
const char *tags0 = "./unescaping-input-fields-exuberant.tags";
36+
t = tagsOpen (tags0, &info);
37+
if (t == NULL
38+
|| info.status.opened == 0)
39+
{
40+
fprintf (stderr, "unexpected result (t: %p, opened: %d)\n",
41+
t, info.status.opened);
42+
return 1;
43+
}
44+
fprintf (stderr, "ok\n");
45+
46+
tagEntry e;
47+
tagResult r;
48+
49+
r = tagsFirst (t, &e);
50+
if (r != TagSuccess)
51+
{
52+
fprintf (stderr, "error in tagsFirst\n");
53+
return 1;
54+
}
55+
56+
CHECK3 ("tab0", "\\tabc", "/^tab0$/");
57+
NEXT_CHECK3 ("tab1", "a\\tbc", "/^tab1$/");
58+
NEXT_CHECK3 ("tab2", "ab\\tc", "/^tab2$/");
59+
NEXT_CHECK3 ("tab3", "abc\\t", "/^tab3$/");
60+
NEXT_CHECK3 ("tab4", "\\\\abc", "/^tab4$/");
61+
NEXT_CHECK3 ("tab5", "a\\\\bc", "/^tab5$/");
62+
NEXT_CHECK3 ("tab6", "ab\\\\c", "/^tab6$/");
63+
NEXT_CHECK3 ("tab7", "abc\\\\", "/^tab7$/");
64+
NEXT_CHECK3 ("tab8", "\\nabc", "/^tab8$/");
65+
NEXT_CHECK3 ("tab9", "a\\nbc", "/^tab9$/");
66+
NEXT_CHECK3 ("taba", "ab\\nc", "/^taba$/");
67+
NEXT_CHECK3 ("tabb", "abc\\n", "/^tabb$/");
68+
NEXT_CHECK3 ("tabc", "\\n\\\\abc", "/^tabc$/");
69+
NEXT_CHECK3 ("tabd", "\\\\\\nabc", "/^tabd$/");
70+
NEXT_CHECK3 ("tabe", "a\\n\\\\bc", "/^tabe$/");
71+
NEXT_CHECK3 ("tabf", "a\\\\\\nbc", "/^tabf$/");
72+
NEXT_CHECK3 ("tabg", "abc\\n\\\\", "/^tabg$/");
73+
NEXT_CHECK3 ("tabh", "abc\\\\\\n", "/^tabh$/");
74+
NEXT_CHECK3 ("tabi", "\\t\\\\\\n", "/^tabi$/");
75+
NEXT_CHECK3 ("tabj", "ab\\t\\\\\\nc", "/^tabj$/");
76+
77+
r = tagsClose(t);
78+
if (r != TagSuccess)
79+
{
80+
fprintf (stderr, "error in tagsClose\n");
81+
return 1;
82+
}
83+
84+
return 0;
85+
}

0 commit comments

Comments
 (0)