#! /usr/bin/awk -f # $NetBSD: gendevcalls.awk,v 1.2 2024/02/09 22:08:37 andvar Exp $ # # Copyright (c) 2021 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Jason R. Thorpe. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # # Parses a device call definition file and produces argument and # binding structures. # function emit_binding(field) { printf("union %s_binding {\n", call_name_ub) printf("\tstruct device_call_generic generic;\n") if (field != "") { printf("\tstruct {\n") printf("\t\tconst char *name;\n") printf("\t\tstruct %s_args *args;\n", call_name_ub) printf("\t} %s;\n", field); } printf("};\n") } function emit_name_macro() { printf("\n") printf("#define %s_STR \"%s\"\n", call_name_ub_uc, call_name) } function emit_invoke_macro(field, marg, carg) { printf("\n") printf("#define %s%s \\\n", call_name_ub_uc, marg) printf("\t&((const union %s_binding){ \\\n", call_name_ub) printf("\t\t.%s.name = \"%s\", \\\n", field, call_name) printf("\t\t.%s.args = %s, \\\n", field, carg) printf("\t})\n") } function start_decl(arg) { if (state == "expecting-subsystem") { print "must declare a subsystem before declaring a call " \ "at line " NR \ > "/dev/stderr" exit 1 } if (state != "expecting-decl-start") { print "unexpected start of declaration at line " NR \ > "/dev/stderr" exit 1 } call_name = arg if (index(call_name, call_name_prefix) != 1) { printf("method name '%s' at line %d must begin with '%s'\n", \ call_name, NR, call_name_prefix) \ > "/dev/stderr" exit 1 } call_name_ub = arg gsub("\-", "_", call_name_ub) call_name_ub_uc = toupper(call_name_ub) } NR == 1 { VERSION = $0 gsub("\\$", "", VERSION) gsub(/ $/, "", VERSION) printf("/*\t$NetBSD" "$\t*/\n\n") printf("/*\n") printf(" * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.\n") printf(" *\n") printf(" * generated from:\n") printf(" *\t%s\n", VERSION) printf(" */\n") subsystem = "" state = "expecting-subsystem" next } # # Subsystem declaration. We use this to generate header file guards, # as well as to sanity-check the method names when they are declared. # state == "expecting-subsystem" && \ /^subsystem[ \t]+[a-zA-Z]+[a-zA-Z0-9\-]*[ \t]*;[ \t]*$/ { subsystem = $2 # strip the trailing ; gsub(";$", "", subsystem) subsystem_ub = subsystem gsub("\-", "_", subsystem_ub) subsystem_ub_uc = toupper(subsystem_ub) # now tack on a trailing - for sanity checking method # names later. call_name_prefix = subsystem "-" # Emit the leading header guard. printf("#ifndef _%s_CALLS_H_\n", subsystem_ub_uc) printf("#define _%s_CALLS_H_\n", subsystem_ub_uc) # Pull in for 'struct device_call_generic'. printf("\n#include \n") state = "expecting-decl-start" next } # # Beginning of a call-with-arguments declaration. Gather up the various # forms of the method name and emit the beginning of the structure declaration. # /^[a-zA-Z]+[a-zA-Z0-9\-]*[ \t]+{[ \t]*$/ { start_decl($1) # Emit the args structure declaration. printf("struct %s_args {\n", call_name_ub) state = "expecting-decl-end" next } # # A call-without-arguments declaration. # /^[a-zA-Z]+[a-zA-Z0-9\-]*[ \t]*;[ \t]*$/ { # strip the trailing ; call_name = $1 gsub(";$", "", call_name) start_decl(call_name) emit_binding("") emit_name_macro() emit_invoke_macro("generic", "", "NULL") next } # # End of a declaration. Wrap up the structure declaration and emit # the binding information. # /^}[ \t]*;[ \t]*$/ { if (state != "expecting-decl-end") { print "unexpected end of declaration at line " NR \ > "/dev/stderr" exit 1 } # Terminate the args structure declaration. printf("};\n") printf("\n") emit_binding("binding") emit_name_macro() emit_invoke_macro("binding", "(_args_)", "(_args_)") state = "expecting-decl-start" next } # # Default action is to simply emit the line as it exists in the source # file. # { print $0 } END { if (state != "expecting-decl-start") { print "unexpected end of file at line " NR \ > "/dev/stderr" exit 1 } # Emit the trailing header guard. printf("\n#endif /* _%s_CALLS_H_ */\n", subsystem_ub_uc) }