xref: /Universal-ctags/misc/roundtrip (revision 9404b13c651ed9dcde38ec56cb9f91dd67e7e5fb)
1#!/bin/sh
2#
3#   Copyright (C) 2014 Masatake YAMATO
4#
5#   This program is free software; you can redistribute it and/or modify
6#   it under the terms of the GNU General Public License as published by
7#   the Free Software Foundation; either version 2 of the License, or
8#   (at your option) any later version.
9#
10#   This program is distributed in the hope that it will be useful,
11#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13#   GNU General Public License for more details.
14#
15#   You should have received a copy of the GNU General Public License
16#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18set -e
19
20# Avoid trouble with weird bytes on non-C locales
21export LC_ALL=C
22
23READTAGS=${1:-./readtags}
24UNITS=${2:-./Units}
25shift 2
26
27MINITRIP=
28while [ $# -gt 0 ]; do
29    case $1 in
30	--minitrip)
31	    MINITRIP=minitrip
32	    ;;
33	*)
34	    echo "Unexpected argument: $1" 1>&2
35	    exit 1
36	    ;;
37    esac
38    shift
39done
40
41s=0
42
43if ! [ -f "${READTAGS}" ]; then
44    echo "No such file: ${READTAGS}" 1>&2
45    exit 1
46fi
47
48if ! [ -x "${READTAGS}" ]; then
49    echo "Not an executable: ${READTAGS}" 1>&2
50    exit 1
51fi
52
53if ! [ -x "${UNITS}" ]; then
54    echo "Not such directory: ${UNITS}" 1>&2
55    exit 1
56fi
57
58
59# Expand CTags escape sequences (and keep the original, too)
60# See docs/format.rst
61expandEscapeSequences()
62{
63    sed -e '
64# early out if there is no escape sequence (common case)
65/\\/!b
66
67# loop until we handled all occurrences of \.
68# as it is not possible to do all replacements at once and we need not to
69# ever use the result of an replacement to perform another one, use two
70# reserved placeholders.
71:again
72    s/\\/__BACKSLASH__/
73    s/__BACKSLASH__\\/__LITBACKSLASH__/;	t again
74    s/__BACKSLASH__t/	/;			t again
75    s/__BACKSLASH__r/'"$(printf '\r')"'/;	t again
76    s/__BACKSLASH__n/\
77/;						t again
78    s/__BACKSLASH__a//;			t again
79    s/__BACKSLASH__b/'"$(printf '\b')"'/;	t again
80    s/__BACKSLASH__v//;			t again
81    s/__BACKSLASH__f//;			t again
82    s/__BACKSLASH__x01//;			t again
83    s/__BACKSLASH__x02//;			t again
84    s/__BACKSLASH__x03//;			t again
85    s/__BACKSLASH__x04//;			t again
86    s/__BACKSLASH__x05//;			t again
87    s/__BACKSLASH__x06//;			t again
88    s/__BACKSLASH__x07//;			t again
89    s/__BACKSLASH__x08//;			t again
90    s/__BACKSLASH__x09/	/;			t again
91    s/__BACKSLASH__x0[aA]/\
92/;						t again
93    s/__BACKSLASH__x0[bB]//;			t again
94    s/__BACKSLASH__x0[cC]//;			t again
95    s/__BACKSLASH__x0[dD]/'"$(printf '\r')"'/;	t again
96    s/__BACKSLASH__x0[eE]//;			t again
97    s/__BACKSLASH__x0[fF]//;			t again
98    s/__BACKSLASH__x10//;			t again
99    s/__BACKSLASH__x11//;			t again
100    s/__BACKSLASH__x12//;			t again
101    s/__BACKSLASH__x13//;			t again
102    s/__BACKSLASH__x14//;			t again
103    s/__BACKSLASH__x15//;			t again
104    s/__BACKSLASH__x16//;			t again
105    s/__BACKSLASH__x17//;			t again
106    s/__BACKSLASH__x18//;			t again
107    s/__BACKSLASH__x19//;			t again
108    s/__BACKSLASH__x1[aA]//;			t again
109    s/__BACKSLASH__x1[bB]//;			t again
110    s/__BACKSLASH__x1[cC]//;			t again
111    s/__BACKSLASH__x1[dD]//;			t again
112    s/__BACKSLASH__x1[eE]//;			t again
113    s/__BACKSLASH__x1[fF]//;			t again
114    s/__BACKSLASH__x21/!/;			t again
115    s/__BACKSLASH__x20/ /;			t again
116    s/__BACKSLASH__x7[fF]//;			t again
117    /\\/b again
118
119# replace lonely "\"es
120s/__BACKSLASH__/\\/g
121# replace literal "\"es ("\\" from the input)
122s/__LITBACKSLASH__/\\/g
123'
124}
125
126# disable path expansion, because we don't need it and it's applied on the
127# result of the commands used to loop on, and we don't want that.
128set -f
129# remove space from IFS as it's valid in tag names
130OLD_IFS="$IFS"
131IFS='
132'
133
134ntagfiles=0
135ntrips=0
136tagfiles=$(find "$UNITS" -name expected.tags)
137for tags in $tagfiles; do
138    ntagfiles=$(expr $ntagfiles + 1)
139    dir=$(dirname "$tags")
140    if [ -n "$MINITRIP" -a ! -e "$dir/$MINITRIP" ]; then
141	continue
142    fi
143    ntrips=$(expr $ntrips + 1)
144
145    tagnames=$(sed -e 's/^\([^	]*\)	.*/\1/' "$tags")
146    for name in $tagnames; do
147	# Yes, there is a reason for this craziness.  We need to properly
148	# handle embedded newlines (expanded from "\n"), including trailing
149	# ones the shell would strip automatically.  To work around this, we
150	# add a dummy character at the end to inhibit stripping, and then
151	# remove it, plus the extra newline, using variable substitutions.
152	# Note: we use "printf '%s\n'" instead of "echo" because Dash's "echo"
153	# unconditionally expands some sequences, like "\t" and alike.
154	t="$(printf '%s\n' "$name" | expandEscapeSequences; printf _)"
155	t="${t%
156_}"
157	if [ 1 -gt $("${READTAGS}" -t "$tags" - "$t" | wc -l) ]; then
158	    printf 'FAILED: "%s" -t "%s" - "%s"\n' "${READTAGS}" "$tags" "$t"
159	    printf '	The raw tag name was "%s"\n' "$name"
160	    s=1
161	fi
162    done
163done
164
165IFS="$OLD_IFS"
166
167note=
168if [ -n "$MINITRIP" ]; then
169    note="[$MINITRIP]"
170fi
171printf "%s/%s%s...%d\n" "$ntrips" "$ntagfiles" "$note" "$s"
172
173exit $s
174