118334Speter#!/bin/sh
218334Speter#
318334Speter# SYNOPSIS
418334Speter#	fixproto TARGET-DIR SOURCE-DIR-ALL SOURCE-DIR-STD
518334Speter#
618334Speter# COPYRIGHT
7132718Skan#	Copyright (C) 1993, 1994, 1997, 1998, 2002, 2003
8132718Skan#       Free Software Foundation, Inc.
990075Sobrien#	This file is part of GCC.
1018334Speter#
1190075Sobrien#	GCC is free software; you can redistribute it and/or modify
1218334Speter#	it under the terms of the GNU General Public License as published by
1318334Speter#	the Free Software Foundation; either version 2, or (at your option)
1418334Speter#	any later version.
1518334Speter#
1690075Sobrien#	GCC is distributed in the hope that it will be useful,
1718334Speter#	but WITHOUT ANY WARRANTY; without even the implied warranty of
1818334Speter#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1918334Speter#	GNU General Public License for more details.
2018334Speter#
2118334Speter#	You should have received a copy of the GNU General Public License
2290075Sobrien#	along with GCC; see the file COPYING.  If not, write to
23169689Skan#	the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24169689Skan#	Boston, MA 02110-1301, USA.
2518334Speter#
2618334Speter# DESCRIPTION
2790075Sobrien#	Adjunct script for GCC to populate a directory with ANSI,
2818334Speter#	Posix.1, and C++ compatible header files.
2918334Speter#
3018334Speter#	Each file found under SOURCE-DIR-ALL is analyzed and "fixed."
3118334Speter#       Only standard ANSI/POSIX files found under SOURCE-DIR-STD
3218334Speter#       are analyzed and "fixed."
3318334Speter#	The SOURCE-DIRs are searched in order; a file found
3418334Speter#	under multiple SOURCE-DIRs is only handled for the first one.
3518334Speter#
3618334Speter# STRATEGY
3718334Speter#       Each include file is fed through cpp, and the scan-decls program
3818334Speter#	parses it, and emits any found function declarations.
3918334Speter#	The fix-header program analyzes the scan-decls output,
4018334Speter#	together with the original include file, and writes a "fixed"
4118334Speter#	include file, if needed.
4218334Speter#
4318334Speter#	The comment at the beginning of fix-header.c lists specifically
4418334Speter#	what kind of changes are made.
4518334Speter#
4618334Speter# NOTE
4718334Speter#	Some file space will be wasted, because the original header
4818334Speter#	files are copied.  An earlier version just included the original
4918334Speter#	by "reference", using GNU cpp's #include_next mechanism.
5018334Speter#	This is currently not done, partly because #include_next is
5118334Speter#	fragile (susceptible to version incompatibilities, and depends
5218334Speter#	and GCC-specific features), and partly for performance reasons.
5318334Speter#
5418334Speter# AUTHORS
5518334Speter#	Ron Guilmette (rfg@netcom.com) (original idea and code)
5618334Speter#	Per Bothner (bothner@cygnus.com) (major re-write)
5718334Speter
5852284Sobriendirname=`echo "$0" | sed 's,^[^/]*$,.,;s,//*[^/]*$,,'`
5952284Sobrienprogname=`echo "$0" | sed 's,.*/,,'`
60117395Skanoriginal_dir=`${PWDCMD-pwd}`
6118334SpeterFIX_HEADER=${FIX_HEADER-$original_dir/fix-header}
6218334SpeterDEFINES="-D__STDC__=0 -D__cplusplus ${FIXPROTO_DEFINES}"
6318334Speter
6452284Sobrienif mkdir -p . 2> /dev/null; then
6552284Sobrien  # Great, mkdir accepts -p
6652284Sobrien  mkinstalldirs="mkdir -p"
6752284Sobrienelse
6852284Sobrien  # We expect mkinstalldirs to be passed in the environment.
6952284Sobrien  # If it is not, assume it is in the directory that contains this script.
7052284Sobrien  mkinstalldirs=${mkinstalldirs-"/bin/sh $dirname/mkinstalldirs"}
7152284Sobrien  if $mkinstalldirs . 2> /dev/null; then
7252284Sobrien    :
7352284Sobrien  else
7452284Sobrien    # But, in case of failure, fallback to plain mkdir, and hope it works
7552284Sobrien    mkinstalldirs=mkdir
7652284Sobrien  fi
7752284Sobrienfi
7852284Sobrien
7918334Speterif [ `echo $1 | wc -w` = 0 ] ; then
8018334Speter  echo $progname\: usage\: $progname target-dir \[ source-dir \.\.\. \]
8118334Speter  exit 1
8218334Speterfi
8318334Speter
8450397Sobrienstd_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"
8518334Speter
8618334Speterrel_target_dir=$1
8718334Speter# All files in $src_dir_all (normally same as $rel_target_dir) are
8818334Speter# processed.
8918334Spetersrc_dir_all=$2
9018334Speter# In $src_dir_std (normally same as /usr/include), only the
9118334Speter# "standard" ANSI/POSIX files listed in $std_files are processed.
9218334Spetersrc_dir_std=$3
9318334Speter
9490075Sobriencase $rel_target_dir in
9590075Sobrien  /* | [A-Za-z]:[\\/]*)
9690075Sobrien     abs_target_dir=$rel_target_dir
9790075Sobrien     ;;
9890075Sobrien  *)
9990075Sobrien     abs_target_dir=$original_dir/$rel_target_dir
10090075Sobrien     ;;
10190075Sobrienesac
10218334Speter
10318334Speter# Determine whether this system has symbolic links.
10418334Speterif ln -s X $rel_target_dir/ShouldNotExist 2>/dev/null; then
10518334Speter  rm -f $rel_target_dir/ShouldNotExist
10618334Speter  LINKS=true
10718334Speterelif ln -s X /tmp/ShouldNotExist 2>/dev/null; then
10818334Speter  rm -f /tmp/ShouldNotExist
10918334Speter  LINKS=true
11018334Speterelse
11118334Speter  LINKS=false
11218334Speterfi
11318334Speter
11418334Speterif [ \! -d $abs_target_dir ] ; then
11518334Speter  echo $progname\: creating directory $rel_target_dir
11652284Sobrien  $mkinstalldirs $abs_target_dir
11718334Speterfi
11818334Speter
11918334Speterecho $progname\: populating \`$rel_target_dir\'
12018334Speter
12118334Speterinclude_path=""
12218334Speter
12318334Speterif [ `echo $* | wc -w` != 0 ] ; then
12418334Speter  for rel_source_dir in $src_dir_all $src_dir_std; do
12590075Sobrien     case $rel_source_dir in
12690075Sobrien       /* | [A-Za-z]:[\\/]*)
12790075Sobrien         abs_source_dir=$rel_source_dir
12890075Sobrien         ;;
12990075Sobrien       *)
13090075Sobrien         abs_source_dir=$original_dir/$rel_source_dir
13190075Sobrien         ;;
13290075Sobrien     esac
13318334Speter    include_path="$include_path -I$abs_source_dir"
13418334Speter  done
13518334Speterfi
13618334Speter
13718334Speterdone_dirs=""
13850397Sobriensubdirs_made=""
13918334Speterecho "" >fixproto.list
14018334Speter
14118334Speterfor code in ALL STD ; do
14218334Speter
14318334Speter  subdirs="."
14418334Speter
14518334Speter  case $code in
14618334Speter    ALL)
14718334Speter      rel_source_dir=$src_dir_all
14818334Speter
14918334Speter      dirs="."
15018334Speter      levels=2
15118334Speter      while $LINKS && test -n "$dirs" -a $levels -gt 0
15218334Speter      do
15318334Speter        levels=`expr $levels - 1`
15418334Speter	newdirs=
15518334Speter	for d in $dirs ; do
15618334Speter	  # Find all directories under $d, relative to $d, excluding $d itself.
15718334Speter	  # Assume directory names ending in CC or containing ++ are
15818334Speter	  # for C++, so skip those.
15918334Speter	  subdirs="$subdirs "`cd $rel_source_dir/$d; find . -type d -print | \
16018334Speter	           sed -e '/^\.$/d' -e "s|^\./|${d}/|" -e 's|^\./||' \
16150397Sobrien		     -e '/CC$/d' -e '/[+][+]/d'`
16218334Speter	  links=
16318334Speter	  links=`cd $rel_source_dir; find $d/. -type l -print | \
16418334Speter		       sed -e "s|$d/./|$d/|" -e 's|^\./||'`
16518334Speter	  for link in $links --dummy-- ; do
16618334Speter	    test -d $rel_source_dir/$link/. && newdirs="$newdirs $link"
16718334Speter	  done
16818334Speter	done
16918334Speter	dirs="$newdirs"
17018334Speter	subdirs="$subdirs $newdirs"
17118334Speter      done
17218334Speter      ;;
17318334Speter    STD)
17418334Speter      rel_source_dir=$src_dir_std
17518334Speter      ;;
17618334Speter  esac
17718334Speter
17890075Sobrien  case $rel_source_dir in
17990075Sobrien    /* | [A-Za-z]:[\\/]*)
18090075Sobrien       abs_source_dir=$rel_source_dir
18190075Sobrien       ;;
18290075Sobrien    *)
18390075Sobrien       abs_source_dir=$original_dir/$rel_source_dir
18490075Sobrien       ;;
18590075Sobrien  esac
18618334Speter
18718334Speter  if [ \! -d $abs_source_dir ] ; then
18818334Speter    echo $progname\: warning\: no such directory\: \`$rel_source_dir\'
18918334Speter    continue
19018334Speter  fi
19118334Speter
19218334Speter  for rel_source_subdir in $subdirs; do
19318334Speter
19418334Speter      abs_target_subdir=${abs_target_dir}/${rel_source_subdir}
19518334Speter      if [ \! -d $abs_target_subdir ] ; then
19652284Sobrien	if $mkinstalldirs $abs_target_subdir ; then
19750397Sobrien	  subdirs_made="$abs_target_subdir $subdirs_made"
19850397Sobrien	fi
19918334Speter      fi
20018334Speter      # Append "/"; remove initial "./". Hence "." -> "" and "sys" -> "sys/".
20118334Speter      rel_source_prefix=`echo $rel_source_subdir | sed -e 's|$|/|' -e 's|^./||'`
20218334Speter
20318334Speter      case $code in
20418334Speter	ALL)
20518334Speter	  # The 'sed' is in case the *.h matches nothing, which yields "*.h"
20618334Speter	  # which would then get re-globbed in the current directory.  Sigh.
20718334Speter	  rel_source_files=`cd ${abs_source_dir}/${rel_source_subdir}; echo *.h | sed -e 's|[*].h|NONE|'`
20818334Speter	  ;;
20918334Speter
21018334Speter	STD)
21118334Speter	  files_to_check="$std_files"
21218334Speter	  rel_source_files=""
21318334Speter
21418334Speter	  # Also process files #included by the $std_files.
21518334Speter	  while [ -n "${files_to_check}" ]
21618334Speter	  do
21718334Speter	    new_files_to_check=""
21818334Speter	    for file in $files_to_check ; do
21918334Speter	      xxfile=`echo $file | sed -e 's|/\([^/\.][^/\.]*\)/\.\./|/|'`
22018334Speter	      # Create the dir where this file will go when fixed.
22118334Speter	      xxdir=`echo ./$file | sed -e 's|/[^/]*$||'`
22218334Speter	      if [ \! -d $abs_target_subdir/$xxdir ] ; then
22352284Sobrien		if $mkinstalldirs $abs_target_subdir/$xxdir ; then
22450397Sobrien		  subdirs_made="$abs_target_subdir/$xxdir $subdirs_made"
22550397Sobrien		fi
22618334Speter	      fi
22718334Speter	      # Just in case we have edited out a symbolic link
22818334Speter	      if [ -f $src_dir_std/$file -a -f $src_dir_std/$xxfile ] ; then
22918334Speter		file=$xxfile
23018334Speter	      fi
23118334Speter	      case " $rel_source_files " in
23218334Speter	        *" ${file} "*)
23318334Speter		  # Already seen $file; nothing to do
23418334Speter		  ;;
23518334Speter		*)
23618334Speter		  if test -f $src_dir_std/$file ; then
23718334Speter		    rel_dir=`echo $file | sed -n -e 's|^\(.*/\)[^/]*$|\1|p'`
23818334Speter		    # For #include "foo.h", that might be either "foo.h"
23918334Speter		    # or "${rel_dir}foo.h (or something bogus).
24018334Speter	            new_files_to_check="$new_files_to_check "`sed -n \
24118334Speter			-e 's@	@ @g' \
24218334Speter		        -e 's@^ *# *include *<\([^>]*\)>.*$@\1@p' -e \
24318334Speter		        's@^ *# *include *\"\([^\"]*\)\".*$@\1 '$rel_dir'\1@p'\
24418334Speter			<$src_dir_std/$file`
24518334Speter	            rel_source_files="$rel_source_files $file"
24618334Speter		  fi
24718334Speter		  ;;
24818334Speter	      esac
24918334Speter	    done
25018334Speter	    files_to_check="$new_files_to_check"
25118334Speter	  done
25218334Speter	  rel_source_files="$rel_source_files"
25318334Speter	  ;;
25418334Speter      esac
25518334Speter
25618334Speter      for filename in $rel_source_files ; do
25718334Speter	rel_source_file=${rel_source_prefix}${filename}
25818334Speter	abs_source_file=$abs_source_dir/$rel_source_file
25918334Speter	abs_target_file=$abs_target_dir/$rel_source_file
26018334Speter
26118334Speter	if test "$filename" = 'NONE' ; then
26218334Speter	  echo "(No *.h files in $abs_source_dir/$rel_source_subdir)"
26318334Speter	# If target file exists, check if was written while processing one
26418334Speter	# of the earlier source directories;  if so ignore it.
26518334Speter	elif test -f $abs_target_file -a -n "$done_dirs" \
26618334Speter	  && grep "$rel_source_file" fixproto.list >/dev/null
26718334Speter	then true
26818334Speter	else
26918334Speter	  $FIX_HEADER $rel_source_file $abs_source_file $abs_target_file ${DEFINES} $include_path
27090075Sobrien	  if test $? != 0 ; then exit 1 ; fi
27118334Speter	  echo "${rel_source_file}" >>fixproto.list
27218334Speter	fi
27318334Speter      done
27418334Speter    done
27518334Speter    done_dirs="$done_dir $rel_source_dir"
27618334Speterdone
27718334Speter
27818334Speter# This might be more cleanly moved into the main loop, by adding
27918334Speter# a <dummy> source directory at the end.  FIXME!
280132718Skan
281132718Skan# All the headers we create define size_t and NULL.
282132718Skanfor rel_source_file in unistd.h stdlib.h string.h time.h ; do
283132718Skan  if grep "$rel_source_file" fixproto.list >/dev/null ; then
284132718Skan    : # It exists, we don't need to make it
28518334Speter  else
28618334Speter    echo Adding missing $rel_source_file
28718334Speter    rel_source_ident=`echo $rel_source_file | tr ./ __`
28818334Speter    cat >tmp.h <<EOF
289132718Skan/* Fake ${rel_source_file}, created by GCC.
290132718Skan   The functions declared in this file do not necessarily exist in
291132718Skan   your C library. */
29250397Sobrien#ifndef __${rel_source_ident}
29350397Sobrien#define __${rel_source_ident}
29450397Sobrien
295132718Skan#define __need_NULL
29650397Sobrien#define __need_size_t
29750397Sobrien#include <stddef.h>
29850397SobrienEOF
299132718Skan    # Insert special stuff for particular files here.
300132718Skan    case ${rel_source_file} in
301132718Skan      time.h)
302132718Skan        # If time.h doesn't exist, find out if sys/time.h does.
303132718Skan        if test -f $src_dir_std/sys/time.h \
304132718Skan            || grep "sys/time.h" fixproto.list >/dev/null ; then
305132718Skan          # It does; include it and hope it has the needed declarations.
306132718Skan          # Some versions require sys/types.h.
307132718Skan          cat >>tmp.h <<EOF
308132718Skan
309132718Skan#include <sys/types.h>
310132718Skan#include <sys/time.h>
311132718SkanEOF
312132718Skan        else
313132718Skan          # It doesn't.  Make up plausible definitions for time_t, clock_t.
314132718Skan          # Forward-declare struct tm.  Hope nobody tries to use it.  (Odds
315132718Skan          # are they won't.)
316132718Skan          cat >>tmp.h <<EOF
317132718Skan
318132718Skantypedef long time_t;
319132718Skantypedef long clock_t;
320132718Skanstruct tm;
321132718SkanEOF
322132718Skan        fi ;;
323132718Skan    esac
32450397Sobrien    cat >>tmp.h <<EOF
32550397Sobrien
32650397Sobrien#endif /* __${rel_source_ident} */
32750397SobrienEOF
32818334Speter    ${FIX_HEADER} $rel_source_file tmp.h $abs_target_dir/$rel_source_file ${DEFINES} $include_path
32990075Sobrien    if test $? != 0 ; then exit 1 ; fi
330132718Skan    if test -f $abs_target_dir/$rel_source_file ; then
33190075Sobrien      rm tmp.h
33290075Sobrien    else
33390075Sobrien      mv tmp.h $abs_target_dir/$rel_source_file
33490075Sobrien    fi
33518334Speter  fi
33618334Speterdone
33750397Sobrien
33850397Sobrien# Remove any directories that we made that are still empty.
33950397Sobrienrmdir $subdirs_made 2>/dev/null
34050397Sobrien
34118334Speterexit 0
342