1#! /bin/sh
2#
3# Copyright (C) 2006-2020 Free Software Foundation, Inc.
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 3 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 <https://www.gnu.org/licenses/>.
17#
18
19# This script determines the declared global symbols in a C header file.
20# Assumptions:
21# - The header files are in C, with only C89 comments.
22# - No use of macros with parameters.
23# - All global declarations are marked with 'extern'.
24# - All declarations end in ';' on the same line.
25# - Not more than one symbol is declared in a declaration.
26
27# This script requires GNU sed.
28
29# func_usage
30# outputs to stdout the --help usage message.
31func_usage ()
32{
33  echo "\
34Usage: declared.sh [OPTION]... < SOURCE.h
35
36Extracts the declared global symbols of a C header file.
37
38Options:
39      --help           print this help and exit
40      --version        print version information and exit
41
42Report bugs to <bruno@clisp.org>."
43}
44
45# func_version
46# outputs to stdout the --version message.
47func_version ()
48{
49  echo "declared.sh (GNU gnulib)"
50  echo "Copyright (C) 2020 Free Software Foundation, Inc.
51License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
52This is free software: you are free to change and redistribute it.
53There is NO WARRANTY, to the extent permitted by law."
54  echo "Written by" "Bruno Haible"
55}
56
57# func_fatal_error message
58# outputs to stderr a fatal error message, and terminates the program.
59func_fatal_error ()
60{
61  echo "declared.sh: *** $1" 1>&2
62  echo "declared.sh: *** Stop." 1>&2
63  exit 1
64}
65
66# Command-line option processing.
67while test $# -gt 0; do
68  case "$1" in
69    --help | --hel | --he | --h )
70      func_usage
71      exit 0 ;;
72   --version | --versio | --versi | --vers | --ver | --ve | --v )
73      func_version
74      exit 0 ;;
75    -- )      # Stop option processing
76      shift; break ;;
77    -* )
78      func_fatal_error "unrecognized option: $option"
79      ;;
80    * )
81      break ;;
82  esac
83done
84
85if test $# -gt 0; then
86  func_fatal_error "too many arguments"
87fi
88
89# A sed expression that removes ANSI C and ISO C99 comments.
90sed_remove_comments="
91/[/][/*]/{
92  ta
93  :a
94  s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)//.*,\\1,
95  te
96  s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*]\\([^*]\\|[*][^/*]\\)*[*][*]*/,\\1 ,
97  ta
98  /^\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*[/][*]/{
99    s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*].*,\\1 ,
100    tu
101    :u
102    n
103    s,^\\([^*]\\|[*][^/*]\\)*[*][*]*/,,
104    tv
105    s,^.*\$,,
106    bu
107    :v
108  }
109  :e
110}"
111
112# Check that 'sed' supports the kind of regular expressions used in
113# sed_remove_comments. The use of \| meaning alternation of basic regular
114# expressions is a GNU extension.
115sed_test='s,^\(\(a\|X\)*\)//.*,\1,'
116sed_result=`echo 'aaa//bcd' | sed -e "$sed_test"`
117test "$sed_result" = 'aaa' \
118  || func_fatal_error "The 'sed' program is not GNU sed. Try installing GNU sed."
119
120# A sed expression that joins 'extern' declarations that are broken over
121# several lines.
122sed_join_multiline_externs='
123/^extern [^;]*$/{
124  :a
125  N
126  s/\n/ /g
127  /^extern [^;]*$/{
128    ba
129  }
130}'
131
132# A sed expression that extracts the identifier of each 'extern' declaration.
133sed_extract_extern_declared='s/^extern [^()]*[ *]\([A-Za-z_][A-Za-z0-9_]*\) *[;(].*$/\1/p'
134
135sed -e "$sed_remove_comments" \
136  | sed -e "$sed_join_multiline_externs" \
137  | sed -n -e "$sed_extract_extern_declared"
138