gencpp 2.0 (was: [...] /usr/lib/cpp for generic text)

Maarten Litmaath maart at cs.vu.nl
Tue Sep 26 14:39:13 AEST 1989


Let's try again.  Still some limitations, but it seems to work well, albeit
a bit slow.
----------8<----------8<----------8<----------8<----------8<----------
#!/bin/sh
#
# @(#)gencpp 2.0 89/09/26 Maarten Litmaath
# generic cpp
# as substitution is done even inside quoted strings, you should choose
# identifiers which won't collide easily, e.g.
#
#	#define MACHINE_ VAX
#
# instead of
#
#	#define machine VAX
#
# don't use `/*' and `*/' to comment out blocks of text, use
#
#	#if 0
#	...
#	#endif /* 0 */
#
# only `<...>' and `"..."' include directives are supported
# furthermore cpp predefines certain symbols, e.g.
#
#	#define unix 1
#
# which can be overruled using cpp's option `-U'

case $1 in
-level2)
	# process included file
	level=2
	shift
	;;
*)
	level=1
	dirs=
	export dirs
	argc=0
	optc=0
	export optc
	tab=`echo I | tr I '\11'`

	for i
	do
		case $i in
		-I*)
			# include directories
			dirs="$dirs "`echo "x$i" | sed 's/...//'`
			;;
		-*)
			optc=`expr $optc + 1`
			eval optv$optc='"$i"'
			eval export optv$optc
			;;
		*)
			# files
			argc=`expr $argc + 1`
			eval argv$argc='"$i"'
		esac
	done

	# double single and double quotes
	q=\"
	SED1="s/['$q]/&&/g"
	# restore quotes and backslashes
	SED2="
		s/''/'/g
		s/$q$q/$q/g
		s/\\\\\\\\/\\\\/g
	"

	for i in define undef ifdef ifndef if elif else endif
	do
		# mark the relevant cpp control lines
		# due to a bug in some sed versions, the `p' mustn't
		# be appended to the previous substitute command
		SED1="
			$SED1
			/^[ $tab]*#[ $tab]*\\($i\\).*/{
				h
				s//\\\\#\\1/
				p
				g
				b
			}
		"
		# remove a marked line and the (empty) next line
		SED2="
			$SED2
			/^\\\\#$i$/{
				N
				d
			}
		"
	done

	# set the file arguments
	set ' '
	i=0
	while
		i=`expr $i + 1`
		test $i -le $argc
	do
		eval set '${1+"$@"}' '"$argv'$i'"'
	done
	shift
esac

# canonicalize the `#include' line
# double backslashes
# protect leading whitespace against stripping by the shell (`read line')
SED3="
	s/^[ $tab]*#[ $tab]*include/#include/
	s/\\\\/&&/g
	s/^[ $tab]/\\\\&/
"
# get include file name
SED4='
	/[^<"]*.\([^>"]*\).*/{
		s//\1/
		s/\\\\/\\/g
		p
	}
'

sed "$SED3" ${1+"$@"} | (
	while read line
	do
		case $line in
		\#include*\<*)
			# don't search dot default
			dot=
			;;
		\#include*\"*)
			dot=.
			;;
		*)
			echo "$line"
			continue
		esac
		name=`echo "$line" | sed -n "$SED4"`
		file=
		case $name in
		/*)
			file=$name
			;;
		*)
			for dir in $dot $dirs
			do
				if test -f "$dir/$name"
				then
					file=$dir/$name
					break
				fi
			done
		esac
		case $file in
		'')
			echo "$0: include file '$name' not found" >&2
			continue
		esac
		# process included file
		$0 -level2 "$file"
	done
) | (
	case $level in
	2)
		cat
		;;
	*)
		# set cpp options
		set ' '
		i=0
		while
			i=`expr $i + 1`
			test $i -le $optc
		do
			eval set '${1+"$@"}' '"$optv'$i'"'
		done
		shift

		sed "$SED1" | /lib/cpp -P ${1+"$@"} | sed "$SED2"
	esac
)
----------8<----------8<----------8<----------8<----------8<----------
-- 
 `I AM NEW HEAR AMD I WANT TO INKRIMENT A |Maarten Litmaath @ VU Amsterdam:
 VURIABLE BY 1 (OONE) IN "c"'  (Tom Neff) |maart at cs.vu.nl, mcvax!botter!maart



More information about the Comp.unix.wizards mailing list