1#!/bin/sh
2#
3# SYNOPSIS
4#	fixproto TARGET-DIR SOURCE-DIR-ALL SOURCE-DIR-STD
5#
6# COPYRIGHT
7#	Copyright (C) 1993, 1994, 1997, 1998, 2002, 2003
8#       Free Software Foundation, Inc.
9#	This file is part of GCC.
10#
11#	GCC is free software; you can redistribute it and/or modify
12#	it under the terms of the GNU General Public License as published by
13#	the Free Software Foundation; either version 2, or (at your option)
14#	any later version.
15#
16#	GCC is distributed in the hope that it will be useful,
17#	but WITHOUT ANY WARRANTY; without even the implied warranty of
18#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19#	GNU General Public License for more details.
20#
21#	You should have received a copy of the GNU General Public License
22#	along with GCC; see the file COPYING.  If not, write to
23#	the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24#	Boston, MA 02110-1301, USA.
25#
26# DESCRIPTION
27#	Adjunct script for GCC to populate a directory with ANSI,
28#	Posix.1, and C++ compatible header files.
29#
30#	Each file found under SOURCE-DIR-ALL is analyzed and "fixed."
31#       Only standard ANSI/POSIX files found under SOURCE-DIR-STD
32#       are analyzed and "fixed."
33#	The SOURCE-DIRs are searched in order; a file found
34#	under multiple SOURCE-DIRs is only handled for the first one.
35#
36# STRATEGY
37#       Each include file is fed through cpp, and the scan-decls program
38#	parses it, and emits any found function declarations.
39#	The fix-header program analyzes the scan-decls output,
40#	together with the original include file, and writes a "fixed"
41#	include file, if needed.
42#
43#	The comment at the beginning of fix-header.c lists specifically
44#	what kind of changes are made.
45#
46# NOTE
47#	Some file space will be wasted, because the original header
48#	files are copied.  An earlier version just included the original
49#	by "reference", using GNU cpp's #include_next mechanism.
50#	This is currently not done, partly because #include_next is
51#	fragile (susceptible to version incompatibilities, and depends
52#	and GCC-specific features), and partly for performance reasons.
53#
54# AUTHORS
55#	Ron Guilmette (rfg@netcom.com) (original idea and code)
56#	Per Bothner (bothner@cygnus.com) (major re-write)
57
58dirname=`echo "$0" | sed 's,^[^/]*$,.,;s,//*[^/]*$,,'`
59progname=`echo "$0" | sed 's,.*/,,'`
60original_dir=`${PWDCMD-pwd}`
61FIX_HEADER=${FIX_HEADER-$original_dir/fix-header}
62DEFINES="-D__STDC__=0 -D__cplusplus ${FIXPROTO_DEFINES}"
63
64if mkdir -p . 2> /dev/null; then
65  # Great, mkdir accepts -p
66  mkinstalldirs="mkdir -p"
67else
68  # We expect mkinstalldirs to be passed in the environment.
69  # If it is not, assume it is in the directory that contains this script.
70  mkinstalldirs=${mkinstalldirs-"/bin/sh $dirname/mkinstalldirs"}
71  if $mkinstalldirs . 2> /dev/null; then
72    :
73  else
74    # But, in case of failure, fallback to plain mkdir, and hope it works
75    mkinstalldirs=mkdir
76  fi
77fi
78
79if [ `echo $1 | wc -w` = 0 ] ; then
80  echo $progname\: usage\: $progname target-dir \[ source-dir \.\.\. \]
81  exit 1
82fi
83
84std_files="ctype.h dirent.h errno.h curses.h fcntl.h grp.h locale.h math.h pwd.h setjmp.h signal.h stdio.h stdlib.h string.h sys/socket.h sys/stat.h sys/times.h sys/resource.h sys/utsname.h sys/wait.h tar.h termios.h time.h unistd.h utime.h"
85
86rel_target_dir=$1
87# All files in $src_dir_all (normally same as $rel_target_dir) are
88# processed.
89src_dir_all=$2
90# In $src_dir_std (normally same as /usr/include), only the
91# "standard" ANSI/POSIX files listed in $std_files are processed.
92src_dir_std=$3
93
94case $rel_target_dir in
95  /* | [A-Za-z]:[\\/]*)
96     abs_target_dir=$rel_target_dir
97     ;;
98  *)
99     abs_target_dir=$original_dir/$rel_target_dir
100     ;;
101esac
102
103# Determine whether this system has symbolic links.
104if ln -s X $rel_target_dir/ShouldNotExist 2>/dev/null; then
105  rm -f $rel_target_dir/ShouldNotExist
106  LINKS=true
107elif ln -s X /tmp/ShouldNotExist 2>/dev/null; then
108  rm -f /tmp/ShouldNotExist
109  LINKS=true
110else
111  LINKS=false
112fi
113
114if [ \! -d $abs_target_dir ] ; then
115  echo $progname\: creating directory $rel_target_dir
116  $mkinstalldirs $abs_target_dir
117fi
118
119echo $progname\: populating \`$rel_target_dir\'
120
121include_path=""
122
123if [ `echo $* | wc -w` != 0 ] ; then
124  for rel_source_dir in $src_dir_all $src_dir_std; do
125     case $rel_source_dir in
126       /* | [A-Za-z]:[\\/]*)
127         abs_source_dir=$rel_source_dir
128         ;;
129       *)
130         abs_source_dir=$original_dir/$rel_source_dir
131         ;;
132     esac
133    include_path="$include_path -I$abs_source_dir"
134  done
135fi
136
137done_dirs=""
138subdirs_made=""
139echo "" >fixproto.list
140
141for code in ALL STD ; do
142
143  subdirs="."
144
145  case $code in
146    ALL)
147      rel_source_dir=$src_dir_all
148
149      dirs="."
150      levels=2
151      while $LINKS && test -n "$dirs" -a $levels -gt 0
152      do
153        levels=`expr $levels - 1`
154	newdirs=
155	for d in $dirs ; do
156	  # Find all directories under $d, relative to $d, excluding $d itself.
157	  # Assume directory names ending in CC or containing ++ are
158	  # for C++, so skip those.
159	  subdirs="$subdirs "`cd $rel_source_dir/$d; find . -type d -print | \
160	           sed -e '/^\.$/d' -e "s|^\./|${d}/|" -e 's|^\./||' \
161		     -e '/CC$/d' -e '/[+][+]/d'`
162	  links=
163	  links=`cd $rel_source_dir; find $d/. -type l -print | \
164		       sed -e "s|$d/./|$d/|" -e 's|^\./||'`
165	  for link in $links --dummy-- ; do
166	    test -d $rel_source_dir/$link/. && newdirs="$newdirs $link"
167	  done
168	done
169	dirs="$newdirs"
170	subdirs="$subdirs $newdirs"
171      done
172      ;;
173    STD)
174      rel_source_dir=$src_dir_std
175      ;;
176  esac
177
178  case $rel_source_dir in
179    /* | [A-Za-z]:[\\/]*)
180       abs_source_dir=$rel_source_dir
181       ;;
182    *)
183       abs_source_dir=$original_dir/$rel_source_dir
184       ;;
185  esac
186
187  if [ \! -d $abs_source_dir ] ; then
188    echo $progname\: warning\: no such directory\: \`$rel_source_dir\'
189    continue
190  fi
191
192  for rel_source_subdir in $subdirs; do
193
194      abs_target_subdir=${abs_target_dir}/${rel_source_subdir}
195      if [ \! -d $abs_target_subdir ] ; then
196	if $mkinstalldirs $abs_target_subdir ; then
197	  subdirs_made="$abs_target_subdir $subdirs_made"
198	fi
199      fi
200      # Append "/"; remove initial "./". Hence "." -> "" and "sys" -> "sys/".
201      rel_source_prefix=`echo $rel_source_subdir | sed -e 's|$|/|' -e 's|^./||'`
202
203      case $code in
204	ALL)
205	  # The 'sed' is in case the *.h matches nothing, which yields "*.h"
206	  # which would then get re-globbed in the current directory.  Sigh.
207	  rel_source_files=`cd ${abs_source_dir}/${rel_source_subdir}; echo *.h | sed -e 's|[*].h|NONE|'`
208	  ;;
209
210	STD)
211	  files_to_check="$std_files"
212	  rel_source_files=""
213
214	  # Also process files #included by the $std_files.
215	  while [ -n "${files_to_check}" ]
216	  do
217	    new_files_to_check=""
218	    for file in $files_to_check ; do
219	      xxfile=`echo $file | sed -e 's|/\([^/\.][^/\.]*\)/\.\./|/|'`
220	      # Create the dir where this file will go when fixed.
221	      xxdir=`echo ./$file | sed -e 's|/[^/]*$||'`
222	      if [ \! -d $abs_target_subdir/$xxdir ] ; then
223		if $mkinstalldirs $abs_target_subdir/$xxdir ; then
224		  subdirs_made="$abs_target_subdir/$xxdir $subdirs_made"
225		fi
226	      fi
227	      # Just in case we have edited out a symbolic link
228	      if [ -f $src_dir_std/$file -a -f $src_dir_std/$xxfile ] ; then
229		file=$xxfile
230	      fi
231	      case " $rel_source_files " in
232	        *" ${file} "*)
233		  # Already seen $file; nothing to do
234		  ;;
235		*)
236		  if test -f $src_dir_std/$file ; then
237		    rel_dir=`echo $file | sed -n -e 's|^\(.*/\)[^/]*$|\1|p'`
238		    # For #include "foo.h", that might be either "foo.h"
239		    # or "${rel_dir}foo.h (or something bogus).
240	            new_files_to_check="$new_files_to_check "`sed -n \
241			-e 's@	@ @g' \
242		        -e 's@^ *# *include *<\([^>]*\)>.*$@\1@p' -e \
243		        's@^ *# *include *\"\([^\"]*\)\".*$@\1 '$rel_dir'\1@p'\
244			<$src_dir_std/$file`
245	            rel_source_files="$rel_source_files $file"
246		  fi
247		  ;;
248	      esac
249	    done
250	    files_to_check="$new_files_to_check"
251	  done
252	  rel_source_files="$rel_source_files"
253	  ;;
254      esac
255
256      for filename in $rel_source_files ; do
257	rel_source_file=${rel_source_prefix}${filename}
258	abs_source_file=$abs_source_dir/$rel_source_file
259	abs_target_file=$abs_target_dir/$rel_source_file
260
261	if test "$filename" = 'NONE' ; then
262	  echo "(No *.h files in $abs_source_dir/$rel_source_subdir)"
263	# If target file exists, check if was written while processing one
264	# of the earlier source directories;  if so ignore it.
265	elif test -f $abs_target_file -a -n "$done_dirs" \
266	  && grep "$rel_source_file" fixproto.list >/dev/null
267	then true
268	else
269	  $FIX_HEADER $rel_source_file $abs_source_file $abs_target_file ${DEFINES} $include_path
270	  if test $? != 0 ; then exit 1 ; fi
271	  echo "${rel_source_file}" >>fixproto.list
272	fi
273      done
274    done
275    done_dirs="$done_dir $rel_source_dir"
276done
277
278# This might be more cleanly moved into the main loop, by adding
279# a <dummy> source directory at the end.  FIXME!
280
281# All the headers we create define size_t and NULL.
282for rel_source_file in unistd.h stdlib.h string.h time.h ; do
283  if grep "$rel_source_file" fixproto.list >/dev/null ; then
284    : # It exists, we don't need to make it
285  else
286    echo Adding missing $rel_source_file
287    rel_source_ident=`echo $rel_source_file | tr ./ __`
288    cat >tmp.h <<EOF
289/* Fake ${rel_source_file}, created by GCC.
290   The functions declared in this file do not necessarily exist in
291   your C library. */
292#ifndef __${rel_source_ident}
293#define __${rel_source_ident}
294
295#define __need_NULL
296#define __need_size_t
297#include <stddef.h>
298EOF
299    # Insert special stuff for particular files here.
300    case ${rel_source_file} in
301      time.h)
302        # If time.h doesn't exist, find out if sys/time.h does.
303        if test -f $src_dir_std/sys/time.h \
304            || grep "sys/time.h" fixproto.list >/dev/null ; then
305          # It does; include it and hope it has the needed declarations.
306          # Some versions require sys/types.h.
307          cat >>tmp.h <<EOF
308
309#include <sys/types.h>
310#include <sys/time.h>
311EOF
312        else
313          # It doesn't.  Make up plausible definitions for time_t, clock_t.
314          # Forward-declare struct tm.  Hope nobody tries to use it.  (Odds
315          # are they won't.)
316          cat >>tmp.h <<EOF
317
318typedef long time_t;
319typedef long clock_t;
320struct tm;
321EOF
322        fi ;;
323    esac
324    cat >>tmp.h <<EOF
325
326#endif /* __${rel_source_ident} */
327EOF
328    ${FIX_HEADER} $rel_source_file tmp.h $abs_target_dir/$rel_source_file ${DEFINES} $include_path
329    if test $? != 0 ; then exit 1 ; fi
330    if test -f $abs_target_dir/$rel_source_file ; then
331      rm tmp.h
332    else
333      mv tmp.h $abs_target_dir/$rel_source_file
334    fi
335  fi
336done
337
338# Remove any directories that we made that are still empty.
339rmdir $subdirs_made 2>/dev/null
340
341exit 0
342