#! /bin/bash cd `dirname $0` if [ $# -eq 2 ]; then if [ `expr $2 : /` -eq 1 ]; then output_dir=$2 else output_dir=$1/$2 fi else output_dir=../objs fi list_file=data/action_list types_file=data/action_types reps_file=data/action_replacements prefix_file=data/prefixes header_file=data/header_files optional_modules_file=data/modules_optional headers_file=data/headers module_dependencies_file=data/module_dependencies conf_macros_file=data/conf_macros conf_locs_file=data/conf_locs conf_args_file=data/conf_args autogen_notice=text/autogen actions_dir=actions srcs_dir=src include_prefix= file_prefix=ndk_ auto_file_name=config auto_includes_name=includes conf_merge_filename=conf_merge.h conf_cmd_basic_filename=conf_cmd_basic.h conf_cmd_extra_filename=conf_cmd_extra.h spacer=¬ sed_delete_empty_lines='t_NEL;d;:_NEL' function trim_lines { sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba' -e '}' } function strtoupper { [ $# -eq 1 ] || return 1 local _str _cu _cl _x _cu=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) _cl=(a b c d e f g h i j k l m n o p q r s t u v w x y z) _str=$1 for ((_x=0;_x<${#_cl[*]};_x++)); do _str=${_str//${_cl[$_x]}/${_cu[$_x]}} done echo $_str } function sed_pad_right { len=$1 spacer=$2 prefix=_PR$3 # returns a SED script that pads out (spaces) to the right to alignment $len # this script should be used inside a call to sed # NOTE : a spacer character $spacer should have already been written into the parsed string echo "t${prefix}a;:${prefix}a;s/^[^$spacer]{$len}/&/;\ t${prefix}b;s/^[^$spacer]*/& /;t${prefix}a;:${prefix}b;s/$spacer/ /" } function sed_pad_left { len=$1 spacer=$2 prefix=_PL$3 # echo "t${prefix}a;:${prefix}a;s/^[^$spacer]{$len}/& /;t${prefix}a" # NOT CORRECT? } function add_notice { echo > $1 cat $autogen_notice | trim_lines >> $1 echo >> $1 echo >> $1 } function add_non_generated_content { file=src/$1.h [ ! -f $file ] && return echo "/* Non-generated macros */" >> $2 echo >> $2 cat $file | trim_lines >> $2 echo >> $2 echo >> $2 } function add_action_macros { list_file=$actions_dir/$1 [ ! -f $list_file ] && return out=$2 # alignment settings align1=20 align2=35 align3=62 base_shrink=12 define="#define " # base macros echo "/* base action macro macros */" >> $out echo >> $out cat $list_file | trim_lines | sed -r \ -e "s/^[ ]*([a-zA-Z0-9_]+)([ ]*)\(([a-zA-Z0-9_,]+)\)([ ]*)(.*)/$define%2%_\1_ac(\3,ac)\2\4 {\5;}/" \ -e "s/[ ]{$base_shrink}\{/\{/" \ -e 's/%A%/ac/g' \ >> $out echo >> $out echo >> $out # generated macros echo "/* generated action macros */" >> $out echo >> $out cat -s $list_file | while read list_line; do [ "x`echo $list_line`" = 'x' ] && continue cat $types_file | while read type_line; do [ "x`echo $type_line`" = 'x' ] && continue #ext=`echo $type_line | grep -E '^[a-zA-Z0-9_]+' | cut -d " " -f1` ext=`echo $type_line | sed -r 's/^([a-zA-Z0-9_]+).*/\1/'` params=`echo $type_line | sed -r 's/^[a-zA-Z0-9_]+[ ]*\((.*)\).*/\1/;ta;d;:a'` act=`echo $type_line | sed -r 's/^[a-zA-Z0-9_]+[ ]*(\(.*\))?(.*)/\2/'` [ "x$params" != "x" ] && params=",$params" echo $list_line | sed -r \ -e "s/^([a-zA-Z0-9_]+)[ ]*\(([a-zA-Z0-9_,]+)\).*/%2%_\1_$ext(\2$params)$spacer%2%_\1_ac$spacer(\2,$act)/" \ -e 's/[ ]*,[ ]*/,/g' \ -e "`sed_pad_right $align2 $spacer 1`" \ -e "`sed_pad_right $align3 $spacer 2`" \ -e "s/.*/$define&/" \ >> $out done echo >> $out done } function replace_prefixes { temp=.temp file=`cat $prefix_file` prefix1= prefix2= for prefix in $file ; do [ "x$prefix2" != "x" ] && echo "Too many prefixes in prefix file $prefix_file" && exit 1 [ "x$prefix1" != "x" ] && prefix2=$prefix && continue prefix1=$prefix done sed -r "s/%1%/$prefix1/g;s/%2%/$prefix2/g" < $1 > $temp mv -f $temp $1 } function replace_other_strings { temp=.temp cat $reps_file | while read line; do rep1= rep2= for rep in $line ; do [ "x$rep2" != "x" ] && echo "Too many replacments in replacements file $reps_file" && exit 1 [ "x$rep1" != "x" ] && rep2=$rep && continue rep1=$rep done sed -r "s/%$rep1%/$rep2/g" < $1 > $temp mv -f $temp $1 done } function generate_header_file { name=$1 out=$output_dir/$file_prefix$name.h add_notice $out add_non_generated_content $name $out add_action_macros $name $out replace_prefixes $out replace_other_strings $out } function add_auto_include { echo "#include <${file_prefix}$2>" >> $1 } function add_include { echo "#include <${include_prefix}${file_prefix}$2>" >> $1 } function generate_non_optional_h_includes { # TODO : split into auto-generated and non-auto-generated ones echo "/* non-optional includes */" >> $1 echo >> $1 for mod in `cat $headers_file | sort`; do add_auto_include $1 $mod.h done echo >> $1 echo >> $1 } function generate_include_all_includes { echo "/* include all optional modules */" >> $1 echo >> $1 echo "#ifdef NDK_ALL" >> $1 echo >> $1 modules=`cat $optional_modules_file | sed 's/*//g' | sort` for mod in $modules; do def="NDK_`strtoupper $mod`" echo "#ifndef $def" >> $1 echo "#define $def 1" >> $1 echo "#endif" >> $1 done echo >> $1 echo "#endif" >> $1 echo >> $1 echo >> $1 } function generate_dependent_includes { echo "/* module dependencies */" >> $1 echo >> $1 cat $module_dependencies_file | while read line; do first=1 for mod in $line; do def="NDK_`strtoupper $mod`" if [ $first = 1 ] ; then echo "#ifdef $def" >> $1 first=0 else echo "#ifndef $def" >> $1 echo "#define $def 1" >> $1 echo "#endif" >> $1 fi done [ $first = 0 ] && echo "#endif" >> $1 done echo >> $1 echo >> $1 } function generate_optional_h_includes { echo "/* optional includes */" >> $1 echo >> $1 for mod in $modules; do def="NDK_`strtoupper $mod`" echo "#if ($def)" >> $1 add_include $1 $mod.h echo "#endif" >> $1 done echo >> $1 echo >> $1 } function generate_conf_merge_macros_file { file=$conf_merge_filename out_file=${file_prefix}$file out=$output_dir/$out_file add_notice $out echo "/* conf-merge-value macros */" >> $out echo >> $out cat $srcs_dir/$file | trim_lines >> $out echo >> $out echo >> $out echo "/* conf-merge-prop macros */" >> $out echo >> $out echo "#define ndk_conf_merge_prop(prop,default)\\" >> $out echo " ndk_conf_merge_value\\" >> $out echo " (conf->prop, prev->prop, default)" >> $out echo >> $out # loads macros, removes empty elements, sorts and translates to merge-prop macros cat $conf_macros_file | sed -r 's/^[A-Z0-9_]+[ ]*[A-Z0-9_]+[ ]*([a-z0-9_]+).*$/\1/;ta;d;:a' \ | sort | sed -r \ 's/(.*)/#define ndk_conf_merge_\1_prop(prop,default,...)\\\ ndk_conf_merge_\1_value\\\ (conf->prop, prev->prop, default,##__VA_ARGS__)\ /' \ >> $out add_auto_include $1 $file } function generate_conf_cmd_basic_file { temp=.rep file=$conf_cmd_basic_filename out_file=${file_prefix}$file out=$output_dir/$out_file align1=35 # initial text add_notice $out # add ndk bitmasks echo "/* conf cmd core values/bitmasks */" >> $out echo >> $out cat $conf_args_file | sort | trim_lines | sed -r \ -e "s/^([A-Z0-9_]+)/${define}NDK_\1${spacer}NGX_\1/" \ -e $sed_delete_empty_lines \ -e "`sed_pad_right $align1 $spacer`" \ >> $out echo >> $out echo >> $out # add additional bitmasks stored in file echo "/* conf cmd bitmasks */" >> $out echo >> $out cat $srcs_dir/$conf_cmd_basic_filename | trim_lines >> $out echo >> $out echo >> $out echo "/* conf cmd basic macros */" >> $out echo >> $out # build replacement string echo -n "s/^([A-Z0-9_]+)$/" > $temp cat $conf_locs_file | sed \ -r -e 's/^([A-Z0-9_]+) *([A-Z0-9_]+).*/#define NDK_\1_CONF_\\1\(name,func,off1,off2,post)\\\\\\\ {ngx_string (name),\\\\\\\ NGX_CONF_\\1|NDK_\1_CONF,\\\\\\\ func, off1, off2, post},\\\ \\/' -e $sed_delete_empty_lines \ >> $temp echo -n "/;$sed_delete_empty_lines" >> $temp # apply the replacement string to the cat $conf_args_file | sort | trim_lines | sed -rf $temp >> $out rm -f $temp add_auto_include $1 $file } function generate_conf_cmd_extra_file { temp=.rep file=$conf_cmd_extra_filename out=$output_dir/${file_prefix}$file align1=35 # initial text add_notice $out echo "/* conf command macros */" >> $out echo >> $out # build replacement string echo -n 's/^([A-Z0-9_]+)[ ]*([A-Z0-9_]+)[ ]*([a-z0-9_]+).*$/' > $temp cat $conf_locs_file | sed \ -r -e 's/^([A-Z0-9_]+)[ ]*([A-Z0-9_]+)[ ]*([a-zA-Z0-9_]+)/#define NDK_\1_CONF_\\1(name,p,post\)\\\\\\\ NDK_\1_CONF_\\2\\\\\\\ (name,\\\\\\\ ndk_conf_set_\\3_slot,\\\\\\\ NGX_\2_CONF_OFFSET,\\\\\\\ offsetof (ndk_module_\3_conf_t, p),\\\\\\\ post)\\\ \\/' -e $sed_delete_empty_lines \ >> $temp echo -n "/;$sed_delete_empty_lines" >> $temp #echo -n ";`sed_pad_right 60 $spacer`" >> $temp # apply the replacement string to the cat $conf_macros_file | sort | trim_lines | sed -rf $temp -e "`sed_pad_right 60 $spacer`" >> $out rm -f $temp add_auto_include $1 $file } function generate_auto_generated_h_includes { echo "/* auto-generated headers */" >> $1 echo >> $1 for name in `cat $header_file | sort` ; do generate_header_file $name add_auto_include $1 $name.h done generate_conf_merge_macros_file $1 generate_conf_cmd_basic_file $1 generate_conf_cmd_extra_file $1 echo >> $1 echo >> $1 } function generate_optional_c_includes { echo "/* optional includes */" >> $1 echo >> $1 modules=`cat $optional_modules_file | sed 's/*//g' | sort` for mod in $modules; do def="NDK_`strtoupper "$mod"`" echo "#if ($def)" >> $1 add_include $1 $mod.c echo "#endif" >> $1 done echo >> $1 echo >> $1 } function generate_commands { echo "/* module commands */" >> $1 echo >> $1 echo "static ngx_command_t ndk_http_commands[] = {" >> $1 cat $optional_modules_file | sort | while read line; do cmds=`echo "$line" | grep -E '\*'` [ "x$cmds" = "x" ] && continue mod=`echo "$line" | grep -E '^[a-zA-Z0-9_]+' | cut -d " " -f1` up=`strtoupper $mod` def="NDK_$up" defcmd="NDK_${up}_CMDS" echo "#if ($def)" >> $1 echo "#define $defcmd 1" >> $1 add_include $1 $mod.h echo "#undef $defcmd" >> $1 echo "#endif" >> $1 done echo -e " ngx_null_command\n};" >> $1 } function generate_all_h_files { out=$output_dir/${file_prefix}$auto_file_name.h add_notice $out generate_include_all_includes $out generate_dependent_includes $out out=$output_dir/${file_prefix}$auto_includes_name.h generate_optional_h_includes $out generate_non_optional_h_includes $out generate_auto_generated_h_includes $out $list } function generate_all_c_files { out=$output_dir/${file_prefix}$auto_file_name.c add_notice $out generate_optional_c_includes $out generate_commands $out } function generate_all_files { mkdir -p $output_dir rm -f $output_dir/* generate_all_h_files generate_all_c_files } generate_all_files