1
2/*
3 * Copyright (C) Texas Instruments - http://www.ti.com/
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21#include "perf_config.h"
22#include "perf_common.h"
23#include <ctype.h>
24
25#ifdef ANDROID
26/* Log for Android system*/
27#include <utils/Log.h>
28#endif
29
30/* pre-declare helper functions */
31static int  assign_string(char **psMember, char const *sValue);
32static int  assign_string_if_matches(char const *line, char const *argument,
33                                     char **psMember);
34static int  assign_long(unsigned long *piMember, char const *sValue);
35static int  assign_long_if_matches(char const *line, char const *argument,
36                                   unsigned long *piMember);
37static void read_line(PERF_Config *sConfig, char const *line, char const *tag);
38static char const *get_value_if_matches(char const *line, char const *argument);
39
40/*-----------------------------------------------------------------------------
41  CONFIGURATION METHODS FUNCTIONS
42-----------------------------------------------------------------------------*/
43/* default configuration */
44void PERF_Config_Init(PERF_Config *sConfig)
45{
46    /* initialize default configuration */
47
48    sConfig->mask           = 0;
49
50    /* logging interface */
51    sConfig->trace_file     = NULL;
52    sConfig->delayed_open   = 0;
53    sConfig->buffer_size    = 65536;
54
55    /* debug interface */
56    sConfig->debug          = FALSE;
57    sConfig->detailed_debug = FALSE;
58    sConfig->csv            = 1;
59    sConfig->log_file       = NULL;
60
61    /* replay interface */
62    sConfig->replay_file    = strdup("STDOUT");
63
64    /* real-time interface */
65    sConfig->realtime       = 0;
66    sConfig->rt_granularity = 1;
67    sConfig->rt_summary     = 1;
68    sConfig->rt_debug       = 0;
69    sConfig->rt_detailed    = 0;
70    sConfig->rt_file        = strdup("STDERR");
71}
72
73/* release configuration memory */
74void PERF_Config_Release(PERF_Config *sConfig)
75{
76    /* release all allocated members */
77    if (sConfig->trace_file)
78    {
79        free(sConfig->trace_file);
80        sConfig->trace_file = NULL;
81    }
82    if (sConfig->log_file)
83    {
84        free(sConfig->log_file);
85        sConfig->log_file = NULL;
86    }
87    if (sConfig->replay_file)
88    {
89        free(sConfig->replay_file);
90        sConfig->replay_file = NULL;
91    }
92    if (sConfig->rt_file)
93    {
94        free(sConfig->rt_file);
95        sConfig->rt_file = NULL;
96    }
97}
98
99/** Method  read_line
100 *
101 *  Arg1    pointer to configuration
102 *
103 *  Arg2    configuration line (trimmed of trailing white
104 *  spaces)
105 *
106 *  Arg3    tag - restrict matches to this tag or no-tag
107 *
108 *  Effects compares configuration lines to assignments to each
109 *  configuration variable.  If tags are specified before the
110 *  configuration variable, they are ignored unless they match
111 *  the supplied tag. If it matches, the assignment is performed
112 *  to the variable. Otherwise, an error message is printed.
113 *  */
114
115static
116void read_line(PERF_Config *cfg, char const *line, char const *tag)
117{
118    char const *ptr;
119
120    /* skip leading spaces */
121    while (*line && isspace(*line)) line++;
122
123    /* ignore comment lines and empty lines */
124    if (!*line || *line == '#') return;
125
126    /* check to see if there is a tag prefix */
127
128    /* find first white-space or . in the line */
129    for (ptr = line; *ptr && !isspace(*ptr) && *ptr != '.' && *ptr != '='; ptr++);
130
131    if (*ptr == '.')
132    {
133        /* ignore lines where the tag does not match */
134        if (!tag || strncmp(line, tag, ptr - line)) return;
135
136        /* otherwise, skip the tag for the match */
137        line = ptr + 1;
138    }
139
140    /* check for known member names */
141
142    if (!(assign_long_if_matches(line, "mask",          &cfg->mask) ||
143          /* logging configuration */
144          assign_string_if_matches(line, "trace_file",  &cfg->trace_file) ||
145          assign_long_if_matches(line, "delayed_open",  &cfg->delayed_open) ||
146          assign_long_if_matches(line, "buffer_size",   &cfg->buffer_size) ||
147          /* debug configuration */
148          assign_string_if_matches(line, "log_file",    &cfg->log_file) ||
149          assign_long_if_matches(line, "debug",         &cfg->debug) ||
150          assign_long_if_matches(line, "detailed_debug",&cfg->detailed_debug) ||
151          assign_long_if_matches(line, "csv",           &cfg->csv) ||
152          /* replay configuration */
153          assign_string_if_matches(line, "replay_file", &cfg->replay_file) ||
154          /* real-time configuration */
155          assign_long_if_matches(line, "realtime",       &cfg->realtime) ||
156          assign_long_if_matches(line, "rt_granularity", &cfg->rt_granularity) ||
157          assign_long_if_matches(line, "rt_debug",       &cfg->rt_debug) ||
158          assign_long_if_matches(line, "rt_detailed",    &cfg->rt_detailed) ||
159          assign_long_if_matches(line, "rt_summary",     &cfg->rt_summary) ||
160          assign_string_if_matches(line, "rt_file",      &cfg->rt_file)
161          ))
162
163    {
164        fprintf(stderr,
165                "warning: incorrect line in configuration file:\n%s\n", line);
166    }
167}
168
169/*
170    Effects: reads each line of the perf.ini file and processes configuration
171    assignments in linear order.  Maximum line length is enforced, and all
172    lines longer than this are ignored.  Also, all lines must end in new-line
173    If ulID is specified, lines starting with the fourCC ULID. will also be
174    read.  Lines starting with # will be ignored.
175*/
176void PERF_Config_Read(PERF_Config *sConfig, char const *tag)
177{
178    FILE *config_file = NULL;
179    char line[PERF_CONFIG_LINELENGTH];
180    int ignore = FALSE;
181
182    if (sConfig)
183    {
184        /* open config file */
185        config_file = fopen(PERF_CONFIG_FILE, "rt");
186        if (config_file)
187        {
188            /* read each line */
189            while (fgets(line, PERF_CONFIG_LINELENGTH, config_file))
190            {
191                if (/* strlen(line) == PERF_CONFIG_LINELENGTH && */
192                    *line && line[strlen(line)-1] != '\n')
193                {
194                    /* ignore lines that reach the max length */
195                    ignore = TRUE;
196                }
197                else if (!ignore)
198                {
199                    /* remove new-line and trailing spaces from end of line */
200                    while (*line && isspace(line [strlen(line)-1]))
201                    {
202                        line[strlen(line)-1] = 0;
203                    }
204
205                    /* process un-ignored lines */
206                    read_line(sConfig, line, tag);
207                }
208                else
209                {
210                    /* no longer ignore lines after they are completely read */
211                    ignore = FALSE;
212                }
213            }
214
215            /* done */
216            fclose(config_file);
217        }
218    }
219}
220
221/*-----------------------------------------------------------------------------
222  HELPER FUNCTIONS
223-----------------------------------------------------------------------------*/
224
225/** Method  get_value_if_matches
226 *
227 *  Arg1    configuration line
228 *
229 *  Arg2    configuration variable name
230 *
231 *  Effects if the configuration line is <variable name> =
232 *  <value>, it returns the <value>. Otherwise, it returns NULL
233 *
234 *  */
235static
236char const *get_value_if_matches(char const *line,
237                                 char const *argument)
238{
239    /* skip leading spaces */
240    while (*line && isspace(*line)) line++;
241
242    /* return NULL if argument name does not match */
243    if (strncasecmp(line, argument, strlen(argument))) return (NULL);
244    line += strlen(argument);
245
246    /* there must be an = after argument name */
247
248    /* skip trailing spaces before = */
249    while (*line && isspace(*line)) line++;
250
251    /* return NULL if = not found */
252    if (*line != '=') return (NULL);
253    line++;
254
255    /* skip leading spaces before value */
256    while (*line && isspace(*line)) line++;
257
258    /* if reached the end of line, return NULL; otherwise, return value */
259    return(*line ? line : NULL);
260}
261
262/** Method  assign_string
263 *
264 *  Arg1    pointer to string configuration member
265 *
266 *  Arg2    configuration value
267 *
268 *  Effects Assigns the value to the configuration member.
269 *  */
270
271static
272int assign_string(char **psMember, char const *sValue)
273{
274    /* delete any prior value */
275    if (*psMember)
276    {
277        free(*psMember);
278        *psMember = NULL;
279    }
280
281    /* set new value unless it is NULL */
282    if (strcasecmp(sValue, "NULL"))
283    {
284        *psMember = strdup(sValue);
285    }
286
287    return (1);
288}
289
290/** Method  assign_long
291 *
292 *  Arg1    pointer to configuration member
293 *
294 *  Arg2    configuration value (string)
295 *
296 *  Effects Assigns the integer value of the string to the
297 *  configuration member.  If value starts with '$' or '0x', it
298 *  interprets the remaining digits as a hexadecimal number.  If
299 *  value starts with -, or with a digit, it is interpreted as a
300 *  decimal (can be signed or unsigned).  Otherwise, if it
301 *  matches 'enabled', 'on' or 'true', the member is assigned 1.
302 *  In all other cases, it is assigned 0.
303 *  */
304
305static
306int assign_long(unsigned long *piMember, char const *sValue)
307{
308    /* set new value */
309
310    /* hexadecimal value */
311    if (!strncasecmp(sValue, "0x", 2)) sscanf(sValue + 2, "%lx", piMember);
312    else if (*sValue == '$') sscanf(sValue + 1, "%lx", piMember);
313
314    /* decimal value */
315    else if (*sValue == '-') sscanf(sValue, "%ld", piMember);
316    else if (isdigit(*sValue)) sscanf(sValue, "%lu", piMember);
317
318    /* boolean value */
319    else *piMember = (!strcasecmp(sValue, "enabled") ||
320                      !strcasecmp(sValue, "on") ||
321                      !strcasecmp(sValue, "true"));
322
323    return (1);
324}
325
326/** Method  assign_string_if_matches
327 *
328 *  Arg1    configuration line
329 *
330 *  Arg2    configuration variable name
331 *
332 *  Arg3    pointer to string configuration member
333 *
334 *  Effects if the configuration line is <variable name> =
335 *  <value>, it assigns the value to the configuration
336 *  member.
337 *
338 *  Returns 1, if assignment occured. 0 otherwise.
339 *  */
340
341static
342int assign_string_if_matches(char const *line, char const *argument,
343                             char **target)
344{
345    char const *value = get_value_if_matches(line, argument);
346    return (value ? (assign_string(target, value), 1) : 0);
347}
348
349/** Method  assign_long_if_matches
350 *
351 *  Arg1    configuration line
352 *
353 *  Arg2    configuration variable name
354 *
355 *  Arg3    pointer to string configuration member
356 *
357 *  Effects if the configuration line is <variable name> =
358 *  <value>, it assigns the integer value of the string to the
359 *  configuration member in the following manner:  If value
360 *  starts with '$' or '0x', it interprets the remaining digits
361 *  as a hexadecimal number. If value starts with -, or with a
362 *  digit, it is interpreted as a decimal (can be signed or
363 *  unsigned). Otherwise, if it matches 'enabled', 'on' or
364 *  'true', the member is assigned 1. In all other cases, it is
365 *  assigned 0.
366 *
367 *  Returns 1, if assignment occured. 0 otherwise (if config
368 *  line was not an assignment to variable name).
369 *  */
370
371static
372int assign_long_if_matches(char const *line, char const *argument,
373                           unsigned long *target)
374{
375    char const *value = get_value_if_matches(line, argument);
376    return (value ? (assign_long(target, value), 1) : 0);
377}
378
379
380