1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-30 10:22:34 +01:00
Files
wmaker/script/nested-func-to-macro.sh
Jeremy Sowden b179803c11 Fix spelling errors
* "unknow" -> "unknown"
* "occured" -> "occurred"

Remove some entries from PO files where these entries contain spelling errors
and there are other entries that are identical except for these mistakes.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2024-11-10 16:59:03 +00:00

217 lines
8.1 KiB
Bash
Executable File

#!/bin/sh
###########################################################################
#
# Window Maker window manager
#
# Copyright (c) 2014 Christophe CURIS
# Copyright (c) 2014 Window Maker Team
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
###########################################################################
#
# nested-func-to-macro.sh:
# from a C source file specified with "-i", convert the functions
# specified with "-f" into preprocessor macros ("#define") and save the
# result as the file specified with "-o"
#
# The goal is to process nested functions (functions defined inside other
# functions), because some compilers do not support that, despite the
# advantages against macros:
# - there is no side effect on arguments, like what macros does;
# - the compiler can check the type used for arguments;
# - the compiler can decide wether it is best to inline them or not;
# - they are better handled by text editors, mainly for indentation but
# also because there is no more '\' at end of lines;
# - generaly, error message from the compiler are a lot clearer.
#
# As opposed to simple static functions, there is a strong benefit because
# they can access the local variables of the function in which they are
# defined without needing extra arguments that may get complicated.
#
# These added values are important for developpement because they help keep
# code simple (and so maintainable and with lower bug risk).
#
# Because this script convert them to macros (only if 'configure' detected
# that the compiler does not support nested functions, see the macro
# WM_PROG_CC_NESTEDFUNC), there are a few constraints when writing such
# nested functions in the code:
#
# - you cannot use the function's address (example: callback), but that
# would be a bad idea anyway (in best case there's a penalty issue, in
# worst case it can crash the program);
#
# - you should be careful on what you're doing with the arguments of the
# function, otherwise the macro's side effects will re-appear;
#
# - you may need some extra '{}' when calling the function in an
# if/for/while/... construct, because of the difference between a function
# call and the macro that will be replaced (the macro will contain its own
# pair of '{}' which will be followed by the ';' you use for the function
# call;
#
# - the prototype of the function must be on a single line, it must not
# spread across multiple lines or replace will fail;
#
# - you should follow the project's coding style, as hacky stuff may
# make the script generate crap. And you don't want that to happen.
#
###########################################################################
#
# Please note that this script is writen in sh+awk on purpose: this script
# is gonna be run on the machine of the person who is trying to compile
# WindowMaker, and as such we cannot be sure to find any scripting language
# in a known version and that works (python/ruby/tcl/perl/php/you-name-it).
#
# So for portability, we stick to the same sh+awk constraint as Autotools
# to limit the problem, see for example:
# http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html
#
###########################################################################
# Report an error on stderr and exit with status 1 to tell make could not work
arg_error() {
echo "$0: $@" >&2
exit 1
}
# print help and exit with success status
print_help() {
echo "$0: convert nested functions into macros in C source"
echo "Usage: $0 [options...] input_file"
echo "valid options are:"
echo " -f name : add 'name' to the list of function to process"
echo " -o file : set output file"
exit 0
}
# Extract command line arguments
while [ $# -gt 0 ]; do
case $1 in
-f)
shift
echo "$1" | grep -q '^[A-Z_a-z][A-Z_a-z0-9]*$' || arg_error "function name \"$1\" is not valid"
function_list="$function_list $1"
;;
-h|-help|--help) print_help ;;
-o) shift ; output_file="$1" ;;
-*) arg_error "unknown option '$1'" ;;
*)
[ "x$input_file" = "x" ] || arg_error "only 1 input file can be specified, not \"$input_file\" and \"$1\""
input_file="$1"
;;
esac
shift
done
# Check consistency of command-line
[ "x$input_file" = "x" ] && arg_error "no source file given"
[ "x$function_list" = "x" ] && arg_error "no function name were given, nothing to do"
[ "x$output_file" = "x" ] && arg_error "no output file name specified"
[ -r "$input_file" ] || arg_error "source file \"$input_file\" is not readable"
# Declare a function that takes care of converting the function code into a
# macro definition. All the code is considered part of the C function's body
# until we have matched the right number of {} pairs
awk_function_handler='
function replace_definition(func_name)
{
# Isolate the list of arguments from the rest of the line
# This code could be updated to handle arg list over multiple lines, but
# it would add unnecessary complexity because a function that big should
# probably be global static
arg_start = index($0, "(");
arg_end = index($0, ")");
argsubstr = substr($0, arg_start + 1, arg_end - arg_start - 1);
remain = substr($0, arg_end);
$0 = "#define " func_name "("
# Remove the types from the list of arguments
split(argsubstr, arglist, /,/);
separator = "";
for (i = 1; i <= length(arglist); i++) {
argname = substr(arglist[i], match(arglist[i], /[A-Z_a-z][A-Z_a-z0-9]*$/));
$0 = $0 separator argname;
separator = ", ";
}
delete arglist;
$0 = $0 remain;
# Count the number of pairs of {} and take next line until we get our matching count
is_first_line = 1;
nb_pair = 0;
while (1) {
# Count the opening braces
split($0, dummy, /\{/);
nb_pair = nb_pair + (length(dummy) - 1);
delete dummy;
# Count the closing braces
split($0, dummy, /\}/);
nb_pair = nb_pair - (length(dummy) - 1);
delete dummy;
# If we found the end of the function, stop now
if (nb_pair <= 0 && !is_first_line) {
# Note that we count on awk that is always executing the match-all
# pattern to print the current line in the $0 pattern
break;
}
# Otherwise, print current line with the macro continuation mark and grab
# next line to process it
$0 = $0 " \\";
print;
getline;
is_first_line = 0;
}
# We mark the current macro as defined so it can be undefined at the end
func_defined[func_name] = 1;
}'
# Build the list of awk pattern matching for each function:
# The regular expression matches function definition by the name of the function
# that must be preceeded by at least one keyword (likely the return type), but
# nothing like a math operator or other esoteric sign
for function in $function_list ; do
awk_function_handler="$awk_function_handler
/^[\\t ]*([A-Za-z][A-Za-z_0-9]*[\\t ])+${function}[\\t ]*\\(/ {
replace_definition(\"${function}\");
}"
done
# Finishing, undefine the macro at the most appropriate place we can easily
# guess
awk_function_handler="$awk_function_handler
/^\\}/ {
# If we are at the end of a function definition, undefine all macros that
# have been defined so far
for (func_name in func_defined) {
print \"#undef \" func_name;
delete func_defined[func_name];
}
}
# Print all other lines as-is
{ print }
"
# Find the specified functions and transform them into macros
awk "$awk_function_handler" < "$input_file" > "$output_file"