1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file conf.c 3d5ac70f0Sopenharmony_ci * \ingroup Configuration 4d5ac70f0Sopenharmony_ci * \brief Configuration helper functions 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 7d5ac70f0Sopenharmony_ci * \date 2000-2001 8d5ac70f0Sopenharmony_ci * 9d5ac70f0Sopenharmony_ci * Tree based, full nesting configuration functions. 10d5ac70f0Sopenharmony_ci * 11d5ac70f0Sopenharmony_ci * See the \ref conf page for more details. 12d5ac70f0Sopenharmony_ci */ 13d5ac70f0Sopenharmony_ci/* 14d5ac70f0Sopenharmony_ci * Configuration helper functions 15d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>, 16d5ac70f0Sopenharmony_ci * Jaroslav Kysela <perex@perex.cz> 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * 19d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 20d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 21d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 22d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 23d5ac70f0Sopenharmony_ci * 24d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 25d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 26d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 28d5ac70f0Sopenharmony_ci * 29d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 30d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 31d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 32d5ac70f0Sopenharmony_ci * 33d5ac70f0Sopenharmony_ci */ 34d5ac70f0Sopenharmony_ci 35d5ac70f0Sopenharmony_ci/*! \page conf Configuration files 36d5ac70f0Sopenharmony_ci 37d5ac70f0Sopenharmony_ci<P>Configuration files use a simple format allowing modern 38d5ac70f0Sopenharmony_cidata description like nesting and array assignments.</P> 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_ci\section conf_whitespace Whitespace 41d5ac70f0Sopenharmony_ci 42d5ac70f0Sopenharmony_ciWhitespace is the collective name given to spaces (blanks), horizontal and 43d5ac70f0Sopenharmony_civertical tabs, newline characters, and comments. Whitespace can 44d5ac70f0Sopenharmony_ciindicate where configuration tokens start and end, but beyond this function, 45d5ac70f0Sopenharmony_ciany surplus whitespace is discarded. For example, the two sequences 46d5ac70f0Sopenharmony_ci 47d5ac70f0Sopenharmony_ci\code 48d5ac70f0Sopenharmony_ci a 1 b 2 49d5ac70f0Sopenharmony_ci\endcode 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_ciand 52d5ac70f0Sopenharmony_ci 53d5ac70f0Sopenharmony_ci\code 54d5ac70f0Sopenharmony_ci a 1 55d5ac70f0Sopenharmony_ci b 2 56d5ac70f0Sopenharmony_ci\endcode 57d5ac70f0Sopenharmony_ci 58d5ac70f0Sopenharmony_ciare lexically equivalent and parse identically to give the four tokens: 59d5ac70f0Sopenharmony_ci 60d5ac70f0Sopenharmony_ci\code 61d5ac70f0Sopenharmony_cia 62d5ac70f0Sopenharmony_ci1 63d5ac70f0Sopenharmony_cib 64d5ac70f0Sopenharmony_ci2 65d5ac70f0Sopenharmony_ci\endcode 66d5ac70f0Sopenharmony_ci 67d5ac70f0Sopenharmony_ciThe ASCII characters representing whitespace can occur within literal 68d5ac70f0Sopenharmony_cistrings, in which case they are protected from the normal parsing process 69d5ac70f0Sopenharmony_ci(they remain as part of the string). For example: 70d5ac70f0Sopenharmony_ci 71d5ac70f0Sopenharmony_ci\code 72d5ac70f0Sopenharmony_ci name "John Smith" 73d5ac70f0Sopenharmony_ci\endcode 74d5ac70f0Sopenharmony_ci 75d5ac70f0Sopenharmony_ciparses to two tokens, including the single literal-string token "John 76d5ac70f0Sopenharmony_ciSmith". 77d5ac70f0Sopenharmony_ci 78d5ac70f0Sopenharmony_ci\section conf_linesplicing Line continuation with \ 79d5ac70f0Sopenharmony_ci 80d5ac70f0Sopenharmony_ciA special case occurs if a newline character in a string is preceded 81d5ac70f0Sopenharmony_ciby a backslash (\). The backslash and the new line are both discarded, 82d5ac70f0Sopenharmony_ciallowing two physical lines of text to be treated as one unit. 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_ci\code 85d5ac70f0Sopenharmony_ci"John \ 86d5ac70f0Sopenharmony_ciSmith" 87d5ac70f0Sopenharmony_ci\endcode 88d5ac70f0Sopenharmony_ci 89d5ac70f0Sopenharmony_ciis parsed as "John Smith". 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_ci\section conf_comments Comments 92d5ac70f0Sopenharmony_ci 93d5ac70f0Sopenharmony_ciA single-line comment begins with the character #. The comment can start 94d5ac70f0Sopenharmony_ciat any position, and extends to the end of the line. 95d5ac70f0Sopenharmony_ci 96d5ac70f0Sopenharmony_ci\code 97d5ac70f0Sopenharmony_ci a 1 # this is a comment 98d5ac70f0Sopenharmony_ci\endcode 99d5ac70f0Sopenharmony_ci 100d5ac70f0Sopenharmony_ci\section conf_include Including configuration files 101d5ac70f0Sopenharmony_ci 102d5ac70f0Sopenharmony_ciTo include another configuration file, write the file name in angle brackets. 103d5ac70f0Sopenharmony_ciThe prefix \c confdir: will reference the global configuration directory. 104d5ac70f0Sopenharmony_ci 105d5ac70f0Sopenharmony_ci\code 106d5ac70f0Sopenharmony_ci</etc/alsa1.conf> 107d5ac70f0Sopenharmony_ci<confdir:pcm/surround.conf> 108d5ac70f0Sopenharmony_ci\endcode 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_ci\section conf_punctuators Punctuators 111d5ac70f0Sopenharmony_ci 112d5ac70f0Sopenharmony_ciThe configuration punctuators (also known as separators) are: 113d5ac70f0Sopenharmony_ci 114d5ac70f0Sopenharmony_ci\code 115d5ac70f0Sopenharmony_ci {} [] , ; = . ' " new-line form-feed carriage-return whitespace 116d5ac70f0Sopenharmony_ci\endcode 117d5ac70f0Sopenharmony_ci 118d5ac70f0Sopenharmony_ci\subsection conf_braces Braces 119d5ac70f0Sopenharmony_ci 120d5ac70f0Sopenharmony_ciOpening and closing braces { } indicate the start and end of a compound 121d5ac70f0Sopenharmony_cistatement: 122d5ac70f0Sopenharmony_ci 123d5ac70f0Sopenharmony_ci\code 124d5ac70f0Sopenharmony_cia { 125d5ac70f0Sopenharmony_ci b 1 126d5ac70f0Sopenharmony_ci} 127d5ac70f0Sopenharmony_ci\endcode 128d5ac70f0Sopenharmony_ci 129d5ac70f0Sopenharmony_ci\subsection conf_brackets Brackets 130d5ac70f0Sopenharmony_ci 131d5ac70f0Sopenharmony_ciOpening and closing brackets indicate a single array definition. The 132d5ac70f0Sopenharmony_ciidentifiers are automatically generated starting with zero. 133d5ac70f0Sopenharmony_ci 134d5ac70f0Sopenharmony_ci\code 135d5ac70f0Sopenharmony_cia [ 136d5ac70f0Sopenharmony_ci "first" 137d5ac70f0Sopenharmony_ci "second" 138d5ac70f0Sopenharmony_ci] 139d5ac70f0Sopenharmony_ci\endcode 140d5ac70f0Sopenharmony_ci 141d5ac70f0Sopenharmony_ciThe above code is equal to 142d5ac70f0Sopenharmony_ci 143d5ac70f0Sopenharmony_ci\code 144d5ac70f0Sopenharmony_cia.0 "first" 145d5ac70f0Sopenharmony_cia.1 "second" 146d5ac70f0Sopenharmony_ci\endcode 147d5ac70f0Sopenharmony_ci 148d5ac70f0Sopenharmony_ci\subsection conf_comma_semicolon Comma and semicolon 149d5ac70f0Sopenharmony_ci 150d5ac70f0Sopenharmony_ciThe comma (,) or semicolon (;) can separate value assignments. It is not 151d5ac70f0Sopenharmony_cistrictly required to use these separators because whitespace suffices to 152d5ac70f0Sopenharmony_ciseparate tokens. 153d5ac70f0Sopenharmony_ci 154d5ac70f0Sopenharmony_ci\code 155d5ac70f0Sopenharmony_cia 1; 156d5ac70f0Sopenharmony_cib 1, 157d5ac70f0Sopenharmony_ci\endcode 158d5ac70f0Sopenharmony_ci 159d5ac70f0Sopenharmony_ci\subsection conf_equal Equal sign 160d5ac70f0Sopenharmony_ci 161d5ac70f0Sopenharmony_ciThe equal sign (=) can separate variable declarations from 162d5ac70f0Sopenharmony_ciinitialization lists: 163d5ac70f0Sopenharmony_ci 164d5ac70f0Sopenharmony_ci\code 165d5ac70f0Sopenharmony_cia=1 166d5ac70f0Sopenharmony_cib=2 167d5ac70f0Sopenharmony_ci\endcode 168d5ac70f0Sopenharmony_ci 169d5ac70f0Sopenharmony_ciUsing equal signs is not required because whitespace suffices to separate 170d5ac70f0Sopenharmony_citokens. 171d5ac70f0Sopenharmony_ci 172d5ac70f0Sopenharmony_ci\section conf_assigns Assignments 173d5ac70f0Sopenharmony_ci 174d5ac70f0Sopenharmony_ciThe configuration file defines id (key) and value pairs. The id (key) can be 175d5ac70f0Sopenharmony_cicomposed from ASCII digits, characters from a to z and A to Z, and the 176d5ac70f0Sopenharmony_ciunderscore (_). The value can be either a string, an integer, a real number, 177d5ac70f0Sopenharmony_cior a compound statement. 178d5ac70f0Sopenharmony_ci 179d5ac70f0Sopenharmony_ci\subsection conf_single Single assignments 180d5ac70f0Sopenharmony_ci 181d5ac70f0Sopenharmony_ci\code 182d5ac70f0Sopenharmony_cia 1 # is equal to 183d5ac70f0Sopenharmony_cia=1 # is equal to 184d5ac70f0Sopenharmony_cia=1; # is equal to 185d5ac70f0Sopenharmony_cia 1, 186d5ac70f0Sopenharmony_ci\endcode 187d5ac70f0Sopenharmony_ci 188d5ac70f0Sopenharmony_ci\subsection conf_compound Compound assignments (definitions using braces) 189d5ac70f0Sopenharmony_ci 190d5ac70f0Sopenharmony_ci\code 191d5ac70f0Sopenharmony_cia { 192d5ac70f0Sopenharmony_ci b = 1 193d5ac70f0Sopenharmony_ci} 194d5ac70f0Sopenharmony_cia={ 195d5ac70f0Sopenharmony_ci b 1, 196d5ac70f0Sopenharmony_ci} 197d5ac70f0Sopenharmony_ci\endcode 198d5ac70f0Sopenharmony_ci 199d5ac70f0Sopenharmony_ci\section conf_compound1 Compound assignments (one key definitions) 200d5ac70f0Sopenharmony_ci 201d5ac70f0Sopenharmony_ci\code 202d5ac70f0Sopenharmony_cia.b 1 203d5ac70f0Sopenharmony_cia.b=1 204d5ac70f0Sopenharmony_ci\endcode 205d5ac70f0Sopenharmony_ci 206d5ac70f0Sopenharmony_ci\subsection conf_array Array assignments (definitions using brackets) 207d5ac70f0Sopenharmony_ci 208d5ac70f0Sopenharmony_ci\code 209d5ac70f0Sopenharmony_cia [ 210d5ac70f0Sopenharmony_ci "first" 211d5ac70f0Sopenharmony_ci "second" 212d5ac70f0Sopenharmony_ci] 213d5ac70f0Sopenharmony_ci\endcode 214d5ac70f0Sopenharmony_ci 215d5ac70f0Sopenharmony_ci\subsection conf_array1 Array assignments (one key definitions) 216d5ac70f0Sopenharmony_ci 217d5ac70f0Sopenharmony_ci\code 218d5ac70f0Sopenharmony_cia.0 "first" 219d5ac70f0Sopenharmony_cia.1 "second" 220d5ac70f0Sopenharmony_ci\endcode 221d5ac70f0Sopenharmony_ci 222d5ac70f0Sopenharmony_ci\section conf_mode Operation modes for parsing nodes 223d5ac70f0Sopenharmony_ci 224d5ac70f0Sopenharmony_ciBy default, the node operation mode is 'merge+create', i.e., if 225d5ac70f0Sopenharmony_cia configuration node is not present a new one is created, otherwise 226d5ac70f0Sopenharmony_cithe latest assignment is merged (if possible - type checking). The 227d5ac70f0Sopenharmony_ci'merge+create' operation mode is specified with the prefix character plus (+). 228d5ac70f0Sopenharmony_ci 229d5ac70f0Sopenharmony_ciThe operation mode 'merge' merges the node with the old one (which must 230d5ac70f0Sopenharmony_ciexist). Type checking is done, so strings cannot be assigned to integers 231d5ac70f0Sopenharmony_ciand so on. This mode is specified with the prefix character minus (-). 232d5ac70f0Sopenharmony_ci 233d5ac70f0Sopenharmony_ciThe operation mode 'do not override' ignores a new configuration node 234d5ac70f0Sopenharmony_ciif a configuration node with the same name exists. This mode is specified with 235d5ac70f0Sopenharmony_cithe prefix character question mark (?). 236d5ac70f0Sopenharmony_ci 237d5ac70f0Sopenharmony_ciThe operation mode 'override' always overrides the old configuration node 238d5ac70f0Sopenharmony_ciwith new contents. This mode is specified with the prefix character 239d5ac70f0Sopenharmony_ciexclamation mark (!). 240d5ac70f0Sopenharmony_ci 241d5ac70f0Sopenharmony_ci\code 242d5ac70f0Sopenharmony_cidefaults.pcm.!device 1 243d5ac70f0Sopenharmony_ci\endcode 244d5ac70f0Sopenharmony_ci 245d5ac70f0Sopenharmony_ci\section conf_syntax_summary Syntax summary 246d5ac70f0Sopenharmony_ci 247d5ac70f0Sopenharmony_ci\code 248d5ac70f0Sopenharmony_ci# Configuration file syntax 249d5ac70f0Sopenharmony_ci 250d5ac70f0Sopenharmony_ci# Include a new configuration file 251d5ac70f0Sopenharmony_ci<filename> 252d5ac70f0Sopenharmony_ci 253d5ac70f0Sopenharmony_ci# Simple assignment 254d5ac70f0Sopenharmony_ciname [=] value [,|;] 255d5ac70f0Sopenharmony_ci 256d5ac70f0Sopenharmony_ci# Compound assignment (first style) 257d5ac70f0Sopenharmony_ciname [=] { 258d5ac70f0Sopenharmony_ci name1 [=] value [,|;] 259d5ac70f0Sopenharmony_ci ... 260d5ac70f0Sopenharmony_ci} 261d5ac70f0Sopenharmony_ci 262d5ac70f0Sopenharmony_ci# Compound assignment (second style) 263d5ac70f0Sopenharmony_ciname.name1 [=] value [,|;] 264d5ac70f0Sopenharmony_ci 265d5ac70f0Sopenharmony_ci# Array assignment (first style) 266d5ac70f0Sopenharmony_ciname [ 267d5ac70f0Sopenharmony_ci value0 [,|;] 268d5ac70f0Sopenharmony_ci value1 [,|;] 269d5ac70f0Sopenharmony_ci ... 270d5ac70f0Sopenharmony_ci] 271d5ac70f0Sopenharmony_ci 272d5ac70f0Sopenharmony_ci# Array assignment (second style) 273d5ac70f0Sopenharmony_ciname.0 [=] value0 [,|;] 274d5ac70f0Sopenharmony_ciname.1 [=] value1 [,|;] 275d5ac70f0Sopenharmony_ci\endcode 276d5ac70f0Sopenharmony_ci 277d5ac70f0Sopenharmony_ci\section conf_syntax_ref References 278d5ac70f0Sopenharmony_ci 279d5ac70f0Sopenharmony_ci\ref confarg 280d5ac70f0Sopenharmony_ci\ref conffunc 281d5ac70f0Sopenharmony_ci\ref confhooks 282d5ac70f0Sopenharmony_ci 283d5ac70f0Sopenharmony_ci*/ 284d5ac70f0Sopenharmony_ci 285d5ac70f0Sopenharmony_ci/*! \page confarg Runtime arguments in configuration files 286d5ac70f0Sopenharmony_ci 287d5ac70f0Sopenharmony_ci<P>The ALSA library can accept runtime arguments for some configuration 288d5ac70f0Sopenharmony_ciblocks. This extension is built on top of the basic configuration file 289d5ac70f0Sopenharmony_cisyntax.<P> 290d5ac70f0Sopenharmony_ci 291d5ac70f0Sopenharmony_ci\section confarg_define Defining arguments 292d5ac70f0Sopenharmony_ci 293d5ac70f0Sopenharmony_ciArguments are defined using the id (key) \c \@args and array values containing 294d5ac70f0Sopenharmony_cithe string names of the arguments: 295d5ac70f0Sopenharmony_ci 296d5ac70f0Sopenharmony_ci\code 297d5ac70f0Sopenharmony_ci@args [ CARD ] # or 298d5ac70f0Sopenharmony_ci@args.0 CARD 299d5ac70f0Sopenharmony_ci\endcode 300d5ac70f0Sopenharmony_ci 301d5ac70f0Sopenharmony_ci\section confarg_type Defining argument types and default values 302d5ac70f0Sopenharmony_ci 303d5ac70f0Sopenharmony_ciAn argument's type is specified with the id (key) \c \@args and the argument 304d5ac70f0Sopenharmony_ciname. The type and the default value are specified in the compound block: 305d5ac70f0Sopenharmony_ci 306d5ac70f0Sopenharmony_ci\code 307d5ac70f0Sopenharmony_ci@args.CARD { 308d5ac70f0Sopenharmony_ci type string 309d5ac70f0Sopenharmony_ci default "abcd" 310d5ac70f0Sopenharmony_ci} 311d5ac70f0Sopenharmony_ci\endcode 312d5ac70f0Sopenharmony_ci 313d5ac70f0Sopenharmony_ci\section confarg_refer Referring to arguments 314d5ac70f0Sopenharmony_ci 315d5ac70f0Sopenharmony_ciArguments are referred to with a dollar-sign ($) and the name of the argument: 316d5ac70f0Sopenharmony_ci 317d5ac70f0Sopenharmony_ci\code 318d5ac70f0Sopenharmony_ci card $CARD 319d5ac70f0Sopenharmony_ci\endcode 320d5ac70f0Sopenharmony_ci 321d5ac70f0Sopenharmony_ci\section confarg_math simple math expressions 322d5ac70f0Sopenharmony_ci 323d5ac70f0Sopenharmony_ciThe simple math expressions are identified using a unix shell like expression syntax 324d5ac70f0Sopenharmony_ciwith a dollar-sign ($) and bracket ([): 325d5ac70f0Sopenharmony_ci 326d5ac70f0Sopenharmony_ci\code 327d5ac70f0Sopenharmony_ci card "$[$CARD + 1]" 328d5ac70f0Sopenharmony_ci\endcode 329d5ac70f0Sopenharmony_ci 330d5ac70f0Sopenharmony_ci\section confarg_usage Usage 331d5ac70f0Sopenharmony_ci 332d5ac70f0Sopenharmony_ciTo use a block with arguments, write the argument values after the key, 333d5ac70f0Sopenharmony_ciseparated with a colon (:). For example, all these names for PCM interfaces 334d5ac70f0Sopenharmony_cigive the same result: 335d5ac70f0Sopenharmony_ci 336d5ac70f0Sopenharmony_ci\code 337d5ac70f0Sopenharmony_cihw:0,1 338d5ac70f0Sopenharmony_cihw:CARD=0,DEV=1 339d5ac70f0Sopenharmony_cihw:{CARD 0 DEV 1} 340d5ac70f0Sopenharmony_ciplug:"hw:0,1" 341d5ac70f0Sopenharmony_ciplug:{SLAVE="hw:{CARD 0 DEV 1}"} 342d5ac70f0Sopenharmony_ci\endcode 343d5ac70f0Sopenharmony_ci 344d5ac70f0Sopenharmony_ciAs you see, arguments can be specified in their proper order or by name. 345d5ac70f0Sopenharmony_ciNote that arguments enclosed in braces are parsed in the same way as in 346d5ac70f0Sopenharmony_ciconfiguration files, but using the override method by default. 347d5ac70f0Sopenharmony_ci 348d5ac70f0Sopenharmony_ci\section confarg_example Example 349d5ac70f0Sopenharmony_ci 350d5ac70f0Sopenharmony_ci\code 351d5ac70f0Sopenharmony_cipcm.demo { 352d5ac70f0Sopenharmony_ci @args [ CARD DEVICE ] 353d5ac70f0Sopenharmony_ci @args.CARD { 354d5ac70f0Sopenharmony_ci type string 355d5ac70f0Sopenharmony_ci default "supersonic" 356d5ac70f0Sopenharmony_ci } 357d5ac70f0Sopenharmony_ci @args.DEVICE { 358d5ac70f0Sopenharmony_ci type integer 359d5ac70f0Sopenharmony_ci default 0 360d5ac70f0Sopenharmony_ci } 361d5ac70f0Sopenharmony_ci type hw 362d5ac70f0Sopenharmony_ci card $CARD 363d5ac70f0Sopenharmony_ci device $DEVICE 364d5ac70f0Sopenharmony_ci} 365d5ac70f0Sopenharmony_ci\endcode 366d5ac70f0Sopenharmony_ci 367d5ac70f0Sopenharmony_ci 368d5ac70f0Sopenharmony_ci*/ 369d5ac70f0Sopenharmony_ci 370d5ac70f0Sopenharmony_ci/*! \page conffunc Runtime functions in configuration files 371d5ac70f0Sopenharmony_ci 372d5ac70f0Sopenharmony_ci<P>The ALSA library can modify the configuration at runtime. 373d5ac70f0Sopenharmony_ciSeveral built-in functions are available.</P> 374d5ac70f0Sopenharmony_ci 375d5ac70f0Sopenharmony_ci<P>A function is defined with the id \c \@func and the function name. All other 376d5ac70f0Sopenharmony_civalues in the current compound are used as configuration for the function. 377d5ac70f0Sopenharmony_ciIf the compound func.\<function_name\> is defined in the root node, then the 378d5ac70f0Sopenharmony_cilibrary and function from this compound configuration are used, otherwise 379d5ac70f0Sopenharmony_ci'snd_func_' is prefixed to the string and code from the ALSA library is used. 380d5ac70f0Sopenharmony_ciThe definition of a function looks like:</P> 381d5ac70f0Sopenharmony_ci 382d5ac70f0Sopenharmony_ci\code 383d5ac70f0Sopenharmony_cifunc.remove_first_char { 384d5ac70f0Sopenharmony_ci lib "/usr/lib/libasoundextend.so" 385d5ac70f0Sopenharmony_ci func "extend_remove_first_char" 386d5ac70f0Sopenharmony_ci} 387d5ac70f0Sopenharmony_ci\endcode 388d5ac70f0Sopenharmony_ci 389d5ac70f0Sopenharmony_ci*/ 390d5ac70f0Sopenharmony_ci 391d5ac70f0Sopenharmony_ci/*! \page confhooks Hooks in configuration files 392d5ac70f0Sopenharmony_ci 393d5ac70f0Sopenharmony_ci<P>The hook extension in the ALSA library allows expansion of configuration 394d5ac70f0Sopenharmony_cinodes at run-time. The existence of a hook is determined by the 395d5ac70f0Sopenharmony_cipresence of a \@hooks compound node.</P> 396d5ac70f0Sopenharmony_ci 397d5ac70f0Sopenharmony_ci<P>This example defines a hook which loads two configuration files at the 398d5ac70f0Sopenharmony_cibeginning:</P> 399d5ac70f0Sopenharmony_ci 400d5ac70f0Sopenharmony_ci\code 401d5ac70f0Sopenharmony_ci@hooks [ 402d5ac70f0Sopenharmony_ci { 403d5ac70f0Sopenharmony_ci func load 404d5ac70f0Sopenharmony_ci files [ 405d5ac70f0Sopenharmony_ci "/etc/asound.conf" 406d5ac70f0Sopenharmony_ci "~/.asoundrc" 407d5ac70f0Sopenharmony_ci ] 408d5ac70f0Sopenharmony_ci errors false 409d5ac70f0Sopenharmony_ci } 410d5ac70f0Sopenharmony_ci] 411d5ac70f0Sopenharmony_ci\endcode 412d5ac70f0Sopenharmony_ci 413d5ac70f0Sopenharmony_ci\section confhooks_ref Function reference 414d5ac70f0Sopenharmony_ci 415d5ac70f0Sopenharmony_ci<UL> 416d5ac70f0Sopenharmony_ci <LI>The function load - \c snd_config_hook_load() - loads and parses the 417d5ac70f0Sopenharmony_ci given configuration files. 418d5ac70f0Sopenharmony_ci <LI>The function load_for_all_cards - \c snd_config_hook_load_for_all_cards() - 419d5ac70f0Sopenharmony_ci loads and parses the given configuration files for each installed sound 420d5ac70f0Sopenharmony_ci card. The driver name (the type of the sound card) is passed in the 421d5ac70f0Sopenharmony_ci private configuration node. 422d5ac70f0Sopenharmony_ci</UL> 423d5ac70f0Sopenharmony_ci 424d5ac70f0Sopenharmony_ci*/ 425d5ac70f0Sopenharmony_ci 426d5ac70f0Sopenharmony_ci 427d5ac70f0Sopenharmony_ci#include "local.h" 428d5ac70f0Sopenharmony_ci#include <stdarg.h> 429d5ac70f0Sopenharmony_ci#include <stdbool.h> 430d5ac70f0Sopenharmony_ci#include <limits.h> 431d5ac70f0Sopenharmony_ci#include <sys/stat.h> 432d5ac70f0Sopenharmony_ci#include <dirent.h> 433d5ac70f0Sopenharmony_ci#include <locale.h> 434d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD 435d5ac70f0Sopenharmony_ci#include <pthread.h> 436d5ac70f0Sopenharmony_ci#endif 437d5ac70f0Sopenharmony_ci 438d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 439d5ac70f0Sopenharmony_ci 440d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD 441d5ac70f0Sopenharmony_cistatic pthread_mutex_t snd_config_update_mutex; 442d5ac70f0Sopenharmony_cistatic pthread_once_t snd_config_update_mutex_once = PTHREAD_ONCE_INIT; 443d5ac70f0Sopenharmony_ci#endif 444d5ac70f0Sopenharmony_ci 445d5ac70f0Sopenharmony_cistruct _snd_config { 446d5ac70f0Sopenharmony_ci char *id; 447d5ac70f0Sopenharmony_ci snd_config_type_t type; 448d5ac70f0Sopenharmony_ci int refcount; /* default = 0 */ 449d5ac70f0Sopenharmony_ci union { 450d5ac70f0Sopenharmony_ci long integer; 451d5ac70f0Sopenharmony_ci long long integer64; 452d5ac70f0Sopenharmony_ci char *string; 453d5ac70f0Sopenharmony_ci double real; 454d5ac70f0Sopenharmony_ci const void *ptr; 455d5ac70f0Sopenharmony_ci struct { 456d5ac70f0Sopenharmony_ci struct list_head fields; 457d5ac70f0Sopenharmony_ci bool join; 458d5ac70f0Sopenharmony_ci } compound; 459d5ac70f0Sopenharmony_ci } u; 460d5ac70f0Sopenharmony_ci struct list_head list; 461d5ac70f0Sopenharmony_ci snd_config_t *parent; 462d5ac70f0Sopenharmony_ci int hop; 463d5ac70f0Sopenharmony_ci}; 464d5ac70f0Sopenharmony_ci 465d5ac70f0Sopenharmony_cistruct filedesc { 466d5ac70f0Sopenharmony_ci char *name; 467d5ac70f0Sopenharmony_ci snd_input_t *in; 468d5ac70f0Sopenharmony_ci unsigned int line, column; 469d5ac70f0Sopenharmony_ci struct filedesc *next; 470d5ac70f0Sopenharmony_ci 471d5ac70f0Sopenharmony_ci /* list of the include paths (configuration directories), 472d5ac70f0Sopenharmony_ci * defined by <searchdir:relative-path/to/top-alsa-conf-dir>, 473d5ac70f0Sopenharmony_ci * for searching its included files. 474d5ac70f0Sopenharmony_ci */ 475d5ac70f0Sopenharmony_ci struct list_head include_paths; 476d5ac70f0Sopenharmony_ci}; 477d5ac70f0Sopenharmony_ci 478d5ac70f0Sopenharmony_ci/* path to search included files */ 479d5ac70f0Sopenharmony_cistruct include_path { 480d5ac70f0Sopenharmony_ci char *dir; 481d5ac70f0Sopenharmony_ci struct list_head list; 482d5ac70f0Sopenharmony_ci}; 483d5ac70f0Sopenharmony_ci 484d5ac70f0Sopenharmony_ci#define LOCAL_ERROR (-0x68000000) 485d5ac70f0Sopenharmony_ci 486d5ac70f0Sopenharmony_ci#define LOCAL_UNTERMINATED_STRING (LOCAL_ERROR - 0) 487d5ac70f0Sopenharmony_ci#define LOCAL_UNTERMINATED_QUOTE (LOCAL_ERROR - 1) 488d5ac70f0Sopenharmony_ci#define LOCAL_UNEXPECTED_CHAR (LOCAL_ERROR - 2) 489d5ac70f0Sopenharmony_ci#define LOCAL_UNEXPECTED_EOF (LOCAL_ERROR - 3) 490d5ac70f0Sopenharmony_ci 491d5ac70f0Sopenharmony_citypedef struct { 492d5ac70f0Sopenharmony_ci struct filedesc *current; 493d5ac70f0Sopenharmony_ci int unget; 494d5ac70f0Sopenharmony_ci int ch; 495d5ac70f0Sopenharmony_ci} input_t; 496d5ac70f0Sopenharmony_ci 497d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD 498d5ac70f0Sopenharmony_ci 499d5ac70f0Sopenharmony_cistatic void snd_config_init_mutex(void) 500d5ac70f0Sopenharmony_ci{ 501d5ac70f0Sopenharmony_ci pthread_mutexattr_t attr; 502d5ac70f0Sopenharmony_ci 503d5ac70f0Sopenharmony_ci pthread_mutexattr_init(&attr); 504d5ac70f0Sopenharmony_ci#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE 505d5ac70f0Sopenharmony_ci pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 506d5ac70f0Sopenharmony_ci#endif 507d5ac70f0Sopenharmony_ci pthread_mutex_init(&snd_config_update_mutex, &attr); 508d5ac70f0Sopenharmony_ci pthread_mutexattr_destroy(&attr); 509d5ac70f0Sopenharmony_ci} 510d5ac70f0Sopenharmony_ci 511d5ac70f0Sopenharmony_cistatic inline void snd_config_lock(void) 512d5ac70f0Sopenharmony_ci{ 513d5ac70f0Sopenharmony_ci pthread_once(&snd_config_update_mutex_once, snd_config_init_mutex); 514d5ac70f0Sopenharmony_ci pthread_mutex_lock(&snd_config_update_mutex); 515d5ac70f0Sopenharmony_ci} 516d5ac70f0Sopenharmony_ci 517d5ac70f0Sopenharmony_cistatic inline void snd_config_unlock(void) 518d5ac70f0Sopenharmony_ci{ 519d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&snd_config_update_mutex); 520d5ac70f0Sopenharmony_ci} 521d5ac70f0Sopenharmony_ci 522d5ac70f0Sopenharmony_ci#else 523d5ac70f0Sopenharmony_ci 524d5ac70f0Sopenharmony_cistatic inline void snd_config_lock(void) { } 525d5ac70f0Sopenharmony_cistatic inline void snd_config_unlock(void) { } 526d5ac70f0Sopenharmony_ci 527d5ac70f0Sopenharmony_ci#endif 528d5ac70f0Sopenharmony_ci 529d5ac70f0Sopenharmony_ci/* 530d5ac70f0Sopenharmony_ci * Add a directory to the paths to search included files. 531d5ac70f0Sopenharmony_ci * param fd - File object that owns these paths to search files included by it. 532d5ac70f0Sopenharmony_ci * param dir - Path of the directory to add. Allocated externally and need to 533d5ac70f0Sopenharmony_ci* be freed manually later. 534d5ac70f0Sopenharmony_ci * return - Zero if successful, otherwise a negative error code. 535d5ac70f0Sopenharmony_ci * 536d5ac70f0Sopenharmony_ci * The direcotry should be a subdiretory of top configuration directory 537d5ac70f0Sopenharmony_ci * "/usr/share/alsa/". 538d5ac70f0Sopenharmony_ci */ 539d5ac70f0Sopenharmony_cistatic int add_include_path(struct filedesc *fd, const char *dir) 540d5ac70f0Sopenharmony_ci{ 541d5ac70f0Sopenharmony_ci struct include_path *path; 542d5ac70f0Sopenharmony_ci struct filedesc *fd1; 543d5ac70f0Sopenharmony_ci struct list_head *pos; 544d5ac70f0Sopenharmony_ci 545d5ac70f0Sopenharmony_ci /* check, if dir is already registered (also in parents) */ 546d5ac70f0Sopenharmony_ci for (fd1 = fd; fd1; fd1 = fd1->next) { 547d5ac70f0Sopenharmony_ci list_for_each(pos, &fd1->include_paths) { 548d5ac70f0Sopenharmony_ci path = list_entry(pos, struct include_path, list); 549d5ac70f0Sopenharmony_ci if (strcmp(path->dir, dir) == 0) 550d5ac70f0Sopenharmony_ci return 0; 551d5ac70f0Sopenharmony_ci } 552d5ac70f0Sopenharmony_ci } 553d5ac70f0Sopenharmony_ci 554d5ac70f0Sopenharmony_ci path = calloc(1, sizeof(*path)); 555d5ac70f0Sopenharmony_ci if (!path) 556d5ac70f0Sopenharmony_ci return -ENOMEM; 557d5ac70f0Sopenharmony_ci 558d5ac70f0Sopenharmony_ci path->dir = strdup(dir); 559d5ac70f0Sopenharmony_ci if (path->dir == NULL) { 560d5ac70f0Sopenharmony_ci free(path); 561d5ac70f0Sopenharmony_ci return -ENOMEM; 562d5ac70f0Sopenharmony_ci } 563d5ac70f0Sopenharmony_ci 564d5ac70f0Sopenharmony_ci list_add_tail(&path->list, &fd->include_paths); 565d5ac70f0Sopenharmony_ci return 0; 566d5ac70f0Sopenharmony_ci} 567d5ac70f0Sopenharmony_ci 568d5ac70f0Sopenharmony_ci/* 569d5ac70f0Sopenharmony_ci * Free all include paths of a file descriptor. 570d5ac70f0Sopenharmony_ci * param fd - File object that owns these paths to search files included by it. 571d5ac70f0Sopenharmony_ci */ 572d5ac70f0Sopenharmony_cistatic void free_include_paths(struct filedesc *fd) 573d5ac70f0Sopenharmony_ci{ 574d5ac70f0Sopenharmony_ci struct list_head *pos, *npos, *base; 575d5ac70f0Sopenharmony_ci struct include_path *path; 576d5ac70f0Sopenharmony_ci 577d5ac70f0Sopenharmony_ci base = &fd->include_paths; 578d5ac70f0Sopenharmony_ci list_for_each_safe(pos, npos, base) { 579d5ac70f0Sopenharmony_ci path = list_entry(pos, struct include_path, list); 580d5ac70f0Sopenharmony_ci list_del(&path->list); 581d5ac70f0Sopenharmony_ci if (path->dir) 582d5ac70f0Sopenharmony_ci free(path->dir); 583d5ac70f0Sopenharmony_ci free(path); 584d5ac70f0Sopenharmony_ci } 585d5ac70f0Sopenharmony_ci} 586d5ac70f0Sopenharmony_ci 587d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 588d5ac70f0Sopenharmony_ci 589d5ac70f0Sopenharmony_ci/** 590d5ac70f0Sopenharmony_ci * \brief Returns the default top-level config directory 591d5ac70f0Sopenharmony_ci * \return The top-level config directory path string 592d5ac70f0Sopenharmony_ci * 593d5ac70f0Sopenharmony_ci * This function returns the string of the top-level config directory path. 594d5ac70f0Sopenharmony_ci * If the path is specified via the environment variable \c ALSA_CONFIG_DIR 595d5ac70f0Sopenharmony_ci * and the value is a valid path, it returns this value. If unspecified, it 596d5ac70f0Sopenharmony_ci * returns the default value, "/usr/share/alsa". 597d5ac70f0Sopenharmony_ci */ 598d5ac70f0Sopenharmony_ciconst char *snd_config_topdir(void) 599d5ac70f0Sopenharmony_ci{ 600d5ac70f0Sopenharmony_ci static char *topdir; 601d5ac70f0Sopenharmony_ci 602d5ac70f0Sopenharmony_ci if (!topdir) { 603d5ac70f0Sopenharmony_ci topdir = getenv("ALSA_CONFIG_DIR"); 604d5ac70f0Sopenharmony_ci if (!topdir || *topdir != '/' || strlen(topdir) >= PATH_MAX) 605d5ac70f0Sopenharmony_ci topdir = ALSA_CONFIG_DIR; 606d5ac70f0Sopenharmony_ci } 607d5ac70f0Sopenharmony_ci return topdir; 608d5ac70f0Sopenharmony_ci} 609d5ac70f0Sopenharmony_ci 610d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 611d5ac70f0Sopenharmony_ci 612d5ac70f0Sopenharmony_cistatic char *_snd_config_path(const char *name) 613d5ac70f0Sopenharmony_ci{ 614d5ac70f0Sopenharmony_ci const char *root = snd_config_topdir(); 615d5ac70f0Sopenharmony_ci char *path = malloc(strlen(root) + strlen(name) + 2); 616d5ac70f0Sopenharmony_ci if (!path) 617d5ac70f0Sopenharmony_ci return NULL; 618d5ac70f0Sopenharmony_ci sprintf(path, "%s/%s", root, name); 619d5ac70f0Sopenharmony_ci return path; 620d5ac70f0Sopenharmony_ci} 621d5ac70f0Sopenharmony_ci 622d5ac70f0Sopenharmony_ci/* 623d5ac70f0Sopenharmony_ci * Search and open a file, and creates a new input object reading from the file. 624d5ac70f0Sopenharmony_ci * param inputp - The functions puts the pointer to the new input object 625d5ac70f0Sopenharmony_ci * at the address specified by \p inputp. 626d5ac70f0Sopenharmony_ci * param file - Name of the configuration file. 627d5ac70f0Sopenharmony_ci * param include_paths - Optional, addtional directories to search the file. 628d5ac70f0Sopenharmony_ci * return - Zero if successful, otherwise a negative error code. 629d5ac70f0Sopenharmony_ci * 630d5ac70f0Sopenharmony_ci * This function will search and open the file in the following order 631d5ac70f0Sopenharmony_ci * of priority: 632d5ac70f0Sopenharmony_ci * 1. directly open the file by its name (only if absolute) 633d5ac70f0Sopenharmony_ci * 2. search for the file name in in additional configuration directories 634d5ac70f0Sopenharmony_ci * specified by users, via alsaconf syntax 635d5ac70f0Sopenharmony_ci * <searchdir:relative-path/to/user/share/alsa>; 636d5ac70f0Sopenharmony_ci * These directories should be subdirectories of /usr/share/alsa. 637d5ac70f0Sopenharmony_ci */ 638d5ac70f0Sopenharmony_cistatic int input_stdio_open(snd_input_t **inputp, const char *file, 639d5ac70f0Sopenharmony_ci struct filedesc *current) 640d5ac70f0Sopenharmony_ci{ 641d5ac70f0Sopenharmony_ci struct list_head *pos; 642d5ac70f0Sopenharmony_ci struct include_path *path; 643d5ac70f0Sopenharmony_ci char full_path[PATH_MAX]; 644d5ac70f0Sopenharmony_ci int err; 645d5ac70f0Sopenharmony_ci 646d5ac70f0Sopenharmony_ci if (file[0] == '/') 647d5ac70f0Sopenharmony_ci return snd_input_stdio_open(inputp, file, "r"); 648d5ac70f0Sopenharmony_ci 649d5ac70f0Sopenharmony_ci /* search file in user specified include paths. These directories 650d5ac70f0Sopenharmony_ci * are subdirectories of /usr/share/alsa. 651d5ac70f0Sopenharmony_ci */ 652d5ac70f0Sopenharmony_ci err = -ENOENT; 653d5ac70f0Sopenharmony_ci while (current) { 654d5ac70f0Sopenharmony_ci list_for_each(pos, ¤t->include_paths) { 655d5ac70f0Sopenharmony_ci path = list_entry(pos, struct include_path, list); 656d5ac70f0Sopenharmony_ci if (!path->dir) 657d5ac70f0Sopenharmony_ci continue; 658d5ac70f0Sopenharmony_ci 659d5ac70f0Sopenharmony_ci snprintf(full_path, PATH_MAX, "%s/%s", path->dir, file); 660d5ac70f0Sopenharmony_ci err = snd_input_stdio_open(inputp, full_path, "r"); 661d5ac70f0Sopenharmony_ci if (err == 0) 662d5ac70f0Sopenharmony_ci return 0; 663d5ac70f0Sopenharmony_ci } 664d5ac70f0Sopenharmony_ci current = current->next; 665d5ac70f0Sopenharmony_ci } 666d5ac70f0Sopenharmony_ci 667d5ac70f0Sopenharmony_ci return err; 668d5ac70f0Sopenharmony_ci} 669d5ac70f0Sopenharmony_ci 670d5ac70f0Sopenharmony_ciint _snd_safe_strtoll_base(const char *str, long long *val, int base) 671d5ac70f0Sopenharmony_ci{ 672d5ac70f0Sopenharmony_ci char *end; 673d5ac70f0Sopenharmony_ci long v; 674d5ac70f0Sopenharmony_ci if (!*str) 675d5ac70f0Sopenharmony_ci return -EINVAL; 676d5ac70f0Sopenharmony_ci errno = 0; 677d5ac70f0Sopenharmony_ci v = strtoll(str, &end, base); 678d5ac70f0Sopenharmony_ci if (errno) 679d5ac70f0Sopenharmony_ci return -errno; 680d5ac70f0Sopenharmony_ci if (*end) 681d5ac70f0Sopenharmony_ci return -EINVAL; 682d5ac70f0Sopenharmony_ci *val = v; 683d5ac70f0Sopenharmony_ci return 0; 684d5ac70f0Sopenharmony_ci} 685d5ac70f0Sopenharmony_ci 686d5ac70f0Sopenharmony_ciint _snd_safe_strtol_base(const char *str, long *val, int base) 687d5ac70f0Sopenharmony_ci{ 688d5ac70f0Sopenharmony_ci char *end; 689d5ac70f0Sopenharmony_ci long v; 690d5ac70f0Sopenharmony_ci if (!*str) 691d5ac70f0Sopenharmony_ci return -EINVAL; 692d5ac70f0Sopenharmony_ci errno = 0; 693d5ac70f0Sopenharmony_ci v = strtol(str, &end, base); 694d5ac70f0Sopenharmony_ci if (errno) 695d5ac70f0Sopenharmony_ci return -errno; 696d5ac70f0Sopenharmony_ci if (*end) 697d5ac70f0Sopenharmony_ci return -EINVAL; 698d5ac70f0Sopenharmony_ci *val = v; 699d5ac70f0Sopenharmony_ci return 0; 700d5ac70f0Sopenharmony_ci} 701d5ac70f0Sopenharmony_ci 702d5ac70f0Sopenharmony_ciint _snd_safe_strtod(const char *str, double *val) 703d5ac70f0Sopenharmony_ci{ 704d5ac70f0Sopenharmony_ci char *end; 705d5ac70f0Sopenharmony_ci double v; 706d5ac70f0Sopenharmony_ci#ifdef HAVE_USELOCALE 707d5ac70f0Sopenharmony_ci locale_t saved_locale, c_locale; 708d5ac70f0Sopenharmony_ci#else 709d5ac70f0Sopenharmony_ci char *saved_locale; 710d5ac70f0Sopenharmony_ci char locstr[64]; /* enough? */ 711d5ac70f0Sopenharmony_ci#endif 712d5ac70f0Sopenharmony_ci int err; 713d5ac70f0Sopenharmony_ci 714d5ac70f0Sopenharmony_ci if (!*str) 715d5ac70f0Sopenharmony_ci return -EINVAL; 716d5ac70f0Sopenharmony_ci#ifdef HAVE_USELOCALE 717d5ac70f0Sopenharmony_ci c_locale = newlocale(LC_NUMERIC_MASK, "C", 0); 718d5ac70f0Sopenharmony_ci saved_locale = uselocale(c_locale); 719d5ac70f0Sopenharmony_ci#else 720d5ac70f0Sopenharmony_ci saved_locale = setlocale(LC_NUMERIC, NULL); 721d5ac70f0Sopenharmony_ci if (saved_locale) { 722d5ac70f0Sopenharmony_ci snprintf(locstr, sizeof(locstr), "%s", saved_locale); 723d5ac70f0Sopenharmony_ci setlocale(LC_NUMERIC, "C"); 724d5ac70f0Sopenharmony_ci } 725d5ac70f0Sopenharmony_ci#endif 726d5ac70f0Sopenharmony_ci errno = 0; 727d5ac70f0Sopenharmony_ci v = strtod(str, &end); 728d5ac70f0Sopenharmony_ci err = -errno; 729d5ac70f0Sopenharmony_ci#ifdef HAVE_USELOCALE 730d5ac70f0Sopenharmony_ci if (c_locale != (locale_t)0) { 731d5ac70f0Sopenharmony_ci uselocale(saved_locale); 732d5ac70f0Sopenharmony_ci freelocale(c_locale); 733d5ac70f0Sopenharmony_ci } 734d5ac70f0Sopenharmony_ci#else 735d5ac70f0Sopenharmony_ci if (saved_locale) 736d5ac70f0Sopenharmony_ci setlocale(LC_NUMERIC, locstr); 737d5ac70f0Sopenharmony_ci#endif 738d5ac70f0Sopenharmony_ci if (err) 739d5ac70f0Sopenharmony_ci return err; 740d5ac70f0Sopenharmony_ci if (*end) 741d5ac70f0Sopenharmony_ci return -EINVAL; 742d5ac70f0Sopenharmony_ci *val = v; 743d5ac70f0Sopenharmony_ci return 0; 744d5ac70f0Sopenharmony_ci} 745d5ac70f0Sopenharmony_ci 746d5ac70f0Sopenharmony_cistatic int get_char(input_t *input) 747d5ac70f0Sopenharmony_ci{ 748d5ac70f0Sopenharmony_ci int c; 749d5ac70f0Sopenharmony_ci struct filedesc *fd; 750d5ac70f0Sopenharmony_ci if (input->unget) { 751d5ac70f0Sopenharmony_ci input->unget = 0; 752d5ac70f0Sopenharmony_ci return input->ch; 753d5ac70f0Sopenharmony_ci } 754d5ac70f0Sopenharmony_ci again: 755d5ac70f0Sopenharmony_ci fd = input->current; 756d5ac70f0Sopenharmony_ci c = snd_input_getc(fd->in); 757d5ac70f0Sopenharmony_ci switch (c) { 758d5ac70f0Sopenharmony_ci case '\n': 759d5ac70f0Sopenharmony_ci fd->column = 0; 760d5ac70f0Sopenharmony_ci fd->line++; 761d5ac70f0Sopenharmony_ci break; 762d5ac70f0Sopenharmony_ci case '\t': 763d5ac70f0Sopenharmony_ci fd->column += 8 - fd->column % 8; 764d5ac70f0Sopenharmony_ci break; 765d5ac70f0Sopenharmony_ci case EOF: 766d5ac70f0Sopenharmony_ci if (fd->next) { 767d5ac70f0Sopenharmony_ci snd_input_close(fd->in); 768d5ac70f0Sopenharmony_ci free(fd->name); 769d5ac70f0Sopenharmony_ci input->current = fd->next; 770d5ac70f0Sopenharmony_ci free(fd); 771d5ac70f0Sopenharmony_ci goto again; 772d5ac70f0Sopenharmony_ci } 773d5ac70f0Sopenharmony_ci return LOCAL_UNEXPECTED_EOF; 774d5ac70f0Sopenharmony_ci default: 775d5ac70f0Sopenharmony_ci fd->column++; 776d5ac70f0Sopenharmony_ci break; 777d5ac70f0Sopenharmony_ci } 778d5ac70f0Sopenharmony_ci return (unsigned char)c; 779d5ac70f0Sopenharmony_ci} 780d5ac70f0Sopenharmony_ci 781d5ac70f0Sopenharmony_cistatic void unget_char(int c, input_t *input) 782d5ac70f0Sopenharmony_ci{ 783d5ac70f0Sopenharmony_ci assert(!input->unget); 784d5ac70f0Sopenharmony_ci input->ch = c; 785d5ac70f0Sopenharmony_ci input->unget = 1; 786d5ac70f0Sopenharmony_ci} 787d5ac70f0Sopenharmony_ci 788d5ac70f0Sopenharmony_cistatic int get_delimstring(char **string, int delim, input_t *input); 789d5ac70f0Sopenharmony_ci 790d5ac70f0Sopenharmony_cistatic int get_char_skip_comments(input_t *input) 791d5ac70f0Sopenharmony_ci{ 792d5ac70f0Sopenharmony_ci int c; 793d5ac70f0Sopenharmony_ci while (1) { 794d5ac70f0Sopenharmony_ci c = get_char(input); 795d5ac70f0Sopenharmony_ci if (c == '<') { 796d5ac70f0Sopenharmony_ci char *str; 797d5ac70f0Sopenharmony_ci snd_input_t *in; 798d5ac70f0Sopenharmony_ci struct filedesc *fd; 799d5ac70f0Sopenharmony_ci DIR *dirp; 800d5ac70f0Sopenharmony_ci int err = get_delimstring(&str, '>', input); 801d5ac70f0Sopenharmony_ci if (err < 0) 802d5ac70f0Sopenharmony_ci return err; 803d5ac70f0Sopenharmony_ci 804d5ac70f0Sopenharmony_ci if (!strncmp(str, "searchdir:", 10)) { 805d5ac70f0Sopenharmony_ci /* directory to search included files */ 806d5ac70f0Sopenharmony_ci char *tmp = _snd_config_path(str + 10); 807d5ac70f0Sopenharmony_ci free(str); 808d5ac70f0Sopenharmony_ci if (tmp == NULL) 809d5ac70f0Sopenharmony_ci return -ENOMEM; 810d5ac70f0Sopenharmony_ci str = tmp; 811d5ac70f0Sopenharmony_ci 812d5ac70f0Sopenharmony_ci dirp = opendir(str); 813d5ac70f0Sopenharmony_ci if (!dirp) { 814d5ac70f0Sopenharmony_ci SNDERR("Invalid search dir %s", str); 815d5ac70f0Sopenharmony_ci free(str); 816d5ac70f0Sopenharmony_ci return -EINVAL; 817d5ac70f0Sopenharmony_ci } 818d5ac70f0Sopenharmony_ci closedir(dirp); 819d5ac70f0Sopenharmony_ci 820d5ac70f0Sopenharmony_ci err = add_include_path(input->current, str); 821d5ac70f0Sopenharmony_ci if (err < 0) { 822d5ac70f0Sopenharmony_ci SNDERR("Cannot add search dir %s", str); 823d5ac70f0Sopenharmony_ci free(str); 824d5ac70f0Sopenharmony_ci return err; 825d5ac70f0Sopenharmony_ci } 826d5ac70f0Sopenharmony_ci free(str); 827d5ac70f0Sopenharmony_ci continue; 828d5ac70f0Sopenharmony_ci } 829d5ac70f0Sopenharmony_ci 830d5ac70f0Sopenharmony_ci if (!strncmp(str, "confdir:", 8)) { 831d5ac70f0Sopenharmony_ci /* file in the specified directory */ 832d5ac70f0Sopenharmony_ci char *tmp = _snd_config_path(str + 8); 833d5ac70f0Sopenharmony_ci free(str); 834d5ac70f0Sopenharmony_ci if (tmp == NULL) 835d5ac70f0Sopenharmony_ci return -ENOMEM; 836d5ac70f0Sopenharmony_ci str = tmp; 837d5ac70f0Sopenharmony_ci err = snd_input_stdio_open(&in, str, "r"); 838d5ac70f0Sopenharmony_ci } else { /* absolute or relative file path */ 839d5ac70f0Sopenharmony_ci err = input_stdio_open(&in, str, input->current); 840d5ac70f0Sopenharmony_ci } 841d5ac70f0Sopenharmony_ci 842d5ac70f0Sopenharmony_ci if (err < 0) { 843d5ac70f0Sopenharmony_ci SNDERR("Cannot access file %s", str); 844d5ac70f0Sopenharmony_ci free(str); 845d5ac70f0Sopenharmony_ci return err; 846d5ac70f0Sopenharmony_ci } 847d5ac70f0Sopenharmony_ci fd = malloc(sizeof(*fd)); 848d5ac70f0Sopenharmony_ci if (!fd) { 849d5ac70f0Sopenharmony_ci free(str); 850d5ac70f0Sopenharmony_ci return -ENOMEM; 851d5ac70f0Sopenharmony_ci } 852d5ac70f0Sopenharmony_ci fd->name = str; 853d5ac70f0Sopenharmony_ci fd->in = in; 854d5ac70f0Sopenharmony_ci fd->next = input->current; 855d5ac70f0Sopenharmony_ci fd->line = 1; 856d5ac70f0Sopenharmony_ci fd->column = 0; 857d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&fd->include_paths); 858d5ac70f0Sopenharmony_ci input->current = fd; 859d5ac70f0Sopenharmony_ci continue; 860d5ac70f0Sopenharmony_ci } 861d5ac70f0Sopenharmony_ci if (c != '#') 862d5ac70f0Sopenharmony_ci break; 863d5ac70f0Sopenharmony_ci while (1) { 864d5ac70f0Sopenharmony_ci c = get_char(input); 865d5ac70f0Sopenharmony_ci if (c < 0) 866d5ac70f0Sopenharmony_ci return c; 867d5ac70f0Sopenharmony_ci if (c == '\n') 868d5ac70f0Sopenharmony_ci break; 869d5ac70f0Sopenharmony_ci } 870d5ac70f0Sopenharmony_ci } 871d5ac70f0Sopenharmony_ci 872d5ac70f0Sopenharmony_ci return c; 873d5ac70f0Sopenharmony_ci} 874d5ac70f0Sopenharmony_ci 875d5ac70f0Sopenharmony_ci 876d5ac70f0Sopenharmony_cistatic int get_nonwhite(input_t *input) 877d5ac70f0Sopenharmony_ci{ 878d5ac70f0Sopenharmony_ci int c; 879d5ac70f0Sopenharmony_ci while (1) { 880d5ac70f0Sopenharmony_ci c = get_char_skip_comments(input); 881d5ac70f0Sopenharmony_ci switch (c) { 882d5ac70f0Sopenharmony_ci case ' ': 883d5ac70f0Sopenharmony_ci case '\f': 884d5ac70f0Sopenharmony_ci case '\t': 885d5ac70f0Sopenharmony_ci case '\n': 886d5ac70f0Sopenharmony_ci case '\r': 887d5ac70f0Sopenharmony_ci break; 888d5ac70f0Sopenharmony_ci default: 889d5ac70f0Sopenharmony_ci return c; 890d5ac70f0Sopenharmony_ci } 891d5ac70f0Sopenharmony_ci } 892d5ac70f0Sopenharmony_ci} 893d5ac70f0Sopenharmony_ci 894d5ac70f0Sopenharmony_cistatic inline int get_hexachar(input_t *input) 895d5ac70f0Sopenharmony_ci{ 896d5ac70f0Sopenharmony_ci int c, num = 0; 897d5ac70f0Sopenharmony_ci 898d5ac70f0Sopenharmony_ci c = get_char(input); 899d5ac70f0Sopenharmony_ci if (c >= '0' && c <= '9') num |= (c - '0') << 4; 900d5ac70f0Sopenharmony_ci else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 4; 901d5ac70f0Sopenharmony_ci else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 4; 902d5ac70f0Sopenharmony_ci c = get_char(input); 903d5ac70f0Sopenharmony_ci if (c >= '0' && c <= '9') num |= (c - '0') << 0; 904d5ac70f0Sopenharmony_ci else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 0; 905d5ac70f0Sopenharmony_ci else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 0; 906d5ac70f0Sopenharmony_ci return num; 907d5ac70f0Sopenharmony_ci} 908d5ac70f0Sopenharmony_ci 909d5ac70f0Sopenharmony_cistatic int get_quotedchar(input_t *input) 910d5ac70f0Sopenharmony_ci{ 911d5ac70f0Sopenharmony_ci int c; 912d5ac70f0Sopenharmony_ci c = get_char(input); 913d5ac70f0Sopenharmony_ci switch (c) { 914d5ac70f0Sopenharmony_ci case 'n': 915d5ac70f0Sopenharmony_ci return '\n'; 916d5ac70f0Sopenharmony_ci case 't': 917d5ac70f0Sopenharmony_ci return '\t'; 918d5ac70f0Sopenharmony_ci case 'v': 919d5ac70f0Sopenharmony_ci return '\v'; 920d5ac70f0Sopenharmony_ci case 'b': 921d5ac70f0Sopenharmony_ci return '\b'; 922d5ac70f0Sopenharmony_ci case 'r': 923d5ac70f0Sopenharmony_ci return '\r'; 924d5ac70f0Sopenharmony_ci case 'f': 925d5ac70f0Sopenharmony_ci return '\f'; 926d5ac70f0Sopenharmony_ci case 'x': 927d5ac70f0Sopenharmony_ci return get_hexachar(input); 928d5ac70f0Sopenharmony_ci case '0': case '1': case '2': case '3': 929d5ac70f0Sopenharmony_ci case '4': case '5': case '6': case '7': 930d5ac70f0Sopenharmony_ci { 931d5ac70f0Sopenharmony_ci int num = c - '0'; 932d5ac70f0Sopenharmony_ci int i = 1; 933d5ac70f0Sopenharmony_ci do { 934d5ac70f0Sopenharmony_ci c = get_char(input); 935d5ac70f0Sopenharmony_ci if (c < '0' || c > '7') { 936d5ac70f0Sopenharmony_ci unget_char(c, input); 937d5ac70f0Sopenharmony_ci break; 938d5ac70f0Sopenharmony_ci } 939d5ac70f0Sopenharmony_ci num = num * 8 + c - '0'; 940d5ac70f0Sopenharmony_ci i++; 941d5ac70f0Sopenharmony_ci } while (i < 3); 942d5ac70f0Sopenharmony_ci return num; 943d5ac70f0Sopenharmony_ci } 944d5ac70f0Sopenharmony_ci default: 945d5ac70f0Sopenharmony_ci return c; 946d5ac70f0Sopenharmony_ci } 947d5ac70f0Sopenharmony_ci} 948d5ac70f0Sopenharmony_ci 949d5ac70f0Sopenharmony_ci#define LOCAL_STR_BUFSIZE 64 950d5ac70f0Sopenharmony_cistruct local_string { 951d5ac70f0Sopenharmony_ci char *buf; 952d5ac70f0Sopenharmony_ci size_t alloc; 953d5ac70f0Sopenharmony_ci size_t idx; 954d5ac70f0Sopenharmony_ci char tmpbuf[LOCAL_STR_BUFSIZE]; 955d5ac70f0Sopenharmony_ci}; 956d5ac70f0Sopenharmony_ci 957d5ac70f0Sopenharmony_cistatic void init_local_string(struct local_string *s) 958d5ac70f0Sopenharmony_ci{ 959d5ac70f0Sopenharmony_ci memset(s, 0, sizeof(*s)); 960d5ac70f0Sopenharmony_ci s->buf = s->tmpbuf; 961d5ac70f0Sopenharmony_ci s->alloc = LOCAL_STR_BUFSIZE; 962d5ac70f0Sopenharmony_ci} 963d5ac70f0Sopenharmony_ci 964d5ac70f0Sopenharmony_cistatic void free_local_string(struct local_string *s) 965d5ac70f0Sopenharmony_ci{ 966d5ac70f0Sopenharmony_ci if (s->buf != s->tmpbuf) 967d5ac70f0Sopenharmony_ci free(s->buf); 968d5ac70f0Sopenharmony_ci} 969d5ac70f0Sopenharmony_ci 970d5ac70f0Sopenharmony_cistatic int add_char_local_string(struct local_string *s, int c) 971d5ac70f0Sopenharmony_ci{ 972d5ac70f0Sopenharmony_ci if (s->idx >= s->alloc) { 973d5ac70f0Sopenharmony_ci size_t nalloc = s->alloc * 2; 974d5ac70f0Sopenharmony_ci if (s->buf == s->tmpbuf) { 975d5ac70f0Sopenharmony_ci s->buf = malloc(nalloc); 976d5ac70f0Sopenharmony_ci if (s->buf == NULL) 977d5ac70f0Sopenharmony_ci return -ENOMEM; 978d5ac70f0Sopenharmony_ci memcpy(s->buf, s->tmpbuf, s->alloc); 979d5ac70f0Sopenharmony_ci } else { 980d5ac70f0Sopenharmony_ci char *ptr = realloc(s->buf, nalloc); 981d5ac70f0Sopenharmony_ci if (ptr == NULL) 982d5ac70f0Sopenharmony_ci return -ENOMEM; 983d5ac70f0Sopenharmony_ci s->buf = ptr; 984d5ac70f0Sopenharmony_ci } 985d5ac70f0Sopenharmony_ci s->alloc = nalloc; 986d5ac70f0Sopenharmony_ci } 987d5ac70f0Sopenharmony_ci s->buf[s->idx++] = c; 988d5ac70f0Sopenharmony_ci return 0; 989d5ac70f0Sopenharmony_ci} 990d5ac70f0Sopenharmony_ci 991d5ac70f0Sopenharmony_cistatic char *copy_local_string(struct local_string *s) 992d5ac70f0Sopenharmony_ci{ 993d5ac70f0Sopenharmony_ci char *dst = malloc(s->idx + 1); 994d5ac70f0Sopenharmony_ci if (dst) { 995d5ac70f0Sopenharmony_ci memcpy(dst, s->buf, s->idx); 996d5ac70f0Sopenharmony_ci dst[s->idx] = '\0'; 997d5ac70f0Sopenharmony_ci } 998d5ac70f0Sopenharmony_ci return dst; 999d5ac70f0Sopenharmony_ci} 1000d5ac70f0Sopenharmony_ci 1001d5ac70f0Sopenharmony_cistatic int get_freestring(char **string, int id, input_t *input) 1002d5ac70f0Sopenharmony_ci{ 1003d5ac70f0Sopenharmony_ci struct local_string str; 1004d5ac70f0Sopenharmony_ci int c; 1005d5ac70f0Sopenharmony_ci 1006d5ac70f0Sopenharmony_ci init_local_string(&str); 1007d5ac70f0Sopenharmony_ci while (1) { 1008d5ac70f0Sopenharmony_ci c = get_char(input); 1009d5ac70f0Sopenharmony_ci if (c < 0) { 1010d5ac70f0Sopenharmony_ci if (c == LOCAL_UNEXPECTED_EOF) { 1011d5ac70f0Sopenharmony_ci *string = copy_local_string(&str); 1012d5ac70f0Sopenharmony_ci if (! *string) 1013d5ac70f0Sopenharmony_ci c = -ENOMEM; 1014d5ac70f0Sopenharmony_ci else 1015d5ac70f0Sopenharmony_ci c = 0; 1016d5ac70f0Sopenharmony_ci } 1017d5ac70f0Sopenharmony_ci break; 1018d5ac70f0Sopenharmony_ci } 1019d5ac70f0Sopenharmony_ci switch (c) { 1020d5ac70f0Sopenharmony_ci case '.': 1021d5ac70f0Sopenharmony_ci if (!id) 1022d5ac70f0Sopenharmony_ci break; 1023d5ac70f0Sopenharmony_ci /* fall through */ 1024d5ac70f0Sopenharmony_ci case ' ': 1025d5ac70f0Sopenharmony_ci case '\f': 1026d5ac70f0Sopenharmony_ci case '\t': 1027d5ac70f0Sopenharmony_ci case '\n': 1028d5ac70f0Sopenharmony_ci case '\r': 1029d5ac70f0Sopenharmony_ci case '=': 1030d5ac70f0Sopenharmony_ci case ',': 1031d5ac70f0Sopenharmony_ci case ';': 1032d5ac70f0Sopenharmony_ci case '{': 1033d5ac70f0Sopenharmony_ci case '}': 1034d5ac70f0Sopenharmony_ci case '[': 1035d5ac70f0Sopenharmony_ci case ']': 1036d5ac70f0Sopenharmony_ci case '\'': 1037d5ac70f0Sopenharmony_ci case '"': 1038d5ac70f0Sopenharmony_ci case '\\': 1039d5ac70f0Sopenharmony_ci case '#': 1040d5ac70f0Sopenharmony_ci *string = copy_local_string(&str); 1041d5ac70f0Sopenharmony_ci if (! *string) 1042d5ac70f0Sopenharmony_ci c = -ENOMEM; 1043d5ac70f0Sopenharmony_ci else { 1044d5ac70f0Sopenharmony_ci unget_char(c, input); 1045d5ac70f0Sopenharmony_ci c = 0; 1046d5ac70f0Sopenharmony_ci } 1047d5ac70f0Sopenharmony_ci goto _out; 1048d5ac70f0Sopenharmony_ci default: 1049d5ac70f0Sopenharmony_ci break; 1050d5ac70f0Sopenharmony_ci } 1051d5ac70f0Sopenharmony_ci if (add_char_local_string(&str, c) < 0) { 1052d5ac70f0Sopenharmony_ci c = -ENOMEM; 1053d5ac70f0Sopenharmony_ci break; 1054d5ac70f0Sopenharmony_ci } 1055d5ac70f0Sopenharmony_ci } 1056d5ac70f0Sopenharmony_ci _out: 1057d5ac70f0Sopenharmony_ci free_local_string(&str); 1058d5ac70f0Sopenharmony_ci return c; 1059d5ac70f0Sopenharmony_ci} 1060d5ac70f0Sopenharmony_ci 1061d5ac70f0Sopenharmony_cistatic int get_delimstring(char **string, int delim, input_t *input) 1062d5ac70f0Sopenharmony_ci{ 1063d5ac70f0Sopenharmony_ci struct local_string str; 1064d5ac70f0Sopenharmony_ci int c; 1065d5ac70f0Sopenharmony_ci 1066d5ac70f0Sopenharmony_ci init_local_string(&str); 1067d5ac70f0Sopenharmony_ci while (1) { 1068d5ac70f0Sopenharmony_ci c = get_char(input); 1069d5ac70f0Sopenharmony_ci if (c < 0) 1070d5ac70f0Sopenharmony_ci break; 1071d5ac70f0Sopenharmony_ci if (c == '\\') { 1072d5ac70f0Sopenharmony_ci c = get_quotedchar(input); 1073d5ac70f0Sopenharmony_ci if (c < 0) 1074d5ac70f0Sopenharmony_ci break; 1075d5ac70f0Sopenharmony_ci if (c == '\n') 1076d5ac70f0Sopenharmony_ci continue; 1077d5ac70f0Sopenharmony_ci } else if (c == delim) { 1078d5ac70f0Sopenharmony_ci *string = copy_local_string(&str); 1079d5ac70f0Sopenharmony_ci if (! *string) 1080d5ac70f0Sopenharmony_ci c = -ENOMEM; 1081d5ac70f0Sopenharmony_ci else 1082d5ac70f0Sopenharmony_ci c = 0; 1083d5ac70f0Sopenharmony_ci break; 1084d5ac70f0Sopenharmony_ci } 1085d5ac70f0Sopenharmony_ci if (add_char_local_string(&str, c) < 0) { 1086d5ac70f0Sopenharmony_ci c = -ENOMEM; 1087d5ac70f0Sopenharmony_ci break; 1088d5ac70f0Sopenharmony_ci } 1089d5ac70f0Sopenharmony_ci } 1090d5ac70f0Sopenharmony_ci free_local_string(&str); 1091d5ac70f0Sopenharmony_ci return c; 1092d5ac70f0Sopenharmony_ci} 1093d5ac70f0Sopenharmony_ci 1094d5ac70f0Sopenharmony_ci/* Return 0 for free string, 1 for delimited string */ 1095d5ac70f0Sopenharmony_cistatic int get_string(char **string, int id, input_t *input) 1096d5ac70f0Sopenharmony_ci{ 1097d5ac70f0Sopenharmony_ci int c = get_nonwhite(input), err; 1098d5ac70f0Sopenharmony_ci if (c < 0) 1099d5ac70f0Sopenharmony_ci return c; 1100d5ac70f0Sopenharmony_ci switch (c) { 1101d5ac70f0Sopenharmony_ci case '=': 1102d5ac70f0Sopenharmony_ci case ',': 1103d5ac70f0Sopenharmony_ci case ';': 1104d5ac70f0Sopenharmony_ci case '.': 1105d5ac70f0Sopenharmony_ci case '{': 1106d5ac70f0Sopenharmony_ci case '}': 1107d5ac70f0Sopenharmony_ci case '[': 1108d5ac70f0Sopenharmony_ci case ']': 1109d5ac70f0Sopenharmony_ci case '\\': 1110d5ac70f0Sopenharmony_ci return LOCAL_UNEXPECTED_CHAR; 1111d5ac70f0Sopenharmony_ci case '\'': 1112d5ac70f0Sopenharmony_ci case '"': 1113d5ac70f0Sopenharmony_ci err = get_delimstring(string, c, input); 1114d5ac70f0Sopenharmony_ci if (err < 0) 1115d5ac70f0Sopenharmony_ci return err; 1116d5ac70f0Sopenharmony_ci return 1; 1117d5ac70f0Sopenharmony_ci default: 1118d5ac70f0Sopenharmony_ci unget_char(c, input); 1119d5ac70f0Sopenharmony_ci err = get_freestring(string, id, input); 1120d5ac70f0Sopenharmony_ci if (err < 0) 1121d5ac70f0Sopenharmony_ci return err; 1122d5ac70f0Sopenharmony_ci return 0; 1123d5ac70f0Sopenharmony_ci } 1124d5ac70f0Sopenharmony_ci} 1125d5ac70f0Sopenharmony_ci 1126d5ac70f0Sopenharmony_cistatic int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type) 1127d5ac70f0Sopenharmony_ci{ 1128d5ac70f0Sopenharmony_ci snd_config_t *n; 1129d5ac70f0Sopenharmony_ci assert(config); 1130d5ac70f0Sopenharmony_ci n = calloc(1, sizeof(*n)); 1131d5ac70f0Sopenharmony_ci if (n == NULL) { 1132d5ac70f0Sopenharmony_ci if (*id) { 1133d5ac70f0Sopenharmony_ci free(*id); 1134d5ac70f0Sopenharmony_ci *id = NULL; 1135d5ac70f0Sopenharmony_ci } 1136d5ac70f0Sopenharmony_ci return -ENOMEM; 1137d5ac70f0Sopenharmony_ci } 1138d5ac70f0Sopenharmony_ci if (id) { 1139d5ac70f0Sopenharmony_ci n->id = *id; 1140d5ac70f0Sopenharmony_ci *id = NULL; 1141d5ac70f0Sopenharmony_ci } 1142d5ac70f0Sopenharmony_ci n->type = type; 1143d5ac70f0Sopenharmony_ci if (type == SND_CONFIG_TYPE_COMPOUND) 1144d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&n->u.compound.fields); 1145d5ac70f0Sopenharmony_ci *config = n; 1146d5ac70f0Sopenharmony_ci return 0; 1147d5ac70f0Sopenharmony_ci} 1148d5ac70f0Sopenharmony_ci 1149d5ac70f0Sopenharmony_ci 1150d5ac70f0Sopenharmony_cistatic int _snd_config_make_add(snd_config_t **config, char **id, 1151d5ac70f0Sopenharmony_ci snd_config_type_t type, snd_config_t *parent) 1152d5ac70f0Sopenharmony_ci{ 1153d5ac70f0Sopenharmony_ci snd_config_t *n; 1154d5ac70f0Sopenharmony_ci int err; 1155d5ac70f0Sopenharmony_ci assert(parent->type == SND_CONFIG_TYPE_COMPOUND); 1156d5ac70f0Sopenharmony_ci err = _snd_config_make(&n, id, type); 1157d5ac70f0Sopenharmony_ci if (err < 0) 1158d5ac70f0Sopenharmony_ci return err; 1159d5ac70f0Sopenharmony_ci n->parent = parent; 1160d5ac70f0Sopenharmony_ci list_add_tail(&n->list, &parent->u.compound.fields); 1161d5ac70f0Sopenharmony_ci *config = n; 1162d5ac70f0Sopenharmony_ci return 0; 1163d5ac70f0Sopenharmony_ci} 1164d5ac70f0Sopenharmony_ci 1165d5ac70f0Sopenharmony_cistatic int _snd_config_search(snd_config_t *config, 1166d5ac70f0Sopenharmony_ci const char *id, int len, snd_config_t **result) 1167d5ac70f0Sopenharmony_ci{ 1168d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1169d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, config) { 1170d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1171d5ac70f0Sopenharmony_ci if (len < 0) { 1172d5ac70f0Sopenharmony_ci if (strcmp(n->id, id) != 0) 1173d5ac70f0Sopenharmony_ci continue; 1174d5ac70f0Sopenharmony_ci } else if (strlen(n->id) != (size_t) len || 1175d5ac70f0Sopenharmony_ci memcmp(n->id, id, (size_t) len) != 0) 1176d5ac70f0Sopenharmony_ci continue; 1177d5ac70f0Sopenharmony_ci if (result) 1178d5ac70f0Sopenharmony_ci *result = n; 1179d5ac70f0Sopenharmony_ci return 0; 1180d5ac70f0Sopenharmony_ci } 1181d5ac70f0Sopenharmony_ci return -ENOENT; 1182d5ac70f0Sopenharmony_ci} 1183d5ac70f0Sopenharmony_ci 1184d5ac70f0Sopenharmony_cistatic int parse_value(snd_config_t **_n, snd_config_t *parent, input_t *input, char **id, int skip) 1185d5ac70f0Sopenharmony_ci{ 1186d5ac70f0Sopenharmony_ci snd_config_t *n = *_n; 1187d5ac70f0Sopenharmony_ci char *s; 1188d5ac70f0Sopenharmony_ci int err; 1189d5ac70f0Sopenharmony_ci 1190d5ac70f0Sopenharmony_ci err = get_string(&s, 0, input); 1191d5ac70f0Sopenharmony_ci if (err < 0) 1192d5ac70f0Sopenharmony_ci return err; 1193d5ac70f0Sopenharmony_ci if (skip) { 1194d5ac70f0Sopenharmony_ci free(s); 1195d5ac70f0Sopenharmony_ci return 0; 1196d5ac70f0Sopenharmony_ci } 1197d5ac70f0Sopenharmony_ci if (err == 0 && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) { 1198d5ac70f0Sopenharmony_ci long long i; 1199d5ac70f0Sopenharmony_ci errno = 0; 1200d5ac70f0Sopenharmony_ci err = safe_strtoll(s, &i); 1201d5ac70f0Sopenharmony_ci if (err < 0) { 1202d5ac70f0Sopenharmony_ci double r; 1203d5ac70f0Sopenharmony_ci err = safe_strtod(s, &r); 1204d5ac70f0Sopenharmony_ci if (err >= 0) { 1205d5ac70f0Sopenharmony_ci free(s); 1206d5ac70f0Sopenharmony_ci if (n) { 1207d5ac70f0Sopenharmony_ci if (n->type != SND_CONFIG_TYPE_REAL) { 1208d5ac70f0Sopenharmony_ci SNDERR("%s is not a real", *id); 1209d5ac70f0Sopenharmony_ci return -EINVAL; 1210d5ac70f0Sopenharmony_ci } 1211d5ac70f0Sopenharmony_ci } else { 1212d5ac70f0Sopenharmony_ci err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, parent); 1213d5ac70f0Sopenharmony_ci if (err < 0) 1214d5ac70f0Sopenharmony_ci return err; 1215d5ac70f0Sopenharmony_ci } 1216d5ac70f0Sopenharmony_ci n->u.real = r; 1217d5ac70f0Sopenharmony_ci *_n = n; 1218d5ac70f0Sopenharmony_ci return 0; 1219d5ac70f0Sopenharmony_ci } 1220d5ac70f0Sopenharmony_ci } else { 1221d5ac70f0Sopenharmony_ci free(s); 1222d5ac70f0Sopenharmony_ci if (n) { 1223d5ac70f0Sopenharmony_ci if (n->type != SND_CONFIG_TYPE_INTEGER && n->type != SND_CONFIG_TYPE_INTEGER64) { 1224d5ac70f0Sopenharmony_ci SNDERR("%s is not an integer", *id); 1225d5ac70f0Sopenharmony_ci return -EINVAL; 1226d5ac70f0Sopenharmony_ci } 1227d5ac70f0Sopenharmony_ci } else { 1228d5ac70f0Sopenharmony_ci if (i <= INT_MAX) 1229d5ac70f0Sopenharmony_ci err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, parent); 1230d5ac70f0Sopenharmony_ci else 1231d5ac70f0Sopenharmony_ci err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, parent); 1232d5ac70f0Sopenharmony_ci if (err < 0) 1233d5ac70f0Sopenharmony_ci return err; 1234d5ac70f0Sopenharmony_ci } 1235d5ac70f0Sopenharmony_ci if (n->type == SND_CONFIG_TYPE_INTEGER) 1236d5ac70f0Sopenharmony_ci n->u.integer = (long) i; 1237d5ac70f0Sopenharmony_ci else 1238d5ac70f0Sopenharmony_ci n->u.integer64 = i; 1239d5ac70f0Sopenharmony_ci *_n = n; 1240d5ac70f0Sopenharmony_ci return 0; 1241d5ac70f0Sopenharmony_ci } 1242d5ac70f0Sopenharmony_ci } 1243d5ac70f0Sopenharmony_ci if (n) { 1244d5ac70f0Sopenharmony_ci if (n->type != SND_CONFIG_TYPE_STRING) { 1245d5ac70f0Sopenharmony_ci SNDERR("%s is not a string", *id); 1246d5ac70f0Sopenharmony_ci free(s); 1247d5ac70f0Sopenharmony_ci return -EINVAL; 1248d5ac70f0Sopenharmony_ci } 1249d5ac70f0Sopenharmony_ci } else { 1250d5ac70f0Sopenharmony_ci err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, parent); 1251d5ac70f0Sopenharmony_ci if (err < 0) 1252d5ac70f0Sopenharmony_ci return err; 1253d5ac70f0Sopenharmony_ci } 1254d5ac70f0Sopenharmony_ci free(n->u.string); 1255d5ac70f0Sopenharmony_ci n->u.string = s; 1256d5ac70f0Sopenharmony_ci *_n = n; 1257d5ac70f0Sopenharmony_ci return 0; 1258d5ac70f0Sopenharmony_ci} 1259d5ac70f0Sopenharmony_ci 1260d5ac70f0Sopenharmony_cistatic int parse_defs(snd_config_t *parent, input_t *input, int skip, int override); 1261d5ac70f0Sopenharmony_cistatic int parse_array_defs(snd_config_t *farther, input_t *input, int skip, int override); 1262d5ac70f0Sopenharmony_ci 1263d5ac70f0Sopenharmony_cistatic int parse_array_def(snd_config_t *parent, input_t *input, int *idx, int skip, int override) 1264d5ac70f0Sopenharmony_ci{ 1265d5ac70f0Sopenharmony_ci char *id = NULL; 1266d5ac70f0Sopenharmony_ci int c; 1267d5ac70f0Sopenharmony_ci int err; 1268d5ac70f0Sopenharmony_ci snd_config_t *n = NULL; 1269d5ac70f0Sopenharmony_ci 1270d5ac70f0Sopenharmony_ci if (!skip) { 1271d5ac70f0Sopenharmony_ci snd_config_t *g; 1272d5ac70f0Sopenharmony_ci char static_id[12]; 1273d5ac70f0Sopenharmony_ci while (1) { 1274d5ac70f0Sopenharmony_ci snprintf(static_id, sizeof(static_id), "%i", *idx); 1275d5ac70f0Sopenharmony_ci if (_snd_config_search(parent, static_id, -1, &g) == 0) { 1276d5ac70f0Sopenharmony_ci if (override) { 1277d5ac70f0Sopenharmony_ci snd_config_delete(n); 1278d5ac70f0Sopenharmony_ci } else { 1279d5ac70f0Sopenharmony_ci /* merge */ 1280d5ac70f0Sopenharmony_ci (*idx)++; 1281d5ac70f0Sopenharmony_ci continue; 1282d5ac70f0Sopenharmony_ci } 1283d5ac70f0Sopenharmony_ci } 1284d5ac70f0Sopenharmony_ci break; 1285d5ac70f0Sopenharmony_ci } 1286d5ac70f0Sopenharmony_ci id = strdup(static_id); 1287d5ac70f0Sopenharmony_ci if (id == NULL) 1288d5ac70f0Sopenharmony_ci return -ENOMEM; 1289d5ac70f0Sopenharmony_ci } 1290d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1291d5ac70f0Sopenharmony_ci if (c < 0) { 1292d5ac70f0Sopenharmony_ci err = c; 1293d5ac70f0Sopenharmony_ci goto __end; 1294d5ac70f0Sopenharmony_ci } 1295d5ac70f0Sopenharmony_ci switch (c) { 1296d5ac70f0Sopenharmony_ci case '{': 1297d5ac70f0Sopenharmony_ci case '[': 1298d5ac70f0Sopenharmony_ci { 1299d5ac70f0Sopenharmony_ci char endchr; 1300d5ac70f0Sopenharmony_ci if (!skip) { 1301d5ac70f0Sopenharmony_ci if (n) { 1302d5ac70f0Sopenharmony_ci if (n->type != SND_CONFIG_TYPE_COMPOUND) { 1303d5ac70f0Sopenharmony_ci SNDERR("%s is not a compound", id); 1304d5ac70f0Sopenharmony_ci err = -EINVAL; 1305d5ac70f0Sopenharmony_ci goto __end; 1306d5ac70f0Sopenharmony_ci } 1307d5ac70f0Sopenharmony_ci } else { 1308d5ac70f0Sopenharmony_ci err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); 1309d5ac70f0Sopenharmony_ci if (err < 0) 1310d5ac70f0Sopenharmony_ci goto __end; 1311d5ac70f0Sopenharmony_ci } 1312d5ac70f0Sopenharmony_ci } 1313d5ac70f0Sopenharmony_ci if (c == '{') { 1314d5ac70f0Sopenharmony_ci err = parse_defs(n, input, skip, override); 1315d5ac70f0Sopenharmony_ci endchr = '}'; 1316d5ac70f0Sopenharmony_ci } else { 1317d5ac70f0Sopenharmony_ci err = parse_array_defs(n, input, skip, override); 1318d5ac70f0Sopenharmony_ci endchr = ']'; 1319d5ac70f0Sopenharmony_ci } 1320d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1321d5ac70f0Sopenharmony_ci if (c < 0) { 1322d5ac70f0Sopenharmony_ci err = c; 1323d5ac70f0Sopenharmony_ci goto __end; 1324d5ac70f0Sopenharmony_ci } 1325d5ac70f0Sopenharmony_ci if (c != endchr) { 1326d5ac70f0Sopenharmony_ci if (n) 1327d5ac70f0Sopenharmony_ci snd_config_delete(n); 1328d5ac70f0Sopenharmony_ci err = LOCAL_UNEXPECTED_CHAR; 1329d5ac70f0Sopenharmony_ci goto __end; 1330d5ac70f0Sopenharmony_ci } 1331d5ac70f0Sopenharmony_ci break; 1332d5ac70f0Sopenharmony_ci } 1333d5ac70f0Sopenharmony_ci default: 1334d5ac70f0Sopenharmony_ci unget_char(c, input); 1335d5ac70f0Sopenharmony_ci err = parse_value(&n, parent, input, &id, skip); 1336d5ac70f0Sopenharmony_ci if (err < 0) 1337d5ac70f0Sopenharmony_ci goto __end; 1338d5ac70f0Sopenharmony_ci break; 1339d5ac70f0Sopenharmony_ci } 1340d5ac70f0Sopenharmony_ci err = 0; 1341d5ac70f0Sopenharmony_ci __end: 1342d5ac70f0Sopenharmony_ci free(id); 1343d5ac70f0Sopenharmony_ci return err; 1344d5ac70f0Sopenharmony_ci} 1345d5ac70f0Sopenharmony_ci 1346d5ac70f0Sopenharmony_cistatic int parse_array_defs(snd_config_t *parent, input_t *input, int skip, int override) 1347d5ac70f0Sopenharmony_ci{ 1348d5ac70f0Sopenharmony_ci int idx = 0; 1349d5ac70f0Sopenharmony_ci while (1) { 1350d5ac70f0Sopenharmony_ci int c = get_nonwhite(input), err; 1351d5ac70f0Sopenharmony_ci if (c < 0) 1352d5ac70f0Sopenharmony_ci return c; 1353d5ac70f0Sopenharmony_ci unget_char(c, input); 1354d5ac70f0Sopenharmony_ci if (c == ']') 1355d5ac70f0Sopenharmony_ci return 0; 1356d5ac70f0Sopenharmony_ci err = parse_array_def(parent, input, &idx, skip, override); 1357d5ac70f0Sopenharmony_ci if (err < 0) 1358d5ac70f0Sopenharmony_ci return err; 1359d5ac70f0Sopenharmony_ci idx++; 1360d5ac70f0Sopenharmony_ci } 1361d5ac70f0Sopenharmony_ci return 0; 1362d5ac70f0Sopenharmony_ci} 1363d5ac70f0Sopenharmony_ci 1364d5ac70f0Sopenharmony_cistatic int parse_def(snd_config_t *parent, input_t *input, int skip, int override) 1365d5ac70f0Sopenharmony_ci{ 1366d5ac70f0Sopenharmony_ci char *id = NULL; 1367d5ac70f0Sopenharmony_ci int c; 1368d5ac70f0Sopenharmony_ci int err; 1369d5ac70f0Sopenharmony_ci snd_config_t *n; 1370d5ac70f0Sopenharmony_ci enum {MERGE_CREATE, MERGE, OVERRIDE, DONT_OVERRIDE} mode; 1371d5ac70f0Sopenharmony_ci while (1) { 1372d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1373d5ac70f0Sopenharmony_ci if (c < 0) 1374d5ac70f0Sopenharmony_ci return c; 1375d5ac70f0Sopenharmony_ci switch (c) { 1376d5ac70f0Sopenharmony_ci case '+': 1377d5ac70f0Sopenharmony_ci mode = MERGE_CREATE; 1378d5ac70f0Sopenharmony_ci break; 1379d5ac70f0Sopenharmony_ci case '-': 1380d5ac70f0Sopenharmony_ci mode = MERGE; 1381d5ac70f0Sopenharmony_ci break; 1382d5ac70f0Sopenharmony_ci case '?': 1383d5ac70f0Sopenharmony_ci mode = DONT_OVERRIDE; 1384d5ac70f0Sopenharmony_ci break; 1385d5ac70f0Sopenharmony_ci case '!': 1386d5ac70f0Sopenharmony_ci mode = OVERRIDE; 1387d5ac70f0Sopenharmony_ci break; 1388d5ac70f0Sopenharmony_ci default: 1389d5ac70f0Sopenharmony_ci mode = !override ? MERGE_CREATE : OVERRIDE; 1390d5ac70f0Sopenharmony_ci unget_char(c, input); 1391d5ac70f0Sopenharmony_ci } 1392d5ac70f0Sopenharmony_ci err = get_string(&id, 1, input); 1393d5ac70f0Sopenharmony_ci if (err < 0) 1394d5ac70f0Sopenharmony_ci return err; 1395d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1396d5ac70f0Sopenharmony_ci if (c != '.') 1397d5ac70f0Sopenharmony_ci break; 1398d5ac70f0Sopenharmony_ci if (skip) { 1399d5ac70f0Sopenharmony_ci free(id); 1400d5ac70f0Sopenharmony_ci continue; 1401d5ac70f0Sopenharmony_ci } 1402d5ac70f0Sopenharmony_ci if (_snd_config_search(parent, id, -1, &n) == 0) { 1403d5ac70f0Sopenharmony_ci if (mode == DONT_OVERRIDE) { 1404d5ac70f0Sopenharmony_ci skip = 1; 1405d5ac70f0Sopenharmony_ci free(id); 1406d5ac70f0Sopenharmony_ci continue; 1407d5ac70f0Sopenharmony_ci } 1408d5ac70f0Sopenharmony_ci if (mode != OVERRIDE) { 1409d5ac70f0Sopenharmony_ci if (n->type != SND_CONFIG_TYPE_COMPOUND) { 1410d5ac70f0Sopenharmony_ci SNDERR("%s is not a compound", id); 1411d5ac70f0Sopenharmony_ci return -EINVAL; 1412d5ac70f0Sopenharmony_ci } 1413d5ac70f0Sopenharmony_ci n->u.compound.join = true; 1414d5ac70f0Sopenharmony_ci parent = n; 1415d5ac70f0Sopenharmony_ci free(id); 1416d5ac70f0Sopenharmony_ci continue; 1417d5ac70f0Sopenharmony_ci } 1418d5ac70f0Sopenharmony_ci snd_config_delete(n); 1419d5ac70f0Sopenharmony_ci } 1420d5ac70f0Sopenharmony_ci if (mode == MERGE) { 1421d5ac70f0Sopenharmony_ci SNDERR("%s does not exists", id); 1422d5ac70f0Sopenharmony_ci err = -ENOENT; 1423d5ac70f0Sopenharmony_ci goto __end; 1424d5ac70f0Sopenharmony_ci } 1425d5ac70f0Sopenharmony_ci err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); 1426d5ac70f0Sopenharmony_ci if (err < 0) 1427d5ac70f0Sopenharmony_ci goto __end; 1428d5ac70f0Sopenharmony_ci n->u.compound.join = true; 1429d5ac70f0Sopenharmony_ci parent = n; 1430d5ac70f0Sopenharmony_ci } 1431d5ac70f0Sopenharmony_ci if (c == '=') { 1432d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1433d5ac70f0Sopenharmony_ci if (c < 0) 1434d5ac70f0Sopenharmony_ci return c; 1435d5ac70f0Sopenharmony_ci } 1436d5ac70f0Sopenharmony_ci if (!skip) { 1437d5ac70f0Sopenharmony_ci if (_snd_config_search(parent, id, -1, &n) == 0) { 1438d5ac70f0Sopenharmony_ci if (mode == DONT_OVERRIDE) { 1439d5ac70f0Sopenharmony_ci skip = 1; 1440d5ac70f0Sopenharmony_ci n = NULL; 1441d5ac70f0Sopenharmony_ci } else if (mode == OVERRIDE) { 1442d5ac70f0Sopenharmony_ci snd_config_delete(n); 1443d5ac70f0Sopenharmony_ci n = NULL; 1444d5ac70f0Sopenharmony_ci } 1445d5ac70f0Sopenharmony_ci } else { 1446d5ac70f0Sopenharmony_ci n = NULL; 1447d5ac70f0Sopenharmony_ci if (mode == MERGE) { 1448d5ac70f0Sopenharmony_ci SNDERR("%s does not exists", id); 1449d5ac70f0Sopenharmony_ci err = -ENOENT; 1450d5ac70f0Sopenharmony_ci goto __end; 1451d5ac70f0Sopenharmony_ci } 1452d5ac70f0Sopenharmony_ci } 1453d5ac70f0Sopenharmony_ci } 1454d5ac70f0Sopenharmony_ci switch (c) { 1455d5ac70f0Sopenharmony_ci case '{': 1456d5ac70f0Sopenharmony_ci case '[': 1457d5ac70f0Sopenharmony_ci { 1458d5ac70f0Sopenharmony_ci char endchr; 1459d5ac70f0Sopenharmony_ci if (!skip) { 1460d5ac70f0Sopenharmony_ci if (n) { 1461d5ac70f0Sopenharmony_ci if (n->type != SND_CONFIG_TYPE_COMPOUND) { 1462d5ac70f0Sopenharmony_ci SNDERR("%s is not a compound", id); 1463d5ac70f0Sopenharmony_ci err = -EINVAL; 1464d5ac70f0Sopenharmony_ci goto __end; 1465d5ac70f0Sopenharmony_ci } 1466d5ac70f0Sopenharmony_ci } else { 1467d5ac70f0Sopenharmony_ci err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); 1468d5ac70f0Sopenharmony_ci if (err < 0) 1469d5ac70f0Sopenharmony_ci goto __end; 1470d5ac70f0Sopenharmony_ci } 1471d5ac70f0Sopenharmony_ci } 1472d5ac70f0Sopenharmony_ci if (c == '{') { 1473d5ac70f0Sopenharmony_ci err = parse_defs(n, input, skip, override); 1474d5ac70f0Sopenharmony_ci endchr = '}'; 1475d5ac70f0Sopenharmony_ci } else { 1476d5ac70f0Sopenharmony_ci err = parse_array_defs(n, input, skip, override); 1477d5ac70f0Sopenharmony_ci endchr = ']'; 1478d5ac70f0Sopenharmony_ci } 1479d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1480d5ac70f0Sopenharmony_ci if (c != endchr) { 1481d5ac70f0Sopenharmony_ci if (n) 1482d5ac70f0Sopenharmony_ci snd_config_delete(n); 1483d5ac70f0Sopenharmony_ci err = LOCAL_UNEXPECTED_CHAR; 1484d5ac70f0Sopenharmony_ci goto __end; 1485d5ac70f0Sopenharmony_ci } 1486d5ac70f0Sopenharmony_ci break; 1487d5ac70f0Sopenharmony_ci } 1488d5ac70f0Sopenharmony_ci default: 1489d5ac70f0Sopenharmony_ci unget_char(c, input); 1490d5ac70f0Sopenharmony_ci err = parse_value(&n, parent, input, &id, skip); 1491d5ac70f0Sopenharmony_ci if (err < 0) 1492d5ac70f0Sopenharmony_ci goto __end; 1493d5ac70f0Sopenharmony_ci break; 1494d5ac70f0Sopenharmony_ci } 1495d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1496d5ac70f0Sopenharmony_ci switch (c) { 1497d5ac70f0Sopenharmony_ci case ';': 1498d5ac70f0Sopenharmony_ci case ',': 1499d5ac70f0Sopenharmony_ci break; 1500d5ac70f0Sopenharmony_ci default: 1501d5ac70f0Sopenharmony_ci unget_char(c, input); 1502d5ac70f0Sopenharmony_ci } 1503d5ac70f0Sopenharmony_ci __end: 1504d5ac70f0Sopenharmony_ci free(id); 1505d5ac70f0Sopenharmony_ci return err; 1506d5ac70f0Sopenharmony_ci} 1507d5ac70f0Sopenharmony_ci 1508d5ac70f0Sopenharmony_cistatic int parse_defs(snd_config_t *parent, input_t *input, int skip, int override) 1509d5ac70f0Sopenharmony_ci{ 1510d5ac70f0Sopenharmony_ci int c, err; 1511d5ac70f0Sopenharmony_ci while (1) { 1512d5ac70f0Sopenharmony_ci c = get_nonwhite(input); 1513d5ac70f0Sopenharmony_ci if (c < 0) 1514d5ac70f0Sopenharmony_ci return c == LOCAL_UNEXPECTED_EOF ? 0 : c; 1515d5ac70f0Sopenharmony_ci unget_char(c, input); 1516d5ac70f0Sopenharmony_ci if (c == '}') 1517d5ac70f0Sopenharmony_ci return 0; 1518d5ac70f0Sopenharmony_ci err = parse_def(parent, input, skip, override); 1519d5ac70f0Sopenharmony_ci if (err < 0) 1520d5ac70f0Sopenharmony_ci return err; 1521d5ac70f0Sopenharmony_ci } 1522d5ac70f0Sopenharmony_ci return 0; 1523d5ac70f0Sopenharmony_ci} 1524d5ac70f0Sopenharmony_ci 1525d5ac70f0Sopenharmony_cistatic void string_print(char *str, int id, snd_output_t *out) 1526d5ac70f0Sopenharmony_ci{ 1527d5ac70f0Sopenharmony_ci int q; 1528d5ac70f0Sopenharmony_ci unsigned char *p = (unsigned char *)str; 1529d5ac70f0Sopenharmony_ci if (!p || !*p) { 1530d5ac70f0Sopenharmony_ci snd_output_puts(out, "''"); 1531d5ac70f0Sopenharmony_ci return; 1532d5ac70f0Sopenharmony_ci } 1533d5ac70f0Sopenharmony_ci if (!id) { 1534d5ac70f0Sopenharmony_ci switch (*p) { 1535d5ac70f0Sopenharmony_ci case '0': case '1': case '2': case '3': case '4': 1536d5ac70f0Sopenharmony_ci case '5': case '6': case '7': case '8': case '9': 1537d5ac70f0Sopenharmony_ci case '-': 1538d5ac70f0Sopenharmony_ci goto quoted; 1539d5ac70f0Sopenharmony_ci } 1540d5ac70f0Sopenharmony_ci } 1541d5ac70f0Sopenharmony_ci loop: 1542d5ac70f0Sopenharmony_ci switch (*p) { 1543d5ac70f0Sopenharmony_ci case 0: 1544d5ac70f0Sopenharmony_ci goto nonquoted; 1545d5ac70f0Sopenharmony_ci case ' ': 1546d5ac70f0Sopenharmony_ci case '=': 1547d5ac70f0Sopenharmony_ci case ';': 1548d5ac70f0Sopenharmony_ci case ',': 1549d5ac70f0Sopenharmony_ci case '.': 1550d5ac70f0Sopenharmony_ci case '{': 1551d5ac70f0Sopenharmony_ci case '}': 1552d5ac70f0Sopenharmony_ci case '[': 1553d5ac70f0Sopenharmony_ci case ']': 1554d5ac70f0Sopenharmony_ci case '\'': 1555d5ac70f0Sopenharmony_ci case '"': 1556d5ac70f0Sopenharmony_ci case '*': 1557d5ac70f0Sopenharmony_ci case '#': 1558d5ac70f0Sopenharmony_ci goto quoted; 1559d5ac70f0Sopenharmony_ci default: 1560d5ac70f0Sopenharmony_ci if (*p <= 31 || *p >= 127) 1561d5ac70f0Sopenharmony_ci goto quoted; 1562d5ac70f0Sopenharmony_ci p++; 1563d5ac70f0Sopenharmony_ci goto loop; 1564d5ac70f0Sopenharmony_ci } 1565d5ac70f0Sopenharmony_ci nonquoted: 1566d5ac70f0Sopenharmony_ci snd_output_puts(out, str); 1567d5ac70f0Sopenharmony_ci return; 1568d5ac70f0Sopenharmony_ci quoted: 1569d5ac70f0Sopenharmony_ci q = strchr(str, '\'') ? '"' : '\''; 1570d5ac70f0Sopenharmony_ci snd_output_putc(out, q); 1571d5ac70f0Sopenharmony_ci p = (unsigned char *)str; 1572d5ac70f0Sopenharmony_ci while (*p) { 1573d5ac70f0Sopenharmony_ci int c; 1574d5ac70f0Sopenharmony_ci c = *p; 1575d5ac70f0Sopenharmony_ci switch (c) { 1576d5ac70f0Sopenharmony_ci case '\n': 1577d5ac70f0Sopenharmony_ci snd_output_putc(out, '\\'); 1578d5ac70f0Sopenharmony_ci snd_output_putc(out, 'n'); 1579d5ac70f0Sopenharmony_ci break; 1580d5ac70f0Sopenharmony_ci case '\t': 1581d5ac70f0Sopenharmony_ci snd_output_putc(out, '\\'); 1582d5ac70f0Sopenharmony_ci snd_output_putc(out, 't'); 1583d5ac70f0Sopenharmony_ci break; 1584d5ac70f0Sopenharmony_ci case '\v': 1585d5ac70f0Sopenharmony_ci snd_output_putc(out, '\\'); 1586d5ac70f0Sopenharmony_ci snd_output_putc(out, 'v'); 1587d5ac70f0Sopenharmony_ci break; 1588d5ac70f0Sopenharmony_ci case '\b': 1589d5ac70f0Sopenharmony_ci snd_output_putc(out, '\\'); 1590d5ac70f0Sopenharmony_ci snd_output_putc(out, 'b'); 1591d5ac70f0Sopenharmony_ci break; 1592d5ac70f0Sopenharmony_ci case '\r': 1593d5ac70f0Sopenharmony_ci snd_output_putc(out, '\\'); 1594d5ac70f0Sopenharmony_ci snd_output_putc(out, 'r'); 1595d5ac70f0Sopenharmony_ci break; 1596d5ac70f0Sopenharmony_ci case '\f': 1597d5ac70f0Sopenharmony_ci snd_output_putc(out, '\\'); 1598d5ac70f0Sopenharmony_ci snd_output_putc(out, 'f'); 1599d5ac70f0Sopenharmony_ci break; 1600d5ac70f0Sopenharmony_ci default: 1601d5ac70f0Sopenharmony_ci if (c == q) { 1602d5ac70f0Sopenharmony_ci snd_output_putc(out, '\\'); 1603d5ac70f0Sopenharmony_ci snd_output_putc(out, c); 1604d5ac70f0Sopenharmony_ci } else { 1605d5ac70f0Sopenharmony_ci if (c >= 32 && c <= 126) 1606d5ac70f0Sopenharmony_ci snd_output_putc(out, c); 1607d5ac70f0Sopenharmony_ci else 1608d5ac70f0Sopenharmony_ci snd_output_printf(out, "\\%04o", c); 1609d5ac70f0Sopenharmony_ci } 1610d5ac70f0Sopenharmony_ci break; 1611d5ac70f0Sopenharmony_ci } 1612d5ac70f0Sopenharmony_ci p++; 1613d5ac70f0Sopenharmony_ci } 1614d5ac70f0Sopenharmony_ci snd_output_putc(out, q); 1615d5ac70f0Sopenharmony_ci} 1616d5ac70f0Sopenharmony_ci 1617d5ac70f0Sopenharmony_cistatic void level_print(snd_output_t *out, unsigned int level) 1618d5ac70f0Sopenharmony_ci{ 1619d5ac70f0Sopenharmony_ci char a[level + 1]; 1620d5ac70f0Sopenharmony_ci memset(a, '\t', level); 1621d5ac70f0Sopenharmony_ci a[level] = '\0'; 1622d5ac70f0Sopenharmony_ci snd_output_puts(out, a); 1623d5ac70f0Sopenharmony_ci} 1624d5ac70f0Sopenharmony_ci 1625d5ac70f0Sopenharmony_cistatic int _snd_config_save_children(snd_config_t *config, snd_output_t *out, 1626d5ac70f0Sopenharmony_ci unsigned int level, unsigned int joins, 1627d5ac70f0Sopenharmony_ci int array); 1628d5ac70f0Sopenharmony_ci 1629d5ac70f0Sopenharmony_ciint _snd_config_save_node_value(snd_config_t *n, snd_output_t *out, 1630d5ac70f0Sopenharmony_ci unsigned int level) 1631d5ac70f0Sopenharmony_ci{ 1632d5ac70f0Sopenharmony_ci int err, array; 1633d5ac70f0Sopenharmony_ci switch (n->type) { 1634d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER: 1635d5ac70f0Sopenharmony_ci snd_output_printf(out, "%ld", n->u.integer); 1636d5ac70f0Sopenharmony_ci break; 1637d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER64: 1638d5ac70f0Sopenharmony_ci snd_output_printf(out, "%lld", n->u.integer64); 1639d5ac70f0Sopenharmony_ci break; 1640d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_REAL: 1641d5ac70f0Sopenharmony_ci snd_output_printf(out, "%-16g", n->u.real); 1642d5ac70f0Sopenharmony_ci break; 1643d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_STRING: 1644d5ac70f0Sopenharmony_ci string_print(n->u.string, 0, out); 1645d5ac70f0Sopenharmony_ci break; 1646d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_POINTER: 1647d5ac70f0Sopenharmony_ci SNDERR("cannot save runtime pointer type"); 1648d5ac70f0Sopenharmony_ci return -EINVAL; 1649d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_COMPOUND: 1650d5ac70f0Sopenharmony_ci array = snd_config_is_array(n); 1651d5ac70f0Sopenharmony_ci snd_output_putc(out, array ? '[' : '{'); 1652d5ac70f0Sopenharmony_ci snd_output_putc(out, '\n'); 1653d5ac70f0Sopenharmony_ci err = _snd_config_save_children(n, out, level + 1, 0, array); 1654d5ac70f0Sopenharmony_ci if (err < 0) 1655d5ac70f0Sopenharmony_ci return err; 1656d5ac70f0Sopenharmony_ci level_print(out, level); 1657d5ac70f0Sopenharmony_ci snd_output_putc(out, array ? ']' : '}'); 1658d5ac70f0Sopenharmony_ci break; 1659d5ac70f0Sopenharmony_ci } 1660d5ac70f0Sopenharmony_ci return 0; 1661d5ac70f0Sopenharmony_ci} 1662d5ac70f0Sopenharmony_ci 1663d5ac70f0Sopenharmony_cistatic void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins) 1664d5ac70f0Sopenharmony_ci{ 1665d5ac70f0Sopenharmony_ci if (joins > 0) { 1666d5ac70f0Sopenharmony_ci assert(n->parent); 1667d5ac70f0Sopenharmony_ci id_print(n->parent, out, joins - 1); 1668d5ac70f0Sopenharmony_ci snd_output_putc(out, '.'); 1669d5ac70f0Sopenharmony_ci } 1670d5ac70f0Sopenharmony_ci string_print(n->id, 1, out); 1671d5ac70f0Sopenharmony_ci} 1672d5ac70f0Sopenharmony_ci 1673d5ac70f0Sopenharmony_cistatic int _snd_config_save_children(snd_config_t *config, snd_output_t *out, 1674d5ac70f0Sopenharmony_ci unsigned int level, unsigned int joins, 1675d5ac70f0Sopenharmony_ci int array) 1676d5ac70f0Sopenharmony_ci{ 1677d5ac70f0Sopenharmony_ci int err; 1678d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1679d5ac70f0Sopenharmony_ci assert(config && out); 1680d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, config) { 1681d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1682d5ac70f0Sopenharmony_ci if (n->type == SND_CONFIG_TYPE_COMPOUND && 1683d5ac70f0Sopenharmony_ci n->u.compound.join) { 1684d5ac70f0Sopenharmony_ci err = _snd_config_save_children(n, out, level, joins + 1, 0); 1685d5ac70f0Sopenharmony_ci if (err < 0) 1686d5ac70f0Sopenharmony_ci return err; 1687d5ac70f0Sopenharmony_ci continue; 1688d5ac70f0Sopenharmony_ci } 1689d5ac70f0Sopenharmony_ci level_print(out, level); 1690d5ac70f0Sopenharmony_ci if (!array) { 1691d5ac70f0Sopenharmony_ci id_print(n, out, joins); 1692d5ac70f0Sopenharmony_ci snd_output_putc(out, ' '); 1693d5ac70f0Sopenharmony_ci#if 0 1694d5ac70f0Sopenharmony_ci snd_output_putc(out, '='); 1695d5ac70f0Sopenharmony_ci#endif 1696d5ac70f0Sopenharmony_ci } 1697d5ac70f0Sopenharmony_ci err = _snd_config_save_node_value(n, out, level); 1698d5ac70f0Sopenharmony_ci if (err < 0) 1699d5ac70f0Sopenharmony_ci return err; 1700d5ac70f0Sopenharmony_ci#if 0 1701d5ac70f0Sopenharmony_ci snd_output_putc(out, ';'); 1702d5ac70f0Sopenharmony_ci#endif 1703d5ac70f0Sopenharmony_ci snd_output_putc(out, '\n'); 1704d5ac70f0Sopenharmony_ci } 1705d5ac70f0Sopenharmony_ci return 0; 1706d5ac70f0Sopenharmony_ci} 1707d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 1708d5ac70f0Sopenharmony_ci 1709d5ac70f0Sopenharmony_ci 1710d5ac70f0Sopenharmony_ci/** 1711d5ac70f0Sopenharmony_ci * \brief Substitutes one configuration node to another. 1712d5ac70f0Sopenharmony_ci * \param dst Handle to the destination node. 1713d5ac70f0Sopenharmony_ci * \param src Handle to the source node. Must not be the same as \a dst. 1714d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 1715d5ac70f0Sopenharmony_ci * 1716d5ac70f0Sopenharmony_ci * If both nodes are compounds, the source compound node members will 1717d5ac70f0Sopenharmony_ci * be moved to the destination compound node. The original destination 1718d5ac70f0Sopenharmony_ci * compound node members will be deleted (overwritten). 1719d5ac70f0Sopenharmony_ci * 1720d5ac70f0Sopenharmony_ci * If the destination node is a compound and the source node is 1721d5ac70f0Sopenharmony_ci * an ordinary type, the compound members are deleted (including 1722d5ac70f0Sopenharmony_ci * their contents). 1723d5ac70f0Sopenharmony_ci * 1724d5ac70f0Sopenharmony_ci * Otherwise, the source node's value replaces the destination node's 1725d5ac70f0Sopenharmony_ci * value. 1726d5ac70f0Sopenharmony_ci * 1727d5ac70f0Sopenharmony_ci * In any case, a successful call to this function frees the source 1728d5ac70f0Sopenharmony_ci * node. 1729d5ac70f0Sopenharmony_ci */ 1730d5ac70f0Sopenharmony_ciint snd_config_substitute(snd_config_t *dst, snd_config_t *src) 1731d5ac70f0Sopenharmony_ci{ 1732d5ac70f0Sopenharmony_ci assert(dst && src); 1733d5ac70f0Sopenharmony_ci if (dst->type == SND_CONFIG_TYPE_COMPOUND) { 1734d5ac70f0Sopenharmony_ci int err = snd_config_delete_compound_members(dst); 1735d5ac70f0Sopenharmony_ci if (err < 0) 1736d5ac70f0Sopenharmony_ci return err; 1737d5ac70f0Sopenharmony_ci } 1738d5ac70f0Sopenharmony_ci if (dst->type == SND_CONFIG_TYPE_COMPOUND && 1739d5ac70f0Sopenharmony_ci src->type == SND_CONFIG_TYPE_COMPOUND) { /* overwrite */ 1740d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1741d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, src) { 1742d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1743d5ac70f0Sopenharmony_ci n->parent = dst; 1744d5ac70f0Sopenharmony_ci } 1745d5ac70f0Sopenharmony_ci src->u.compound.fields.next->prev = &dst->u.compound.fields; 1746d5ac70f0Sopenharmony_ci src->u.compound.fields.prev->next = &dst->u.compound.fields; 1747d5ac70f0Sopenharmony_ci } 1748d5ac70f0Sopenharmony_ci free(dst->id); 1749d5ac70f0Sopenharmony_ci if (dst->type == SND_CONFIG_TYPE_STRING) 1750d5ac70f0Sopenharmony_ci free(dst->u.string); 1751d5ac70f0Sopenharmony_ci dst->id = src->id; 1752d5ac70f0Sopenharmony_ci dst->type = src->type; 1753d5ac70f0Sopenharmony_ci dst->u = src->u; 1754d5ac70f0Sopenharmony_ci free(src); 1755d5ac70f0Sopenharmony_ci return 0; 1756d5ac70f0Sopenharmony_ci} 1757d5ac70f0Sopenharmony_ci 1758d5ac70f0Sopenharmony_ci/** 1759d5ac70f0Sopenharmony_ci * \brief Converts an ASCII string to a configuration node type. 1760d5ac70f0Sopenharmony_ci * \param[in] ascii A string containing a configuration node type. 1761d5ac70f0Sopenharmony_ci * \param[out] type The node type corresponding to \a ascii. 1762d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 1763d5ac70f0Sopenharmony_ci * 1764d5ac70f0Sopenharmony_ci * This function recognizes at least the following node types: 1765d5ac70f0Sopenharmony_ci * <dl> 1766d5ac70f0Sopenharmony_ci * <dt>integer<dt>#SND_CONFIG_TYPE_INTEGER 1767d5ac70f0Sopenharmony_ci * <dt>integer64<dt>#SND_CONFIG_TYPE_INTEGER64 1768d5ac70f0Sopenharmony_ci * <dt>real<dt>#SND_CONFIG_TYPE_REAL 1769d5ac70f0Sopenharmony_ci * <dt>string<dt>#SND_CONFIG_TYPE_STRING 1770d5ac70f0Sopenharmony_ci * <dt>compound<dt>#SND_CONFIG_TYPE_COMPOUND 1771d5ac70f0Sopenharmony_ci * </dl> 1772d5ac70f0Sopenharmony_ci * 1773d5ac70f0Sopenharmony_ci * \par Errors: 1774d5ac70f0Sopenharmony_ci * <dl> 1775d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>Unknown note type in \a type. 1776d5ac70f0Sopenharmony_ci * </dl> 1777d5ac70f0Sopenharmony_ci */ 1778d5ac70f0Sopenharmony_ciint snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type) 1779d5ac70f0Sopenharmony_ci{ 1780d5ac70f0Sopenharmony_ci assert(ascii && type); 1781d5ac70f0Sopenharmony_ci if (!strcmp(ascii, "integer")) { 1782d5ac70f0Sopenharmony_ci *type = SND_CONFIG_TYPE_INTEGER; 1783d5ac70f0Sopenharmony_ci return 0; 1784d5ac70f0Sopenharmony_ci } 1785d5ac70f0Sopenharmony_ci if (!strcmp(ascii, "integer64")) { 1786d5ac70f0Sopenharmony_ci *type = SND_CONFIG_TYPE_INTEGER64; 1787d5ac70f0Sopenharmony_ci return 0; 1788d5ac70f0Sopenharmony_ci } 1789d5ac70f0Sopenharmony_ci if (!strcmp(ascii, "real")) { 1790d5ac70f0Sopenharmony_ci *type = SND_CONFIG_TYPE_REAL; 1791d5ac70f0Sopenharmony_ci return 0; 1792d5ac70f0Sopenharmony_ci } 1793d5ac70f0Sopenharmony_ci if (!strcmp(ascii, "string")) { 1794d5ac70f0Sopenharmony_ci *type = SND_CONFIG_TYPE_STRING; 1795d5ac70f0Sopenharmony_ci return 0; 1796d5ac70f0Sopenharmony_ci } 1797d5ac70f0Sopenharmony_ci if (!strcmp(ascii, "compound")) { 1798d5ac70f0Sopenharmony_ci *type = SND_CONFIG_TYPE_COMPOUND; 1799d5ac70f0Sopenharmony_ci return 0; 1800d5ac70f0Sopenharmony_ci } 1801d5ac70f0Sopenharmony_ci return -EINVAL; 1802d5ac70f0Sopenharmony_ci} 1803d5ac70f0Sopenharmony_ci 1804d5ac70f0Sopenharmony_ci/** 1805d5ac70f0Sopenharmony_ci * \brief Returns the type of a configuration node. 1806d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 1807d5ac70f0Sopenharmony_ci * \return The node's type. 1808d5ac70f0Sopenharmony_ci * 1809d5ac70f0Sopenharmony_ci * \par Conforming to: 1810d5ac70f0Sopenharmony_ci * LSB 3.2 1811d5ac70f0Sopenharmony_ci */ 1812d5ac70f0Sopenharmony_cisnd_config_type_t snd_config_get_type(const snd_config_t *config) 1813d5ac70f0Sopenharmony_ci{ 1814d5ac70f0Sopenharmony_ci return config->type; 1815d5ac70f0Sopenharmony_ci} 1816d5ac70f0Sopenharmony_ci 1817d5ac70f0Sopenharmony_cistatic int check_array_item(const char *id, int index) 1818d5ac70f0Sopenharmony_ci{ 1819d5ac70f0Sopenharmony_ci const char *p; 1820d5ac70f0Sopenharmony_ci long val; 1821d5ac70f0Sopenharmony_ci 1822d5ac70f0Sopenharmony_ci for (p = id; *p; p++) { 1823d5ac70f0Sopenharmony_ci if (*p < '0' || *p > '9') 1824d5ac70f0Sopenharmony_ci return 0; 1825d5ac70f0Sopenharmony_ci } 1826d5ac70f0Sopenharmony_ci 1827d5ac70f0Sopenharmony_ci if (safe_strtol(id, &val)) 1828d5ac70f0Sopenharmony_ci return 0; 1829d5ac70f0Sopenharmony_ci return val == index; 1830d5ac70f0Sopenharmony_ci} 1831d5ac70f0Sopenharmony_ci 1832d5ac70f0Sopenharmony_ci/** 1833d5ac70f0Sopenharmony_ci * \brief Returns if the compound is an array (and count of items). 1834d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 1835d5ac70f0Sopenharmony_ci * \return A count of items in array, zero when the compound is not an array, 1836d5ac70f0Sopenharmony_ci * otherwise a negative error code. 1837d5ac70f0Sopenharmony_ci */ 1838d5ac70f0Sopenharmony_ciint snd_config_is_array(const snd_config_t *config) 1839d5ac70f0Sopenharmony_ci{ 1840d5ac70f0Sopenharmony_ci int idx; 1841d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1842d5ac70f0Sopenharmony_ci snd_config_t *node; 1843d5ac70f0Sopenharmony_ci 1844d5ac70f0Sopenharmony_ci assert(config); 1845d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_COMPOUND) 1846d5ac70f0Sopenharmony_ci return -EINVAL; 1847d5ac70f0Sopenharmony_ci idx = 0; 1848d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, config) { 1849d5ac70f0Sopenharmony_ci node = snd_config_iterator_entry(i); 1850d5ac70f0Sopenharmony_ci if (!check_array_item(node->id, idx)) 1851d5ac70f0Sopenharmony_ci return 0; 1852d5ac70f0Sopenharmony_ci idx++; 1853d5ac70f0Sopenharmony_ci } 1854d5ac70f0Sopenharmony_ci return idx; 1855d5ac70f0Sopenharmony_ci} 1856d5ac70f0Sopenharmony_ci 1857d5ac70f0Sopenharmony_ci/** 1858d5ac70f0Sopenharmony_ci * \brief Returns if the compound has no fields (is empty). 1859d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 1860d5ac70f0Sopenharmony_ci * \return A positive value when true, zero when false, otherwise a negative error code. 1861d5ac70f0Sopenharmony_ci */ 1862d5ac70f0Sopenharmony_ciint snd_config_is_empty(const snd_config_t *config) 1863d5ac70f0Sopenharmony_ci{ 1864d5ac70f0Sopenharmony_ci assert(config); 1865d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_COMPOUND) 1866d5ac70f0Sopenharmony_ci return -EINVAL; 1867d5ac70f0Sopenharmony_ci return list_empty(&config->u.compound.fields); 1868d5ac70f0Sopenharmony_ci} 1869d5ac70f0Sopenharmony_ci 1870d5ac70f0Sopenharmony_ci/** 1871d5ac70f0Sopenharmony_ci * \brief Returns the id of a configuration node. 1872d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 1873d5ac70f0Sopenharmony_ci * \param[out] id The function puts the pointer to the id string at the 1874d5ac70f0Sopenharmony_ci * address specified by \a id. 1875d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 1876d5ac70f0Sopenharmony_ci * 1877d5ac70f0Sopenharmony_ci * The returned string is owned by the configuration node; the application 1878d5ac70f0Sopenharmony_ci * must not modify or delete it, and the string becomes invalid when the 1879d5ac70f0Sopenharmony_ci * node's id changes or when the node is freed. 1880d5ac70f0Sopenharmony_ci * 1881d5ac70f0Sopenharmony_ci * If the node does not have an id, \a *id is set to \c NULL. 1882d5ac70f0Sopenharmony_ci * 1883d5ac70f0Sopenharmony_ci * \par Conforming to: 1884d5ac70f0Sopenharmony_ci * LSB 3.2 1885d5ac70f0Sopenharmony_ci */ 1886d5ac70f0Sopenharmony_ciint snd_config_get_id(const snd_config_t *config, const char **id) 1887d5ac70f0Sopenharmony_ci{ 1888d5ac70f0Sopenharmony_ci assert(config && id); 1889d5ac70f0Sopenharmony_ci *id = config->id; 1890d5ac70f0Sopenharmony_ci return 0; 1891d5ac70f0Sopenharmony_ci} 1892d5ac70f0Sopenharmony_ci 1893d5ac70f0Sopenharmony_ci/** 1894d5ac70f0Sopenharmony_ci * \brief Sets the id of a configuration node. 1895d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 1896d5ac70f0Sopenharmony_ci * \param id The new node id, must not be \c NULL. 1897d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 1898d5ac70f0Sopenharmony_ci * 1899d5ac70f0Sopenharmony_ci * This function stores a copy of \a id in the node. 1900d5ac70f0Sopenharmony_ci * 1901d5ac70f0Sopenharmony_ci * \par Errors: 1902d5ac70f0Sopenharmony_ci * <dl> 1903d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>One of \a config's siblings already has the id \a id. 1904d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>The id of a node with a parent cannot be set to \c NULL. 1905d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 1906d5ac70f0Sopenharmony_ci * </dl> 1907d5ac70f0Sopenharmony_ci */ 1908d5ac70f0Sopenharmony_ciint snd_config_set_id(snd_config_t *config, const char *id) 1909d5ac70f0Sopenharmony_ci{ 1910d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1911d5ac70f0Sopenharmony_ci char *new_id; 1912d5ac70f0Sopenharmony_ci assert(config); 1913d5ac70f0Sopenharmony_ci if (id) { 1914d5ac70f0Sopenharmony_ci if (config->parent) { 1915d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, config->parent) { 1916d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1917d5ac70f0Sopenharmony_ci if (n != config && strcmp(id, n->id) == 0) 1918d5ac70f0Sopenharmony_ci return -EEXIST; 1919d5ac70f0Sopenharmony_ci } 1920d5ac70f0Sopenharmony_ci } 1921d5ac70f0Sopenharmony_ci new_id = strdup(id); 1922d5ac70f0Sopenharmony_ci if (!new_id) 1923d5ac70f0Sopenharmony_ci return -ENOMEM; 1924d5ac70f0Sopenharmony_ci } else { 1925d5ac70f0Sopenharmony_ci if (config->parent) 1926d5ac70f0Sopenharmony_ci return -EINVAL; 1927d5ac70f0Sopenharmony_ci new_id = NULL; 1928d5ac70f0Sopenharmony_ci } 1929d5ac70f0Sopenharmony_ci free(config->id); 1930d5ac70f0Sopenharmony_ci config->id = new_id; 1931d5ac70f0Sopenharmony_ci return 0; 1932d5ac70f0Sopenharmony_ci} 1933d5ac70f0Sopenharmony_ci 1934d5ac70f0Sopenharmony_ci/** 1935d5ac70f0Sopenharmony_ci * \brief Creates a top level configuration node. 1936d5ac70f0Sopenharmony_ci * \param[out] config Handle to the new node. 1937d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 1938d5ac70f0Sopenharmony_ci * 1939d5ac70f0Sopenharmony_ci * The returned node is an empty compound node without a parent and 1940d5ac70f0Sopenharmony_ci * without an id. 1941d5ac70f0Sopenharmony_ci * 1942d5ac70f0Sopenharmony_ci * \par Errors: 1943d5ac70f0Sopenharmony_ci * <dl> 1944d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 1945d5ac70f0Sopenharmony_ci * </dl> 1946d5ac70f0Sopenharmony_ci * 1947d5ac70f0Sopenharmony_ci * \par Conforming to: 1948d5ac70f0Sopenharmony_ci * LSB 3.2 1949d5ac70f0Sopenharmony_ci */ 1950d5ac70f0Sopenharmony_ciint snd_config_top(snd_config_t **config) 1951d5ac70f0Sopenharmony_ci{ 1952d5ac70f0Sopenharmony_ci assert(config); 1953d5ac70f0Sopenharmony_ci return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND); 1954d5ac70f0Sopenharmony_ci} 1955d5ac70f0Sopenharmony_ci 1956d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 1957d5ac70f0Sopenharmony_ciint _snd_config_load_with_include(snd_config_t *config, snd_input_t *in, 1958d5ac70f0Sopenharmony_ci int override, const char * const *include_paths) 1959d5ac70f0Sopenharmony_ci{ 1960d5ac70f0Sopenharmony_ci int err; 1961d5ac70f0Sopenharmony_ci input_t input; 1962d5ac70f0Sopenharmony_ci struct filedesc *fd, *fd_next; 1963d5ac70f0Sopenharmony_ci 1964d5ac70f0Sopenharmony_ci assert(config && in); 1965d5ac70f0Sopenharmony_ci fd = malloc(sizeof(*fd)); 1966d5ac70f0Sopenharmony_ci if (!fd) 1967d5ac70f0Sopenharmony_ci return -ENOMEM; 1968d5ac70f0Sopenharmony_ci fd->name = NULL; 1969d5ac70f0Sopenharmony_ci fd->in = in; 1970d5ac70f0Sopenharmony_ci fd->line = 1; 1971d5ac70f0Sopenharmony_ci fd->column = 0; 1972d5ac70f0Sopenharmony_ci fd->next = NULL; 1973d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&fd->include_paths); 1974d5ac70f0Sopenharmony_ci if (include_paths) { 1975d5ac70f0Sopenharmony_ci for (; *include_paths; include_paths++) { 1976d5ac70f0Sopenharmony_ci err = add_include_path(fd, *include_paths); 1977d5ac70f0Sopenharmony_ci if (err < 0) 1978d5ac70f0Sopenharmony_ci goto _end; 1979d5ac70f0Sopenharmony_ci } 1980d5ac70f0Sopenharmony_ci } else { 1981d5ac70f0Sopenharmony_ci err = add_include_path(fd, snd_config_topdir()); 1982d5ac70f0Sopenharmony_ci if (err < 0) 1983d5ac70f0Sopenharmony_ci goto _end; 1984d5ac70f0Sopenharmony_ci } 1985d5ac70f0Sopenharmony_ci input.current = fd; 1986d5ac70f0Sopenharmony_ci input.unget = 0; 1987d5ac70f0Sopenharmony_ci err = parse_defs(config, &input, 0, override); 1988d5ac70f0Sopenharmony_ci fd = input.current; 1989d5ac70f0Sopenharmony_ci if (err < 0) { 1990d5ac70f0Sopenharmony_ci const char *str; 1991d5ac70f0Sopenharmony_ci switch (err) { 1992d5ac70f0Sopenharmony_ci case LOCAL_UNTERMINATED_STRING: 1993d5ac70f0Sopenharmony_ci str = "Unterminated string"; 1994d5ac70f0Sopenharmony_ci err = -EINVAL; 1995d5ac70f0Sopenharmony_ci break; 1996d5ac70f0Sopenharmony_ci case LOCAL_UNTERMINATED_QUOTE: 1997d5ac70f0Sopenharmony_ci str = "Unterminated quote"; 1998d5ac70f0Sopenharmony_ci err = -EINVAL; 1999d5ac70f0Sopenharmony_ci break; 2000d5ac70f0Sopenharmony_ci case LOCAL_UNEXPECTED_CHAR: 2001d5ac70f0Sopenharmony_ci str = "Unexpected char"; 2002d5ac70f0Sopenharmony_ci err = -EINVAL; 2003d5ac70f0Sopenharmony_ci break; 2004d5ac70f0Sopenharmony_ci case LOCAL_UNEXPECTED_EOF: 2005d5ac70f0Sopenharmony_ci str = "Unexpected end of file"; 2006d5ac70f0Sopenharmony_ci err = -EINVAL; 2007d5ac70f0Sopenharmony_ci break; 2008d5ac70f0Sopenharmony_ci default: 2009d5ac70f0Sopenharmony_ci str = strerror(-err); 2010d5ac70f0Sopenharmony_ci break; 2011d5ac70f0Sopenharmony_ci } 2012d5ac70f0Sopenharmony_ci SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str); 2013d5ac70f0Sopenharmony_ci goto _end; 2014d5ac70f0Sopenharmony_ci } 2015d5ac70f0Sopenharmony_ci err = get_char(&input); 2016d5ac70f0Sopenharmony_ci fd = input.current; 2017d5ac70f0Sopenharmony_ci if (err != LOCAL_UNEXPECTED_EOF) { 2018d5ac70f0Sopenharmony_ci SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column); 2019d5ac70f0Sopenharmony_ci err = -EINVAL; 2020d5ac70f0Sopenharmony_ci goto _end; 2021d5ac70f0Sopenharmony_ci } 2022d5ac70f0Sopenharmony_ci err = 0; 2023d5ac70f0Sopenharmony_ci _end: 2024d5ac70f0Sopenharmony_ci while (fd->next) { 2025d5ac70f0Sopenharmony_ci fd_next = fd->next; 2026d5ac70f0Sopenharmony_ci snd_input_close(fd->in); 2027d5ac70f0Sopenharmony_ci free(fd->name); 2028d5ac70f0Sopenharmony_ci free_include_paths(fd); 2029d5ac70f0Sopenharmony_ci free(fd); 2030d5ac70f0Sopenharmony_ci fd = fd_next; 2031d5ac70f0Sopenharmony_ci } 2032d5ac70f0Sopenharmony_ci 2033d5ac70f0Sopenharmony_ci free_include_paths(fd); 2034d5ac70f0Sopenharmony_ci free(fd); 2035d5ac70f0Sopenharmony_ci return err; 2036d5ac70f0Sopenharmony_ci} 2037d5ac70f0Sopenharmony_ci#endif 2038d5ac70f0Sopenharmony_ci 2039d5ac70f0Sopenharmony_ci/** 2040d5ac70f0Sopenharmony_ci * \brief Loads a configuration tree. 2041d5ac70f0Sopenharmony_ci * \param config Handle to a top level configuration node. 2042d5ac70f0Sopenharmony_ci * \param in Input handle to read the configuration from. 2043d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2044d5ac70f0Sopenharmony_ci * 2045d5ac70f0Sopenharmony_ci * The definitions loaded from the input are added to \a config, which 2046d5ac70f0Sopenharmony_ci * must be a compound node. 2047d5ac70f0Sopenharmony_ci * 2048d5ac70f0Sopenharmony_ci * \par Errors: 2049d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or 2050d5ac70f0Sopenharmony_ci * functions. 2051d5ac70f0Sopenharmony_ci * 2052d5ac70f0Sopenharmony_ci * \par Conforming to: 2053d5ac70f0Sopenharmony_ci * LSB 3.2 2054d5ac70f0Sopenharmony_ci */ 2055d5ac70f0Sopenharmony_ciint snd_config_load(snd_config_t *config, snd_input_t *in) 2056d5ac70f0Sopenharmony_ci{ 2057d5ac70f0Sopenharmony_ci return _snd_config_load_with_include(config, in, 0, NULL); 2058d5ac70f0Sopenharmony_ci} 2059d5ac70f0Sopenharmony_ci 2060d5ac70f0Sopenharmony_ci/** 2061d5ac70f0Sopenharmony_ci * \brief Loads a configuration tree from a string. 2062d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the configuration 2063d5ac70f0Sopenharmony_ci * node loaded from the file(s) at the address specified 2064d5ac70f0Sopenharmony_ci * by \a config. 2065d5ac70f0Sopenharmony_ci * \param[in] s String with the ASCII configuration 2066d5ac70f0Sopenharmony_ci * \param[in] size String size, if zero, a C string is expected (with termination) 2067d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2068d5ac70f0Sopenharmony_ci * 2069d5ac70f0Sopenharmony_ci * The definitions loaded from the string are put to \a config, which 2070d5ac70f0Sopenharmony_ci * is created as a new top node. 2071d5ac70f0Sopenharmony_ci * 2072d5ac70f0Sopenharmony_ci * \par Errors: 2073d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or 2074d5ac70f0Sopenharmony_ci * functions. 2075d5ac70f0Sopenharmony_ci */ 2076d5ac70f0Sopenharmony_ciint snd_config_load_string(snd_config_t **config, const char *s, size_t size) 2077d5ac70f0Sopenharmony_ci{ 2078d5ac70f0Sopenharmony_ci snd_input_t *input; 2079d5ac70f0Sopenharmony_ci snd_config_t *dst; 2080d5ac70f0Sopenharmony_ci int err; 2081d5ac70f0Sopenharmony_ci 2082d5ac70f0Sopenharmony_ci assert(config && s); 2083d5ac70f0Sopenharmony_ci if (size == 0) 2084d5ac70f0Sopenharmony_ci size = strlen(s); 2085d5ac70f0Sopenharmony_ci err = snd_input_buffer_open(&input, s, size); 2086d5ac70f0Sopenharmony_ci if (err < 0) 2087d5ac70f0Sopenharmony_ci return err; 2088d5ac70f0Sopenharmony_ci err = snd_config_top(&dst); 2089d5ac70f0Sopenharmony_ci if (err < 0) { 2090d5ac70f0Sopenharmony_ci snd_input_close(input); 2091d5ac70f0Sopenharmony_ci return err; 2092d5ac70f0Sopenharmony_ci } 2093d5ac70f0Sopenharmony_ci err = snd_config_load(dst, input); 2094d5ac70f0Sopenharmony_ci snd_input_close(input); 2095d5ac70f0Sopenharmony_ci if (err < 0) { 2096d5ac70f0Sopenharmony_ci snd_config_delete(dst); 2097d5ac70f0Sopenharmony_ci return err; 2098d5ac70f0Sopenharmony_ci } 2099d5ac70f0Sopenharmony_ci *config = dst; 2100d5ac70f0Sopenharmony_ci return 0; 2101d5ac70f0Sopenharmony_ci} 2102d5ac70f0Sopenharmony_ci 2103d5ac70f0Sopenharmony_ci/** 2104d5ac70f0Sopenharmony_ci * \brief Loads a configuration tree and overrides existing configuration nodes. 2105d5ac70f0Sopenharmony_ci * \param config Handle to a top level configuration node. 2106d5ac70f0Sopenharmony_ci * \param in Input handle to read the configuration from. 2107d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2108d5ac70f0Sopenharmony_ci * 2109d5ac70f0Sopenharmony_ci * This function loads definitions from \a in into \a config like 2110d5ac70f0Sopenharmony_ci * #snd_config_load, but the default mode for input nodes is 'override' 2111d5ac70f0Sopenharmony_ci * (!) instead of 'merge+create' (+). 2112d5ac70f0Sopenharmony_ci */ 2113d5ac70f0Sopenharmony_ciint snd_config_load_override(snd_config_t *config, snd_input_t *in) 2114d5ac70f0Sopenharmony_ci{ 2115d5ac70f0Sopenharmony_ci return _snd_config_load_with_include(config, in, 1, NULL); 2116d5ac70f0Sopenharmony_ci} 2117d5ac70f0Sopenharmony_ci 2118d5ac70f0Sopenharmony_ci/** 2119d5ac70f0Sopenharmony_ci * \brief Adds a child to a compound configuration node. 2120d5ac70f0Sopenharmony_ci * \param parent Handle to a compound configuration node. 2121d5ac70f0Sopenharmony_ci * \param child Handle to the configuration node to be added. 2122d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2123d5ac70f0Sopenharmony_ci * 2124d5ac70f0Sopenharmony_ci * This function makes the node \a child a child of the node \a parent. 2125d5ac70f0Sopenharmony_ci * 2126d5ac70f0Sopenharmony_ci * The parent node then owns the child node, i.e., the child node gets 2127d5ac70f0Sopenharmony_ci * deleted together with its parent. 2128d5ac70f0Sopenharmony_ci * 2129d5ac70f0Sopenharmony_ci * \a child must have an id. 2130d5ac70f0Sopenharmony_ci * 2131d5ac70f0Sopenharmony_ci * \par Errors: 2132d5ac70f0Sopenharmony_ci * <dl> 2133d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child does not have an id. 2134d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child already has a parent. 2135d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>\a parent already contains a child node with the same 2136d5ac70f0Sopenharmony_ci * id as \a child. 2137d5ac70f0Sopenharmony_ci * </dl> 2138d5ac70f0Sopenharmony_ci * 2139d5ac70f0Sopenharmony_ci * \par Conforming to: 2140d5ac70f0Sopenharmony_ci * LSB 3.2 2141d5ac70f0Sopenharmony_ci */ 2142d5ac70f0Sopenharmony_ciint snd_config_add(snd_config_t *parent, snd_config_t *child) 2143d5ac70f0Sopenharmony_ci{ 2144d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 2145d5ac70f0Sopenharmony_ci assert(parent && child); 2146d5ac70f0Sopenharmony_ci if (!child->id || child->parent) 2147d5ac70f0Sopenharmony_ci return -EINVAL; 2148d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, parent) { 2149d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 2150d5ac70f0Sopenharmony_ci if (strcmp(child->id, n->id) == 0) 2151d5ac70f0Sopenharmony_ci return -EEXIST; 2152d5ac70f0Sopenharmony_ci } 2153d5ac70f0Sopenharmony_ci child->parent = parent; 2154d5ac70f0Sopenharmony_ci list_add_tail(&child->list, &parent->u.compound.fields); 2155d5ac70f0Sopenharmony_ci return 0; 2156d5ac70f0Sopenharmony_ci} 2157d5ac70f0Sopenharmony_ci 2158d5ac70f0Sopenharmony_ci/** 2159d5ac70f0Sopenharmony_ci * \brief Adds a child after another child configuration node. 2160d5ac70f0Sopenharmony_ci * \param after Handle to the start configuration node. 2161d5ac70f0Sopenharmony_ci * \param child Handle to the configuration node to be added. 2162d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2163d5ac70f0Sopenharmony_ci * 2164d5ac70f0Sopenharmony_ci * This function makes the node \a child a child of the parent of 2165d5ac70f0Sopenharmony_ci * the node \a after. 2166d5ac70f0Sopenharmony_ci * 2167d5ac70f0Sopenharmony_ci * The parent node then owns the child node, i.e., the child node gets 2168d5ac70f0Sopenharmony_ci * deleted together with its parent. 2169d5ac70f0Sopenharmony_ci * 2170d5ac70f0Sopenharmony_ci * \a child must have an id. 2171d5ac70f0Sopenharmony_ci * 2172d5ac70f0Sopenharmony_ci * \par Errors: 2173d5ac70f0Sopenharmony_ci * <dl> 2174d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child does not have an id. 2175d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child already has a parent. 2176d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>\a parent already contains a child node with the same 2177d5ac70f0Sopenharmony_ci * id as \a child. 2178d5ac70f0Sopenharmony_ci * </dl> 2179d5ac70f0Sopenharmony_ci */ 2180d5ac70f0Sopenharmony_ciint snd_config_add_after(snd_config_t *after, snd_config_t *child) 2181d5ac70f0Sopenharmony_ci{ 2182d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 2183d5ac70f0Sopenharmony_ci snd_config_t *parent; 2184d5ac70f0Sopenharmony_ci assert(after && child); 2185d5ac70f0Sopenharmony_ci parent = after->parent; 2186d5ac70f0Sopenharmony_ci assert(parent); 2187d5ac70f0Sopenharmony_ci if (!child->id || child->parent) 2188d5ac70f0Sopenharmony_ci return -EINVAL; 2189d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, parent) { 2190d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 2191d5ac70f0Sopenharmony_ci if (strcmp(child->id, n->id) == 0) 2192d5ac70f0Sopenharmony_ci return -EEXIST; 2193d5ac70f0Sopenharmony_ci } 2194d5ac70f0Sopenharmony_ci child->parent = parent; 2195d5ac70f0Sopenharmony_ci list_insert(&child->list, &after->list, after->list.next); 2196d5ac70f0Sopenharmony_ci return 0; 2197d5ac70f0Sopenharmony_ci} 2198d5ac70f0Sopenharmony_ci 2199d5ac70f0Sopenharmony_ci/** 2200d5ac70f0Sopenharmony_ci * \brief Adds a child before another child configuration node. 2201d5ac70f0Sopenharmony_ci * \param before Handle to the start configuration node. 2202d5ac70f0Sopenharmony_ci * \param child Handle to the configuration node to be added. 2203d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2204d5ac70f0Sopenharmony_ci * 2205d5ac70f0Sopenharmony_ci * This function makes the node \a child a child of the parent of 2206d5ac70f0Sopenharmony_ci * the node \a before. 2207d5ac70f0Sopenharmony_ci * 2208d5ac70f0Sopenharmony_ci * The parent node then owns the child node, i.e., the child node gets 2209d5ac70f0Sopenharmony_ci * deleted together with its parent. 2210d5ac70f0Sopenharmony_ci * 2211d5ac70f0Sopenharmony_ci * \a child must have an id. 2212d5ac70f0Sopenharmony_ci * 2213d5ac70f0Sopenharmony_ci * \par Errors: 2214d5ac70f0Sopenharmony_ci * <dl> 2215d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child does not have an id. 2216d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child already has a parent. 2217d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>\a parent already contains a child node with the same 2218d5ac70f0Sopenharmony_ci * id as \a child. 2219d5ac70f0Sopenharmony_ci * </dl> 2220d5ac70f0Sopenharmony_ci */ 2221d5ac70f0Sopenharmony_ciint snd_config_add_before(snd_config_t *before, snd_config_t *child) 2222d5ac70f0Sopenharmony_ci{ 2223d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 2224d5ac70f0Sopenharmony_ci snd_config_t *parent; 2225d5ac70f0Sopenharmony_ci assert(before && child); 2226d5ac70f0Sopenharmony_ci parent = before->parent; 2227d5ac70f0Sopenharmony_ci assert(parent); 2228d5ac70f0Sopenharmony_ci if (!child->id || child->parent) 2229d5ac70f0Sopenharmony_ci return -EINVAL; 2230d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, parent) { 2231d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 2232d5ac70f0Sopenharmony_ci if (strcmp(child->id, n->id) == 0) 2233d5ac70f0Sopenharmony_ci return -EEXIST; 2234d5ac70f0Sopenharmony_ci } 2235d5ac70f0Sopenharmony_ci child->parent = parent; 2236d5ac70f0Sopenharmony_ci list_insert(&child->list, before->list.prev, &before->list); 2237d5ac70f0Sopenharmony_ci return 0; 2238d5ac70f0Sopenharmony_ci} 2239d5ac70f0Sopenharmony_ci 2240d5ac70f0Sopenharmony_ci/* 2241d5ac70f0Sopenharmony_ci * append all src items to the end of dst arrray 2242d5ac70f0Sopenharmony_ci */ 2243d5ac70f0Sopenharmony_cistatic int _snd_config_array_merge(snd_config_t *dst, snd_config_t *src, int index) 2244d5ac70f0Sopenharmony_ci{ 2245d5ac70f0Sopenharmony_ci snd_config_iterator_t si, snext; 2246d5ac70f0Sopenharmony_ci int err; 2247d5ac70f0Sopenharmony_ci 2248d5ac70f0Sopenharmony_ci snd_config_for_each(si, snext, src) { 2249d5ac70f0Sopenharmony_ci snd_config_t *sn = snd_config_iterator_entry(si); 2250d5ac70f0Sopenharmony_ci char id[16]; 2251d5ac70f0Sopenharmony_ci snd_config_remove(sn); 2252d5ac70f0Sopenharmony_ci snprintf(id, sizeof(id), "%d", index++); 2253d5ac70f0Sopenharmony_ci err = snd_config_set_id(sn, id); 2254d5ac70f0Sopenharmony_ci if (err < 0) { 2255d5ac70f0Sopenharmony_ci snd_config_delete(sn); 2256d5ac70f0Sopenharmony_ci return err; 2257d5ac70f0Sopenharmony_ci } 2258d5ac70f0Sopenharmony_ci sn->parent = dst; 2259d5ac70f0Sopenharmony_ci list_add_tail(&sn->list, &dst->u.compound.fields); 2260d5ac70f0Sopenharmony_ci } 2261d5ac70f0Sopenharmony_ci snd_config_delete(src); 2262d5ac70f0Sopenharmony_ci return 0; 2263d5ac70f0Sopenharmony_ci} 2264d5ac70f0Sopenharmony_ci 2265d5ac70f0Sopenharmony_ci/** 2266d5ac70f0Sopenharmony_ci * \brief In-place merge of two config handles 2267d5ac70f0Sopenharmony_ci * \param[out] dst Config handle for the merged contents 2268d5ac70f0Sopenharmony_ci * \param[in] src Config handle to merge into dst (may be NULL) 2269d5ac70f0Sopenharmony_ci * \param[in] override Override flag 2270d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2271d5ac70f0Sopenharmony_ci * 2272d5ac70f0Sopenharmony_ci * This function merges all fields from the source compound to the destination compound. 2273d5ac70f0Sopenharmony_ci * When the \a override flag is set, the related subtree in \a dst is replaced from \a src. 2274d5ac70f0Sopenharmony_ci * 2275d5ac70f0Sopenharmony_ci * When \a override is not set, the child compounds are traversed and merged. 2276d5ac70f0Sopenharmony_ci * 2277d5ac70f0Sopenharmony_ci * The configuration elements other than compounds are always substituted (overwritten) 2278d5ac70f0Sopenharmony_ci * from the \a src config handle. 2279d5ac70f0Sopenharmony_ci * 2280d5ac70f0Sopenharmony_ci * The src handle is deleted. 2281d5ac70f0Sopenharmony_ci * 2282d5ac70f0Sopenharmony_ci * Note: On error, config handles may be modified. 2283d5ac70f0Sopenharmony_ci * 2284d5ac70f0Sopenharmony_ci * \par Errors: 2285d5ac70f0Sopenharmony_ci * <dl> 2286d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>identifier already exists (!override) 2287d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>not enough memory 2288d5ac70f0Sopenharmony_ci * </dl> 2289d5ac70f0Sopenharmony_ci */ 2290d5ac70f0Sopenharmony_ciint snd_config_merge(snd_config_t *dst, snd_config_t *src, int override) 2291d5ac70f0Sopenharmony_ci{ 2292d5ac70f0Sopenharmony_ci snd_config_iterator_t di, si, dnext, snext; 2293d5ac70f0Sopenharmony_ci bool found; 2294d5ac70f0Sopenharmony_ci int err, array; 2295d5ac70f0Sopenharmony_ci 2296d5ac70f0Sopenharmony_ci assert(dst); 2297d5ac70f0Sopenharmony_ci if (src == NULL) 2298d5ac70f0Sopenharmony_ci return 0; 2299d5ac70f0Sopenharmony_ci if (dst->type != SND_CONFIG_TYPE_COMPOUND || src->type != SND_CONFIG_TYPE_COMPOUND) 2300d5ac70f0Sopenharmony_ci return snd_config_substitute(dst, src); 2301d5ac70f0Sopenharmony_ci array = snd_config_is_array(dst); 2302d5ac70f0Sopenharmony_ci if (array && snd_config_is_array(src)) 2303d5ac70f0Sopenharmony_ci return _snd_config_array_merge(dst, src, array); 2304d5ac70f0Sopenharmony_ci snd_config_for_each(si, snext, src) { 2305d5ac70f0Sopenharmony_ci snd_config_t *sn = snd_config_iterator_entry(si); 2306d5ac70f0Sopenharmony_ci found = false; 2307d5ac70f0Sopenharmony_ci snd_config_for_each(di, dnext, dst) { 2308d5ac70f0Sopenharmony_ci snd_config_t *dn = snd_config_iterator_entry(di); 2309d5ac70f0Sopenharmony_ci if (strcmp(sn->id, dn->id) == 0) { 2310d5ac70f0Sopenharmony_ci if (override || 2311d5ac70f0Sopenharmony_ci sn->type != SND_CONFIG_TYPE_COMPOUND || 2312d5ac70f0Sopenharmony_ci dn->type != SND_CONFIG_TYPE_COMPOUND) { 2313d5ac70f0Sopenharmony_ci snd_config_remove(sn); 2314d5ac70f0Sopenharmony_ci err = snd_config_substitute(dn, sn); 2315d5ac70f0Sopenharmony_ci if (err < 0) 2316d5ac70f0Sopenharmony_ci return err; 2317d5ac70f0Sopenharmony_ci } else { 2318d5ac70f0Sopenharmony_ci err = snd_config_merge(dn, sn, 0); 2319d5ac70f0Sopenharmony_ci if (err < 0) 2320d5ac70f0Sopenharmony_ci return err; 2321d5ac70f0Sopenharmony_ci } 2322d5ac70f0Sopenharmony_ci found = true; 2323d5ac70f0Sopenharmony_ci break; 2324d5ac70f0Sopenharmony_ci } 2325d5ac70f0Sopenharmony_ci } 2326d5ac70f0Sopenharmony_ci if (!found) { 2327d5ac70f0Sopenharmony_ci /* move config from src to dst */ 2328d5ac70f0Sopenharmony_ci snd_config_remove(sn); 2329d5ac70f0Sopenharmony_ci sn->parent = dst; 2330d5ac70f0Sopenharmony_ci list_add_tail(&sn->list, &dst->u.compound.fields); 2331d5ac70f0Sopenharmony_ci } 2332d5ac70f0Sopenharmony_ci } 2333d5ac70f0Sopenharmony_ci snd_config_delete(src); 2334d5ac70f0Sopenharmony_ci return 0; 2335d5ac70f0Sopenharmony_ci} 2336d5ac70f0Sopenharmony_ci 2337d5ac70f0Sopenharmony_ci/** 2338d5ac70f0Sopenharmony_ci * \brief Removes a configuration node from its tree. 2339d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node to be removed. 2340d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2341d5ac70f0Sopenharmony_ci * 2342d5ac70f0Sopenharmony_ci * This function makes \a config a top-level node, i.e., if \a config 2343d5ac70f0Sopenharmony_ci * has a parent, then \a config is removed from the list of the parent's 2344d5ac70f0Sopenharmony_ci * children. 2345d5ac70f0Sopenharmony_ci * 2346d5ac70f0Sopenharmony_ci * This functions does \e not free the removed node. 2347d5ac70f0Sopenharmony_ci * 2348d5ac70f0Sopenharmony_ci * \sa snd_config_delete 2349d5ac70f0Sopenharmony_ci */ 2350d5ac70f0Sopenharmony_ciint snd_config_remove(snd_config_t *config) 2351d5ac70f0Sopenharmony_ci{ 2352d5ac70f0Sopenharmony_ci assert(config); 2353d5ac70f0Sopenharmony_ci if (config->parent) 2354d5ac70f0Sopenharmony_ci list_del(&config->list); 2355d5ac70f0Sopenharmony_ci config->parent = NULL; 2356d5ac70f0Sopenharmony_ci return 0; 2357d5ac70f0Sopenharmony_ci} 2358d5ac70f0Sopenharmony_ci 2359d5ac70f0Sopenharmony_ci/** 2360d5ac70f0Sopenharmony_ci * \brief Frees a configuration node. 2361d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node to be deleted. 2362d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2363d5ac70f0Sopenharmony_ci * 2364d5ac70f0Sopenharmony_ci * This function frees a configuration node and all its resources. 2365d5ac70f0Sopenharmony_ci * 2366d5ac70f0Sopenharmony_ci * If the node is a child node, it is removed from the tree before being 2367d5ac70f0Sopenharmony_ci * deleted. 2368d5ac70f0Sopenharmony_ci * 2369d5ac70f0Sopenharmony_ci * If the node is a compound node, its descendants (the whole subtree) 2370d5ac70f0Sopenharmony_ci * are deleted recursively. 2371d5ac70f0Sopenharmony_ci * 2372d5ac70f0Sopenharmony_ci * The function is supposed to be called only for locally copied config 2373d5ac70f0Sopenharmony_ci * trees. For the global tree, take the reference via #snd_config_update_ref 2374d5ac70f0Sopenharmony_ci * and free it via #snd_config_unref. 2375d5ac70f0Sopenharmony_ci * 2376d5ac70f0Sopenharmony_ci * \par Conforming to: 2377d5ac70f0Sopenharmony_ci * LSB 3.2 2378d5ac70f0Sopenharmony_ci * 2379d5ac70f0Sopenharmony_ci * \sa snd_config_remove 2380d5ac70f0Sopenharmony_ci */ 2381d5ac70f0Sopenharmony_ciint snd_config_delete(snd_config_t *config) 2382d5ac70f0Sopenharmony_ci{ 2383d5ac70f0Sopenharmony_ci assert(config); 2384d5ac70f0Sopenharmony_ci if (config->refcount > 0) { 2385d5ac70f0Sopenharmony_ci config->refcount--; 2386d5ac70f0Sopenharmony_ci return 0; 2387d5ac70f0Sopenharmony_ci } 2388d5ac70f0Sopenharmony_ci switch (config->type) { 2389d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_COMPOUND: 2390d5ac70f0Sopenharmony_ci { 2391d5ac70f0Sopenharmony_ci int err; 2392d5ac70f0Sopenharmony_ci struct list_head *i; 2393d5ac70f0Sopenharmony_ci i = config->u.compound.fields.next; 2394d5ac70f0Sopenharmony_ci while (i != &config->u.compound.fields) { 2395d5ac70f0Sopenharmony_ci struct list_head *nexti = i->next; 2396d5ac70f0Sopenharmony_ci snd_config_t *child = snd_config_iterator_entry(i); 2397d5ac70f0Sopenharmony_ci err = snd_config_delete(child); 2398d5ac70f0Sopenharmony_ci if (err < 0) 2399d5ac70f0Sopenharmony_ci return err; 2400d5ac70f0Sopenharmony_ci i = nexti; 2401d5ac70f0Sopenharmony_ci } 2402d5ac70f0Sopenharmony_ci break; 2403d5ac70f0Sopenharmony_ci } 2404d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_STRING: 2405d5ac70f0Sopenharmony_ci free(config->u.string); 2406d5ac70f0Sopenharmony_ci break; 2407d5ac70f0Sopenharmony_ci default: 2408d5ac70f0Sopenharmony_ci break; 2409d5ac70f0Sopenharmony_ci } 2410d5ac70f0Sopenharmony_ci if (config->parent) 2411d5ac70f0Sopenharmony_ci list_del(&config->list); 2412d5ac70f0Sopenharmony_ci free(config->id); 2413d5ac70f0Sopenharmony_ci free(config); 2414d5ac70f0Sopenharmony_ci return 0; 2415d5ac70f0Sopenharmony_ci} 2416d5ac70f0Sopenharmony_ci 2417d5ac70f0Sopenharmony_ci/** 2418d5ac70f0Sopenharmony_ci * \brief Deletes the children of a node. 2419d5ac70f0Sopenharmony_ci * \param config Handle to the compound configuration node. 2420d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2421d5ac70f0Sopenharmony_ci * 2422d5ac70f0Sopenharmony_ci * This function removes and frees all children of a configuration node. 2423d5ac70f0Sopenharmony_ci * 2424d5ac70f0Sopenharmony_ci * Any compound nodes among the children of \a config are deleted 2425d5ac70f0Sopenharmony_ci * recursively. 2426d5ac70f0Sopenharmony_ci * 2427d5ac70f0Sopenharmony_ci * After a successful call to this function, \a config is an empty 2428d5ac70f0Sopenharmony_ci * compound node. 2429d5ac70f0Sopenharmony_ci * 2430d5ac70f0Sopenharmony_ci * \par Errors: 2431d5ac70f0Sopenharmony_ci * <dl> 2432d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a compound node. 2433d5ac70f0Sopenharmony_ci * </dl> 2434d5ac70f0Sopenharmony_ci */ 2435d5ac70f0Sopenharmony_ciint snd_config_delete_compound_members(const snd_config_t *config) 2436d5ac70f0Sopenharmony_ci{ 2437d5ac70f0Sopenharmony_ci int err; 2438d5ac70f0Sopenharmony_ci struct list_head *i; 2439d5ac70f0Sopenharmony_ci 2440d5ac70f0Sopenharmony_ci assert(config); 2441d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_COMPOUND) 2442d5ac70f0Sopenharmony_ci return -EINVAL; 2443d5ac70f0Sopenharmony_ci i = config->u.compound.fields.next; 2444d5ac70f0Sopenharmony_ci while (i != &config->u.compound.fields) { 2445d5ac70f0Sopenharmony_ci struct list_head *nexti = i->next; 2446d5ac70f0Sopenharmony_ci snd_config_t *child = snd_config_iterator_entry(i); 2447d5ac70f0Sopenharmony_ci err = snd_config_delete(child); 2448d5ac70f0Sopenharmony_ci if (err < 0) 2449d5ac70f0Sopenharmony_ci return err; 2450d5ac70f0Sopenharmony_ci i = nexti; 2451d5ac70f0Sopenharmony_ci } 2452d5ac70f0Sopenharmony_ci return 0; 2453d5ac70f0Sopenharmony_ci} 2454d5ac70f0Sopenharmony_ci 2455d5ac70f0Sopenharmony_ci/** 2456d5ac70f0Sopenharmony_ci * \brief Creates a configuration node. 2457d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2458d5ac70f0Sopenharmony_ci * the address specified by \a config. 2459d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2460d5ac70f0Sopenharmony_ci * \param[in] type The type of the new node. 2461d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2462d5ac70f0Sopenharmony_ci * 2463d5ac70f0Sopenharmony_ci * This functions creates a new node of the specified type. 2464d5ac70f0Sopenharmony_ci * The new node has id \a id, which may be \c NULL. 2465d5ac70f0Sopenharmony_ci * 2466d5ac70f0Sopenharmony_ci * The value of the new node is zero (for numbers), or \c NULL (for 2467d5ac70f0Sopenharmony_ci * strings and pointers), or empty (for compound nodes). 2468d5ac70f0Sopenharmony_ci * 2469d5ac70f0Sopenharmony_ci * \par Errors: 2470d5ac70f0Sopenharmony_ci * <dl> 2471d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2472d5ac70f0Sopenharmony_ci * </dl> 2473d5ac70f0Sopenharmony_ci */ 2474d5ac70f0Sopenharmony_ciint snd_config_make(snd_config_t **config, const char *id, 2475d5ac70f0Sopenharmony_ci snd_config_type_t type) 2476d5ac70f0Sopenharmony_ci{ 2477d5ac70f0Sopenharmony_ci char *id1; 2478d5ac70f0Sopenharmony_ci assert(config); 2479d5ac70f0Sopenharmony_ci if (id) { 2480d5ac70f0Sopenharmony_ci id1 = strdup(id); 2481d5ac70f0Sopenharmony_ci if (!id1) 2482d5ac70f0Sopenharmony_ci return -ENOMEM; 2483d5ac70f0Sopenharmony_ci } else 2484d5ac70f0Sopenharmony_ci id1 = NULL; 2485d5ac70f0Sopenharmony_ci return _snd_config_make(config, &id1, type); 2486d5ac70f0Sopenharmony_ci} 2487d5ac70f0Sopenharmony_ci 2488d5ac70f0Sopenharmony_ci/** 2489d5ac70f0Sopenharmony_ci * \brief Creates an integer configuration node. 2490d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2491d5ac70f0Sopenharmony_ci * the address specified by \a config. 2492d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2493d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2494d5ac70f0Sopenharmony_ci * 2495d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and 2496d5ac70f0Sopenharmony_ci * with value \c 0. 2497d5ac70f0Sopenharmony_ci * 2498d5ac70f0Sopenharmony_ci * \par Errors: 2499d5ac70f0Sopenharmony_ci * <dl> 2500d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2501d5ac70f0Sopenharmony_ci * </dl> 2502d5ac70f0Sopenharmony_ci * 2503d5ac70f0Sopenharmony_ci * \par Conforming to: 2504d5ac70f0Sopenharmony_ci * LSB 3.2 2505d5ac70f0Sopenharmony_ci * 2506d5ac70f0Sopenharmony_ci * \sa snd_config_imake_integer 2507d5ac70f0Sopenharmony_ci */ 2508d5ac70f0Sopenharmony_ciint snd_config_make_integer(snd_config_t **config, const char *id) 2509d5ac70f0Sopenharmony_ci{ 2510d5ac70f0Sopenharmony_ci return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER); 2511d5ac70f0Sopenharmony_ci} 2512d5ac70f0Sopenharmony_ci 2513d5ac70f0Sopenharmony_ci/** 2514d5ac70f0Sopenharmony_ci * \brief Creates a 64-bit-integer configuration node. 2515d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2516d5ac70f0Sopenharmony_ci * the address specified by \a config. 2517d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2518d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2519d5ac70f0Sopenharmony_ci * 2520d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64 2521d5ac70f0Sopenharmony_ci * and with value \c 0. 2522d5ac70f0Sopenharmony_ci * 2523d5ac70f0Sopenharmony_ci * \par Errors: 2524d5ac70f0Sopenharmony_ci * <dl> 2525d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2526d5ac70f0Sopenharmony_ci * </dl> 2527d5ac70f0Sopenharmony_ci * 2528d5ac70f0Sopenharmony_ci * \par Conforming to: 2529d5ac70f0Sopenharmony_ci * LSB 3.2 2530d5ac70f0Sopenharmony_ci * 2531d5ac70f0Sopenharmony_ci * \sa snd_config_imake_integer64 2532d5ac70f0Sopenharmony_ci */ 2533d5ac70f0Sopenharmony_ciint snd_config_make_integer64(snd_config_t **config, const char *id) 2534d5ac70f0Sopenharmony_ci{ 2535d5ac70f0Sopenharmony_ci return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64); 2536d5ac70f0Sopenharmony_ci} 2537d5ac70f0Sopenharmony_ci 2538d5ac70f0Sopenharmony_ci/** 2539d5ac70f0Sopenharmony_ci * \brief Creates a real number configuration node. 2540d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2541d5ac70f0Sopenharmony_ci * the address specified by \a config. 2542d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2543d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2544d5ac70f0Sopenharmony_ci * 2545d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_REAL and 2546d5ac70f0Sopenharmony_ci * with value \c 0.0. 2547d5ac70f0Sopenharmony_ci * 2548d5ac70f0Sopenharmony_ci * \par Errors: 2549d5ac70f0Sopenharmony_ci * <dl> 2550d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2551d5ac70f0Sopenharmony_ci * </dl> 2552d5ac70f0Sopenharmony_ci * 2553d5ac70f0Sopenharmony_ci * \sa snd_config_imake_real 2554d5ac70f0Sopenharmony_ci */ 2555d5ac70f0Sopenharmony_ciint snd_config_make_real(snd_config_t **config, const char *id) 2556d5ac70f0Sopenharmony_ci{ 2557d5ac70f0Sopenharmony_ci return snd_config_make(config, id, SND_CONFIG_TYPE_REAL); 2558d5ac70f0Sopenharmony_ci} 2559d5ac70f0Sopenharmony_ci 2560d5ac70f0Sopenharmony_ci/** 2561d5ac70f0Sopenharmony_ci * \brief Creates a string configuration node. 2562d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2563d5ac70f0Sopenharmony_ci * the address specified by \a config. 2564d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2565d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2566d5ac70f0Sopenharmony_ci * 2567d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_STRING and 2568d5ac70f0Sopenharmony_ci * with value \c NULL. 2569d5ac70f0Sopenharmony_ci * 2570d5ac70f0Sopenharmony_ci * \par Errors: 2571d5ac70f0Sopenharmony_ci * <dl> 2572d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2573d5ac70f0Sopenharmony_ci * </dl> 2574d5ac70f0Sopenharmony_ci * 2575d5ac70f0Sopenharmony_ci * \par Conforming to: 2576d5ac70f0Sopenharmony_ci * LSB 3.2 2577d5ac70f0Sopenharmony_ci * 2578d5ac70f0Sopenharmony_ci * \sa snd_config_imake_string 2579d5ac70f0Sopenharmony_ci */ 2580d5ac70f0Sopenharmony_ciint snd_config_make_string(snd_config_t **config, const char *id) 2581d5ac70f0Sopenharmony_ci{ 2582d5ac70f0Sopenharmony_ci return snd_config_make(config, id, SND_CONFIG_TYPE_STRING); 2583d5ac70f0Sopenharmony_ci} 2584d5ac70f0Sopenharmony_ci 2585d5ac70f0Sopenharmony_ci/** 2586d5ac70f0Sopenharmony_ci * \brief Creates a pointer configuration node. 2587d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2588d5ac70f0Sopenharmony_ci * the address specified by \a config. 2589d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2590d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2591d5ac70f0Sopenharmony_ci * 2592d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and 2593d5ac70f0Sopenharmony_ci * with value \c NULL. 2594d5ac70f0Sopenharmony_ci * 2595d5ac70f0Sopenharmony_ci * \par Errors: 2596d5ac70f0Sopenharmony_ci * <dl> 2597d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2598d5ac70f0Sopenharmony_ci * </dl> 2599d5ac70f0Sopenharmony_ci * 2600d5ac70f0Sopenharmony_ci * \sa snd_config_imake_pointer 2601d5ac70f0Sopenharmony_ci */ 2602d5ac70f0Sopenharmony_ciint snd_config_make_pointer(snd_config_t **config, const char *id) 2603d5ac70f0Sopenharmony_ci{ 2604d5ac70f0Sopenharmony_ci return snd_config_make(config, id, SND_CONFIG_TYPE_POINTER); 2605d5ac70f0Sopenharmony_ci} 2606d5ac70f0Sopenharmony_ci 2607d5ac70f0Sopenharmony_ci/** 2608d5ac70f0Sopenharmony_ci * \brief Creates an empty compound configuration node. 2609d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2610d5ac70f0Sopenharmony_ci * the address specified by \a config. 2611d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2612d5ac70f0Sopenharmony_ci * \param[in] join Join flag. 2613d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2614d5ac70f0Sopenharmony_ci * 2615d5ac70f0Sopenharmony_ci * This function creates a new empty node of type 2616d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_COMPOUND. 2617d5ac70f0Sopenharmony_ci * 2618d5ac70f0Sopenharmony_ci * \a join determines how the compound node's id is printed when the 2619d5ac70f0Sopenharmony_ci * configuration is saved to a text file. For example, if the join flag 2620d5ac70f0Sopenharmony_ci * of compound node \c a is zero, the output will look as follows: 2621d5ac70f0Sopenharmony_ci * \code 2622d5ac70f0Sopenharmony_ci * a { 2623d5ac70f0Sopenharmony_ci * b "hello" 2624d5ac70f0Sopenharmony_ci * c 42 2625d5ac70f0Sopenharmony_ci * } 2626d5ac70f0Sopenharmony_ci * \endcode 2627d5ac70f0Sopenharmony_ci * If, however, the join flag of \c a is nonzero, its id will be joined 2628d5ac70f0Sopenharmony_ci * with its children's ids, like this: 2629d5ac70f0Sopenharmony_ci * \code 2630d5ac70f0Sopenharmony_ci * a.b "hello" 2631d5ac70f0Sopenharmony_ci * a.c 42 2632d5ac70f0Sopenharmony_ci * \endcode 2633d5ac70f0Sopenharmony_ci * An \e empty compound node with its join flag set would result in no 2634d5ac70f0Sopenharmony_ci * output, i.e., after saving and reloading the configuration file, that 2635d5ac70f0Sopenharmony_ci * compound node would be lost. 2636d5ac70f0Sopenharmony_ci * 2637d5ac70f0Sopenharmony_ci * \par Errors: 2638d5ac70f0Sopenharmony_ci * <dl> 2639d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2640d5ac70f0Sopenharmony_ci * </dl> 2641d5ac70f0Sopenharmony_ci * 2642d5ac70f0Sopenharmony_ci * \par Conforming to: 2643d5ac70f0Sopenharmony_ci * LSB 3.2 2644d5ac70f0Sopenharmony_ci */ 2645d5ac70f0Sopenharmony_ciint snd_config_make_compound(snd_config_t **config, const char *id, 2646d5ac70f0Sopenharmony_ci int join) 2647d5ac70f0Sopenharmony_ci{ 2648d5ac70f0Sopenharmony_ci int err; 2649d5ac70f0Sopenharmony_ci err = snd_config_make(config, id, SND_CONFIG_TYPE_COMPOUND); 2650d5ac70f0Sopenharmony_ci if (err < 0) 2651d5ac70f0Sopenharmony_ci return err; 2652d5ac70f0Sopenharmony_ci (*config)->u.compound.join = join; 2653d5ac70f0Sopenharmony_ci return 0; 2654d5ac70f0Sopenharmony_ci} 2655d5ac70f0Sopenharmony_ci 2656d5ac70f0Sopenharmony_ci/** 2657d5ac70f0Sopenharmony_ci * \brief Creates an empty compound configuration node in the path. 2658d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new or 2659d5ac70f0Sopenharmony_ci * existing compound node at the address specified 2660d5ac70f0Sopenharmony_ci * by \a config. 2661d5ac70f0Sopenharmony_ci * \param[in] root The id of the new node. 2662d5ac70f0Sopenharmony_ci * \param[in] key The id of the new node. 2663d5ac70f0Sopenharmony_ci * \param[in] join Join flag. 2664d5ac70f0Sopenharmony_ci * \param[in] override Override flag. 2665d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2666d5ac70f0Sopenharmony_ci * 2667d5ac70f0Sopenharmony_ci * This function creates a new empty node of type 2668d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_COMPOUND if the path does not exist. Otherwise, 2669d5ac70f0Sopenharmony_ci * the node from the current configuration tree is returned without 2670d5ac70f0Sopenharmony_ci * any modification. The \a join argument is ignored in this case. 2671d5ac70f0Sopenharmony_ci * 2672d5ac70f0Sopenharmony_ci * \a join determines how the compound node's id is printed when the 2673d5ac70f0Sopenharmony_ci * configuration is saved to a text file. For example, if the join flag 2674d5ac70f0Sopenharmony_ci * of compound node \c a is zero, the output will look as follows: 2675d5ac70f0Sopenharmony_ci * \code 2676d5ac70f0Sopenharmony_ci * a { 2677d5ac70f0Sopenharmony_ci * b "hello" 2678d5ac70f0Sopenharmony_ci * c 42 2679d5ac70f0Sopenharmony_ci * } 2680d5ac70f0Sopenharmony_ci * \endcode 2681d5ac70f0Sopenharmony_ci * If, however, the join flag of \c a is nonzero, its id will be joined 2682d5ac70f0Sopenharmony_ci * with its children's ids, like this: 2683d5ac70f0Sopenharmony_ci * \code 2684d5ac70f0Sopenharmony_ci * a.b "hello" 2685d5ac70f0Sopenharmony_ci * a.c 42 2686d5ac70f0Sopenharmony_ci * \endcode 2687d5ac70f0Sopenharmony_ci * An \e empty compound node with its join flag set would result in no 2688d5ac70f0Sopenharmony_ci * output, i.e., after saving and reloading the configuration file, that 2689d5ac70f0Sopenharmony_ci * compound node would be lost. 2690d5ac70f0Sopenharmony_ci * 2691d5ac70f0Sopenharmony_ci * \par Errors: 2692d5ac70f0Sopenharmony_ci * <dl> 2693d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2694d5ac70f0Sopenharmony_ci * <dt>-EACCESS<dd>Path exists, but it's not a compound (!override) 2695d5ac70f0Sopenharmony_ci * </dl> 2696d5ac70f0Sopenharmony_ci */ 2697d5ac70f0Sopenharmony_ciint snd_config_make_path(snd_config_t **config, snd_config_t *root, 2698d5ac70f0Sopenharmony_ci const char *key, int join, int override) 2699d5ac70f0Sopenharmony_ci{ 2700d5ac70f0Sopenharmony_ci snd_config_t *n; 2701d5ac70f0Sopenharmony_ci const char *p; 2702d5ac70f0Sopenharmony_ci int err; 2703d5ac70f0Sopenharmony_ci 2704d5ac70f0Sopenharmony_ci while (1) { 2705d5ac70f0Sopenharmony_ci p = strchr(key, '.'); 2706d5ac70f0Sopenharmony_ci if (p) { 2707d5ac70f0Sopenharmony_ci err = _snd_config_search(root, key, p - key, &n); 2708d5ac70f0Sopenharmony_ci if (err < 0) { 2709d5ac70f0Sopenharmony_ci size_t l = p - key; 2710d5ac70f0Sopenharmony_ci char *s = malloc(l + 1); 2711d5ac70f0Sopenharmony_ci if (s == NULL) 2712d5ac70f0Sopenharmony_ci return -ENOMEM; 2713d5ac70f0Sopenharmony_ci strncpy(s, key, l); 2714d5ac70f0Sopenharmony_ci s[l] = '\0'; 2715d5ac70f0Sopenharmony_ci err = snd_config_make_compound(&n, s, join); 2716d5ac70f0Sopenharmony_ci free(s); 2717d5ac70f0Sopenharmony_ci if (err < 0) 2718d5ac70f0Sopenharmony_ci return err; 2719d5ac70f0Sopenharmony_ci err = snd_config_add(root, n); 2720d5ac70f0Sopenharmony_ci if (err < 0) 2721d5ac70f0Sopenharmony_ci return err; 2722d5ac70f0Sopenharmony_ci } 2723d5ac70f0Sopenharmony_ci root = n; 2724d5ac70f0Sopenharmony_ci key = p + 1; 2725d5ac70f0Sopenharmony_ci } else { 2726d5ac70f0Sopenharmony_ci err = _snd_config_search(root, key, -1, config); 2727d5ac70f0Sopenharmony_ci if (err == 0) { 2728d5ac70f0Sopenharmony_ci if ((*config)->type != SND_CONFIG_TYPE_COMPOUND) { 2729d5ac70f0Sopenharmony_ci if (override) { 2730d5ac70f0Sopenharmony_ci err = snd_config_delete(*config); 2731d5ac70f0Sopenharmony_ci if (err < 0) 2732d5ac70f0Sopenharmony_ci return err; 2733d5ac70f0Sopenharmony_ci goto __make; 2734d5ac70f0Sopenharmony_ci } else { 2735d5ac70f0Sopenharmony_ci return -EACCES; 2736d5ac70f0Sopenharmony_ci } 2737d5ac70f0Sopenharmony_ci } 2738d5ac70f0Sopenharmony_ci return 0; 2739d5ac70f0Sopenharmony_ci } 2740d5ac70f0Sopenharmony_ci__make: 2741d5ac70f0Sopenharmony_ci err = snd_config_make_compound(&n, key, join); 2742d5ac70f0Sopenharmony_ci if (err < 0) 2743d5ac70f0Sopenharmony_ci return err; 2744d5ac70f0Sopenharmony_ci err = snd_config_add(root, n); 2745d5ac70f0Sopenharmony_ci if (err < 0) 2746d5ac70f0Sopenharmony_ci return err; 2747d5ac70f0Sopenharmony_ci *config = n; 2748d5ac70f0Sopenharmony_ci return 0; 2749d5ac70f0Sopenharmony_ci } 2750d5ac70f0Sopenharmony_ci } 2751d5ac70f0Sopenharmony_ci} 2752d5ac70f0Sopenharmony_ci 2753d5ac70f0Sopenharmony_ci/** 2754d5ac70f0Sopenharmony_ci * \brief Creates an integer configuration node with the given initial value. 2755d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2756d5ac70f0Sopenharmony_ci * the address specified by \a config. 2757d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2758d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node. 2759d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2760d5ac70f0Sopenharmony_ci * 2761d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and 2762d5ac70f0Sopenharmony_ci * with value \a value. 2763d5ac70f0Sopenharmony_ci * 2764d5ac70f0Sopenharmony_ci * \par Errors: 2765d5ac70f0Sopenharmony_ci * <dl> 2766d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2767d5ac70f0Sopenharmony_ci * </dl> 2768d5ac70f0Sopenharmony_ci * 2769d5ac70f0Sopenharmony_ci * \par Conforming to: 2770d5ac70f0Sopenharmony_ci * LSB 3.2 2771d5ac70f0Sopenharmony_ci */ 2772d5ac70f0Sopenharmony_ciint snd_config_imake_integer(snd_config_t **config, const char *id, const long value) 2773d5ac70f0Sopenharmony_ci{ 2774d5ac70f0Sopenharmony_ci int err; 2775d5ac70f0Sopenharmony_ci 2776d5ac70f0Sopenharmony_ci err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER); 2777d5ac70f0Sopenharmony_ci if (err < 0) 2778d5ac70f0Sopenharmony_ci return err; 2779d5ac70f0Sopenharmony_ci (*config)->u.integer = value; 2780d5ac70f0Sopenharmony_ci return 0; 2781d5ac70f0Sopenharmony_ci} 2782d5ac70f0Sopenharmony_ci 2783d5ac70f0Sopenharmony_ci/** 2784d5ac70f0Sopenharmony_ci * \brief Creates a 64-bit-integer configuration node with the given initial value. 2785d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2786d5ac70f0Sopenharmony_ci * the address specified by \a config. 2787d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2788d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node. 2789d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2790d5ac70f0Sopenharmony_ci * 2791d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64 2792d5ac70f0Sopenharmony_ci * and with value \a value. 2793d5ac70f0Sopenharmony_ci * 2794d5ac70f0Sopenharmony_ci * \par Errors: 2795d5ac70f0Sopenharmony_ci * <dl> 2796d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2797d5ac70f0Sopenharmony_ci * </dl> 2798d5ac70f0Sopenharmony_ci * 2799d5ac70f0Sopenharmony_ci * \par Conforming to: 2800d5ac70f0Sopenharmony_ci * LSB 3.2 2801d5ac70f0Sopenharmony_ci */ 2802d5ac70f0Sopenharmony_ciint snd_config_imake_integer64(snd_config_t **config, const char *id, const long long value) 2803d5ac70f0Sopenharmony_ci{ 2804d5ac70f0Sopenharmony_ci int err; 2805d5ac70f0Sopenharmony_ci 2806d5ac70f0Sopenharmony_ci err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64); 2807d5ac70f0Sopenharmony_ci if (err < 0) 2808d5ac70f0Sopenharmony_ci return err; 2809d5ac70f0Sopenharmony_ci (*config)->u.integer64 = value; 2810d5ac70f0Sopenharmony_ci return 0; 2811d5ac70f0Sopenharmony_ci} 2812d5ac70f0Sopenharmony_ci 2813d5ac70f0Sopenharmony_ci/** 2814d5ac70f0Sopenharmony_ci * \brief Creates a real number configuration node with the given initial value. 2815d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2816d5ac70f0Sopenharmony_ci * the address specified by \a config. 2817d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2818d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node. 2819d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2820d5ac70f0Sopenharmony_ci * 2821d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_REAL and 2822d5ac70f0Sopenharmony_ci * with value \a value. 2823d5ac70f0Sopenharmony_ci * 2824d5ac70f0Sopenharmony_ci * \par Errors: 2825d5ac70f0Sopenharmony_ci * <dl> 2826d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2827d5ac70f0Sopenharmony_ci * </dl> 2828d5ac70f0Sopenharmony_ci */ 2829d5ac70f0Sopenharmony_ciint snd_config_imake_real(snd_config_t **config, const char *id, const double value) 2830d5ac70f0Sopenharmony_ci{ 2831d5ac70f0Sopenharmony_ci int err; 2832d5ac70f0Sopenharmony_ci 2833d5ac70f0Sopenharmony_ci err = snd_config_make(config, id, SND_CONFIG_TYPE_REAL); 2834d5ac70f0Sopenharmony_ci if (err < 0) 2835d5ac70f0Sopenharmony_ci return err; 2836d5ac70f0Sopenharmony_ci (*config)->u.real = value; 2837d5ac70f0Sopenharmony_ci return 0; 2838d5ac70f0Sopenharmony_ci} 2839d5ac70f0Sopenharmony_ci 2840d5ac70f0Sopenharmony_ci/** 2841d5ac70f0Sopenharmony_ci * \brief Creates a string configuration node with the given initial value. 2842d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2843d5ac70f0Sopenharmony_ci * the address specified by \a config. 2844d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2845d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node. May be \c NULL. 2846d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2847d5ac70f0Sopenharmony_ci * 2848d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_STRING and 2849d5ac70f0Sopenharmony_ci * with a copy of the string \c value. 2850d5ac70f0Sopenharmony_ci * 2851d5ac70f0Sopenharmony_ci * \par Errors: 2852d5ac70f0Sopenharmony_ci * <dl> 2853d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2854d5ac70f0Sopenharmony_ci * </dl> 2855d5ac70f0Sopenharmony_ci * 2856d5ac70f0Sopenharmony_ci * \par Conforming to: 2857d5ac70f0Sopenharmony_ci * LSB 3.2 2858d5ac70f0Sopenharmony_ci */ 2859d5ac70f0Sopenharmony_ciint snd_config_imake_string(snd_config_t **config, const char *id, const char *value) 2860d5ac70f0Sopenharmony_ci{ 2861d5ac70f0Sopenharmony_ci int err; 2862d5ac70f0Sopenharmony_ci snd_config_t *tmp; 2863d5ac70f0Sopenharmony_ci 2864d5ac70f0Sopenharmony_ci err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING); 2865d5ac70f0Sopenharmony_ci if (err < 0) 2866d5ac70f0Sopenharmony_ci return err; 2867d5ac70f0Sopenharmony_ci if (value) { 2868d5ac70f0Sopenharmony_ci tmp->u.string = strdup(value); 2869d5ac70f0Sopenharmony_ci if (!tmp->u.string) { 2870d5ac70f0Sopenharmony_ci snd_config_delete(tmp); 2871d5ac70f0Sopenharmony_ci return -ENOMEM; 2872d5ac70f0Sopenharmony_ci } 2873d5ac70f0Sopenharmony_ci } else { 2874d5ac70f0Sopenharmony_ci tmp->u.string = NULL; 2875d5ac70f0Sopenharmony_ci } 2876d5ac70f0Sopenharmony_ci *config = tmp; 2877d5ac70f0Sopenharmony_ci return 0; 2878d5ac70f0Sopenharmony_ci} 2879d5ac70f0Sopenharmony_ci 2880d5ac70f0Sopenharmony_ci/** 2881d5ac70f0Sopenharmony_ci * \brief Creates a string configuration node with the given initial value. 2882d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2883d5ac70f0Sopenharmony_ci * the address specified by \a config. 2884d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2885d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node. May be \c NULL. 2886d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2887d5ac70f0Sopenharmony_ci * 2888d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_STRING. The node 2889d5ac70f0Sopenharmony_ci * contains with a copy of the string \c value, replacing any character other 2890d5ac70f0Sopenharmony_ci * than alphanumeric, space, or '-' with the character '_'. 2891d5ac70f0Sopenharmony_ci * 2892d5ac70f0Sopenharmony_ci * \par Errors: 2893d5ac70f0Sopenharmony_ci * <dl> 2894d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2895d5ac70f0Sopenharmony_ci * </dl> 2896d5ac70f0Sopenharmony_ci * 2897d5ac70f0Sopenharmony_ci * \par Conforming to: 2898d5ac70f0Sopenharmony_ci * LSB 3.2 2899d5ac70f0Sopenharmony_ci */ 2900d5ac70f0Sopenharmony_ciint snd_config_imake_safe_string(snd_config_t **config, const char *id, const char *value) 2901d5ac70f0Sopenharmony_ci{ 2902d5ac70f0Sopenharmony_ci int err; 2903d5ac70f0Sopenharmony_ci snd_config_t *tmp; 2904d5ac70f0Sopenharmony_ci char *c; 2905d5ac70f0Sopenharmony_ci 2906d5ac70f0Sopenharmony_ci err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING); 2907d5ac70f0Sopenharmony_ci if (err < 0) 2908d5ac70f0Sopenharmony_ci return err; 2909d5ac70f0Sopenharmony_ci if (value) { 2910d5ac70f0Sopenharmony_ci tmp->u.string = strdup(value); 2911d5ac70f0Sopenharmony_ci if (!tmp->u.string) { 2912d5ac70f0Sopenharmony_ci snd_config_delete(tmp); 2913d5ac70f0Sopenharmony_ci return -ENOMEM; 2914d5ac70f0Sopenharmony_ci } 2915d5ac70f0Sopenharmony_ci 2916d5ac70f0Sopenharmony_ci for (c = tmp->u.string; *c; c++) { 2917d5ac70f0Sopenharmony_ci if (*c == ' ' || *c == '-' || *c == '_' || 2918d5ac70f0Sopenharmony_ci (*c >= '0' && *c <= '9') || 2919d5ac70f0Sopenharmony_ci (*c >= 'a' && *c <= 'z') || 2920d5ac70f0Sopenharmony_ci (*c >= 'A' && *c <= 'Z')) 2921d5ac70f0Sopenharmony_ci continue; 2922d5ac70f0Sopenharmony_ci *c = '_'; 2923d5ac70f0Sopenharmony_ci } 2924d5ac70f0Sopenharmony_ci } else { 2925d5ac70f0Sopenharmony_ci tmp->u.string = NULL; 2926d5ac70f0Sopenharmony_ci } 2927d5ac70f0Sopenharmony_ci *config = tmp; 2928d5ac70f0Sopenharmony_ci return 0; 2929d5ac70f0Sopenharmony_ci} 2930d5ac70f0Sopenharmony_ci 2931d5ac70f0Sopenharmony_ci 2932d5ac70f0Sopenharmony_ci/** 2933d5ac70f0Sopenharmony_ci * \brief Creates a pointer configuration node with the given initial value. 2934d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at 2935d5ac70f0Sopenharmony_ci * the address specified by \a config. 2936d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node. 2937d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node. 2938d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2939d5ac70f0Sopenharmony_ci * 2940d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and 2941d5ac70f0Sopenharmony_ci * with value \c value. 2942d5ac70f0Sopenharmony_ci * 2943d5ac70f0Sopenharmony_ci * \par Errors: 2944d5ac70f0Sopenharmony_ci * <dl> 2945d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 2946d5ac70f0Sopenharmony_ci * </dl> 2947d5ac70f0Sopenharmony_ci */ 2948d5ac70f0Sopenharmony_ciint snd_config_imake_pointer(snd_config_t **config, const char *id, const void *value) 2949d5ac70f0Sopenharmony_ci{ 2950d5ac70f0Sopenharmony_ci int err; 2951d5ac70f0Sopenharmony_ci 2952d5ac70f0Sopenharmony_ci err = snd_config_make(config, id, SND_CONFIG_TYPE_POINTER); 2953d5ac70f0Sopenharmony_ci if (err < 0) 2954d5ac70f0Sopenharmony_ci return err; 2955d5ac70f0Sopenharmony_ci (*config)->u.ptr = value; 2956d5ac70f0Sopenharmony_ci return 0; 2957d5ac70f0Sopenharmony_ci} 2958d5ac70f0Sopenharmony_ci 2959d5ac70f0Sopenharmony_ci/** 2960d5ac70f0Sopenharmony_ci * \brief Changes the value of an integer configuration node. 2961d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 2962d5ac70f0Sopenharmony_ci * \param value The new value for the node. 2963d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2964d5ac70f0Sopenharmony_ci * 2965d5ac70f0Sopenharmony_ci * \par Errors: 2966d5ac70f0Sopenharmony_ci * <dl> 2967d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not an integer node. 2968d5ac70f0Sopenharmony_ci * </dl> 2969d5ac70f0Sopenharmony_ci * 2970d5ac70f0Sopenharmony_ci * \par Conforming to: 2971d5ac70f0Sopenharmony_ci * LSB 3.2 2972d5ac70f0Sopenharmony_ci */ 2973d5ac70f0Sopenharmony_ciint snd_config_set_integer(snd_config_t *config, long value) 2974d5ac70f0Sopenharmony_ci{ 2975d5ac70f0Sopenharmony_ci assert(config); 2976d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_INTEGER) 2977d5ac70f0Sopenharmony_ci return -EINVAL; 2978d5ac70f0Sopenharmony_ci config->u.integer = value; 2979d5ac70f0Sopenharmony_ci return 0; 2980d5ac70f0Sopenharmony_ci} 2981d5ac70f0Sopenharmony_ci 2982d5ac70f0Sopenharmony_ci/** 2983d5ac70f0Sopenharmony_ci * \brief Changes the value of a 64-bit-integer configuration node. 2984d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 2985d5ac70f0Sopenharmony_ci * \param value The new value for the node. 2986d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 2987d5ac70f0Sopenharmony_ci * 2988d5ac70f0Sopenharmony_ci * \par Errors: 2989d5ac70f0Sopenharmony_ci * <dl> 2990d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a 64-bit-integer node. 2991d5ac70f0Sopenharmony_ci * </dl> 2992d5ac70f0Sopenharmony_ci * 2993d5ac70f0Sopenharmony_ci * \par Conforming to: 2994d5ac70f0Sopenharmony_ci * LSB 3.2 2995d5ac70f0Sopenharmony_ci */ 2996d5ac70f0Sopenharmony_ciint snd_config_set_integer64(snd_config_t *config, long long value) 2997d5ac70f0Sopenharmony_ci{ 2998d5ac70f0Sopenharmony_ci assert(config); 2999d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_INTEGER64) 3000d5ac70f0Sopenharmony_ci return -EINVAL; 3001d5ac70f0Sopenharmony_ci config->u.integer64 = value; 3002d5ac70f0Sopenharmony_ci return 0; 3003d5ac70f0Sopenharmony_ci} 3004d5ac70f0Sopenharmony_ci 3005d5ac70f0Sopenharmony_ci/** 3006d5ac70f0Sopenharmony_ci * \brief Changes the value of a real-number configuration node. 3007d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 3008d5ac70f0Sopenharmony_ci * \param value The new value for the node. 3009d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3010d5ac70f0Sopenharmony_ci * 3011d5ac70f0Sopenharmony_ci * \par Errors: 3012d5ac70f0Sopenharmony_ci * <dl> 3013d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a real-number node. 3014d5ac70f0Sopenharmony_ci * </dl> 3015d5ac70f0Sopenharmony_ci */ 3016d5ac70f0Sopenharmony_ciint snd_config_set_real(snd_config_t *config, double value) 3017d5ac70f0Sopenharmony_ci{ 3018d5ac70f0Sopenharmony_ci assert(config); 3019d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_REAL) 3020d5ac70f0Sopenharmony_ci return -EINVAL; 3021d5ac70f0Sopenharmony_ci config->u.real = value; 3022d5ac70f0Sopenharmony_ci return 0; 3023d5ac70f0Sopenharmony_ci} 3024d5ac70f0Sopenharmony_ci 3025d5ac70f0Sopenharmony_ci/** 3026d5ac70f0Sopenharmony_ci * \brief Changes the value of a string configuration node. 3027d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 3028d5ac70f0Sopenharmony_ci * \param value The new value for the node. May be \c NULL. 3029d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3030d5ac70f0Sopenharmony_ci * 3031d5ac70f0Sopenharmony_ci * This function deletes the old string in the node and stores a copy of 3032d5ac70f0Sopenharmony_ci * \a value string in the node. 3033d5ac70f0Sopenharmony_ci * 3034d5ac70f0Sopenharmony_ci * \par Errors: 3035d5ac70f0Sopenharmony_ci * <dl> 3036d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a string node. 3037d5ac70f0Sopenharmony_ci * </dl> 3038d5ac70f0Sopenharmony_ci * 3039d5ac70f0Sopenharmony_ci * \par Conforming to: 3040d5ac70f0Sopenharmony_ci * LSB 3.2 3041d5ac70f0Sopenharmony_ci */ 3042d5ac70f0Sopenharmony_ciint snd_config_set_string(snd_config_t *config, const char *value) 3043d5ac70f0Sopenharmony_ci{ 3044d5ac70f0Sopenharmony_ci char *new_string; 3045d5ac70f0Sopenharmony_ci assert(config); 3046d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_STRING) 3047d5ac70f0Sopenharmony_ci return -EINVAL; 3048d5ac70f0Sopenharmony_ci if (value) { 3049d5ac70f0Sopenharmony_ci new_string = strdup(value); 3050d5ac70f0Sopenharmony_ci if (!new_string) 3051d5ac70f0Sopenharmony_ci return -ENOMEM; 3052d5ac70f0Sopenharmony_ci } else { 3053d5ac70f0Sopenharmony_ci new_string = NULL; 3054d5ac70f0Sopenharmony_ci } 3055d5ac70f0Sopenharmony_ci free(config->u.string); 3056d5ac70f0Sopenharmony_ci config->u.string = new_string; 3057d5ac70f0Sopenharmony_ci return 0; 3058d5ac70f0Sopenharmony_ci} 3059d5ac70f0Sopenharmony_ci 3060d5ac70f0Sopenharmony_ci/** 3061d5ac70f0Sopenharmony_ci * \brief Changes the value of a pointer configuration node. 3062d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 3063d5ac70f0Sopenharmony_ci * \param value The new value for the node. May be \c NULL. 3064d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3065d5ac70f0Sopenharmony_ci * 3066d5ac70f0Sopenharmony_ci * This function does not free the old pointer in the node. 3067d5ac70f0Sopenharmony_ci * 3068d5ac70f0Sopenharmony_ci * \par Errors: 3069d5ac70f0Sopenharmony_ci * <dl> 3070d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a pointer node. 3071d5ac70f0Sopenharmony_ci * </dl> 3072d5ac70f0Sopenharmony_ci */ 3073d5ac70f0Sopenharmony_ciint snd_config_set_pointer(snd_config_t *config, const void *value) 3074d5ac70f0Sopenharmony_ci{ 3075d5ac70f0Sopenharmony_ci assert(config); 3076d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_POINTER) 3077d5ac70f0Sopenharmony_ci return -EINVAL; 3078d5ac70f0Sopenharmony_ci config->u.ptr = value; 3079d5ac70f0Sopenharmony_ci return 0; 3080d5ac70f0Sopenharmony_ci} 3081d5ac70f0Sopenharmony_ci 3082d5ac70f0Sopenharmony_ci/** 3083d5ac70f0Sopenharmony_ci * \brief Changes the value of a configuration node. 3084d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 3085d5ac70f0Sopenharmony_ci * \param ascii The new value for the node, as an ASCII string. 3086d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3087d5ac70f0Sopenharmony_ci * 3088d5ac70f0Sopenharmony_ci * This function changes the node's value to a new value that is parsed 3089d5ac70f0Sopenharmony_ci * from the string \a ascii. \a ascii must not be \c NULL, not even for 3090d5ac70f0Sopenharmony_ci * a string node. 3091d5ac70f0Sopenharmony_ci * 3092d5ac70f0Sopenharmony_ci * The node's type does not change, i.e., the string must contain a 3093d5ac70f0Sopenharmony_ci * valid value with the same type as the node's type. For a string 3094d5ac70f0Sopenharmony_ci * node, the node's new value is a copy of \a ascii. 3095d5ac70f0Sopenharmony_ci * 3096d5ac70f0Sopenharmony_ci * \par Errors: 3097d5ac70f0Sopenharmony_ci * <dl> 3098d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a number or string node. 3099d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>The value in \a ascii cannot be parsed. 3100d5ac70f0Sopenharmony_ci * <dt>-ERANGE<dd>The value in \a ascii is too big for the node's type. 3101d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 3102d5ac70f0Sopenharmony_ci * </dl> 3103d5ac70f0Sopenharmony_ci * 3104d5ac70f0Sopenharmony_ci * \par Conforming to: 3105d5ac70f0Sopenharmony_ci * LSB 3.2 3106d5ac70f0Sopenharmony_ci */ 3107d5ac70f0Sopenharmony_ciint snd_config_set_ascii(snd_config_t *config, const char *ascii) 3108d5ac70f0Sopenharmony_ci{ 3109d5ac70f0Sopenharmony_ci assert(config && ascii); 3110d5ac70f0Sopenharmony_ci switch (config->type) { 3111d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER: 3112d5ac70f0Sopenharmony_ci { 3113d5ac70f0Sopenharmony_ci long i; 3114d5ac70f0Sopenharmony_ci int err = safe_strtol(ascii, &i); 3115d5ac70f0Sopenharmony_ci if (err < 0) 3116d5ac70f0Sopenharmony_ci return err; 3117d5ac70f0Sopenharmony_ci config->u.integer = i; 3118d5ac70f0Sopenharmony_ci } 3119d5ac70f0Sopenharmony_ci break; 3120d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER64: 3121d5ac70f0Sopenharmony_ci { 3122d5ac70f0Sopenharmony_ci long long i; 3123d5ac70f0Sopenharmony_ci int err = safe_strtoll(ascii, &i); 3124d5ac70f0Sopenharmony_ci if (err < 0) 3125d5ac70f0Sopenharmony_ci return err; 3126d5ac70f0Sopenharmony_ci config->u.integer64 = i; 3127d5ac70f0Sopenharmony_ci } 3128d5ac70f0Sopenharmony_ci break; 3129d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_REAL: 3130d5ac70f0Sopenharmony_ci { 3131d5ac70f0Sopenharmony_ci double d; 3132d5ac70f0Sopenharmony_ci int err = safe_strtod(ascii, &d); 3133d5ac70f0Sopenharmony_ci if (err < 0) 3134d5ac70f0Sopenharmony_ci return err; 3135d5ac70f0Sopenharmony_ci config->u.real = d; 3136d5ac70f0Sopenharmony_ci break; 3137d5ac70f0Sopenharmony_ci } 3138d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_STRING: 3139d5ac70f0Sopenharmony_ci { 3140d5ac70f0Sopenharmony_ci char *ptr = strdup(ascii); 3141d5ac70f0Sopenharmony_ci if (ptr == NULL) 3142d5ac70f0Sopenharmony_ci return -ENOMEM; 3143d5ac70f0Sopenharmony_ci free(config->u.string); 3144d5ac70f0Sopenharmony_ci config->u.string = ptr; 3145d5ac70f0Sopenharmony_ci } 3146d5ac70f0Sopenharmony_ci break; 3147d5ac70f0Sopenharmony_ci default: 3148d5ac70f0Sopenharmony_ci return -EINVAL; 3149d5ac70f0Sopenharmony_ci } 3150d5ac70f0Sopenharmony_ci return 0; 3151d5ac70f0Sopenharmony_ci} 3152d5ac70f0Sopenharmony_ci 3153d5ac70f0Sopenharmony_ci/** 3154d5ac70f0Sopenharmony_ci * \brief Returns the value of an integer configuration node. 3155d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 3156d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value. 3157d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3158d5ac70f0Sopenharmony_ci * 3159d5ac70f0Sopenharmony_ci * \par Errors: 3160d5ac70f0Sopenharmony_ci * <dl> 3161d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not an integer node. 3162d5ac70f0Sopenharmony_ci * </dl> 3163d5ac70f0Sopenharmony_ci * 3164d5ac70f0Sopenharmony_ci * \par Conforming to: 3165d5ac70f0Sopenharmony_ci * LSB 3.2 3166d5ac70f0Sopenharmony_ci */ 3167d5ac70f0Sopenharmony_ciint snd_config_get_integer(const snd_config_t *config, long *ptr) 3168d5ac70f0Sopenharmony_ci{ 3169d5ac70f0Sopenharmony_ci assert(config && ptr); 3170d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_INTEGER) 3171d5ac70f0Sopenharmony_ci return -EINVAL; 3172d5ac70f0Sopenharmony_ci *ptr = config->u.integer; 3173d5ac70f0Sopenharmony_ci return 0; 3174d5ac70f0Sopenharmony_ci} 3175d5ac70f0Sopenharmony_ci 3176d5ac70f0Sopenharmony_ci/** 3177d5ac70f0Sopenharmony_ci * \brief Returns the value of a 64-bit-integer configuration node. 3178d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 3179d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value. 3180d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3181d5ac70f0Sopenharmony_ci * 3182d5ac70f0Sopenharmony_ci * \par Errors: 3183d5ac70f0Sopenharmony_ci * <dl> 3184d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a 64-bit-integer node. 3185d5ac70f0Sopenharmony_ci * </dl> 3186d5ac70f0Sopenharmony_ci * 3187d5ac70f0Sopenharmony_ci * \par Conforming to: 3188d5ac70f0Sopenharmony_ci * LSB 3.2 3189d5ac70f0Sopenharmony_ci */ 3190d5ac70f0Sopenharmony_ciint snd_config_get_integer64(const snd_config_t *config, long long *ptr) 3191d5ac70f0Sopenharmony_ci{ 3192d5ac70f0Sopenharmony_ci assert(config && ptr); 3193d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_INTEGER64) 3194d5ac70f0Sopenharmony_ci return -EINVAL; 3195d5ac70f0Sopenharmony_ci *ptr = config->u.integer64; 3196d5ac70f0Sopenharmony_ci return 0; 3197d5ac70f0Sopenharmony_ci} 3198d5ac70f0Sopenharmony_ci 3199d5ac70f0Sopenharmony_ci/** 3200d5ac70f0Sopenharmony_ci * \brief Returns the value of a real-number configuration node. 3201d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 3202d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value. 3203d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3204d5ac70f0Sopenharmony_ci * 3205d5ac70f0Sopenharmony_ci * \par Errors: 3206d5ac70f0Sopenharmony_ci * <dl> 3207d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a real-number node. 3208d5ac70f0Sopenharmony_ci * </dl> 3209d5ac70f0Sopenharmony_ci */ 3210d5ac70f0Sopenharmony_ciint snd_config_get_real(const snd_config_t *config, double *ptr) 3211d5ac70f0Sopenharmony_ci{ 3212d5ac70f0Sopenharmony_ci assert(config && ptr); 3213d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_REAL) 3214d5ac70f0Sopenharmony_ci return -EINVAL; 3215d5ac70f0Sopenharmony_ci *ptr = config->u.real; 3216d5ac70f0Sopenharmony_ci return 0; 3217d5ac70f0Sopenharmony_ci} 3218d5ac70f0Sopenharmony_ci 3219d5ac70f0Sopenharmony_ci/** 3220d5ac70f0Sopenharmony_ci * \brief Returns the value of a real or integer configuration node. 3221d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 3222d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value. 3223d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3224d5ac70f0Sopenharmony_ci * 3225d5ac70f0Sopenharmony_ci * If the node's type is integer or integer64, the value is converted 3226d5ac70f0Sopenharmony_ci * to the \c double type on the fly. 3227d5ac70f0Sopenharmony_ci * 3228d5ac70f0Sopenharmony_ci * \par Errors: 3229d5ac70f0Sopenharmony_ci * <dl> 3230d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a number node. 3231d5ac70f0Sopenharmony_ci * </dl> 3232d5ac70f0Sopenharmony_ci */ 3233d5ac70f0Sopenharmony_ciint snd_config_get_ireal(const snd_config_t *config, double *ptr) 3234d5ac70f0Sopenharmony_ci{ 3235d5ac70f0Sopenharmony_ci assert(config && ptr); 3236d5ac70f0Sopenharmony_ci if (config->type == SND_CONFIG_TYPE_REAL) 3237d5ac70f0Sopenharmony_ci *ptr = config->u.real; 3238d5ac70f0Sopenharmony_ci else if (config->type == SND_CONFIG_TYPE_INTEGER) 3239d5ac70f0Sopenharmony_ci *ptr = config->u.integer; 3240d5ac70f0Sopenharmony_ci else if (config->type == SND_CONFIG_TYPE_INTEGER64) 3241d5ac70f0Sopenharmony_ci *ptr = config->u.integer64; 3242d5ac70f0Sopenharmony_ci else 3243d5ac70f0Sopenharmony_ci return -EINVAL; 3244d5ac70f0Sopenharmony_ci return 0; 3245d5ac70f0Sopenharmony_ci} 3246d5ac70f0Sopenharmony_ci 3247d5ac70f0Sopenharmony_ci/** 3248d5ac70f0Sopenharmony_ci * \brief Returns the value of a string configuration node. 3249d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 3250d5ac70f0Sopenharmony_ci * \param[out] ptr The function puts the node's value at the address 3251d5ac70f0Sopenharmony_ci * specified by \a ptr. 3252d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3253d5ac70f0Sopenharmony_ci * 3254d5ac70f0Sopenharmony_ci * The returned string is owned by the configuration node; the 3255d5ac70f0Sopenharmony_ci * application must not modify or delete it, and the string becomes 3256d5ac70f0Sopenharmony_ci * invalid when the node's value changes or when the node is freed. 3257d5ac70f0Sopenharmony_ci * 3258d5ac70f0Sopenharmony_ci * The string may be \c NULL. 3259d5ac70f0Sopenharmony_ci * 3260d5ac70f0Sopenharmony_ci * \par Errors: 3261d5ac70f0Sopenharmony_ci * <dl> 3262d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a string node. 3263d5ac70f0Sopenharmony_ci * </dl> 3264d5ac70f0Sopenharmony_ci * 3265d5ac70f0Sopenharmony_ci * \par Conforming to: 3266d5ac70f0Sopenharmony_ci * LSB 3.2 3267d5ac70f0Sopenharmony_ci */ 3268d5ac70f0Sopenharmony_ciint snd_config_get_string(const snd_config_t *config, const char **ptr) 3269d5ac70f0Sopenharmony_ci{ 3270d5ac70f0Sopenharmony_ci assert(config && ptr); 3271d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_STRING) 3272d5ac70f0Sopenharmony_ci return -EINVAL; 3273d5ac70f0Sopenharmony_ci *ptr = config->u.string; 3274d5ac70f0Sopenharmony_ci return 0; 3275d5ac70f0Sopenharmony_ci} 3276d5ac70f0Sopenharmony_ci 3277d5ac70f0Sopenharmony_ci/** 3278d5ac70f0Sopenharmony_ci * \brief Returns the value of a pointer configuration node. 3279d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 3280d5ac70f0Sopenharmony_ci * \param[out] ptr The function puts the node's value at the address 3281d5ac70f0Sopenharmony_ci * specified by \a ptr. 3282d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3283d5ac70f0Sopenharmony_ci * 3284d5ac70f0Sopenharmony_ci * \par Errors: 3285d5ac70f0Sopenharmony_ci * <dl> 3286d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a string node. 3287d5ac70f0Sopenharmony_ci * </dl> 3288d5ac70f0Sopenharmony_ci */ 3289d5ac70f0Sopenharmony_ciint snd_config_get_pointer(const snd_config_t *config, const void **ptr) 3290d5ac70f0Sopenharmony_ci{ 3291d5ac70f0Sopenharmony_ci assert(config && ptr); 3292d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_POINTER) 3293d5ac70f0Sopenharmony_ci return -EINVAL; 3294d5ac70f0Sopenharmony_ci *ptr = config->u.ptr; 3295d5ac70f0Sopenharmony_ci return 0; 3296d5ac70f0Sopenharmony_ci} 3297d5ac70f0Sopenharmony_ci 3298d5ac70f0Sopenharmony_ci/** 3299d5ac70f0Sopenharmony_ci * \brief Returns the value of a configuration node as a string. 3300d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 3301d5ac70f0Sopenharmony_ci * \param[out] ascii The function puts the pointer to the returned 3302d5ac70f0Sopenharmony_ci * string at the address specified by \a ascii. 3303d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3304d5ac70f0Sopenharmony_ci * 3305d5ac70f0Sopenharmony_ci * This function dynamically allocates the returned string. The 3306d5ac70f0Sopenharmony_ci * application is responsible for deleting it with \c free() when it is 3307d5ac70f0Sopenharmony_ci * no longer used. 3308d5ac70f0Sopenharmony_ci * 3309d5ac70f0Sopenharmony_ci * For a string node with \c NULL value, the returned string is \c NULL. 3310d5ac70f0Sopenharmony_ci * 3311d5ac70f0Sopenharmony_ci * Supported node types are #SND_CONFIG_TYPE_INTEGER, 3312d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_INTEGER64, #SND_CONFIG_TYPE_REAL, and 3313d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_STRING. 3314d5ac70f0Sopenharmony_ci * 3315d5ac70f0Sopenharmony_ci * \par Errors: 3316d5ac70f0Sopenharmony_ci * <dl> 3317d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a (64-bit) integer or real number or 3318d5ac70f0Sopenharmony_ci * string node. 3319d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 3320d5ac70f0Sopenharmony_ci * </dl> 3321d5ac70f0Sopenharmony_ci * 3322d5ac70f0Sopenharmony_ci * \par Conforming to: 3323d5ac70f0Sopenharmony_ci * LSB 3.2 3324d5ac70f0Sopenharmony_ci */ 3325d5ac70f0Sopenharmony_ciint snd_config_get_ascii(const snd_config_t *config, char **ascii) 3326d5ac70f0Sopenharmony_ci{ 3327d5ac70f0Sopenharmony_ci assert(config && ascii); 3328d5ac70f0Sopenharmony_ci switch (config->type) { 3329d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER: 3330d5ac70f0Sopenharmony_ci { 3331d5ac70f0Sopenharmony_ci char res[12]; 3332d5ac70f0Sopenharmony_ci int err; 3333d5ac70f0Sopenharmony_ci err = snprintf(res, sizeof(res), "%li", config->u.integer); 3334d5ac70f0Sopenharmony_ci if (err < 0 || err == sizeof(res)) { 3335d5ac70f0Sopenharmony_ci assert(0); 3336d5ac70f0Sopenharmony_ci return -ENOMEM; 3337d5ac70f0Sopenharmony_ci } 3338d5ac70f0Sopenharmony_ci *ascii = strdup(res); 3339d5ac70f0Sopenharmony_ci } 3340d5ac70f0Sopenharmony_ci break; 3341d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER64: 3342d5ac70f0Sopenharmony_ci { 3343d5ac70f0Sopenharmony_ci char res[32]; 3344d5ac70f0Sopenharmony_ci int err; 3345d5ac70f0Sopenharmony_ci err = snprintf(res, sizeof(res), "%lli", config->u.integer64); 3346d5ac70f0Sopenharmony_ci if (err < 0 || err == sizeof(res)) { 3347d5ac70f0Sopenharmony_ci assert(0); 3348d5ac70f0Sopenharmony_ci return -ENOMEM; 3349d5ac70f0Sopenharmony_ci } 3350d5ac70f0Sopenharmony_ci *ascii = strdup(res); 3351d5ac70f0Sopenharmony_ci } 3352d5ac70f0Sopenharmony_ci break; 3353d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_REAL: 3354d5ac70f0Sopenharmony_ci { 3355d5ac70f0Sopenharmony_ci char res[32]; 3356d5ac70f0Sopenharmony_ci int err; 3357d5ac70f0Sopenharmony_ci err = snprintf(res, sizeof(res), "%-16g", config->u.real); 3358d5ac70f0Sopenharmony_ci if (err < 0 || err == sizeof(res)) { 3359d5ac70f0Sopenharmony_ci assert(0); 3360d5ac70f0Sopenharmony_ci return -ENOMEM; 3361d5ac70f0Sopenharmony_ci } 3362d5ac70f0Sopenharmony_ci if (res[0]) { /* trim the string */ 3363d5ac70f0Sopenharmony_ci char *ptr; 3364d5ac70f0Sopenharmony_ci ptr = res + strlen(res) - 1; 3365d5ac70f0Sopenharmony_ci while (ptr != res && *ptr == ' ') 3366d5ac70f0Sopenharmony_ci ptr--; 3367d5ac70f0Sopenharmony_ci if (*ptr != ' ') 3368d5ac70f0Sopenharmony_ci ptr++; 3369d5ac70f0Sopenharmony_ci *ptr = '\0'; 3370d5ac70f0Sopenharmony_ci } 3371d5ac70f0Sopenharmony_ci *ascii = strdup(res); 3372d5ac70f0Sopenharmony_ci } 3373d5ac70f0Sopenharmony_ci break; 3374d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_STRING: 3375d5ac70f0Sopenharmony_ci if (config->u.string) 3376d5ac70f0Sopenharmony_ci *ascii = strdup(config->u.string); 3377d5ac70f0Sopenharmony_ci else { 3378d5ac70f0Sopenharmony_ci *ascii = NULL; 3379d5ac70f0Sopenharmony_ci return 0; 3380d5ac70f0Sopenharmony_ci } 3381d5ac70f0Sopenharmony_ci break; 3382d5ac70f0Sopenharmony_ci default: 3383d5ac70f0Sopenharmony_ci return -EINVAL; 3384d5ac70f0Sopenharmony_ci } 3385d5ac70f0Sopenharmony_ci if (*ascii == NULL) 3386d5ac70f0Sopenharmony_ci return -ENOMEM; 3387d5ac70f0Sopenharmony_ci return 0; 3388d5ac70f0Sopenharmony_ci} 3389d5ac70f0Sopenharmony_ci 3390d5ac70f0Sopenharmony_ci/** 3391d5ac70f0Sopenharmony_ci * \brief Compares the id of a configuration node to a given string. 3392d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node. 3393d5ac70f0Sopenharmony_ci * \param id ASCII id. 3394d5ac70f0Sopenharmony_ci * \return The same value as the result of the \c strcmp function, i.e., 3395d5ac70f0Sopenharmony_ci * less than zero if \a config's id is lexicographically less 3396d5ac70f0Sopenharmony_ci * than \a id, zero if \a config's id is equal to id, greater 3397d5ac70f0Sopenharmony_ci * than zero otherwise. 3398d5ac70f0Sopenharmony_ci */ 3399d5ac70f0Sopenharmony_ciint snd_config_test_id(const snd_config_t *config, const char *id) 3400d5ac70f0Sopenharmony_ci{ 3401d5ac70f0Sopenharmony_ci assert(config && id); 3402d5ac70f0Sopenharmony_ci if (config->id) 3403d5ac70f0Sopenharmony_ci return strcmp(config->id, id); 3404d5ac70f0Sopenharmony_ci else 3405d5ac70f0Sopenharmony_ci return -1; 3406d5ac70f0Sopenharmony_ci} 3407d5ac70f0Sopenharmony_ci 3408d5ac70f0Sopenharmony_ci/** 3409d5ac70f0Sopenharmony_ci * \brief Dumps the contents of a configuration node or tree. 3410d5ac70f0Sopenharmony_ci * \param config Handle to the (root) configuration node. 3411d5ac70f0Sopenharmony_ci * \param out Output handle. 3412d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3413d5ac70f0Sopenharmony_ci * 3414d5ac70f0Sopenharmony_ci * This function writes a textual representation of \a config's value to 3415d5ac70f0Sopenharmony_ci * the output \a out. 3416d5ac70f0Sopenharmony_ci * 3417d5ac70f0Sopenharmony_ci * \par Errors: 3418d5ac70f0Sopenharmony_ci * <dl> 3419d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>A node in the tree has a type that cannot be printed, 3420d5ac70f0Sopenharmony_ci * i.e., #SND_CONFIG_TYPE_POINTER. 3421d5ac70f0Sopenharmony_ci * </dl> 3422d5ac70f0Sopenharmony_ci * 3423d5ac70f0Sopenharmony_ci * \par Conforming to: 3424d5ac70f0Sopenharmony_ci * LSB 3.2 3425d5ac70f0Sopenharmony_ci */ 3426d5ac70f0Sopenharmony_ciint snd_config_save(snd_config_t *config, snd_output_t *out) 3427d5ac70f0Sopenharmony_ci{ 3428d5ac70f0Sopenharmony_ci assert(config && out); 3429d5ac70f0Sopenharmony_ci if (config->type == SND_CONFIG_TYPE_COMPOUND) { 3430d5ac70f0Sopenharmony_ci int array = snd_config_is_array(config); 3431d5ac70f0Sopenharmony_ci return _snd_config_save_children(config, out, 0, 0, array); 3432d5ac70f0Sopenharmony_ci } else { 3433d5ac70f0Sopenharmony_ci return _snd_config_save_node_value(config, out, 0); 3434d5ac70f0Sopenharmony_ci } 3435d5ac70f0Sopenharmony_ci} 3436d5ac70f0Sopenharmony_ci 3437d5ac70f0Sopenharmony_ci/* 3438d5ac70f0Sopenharmony_ci * *** search macros *** 3439d5ac70f0Sopenharmony_ci */ 3440d5ac70f0Sopenharmony_ci 3441d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 3442d5ac70f0Sopenharmony_ci 3443d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCH(config, key, result, extra_code) \ 3444d5ac70f0Sopenharmony_ci{ \ 3445d5ac70f0Sopenharmony_ci snd_config_t *n; \ 3446d5ac70f0Sopenharmony_ci int err; \ 3447d5ac70f0Sopenharmony_ci const char *p; \ 3448d5ac70f0Sopenharmony_ci assert(config && key); \ 3449d5ac70f0Sopenharmony_ci while (1) { \ 3450d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_COMPOUND) \ 3451d5ac70f0Sopenharmony_ci return -ENOENT; \ 3452d5ac70f0Sopenharmony_ci { extra_code ; } \ 3453d5ac70f0Sopenharmony_ci p = strchr(key, '.'); \ 3454d5ac70f0Sopenharmony_ci if (p) { \ 3455d5ac70f0Sopenharmony_ci err = _snd_config_search(config, key, p - key, &n); \ 3456d5ac70f0Sopenharmony_ci if (err < 0) \ 3457d5ac70f0Sopenharmony_ci return err; \ 3458d5ac70f0Sopenharmony_ci config = n; \ 3459d5ac70f0Sopenharmony_ci key = p + 1; \ 3460d5ac70f0Sopenharmony_ci } else \ 3461d5ac70f0Sopenharmony_ci return _snd_config_search(config, key, -1, result); \ 3462d5ac70f0Sopenharmony_ci } \ 3463d5ac70f0Sopenharmony_ci} 3464d5ac70f0Sopenharmony_ci 3465d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCHA(root, config, key, result, fcn, extra_code) \ 3466d5ac70f0Sopenharmony_ci{ \ 3467d5ac70f0Sopenharmony_ci snd_config_t *n; \ 3468d5ac70f0Sopenharmony_ci int err; \ 3469d5ac70f0Sopenharmony_ci const char *p; \ 3470d5ac70f0Sopenharmony_ci assert(config && key); \ 3471d5ac70f0Sopenharmony_ci while (1) { \ 3472d5ac70f0Sopenharmony_ci if (config->type != SND_CONFIG_TYPE_COMPOUND) { \ 3473d5ac70f0Sopenharmony_ci if (snd_config_get_string(config, &p) < 0) \ 3474d5ac70f0Sopenharmony_ci return -ENOENT; \ 3475d5ac70f0Sopenharmony_ci err = fcn(root, root, p, &config); \ 3476d5ac70f0Sopenharmony_ci if (err < 0) \ 3477d5ac70f0Sopenharmony_ci return err; \ 3478d5ac70f0Sopenharmony_ci } \ 3479d5ac70f0Sopenharmony_ci { extra_code ; } \ 3480d5ac70f0Sopenharmony_ci p = strchr(key, '.'); \ 3481d5ac70f0Sopenharmony_ci if (p) { \ 3482d5ac70f0Sopenharmony_ci err = _snd_config_search(config, key, p - key, &n); \ 3483d5ac70f0Sopenharmony_ci if (err < 0) \ 3484d5ac70f0Sopenharmony_ci return err; \ 3485d5ac70f0Sopenharmony_ci config = n; \ 3486d5ac70f0Sopenharmony_ci key = p + 1; \ 3487d5ac70f0Sopenharmony_ci } else \ 3488d5ac70f0Sopenharmony_ci return _snd_config_search(config, key, -1, result); \ 3489d5ac70f0Sopenharmony_ci } \ 3490d5ac70f0Sopenharmony_ci} 3491d5ac70f0Sopenharmony_ci 3492d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCHV(config, result, fcn) \ 3493d5ac70f0Sopenharmony_ci{ \ 3494d5ac70f0Sopenharmony_ci snd_config_t *n; \ 3495d5ac70f0Sopenharmony_ci va_list arg; \ 3496d5ac70f0Sopenharmony_ci assert(config); \ 3497d5ac70f0Sopenharmony_ci va_start(arg, result); \ 3498d5ac70f0Sopenharmony_ci while (1) { \ 3499d5ac70f0Sopenharmony_ci const char *k = va_arg(arg, const char *); \ 3500d5ac70f0Sopenharmony_ci int err; \ 3501d5ac70f0Sopenharmony_ci if (!k) \ 3502d5ac70f0Sopenharmony_ci break; \ 3503d5ac70f0Sopenharmony_ci err = fcn(config, k, &n); \ 3504d5ac70f0Sopenharmony_ci if (err < 0) { \ 3505d5ac70f0Sopenharmony_ci va_end(arg); \ 3506d5ac70f0Sopenharmony_ci return err; \ 3507d5ac70f0Sopenharmony_ci } \ 3508d5ac70f0Sopenharmony_ci config = n; \ 3509d5ac70f0Sopenharmony_ci } \ 3510d5ac70f0Sopenharmony_ci va_end(arg); \ 3511d5ac70f0Sopenharmony_ci if (result) \ 3512d5ac70f0Sopenharmony_ci *result = n; \ 3513d5ac70f0Sopenharmony_ci return 0; \ 3514d5ac70f0Sopenharmony_ci} 3515d5ac70f0Sopenharmony_ci 3516d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCHVA(root, config, result, fcn) \ 3517d5ac70f0Sopenharmony_ci{ \ 3518d5ac70f0Sopenharmony_ci snd_config_t *n; \ 3519d5ac70f0Sopenharmony_ci va_list arg; \ 3520d5ac70f0Sopenharmony_ci assert(config); \ 3521d5ac70f0Sopenharmony_ci va_start(arg, result); \ 3522d5ac70f0Sopenharmony_ci while (1) { \ 3523d5ac70f0Sopenharmony_ci const char *k = va_arg(arg, const char *); \ 3524d5ac70f0Sopenharmony_ci int err; \ 3525d5ac70f0Sopenharmony_ci if (!k) \ 3526d5ac70f0Sopenharmony_ci break; \ 3527d5ac70f0Sopenharmony_ci err = fcn(root, config, k, &n); \ 3528d5ac70f0Sopenharmony_ci if (err < 0) { \ 3529d5ac70f0Sopenharmony_ci va_end(arg); \ 3530d5ac70f0Sopenharmony_ci return err; \ 3531d5ac70f0Sopenharmony_ci } \ 3532d5ac70f0Sopenharmony_ci config = n; \ 3533d5ac70f0Sopenharmony_ci } \ 3534d5ac70f0Sopenharmony_ci va_end(arg); \ 3535d5ac70f0Sopenharmony_ci if (result) \ 3536d5ac70f0Sopenharmony_ci *result = n; \ 3537d5ac70f0Sopenharmony_ci return 0; \ 3538d5ac70f0Sopenharmony_ci} 3539d5ac70f0Sopenharmony_ci 3540d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCH_ALIAS(config, base, key, result, fcn1, fcn2) \ 3541d5ac70f0Sopenharmony_ci{ \ 3542d5ac70f0Sopenharmony_ci snd_config_t *res = NULL; \ 3543d5ac70f0Sopenharmony_ci char *old_key; \ 3544d5ac70f0Sopenharmony_ci int err, first = 1, maxloop = 1000; \ 3545d5ac70f0Sopenharmony_ci assert(config && key); \ 3546d5ac70f0Sopenharmony_ci while (1) { \ 3547d5ac70f0Sopenharmony_ci old_key = strdup(key); \ 3548d5ac70f0Sopenharmony_ci if (old_key == NULL) { \ 3549d5ac70f0Sopenharmony_ci err = -ENOMEM; \ 3550d5ac70f0Sopenharmony_ci res = NULL; \ 3551d5ac70f0Sopenharmony_ci break; \ 3552d5ac70f0Sopenharmony_ci } \ 3553d5ac70f0Sopenharmony_ci err = first && base ? -EIO : fcn1(config, config, key, &res); \ 3554d5ac70f0Sopenharmony_ci if (err < 0) { \ 3555d5ac70f0Sopenharmony_ci if (!base) \ 3556d5ac70f0Sopenharmony_ci break; \ 3557d5ac70f0Sopenharmony_ci err = fcn2(config, config, &res, base, key, NULL); \ 3558d5ac70f0Sopenharmony_ci if (err < 0) \ 3559d5ac70f0Sopenharmony_ci break; \ 3560d5ac70f0Sopenharmony_ci } \ 3561d5ac70f0Sopenharmony_ci if (snd_config_get_string(res, &key) < 0) \ 3562d5ac70f0Sopenharmony_ci break; \ 3563d5ac70f0Sopenharmony_ci assert(key); \ 3564d5ac70f0Sopenharmony_ci if (!first && (strcmp(key, old_key) == 0 || maxloop <= 0)) { \ 3565d5ac70f0Sopenharmony_ci if (maxloop == 0) \ 3566d5ac70f0Sopenharmony_ci SNDERR("maximum loop count reached (circular configuration?)"); \ 3567d5ac70f0Sopenharmony_ci else \ 3568d5ac70f0Sopenharmony_ci SNDERR("key %s refers to itself", key); \ 3569d5ac70f0Sopenharmony_ci err = -EINVAL; \ 3570d5ac70f0Sopenharmony_ci res = NULL; \ 3571d5ac70f0Sopenharmony_ci break; \ 3572d5ac70f0Sopenharmony_ci } \ 3573d5ac70f0Sopenharmony_ci free(old_key); \ 3574d5ac70f0Sopenharmony_ci first = 0; \ 3575d5ac70f0Sopenharmony_ci maxloop--; \ 3576d5ac70f0Sopenharmony_ci } \ 3577d5ac70f0Sopenharmony_ci free(old_key); \ 3578d5ac70f0Sopenharmony_ci if (!res) \ 3579d5ac70f0Sopenharmony_ci return err; \ 3580d5ac70f0Sopenharmony_ci if (result) \ 3581d5ac70f0Sopenharmony_ci *result = res; \ 3582d5ac70f0Sopenharmony_ci return 0; \ 3583d5ac70f0Sopenharmony_ci} 3584d5ac70f0Sopenharmony_ci 3585d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 3586d5ac70f0Sopenharmony_ci 3587d5ac70f0Sopenharmony_ci/** 3588d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree. 3589d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search. 3590d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node ids, separated with dots. 3591d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the 3592d5ac70f0Sopenharmony_ci * handle to the node found at the address specified 3593d5ac70f0Sopenharmony_ci * by \a result. 3594d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3595d5ac70f0Sopenharmony_ci * 3596d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config that is 3597d5ac70f0Sopenharmony_ci * identified by \a key, which contains either the id of a direct child 3598d5ac70f0Sopenharmony_ci * node of \a config, or a series of ids, separated with dots, where 3599d5ac70f0Sopenharmony_ci * each id specifies a node that is contained in the previous compound 3600d5ac70f0Sopenharmony_ci * node. 3601d5ac70f0Sopenharmony_ci * 3602d5ac70f0Sopenharmony_ci * In the following example, the comment after each node shows the 3603d5ac70f0Sopenharmony_ci * search key to find that node, assuming that \a config is a handle to 3604d5ac70f0Sopenharmony_ci * the compound node with id \c config: 3605d5ac70f0Sopenharmony_ci * \code 3606d5ac70f0Sopenharmony_ci * config { 3607d5ac70f0Sopenharmony_ci * a 42 # "a" 3608d5ac70f0Sopenharmony_ci * b { # "b" 3609d5ac70f0Sopenharmony_ci * c "cee" # "b.c" 3610d5ac70f0Sopenharmony_ci * d { # "b.d" 3611d5ac70f0Sopenharmony_ci * e 2.71828 # "b.d.e" 3612d5ac70f0Sopenharmony_ci * } 3613d5ac70f0Sopenharmony_ci * } 3614d5ac70f0Sopenharmony_ci * } 3615d5ac70f0Sopenharmony_ci * \endcode 3616d5ac70f0Sopenharmony_ci * 3617d5ac70f0Sopenharmony_ci * \par Errors: 3618d5ac70f0Sopenharmony_ci * <dl> 3619d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key does not exist. 3620d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3621d5ac70f0Sopenharmony_ci * not a compound node. 3622d5ac70f0Sopenharmony_ci * </dl> 3623d5ac70f0Sopenharmony_ci * 3624d5ac70f0Sopenharmony_ci * \par Conforming to: 3625d5ac70f0Sopenharmony_ci * LSB 3.2 3626d5ac70f0Sopenharmony_ci */ 3627d5ac70f0Sopenharmony_ciint snd_config_search(snd_config_t *config, const char *key, snd_config_t **result) 3628d5ac70f0Sopenharmony_ci{ 3629d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCH(config, key, result, ); 3630d5ac70f0Sopenharmony_ci} 3631d5ac70f0Sopenharmony_ci 3632d5ac70f0Sopenharmony_ci/** 3633d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases. 3634d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing 3635d5ac70f0Sopenharmony_ci * alias definitions. 3636d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search. 3637d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node keys, separated with dots. 3638d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the 3639d5ac70f0Sopenharmony_ci * handle to the node found at the address specified 3640d5ac70f0Sopenharmony_ci * by \a result. 3641d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3642d5ac70f0Sopenharmony_ci * 3643d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config like 3644d5ac70f0Sopenharmony_ci * #snd_config_search. However, any compound node can also be 3645d5ac70f0Sopenharmony_ci * identified by an alias, which is a string node whose value is taken 3646d5ac70f0Sopenharmony_ci * as the id of a compound node below \a root. 3647d5ac70f0Sopenharmony_ci * 3648d5ac70f0Sopenharmony_ci * \a root must be a compound node. 3649d5ac70f0Sopenharmony_ci * \a root and \a config may be the same node. 3650d5ac70f0Sopenharmony_ci * 3651d5ac70f0Sopenharmony_ci * For example, with the following configuration, the call 3652d5ac70f0Sopenharmony_ci * \code 3653d5ac70f0Sopenharmony_ci * snd_config_searcha(root, config, "a.b.c.d", &result); 3654d5ac70f0Sopenharmony_ci * \endcode 3655d5ac70f0Sopenharmony_ci * would return the node with id \c d: 3656d5ac70f0Sopenharmony_ci * \code 3657d5ac70f0Sopenharmony_ci * config { 3658d5ac70f0Sopenharmony_ci * a { 3659d5ac70f0Sopenharmony_ci * b bb 3660d5ac70f0Sopenharmony_ci * } 3661d5ac70f0Sopenharmony_ci * } 3662d5ac70f0Sopenharmony_ci * root { 3663d5ac70f0Sopenharmony_ci * bb { 3664d5ac70f0Sopenharmony_ci * c cc 3665d5ac70f0Sopenharmony_ci * } 3666d5ac70f0Sopenharmony_ci * cc ccc 3667d5ac70f0Sopenharmony_ci * ccc { 3668d5ac70f0Sopenharmony_ci * d { 3669d5ac70f0Sopenharmony_ci * x "icks" 3670d5ac70f0Sopenharmony_ci * } 3671d5ac70f0Sopenharmony_ci * } 3672d5ac70f0Sopenharmony_ci * } 3673d5ac70f0Sopenharmony_ci * \endcode 3674d5ac70f0Sopenharmony_ci * 3675d5ac70f0Sopenharmony_ci * \par Errors: 3676d5ac70f0Sopenharmony_ci * <dl> 3677d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist. 3678d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3679d5ac70f0Sopenharmony_ci * not a compound or string node. 3680d5ac70f0Sopenharmony_ci * </dl> 3681d5ac70f0Sopenharmony_ci */ 3682d5ac70f0Sopenharmony_ciint snd_config_searcha(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result) 3683d5ac70f0Sopenharmony_ci{ 3684d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCHA(root, config, key, result, snd_config_searcha, ); 3685d5ac70f0Sopenharmony_ci} 3686d5ac70f0Sopenharmony_ci 3687d5ac70f0Sopenharmony_ci/** 3688d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree. 3689d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search. 3690d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the 3691d5ac70f0Sopenharmony_ci * handle to the node found at the address specified 3692d5ac70f0Sopenharmony_ci * by \a result. 3693d5ac70f0Sopenharmony_ci * \param[in] ... One or more concatenated dot-separated search keys, 3694d5ac70f0Sopenharmony_ci * terminated with \c NULL. 3695d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3696d5ac70f0Sopenharmony_ci * 3697d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config like 3698d5ac70f0Sopenharmony_ci * #snd_config_search, but the search key is the concatenation of all 3699d5ac70f0Sopenharmony_ci * passed search key strings. For example, the call 3700d5ac70f0Sopenharmony_ci * \code 3701d5ac70f0Sopenharmony_ci * snd_config_searchv(cfg, &res, "a", "b.c", "d.e", NULL); 3702d5ac70f0Sopenharmony_ci * \endcode 3703d5ac70f0Sopenharmony_ci * is equivalent to the call 3704d5ac70f0Sopenharmony_ci * \code 3705d5ac70f0Sopenharmony_ci * snd_config_search(cfg, "a.b.c.d.e", &res); 3706d5ac70f0Sopenharmony_ci * \endcode 3707d5ac70f0Sopenharmony_ci * 3708d5ac70f0Sopenharmony_ci * \par Errors: 3709d5ac70f0Sopenharmony_ci * <dl> 3710d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in a search key does not exist. 3711d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3712d5ac70f0Sopenharmony_ci * not a compound node. 3713d5ac70f0Sopenharmony_ci * </dl> 3714d5ac70f0Sopenharmony_ci * 3715d5ac70f0Sopenharmony_ci * \par Conforming to: 3716d5ac70f0Sopenharmony_ci * LSB 3.2 3717d5ac70f0Sopenharmony_ci */ 3718d5ac70f0Sopenharmony_ciint snd_config_searchv(snd_config_t *config, snd_config_t **result, ...) 3719d5ac70f0Sopenharmony_ci{ 3720d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCHV(config, result, snd_config_search); 3721d5ac70f0Sopenharmony_ci} 3722d5ac70f0Sopenharmony_ci 3723d5ac70f0Sopenharmony_ci/** 3724d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases. 3725d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing 3726d5ac70f0Sopenharmony_ci * alias definitions. 3727d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search. 3728d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the 3729d5ac70f0Sopenharmony_ci * handle to the node found at the address specified 3730d5ac70f0Sopenharmony_ci * by \a result. 3731d5ac70f0Sopenharmony_ci * \param[in] ... One or more concatenated dot separated search keys, 3732d5ac70f0Sopenharmony_ci * terminated with \c NULL. 3733d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3734d5ac70f0Sopenharmony_ci * 3735d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config, allowing 3736d5ac70f0Sopenharmony_ci * aliases, like #snd_config_searcha, but the search key is the 3737d5ac70f0Sopenharmony_ci * concatenation of all passed seach key strings, like with 3738d5ac70f0Sopenharmony_ci * #snd_config_searchv. 3739d5ac70f0Sopenharmony_ci * 3740d5ac70f0Sopenharmony_ci * \par Errors: 3741d5ac70f0Sopenharmony_ci * <dl> 3742d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in a search key does not exist. 3743d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3744d5ac70f0Sopenharmony_ci * not a compound or string node. 3745d5ac70f0Sopenharmony_ci * </dl> 3746d5ac70f0Sopenharmony_ci */ 3747d5ac70f0Sopenharmony_ciint snd_config_searchva(snd_config_t *root, snd_config_t *config, snd_config_t **result, ...) 3748d5ac70f0Sopenharmony_ci{ 3749d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha); 3750d5ac70f0Sopenharmony_ci} 3751d5ac70f0Sopenharmony_ci 3752d5ac70f0Sopenharmony_ci/** 3753d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases. 3754d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search. 3755d5ac70f0Sopenharmony_ci * \param[in] base Search key base, or \c NULL. 3756d5ac70f0Sopenharmony_ci * \param[in] key Search key suffix. 3757d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the 3758d5ac70f0Sopenharmony_ci * handle to the node found at the address specified 3759d5ac70f0Sopenharmony_ci * by \a result. 3760d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3761d5ac70f0Sopenharmony_ci * 3762d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config, allowing 3763d5ac70f0Sopenharmony_ci * aliases, like #snd_config_searcha. However, alias definitions are 3764d5ac70f0Sopenharmony_ci * searched below \a config (there is no separate \a root parameter), 3765d5ac70f0Sopenharmony_ci * and \a base specifies a seach key that identifies a compound node 3766d5ac70f0Sopenharmony_ci * that is used to search for an alias definitions that is not found 3767d5ac70f0Sopenharmony_ci * directly below \a config and that does not contain a period. In 3768d5ac70f0Sopenharmony_ci * other words, when \c "id" is not found in \a config, this function 3769d5ac70f0Sopenharmony_ci * also tries \c "base.id". 3770d5ac70f0Sopenharmony_ci * 3771d5ac70f0Sopenharmony_ci * \par Errors: 3772d5ac70f0Sopenharmony_ci * <dl> 3773d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist. 3774d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3775d5ac70f0Sopenharmony_ci * not a compound or string node. 3776d5ac70f0Sopenharmony_ci * </dl> 3777d5ac70f0Sopenharmony_ci */ 3778d5ac70f0Sopenharmony_ciint snd_config_search_alias(snd_config_t *config, 3779d5ac70f0Sopenharmony_ci const char *base, const char *key, 3780d5ac70f0Sopenharmony_ci snd_config_t **result) 3781d5ac70f0Sopenharmony_ci{ 3782d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCH_ALIAS(config, base, key, result, 3783d5ac70f0Sopenharmony_ci snd_config_searcha, snd_config_searchva); 3784d5ac70f0Sopenharmony_ci} 3785d5ac70f0Sopenharmony_ci 3786d5ac70f0Sopenharmony_cistatic int snd_config_hooks(snd_config_t *config, snd_config_t *private_data); 3787d5ac70f0Sopenharmony_ci 3788d5ac70f0Sopenharmony_ci/** 3789d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree and expands hooks. 3790d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the root of the configuration 3791d5ac70f0Sopenharmony_ci * (sub)tree to search. 3792d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node keys, separated with dots. 3793d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at 3794d5ac70f0Sopenharmony_ci * the address specified by \a result. 3795d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3796d5ac70f0Sopenharmony_ci * 3797d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config like 3798d5ac70f0Sopenharmony_ci * #snd_config_search, but any compound nodes to be searched that 3799d5ac70f0Sopenharmony_ci * contain hooks are modified by the respective hook functions. 3800d5ac70f0Sopenharmony_ci * 3801d5ac70f0Sopenharmony_ci * \par Errors: 3802d5ac70f0Sopenharmony_ci * <dl> 3803d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key does not exist. 3804d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3805d5ac70f0Sopenharmony_ci * not a compound node. 3806d5ac70f0Sopenharmony_ci * </dl> 3807d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook 3808d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions. 3809d5ac70f0Sopenharmony_ci */ 3810d5ac70f0Sopenharmony_ciint snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t **result) 3811d5ac70f0Sopenharmony_ci{ 3812d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCH(config, key, result, \ 3813d5ac70f0Sopenharmony_ci err = snd_config_hooks(config, NULL); \ 3814d5ac70f0Sopenharmony_ci if (err < 0) \ 3815d5ac70f0Sopenharmony_ci return err; \ 3816d5ac70f0Sopenharmony_ci ); 3817d5ac70f0Sopenharmony_ci} 3818d5ac70f0Sopenharmony_ci 3819d5ac70f0Sopenharmony_ci/** 3820d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases and hooks. 3821d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing 3822d5ac70f0Sopenharmony_ci * alias definitions. 3823d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the root of the configuration 3824d5ac70f0Sopenharmony_ci * (sub)tree to search. 3825d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node keys, separated with dots. 3826d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at 3827d5ac70f0Sopenharmony_ci * the address specified by \a result. 3828d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3829d5ac70f0Sopenharmony_ci * 3830d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config, allowing 3831d5ac70f0Sopenharmony_ci * aliases, like #snd_config_searcha, and expanding hooks, like 3832d5ac70f0Sopenharmony_ci * #snd_config_search_hooks. 3833d5ac70f0Sopenharmony_ci * 3834d5ac70f0Sopenharmony_ci * \par Errors: 3835d5ac70f0Sopenharmony_ci * <dl> 3836d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist. 3837d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3838d5ac70f0Sopenharmony_ci * not a compound node. 3839d5ac70f0Sopenharmony_ci * </dl> 3840d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook 3841d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions. 3842d5ac70f0Sopenharmony_ci */ 3843d5ac70f0Sopenharmony_ciint snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result) 3844d5ac70f0Sopenharmony_ci{ 3845d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCHA(root, config, key, result, 3846d5ac70f0Sopenharmony_ci snd_config_searcha_hooks, 3847d5ac70f0Sopenharmony_ci err = snd_config_hooks(config, NULL); \ 3848d5ac70f0Sopenharmony_ci if (err < 0) \ 3849d5ac70f0Sopenharmony_ci return err; \ 3850d5ac70f0Sopenharmony_ci ); 3851d5ac70f0Sopenharmony_ci} 3852d5ac70f0Sopenharmony_ci 3853d5ac70f0Sopenharmony_ci/** 3854d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases and hooks. 3855d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing 3856d5ac70f0Sopenharmony_ci * alias definitions. 3857d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the root of the configuration 3858d5ac70f0Sopenharmony_ci * (sub)tree to search. 3859d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at 3860d5ac70f0Sopenharmony_ci * the address specified by \a result. 3861d5ac70f0Sopenharmony_ci * \param[in] ... One or more concatenated dot separated search keys, 3862d5ac70f0Sopenharmony_ci * terminated with \c NULL. 3863d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3864d5ac70f0Sopenharmony_ci * 3865d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config, allowing 3866d5ac70f0Sopenharmony_ci * aliases and expanding hooks like #snd_config_searcha_hooks, but the 3867d5ac70f0Sopenharmony_ci * search key is the concatenation of all passed seach key strings, like 3868d5ac70f0Sopenharmony_ci * with #snd_config_searchv. 3869d5ac70f0Sopenharmony_ci * 3870d5ac70f0Sopenharmony_ci * \par Errors: 3871d5ac70f0Sopenharmony_ci * <dl> 3872d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist. 3873d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3874d5ac70f0Sopenharmony_ci * not a compound node. 3875d5ac70f0Sopenharmony_ci * </dl> 3876d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook 3877d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions. 3878d5ac70f0Sopenharmony_ci */ 3879d5ac70f0Sopenharmony_ciint snd_config_searchva_hooks(snd_config_t *root, snd_config_t *config, 3880d5ac70f0Sopenharmony_ci snd_config_t **result, ...) 3881d5ac70f0Sopenharmony_ci{ 3882d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha_hooks); 3883d5ac70f0Sopenharmony_ci} 3884d5ac70f0Sopenharmony_ci 3885d5ac70f0Sopenharmony_ci/** 3886d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, using an alias and expanding hooks. 3887d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree 3888d5ac70f0Sopenharmony_ci * to search. 3889d5ac70f0Sopenharmony_ci * \param[in] base Search key base, or \c NULL. 3890d5ac70f0Sopenharmony_ci * \param[in] key Search key suffix. 3891d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at 3892d5ac70f0Sopenharmony_ci * the address specified by \a result. 3893d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 3894d5ac70f0Sopenharmony_ci * 3895d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config, allowing 3896d5ac70f0Sopenharmony_ci * aliases, like #snd_config_search_alias, and expanding hooks, like 3897d5ac70f0Sopenharmony_ci * #snd_config_search_hooks. 3898d5ac70f0Sopenharmony_ci * 3899d5ac70f0Sopenharmony_ci * \par Errors: 3900d5ac70f0Sopenharmony_ci * <dl> 3901d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist. 3902d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 3903d5ac70f0Sopenharmony_ci * not a compound node. 3904d5ac70f0Sopenharmony_ci * </dl> 3905d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook 3906d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions. 3907d5ac70f0Sopenharmony_ci */ 3908d5ac70f0Sopenharmony_ciint snd_config_search_alias_hooks(snd_config_t *config, 3909d5ac70f0Sopenharmony_ci const char *base, const char *key, 3910d5ac70f0Sopenharmony_ci snd_config_t **result) 3911d5ac70f0Sopenharmony_ci{ 3912d5ac70f0Sopenharmony_ci SND_CONFIG_SEARCH_ALIAS(config, base, key, result, 3913d5ac70f0Sopenharmony_ci snd_config_searcha_hooks, 3914d5ac70f0Sopenharmony_ci snd_config_searchva_hooks); 3915d5ac70f0Sopenharmony_ci} 3916d5ac70f0Sopenharmony_ci 3917d5ac70f0Sopenharmony_ci/** The name of the environment variable containing the files list for #snd_config_update. */ 3918d5ac70f0Sopenharmony_ci#define ALSA_CONFIG_PATH_VAR "ALSA_CONFIG_PATH" 3919d5ac70f0Sopenharmony_ci 3920d5ac70f0Sopenharmony_ci/** 3921d5ac70f0Sopenharmony_ci * \brief Configuration top-level node (the global configuration). 3922d5ac70f0Sopenharmony_ci * 3923d5ac70f0Sopenharmony_ci * This variable contains a handle to the top-level configuration node, 3924d5ac70f0Sopenharmony_ci * as loaded from global configuration file. 3925d5ac70f0Sopenharmony_ci * 3926d5ac70f0Sopenharmony_ci * This variable is initialized or updated by #snd_config_update. 3927d5ac70f0Sopenharmony_ci * Functions like #snd_pcm_open (that use a device name from the global 3928d5ac70f0Sopenharmony_ci * configuration) automatically call #snd_config_update. Before the 3929d5ac70f0Sopenharmony_ci * first call to #snd_config_update, this variable is \c NULL. 3930d5ac70f0Sopenharmony_ci * 3931d5ac70f0Sopenharmony_ci * The global configuration files are specified in the environment 3932d5ac70f0Sopenharmony_ci * variable \c ALSA_CONFIG_PATH. If this is not set, the default value 3933d5ac70f0Sopenharmony_ci * is "/usr/share/alsa/alsa.conf". 3934d5ac70f0Sopenharmony_ci * 3935d5ac70f0Sopenharmony_ci * \warning Whenever the configuration tree is updated, all string 3936d5ac70f0Sopenharmony_ci * pointers and configuration node handles previously obtained from this 3937d5ac70f0Sopenharmony_ci * variable may become invalid. 3938d5ac70f0Sopenharmony_ci * 3939d5ac70f0Sopenharmony_ci * \par Conforming to: 3940d5ac70f0Sopenharmony_ci * LSB 3.2 3941d5ac70f0Sopenharmony_ci */ 3942d5ac70f0Sopenharmony_cisnd_config_t *snd_config = NULL; 3943d5ac70f0Sopenharmony_ci 3944d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 3945d5ac70f0Sopenharmony_cistruct finfo { 3946d5ac70f0Sopenharmony_ci char *name; 3947d5ac70f0Sopenharmony_ci dev_t dev; 3948d5ac70f0Sopenharmony_ci ino64_t ino; 3949d5ac70f0Sopenharmony_ci time_t mtime; 3950d5ac70f0Sopenharmony_ci}; 3951d5ac70f0Sopenharmony_ci 3952d5ac70f0Sopenharmony_cistruct _snd_config_update { 3953d5ac70f0Sopenharmony_ci unsigned int count; 3954d5ac70f0Sopenharmony_ci struct finfo *finfo; 3955d5ac70f0Sopenharmony_ci}; 3956d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 3957d5ac70f0Sopenharmony_ci 3958d5ac70f0Sopenharmony_cistatic snd_config_update_t *snd_config_global_update = NULL; 3959d5ac70f0Sopenharmony_ci 3960d5ac70f0Sopenharmony_cistatic int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data) 3961d5ac70f0Sopenharmony_ci{ 3962d5ac70f0Sopenharmony_ci void *h = NULL; 3963d5ac70f0Sopenharmony_ci snd_config_t *c, *func_conf = NULL; 3964d5ac70f0Sopenharmony_ci char *buf = NULL, errbuf[256]; 3965d5ac70f0Sopenharmony_ci const char *lib = NULL, *func_name = NULL; 3966d5ac70f0Sopenharmony_ci const char *str; 3967d5ac70f0Sopenharmony_ci int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) = NULL; 3968d5ac70f0Sopenharmony_ci int err; 3969d5ac70f0Sopenharmony_ci 3970d5ac70f0Sopenharmony_ci err = snd_config_search(config, "func", &c); 3971d5ac70f0Sopenharmony_ci if (err < 0) { 3972d5ac70f0Sopenharmony_ci SNDERR("Field func is missing"); 3973d5ac70f0Sopenharmony_ci return err; 3974d5ac70f0Sopenharmony_ci } 3975d5ac70f0Sopenharmony_ci err = snd_config_get_string(c, &str); 3976d5ac70f0Sopenharmony_ci if (err < 0) { 3977d5ac70f0Sopenharmony_ci SNDERR("Invalid type for field func"); 3978d5ac70f0Sopenharmony_ci return err; 3979d5ac70f0Sopenharmony_ci } 3980d5ac70f0Sopenharmony_ci assert(str); 3981d5ac70f0Sopenharmony_ci err = snd_config_search_definition(root, "hook_func", str, &func_conf); 3982d5ac70f0Sopenharmony_ci if (err >= 0) { 3983d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 3984d5ac70f0Sopenharmony_ci if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) { 3985d5ac70f0Sopenharmony_ci SNDERR("Invalid type for func %s definition", str); 3986d5ac70f0Sopenharmony_ci err = -EINVAL; 3987d5ac70f0Sopenharmony_ci goto _err; 3988d5ac70f0Sopenharmony_ci } 3989d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, func_conf) { 3990d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 3991d5ac70f0Sopenharmony_ci const char *id = n->id; 3992d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0) 3993d5ac70f0Sopenharmony_ci continue; 3994d5ac70f0Sopenharmony_ci if (strcmp(id, "lib") == 0) { 3995d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &lib); 3996d5ac70f0Sopenharmony_ci if (err < 0) { 3997d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 3998d5ac70f0Sopenharmony_ci goto _err; 3999d5ac70f0Sopenharmony_ci } 4000d5ac70f0Sopenharmony_ci continue; 4001d5ac70f0Sopenharmony_ci } 4002d5ac70f0Sopenharmony_ci if (strcmp(id, "func") == 0) { 4003d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &func_name); 4004d5ac70f0Sopenharmony_ci if (err < 0) { 4005d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 4006d5ac70f0Sopenharmony_ci goto _err; 4007d5ac70f0Sopenharmony_ci } 4008d5ac70f0Sopenharmony_ci continue; 4009d5ac70f0Sopenharmony_ci } 4010d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 4011d5ac70f0Sopenharmony_ci } 4012d5ac70f0Sopenharmony_ci } 4013d5ac70f0Sopenharmony_ci if (!func_name) { 4014d5ac70f0Sopenharmony_ci int len = 16 + strlen(str) + 1; 4015d5ac70f0Sopenharmony_ci buf = malloc(len); 4016d5ac70f0Sopenharmony_ci if (! buf) { 4017d5ac70f0Sopenharmony_ci err = -ENOMEM; 4018d5ac70f0Sopenharmony_ci goto _err; 4019d5ac70f0Sopenharmony_ci } 4020d5ac70f0Sopenharmony_ci snprintf(buf, len, "snd_config_hook_%s", str); 4021d5ac70f0Sopenharmony_ci buf[len-1] = '\0'; 4022d5ac70f0Sopenharmony_ci func_name = buf; 4023d5ac70f0Sopenharmony_ci } 4024d5ac70f0Sopenharmony_ci h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); 4025d5ac70f0Sopenharmony_ci func = h ? snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_HOOK)) : NULL; 4026d5ac70f0Sopenharmony_ci err = 0; 4027d5ac70f0Sopenharmony_ci if (!h) { 4028d5ac70f0Sopenharmony_ci SNDERR("Cannot open shared library %s (%s)", lib, errbuf); 4029d5ac70f0Sopenharmony_ci err = -ENOENT; 4030d5ac70f0Sopenharmony_ci } else if (!func) { 4031d5ac70f0Sopenharmony_ci SNDERR("symbol %s is not defined inside %s", func_name, lib); 4032d5ac70f0Sopenharmony_ci snd_dlclose(h); 4033d5ac70f0Sopenharmony_ci err = -ENXIO; 4034d5ac70f0Sopenharmony_ci } 4035d5ac70f0Sopenharmony_ci _err: 4036d5ac70f0Sopenharmony_ci if (func_conf) 4037d5ac70f0Sopenharmony_ci snd_config_delete(func_conf); 4038d5ac70f0Sopenharmony_ci if (err >= 0) { 4039d5ac70f0Sopenharmony_ci snd_config_t *nroot; 4040d5ac70f0Sopenharmony_ci err = func(root, config, &nroot, private_data); 4041d5ac70f0Sopenharmony_ci if (err < 0) 4042d5ac70f0Sopenharmony_ci SNDERR("function %s returned error: %s", func_name, snd_strerror(err)); 4043d5ac70f0Sopenharmony_ci snd_dlclose(h); 4044d5ac70f0Sopenharmony_ci if (err >= 0 && nroot) 4045d5ac70f0Sopenharmony_ci err = snd_config_substitute(root, nroot); 4046d5ac70f0Sopenharmony_ci } 4047d5ac70f0Sopenharmony_ci free(buf); 4048d5ac70f0Sopenharmony_ci if (err < 0) 4049d5ac70f0Sopenharmony_ci return err; 4050d5ac70f0Sopenharmony_ci return 0; 4051d5ac70f0Sopenharmony_ci} 4052d5ac70f0Sopenharmony_ci 4053d5ac70f0Sopenharmony_cistatic int snd_config_hooks(snd_config_t *config, snd_config_t *private_data) 4054d5ac70f0Sopenharmony_ci{ 4055d5ac70f0Sopenharmony_ci snd_config_t *n; 4056d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 4057d5ac70f0Sopenharmony_ci int err, hit, idx = 0; 4058d5ac70f0Sopenharmony_ci 4059d5ac70f0Sopenharmony_ci if ((err = snd_config_search(config, "@hooks", &n)) < 0) 4060d5ac70f0Sopenharmony_ci return 0; 4061d5ac70f0Sopenharmony_ci snd_config_lock(); 4062d5ac70f0Sopenharmony_ci snd_config_remove(n); 4063d5ac70f0Sopenharmony_ci do { 4064d5ac70f0Sopenharmony_ci hit = 0; 4065d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, n) { 4066d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 4067d5ac70f0Sopenharmony_ci const char *id = n->id; 4068d5ac70f0Sopenharmony_ci long i; 4069d5ac70f0Sopenharmony_ci err = safe_strtol(id, &i); 4070d5ac70f0Sopenharmony_ci if (err < 0) { 4071d5ac70f0Sopenharmony_ci SNDERR("id of field %s is not and integer", id); 4072d5ac70f0Sopenharmony_ci err = -EINVAL; 4073d5ac70f0Sopenharmony_ci goto _err; 4074d5ac70f0Sopenharmony_ci } 4075d5ac70f0Sopenharmony_ci if (i == idx) { 4076d5ac70f0Sopenharmony_ci err = snd_config_hooks_call(config, n, private_data); 4077d5ac70f0Sopenharmony_ci if (err < 0) 4078d5ac70f0Sopenharmony_ci goto _err; 4079d5ac70f0Sopenharmony_ci idx++; 4080d5ac70f0Sopenharmony_ci hit = 1; 4081d5ac70f0Sopenharmony_ci } 4082d5ac70f0Sopenharmony_ci } 4083d5ac70f0Sopenharmony_ci } while (hit); 4084d5ac70f0Sopenharmony_ci err = 0; 4085d5ac70f0Sopenharmony_ci _err: 4086d5ac70f0Sopenharmony_ci snd_config_delete(n); 4087d5ac70f0Sopenharmony_ci snd_config_unlock(); 4088d5ac70f0Sopenharmony_ci return err; 4089d5ac70f0Sopenharmony_ci} 4090d5ac70f0Sopenharmony_ci 4091d5ac70f0Sopenharmony_cistatic int config_filename_filter(const struct dirent64 *dirent) 4092d5ac70f0Sopenharmony_ci{ 4093d5ac70f0Sopenharmony_ci size_t flen; 4094d5ac70f0Sopenharmony_ci 4095d5ac70f0Sopenharmony_ci if (dirent == NULL) 4096d5ac70f0Sopenharmony_ci return 0; 4097d5ac70f0Sopenharmony_ci if (dirent->d_type == DT_DIR) 4098d5ac70f0Sopenharmony_ci return 0; 4099d5ac70f0Sopenharmony_ci 4100d5ac70f0Sopenharmony_ci flen = strlen(dirent->d_name); 4101d5ac70f0Sopenharmony_ci if (flen <= 5) 4102d5ac70f0Sopenharmony_ci return 0; 4103d5ac70f0Sopenharmony_ci 4104d5ac70f0Sopenharmony_ci if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0) 4105d5ac70f0Sopenharmony_ci return 1; 4106d5ac70f0Sopenharmony_ci 4107d5ac70f0Sopenharmony_ci return 0; 4108d5ac70f0Sopenharmony_ci} 4109d5ac70f0Sopenharmony_ci 4110d5ac70f0Sopenharmony_cistatic int config_file_open(snd_config_t *root, const char *filename) 4111d5ac70f0Sopenharmony_ci{ 4112d5ac70f0Sopenharmony_ci snd_input_t *in; 4113d5ac70f0Sopenharmony_ci int err; 4114d5ac70f0Sopenharmony_ci 4115d5ac70f0Sopenharmony_ci err = snd_input_stdio_open(&in, filename, "r"); 4116d5ac70f0Sopenharmony_ci if (err >= 0) { 4117d5ac70f0Sopenharmony_ci err = snd_config_load(root, in); 4118d5ac70f0Sopenharmony_ci snd_input_close(in); 4119d5ac70f0Sopenharmony_ci if (err < 0) 4120d5ac70f0Sopenharmony_ci SNDERR("%s may be old or corrupted: consider to remove or fix it", filename); 4121d5ac70f0Sopenharmony_ci } else 4122d5ac70f0Sopenharmony_ci SNDERR("cannot access file %s", filename); 4123d5ac70f0Sopenharmony_ci 4124d5ac70f0Sopenharmony_ci return err; 4125d5ac70f0Sopenharmony_ci} 4126d5ac70f0Sopenharmony_ci 4127d5ac70f0Sopenharmony_cistatic int config_file_load(snd_config_t *root, const char *fn, int errors) 4128d5ac70f0Sopenharmony_ci{ 4129d5ac70f0Sopenharmony_ci struct stat64 st; 4130d5ac70f0Sopenharmony_ci struct dirent64 **namelist; 4131d5ac70f0Sopenharmony_ci int err, n; 4132d5ac70f0Sopenharmony_ci 4133d5ac70f0Sopenharmony_ci if (!errors && access(fn, R_OK) < 0) 4134d5ac70f0Sopenharmony_ci return 1; 4135d5ac70f0Sopenharmony_ci if (stat64(fn, &st) < 0) { 4136d5ac70f0Sopenharmony_ci SNDERR("cannot stat file/directory %s", fn); 4137d5ac70f0Sopenharmony_ci return 1; 4138d5ac70f0Sopenharmony_ci } 4139d5ac70f0Sopenharmony_ci if (!S_ISDIR(st.st_mode)) 4140d5ac70f0Sopenharmony_ci return config_file_open(root, fn); 4141d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 4142d5ac70f0Sopenharmony_ci#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__sun) && !defined(__ANDROID__) 4143d5ac70f0Sopenharmony_ci#define SORTFUNC versionsort64 4144d5ac70f0Sopenharmony_ci#else 4145d5ac70f0Sopenharmony_ci#define SORTFUNC alphasort64 4146d5ac70f0Sopenharmony_ci#endif 4147d5ac70f0Sopenharmony_ci#endif 4148d5ac70f0Sopenharmony_ci n = scandir64(fn, &namelist, config_filename_filter, SORTFUNC); 4149d5ac70f0Sopenharmony_ci if (n > 0) { 4150d5ac70f0Sopenharmony_ci int j; 4151d5ac70f0Sopenharmony_ci err = 0; 4152d5ac70f0Sopenharmony_ci for (j = 0; j < n; ++j) { 4153d5ac70f0Sopenharmony_ci if (err >= 0) { 4154d5ac70f0Sopenharmony_ci int sl = strlen(fn) + strlen(namelist[j]->d_name) + 2; 4155d5ac70f0Sopenharmony_ci char *filename = malloc(sl); 4156d5ac70f0Sopenharmony_ci snprintf(filename, sl, "%s/%s", fn, namelist[j]->d_name); 4157d5ac70f0Sopenharmony_ci filename[sl-1] = '\0'; 4158d5ac70f0Sopenharmony_ci 4159d5ac70f0Sopenharmony_ci err = config_file_open(root, filename); 4160d5ac70f0Sopenharmony_ci free(filename); 4161d5ac70f0Sopenharmony_ci } 4162d5ac70f0Sopenharmony_ci free(namelist[j]); 4163d5ac70f0Sopenharmony_ci } 4164d5ac70f0Sopenharmony_ci free(namelist); 4165d5ac70f0Sopenharmony_ci if (err < 0) 4166d5ac70f0Sopenharmony_ci return err; 4167d5ac70f0Sopenharmony_ci } 4168d5ac70f0Sopenharmony_ci return 0; 4169d5ac70f0Sopenharmony_ci} 4170d5ac70f0Sopenharmony_ci 4171d5ac70f0Sopenharmony_cistatic int config_file_load_user(snd_config_t *root, const char *fn, int errors) 4172d5ac70f0Sopenharmony_ci{ 4173d5ac70f0Sopenharmony_ci char *fn2; 4174d5ac70f0Sopenharmony_ci int err; 4175d5ac70f0Sopenharmony_ci 4176d5ac70f0Sopenharmony_ci err = snd_user_file(fn, &fn2); 4177d5ac70f0Sopenharmony_ci if (err < 0) 4178d5ac70f0Sopenharmony_ci return config_file_load(root, fn, errors); 4179d5ac70f0Sopenharmony_ci err = config_file_load(root, fn2, errors); 4180d5ac70f0Sopenharmony_ci free(fn2); 4181d5ac70f0Sopenharmony_ci return err; 4182d5ac70f0Sopenharmony_ci} 4183d5ac70f0Sopenharmony_ci 4184d5ac70f0Sopenharmony_cistatic int config_file_load_user_all(snd_config_t *_root, snd_config_t *_file, int errors) 4185d5ac70f0Sopenharmony_ci{ 4186d5ac70f0Sopenharmony_ci snd_config_t *file = _file, *root = _root, *n; 4187d5ac70f0Sopenharmony_ci char *name, *name2, *remain, *rname = NULL; 4188d5ac70f0Sopenharmony_ci int err; 4189d5ac70f0Sopenharmony_ci 4190d5ac70f0Sopenharmony_ci if (snd_config_get_type(_file) == SND_CONFIG_TYPE_COMPOUND) { 4191d5ac70f0Sopenharmony_ci if ((err = snd_config_search(_file, "file", &file)) < 0) { 4192d5ac70f0Sopenharmony_ci SNDERR("Field file not found"); 4193d5ac70f0Sopenharmony_ci return err; 4194d5ac70f0Sopenharmony_ci } 4195d5ac70f0Sopenharmony_ci if ((err = snd_config_search(_file, "root", &root)) >= 0) { 4196d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(root, &rname); 4197d5ac70f0Sopenharmony_ci if (err < 0) { 4198d5ac70f0Sopenharmony_ci SNDERR("Field root is bad"); 4199d5ac70f0Sopenharmony_ci return err; 4200d5ac70f0Sopenharmony_ci } 4201d5ac70f0Sopenharmony_ci err = snd_config_make_compound(&root, rname, 0); 4202d5ac70f0Sopenharmony_ci if (err < 0) 4203d5ac70f0Sopenharmony_ci return err; 4204d5ac70f0Sopenharmony_ci } 4205d5ac70f0Sopenharmony_ci } 4206d5ac70f0Sopenharmony_ci if ((err = snd_config_get_ascii(file, &name)) < 0) 4207d5ac70f0Sopenharmony_ci goto _err; 4208d5ac70f0Sopenharmony_ci name2 = name; 4209d5ac70f0Sopenharmony_ci remain = strstr(name, "|||"); 4210d5ac70f0Sopenharmony_ci while (1) { 4211d5ac70f0Sopenharmony_ci if (remain) { 4212d5ac70f0Sopenharmony_ci *remain = '\0'; 4213d5ac70f0Sopenharmony_ci remain += 3; 4214d5ac70f0Sopenharmony_ci } 4215d5ac70f0Sopenharmony_ci err = config_file_load_user(root, name2, errors); 4216d5ac70f0Sopenharmony_ci if (err < 0) 4217d5ac70f0Sopenharmony_ci goto _err; 4218d5ac70f0Sopenharmony_ci if (err == 0) /* first hit wins */ 4219d5ac70f0Sopenharmony_ci break; 4220d5ac70f0Sopenharmony_ci if (!remain) 4221d5ac70f0Sopenharmony_ci break; 4222d5ac70f0Sopenharmony_ci name2 = remain; 4223d5ac70f0Sopenharmony_ci remain = strstr(remain, "|||"); 4224d5ac70f0Sopenharmony_ci } 4225d5ac70f0Sopenharmony_ci_err: 4226d5ac70f0Sopenharmony_ci if (root != _root) { 4227d5ac70f0Sopenharmony_ci if (err == 0) { 4228d5ac70f0Sopenharmony_ci if (snd_config_get_type(root) == SND_CONFIG_TYPE_COMPOUND) { 4229d5ac70f0Sopenharmony_ci if (snd_config_is_empty(root)) 4230d5ac70f0Sopenharmony_ci goto _del; 4231d5ac70f0Sopenharmony_ci } 4232d5ac70f0Sopenharmony_ci err = snd_config_make_path(&n, _root, rname, 0, 1); 4233d5ac70f0Sopenharmony_ci if (err < 0) 4234d5ac70f0Sopenharmony_ci goto _del; 4235d5ac70f0Sopenharmony_ci err = snd_config_substitute(n, root); 4236d5ac70f0Sopenharmony_ci if (err == 0) 4237d5ac70f0Sopenharmony_ci goto _fin; 4238d5ac70f0Sopenharmony_ci } 4239d5ac70f0Sopenharmony_ci_del: 4240d5ac70f0Sopenharmony_ci snd_config_delete(root); 4241d5ac70f0Sopenharmony_ci } 4242d5ac70f0Sopenharmony_ci_fin: 4243d5ac70f0Sopenharmony_ci free(name); 4244d5ac70f0Sopenharmony_ci free(rname); 4245d5ac70f0Sopenharmony_ci return err; 4246d5ac70f0Sopenharmony_ci} 4247d5ac70f0Sopenharmony_ci 4248d5ac70f0Sopenharmony_ci/** 4249d5ac70f0Sopenharmony_ci * \brief Loads and parses the given configurations files. 4250d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node. 4251d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node for this hook. 4252d5ac70f0Sopenharmony_ci * \param[out] dst The function puts the handle to the configuration 4253d5ac70f0Sopenharmony_ci * node loaded from the file(s) at the address specified 4254d5ac70f0Sopenharmony_ci * by \a dst. 4255d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data configuration node. 4256d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 4257d5ac70f0Sopenharmony_ci * 4258d5ac70f0Sopenharmony_ci * See \ref confhooks for an example. 4259d5ac70f0Sopenharmony_ci */ 4260d5ac70f0Sopenharmony_ciint snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) 4261d5ac70f0Sopenharmony_ci{ 4262d5ac70f0Sopenharmony_ci snd_config_t *n; 4263d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 4264d5ac70f0Sopenharmony_ci int err, idx = 0, errors = 1, hit; 4265d5ac70f0Sopenharmony_ci 4266d5ac70f0Sopenharmony_ci assert(root && dst); 4267d5ac70f0Sopenharmony_ci if ((err = snd_config_search(config, "errors", &n)) >= 0) { 4268d5ac70f0Sopenharmony_ci errors = snd_config_get_bool(n); 4269d5ac70f0Sopenharmony_ci if (errors < 0) { 4270d5ac70f0Sopenharmony_ci SNDERR("Invalid bool value in field errors"); 4271d5ac70f0Sopenharmony_ci return errors; 4272d5ac70f0Sopenharmony_ci } 4273d5ac70f0Sopenharmony_ci } 4274d5ac70f0Sopenharmony_ci if ((err = snd_config_search(config, "files", &n)) < 0) { 4275d5ac70f0Sopenharmony_ci SNDERR("Unable to find field files in the pre-load section"); 4276d5ac70f0Sopenharmony_ci return -EINVAL; 4277d5ac70f0Sopenharmony_ci } 4278d5ac70f0Sopenharmony_ci if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) { 4279d5ac70f0Sopenharmony_ci SNDERR("Unable to expand filenames in the pre-load section"); 4280d5ac70f0Sopenharmony_ci return err; 4281d5ac70f0Sopenharmony_ci } 4282d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 4283d5ac70f0Sopenharmony_ci SNDERR("Invalid type for field filenames"); 4284d5ac70f0Sopenharmony_ci goto _err; 4285d5ac70f0Sopenharmony_ci } 4286d5ac70f0Sopenharmony_ci do { 4287d5ac70f0Sopenharmony_ci hit = 0; 4288d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, n) { 4289d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 4290d5ac70f0Sopenharmony_ci const char *id = n->id; 4291d5ac70f0Sopenharmony_ci long i; 4292d5ac70f0Sopenharmony_ci err = safe_strtol(id, &i); 4293d5ac70f0Sopenharmony_ci if (err < 0) { 4294d5ac70f0Sopenharmony_ci SNDERR("id of field %s is not and integer", id); 4295d5ac70f0Sopenharmony_ci err = -EINVAL; 4296d5ac70f0Sopenharmony_ci goto _err; 4297d5ac70f0Sopenharmony_ci } 4298d5ac70f0Sopenharmony_ci if (i == idx) { 4299d5ac70f0Sopenharmony_ci err = config_file_load_user_all(root, n, errors); 4300d5ac70f0Sopenharmony_ci if (err < 0) 4301d5ac70f0Sopenharmony_ci goto _err; 4302d5ac70f0Sopenharmony_ci idx++; 4303d5ac70f0Sopenharmony_ci hit = 1; 4304d5ac70f0Sopenharmony_ci } 4305d5ac70f0Sopenharmony_ci } 4306d5ac70f0Sopenharmony_ci } while (hit); 4307d5ac70f0Sopenharmony_ci *dst = NULL; 4308d5ac70f0Sopenharmony_ci err = 0; 4309d5ac70f0Sopenharmony_ci _err: 4310d5ac70f0Sopenharmony_ci snd_config_delete(n); 4311d5ac70f0Sopenharmony_ci return err; 4312d5ac70f0Sopenharmony_ci} 4313d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 4314d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(snd_config_hook_load, SND_CONFIG_DLSYM_VERSION_HOOK); 4315d5ac70f0Sopenharmony_ci#endif 4316d5ac70f0Sopenharmony_ci 4317d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 4318d5ac70f0Sopenharmony_ciint snd_determine_driver(int card, char **driver); 4319d5ac70f0Sopenharmony_ci#endif 4320d5ac70f0Sopenharmony_ci 4321d5ac70f0Sopenharmony_cistatic snd_config_t *_snd_config_hook_private_data(int card, const char *driver) 4322d5ac70f0Sopenharmony_ci{ 4323d5ac70f0Sopenharmony_ci snd_config_t *private_data, *v; 4324d5ac70f0Sopenharmony_ci int err; 4325d5ac70f0Sopenharmony_ci 4326d5ac70f0Sopenharmony_ci err = snd_config_make_compound(&private_data, NULL, 0); 4327d5ac70f0Sopenharmony_ci if (err < 0) 4328d5ac70f0Sopenharmony_ci goto __err; 4329d5ac70f0Sopenharmony_ci err = snd_config_imake_integer(&v, "integer", card); 4330d5ac70f0Sopenharmony_ci if (err < 0) 4331d5ac70f0Sopenharmony_ci goto __err; 4332d5ac70f0Sopenharmony_ci err = snd_config_add(private_data, v); 4333d5ac70f0Sopenharmony_ci if (err < 0) { 4334d5ac70f0Sopenharmony_ci snd_config_delete(v); 4335d5ac70f0Sopenharmony_ci goto __err; 4336d5ac70f0Sopenharmony_ci } 4337d5ac70f0Sopenharmony_ci err = snd_config_imake_string(&v, "string", driver); 4338d5ac70f0Sopenharmony_ci if (err < 0) 4339d5ac70f0Sopenharmony_ci goto __err; 4340d5ac70f0Sopenharmony_ci err = snd_config_add(private_data, v); 4341d5ac70f0Sopenharmony_ci if (err < 0) { 4342d5ac70f0Sopenharmony_ci snd_config_delete(v); 4343d5ac70f0Sopenharmony_ci goto __err; 4344d5ac70f0Sopenharmony_ci } 4345d5ac70f0Sopenharmony_ci return private_data; 4346d5ac70f0Sopenharmony_ci 4347d5ac70f0Sopenharmony_ci__err: 4348d5ac70f0Sopenharmony_ci snd_config_delete(private_data); 4349d5ac70f0Sopenharmony_ci return NULL; 4350d5ac70f0Sopenharmony_ci} 4351d5ac70f0Sopenharmony_ci 4352d5ac70f0Sopenharmony_cistatic int _snd_config_hook_table(snd_config_t *root, snd_config_t *config, snd_config_t *private_data) 4353d5ac70f0Sopenharmony_ci{ 4354d5ac70f0Sopenharmony_ci snd_config_t *n, *tn; 4355d5ac70f0Sopenharmony_ci const char *id; 4356d5ac70f0Sopenharmony_ci int err; 4357d5ac70f0Sopenharmony_ci 4358d5ac70f0Sopenharmony_ci if (snd_config_search(config, "table", &n) < 0) 4359d5ac70f0Sopenharmony_ci return 0; 4360d5ac70f0Sopenharmony_ci if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) { 4361d5ac70f0Sopenharmony_ci SNDERR("Unable to expand table compound"); 4362d5ac70f0Sopenharmony_ci return err; 4363d5ac70f0Sopenharmony_ci } 4364d5ac70f0Sopenharmony_ci if (snd_config_search(n, "id", &tn) < 0 || 4365d5ac70f0Sopenharmony_ci snd_config_get_string(tn, &id) < 0) { 4366d5ac70f0Sopenharmony_ci SNDERR("Unable to find field table.id"); 4367d5ac70f0Sopenharmony_ci snd_config_delete(n); 4368d5ac70f0Sopenharmony_ci return -EINVAL; 4369d5ac70f0Sopenharmony_ci } 4370d5ac70f0Sopenharmony_ci if (snd_config_search(n, "value", &tn) < 0 || 4371d5ac70f0Sopenharmony_ci snd_config_get_type(tn) != SND_CONFIG_TYPE_STRING) { 4372d5ac70f0Sopenharmony_ci SNDERR("Unable to find field table.value"); 4373d5ac70f0Sopenharmony_ci snd_config_delete(n); 4374d5ac70f0Sopenharmony_ci return -EINVAL; 4375d5ac70f0Sopenharmony_ci } 4376d5ac70f0Sopenharmony_ci snd_config_remove(tn); 4377d5ac70f0Sopenharmony_ci if ((err = snd_config_set_id(tn, id)) < 0) { 4378d5ac70f0Sopenharmony_ci snd_config_delete(tn); 4379d5ac70f0Sopenharmony_ci snd_config_delete(n); 4380d5ac70f0Sopenharmony_ci return err; 4381d5ac70f0Sopenharmony_ci } 4382d5ac70f0Sopenharmony_ci snd_config_delete(n); 4383d5ac70f0Sopenharmony_ci if ((err = snd_config_add(root, tn)) < 0) { 4384d5ac70f0Sopenharmony_ci snd_config_delete(tn); 4385d5ac70f0Sopenharmony_ci return err; 4386d5ac70f0Sopenharmony_ci } 4387d5ac70f0Sopenharmony_ci return 0; 4388d5ac70f0Sopenharmony_ci} 4389d5ac70f0Sopenharmony_ci 4390d5ac70f0Sopenharmony_ci/** 4391d5ac70f0Sopenharmony_ci * \brief Loads and parses the given configurations files for each 4392d5ac70f0Sopenharmony_ci * installed sound card. 4393d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node. 4394d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node for this hook. 4395d5ac70f0Sopenharmony_ci * \param[out] dst The function puts the handle to the configuration 4396d5ac70f0Sopenharmony_ci * node loaded from the file(s) at the address specified 4397d5ac70f0Sopenharmony_ci * by \a dst. 4398d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data configuration node. 4399d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 4400d5ac70f0Sopenharmony_ci * 4401d5ac70f0Sopenharmony_ci * This function works like #snd_config_hook_load, but the files are 4402d5ac70f0Sopenharmony_ci * loaded once for each sound card. The driver name is available with 4403d5ac70f0Sopenharmony_ci * the \c private_string function to customize the file name. 4404d5ac70f0Sopenharmony_ci */ 4405d5ac70f0Sopenharmony_ciint snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data ATTRIBUTE_UNUSED) 4406d5ac70f0Sopenharmony_ci{ 4407d5ac70f0Sopenharmony_ci int card = -1, err; 4408d5ac70f0Sopenharmony_ci snd_config_t *loaded; // trace loaded cards 4409d5ac70f0Sopenharmony_ci 4410d5ac70f0Sopenharmony_ci err = snd_config_top(&loaded); 4411d5ac70f0Sopenharmony_ci if (err < 0) 4412d5ac70f0Sopenharmony_ci return err; 4413d5ac70f0Sopenharmony_ci do { 4414d5ac70f0Sopenharmony_ci err = snd_card_next(&card); 4415d5ac70f0Sopenharmony_ci if (err < 0) 4416d5ac70f0Sopenharmony_ci goto __fin_err; 4417d5ac70f0Sopenharmony_ci if (card >= 0) { 4418d5ac70f0Sopenharmony_ci snd_config_t *n, *m, *private_data = NULL; 4419d5ac70f0Sopenharmony_ci const char *driver; 4420d5ac70f0Sopenharmony_ci char *fdriver = NULL; 4421d5ac70f0Sopenharmony_ci bool load; 4422d5ac70f0Sopenharmony_ci err = snd_determine_driver(card, &fdriver); 4423d5ac70f0Sopenharmony_ci if (err < 0) 4424d5ac70f0Sopenharmony_ci goto __fin_err; 4425d5ac70f0Sopenharmony_ci if (snd_config_search(root, fdriver, &n) >= 0) { 4426d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &driver) < 0) { 4427d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) { 4428d5ac70f0Sopenharmony_ci snd_config_get_id(n, &driver); 4429d5ac70f0Sopenharmony_ci goto __std; 4430d5ac70f0Sopenharmony_ci } 4431d5ac70f0Sopenharmony_ci goto __err; 4432d5ac70f0Sopenharmony_ci } 4433d5ac70f0Sopenharmony_ci while (1) { 4434d5ac70f0Sopenharmony_ci char *s = strchr(driver, '.'); 4435d5ac70f0Sopenharmony_ci if (s == NULL) 4436d5ac70f0Sopenharmony_ci break; 4437d5ac70f0Sopenharmony_ci driver = s + 1; 4438d5ac70f0Sopenharmony_ci } 4439d5ac70f0Sopenharmony_ci if (snd_config_search(root, driver, &n) >= 0) 4440d5ac70f0Sopenharmony_ci goto __err; 4441d5ac70f0Sopenharmony_ci } else { 4442d5ac70f0Sopenharmony_ci driver = fdriver; 4443d5ac70f0Sopenharmony_ci } 4444d5ac70f0Sopenharmony_ci __std: 4445d5ac70f0Sopenharmony_ci load = true; 4446d5ac70f0Sopenharmony_ci err = snd_config_imake_integer(&m, driver, 1); 4447d5ac70f0Sopenharmony_ci if (err < 0) 4448d5ac70f0Sopenharmony_ci goto __err; 4449d5ac70f0Sopenharmony_ci err = snd_config_add(loaded, m); 4450d5ac70f0Sopenharmony_ci if (err < 0) { 4451d5ac70f0Sopenharmony_ci if (err == -EEXIST) { 4452d5ac70f0Sopenharmony_ci snd_config_delete(m); 4453d5ac70f0Sopenharmony_ci load = false; 4454d5ac70f0Sopenharmony_ci } else { 4455d5ac70f0Sopenharmony_ci goto __err; 4456d5ac70f0Sopenharmony_ci } 4457d5ac70f0Sopenharmony_ci } 4458d5ac70f0Sopenharmony_ci private_data = _snd_config_hook_private_data(card, driver); 4459d5ac70f0Sopenharmony_ci if (!private_data) { 4460d5ac70f0Sopenharmony_ci err = -ENOMEM; 4461d5ac70f0Sopenharmony_ci goto __err; 4462d5ac70f0Sopenharmony_ci } 4463d5ac70f0Sopenharmony_ci err = _snd_config_hook_table(root, config, private_data); 4464d5ac70f0Sopenharmony_ci if (err < 0) 4465d5ac70f0Sopenharmony_ci goto __err; 4466d5ac70f0Sopenharmony_ci if (load) 4467d5ac70f0Sopenharmony_ci err = snd_config_hook_load(root, config, &n, private_data); 4468d5ac70f0Sopenharmony_ci __err: 4469d5ac70f0Sopenharmony_ci if (private_data) 4470d5ac70f0Sopenharmony_ci snd_config_delete(private_data); 4471d5ac70f0Sopenharmony_ci free(fdriver); 4472d5ac70f0Sopenharmony_ci if (err < 0) 4473d5ac70f0Sopenharmony_ci goto __fin_err; 4474d5ac70f0Sopenharmony_ci } 4475d5ac70f0Sopenharmony_ci } while (card >= 0); 4476d5ac70f0Sopenharmony_ci snd_config_delete(loaded); 4477d5ac70f0Sopenharmony_ci *dst = NULL; 4478d5ac70f0Sopenharmony_ci return 0; 4479d5ac70f0Sopenharmony_ci__fin_err: 4480d5ac70f0Sopenharmony_ci snd_config_delete(loaded); 4481d5ac70f0Sopenharmony_ci return err; 4482d5ac70f0Sopenharmony_ci} 4483d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 4484d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VERSION_HOOK); 4485d5ac70f0Sopenharmony_ci#endif 4486d5ac70f0Sopenharmony_ci 4487d5ac70f0Sopenharmony_ci/** 4488d5ac70f0Sopenharmony_ci * \brief Updates a configuration tree by rereading the configuration files (if needed). 4489d5ac70f0Sopenharmony_ci * \param[in,out] _top Address of the handle to the top-level node. 4490d5ac70f0Sopenharmony_ci * \param[in,out] _update Address of a pointer to private update information. 4491d5ac70f0Sopenharmony_ci * \param[in] cfgs A list of configuration file names, delimited with ':'. 4492d5ac70f0Sopenharmony_ci * If \p cfgs is \c NULL, the default global 4493d5ac70f0Sopenharmony_ci * configuration file is used. 4494d5ac70f0Sopenharmony_ci * \return 0 if \a _top was up to date, 1 if the configuration files 4495d5ac70f0Sopenharmony_ci * have been reread, otherwise a negative error code. 4496d5ac70f0Sopenharmony_ci * 4497d5ac70f0Sopenharmony_ci * The variables pointed to by \a _top and \a _update can be initialized 4498d5ac70f0Sopenharmony_ci * to \c NULL before the first call to this function. The private 4499d5ac70f0Sopenharmony_ci * update information holds information about all used configuration 4500d5ac70f0Sopenharmony_ci * files that allows this function to detects changes to them; this data 4501d5ac70f0Sopenharmony_ci * can be freed with #snd_config_update_free. 4502d5ac70f0Sopenharmony_ci * 4503d5ac70f0Sopenharmony_ci * The global configuration files are specified in the environment variable 4504d5ac70f0Sopenharmony_ci * \c ALSA_CONFIG_PATH. 4505d5ac70f0Sopenharmony_ci * 4506d5ac70f0Sopenharmony_ci * \warning If the configuration tree is reread, all string pointers and 4507d5ac70f0Sopenharmony_ci * configuration node handles previously obtained from this tree become 4508d5ac70f0Sopenharmony_ci * invalid. 4509d5ac70f0Sopenharmony_ci * 4510d5ac70f0Sopenharmony_ci * \par Errors: 4511d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or 4512d5ac70f0Sopenharmony_ci * functions. 4513d5ac70f0Sopenharmony_ci */ 4514d5ac70f0Sopenharmony_ciint snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs) 4515d5ac70f0Sopenharmony_ci{ 4516d5ac70f0Sopenharmony_ci int err; 4517d5ac70f0Sopenharmony_ci const char *configs, *c; 4518d5ac70f0Sopenharmony_ci unsigned int k; 4519d5ac70f0Sopenharmony_ci size_t l; 4520d5ac70f0Sopenharmony_ci snd_config_update_t *local; 4521d5ac70f0Sopenharmony_ci snd_config_update_t *update; 4522d5ac70f0Sopenharmony_ci snd_config_t *top; 4523d5ac70f0Sopenharmony_ci 4524d5ac70f0Sopenharmony_ci assert(_top && _update); 4525d5ac70f0Sopenharmony_ci top = *_top; 4526d5ac70f0Sopenharmony_ci update = *_update; 4527d5ac70f0Sopenharmony_ci configs = cfgs; 4528d5ac70f0Sopenharmony_ci if (!configs) { 4529d5ac70f0Sopenharmony_ci configs = getenv(ALSA_CONFIG_PATH_VAR); 4530d5ac70f0Sopenharmony_ci if (!configs || !*configs) { 4531d5ac70f0Sopenharmony_ci const char *topdir = snd_config_topdir(); 4532d5ac70f0Sopenharmony_ci char *s = alloca(strlen(topdir) + 4533d5ac70f0Sopenharmony_ci strlen("alsa.conf") + 2); 4534d5ac70f0Sopenharmony_ci sprintf(s, "%s/alsa.conf", topdir); 4535d5ac70f0Sopenharmony_ci configs = s; 4536d5ac70f0Sopenharmony_ci } 4537d5ac70f0Sopenharmony_ci } 4538d5ac70f0Sopenharmony_ci for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { 4539d5ac70f0Sopenharmony_ci c += l; 4540d5ac70f0Sopenharmony_ci k++; 4541d5ac70f0Sopenharmony_ci if (!*c) 4542d5ac70f0Sopenharmony_ci break; 4543d5ac70f0Sopenharmony_ci c++; 4544d5ac70f0Sopenharmony_ci } 4545d5ac70f0Sopenharmony_ci if (k == 0) { 4546d5ac70f0Sopenharmony_ci local = NULL; 4547d5ac70f0Sopenharmony_ci goto _reread; 4548d5ac70f0Sopenharmony_ci } 4549d5ac70f0Sopenharmony_ci local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t)); 4550d5ac70f0Sopenharmony_ci if (!local) 4551d5ac70f0Sopenharmony_ci return -ENOMEM; 4552d5ac70f0Sopenharmony_ci local->count = k; 4553d5ac70f0Sopenharmony_ci local->finfo = calloc(local->count, sizeof(struct finfo)); 4554d5ac70f0Sopenharmony_ci if (!local->finfo) { 4555d5ac70f0Sopenharmony_ci free(local); 4556d5ac70f0Sopenharmony_ci return -ENOMEM; 4557d5ac70f0Sopenharmony_ci } 4558d5ac70f0Sopenharmony_ci for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { 4559d5ac70f0Sopenharmony_ci char name[l + 1]; 4560d5ac70f0Sopenharmony_ci memcpy(name, c, l); 4561d5ac70f0Sopenharmony_ci name[l] = 0; 4562d5ac70f0Sopenharmony_ci err = snd_user_file(name, &local->finfo[k].name); 4563d5ac70f0Sopenharmony_ci if (err < 0) 4564d5ac70f0Sopenharmony_ci goto _end; 4565d5ac70f0Sopenharmony_ci c += l; 4566d5ac70f0Sopenharmony_ci k++; 4567d5ac70f0Sopenharmony_ci if (!*c) 4568d5ac70f0Sopenharmony_ci break; 4569d5ac70f0Sopenharmony_ci c++; 4570d5ac70f0Sopenharmony_ci } 4571d5ac70f0Sopenharmony_ci for (k = 0; k < local->count; ++k) { 4572d5ac70f0Sopenharmony_ci struct stat64 st; 4573d5ac70f0Sopenharmony_ci struct finfo *lf = &local->finfo[k]; 4574d5ac70f0Sopenharmony_ci if (stat64(lf->name, &st) >= 0) { 4575d5ac70f0Sopenharmony_ci lf->dev = st.st_dev; 4576d5ac70f0Sopenharmony_ci lf->ino = st.st_ino; 4577d5ac70f0Sopenharmony_ci lf->mtime = st.st_mtime; 4578d5ac70f0Sopenharmony_ci } else { 4579d5ac70f0Sopenharmony_ci SNDERR("Cannot access file %s", lf->name); 4580d5ac70f0Sopenharmony_ci free(lf->name); 4581d5ac70f0Sopenharmony_ci memmove(&local->finfo[k], &local->finfo[k+1], sizeof(struct finfo) * (local->count - k - 1)); 4582d5ac70f0Sopenharmony_ci k--; 4583d5ac70f0Sopenharmony_ci local->count--; 4584d5ac70f0Sopenharmony_ci } 4585d5ac70f0Sopenharmony_ci } 4586d5ac70f0Sopenharmony_ci if (!update) 4587d5ac70f0Sopenharmony_ci goto _reread; 4588d5ac70f0Sopenharmony_ci if (local->count != update->count) 4589d5ac70f0Sopenharmony_ci goto _reread; 4590d5ac70f0Sopenharmony_ci for (k = 0; k < local->count; ++k) { 4591d5ac70f0Sopenharmony_ci struct finfo *lf = &local->finfo[k]; 4592d5ac70f0Sopenharmony_ci struct finfo *uf = &update->finfo[k]; 4593d5ac70f0Sopenharmony_ci if (strcmp(lf->name, uf->name) != 0 || 4594d5ac70f0Sopenharmony_ci lf->dev != uf->dev || 4595d5ac70f0Sopenharmony_ci lf->ino != uf->ino || 4596d5ac70f0Sopenharmony_ci lf->mtime != uf->mtime) 4597d5ac70f0Sopenharmony_ci goto _reread; 4598d5ac70f0Sopenharmony_ci } 4599d5ac70f0Sopenharmony_ci err = 0; 4600d5ac70f0Sopenharmony_ci 4601d5ac70f0Sopenharmony_ci _end: 4602d5ac70f0Sopenharmony_ci if (err < 0) { 4603d5ac70f0Sopenharmony_ci if (top) { 4604d5ac70f0Sopenharmony_ci snd_config_delete(top); 4605d5ac70f0Sopenharmony_ci *_top = NULL; 4606d5ac70f0Sopenharmony_ci } 4607d5ac70f0Sopenharmony_ci if (update) { 4608d5ac70f0Sopenharmony_ci snd_config_update_free(update); 4609d5ac70f0Sopenharmony_ci *_update = NULL; 4610d5ac70f0Sopenharmony_ci } 4611d5ac70f0Sopenharmony_ci } 4612d5ac70f0Sopenharmony_ci if (local) 4613d5ac70f0Sopenharmony_ci snd_config_update_free(local); 4614d5ac70f0Sopenharmony_ci return err; 4615d5ac70f0Sopenharmony_ci 4616d5ac70f0Sopenharmony_ci _reread: 4617d5ac70f0Sopenharmony_ci *_top = NULL; 4618d5ac70f0Sopenharmony_ci *_update = NULL; 4619d5ac70f0Sopenharmony_ci if (update) { 4620d5ac70f0Sopenharmony_ci snd_config_update_free(update); 4621d5ac70f0Sopenharmony_ci update = NULL; 4622d5ac70f0Sopenharmony_ci } 4623d5ac70f0Sopenharmony_ci if (top) { 4624d5ac70f0Sopenharmony_ci snd_config_delete(top); 4625d5ac70f0Sopenharmony_ci top = NULL; 4626d5ac70f0Sopenharmony_ci } 4627d5ac70f0Sopenharmony_ci err = snd_config_top(&top); 4628d5ac70f0Sopenharmony_ci if (err < 0) 4629d5ac70f0Sopenharmony_ci goto _end; 4630d5ac70f0Sopenharmony_ci if (!local) 4631d5ac70f0Sopenharmony_ci goto _skip; 4632d5ac70f0Sopenharmony_ci for (k = 0; k < local->count; ++k) { 4633d5ac70f0Sopenharmony_ci snd_input_t *in; 4634d5ac70f0Sopenharmony_ci err = snd_input_stdio_open(&in, local->finfo[k].name, "r"); 4635d5ac70f0Sopenharmony_ci if (err >= 0) { 4636d5ac70f0Sopenharmony_ci err = snd_config_load(top, in); 4637d5ac70f0Sopenharmony_ci snd_input_close(in); 4638d5ac70f0Sopenharmony_ci if (err < 0) { 4639d5ac70f0Sopenharmony_ci SNDERR("%s may be old or corrupted: consider to remove or fix it", local->finfo[k].name); 4640d5ac70f0Sopenharmony_ci goto _end; 4641d5ac70f0Sopenharmony_ci } 4642d5ac70f0Sopenharmony_ci } else { 4643d5ac70f0Sopenharmony_ci SNDERR("cannot access file %s", local->finfo[k].name); 4644d5ac70f0Sopenharmony_ci } 4645d5ac70f0Sopenharmony_ci } 4646d5ac70f0Sopenharmony_ci _skip: 4647d5ac70f0Sopenharmony_ci err = snd_config_hooks(top, NULL); 4648d5ac70f0Sopenharmony_ci if (err < 0) { 4649d5ac70f0Sopenharmony_ci SNDERR("hooks failed, removing configuration"); 4650d5ac70f0Sopenharmony_ci goto _end; 4651d5ac70f0Sopenharmony_ci } 4652d5ac70f0Sopenharmony_ci *_top = top; 4653d5ac70f0Sopenharmony_ci *_update = local; 4654d5ac70f0Sopenharmony_ci return 1; 4655d5ac70f0Sopenharmony_ci} 4656d5ac70f0Sopenharmony_ci 4657d5ac70f0Sopenharmony_ci/** 4658d5ac70f0Sopenharmony_ci * \brief Updates #snd_config by rereading the global configuration files (if needed). 4659d5ac70f0Sopenharmony_ci * \return 0 if #snd_config was up to date, 1 if #snd_config was 4660d5ac70f0Sopenharmony_ci * updated, otherwise a negative error code. 4661d5ac70f0Sopenharmony_ci * 4662d5ac70f0Sopenharmony_ci * \warning Whenever #snd_config is updated, all string pointers and 4663d5ac70f0Sopenharmony_ci * configuration node handles previously obtained from it may become 4664d5ac70f0Sopenharmony_ci * invalid. 4665d5ac70f0Sopenharmony_ci * For safer operations, use #snd_config_update_ref and release the config 4666d5ac70f0Sopenharmony_ci * via #snd_config_unref. 4667d5ac70f0Sopenharmony_ci * 4668d5ac70f0Sopenharmony_ci * \par Errors: 4669d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or 4670d5ac70f0Sopenharmony_ci * functions. 4671d5ac70f0Sopenharmony_ci * 4672d5ac70f0Sopenharmony_ci * \par Conforming to: 4673d5ac70f0Sopenharmony_ci * LSB 3.2 4674d5ac70f0Sopenharmony_ci */ 4675d5ac70f0Sopenharmony_ciint snd_config_update(void) 4676d5ac70f0Sopenharmony_ci{ 4677d5ac70f0Sopenharmony_ci int err; 4678d5ac70f0Sopenharmony_ci 4679d5ac70f0Sopenharmony_ci snd_config_lock(); 4680d5ac70f0Sopenharmony_ci err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL); 4681d5ac70f0Sopenharmony_ci snd_config_unlock(); 4682d5ac70f0Sopenharmony_ci return err; 4683d5ac70f0Sopenharmony_ci} 4684d5ac70f0Sopenharmony_ci 4685d5ac70f0Sopenharmony_ci/** 4686d5ac70f0Sopenharmony_ci * \brief Updates #snd_config and takes its reference. 4687d5ac70f0Sopenharmony_ci * \return 0 if #snd_config was up to date, 1 if #snd_config was 4688d5ac70f0Sopenharmony_ci * updated, otherwise a negative error code. 4689d5ac70f0Sopenharmony_ci * 4690d5ac70f0Sopenharmony_ci * Unlike #snd_config_update, this function increases a reference counter 4691d5ac70f0Sopenharmony_ci * so that the obtained tree won't be deleted until unreferenced by 4692d5ac70f0Sopenharmony_ci * #snd_config_unref. 4693d5ac70f0Sopenharmony_ci * 4694d5ac70f0Sopenharmony_ci * This function is supposed to be thread-safe. 4695d5ac70f0Sopenharmony_ci */ 4696d5ac70f0Sopenharmony_ciint snd_config_update_ref(snd_config_t **top) 4697d5ac70f0Sopenharmony_ci{ 4698d5ac70f0Sopenharmony_ci int err; 4699d5ac70f0Sopenharmony_ci 4700d5ac70f0Sopenharmony_ci if (top) 4701d5ac70f0Sopenharmony_ci *top = NULL; 4702d5ac70f0Sopenharmony_ci snd_config_lock(); 4703d5ac70f0Sopenharmony_ci err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL); 4704d5ac70f0Sopenharmony_ci if (err >= 0) { 4705d5ac70f0Sopenharmony_ci if (snd_config) { 4706d5ac70f0Sopenharmony_ci if (top) { 4707d5ac70f0Sopenharmony_ci snd_config->refcount++; 4708d5ac70f0Sopenharmony_ci *top = snd_config; 4709d5ac70f0Sopenharmony_ci } 4710d5ac70f0Sopenharmony_ci } else { 4711d5ac70f0Sopenharmony_ci err = -ENODEV; 4712d5ac70f0Sopenharmony_ci } 4713d5ac70f0Sopenharmony_ci } 4714d5ac70f0Sopenharmony_ci snd_config_unlock(); 4715d5ac70f0Sopenharmony_ci return err; 4716d5ac70f0Sopenharmony_ci} 4717d5ac70f0Sopenharmony_ci 4718d5ac70f0Sopenharmony_ci/** 4719d5ac70f0Sopenharmony_ci * \brief Take the reference of the config tree. 4720d5ac70f0Sopenharmony_ci * 4721d5ac70f0Sopenharmony_ci * Increases a reference counter of the given config tree. 4722d5ac70f0Sopenharmony_ci * 4723d5ac70f0Sopenharmony_ci * This function is supposed to be thread-safe. 4724d5ac70f0Sopenharmony_ci */ 4725d5ac70f0Sopenharmony_civoid snd_config_ref(snd_config_t *cfg) 4726d5ac70f0Sopenharmony_ci{ 4727d5ac70f0Sopenharmony_ci snd_config_lock(); 4728d5ac70f0Sopenharmony_ci if (cfg) 4729d5ac70f0Sopenharmony_ci cfg->refcount++; 4730d5ac70f0Sopenharmony_ci snd_config_unlock(); 4731d5ac70f0Sopenharmony_ci} 4732d5ac70f0Sopenharmony_ci 4733d5ac70f0Sopenharmony_ci/** 4734d5ac70f0Sopenharmony_ci * \brief Unreference the config tree. 4735d5ac70f0Sopenharmony_ci * 4736d5ac70f0Sopenharmony_ci * Decreases a reference counter of the given config tree, and eventually 4737d5ac70f0Sopenharmony_ci * deletes the tree if all references are gone. This is the counterpart of 4738d5ac70f0Sopenharmony_ci * #snd_config_unref. 4739d5ac70f0Sopenharmony_ci * 4740d5ac70f0Sopenharmony_ci * Also, the config taken via #snd_config_update_ref must be unreferenced 4741d5ac70f0Sopenharmony_ci * by this function, too. 4742d5ac70f0Sopenharmony_ci * 4743d5ac70f0Sopenharmony_ci * This function is supposed to be thread-safe. 4744d5ac70f0Sopenharmony_ci */ 4745d5ac70f0Sopenharmony_civoid snd_config_unref(snd_config_t *cfg) 4746d5ac70f0Sopenharmony_ci{ 4747d5ac70f0Sopenharmony_ci snd_config_lock(); 4748d5ac70f0Sopenharmony_ci if (cfg) 4749d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 4750d5ac70f0Sopenharmony_ci snd_config_unlock(); 4751d5ac70f0Sopenharmony_ci} 4752d5ac70f0Sopenharmony_ci 4753d5ac70f0Sopenharmony_ci/** 4754d5ac70f0Sopenharmony_ci * \brief Frees a private update structure. 4755d5ac70f0Sopenharmony_ci * \param[in] update The private update structure to free. 4756d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 4757d5ac70f0Sopenharmony_ci */ 4758d5ac70f0Sopenharmony_ciint snd_config_update_free(snd_config_update_t *update) 4759d5ac70f0Sopenharmony_ci{ 4760d5ac70f0Sopenharmony_ci unsigned int k; 4761d5ac70f0Sopenharmony_ci 4762d5ac70f0Sopenharmony_ci assert(update); 4763d5ac70f0Sopenharmony_ci for (k = 0; k < update->count; k++) 4764d5ac70f0Sopenharmony_ci free(update->finfo[k].name); 4765d5ac70f0Sopenharmony_ci free(update->finfo); 4766d5ac70f0Sopenharmony_ci free(update); 4767d5ac70f0Sopenharmony_ci return 0; 4768d5ac70f0Sopenharmony_ci} 4769d5ac70f0Sopenharmony_ci 4770d5ac70f0Sopenharmony_ci/** 4771d5ac70f0Sopenharmony_ci * \brief Frees the global configuration tree in #snd_config. 4772d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code. 4773d5ac70f0Sopenharmony_ci * 4774d5ac70f0Sopenharmony_ci * This functions releases all resources of the global configuration 4775d5ac70f0Sopenharmony_ci * tree, and sets #snd_config to \c NULL. 4776d5ac70f0Sopenharmony_ci * 4777d5ac70f0Sopenharmony_ci * \par Conforming to: 4778d5ac70f0Sopenharmony_ci * LSB 3.2 4779d5ac70f0Sopenharmony_ci */ 4780d5ac70f0Sopenharmony_ciint snd_config_update_free_global(void) 4781d5ac70f0Sopenharmony_ci{ 4782d5ac70f0Sopenharmony_ci snd_config_lock(); 4783d5ac70f0Sopenharmony_ci if (snd_config) 4784d5ac70f0Sopenharmony_ci snd_config_delete(snd_config); 4785d5ac70f0Sopenharmony_ci snd_config = NULL; 4786d5ac70f0Sopenharmony_ci if (snd_config_global_update) 4787d5ac70f0Sopenharmony_ci snd_config_update_free(snd_config_global_update); 4788d5ac70f0Sopenharmony_ci snd_config_global_update = NULL; 4789d5ac70f0Sopenharmony_ci snd_config_unlock(); 4790d5ac70f0Sopenharmony_ci /* FIXME: better to place this in another place... */ 4791d5ac70f0Sopenharmony_ci snd_dlobj_cache_cleanup(); 4792d5ac70f0Sopenharmony_ci 4793d5ac70f0Sopenharmony_ci return 0; 4794d5ac70f0Sopenharmony_ci} 4795d5ac70f0Sopenharmony_ci 4796d5ac70f0Sopenharmony_ci/** 4797d5ac70f0Sopenharmony_ci * \brief Returns an iterator pointing to a node's first child. 4798d5ac70f0Sopenharmony_ci * \param[in] config Handle to a configuration node. 4799d5ac70f0Sopenharmony_ci * \return An iterator pointing to \a config's first child. 4800d5ac70f0Sopenharmony_ci * 4801d5ac70f0Sopenharmony_ci * \a config must be a compound node. 4802d5ac70f0Sopenharmony_ci * 4803d5ac70f0Sopenharmony_ci * The returned iterator is valid if it is not equal to the return value 4804d5ac70f0Sopenharmony_ci * of #snd_config_iterator_end on \a config. 4805d5ac70f0Sopenharmony_ci * 4806d5ac70f0Sopenharmony_ci * Use #snd_config_iterator_entry to get the handle of the node pointed 4807d5ac70f0Sopenharmony_ci * to. 4808d5ac70f0Sopenharmony_ci * 4809d5ac70f0Sopenharmony_ci * \par Conforming to: 4810d5ac70f0Sopenharmony_ci * LSB 3.2 4811d5ac70f0Sopenharmony_ci */ 4812d5ac70f0Sopenharmony_cisnd_config_iterator_t snd_config_iterator_first(const snd_config_t *config) 4813d5ac70f0Sopenharmony_ci{ 4814d5ac70f0Sopenharmony_ci assert(config->type == SND_CONFIG_TYPE_COMPOUND); 4815d5ac70f0Sopenharmony_ci return config->u.compound.fields.next; 4816d5ac70f0Sopenharmony_ci} 4817d5ac70f0Sopenharmony_ci 4818d5ac70f0Sopenharmony_ci/** 4819d5ac70f0Sopenharmony_ci * \brief Returns an iterator pointing to the next sibling. 4820d5ac70f0Sopenharmony_ci * \param[in] iterator An iterator pointing to a child configuration node. 4821d5ac70f0Sopenharmony_ci * \return An iterator pointing to the next sibling of \a iterator. 4822d5ac70f0Sopenharmony_ci * 4823d5ac70f0Sopenharmony_ci * The returned iterator is valid if it is not equal to the return value 4824d5ac70f0Sopenharmony_ci * of #snd_config_iterator_end on the node's parent. 4825d5ac70f0Sopenharmony_ci * 4826d5ac70f0Sopenharmony_ci * Use #snd_config_iterator_entry to get the handle of the node pointed 4827d5ac70f0Sopenharmony_ci * to. 4828d5ac70f0Sopenharmony_ci * 4829d5ac70f0Sopenharmony_ci * \par Conforming to: 4830d5ac70f0Sopenharmony_ci * LSB 3.2 4831d5ac70f0Sopenharmony_ci */ 4832d5ac70f0Sopenharmony_cisnd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator) 4833d5ac70f0Sopenharmony_ci{ 4834d5ac70f0Sopenharmony_ci return iterator->next; 4835d5ac70f0Sopenharmony_ci} 4836d5ac70f0Sopenharmony_ci 4837d5ac70f0Sopenharmony_ci/** 4838d5ac70f0Sopenharmony_ci * \brief Returns an iterator that ends a node's children list. 4839d5ac70f0Sopenharmony_ci * \param[in] config Handle to a configuration node. 4840d5ac70f0Sopenharmony_ci * \return An iterator that indicates the end of \a config's children list. 4841d5ac70f0Sopenharmony_ci * 4842d5ac70f0Sopenharmony_ci * \a config must be a compound node. 4843d5ac70f0Sopenharmony_ci * 4844d5ac70f0Sopenharmony_ci * The return value can be understood as pointing past the last child of 4845d5ac70f0Sopenharmony_ci * \a config. 4846d5ac70f0Sopenharmony_ci * 4847d5ac70f0Sopenharmony_ci * \par Conforming to: 4848d5ac70f0Sopenharmony_ci * LSB 3.2 4849d5ac70f0Sopenharmony_ci */ 4850d5ac70f0Sopenharmony_cisnd_config_iterator_t snd_config_iterator_end(const snd_config_t *config) 4851d5ac70f0Sopenharmony_ci{ 4852d5ac70f0Sopenharmony_ci assert(config->type == SND_CONFIG_TYPE_COMPOUND); 4853d5ac70f0Sopenharmony_ci return (const snd_config_iterator_t)&config->u.compound.fields; 4854d5ac70f0Sopenharmony_ci} 4855d5ac70f0Sopenharmony_ci 4856d5ac70f0Sopenharmony_ci/** 4857d5ac70f0Sopenharmony_ci * \brief Returns the configuration node handle pointed to by an iterator. 4858d5ac70f0Sopenharmony_ci * \param[in] iterator A configuration node iterator. 4859d5ac70f0Sopenharmony_ci * \return The configuration node handle pointed to by \a iterator. 4860d5ac70f0Sopenharmony_ci * 4861d5ac70f0Sopenharmony_ci * \par Conforming to: 4862d5ac70f0Sopenharmony_ci * LSB 3.2 4863d5ac70f0Sopenharmony_ci */ 4864d5ac70f0Sopenharmony_cisnd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator) 4865d5ac70f0Sopenharmony_ci{ 4866d5ac70f0Sopenharmony_ci return list_entry(iterator, snd_config_t, list); 4867d5ac70f0Sopenharmony_ci} 4868d5ac70f0Sopenharmony_ci 4869d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 4870d5ac70f0Sopenharmony_citypedef enum _snd_config_walk_pass { 4871d5ac70f0Sopenharmony_ci SND_CONFIG_WALK_PASS_PRE, 4872d5ac70f0Sopenharmony_ci SND_CONFIG_WALK_PASS_POST, 4873d5ac70f0Sopenharmony_ci SND_CONFIG_WALK_PASS_LEAF, 4874d5ac70f0Sopenharmony_ci} snd_config_walk_pass_t; 4875d5ac70f0Sopenharmony_ci#endif 4876d5ac70f0Sopenharmony_ci 4877d5ac70f0Sopenharmony_ci/* Return 1 if node needs to be attached to parent */ 4878d5ac70f0Sopenharmony_ci/* Return 2 if compound is replaced with standard node */ 4879d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 4880d5ac70f0Sopenharmony_citypedef int (*snd_config_walk_callback_t)(snd_config_t *src, 4881d5ac70f0Sopenharmony_ci snd_config_t *root, 4882d5ac70f0Sopenharmony_ci snd_config_t **dst, 4883d5ac70f0Sopenharmony_ci snd_config_walk_pass_t pass, 4884d5ac70f0Sopenharmony_ci snd_config_expand_fcn_t fcn, 4885d5ac70f0Sopenharmony_ci void *private_data); 4886d5ac70f0Sopenharmony_ci#endif 4887d5ac70f0Sopenharmony_ci 4888d5ac70f0Sopenharmony_cistatic int snd_config_walk(snd_config_t *src, 4889d5ac70f0Sopenharmony_ci snd_config_t *root, 4890d5ac70f0Sopenharmony_ci snd_config_t **dst, 4891d5ac70f0Sopenharmony_ci snd_config_walk_callback_t callback, 4892d5ac70f0Sopenharmony_ci snd_config_expand_fcn_t fcn, 4893d5ac70f0Sopenharmony_ci void *private_data) 4894d5ac70f0Sopenharmony_ci{ 4895d5ac70f0Sopenharmony_ci int err; 4896d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 4897d5ac70f0Sopenharmony_ci 4898d5ac70f0Sopenharmony_ci switch (snd_config_get_type(src)) { 4899d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_COMPOUND: 4900d5ac70f0Sopenharmony_ci err = callback(src, root, dst, SND_CONFIG_WALK_PASS_PRE, fcn, private_data); 4901d5ac70f0Sopenharmony_ci if (err <= 0) 4902d5ac70f0Sopenharmony_ci return err; 4903d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, src) { 4904d5ac70f0Sopenharmony_ci snd_config_t *s = snd_config_iterator_entry(i); 4905d5ac70f0Sopenharmony_ci snd_config_t *d = NULL; 4906d5ac70f0Sopenharmony_ci 4907d5ac70f0Sopenharmony_ci err = snd_config_walk(s, root, (dst && *dst) ? &d : NULL, 4908d5ac70f0Sopenharmony_ci callback, fcn, private_data); 4909d5ac70f0Sopenharmony_ci if (err < 0) 4910d5ac70f0Sopenharmony_ci goto _error; 4911d5ac70f0Sopenharmony_ci if (err && d) { 4912d5ac70f0Sopenharmony_ci err = snd_config_add(*dst, d); 4913d5ac70f0Sopenharmony_ci if (err < 0) 4914d5ac70f0Sopenharmony_ci goto _error; 4915d5ac70f0Sopenharmony_ci } 4916d5ac70f0Sopenharmony_ci } 4917d5ac70f0Sopenharmony_ci err = callback(src, root, dst, SND_CONFIG_WALK_PASS_POST, fcn, private_data); 4918d5ac70f0Sopenharmony_ci if (err <= 0) { 4919d5ac70f0Sopenharmony_ci _error: 4920d5ac70f0Sopenharmony_ci if (dst && *dst) 4921d5ac70f0Sopenharmony_ci snd_config_delete(*dst); 4922d5ac70f0Sopenharmony_ci } 4923d5ac70f0Sopenharmony_ci break; 4924d5ac70f0Sopenharmony_ci default: 4925d5ac70f0Sopenharmony_ci err = callback(src, root, dst, SND_CONFIG_WALK_PASS_LEAF, fcn, private_data); 4926d5ac70f0Sopenharmony_ci break; 4927d5ac70f0Sopenharmony_ci } 4928d5ac70f0Sopenharmony_ci return err; 4929d5ac70f0Sopenharmony_ci} 4930d5ac70f0Sopenharmony_ci 4931d5ac70f0Sopenharmony_cistatic int _snd_config_copy(snd_config_t *src, 4932d5ac70f0Sopenharmony_ci snd_config_t *root ATTRIBUTE_UNUSED, 4933d5ac70f0Sopenharmony_ci snd_config_t **dst, 4934d5ac70f0Sopenharmony_ci snd_config_walk_pass_t pass, 4935d5ac70f0Sopenharmony_ci snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED, 4936d5ac70f0Sopenharmony_ci void *private_data ATTRIBUTE_UNUSED) 4937d5ac70f0Sopenharmony_ci{ 4938d5ac70f0Sopenharmony_ci int err; 4939d5ac70f0Sopenharmony_ci const char *id = src->id; 4940d5ac70f0Sopenharmony_ci snd_config_type_t type = snd_config_get_type(src); 4941d5ac70f0Sopenharmony_ci switch (pass) { 4942d5ac70f0Sopenharmony_ci case SND_CONFIG_WALK_PASS_PRE: 4943d5ac70f0Sopenharmony_ci err = snd_config_make_compound(dst, id, src->u.compound.join); 4944d5ac70f0Sopenharmony_ci if (err < 0) 4945d5ac70f0Sopenharmony_ci return err; 4946d5ac70f0Sopenharmony_ci break; 4947d5ac70f0Sopenharmony_ci case SND_CONFIG_WALK_PASS_LEAF: 4948d5ac70f0Sopenharmony_ci err = snd_config_make(dst, id, type); 4949d5ac70f0Sopenharmony_ci if (err < 0) 4950d5ac70f0Sopenharmony_ci return err; 4951d5ac70f0Sopenharmony_ci switch (type) { 4952d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER: 4953d5ac70f0Sopenharmony_ci { 4954d5ac70f0Sopenharmony_ci long v; 4955d5ac70f0Sopenharmony_ci err = snd_config_get_integer(src, &v); 4956d5ac70f0Sopenharmony_ci assert(err >= 0); 4957d5ac70f0Sopenharmony_ci snd_config_set_integer(*dst, v); 4958d5ac70f0Sopenharmony_ci break; 4959d5ac70f0Sopenharmony_ci } 4960d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER64: 4961d5ac70f0Sopenharmony_ci { 4962d5ac70f0Sopenharmony_ci long long v; 4963d5ac70f0Sopenharmony_ci err = snd_config_get_integer64(src, &v); 4964d5ac70f0Sopenharmony_ci assert(err >= 0); 4965d5ac70f0Sopenharmony_ci snd_config_set_integer64(*dst, v); 4966d5ac70f0Sopenharmony_ci break; 4967d5ac70f0Sopenharmony_ci } 4968d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_REAL: 4969d5ac70f0Sopenharmony_ci { 4970d5ac70f0Sopenharmony_ci double v; 4971d5ac70f0Sopenharmony_ci err = snd_config_get_real(src, &v); 4972d5ac70f0Sopenharmony_ci assert(err >= 0); 4973d5ac70f0Sopenharmony_ci snd_config_set_real(*dst, v); 4974d5ac70f0Sopenharmony_ci break; 4975d5ac70f0Sopenharmony_ci } 4976d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_STRING: 4977d5ac70f0Sopenharmony_ci { 4978d5ac70f0Sopenharmony_ci const char *s; 4979d5ac70f0Sopenharmony_ci err = snd_config_get_string(src, &s); 4980d5ac70f0Sopenharmony_ci assert(err >= 0); 4981d5ac70f0Sopenharmony_ci err = snd_config_set_string(*dst, s); 4982d5ac70f0Sopenharmony_ci if (err < 0) 4983d5ac70f0Sopenharmony_ci return err; 4984d5ac70f0Sopenharmony_ci break; 4985d5ac70f0Sopenharmony_ci } 4986d5ac70f0Sopenharmony_ci default: 4987d5ac70f0Sopenharmony_ci assert(0); 4988d5ac70f0Sopenharmony_ci } 4989d5ac70f0Sopenharmony_ci break; 4990d5ac70f0Sopenharmony_ci default: 4991d5ac70f0Sopenharmony_ci break; 4992d5ac70f0Sopenharmony_ci } 4993d5ac70f0Sopenharmony_ci return 1; 4994d5ac70f0Sopenharmony_ci} 4995d5ac70f0Sopenharmony_ci 4996d5ac70f0Sopenharmony_ci/** 4997d5ac70f0Sopenharmony_ci * \brief Creates a copy of a configuration node. 4998d5ac70f0Sopenharmony_ci * \param[out] dst The function puts the handle to the new configuration 4999d5ac70f0Sopenharmony_ci * node at the address specified by \a dst. 5000d5ac70f0Sopenharmony_ci * \param[in] src Handle to the source configuration node. 5001d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code. 5002d5ac70f0Sopenharmony_ci * 5003d5ac70f0Sopenharmony_ci * This function creates a deep copy, i.e., if \a src is a compound 5004d5ac70f0Sopenharmony_ci * node, all children are copied recursively. 5005d5ac70f0Sopenharmony_ci * 5006d5ac70f0Sopenharmony_ci * \par Errors: 5007d5ac70f0Sopenharmony_ci * <dl> 5008d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory. 5009d5ac70f0Sopenharmony_ci * </dl> 5010d5ac70f0Sopenharmony_ci * 5011d5ac70f0Sopenharmony_ci * \par Conforming to: 5012d5ac70f0Sopenharmony_ci * LSB 3.2 5013d5ac70f0Sopenharmony_ci */ 5014d5ac70f0Sopenharmony_ciint snd_config_copy(snd_config_t **dst, 5015d5ac70f0Sopenharmony_ci snd_config_t *src) 5016d5ac70f0Sopenharmony_ci{ 5017d5ac70f0Sopenharmony_ci return snd_config_walk(src, NULL, dst, _snd_config_copy, NULL, NULL); 5018d5ac70f0Sopenharmony_ci} 5019d5ac70f0Sopenharmony_ci 5020d5ac70f0Sopenharmony_cistatic int _snd_config_expand_vars(snd_config_t **dst, const char *s, void *private_data) 5021d5ac70f0Sopenharmony_ci{ 5022d5ac70f0Sopenharmony_ci snd_config_t *val, *vars = private_data; 5023d5ac70f0Sopenharmony_ci if (snd_config_search(vars, s, &val) < 0) { 5024d5ac70f0Sopenharmony_ci *dst = NULL; 5025d5ac70f0Sopenharmony_ci return 0; 5026d5ac70f0Sopenharmony_ci } 5027d5ac70f0Sopenharmony_ci return snd_config_copy(dst, val); 5028d5ac70f0Sopenharmony_ci} 5029d5ac70f0Sopenharmony_ci 5030d5ac70f0Sopenharmony_cistatic int _snd_config_expand(snd_config_t *src, 5031d5ac70f0Sopenharmony_ci snd_config_t *root ATTRIBUTE_UNUSED, 5032d5ac70f0Sopenharmony_ci snd_config_t **dst, 5033d5ac70f0Sopenharmony_ci snd_config_walk_pass_t pass, 5034d5ac70f0Sopenharmony_ci snd_config_expand_fcn_t fcn, 5035d5ac70f0Sopenharmony_ci void *private_data) 5036d5ac70f0Sopenharmony_ci{ 5037d5ac70f0Sopenharmony_ci int err; 5038d5ac70f0Sopenharmony_ci const char *id = src->id; 5039d5ac70f0Sopenharmony_ci snd_config_type_t type = snd_config_get_type(src); 5040d5ac70f0Sopenharmony_ci switch (pass) { 5041d5ac70f0Sopenharmony_ci case SND_CONFIG_WALK_PASS_PRE: 5042d5ac70f0Sopenharmony_ci { 5043d5ac70f0Sopenharmony_ci if (id && strcmp(id, "@args") == 0) 5044d5ac70f0Sopenharmony_ci return 0; 5045d5ac70f0Sopenharmony_ci err = snd_config_make_compound(dst, id, src->u.compound.join); 5046d5ac70f0Sopenharmony_ci if (err < 0) 5047d5ac70f0Sopenharmony_ci return err; 5048d5ac70f0Sopenharmony_ci break; 5049d5ac70f0Sopenharmony_ci } 5050d5ac70f0Sopenharmony_ci case SND_CONFIG_WALK_PASS_LEAF: 5051d5ac70f0Sopenharmony_ci switch (type) { 5052d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER: 5053d5ac70f0Sopenharmony_ci { 5054d5ac70f0Sopenharmony_ci long v; 5055d5ac70f0Sopenharmony_ci err = snd_config_get_integer(src, &v); 5056d5ac70f0Sopenharmony_ci assert(err >= 0); 5057d5ac70f0Sopenharmony_ci err = snd_config_imake_integer(dst, id, v); 5058d5ac70f0Sopenharmony_ci if (err < 0) 5059d5ac70f0Sopenharmony_ci return err; 5060d5ac70f0Sopenharmony_ci break; 5061d5ac70f0Sopenharmony_ci } 5062d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER64: 5063d5ac70f0Sopenharmony_ci { 5064d5ac70f0Sopenharmony_ci long long v; 5065d5ac70f0Sopenharmony_ci err = snd_config_get_integer64(src, &v); 5066d5ac70f0Sopenharmony_ci assert(err >= 0); 5067d5ac70f0Sopenharmony_ci err = snd_config_imake_integer64(dst, id, v); 5068d5ac70f0Sopenharmony_ci if (err < 0) 5069d5ac70f0Sopenharmony_ci return err; 5070d5ac70f0Sopenharmony_ci break; 5071d5ac70f0Sopenharmony_ci } 5072d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_REAL: 5073d5ac70f0Sopenharmony_ci { 5074d5ac70f0Sopenharmony_ci double v; 5075d5ac70f0Sopenharmony_ci err = snd_config_get_real(src, &v); 5076d5ac70f0Sopenharmony_ci assert(err >= 0); 5077d5ac70f0Sopenharmony_ci err = snd_config_imake_real(dst, id, v); 5078d5ac70f0Sopenharmony_ci if (err < 0) 5079d5ac70f0Sopenharmony_ci return err; 5080d5ac70f0Sopenharmony_ci break; 5081d5ac70f0Sopenharmony_ci } 5082d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_STRING: 5083d5ac70f0Sopenharmony_ci { 5084d5ac70f0Sopenharmony_ci const char *s; 5085d5ac70f0Sopenharmony_ci snd_config_t *vars = private_data; 5086d5ac70f0Sopenharmony_ci snd_config_get_string(src, &s); 5087d5ac70f0Sopenharmony_ci if (s && *s == '$') { 5088d5ac70f0Sopenharmony_ci err = snd_config_evaluate_string(dst, s, fcn, vars); 5089d5ac70f0Sopenharmony_ci if (err < 0) 5090d5ac70f0Sopenharmony_ci return err; 5091d5ac70f0Sopenharmony_ci if (*dst == NULL) 5092d5ac70f0Sopenharmony_ci return 0; 5093d5ac70f0Sopenharmony_ci err = snd_config_set_id(*dst, id); 5094d5ac70f0Sopenharmony_ci if (err < 0) { 5095d5ac70f0Sopenharmony_ci snd_config_delete(*dst); 5096d5ac70f0Sopenharmony_ci return err; 5097d5ac70f0Sopenharmony_ci } 5098d5ac70f0Sopenharmony_ci } else { 5099d5ac70f0Sopenharmony_ci err = snd_config_imake_string(dst, id, s); 5100d5ac70f0Sopenharmony_ci if (err < 0) 5101d5ac70f0Sopenharmony_ci return err; 5102d5ac70f0Sopenharmony_ci } 5103d5ac70f0Sopenharmony_ci break; 5104d5ac70f0Sopenharmony_ci } 5105d5ac70f0Sopenharmony_ci default: 5106d5ac70f0Sopenharmony_ci assert(0); 5107d5ac70f0Sopenharmony_ci } 5108d5ac70f0Sopenharmony_ci break; 5109d5ac70f0Sopenharmony_ci default: 5110d5ac70f0Sopenharmony_ci break; 5111d5ac70f0Sopenharmony_ci } 5112d5ac70f0Sopenharmony_ci return 1; 5113d5ac70f0Sopenharmony_ci} 5114d5ac70f0Sopenharmony_ci 5115d5ac70f0Sopenharmony_cistatic int _snd_config_evaluate(snd_config_t *src, 5116d5ac70f0Sopenharmony_ci snd_config_t *root, 5117d5ac70f0Sopenharmony_ci snd_config_t **dst ATTRIBUTE_UNUSED, 5118d5ac70f0Sopenharmony_ci snd_config_walk_pass_t pass, 5119d5ac70f0Sopenharmony_ci snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED, 5120d5ac70f0Sopenharmony_ci void *private_data) 5121d5ac70f0Sopenharmony_ci{ 5122d5ac70f0Sopenharmony_ci int err; 5123d5ac70f0Sopenharmony_ci if (pass == SND_CONFIG_WALK_PASS_PRE) { 5124d5ac70f0Sopenharmony_ci char *buf = NULL, errbuf[256]; 5125d5ac70f0Sopenharmony_ci const char *lib = NULL, *func_name = NULL; 5126d5ac70f0Sopenharmony_ci const char *str; 5127d5ac70f0Sopenharmony_ci int (*func)(snd_config_t **dst, snd_config_t *root, 5128d5ac70f0Sopenharmony_ci snd_config_t *src, snd_config_t *private_data) = NULL; 5129d5ac70f0Sopenharmony_ci void *h = NULL; 5130d5ac70f0Sopenharmony_ci snd_config_t *c, *func_conf = NULL; 5131d5ac70f0Sopenharmony_ci err = snd_config_search(src, "@func", &c); 5132d5ac70f0Sopenharmony_ci if (err < 0) 5133d5ac70f0Sopenharmony_ci return 1; 5134d5ac70f0Sopenharmony_ci err = snd_config_get_string(c, &str); 5135d5ac70f0Sopenharmony_ci if (err < 0) { 5136d5ac70f0Sopenharmony_ci SNDERR("Invalid type for @func"); 5137d5ac70f0Sopenharmony_ci return err; 5138d5ac70f0Sopenharmony_ci } 5139d5ac70f0Sopenharmony_ci assert(str); 5140d5ac70f0Sopenharmony_ci err = snd_config_search_definition(root, "func", str, &func_conf); 5141d5ac70f0Sopenharmony_ci if (err >= 0) { 5142d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 5143d5ac70f0Sopenharmony_ci if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) { 5144d5ac70f0Sopenharmony_ci SNDERR("Invalid type for func %s definition", str); 5145d5ac70f0Sopenharmony_ci err = -EINVAL; 5146d5ac70f0Sopenharmony_ci goto _err; 5147d5ac70f0Sopenharmony_ci } 5148d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, func_conf) { 5149d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 5150d5ac70f0Sopenharmony_ci const char *id = n->id; 5151d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0) 5152d5ac70f0Sopenharmony_ci continue; 5153d5ac70f0Sopenharmony_ci if (strcmp(id, "lib") == 0) { 5154d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &lib); 5155d5ac70f0Sopenharmony_ci if (err < 0) { 5156d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 5157d5ac70f0Sopenharmony_ci goto _err; 5158d5ac70f0Sopenharmony_ci } 5159d5ac70f0Sopenharmony_ci continue; 5160d5ac70f0Sopenharmony_ci } 5161d5ac70f0Sopenharmony_ci if (strcmp(id, "func") == 0) { 5162d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &func_name); 5163d5ac70f0Sopenharmony_ci if (err < 0) { 5164d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 5165d5ac70f0Sopenharmony_ci goto _err; 5166d5ac70f0Sopenharmony_ci } 5167d5ac70f0Sopenharmony_ci continue; 5168d5ac70f0Sopenharmony_ci } 5169d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 5170d5ac70f0Sopenharmony_ci } 5171d5ac70f0Sopenharmony_ci } 5172d5ac70f0Sopenharmony_ci if (!func_name) { 5173d5ac70f0Sopenharmony_ci int len = 9 + strlen(str) + 1; 5174d5ac70f0Sopenharmony_ci buf = malloc(len); 5175d5ac70f0Sopenharmony_ci if (! buf) { 5176d5ac70f0Sopenharmony_ci err = -ENOMEM; 5177d5ac70f0Sopenharmony_ci goto _err; 5178d5ac70f0Sopenharmony_ci } 5179d5ac70f0Sopenharmony_ci snprintf(buf, len, "snd_func_%s", str); 5180d5ac70f0Sopenharmony_ci buf[len-1] = '\0'; 5181d5ac70f0Sopenharmony_ci func_name = buf; 5182d5ac70f0Sopenharmony_ci } 5183d5ac70f0Sopenharmony_ci h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); 5184d5ac70f0Sopenharmony_ci if (h) 5185d5ac70f0Sopenharmony_ci func = snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_EVALUATE)); 5186d5ac70f0Sopenharmony_ci err = 0; 5187d5ac70f0Sopenharmony_ci if (!h) { 5188d5ac70f0Sopenharmony_ci SNDERR("Cannot open shared library %s (%s)", lib, errbuf); 5189d5ac70f0Sopenharmony_ci err = -ENOENT; 5190d5ac70f0Sopenharmony_ci goto _errbuf; 5191d5ac70f0Sopenharmony_ci } else if (!func) { 5192d5ac70f0Sopenharmony_ci SNDERR("symbol %s is not defined inside %s", func_name, lib); 5193d5ac70f0Sopenharmony_ci snd_dlclose(h); 5194d5ac70f0Sopenharmony_ci err = -ENXIO; 5195d5ac70f0Sopenharmony_ci goto _errbuf; 5196d5ac70f0Sopenharmony_ci } 5197d5ac70f0Sopenharmony_ci _err: 5198d5ac70f0Sopenharmony_ci if (func_conf) 5199d5ac70f0Sopenharmony_ci snd_config_delete(func_conf); 5200d5ac70f0Sopenharmony_ci if (err >= 0) { 5201d5ac70f0Sopenharmony_ci snd_config_t *eval; 5202d5ac70f0Sopenharmony_ci err = func(&eval, root, src, private_data); 5203d5ac70f0Sopenharmony_ci if (err < 0) 5204d5ac70f0Sopenharmony_ci SNDERR("function %s returned error: %s", func_name, snd_strerror(err)); 5205d5ac70f0Sopenharmony_ci snd_dlclose(h); 5206d5ac70f0Sopenharmony_ci if (err >= 0 && eval) 5207d5ac70f0Sopenharmony_ci err = snd_config_substitute(src, eval); 5208d5ac70f0Sopenharmony_ci } 5209d5ac70f0Sopenharmony_ci _errbuf: 5210d5ac70f0Sopenharmony_ci free(buf); 5211d5ac70f0Sopenharmony_ci if (err < 0) 5212d5ac70f0Sopenharmony_ci return err; 5213d5ac70f0Sopenharmony_ci return 0; 5214d5ac70f0Sopenharmony_ci } 5215d5ac70f0Sopenharmony_ci return 1; 5216d5ac70f0Sopenharmony_ci} 5217d5ac70f0Sopenharmony_ci 5218d5ac70f0Sopenharmony_ci/** 5219d5ac70f0Sopenharmony_ci * \brief Evaluates a configuration node at runtime. 5220d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the source configuration node. 5221d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root of the source configuration. 5222d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data node for runtime evaluation. 5223d5ac70f0Sopenharmony_ci * \param result Must be \c NULL. 5224d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code. 5225d5ac70f0Sopenharmony_ci * 5226d5ac70f0Sopenharmony_ci * This function evaluates any functions (\c \@func) in \a config and 5227d5ac70f0Sopenharmony_ci * replaces those nodes with the respective function results. 5228d5ac70f0Sopenharmony_ci */ 5229d5ac70f0Sopenharmony_ciint snd_config_evaluate(snd_config_t *config, snd_config_t *root, 5230d5ac70f0Sopenharmony_ci snd_config_t *private_data, snd_config_t **result) 5231d5ac70f0Sopenharmony_ci{ 5232d5ac70f0Sopenharmony_ci /* FIXME: Only in place evaluation is currently implemented */ 5233d5ac70f0Sopenharmony_ci assert(result == NULL); 5234d5ac70f0Sopenharmony_ci return snd_config_walk(config, root, result, _snd_config_evaluate, NULL, private_data); 5235d5ac70f0Sopenharmony_ci} 5236d5ac70f0Sopenharmony_ci 5237d5ac70f0Sopenharmony_cistatic int load_defaults(snd_config_t *subs, snd_config_t *defs) 5238d5ac70f0Sopenharmony_ci{ 5239d5ac70f0Sopenharmony_ci snd_config_iterator_t d, dnext; 5240d5ac70f0Sopenharmony_ci snd_config_for_each(d, dnext, defs) { 5241d5ac70f0Sopenharmony_ci snd_config_t *def = snd_config_iterator_entry(d); 5242d5ac70f0Sopenharmony_ci snd_config_iterator_t f, fnext; 5243d5ac70f0Sopenharmony_ci if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) 5244d5ac70f0Sopenharmony_ci continue; 5245d5ac70f0Sopenharmony_ci snd_config_for_each(f, fnext, def) { 5246d5ac70f0Sopenharmony_ci snd_config_t *fld = snd_config_iterator_entry(f); 5247d5ac70f0Sopenharmony_ci const char *id = fld->id; 5248d5ac70f0Sopenharmony_ci if (strcmp(id, "type") == 0) 5249d5ac70f0Sopenharmony_ci continue; 5250d5ac70f0Sopenharmony_ci if (strcmp(id, "default") == 0) { 5251d5ac70f0Sopenharmony_ci snd_config_t *deflt; 5252d5ac70f0Sopenharmony_ci int err; 5253d5ac70f0Sopenharmony_ci err = snd_config_copy(&deflt, fld); 5254d5ac70f0Sopenharmony_ci if (err < 0) 5255d5ac70f0Sopenharmony_ci return err; 5256d5ac70f0Sopenharmony_ci err = snd_config_set_id(deflt, def->id); 5257d5ac70f0Sopenharmony_ci if (err < 0) { 5258d5ac70f0Sopenharmony_ci snd_config_delete(deflt); 5259d5ac70f0Sopenharmony_ci return err; 5260d5ac70f0Sopenharmony_ci } 5261d5ac70f0Sopenharmony_ci err = snd_config_add(subs, deflt); 5262d5ac70f0Sopenharmony_ci if (err < 0) { 5263d5ac70f0Sopenharmony_ci snd_config_delete(deflt); 5264d5ac70f0Sopenharmony_ci return err; 5265d5ac70f0Sopenharmony_ci } 5266d5ac70f0Sopenharmony_ci continue; 5267d5ac70f0Sopenharmony_ci } 5268d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 5269d5ac70f0Sopenharmony_ci return -EINVAL; 5270d5ac70f0Sopenharmony_ci } 5271d5ac70f0Sopenharmony_ci } 5272d5ac70f0Sopenharmony_ci return 0; 5273d5ac70f0Sopenharmony_ci} 5274d5ac70f0Sopenharmony_ci 5275d5ac70f0Sopenharmony_cistatic void skip_blank(const char **ptr) 5276d5ac70f0Sopenharmony_ci{ 5277d5ac70f0Sopenharmony_ci while (1) { 5278d5ac70f0Sopenharmony_ci switch (**ptr) { 5279d5ac70f0Sopenharmony_ci case ' ': 5280d5ac70f0Sopenharmony_ci case '\f': 5281d5ac70f0Sopenharmony_ci case '\t': 5282d5ac70f0Sopenharmony_ci case '\n': 5283d5ac70f0Sopenharmony_ci case '\r': 5284d5ac70f0Sopenharmony_ci break; 5285d5ac70f0Sopenharmony_ci default: 5286d5ac70f0Sopenharmony_ci return; 5287d5ac70f0Sopenharmony_ci } 5288d5ac70f0Sopenharmony_ci (*ptr)++; 5289d5ac70f0Sopenharmony_ci } 5290d5ac70f0Sopenharmony_ci} 5291d5ac70f0Sopenharmony_ci 5292d5ac70f0Sopenharmony_cistatic int parse_char(const char **ptr) 5293d5ac70f0Sopenharmony_ci{ 5294d5ac70f0Sopenharmony_ci int c; 5295d5ac70f0Sopenharmony_ci assert(**ptr == '\\'); 5296d5ac70f0Sopenharmony_ci (*ptr)++; 5297d5ac70f0Sopenharmony_ci c = **ptr; 5298d5ac70f0Sopenharmony_ci switch (c) { 5299d5ac70f0Sopenharmony_ci case 'n': 5300d5ac70f0Sopenharmony_ci c = '\n'; 5301d5ac70f0Sopenharmony_ci break; 5302d5ac70f0Sopenharmony_ci case 't': 5303d5ac70f0Sopenharmony_ci c = '\t'; 5304d5ac70f0Sopenharmony_ci break; 5305d5ac70f0Sopenharmony_ci case 'v': 5306d5ac70f0Sopenharmony_ci c = '\v'; 5307d5ac70f0Sopenharmony_ci break; 5308d5ac70f0Sopenharmony_ci case 'b': 5309d5ac70f0Sopenharmony_ci c = '\b'; 5310d5ac70f0Sopenharmony_ci break; 5311d5ac70f0Sopenharmony_ci case 'r': 5312d5ac70f0Sopenharmony_ci c = '\r'; 5313d5ac70f0Sopenharmony_ci break; 5314d5ac70f0Sopenharmony_ci case 'f': 5315d5ac70f0Sopenharmony_ci c = '\f'; 5316d5ac70f0Sopenharmony_ci break; 5317d5ac70f0Sopenharmony_ci case '0': case '1': case '2': case '3': 5318d5ac70f0Sopenharmony_ci case '4': case '5': case '6': case '7': 5319d5ac70f0Sopenharmony_ci { 5320d5ac70f0Sopenharmony_ci int num = c - '0'; 5321d5ac70f0Sopenharmony_ci int i = 1; 5322d5ac70f0Sopenharmony_ci (*ptr)++; 5323d5ac70f0Sopenharmony_ci do { 5324d5ac70f0Sopenharmony_ci c = **ptr; 5325d5ac70f0Sopenharmony_ci if (c < '0' || c > '7') 5326d5ac70f0Sopenharmony_ci break; 5327d5ac70f0Sopenharmony_ci num = num * 8 + c - '0'; 5328d5ac70f0Sopenharmony_ci i++; 5329d5ac70f0Sopenharmony_ci (*ptr)++; 5330d5ac70f0Sopenharmony_ci } while (i < 3); 5331d5ac70f0Sopenharmony_ci return num; 5332d5ac70f0Sopenharmony_ci } 5333d5ac70f0Sopenharmony_ci default: 5334d5ac70f0Sopenharmony_ci break; 5335d5ac70f0Sopenharmony_ci } 5336d5ac70f0Sopenharmony_ci (*ptr)++; 5337d5ac70f0Sopenharmony_ci return c; 5338d5ac70f0Sopenharmony_ci} 5339d5ac70f0Sopenharmony_ci 5340d5ac70f0Sopenharmony_cistatic int parse_id(const char **ptr) 5341d5ac70f0Sopenharmony_ci{ 5342d5ac70f0Sopenharmony_ci if (!**ptr) 5343d5ac70f0Sopenharmony_ci return -EINVAL; 5344d5ac70f0Sopenharmony_ci while (1) { 5345d5ac70f0Sopenharmony_ci switch (**ptr) { 5346d5ac70f0Sopenharmony_ci case '\f': 5347d5ac70f0Sopenharmony_ci case '\t': 5348d5ac70f0Sopenharmony_ci case '\n': 5349d5ac70f0Sopenharmony_ci case '\r': 5350d5ac70f0Sopenharmony_ci case ',': 5351d5ac70f0Sopenharmony_ci case '=': 5352d5ac70f0Sopenharmony_ci case '\0': 5353d5ac70f0Sopenharmony_ci return 0; 5354d5ac70f0Sopenharmony_ci default: 5355d5ac70f0Sopenharmony_ci break; 5356d5ac70f0Sopenharmony_ci } 5357d5ac70f0Sopenharmony_ci (*ptr)++; 5358d5ac70f0Sopenharmony_ci } 5359d5ac70f0Sopenharmony_ci} 5360d5ac70f0Sopenharmony_ci 5361d5ac70f0Sopenharmony_cistatic int parse_string(const char **ptr, char **val) 5362d5ac70f0Sopenharmony_ci{ 5363d5ac70f0Sopenharmony_ci const size_t bufsize = 256; 5364d5ac70f0Sopenharmony_ci char _buf[bufsize]; 5365d5ac70f0Sopenharmony_ci char *buf = _buf; 5366d5ac70f0Sopenharmony_ci size_t alloc = bufsize; 5367d5ac70f0Sopenharmony_ci char delim = **ptr; 5368d5ac70f0Sopenharmony_ci size_t idx = 0; 5369d5ac70f0Sopenharmony_ci (*ptr)++; 5370d5ac70f0Sopenharmony_ci while (1) { 5371d5ac70f0Sopenharmony_ci int c = **ptr; 5372d5ac70f0Sopenharmony_ci switch (c) { 5373d5ac70f0Sopenharmony_ci case '\0': 5374d5ac70f0Sopenharmony_ci SNDERR("Unterminated string"); 5375d5ac70f0Sopenharmony_ci return -EINVAL; 5376d5ac70f0Sopenharmony_ci case '\\': 5377d5ac70f0Sopenharmony_ci c = parse_char(ptr); 5378d5ac70f0Sopenharmony_ci if (c < 0) { 5379d5ac70f0Sopenharmony_ci if (alloc > bufsize) 5380d5ac70f0Sopenharmony_ci free(buf); 5381d5ac70f0Sopenharmony_ci return c; 5382d5ac70f0Sopenharmony_ci } 5383d5ac70f0Sopenharmony_ci break; 5384d5ac70f0Sopenharmony_ci default: 5385d5ac70f0Sopenharmony_ci (*ptr)++; 5386d5ac70f0Sopenharmony_ci if (c == delim) { 5387d5ac70f0Sopenharmony_ci *val = malloc(idx + 1); 5388d5ac70f0Sopenharmony_ci if (!*val) 5389d5ac70f0Sopenharmony_ci return -ENOMEM; 5390d5ac70f0Sopenharmony_ci memcpy(*val, buf, idx); 5391d5ac70f0Sopenharmony_ci (*val)[idx] = 0; 5392d5ac70f0Sopenharmony_ci if (alloc > bufsize) 5393d5ac70f0Sopenharmony_ci free(buf); 5394d5ac70f0Sopenharmony_ci return 0; 5395d5ac70f0Sopenharmony_ci } 5396d5ac70f0Sopenharmony_ci } 5397d5ac70f0Sopenharmony_ci if (idx >= alloc) { 5398d5ac70f0Sopenharmony_ci size_t old_alloc = alloc; 5399d5ac70f0Sopenharmony_ci alloc *= 2; 5400d5ac70f0Sopenharmony_ci if (old_alloc == bufsize) { 5401d5ac70f0Sopenharmony_ci buf = malloc(alloc); 5402d5ac70f0Sopenharmony_ci if (!buf) 5403d5ac70f0Sopenharmony_ci return -ENOMEM; 5404d5ac70f0Sopenharmony_ci memcpy(buf, _buf, old_alloc); 5405d5ac70f0Sopenharmony_ci } else { 5406d5ac70f0Sopenharmony_ci char *buf2 = realloc(buf, alloc); 5407d5ac70f0Sopenharmony_ci if (!buf2) { 5408d5ac70f0Sopenharmony_ci free(buf); 5409d5ac70f0Sopenharmony_ci return -ENOMEM; 5410d5ac70f0Sopenharmony_ci } 5411d5ac70f0Sopenharmony_ci buf = buf2; 5412d5ac70f0Sopenharmony_ci } 5413d5ac70f0Sopenharmony_ci } 5414d5ac70f0Sopenharmony_ci buf[idx++] = c; 5415d5ac70f0Sopenharmony_ci } 5416d5ac70f0Sopenharmony_ci} 5417d5ac70f0Sopenharmony_ci 5418d5ac70f0Sopenharmony_ci 5419d5ac70f0Sopenharmony_ci/* Parse var=val or val */ 5420d5ac70f0Sopenharmony_cistatic int parse_arg(const char **ptr, unsigned int *varlen, char **val) 5421d5ac70f0Sopenharmony_ci{ 5422d5ac70f0Sopenharmony_ci const char *str; 5423d5ac70f0Sopenharmony_ci int err, vallen; 5424d5ac70f0Sopenharmony_ci skip_blank(ptr); 5425d5ac70f0Sopenharmony_ci str = *ptr; 5426d5ac70f0Sopenharmony_ci if (*str == '"' || *str == '\'') { 5427d5ac70f0Sopenharmony_ci err = parse_string(ptr, val); 5428d5ac70f0Sopenharmony_ci if (err < 0) 5429d5ac70f0Sopenharmony_ci return err; 5430d5ac70f0Sopenharmony_ci *varlen = 0; 5431d5ac70f0Sopenharmony_ci return 0; 5432d5ac70f0Sopenharmony_ci } 5433d5ac70f0Sopenharmony_ci err = parse_id(ptr); 5434d5ac70f0Sopenharmony_ci if (err < 0) 5435d5ac70f0Sopenharmony_ci return err; 5436d5ac70f0Sopenharmony_ci vallen = *ptr - str; 5437d5ac70f0Sopenharmony_ci skip_blank(ptr); 5438d5ac70f0Sopenharmony_ci if (**ptr != '=') { 5439d5ac70f0Sopenharmony_ci *varlen = 0; 5440d5ac70f0Sopenharmony_ci goto _value; 5441d5ac70f0Sopenharmony_ci } 5442d5ac70f0Sopenharmony_ci *varlen = vallen; 5443d5ac70f0Sopenharmony_ci (*ptr)++; 5444d5ac70f0Sopenharmony_ci skip_blank(ptr); 5445d5ac70f0Sopenharmony_ci str = *ptr; 5446d5ac70f0Sopenharmony_ci if (*str == '"' || *str == '\'') { 5447d5ac70f0Sopenharmony_ci err = parse_string(ptr, val); 5448d5ac70f0Sopenharmony_ci if (err < 0) 5449d5ac70f0Sopenharmony_ci return err; 5450d5ac70f0Sopenharmony_ci return 0; 5451d5ac70f0Sopenharmony_ci } 5452d5ac70f0Sopenharmony_ci err = parse_id(ptr); 5453d5ac70f0Sopenharmony_ci if (err < 0) 5454d5ac70f0Sopenharmony_ci return err; 5455d5ac70f0Sopenharmony_ci vallen = *ptr - str; 5456d5ac70f0Sopenharmony_ci _value: 5457d5ac70f0Sopenharmony_ci *val = malloc(vallen + 1); 5458d5ac70f0Sopenharmony_ci if (!*val) 5459d5ac70f0Sopenharmony_ci return -ENOMEM; 5460d5ac70f0Sopenharmony_ci memcpy(*val, str, vallen); 5461d5ac70f0Sopenharmony_ci (*val)[vallen] = 0; 5462d5ac70f0Sopenharmony_ci return 0; 5463d5ac70f0Sopenharmony_ci} 5464d5ac70f0Sopenharmony_ci 5465d5ac70f0Sopenharmony_ci 5466d5ac70f0Sopenharmony_ci/* val1, val2, ... 5467d5ac70f0Sopenharmony_ci * var1=val1,var2=val2,... 5468d5ac70f0Sopenharmony_ci * { conf syntax } 5469d5ac70f0Sopenharmony_ci */ 5470d5ac70f0Sopenharmony_cistatic int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) 5471d5ac70f0Sopenharmony_ci{ 5472d5ac70f0Sopenharmony_ci int err; 5473d5ac70f0Sopenharmony_ci int arg = 0; 5474d5ac70f0Sopenharmony_ci if (str == NULL) 5475d5ac70f0Sopenharmony_ci return 0; 5476d5ac70f0Sopenharmony_ci skip_blank(&str); 5477d5ac70f0Sopenharmony_ci if (!*str) 5478d5ac70f0Sopenharmony_ci return 0; 5479d5ac70f0Sopenharmony_ci if (*str == '{') { 5480d5ac70f0Sopenharmony_ci int len = strlen(str); 5481d5ac70f0Sopenharmony_ci snd_input_t *input; 5482d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 5483d5ac70f0Sopenharmony_ci while (1) { 5484d5ac70f0Sopenharmony_ci switch (str[--len]) { 5485d5ac70f0Sopenharmony_ci case ' ': 5486d5ac70f0Sopenharmony_ci case '\f': 5487d5ac70f0Sopenharmony_ci case '\t': 5488d5ac70f0Sopenharmony_ci case '\n': 5489d5ac70f0Sopenharmony_ci case '\r': 5490d5ac70f0Sopenharmony_ci continue; 5491d5ac70f0Sopenharmony_ci default: 5492d5ac70f0Sopenharmony_ci break; 5493d5ac70f0Sopenharmony_ci } 5494d5ac70f0Sopenharmony_ci break; 5495d5ac70f0Sopenharmony_ci } 5496d5ac70f0Sopenharmony_ci if (str[len] != '}') 5497d5ac70f0Sopenharmony_ci return -EINVAL; 5498d5ac70f0Sopenharmony_ci err = snd_input_buffer_open(&input, str + 1, len - 1); 5499d5ac70f0Sopenharmony_ci if (err < 0) 5500d5ac70f0Sopenharmony_ci return err; 5501d5ac70f0Sopenharmony_ci err = snd_config_load_override(subs, input); 5502d5ac70f0Sopenharmony_ci snd_input_close(input); 5503d5ac70f0Sopenharmony_ci if (err < 0) 5504d5ac70f0Sopenharmony_ci return err; 5505d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, subs) { 5506d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 5507d5ac70f0Sopenharmony_ci snd_config_t *d; 5508d5ac70f0Sopenharmony_ci const char *id = n->id; 5509d5ac70f0Sopenharmony_ci err = snd_config_search(defs, id, &d); 5510d5ac70f0Sopenharmony_ci if (err < 0) { 5511d5ac70f0Sopenharmony_ci SNDERR("Unknown parameter %s", id); 5512d5ac70f0Sopenharmony_ci return err; 5513d5ac70f0Sopenharmony_ci } 5514d5ac70f0Sopenharmony_ci } 5515d5ac70f0Sopenharmony_ci return 0; 5516d5ac70f0Sopenharmony_ci } 5517d5ac70f0Sopenharmony_ci 5518d5ac70f0Sopenharmony_ci while (1) { 5519d5ac70f0Sopenharmony_ci char buf[256]; 5520d5ac70f0Sopenharmony_ci const char *var = buf; 5521d5ac70f0Sopenharmony_ci unsigned int varlen; 5522d5ac70f0Sopenharmony_ci snd_config_t *def, *sub, *typ; 5523d5ac70f0Sopenharmony_ci const char *new = str; 5524d5ac70f0Sopenharmony_ci const char *tmp; 5525d5ac70f0Sopenharmony_ci char *val = NULL; 5526d5ac70f0Sopenharmony_ci 5527d5ac70f0Sopenharmony_ci sub = NULL; 5528d5ac70f0Sopenharmony_ci err = parse_arg(&new, &varlen, &val); 5529d5ac70f0Sopenharmony_ci if (err < 0) 5530d5ac70f0Sopenharmony_ci goto _err; 5531d5ac70f0Sopenharmony_ci if (varlen > 0) { 5532d5ac70f0Sopenharmony_ci assert(varlen < sizeof(buf)); 5533d5ac70f0Sopenharmony_ci memcpy(buf, str, varlen); 5534d5ac70f0Sopenharmony_ci buf[varlen] = 0; 5535d5ac70f0Sopenharmony_ci } else { 5536d5ac70f0Sopenharmony_ci sprintf(buf, "%d", arg); 5537d5ac70f0Sopenharmony_ci } 5538d5ac70f0Sopenharmony_ci err = snd_config_search_alias(defs, NULL, var, &def); 5539d5ac70f0Sopenharmony_ci if (err < 0) { 5540d5ac70f0Sopenharmony_ci SNDERR("Unknown parameter %s", var); 5541d5ac70f0Sopenharmony_ci goto _err; 5542d5ac70f0Sopenharmony_ci } 5543d5ac70f0Sopenharmony_ci if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) { 5544d5ac70f0Sopenharmony_ci SNDERR("Parameter %s definition is not correct", var); 5545d5ac70f0Sopenharmony_ci err = -EINVAL; 5546d5ac70f0Sopenharmony_ci goto _err; 5547d5ac70f0Sopenharmony_ci } 5548d5ac70f0Sopenharmony_ci var = def->id; 5549d5ac70f0Sopenharmony_ci err = snd_config_search(subs, var, &sub); 5550d5ac70f0Sopenharmony_ci if (err >= 0) 5551d5ac70f0Sopenharmony_ci snd_config_delete(sub); 5552d5ac70f0Sopenharmony_ci sub = NULL; 5553d5ac70f0Sopenharmony_ci err = snd_config_search(def, "type", &typ); 5554d5ac70f0Sopenharmony_ci if (err < 0) { 5555d5ac70f0Sopenharmony_ci _invalid_type: 5556d5ac70f0Sopenharmony_ci SNDERR("Parameter %s definition is missing a valid type info", var); 5557d5ac70f0Sopenharmony_ci goto _err; 5558d5ac70f0Sopenharmony_ci } 5559d5ac70f0Sopenharmony_ci err = snd_config_get_string(typ, &tmp); 5560d5ac70f0Sopenharmony_ci if (err < 0 || !tmp) 5561d5ac70f0Sopenharmony_ci goto _invalid_type; 5562d5ac70f0Sopenharmony_ci if (strcmp(tmp, "integer") == 0) { 5563d5ac70f0Sopenharmony_ci long v; 5564d5ac70f0Sopenharmony_ci err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER); 5565d5ac70f0Sopenharmony_ci if (err < 0) 5566d5ac70f0Sopenharmony_ci goto _err; 5567d5ac70f0Sopenharmony_ci err = safe_strtol(val, &v); 5568d5ac70f0Sopenharmony_ci if (err < 0) { 5569d5ac70f0Sopenharmony_ci SNDERR("Parameter %s must be an integer", var); 5570d5ac70f0Sopenharmony_ci goto _err; 5571d5ac70f0Sopenharmony_ci } 5572d5ac70f0Sopenharmony_ci err = snd_config_set_integer(sub, v); 5573d5ac70f0Sopenharmony_ci if (err < 0) 5574d5ac70f0Sopenharmony_ci goto _err; 5575d5ac70f0Sopenharmony_ci } else if (strcmp(tmp, "integer64") == 0) { 5576d5ac70f0Sopenharmony_ci long long v; 5577d5ac70f0Sopenharmony_ci err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER64); 5578d5ac70f0Sopenharmony_ci if (err < 0) 5579d5ac70f0Sopenharmony_ci goto _err; 5580d5ac70f0Sopenharmony_ci err = safe_strtoll(val, &v); 5581d5ac70f0Sopenharmony_ci if (err < 0) { 5582d5ac70f0Sopenharmony_ci SNDERR("Parameter %s must be an integer", var); 5583d5ac70f0Sopenharmony_ci goto _err; 5584d5ac70f0Sopenharmony_ci } 5585d5ac70f0Sopenharmony_ci err = snd_config_set_integer64(sub, v); 5586d5ac70f0Sopenharmony_ci if (err < 0) 5587d5ac70f0Sopenharmony_ci goto _err; 5588d5ac70f0Sopenharmony_ci } else if (strcmp(tmp, "real") == 0) { 5589d5ac70f0Sopenharmony_ci double v; 5590d5ac70f0Sopenharmony_ci err = snd_config_make(&sub, var, SND_CONFIG_TYPE_REAL); 5591d5ac70f0Sopenharmony_ci if (err < 0) 5592d5ac70f0Sopenharmony_ci goto _err; 5593d5ac70f0Sopenharmony_ci err = safe_strtod(val, &v); 5594d5ac70f0Sopenharmony_ci if (err < 0) { 5595d5ac70f0Sopenharmony_ci SNDERR("Parameter %s must be a real", var); 5596d5ac70f0Sopenharmony_ci goto _err; 5597d5ac70f0Sopenharmony_ci } 5598d5ac70f0Sopenharmony_ci err = snd_config_set_real(sub, v); 5599d5ac70f0Sopenharmony_ci if (err < 0) 5600d5ac70f0Sopenharmony_ci goto _err; 5601d5ac70f0Sopenharmony_ci } else if (strcmp(tmp, "string") == 0) { 5602d5ac70f0Sopenharmony_ci err = snd_config_make(&sub, var, SND_CONFIG_TYPE_STRING); 5603d5ac70f0Sopenharmony_ci if (err < 0) 5604d5ac70f0Sopenharmony_ci goto _err; 5605d5ac70f0Sopenharmony_ci err = snd_config_set_string(sub, val); 5606d5ac70f0Sopenharmony_ci if (err < 0) 5607d5ac70f0Sopenharmony_ci goto _err; 5608d5ac70f0Sopenharmony_ci } else { 5609d5ac70f0Sopenharmony_ci err = -EINVAL; 5610d5ac70f0Sopenharmony_ci goto _invalid_type; 5611d5ac70f0Sopenharmony_ci } 5612d5ac70f0Sopenharmony_ci err = snd_config_set_id(sub, var); 5613d5ac70f0Sopenharmony_ci if (err < 0) 5614d5ac70f0Sopenharmony_ci goto _err; 5615d5ac70f0Sopenharmony_ci err = snd_config_add(subs, sub); 5616d5ac70f0Sopenharmony_ci if (err < 0) { 5617d5ac70f0Sopenharmony_ci _err: 5618d5ac70f0Sopenharmony_ci if (sub) 5619d5ac70f0Sopenharmony_ci snd_config_delete(sub); 5620d5ac70f0Sopenharmony_ci free(val); 5621d5ac70f0Sopenharmony_ci return err; 5622d5ac70f0Sopenharmony_ci } 5623d5ac70f0Sopenharmony_ci free(val); 5624d5ac70f0Sopenharmony_ci if (!*new) 5625d5ac70f0Sopenharmony_ci break; 5626d5ac70f0Sopenharmony_ci if (*new != ',') 5627d5ac70f0Sopenharmony_ci return -EINVAL; 5628d5ac70f0Sopenharmony_ci str = new + 1; 5629d5ac70f0Sopenharmony_ci arg++; 5630d5ac70f0Sopenharmony_ci } 5631d5ac70f0Sopenharmony_ci return 0; 5632d5ac70f0Sopenharmony_ci} 5633d5ac70f0Sopenharmony_ci 5634d5ac70f0Sopenharmony_ci/** 5635d5ac70f0Sopenharmony_ci * \brief Expands a configuration node, applying arguments and functions. 5636d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 5637d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node. 5638d5ac70f0Sopenharmony_ci * \param[in] fcn Custom function to obtain the referred variable name 5639d5ac70f0Sopenharmony_ci * \param[in] private_data Private data node for the custom function 5640d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the result 5641d5ac70f0Sopenharmony_ci * configuration node at the address specified by 5642d5ac70f0Sopenharmony_ci * \a result. 5643d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code. 5644d5ac70f0Sopenharmony_ci * 5645d5ac70f0Sopenharmony_ci * If \a config has arguments (defined by a child with id \c \@args), 5646d5ac70f0Sopenharmony_ci * this function replaces any string node beginning with $ with the 5647d5ac70f0Sopenharmony_ci * respective argument value, or the default argument value, or nothing. 5648d5ac70f0Sopenharmony_ci * Furthermore, any functions are evaluated (see #snd_config_evaluate). 5649d5ac70f0Sopenharmony_ci * The resulting copy of \a config is returned in \a result. 5650d5ac70f0Sopenharmony_ci * 5651d5ac70f0Sopenharmony_ci * The new tree is not evaluated (\ref snd_config_evaluate). 5652d5ac70f0Sopenharmony_ci */ 5653d5ac70f0Sopenharmony_ciint snd_config_expand_custom(snd_config_t *config, snd_config_t *root, 5654d5ac70f0Sopenharmony_ci snd_config_expand_fcn_t fcn, void *private_data, 5655d5ac70f0Sopenharmony_ci snd_config_t **result) 5656d5ac70f0Sopenharmony_ci{ 5657d5ac70f0Sopenharmony_ci snd_config_t *res; 5658d5ac70f0Sopenharmony_ci int err; 5659d5ac70f0Sopenharmony_ci 5660d5ac70f0Sopenharmony_ci err = snd_config_walk(config, root, &res, _snd_config_expand, fcn, private_data); 5661d5ac70f0Sopenharmony_ci if (err < 0) { 5662d5ac70f0Sopenharmony_ci SNDERR("Expand error (walk): %s", snd_strerror(err)); 5663d5ac70f0Sopenharmony_ci return err; 5664d5ac70f0Sopenharmony_ci } 5665d5ac70f0Sopenharmony_ci *result = res; 5666d5ac70f0Sopenharmony_ci return 1; 5667d5ac70f0Sopenharmony_ci} 5668d5ac70f0Sopenharmony_ci 5669d5ac70f0Sopenharmony_ci/** 5670d5ac70f0Sopenharmony_ci * \brief Expands a configuration node, applying arguments and functions. 5671d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node. 5672d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node. 5673d5ac70f0Sopenharmony_ci * \param[in] args Arguments string, can be \c NULL. 5674d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data node for functions. 5675d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the result 5676d5ac70f0Sopenharmony_ci * configuration node at the address specified by 5677d5ac70f0Sopenharmony_ci * \a result. 5678d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code. 5679d5ac70f0Sopenharmony_ci * 5680d5ac70f0Sopenharmony_ci * If \a config has arguments (defined by a child with id \c \@args), 5681d5ac70f0Sopenharmony_ci * this function replaces any string node beginning with $ with the 5682d5ac70f0Sopenharmony_ci * respective argument value, or the default argument value, or nothing. 5683d5ac70f0Sopenharmony_ci * Furthermore, any functions are evaluated (see #snd_config_evaluate). 5684d5ac70f0Sopenharmony_ci * The resulting copy of \a config is returned in \a result. 5685d5ac70f0Sopenharmony_ci */ 5686d5ac70f0Sopenharmony_ciint snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args, 5687d5ac70f0Sopenharmony_ci snd_config_t *private_data, snd_config_t **result) 5688d5ac70f0Sopenharmony_ci{ 5689d5ac70f0Sopenharmony_ci int err; 5690d5ac70f0Sopenharmony_ci snd_config_t *defs, *subs = NULL, *res; 5691d5ac70f0Sopenharmony_ci err = snd_config_search(config, "@args", &defs); 5692d5ac70f0Sopenharmony_ci if (err < 0) { 5693d5ac70f0Sopenharmony_ci if (args != NULL) { 5694d5ac70f0Sopenharmony_ci SNDERR("Unknown parameters %s", args); 5695d5ac70f0Sopenharmony_ci return -EINVAL; 5696d5ac70f0Sopenharmony_ci } 5697d5ac70f0Sopenharmony_ci err = snd_config_copy(&res, config); 5698d5ac70f0Sopenharmony_ci if (err < 0) 5699d5ac70f0Sopenharmony_ci return err; 5700d5ac70f0Sopenharmony_ci } else { 5701d5ac70f0Sopenharmony_ci err = snd_config_top(&subs); 5702d5ac70f0Sopenharmony_ci if (err < 0) 5703d5ac70f0Sopenharmony_ci return err; 5704d5ac70f0Sopenharmony_ci err = load_defaults(subs, defs); 5705d5ac70f0Sopenharmony_ci if (err < 0) { 5706d5ac70f0Sopenharmony_ci SNDERR("Load defaults error: %s", snd_strerror(err)); 5707d5ac70f0Sopenharmony_ci goto _end; 5708d5ac70f0Sopenharmony_ci } 5709d5ac70f0Sopenharmony_ci err = parse_args(subs, args, defs); 5710d5ac70f0Sopenharmony_ci if (err < 0) { 5711d5ac70f0Sopenharmony_ci SNDERR("Parse arguments error: %s", snd_strerror(err)); 5712d5ac70f0Sopenharmony_ci goto _end; 5713d5ac70f0Sopenharmony_ci } 5714d5ac70f0Sopenharmony_ci err = snd_config_evaluate(subs, root, private_data, NULL); 5715d5ac70f0Sopenharmony_ci if (err < 0) { 5716d5ac70f0Sopenharmony_ci SNDERR("Args evaluate error: %s", snd_strerror(err)); 5717d5ac70f0Sopenharmony_ci goto _end; 5718d5ac70f0Sopenharmony_ci } 5719d5ac70f0Sopenharmony_ci err = snd_config_walk(config, root, &res, _snd_config_expand, _snd_config_expand_vars, subs); 5720d5ac70f0Sopenharmony_ci if (err < 0) { 5721d5ac70f0Sopenharmony_ci SNDERR("Expand error (walk): %s", snd_strerror(err)); 5722d5ac70f0Sopenharmony_ci goto _end; 5723d5ac70f0Sopenharmony_ci } 5724d5ac70f0Sopenharmony_ci } 5725d5ac70f0Sopenharmony_ci err = snd_config_evaluate(res, root, private_data, NULL); 5726d5ac70f0Sopenharmony_ci if (err < 0) { 5727d5ac70f0Sopenharmony_ci SNDERR("Evaluate error: %s", snd_strerror(err)); 5728d5ac70f0Sopenharmony_ci snd_config_delete(res); 5729d5ac70f0Sopenharmony_ci goto _end; 5730d5ac70f0Sopenharmony_ci } 5731d5ac70f0Sopenharmony_ci *result = res; 5732d5ac70f0Sopenharmony_ci err = 1; 5733d5ac70f0Sopenharmony_ci _end: 5734d5ac70f0Sopenharmony_ci if (subs) 5735d5ac70f0Sopenharmony_ci snd_config_delete(subs); 5736d5ac70f0Sopenharmony_ci return err; 5737d5ac70f0Sopenharmony_ci} 5738d5ac70f0Sopenharmony_ci 5739d5ac70f0Sopenharmony_ci/** 5740d5ac70f0Sopenharmony_ci * \brief Searches for a definition in a configuration tree, using 5741d5ac70f0Sopenharmony_ci * aliases and expanding hooks and arguments. 5742d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration (sub)tree to search. 5743d5ac70f0Sopenharmony_ci * \param[in] base Implicit key base, or \c NULL for none. 5744d5ac70f0Sopenharmony_ci * \param[in] name Key suffix, optionally with arguments. 5745d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the expanded found 5746d5ac70f0Sopenharmony_ci * node at the address specified by \a result. 5747d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code. 5748d5ac70f0Sopenharmony_ci * 5749d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config, allowing 5750d5ac70f0Sopenharmony_ci * aliases and expanding hooks, like #snd_config_search_alias_hooks. 5751d5ac70f0Sopenharmony_ci * 5752d5ac70f0Sopenharmony_ci * If \a name contains a colon (:), the rest of the string after the 5753d5ac70f0Sopenharmony_ci * colon contains arguments that are expanded as with 5754d5ac70f0Sopenharmony_ci * #snd_config_expand. 5755d5ac70f0Sopenharmony_ci * 5756d5ac70f0Sopenharmony_ci * In any case, \a result is a new node that must be freed by the 5757d5ac70f0Sopenharmony_ci * caller. 5758d5ac70f0Sopenharmony_ci * 5759d5ac70f0Sopenharmony_ci * \par Errors: 5760d5ac70f0Sopenharmony_ci * <dl> 5761d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist. 5762d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is 5763d5ac70f0Sopenharmony_ci * not a compound node. 5764d5ac70f0Sopenharmony_ci * </dl> 5765d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook 5766d5ac70f0Sopenharmony_ci * definitions or arguments, or returned by (hook) functions. 5767d5ac70f0Sopenharmony_ci */ 5768d5ac70f0Sopenharmony_ciint snd_config_search_definition(snd_config_t *config, 5769d5ac70f0Sopenharmony_ci const char *base, const char *name, 5770d5ac70f0Sopenharmony_ci snd_config_t **result) 5771d5ac70f0Sopenharmony_ci{ 5772d5ac70f0Sopenharmony_ci snd_config_t *conf; 5773d5ac70f0Sopenharmony_ci char *key; 5774d5ac70f0Sopenharmony_ci const char *args = strchr(name, ':'); 5775d5ac70f0Sopenharmony_ci int err; 5776d5ac70f0Sopenharmony_ci if (args) { 5777d5ac70f0Sopenharmony_ci args++; 5778d5ac70f0Sopenharmony_ci key = alloca(args - name); 5779d5ac70f0Sopenharmony_ci memcpy(key, name, args - name - 1); 5780d5ac70f0Sopenharmony_ci key[args - name - 1] = '\0'; 5781d5ac70f0Sopenharmony_ci } else { 5782d5ac70f0Sopenharmony_ci key = (char *) name; 5783d5ac70f0Sopenharmony_ci } 5784d5ac70f0Sopenharmony_ci /* 5785d5ac70f0Sopenharmony_ci * if key contains dot (.), the implicit base is ignored 5786d5ac70f0Sopenharmony_ci * and the key starts from root given by the 'config' parameter 5787d5ac70f0Sopenharmony_ci */ 5788d5ac70f0Sopenharmony_ci snd_config_lock(); 5789d5ac70f0Sopenharmony_ci err = snd_config_search_alias_hooks(config, strchr(key, '.') ? NULL : base, key, &conf); 5790d5ac70f0Sopenharmony_ci if (err < 0) { 5791d5ac70f0Sopenharmony_ci snd_config_unlock(); 5792d5ac70f0Sopenharmony_ci return err; 5793d5ac70f0Sopenharmony_ci } 5794d5ac70f0Sopenharmony_ci err = snd_config_expand(conf, config, args, NULL, result); 5795d5ac70f0Sopenharmony_ci snd_config_unlock(); 5796d5ac70f0Sopenharmony_ci return err; 5797d5ac70f0Sopenharmony_ci} 5798d5ac70f0Sopenharmony_ci 5799d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 5800d5ac70f0Sopenharmony_civoid snd_config_set_hop(snd_config_t *conf, int hop) 5801d5ac70f0Sopenharmony_ci{ 5802d5ac70f0Sopenharmony_ci conf->hop = hop; 5803d5ac70f0Sopenharmony_ci} 5804d5ac70f0Sopenharmony_ci 5805d5ac70f0Sopenharmony_ciint snd_config_check_hop(snd_config_t *conf) 5806d5ac70f0Sopenharmony_ci{ 5807d5ac70f0Sopenharmony_ci if (conf) { 5808d5ac70f0Sopenharmony_ci if (conf->hop >= SND_CONF_MAX_HOPS) { 5809d5ac70f0Sopenharmony_ci SYSERR("Too many definition levels (looped?)\n"); 5810d5ac70f0Sopenharmony_ci return -EINVAL; 5811d5ac70f0Sopenharmony_ci } 5812d5ac70f0Sopenharmony_ci return conf->hop; 5813d5ac70f0Sopenharmony_ci } 5814d5ac70f0Sopenharmony_ci return 0; 5815d5ac70f0Sopenharmony_ci} 5816d5ac70f0Sopenharmony_ci#endif 5817d5ac70f0Sopenharmony_ci 5818d5ac70f0Sopenharmony_ci#if 0 5819d5ac70f0Sopenharmony_ci/* Not strictly needed, but useful to check for memory leaks */ 5820d5ac70f0Sopenharmony_civoid _snd_config_end(void) __attribute__ ((destructor)); 5821d5ac70f0Sopenharmony_ci 5822d5ac70f0Sopenharmony_cistatic void _snd_config_end(void) 5823d5ac70f0Sopenharmony_ci{ 5824d5ac70f0Sopenharmony_ci int k; 5825d5ac70f0Sopenharmony_ci if (snd_config) 5826d5ac70f0Sopenharmony_ci snd_config_delete(snd_config); 5827d5ac70f0Sopenharmony_ci snd_config = 0; 5828d5ac70f0Sopenharmony_ci for (k = 0; k < files_info_count; ++k) 5829d5ac70f0Sopenharmony_ci free(files_info[k].name); 5830d5ac70f0Sopenharmony_ci free(files_info); 5831d5ac70f0Sopenharmony_ci files_info = NULL; 5832d5ac70f0Sopenharmony_ci files_info_count = 0; 5833d5ac70f0Sopenharmony_ci} 5834d5ac70f0Sopenharmony_ci#endif 5835d5ac70f0Sopenharmony_ci 5836d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 5837d5ac70f0Sopenharmony_cisize_t page_size(void) 5838d5ac70f0Sopenharmony_ci{ 5839d5ac70f0Sopenharmony_ci long s = sysconf(_SC_PAGE_SIZE); 5840d5ac70f0Sopenharmony_ci assert(s > 0); 5841d5ac70f0Sopenharmony_ci return s; 5842d5ac70f0Sopenharmony_ci} 5843d5ac70f0Sopenharmony_ci 5844d5ac70f0Sopenharmony_cisize_t page_align(size_t size) 5845d5ac70f0Sopenharmony_ci{ 5846d5ac70f0Sopenharmony_ci size_t r; 5847d5ac70f0Sopenharmony_ci long psz = page_size(); 5848d5ac70f0Sopenharmony_ci r = size % psz; 5849d5ac70f0Sopenharmony_ci if (r) 5850d5ac70f0Sopenharmony_ci return size + psz - r; 5851d5ac70f0Sopenharmony_ci return size; 5852d5ac70f0Sopenharmony_ci} 5853d5ac70f0Sopenharmony_ci 5854d5ac70f0Sopenharmony_cisize_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset) 5855d5ac70f0Sopenharmony_ci{ 5856d5ac70f0Sopenharmony_ci size_t r; 5857d5ac70f0Sopenharmony_ci long psz = page_size(); 5858d5ac70f0Sopenharmony_ci assert(offset); 5859d5ac70f0Sopenharmony_ci assert(mmap_offset); 5860d5ac70f0Sopenharmony_ci *mmap_offset = object_offset; 5861d5ac70f0Sopenharmony_ci object_offset %= psz; 5862d5ac70f0Sopenharmony_ci *mmap_offset -= object_offset; 5863d5ac70f0Sopenharmony_ci object_size += object_offset; 5864d5ac70f0Sopenharmony_ci r = object_size % psz; 5865d5ac70f0Sopenharmony_ci if (r) 5866d5ac70f0Sopenharmony_ci r = object_size + psz - r; 5867d5ac70f0Sopenharmony_ci else 5868d5ac70f0Sopenharmony_ci r = object_size; 5869d5ac70f0Sopenharmony_ci *offset = object_offset; 5870d5ac70f0Sopenharmony_ci return r; 5871d5ac70f0Sopenharmony_ci} 5872d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 5873