A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 432 lines 13 kB view raw
1#!/usr/bin/env perl 2############################################################################ 3# __________ __ ___. 4# Open \______ \ ____ ____ | | _\_ |__ _______ ___ 5# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 6# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 7# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 8# \/ \/ \/ \/ \/ 9# $Id$ 10# 11# Copyright (C) 2018 William Wilgus 12# 13# All files in this archive are subject to the GNU General Public License. 14# See the file COPYING in the source tree root for full license agreement. 15# 16# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 17# KIND, either express or implied. 18# 19############################################################################ 20use strict; 21use warnings; 22 23# Extracts members from c struct 24# places them in a lua array 'member = {offset,size,"type"}' 25# requires two passes 26# first pass outputs a c file that shall be compiled with the -S option 27# second pass extracts the member, offset, size, type from the assembly 28 29my $svnrev = '$Revision$'; 30my $helper_name = 'LUA_RB_SETTINGS_H_HELPER'; 31 32############# configuration ############# 33my @sections = ( 34 '', 35 'struct system_status', 36 'struct user_settings', 37 'struct replaygain_settings', 38 'struct eq_band_setting', 39 'struct compressor_settings', 40 'struct mp3_enc_config', 41 '', # nothing to be captured just placeholder for lua section 42 'struct mp3entry', 43 'struct mp3_albumart', 44 'struct embedded_cuesheet', 45 #'struct cuesheet', 46 #'struct cue_track_info', 47); 48 49my @sections_lua = ( 50 'rb.system', 51 'rb.system.global_status', 52 'rb.system.global_settings', 53 'rb.system.replaygain_settings', 54 'rb.system.eq_band_setting', 55 'rb.system.compressor_settings', 56 'rb.system.mp3_enc_config', 57 'rb.metadata', 58 'rb.metadata.mp3_entry', 59 'rb.metadata.mp3_albumart', 60 'rb.metadata.embedded_cuesheet', 61 #'rb.metadata.cuesheet', 62 #'rb.metadata.cue_track_info', 63); 64 65# structs will have their dependencies included automagically 66my @includes = (); 67 68my $section_lua_suffix = ''; 69 70my %replace_type_prefix = ( 71 unsigned => 'u_', 72 signed => '', 73 struct => 's_', 74 const => 'const_', 75 enum => 'e_', 76 '#pointer#' => 'ptr_', 77); 78 79my %replace_type = ( 80 int => 'i', 81 uint => 'u_i', 82 long => 'l', 83 char => 'c', 84 bool => 'b', 85 double => 'd', 86 '#string#' => 'str', 87); 88 89############# internal ############# 90my @section_count = (); #variables found 91my @section_found = (); #{} bracket matches 92my @section_lists = (); #variable declarations 93my @section_asm_regex = (); 94my @section_begin_regex = (); 95 96my $header = ''; 97my $array_marker = '_typeisarray_'; 98my $pointer_marker = '_typeisptr_'; 99my $current_include; 100 101############# precompile regex for speed ############# 102my $array_mark_regex = qr/^.*${array_marker}$/; 103my $pointer_mark_regex = qr/^(.*)${pointer_marker}.*$/; 104 105my $incl_regex = qr/^.*\".+\/(.+\.h)\".*$/; 106my $extern_regex = qr/^extern\b.*$/; 107 108#type var ????; 109my $decl_regex = qr/^(.+?\s.+;)/; 110my $typevar_regex = qr/\W*(?<type>.*?)\W*(?<var>[^\s\[]+)(?<arr>)\W*;/; 111my$typevar_array_regex = qr/\W*(?<type>.*?)\W*(?<var>[^\s\[]+)\W*(?<arr>\[.+\]).*;/; 112 113# struct or union defined within another structure 114my $embed_structunion_regex = qr/\W*(struct|union\s[^;}]+)/; 115 116#.."section",.."member"..=..offset,..size,..type,..arrayct 117my $asm_regex = qr/.*?,.*?(\".+?\".*?=.*?,.+?,.+?\".+\".*?,.*);/; 118my $asmMOST_regex = qr/\"(?<member>.+)\"=(?<offset>\d+),(?<size>\d+),\"(?<type>.+)\",(?<arr>\d+).*/; 119 120for(my $i = 0; $i < @sections; $i++) 121{ 122 $section_asm_regex[$i] = qr/\"$sections[$i]\"${asm_regex}/; 123 $section_begin_regex[$i] = qr/^$sections[$i]\b\s*+[^\*;]*$/; 124 $section_count[$i] = 0; 125 $section_found[$i] = 0; 126 $section_lists[$i] = ''; 127} 128 129my $section_end_regex = qr/}\s*;.*$/; 130 131####################################################### 132#extract all the variables within the structs(sections) 133####################################################### 134while(my $line = <STDIN>) 135{ 136 next if($line =~ /^\s+$/); 137 138 chomp($line); 139 140 if($header) # [PASS 2] 141 { 142 for(my $i = 0; $i < @sections; $i++) 143 { 144 next if(!$sections[$i]); 145 146 if($line =~ $section_asm_regex[$i]) 147 { 148 $section_lists[$i] .= $1.'@'; 149 $section_count[$i]++; 150 last; 151 } 152 } 153 } 154 elsif($line =~ s/$helper_name\W*//) #is this the second pass? 155 { 156 $header = $line; 157 #warn $header."\n"; 158 for(my $i = 0; $i < @sections; $i++) 159 { 160 @section_lists[$i] = ''; 161 @section_count[$i] = 0; 162 } 163 } 164 else # [PASS 1] 165 { 166 if($line =~ $incl_regex){$current_include = $1; next;} 167 elsif($line =~ $extern_regex){next;} 168 169 for(my $i = 0; $i < @sections; $i++) 170 { 171 next if(!$sections[$i]); 172 173 if($section_found[$i] > 0) 174 { 175 # variable declaration? 176 if($line =~ $decl_regex) 177 { 178 $section_lists[$i] .= $1.'@'; 179 $section_count[$i]++; 180 } 181 # struct or union defined within a structure skip if single line 182 elsif($line =~ $embed_structunion_regex && (index($line, "}") < 0)) 183 { 184 my $embedtype = $line; 185 $embedtype =~ s{[^\w\d_]+}{}gx; #strip non conforming chars 186 while($line = <STDIN>) 187 { 188 #skip over the contents user will have to determine how to parse 189 if($line =~ /^\s*}.+$/) 190 { 191 if($line =~ $decl_regex) 192 { 193 $section_lists[$i] .= $embedtype." ".$1.'@'; 194 $section_count[$i]++; 195 } 196 last 197 } 198 } 199 } 200 201 # struct end? 202 if($line =~ $section_end_regex) 203 { 204 $section_found[$i]--; 205 } 206 last; 207 } 208 elsif($line =~ $section_begin_regex[$i]) # struct begin? 209 { 210 if($current_include) 211 { 212 push (@includes, $current_include); 213 $current_include = ''; 214 } 215 $section_found[$i]++; 216 $section_lists[$i] = ''; 217 $section_count[$i] = 0; 218 last; 219 } 220 } 221 }#else 222} 223 224for(my $i = 0; $i < @sections; $i++) 225{ 226 if($section_found[$i]) 227 { 228 warn "$0 Warning formatting error in: $sections[$i]\n"; 229 } 230} 231 232sub Extract_Variable { 233 #[PASS 1] extracts the member, offset, size, and type from the include file 234 my $sinput = $_[0]; 235 my ($type, $var, $arr); 236 237 $sinput =~ s{\s*\*\s*}{${pointer_marker}}gx; 238 if($sinput =~ $typevar_array_regex) #arrays 239 { 240 $type = $+{type}; 241 $var = $+{var}; 242 $arr = $+{var}; 243 if($type eq ''){$type = "<unknown>";} 244 if($sinput =~ s/\bchar\b//){$type = $replace_type{'#string#'};} 245 else{$type .= ${array_marker};} #for identification of array .. stripped later 246 } 247 elsif($sinput =~ $typevar_regex) 248 { 249 $type = $+{type}; 250 $var = $+{var}; 251 $arr = $+{var}; 252 } 253 else { 254 warn "Skipping ".$sinput."\n"; 255 return ('', '', ''); 256 } 257 258 # Type substitutions 259 $type =~ s/^(unsigned|signed|struct)/$replace_type_prefix{$1}/x; 260 $type =~ s/\b(const|enum)\b/$replace_type_prefix{$1}/gx; 261 $type =~ s/^(?:.?+)(bool)\b/$replace_type{lc $1}/ix; 262 $type =~ s/^(uint|int)(?:\d\d_t)\b/$replace_type{lc $1}/ix; # ...intNN_t... 263 if($type =~ $array_mark_regex) 264 { 265 $type =~ s/\b(int|long|char|double)(${array_marker}.*)\b/$replace_type{$1}$2/; 266 } 267 else {$type =~ s/\b(int|long|char|double)\b/$replace_type{$1}/;} 268 $type =~ s{\s+}{}gx; 269 270 $var =~ s{[^\w\d_]+}{}gx; # strip non conforming chars 271 272 $arr =~ s{[^\[\d\]]+}{}gx; # get element count 273 274 return ($type, $var, $arr); 275} 276 277sub Print_Variable { 278 #[PASS 2] prints the member, offset, size, and type from the assembly file 279 my $sinput = $_[0]; 280 my ($member, $offset, $size, $type, $arr); 281 282 $sinput =~ s{[^\w\d_,=\"\*]+}{}gx; 283 if($sinput =~ $asmMOST_regex) 284 { 285 $member = $+{member}; 286 $offset = $+{offset}; 287 $size = $+{size}; 288 $type = $+{type}; 289 $arr = $+{arr}; 290 291 if($type =~ /^(.*)${array_marker}$/) # strip array marker add [n] 292 { 293 $type = sprintf('%s[%d]', $1, $arr); 294 } 295 296 printf "\t%s = \"0x%x, %d, %s\",\n", $member, $offset, $size, $type; 297 return 1; 298 } 299 return 0; 300} 301 302if($header) #output sections to lua file [PASS 2] 303{ 304 print "-- Don't change this file!\n"; 305 printf "-- It is automatically generated %s\n", $svnrev; 306 print "-- member = \"offset, size, type\"\n\n"; 307 308 print "--"; 309 foreach my $key (sort(keys %replace_type_prefix)) { 310 print $key, '= \'', $replace_type_prefix{$key}, '\', '; 311 } 312 print "\n--"; 313 foreach my $key (sort(keys %replace_type)) { 314 print $key, '= \'', $replace_type{$key}, '\', '; 315 } 316 print "\n\n"; 317 318 for(my $i = 0; $i < @sections_lua; $i++) 319 { 320 if($sections_lua[$i]) 321 { 322 print "$sections_lua[$i]$section_lua_suffix = {\n"; 323 324 my @members=split('@', $section_lists[$i]); 325 $section_lists[$i] = ''; 326 327 foreach my $memb(@members) 328 { 329 $section_count[$i] -= Print_Variable($memb); 330 } 331 332 print "}\n\n"; 333 334 if($sections[$i] && $section_count[$i] ne 0) 335 { 336 warn "$0 Warning: Failed to extract '$sections[$i]'\n"; 337 } 338 } 339 } 340 print "\nreturn false\n"; 341 #my ($user,$system,$cuser,$csystem) = times; 342 #warn "Pass2 ".$user." ".$system." ".$cuser." ".$csystem."\n"; 343 exit; 344} 345 346#else output sections to .c file [PASS 1] 347my $c_header = join(", ", $helper_name, @sections); 348my $print_variable = 'PRINT_M_O_S_T'; 349my $print_array = 'PRINT_ARRAY_M_O_S_T'; 350my $emit_asm = 'ASM_EMIT_M_O_S_T'; 351 352foreach my $incl(@includes) 353{ 354 printf "#include \"%s\"\n", $incl; 355} 356 357print <<EOF 358 359#include <stddef.h> /* offsetof */ 360#include <stdbool.h> 361 362/* (ab)uses the compiler to emit member offset and size to asm comments */ 363/* GAS supports C-style comments in asm files other compilers may not */ 364/* "NAME", "MEMBER" = ?OFFSET, ?SIZE, "TYPE, ?ARRAYCT"; 365 NOTE: ? may differ between machines */ 366 367#undef ${emit_asm} 368#define ${emit_asm}(name, member, type, offset, size, elems) asm volatile\\ 369("/* "#name ", " #member " = %0, %1, " #type ", %2; */\\n" : : \\ 370"n"(offset), "n"(size), "n"(elems)) 371 372/* constraint 'n' - An immediate integer operand with a known numeric value is allowed */ 373 374#undef ${print_variable} 375#define ${print_variable}(name, member, value, type) ${emit_asm}(#name, \\ 376#member, #type, offsetof(name, member), sizeof(value), 0) 377 378#undef ${print_array} 379#define ${print_array}(name, member, value, type) ${emit_asm}(#name, \\ 380#member, #type, offsetof(name, member), sizeof(value), sizeof(value)/sizeof(value[0])) 381 382int main(void) 383{ 384 385/* GAS supports C-style comments in asm files other compilers may not */ 386/* This header identifies assembler output for second pass */ 387asm volatile("/* $c_header; */"); 388 389EOF 390; 391my $section_prefix = "section_"; 392my $format_asm = " %s(%s, %s, ${section_prefix}%d.%s, %s);\n"; 393 394 395for(my $i = 0; $i < @sections; $i++) 396{ 397 if($sections[$i] && $section_lists[$i]) 398 { 399 printf "%s %s%d;\n", $sections[$i], $section_prefix, $i; #create variable for each section 400 my @members=split('@', $section_lists[$i]); 401 $section_lists[$i] = ''; 402 403 foreach my $memb(@members) 404 { 405 my ($type, $var, $arr) = Extract_Variable($memb); 406 my $call = ${print_variable}; 407 408 if($var =~ $pointer_mark_regex) #strip pointer marker 409 { 410 $type = $type.$1; 411 $var =~ s{.*${pointer_marker}}{}gx; 412 $type = $replace_type_prefix{'#pointer#'}.$type; 413 } 414 415 if($type && $var) 416 { 417 if($type =~ $array_mark_regex){$call = ${print_array};} 418 printf $format_asm, $call, $sections[$i], $var, $i, $var, $type; 419 } 420 } 421 } 422} 423print <<EOF 424 425 return 0; 426} 427 428EOF 429; 430 431#my ($user,$system,$cuser,$csystem) = times; 432#warn "Pass1 ".$user." ".$system." ".$cuser." ".$csystem."\n";