1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | /***************************************************************************** |
29 | * |
30 | * This file provides a generic command line interface which allows |
31 | * vcos internals to be manipulated and/or displayed. |
32 | * |
33 | *****************************************************************************/ |
34 | |
35 | /* ---- Include Files ---------------------------------------------------- */ |
36 | |
37 | #include "interface/vcos/vcos.h" |
38 | |
39 | #ifdef HAVE_VCOS_VERSION |
40 | #include "interface/vcos/vcos_build_info.h" |
41 | #endif |
42 | |
43 | #ifdef _VIDEOCORE |
44 | #include "vcfw/logging/logging.h" |
45 | #endif |
46 | |
47 | /* ---- Public Variables ------------------------------------------------- */ |
48 | |
49 | /* ---- Private Constants and Types -------------------------------------- */ |
50 | |
51 | #define VCOS_LOG_CATEGORY (&vcos_cmd_log_category) |
52 | VCOS_LOG_CAT_T vcos_cmd_log_category; |
53 | |
54 | /* ---- Private Variables ------------------------------------------------ */ |
55 | |
56 | static struct VCOS_CMD_GLOBALS_T |
57 | { |
58 | VCOS_MUTEX_T lock; |
59 | VCOS_ONCE_T initialized; |
60 | |
61 | unsigned num_cmd_entries; |
62 | unsigned num_cmd_alloc; |
63 | VCOS_CMD_T *cmd_entry; |
64 | |
65 | VCOS_LOG_CAT_T *log_category; |
66 | } cmd_globals; |
67 | |
68 | #ifdef HAVE_VCOS_VERSION |
69 | /* Keep the static strings in the image from being dropped by |
70 | * the linker. |
71 | */ |
72 | extern const char *vcos_get_build_strings(unsigned id); |
73 | const char *(*vcos_keep_static_strings)(unsigned); |
74 | #endif |
75 | |
76 | /* ---- Private Function Prototypes -------------------------------------- */ |
77 | |
78 | static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param ); |
79 | |
80 | /* ---- Functions ------------------------------------------------------- */ |
81 | |
82 | /***************************************************************************** |
83 | * |
84 | * Walks through the commands looking for a particular command |
85 | * |
86 | *****************************************************************************/ |
87 | |
88 | static VCOS_CMD_T *find_cmd( VCOS_CMD_T *cmd_entry, const char *name ) |
89 | { |
90 | VCOS_CMD_T *scan_entry = cmd_entry; |
91 | |
92 | while ( scan_entry->name != NULL ) |
93 | { |
94 | if ( vcos_strcmp( scan_entry->name, name ) == 0 ) |
95 | { |
96 | return scan_entry; |
97 | } |
98 | scan_entry++; |
99 | } |
100 | |
101 | return NULL; |
102 | } |
103 | |
104 | /***************************************************************************** |
105 | * |
106 | * Saves away |
107 | * each line individually. |
108 | * |
109 | *****************************************************************************/ |
110 | |
111 | void vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category ) |
112 | { |
113 | cmd_globals.log_category = log_category; |
114 | } |
115 | |
116 | /***************************************************************************** |
117 | * |
118 | * Walks through a buffer containing newline separated lines, and logs |
119 | * each line individually. |
120 | * |
121 | *****************************************************************************/ |
122 | |
123 | static void cmd_log_results( VCOS_CMD_PARAM_T *param ) |
124 | { |
125 | char *start; |
126 | char *end; |
127 | |
128 | start = end = param->result_buf; |
129 | |
130 | while ( *start != '\0' ) |
131 | { |
132 | while (( *end != '\0' ) && ( *end != '\n' )) |
133 | end++; |
134 | |
135 | if ( *end == '\n' ) |
136 | { |
137 | *end++ = '\0'; |
138 | } |
139 | |
140 | if ( cmd_globals.log_category != NULL ) |
141 | { |
142 | if ( vcos_is_log_enabled( cmd_globals.log_category, VCOS_LOG_INFO )) |
143 | { |
144 | vcos_log_impl( cmd_globals.log_category, VCOS_LOG_INFO, "%s" , start ); |
145 | } |
146 | } |
147 | else |
148 | { |
149 | vcos_log_info( "%s" , start ); |
150 | } |
151 | |
152 | start = end; |
153 | } |
154 | |
155 | /* Since we logged the buffer, reset the pointer back to the beginning. */ |
156 | |
157 | param->result_ptr = param->result_buf; |
158 | param->result_buf[0] = '\0'; |
159 | } |
160 | |
161 | /***************************************************************************** |
162 | * |
163 | * Since we may have limited output space, we create a generic routine |
164 | * which tries to use the result space, but will switch over to using |
165 | * logging if the output is too large. |
166 | * |
167 | *****************************************************************************/ |
168 | |
169 | void vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args ) |
170 | { |
171 | int bytes_written; |
172 | int bytes_remaining; |
173 | |
174 | bytes_remaining = (int)(param->result_size - ( param->result_ptr - param->result_buf )); |
175 | |
176 | bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args ); |
177 | |
178 | if ( cmd_globals.log_category != NULL ) |
179 | { |
180 | /* We're going to log each line as we encounter it. If the buffer |
181 | * doesn't end in a newline, then we'll wait for one first. |
182 | */ |
183 | |
184 | if ( (( bytes_written + 1 ) >= bytes_remaining ) |
185 | || ( param->result_ptr[ bytes_written - 1 ] == '\n' )) |
186 | { |
187 | cmd_log_results( param ); |
188 | } |
189 | else |
190 | { |
191 | param->result_ptr += bytes_written; |
192 | } |
193 | } |
194 | else |
195 | { |
196 | if (( bytes_written + 1 ) >= bytes_remaining ) |
197 | { |
198 | /* Output doesn't fit - switch over to logging */ |
199 | |
200 | param->use_log = 1; |
201 | |
202 | *param->result_ptr = '\0'; /* Zap the partial line that didn't fit above. */ |
203 | |
204 | cmd_log_results( param ); /* resets result_ptr */ |
205 | |
206 | bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args ); |
207 | } |
208 | param->result_ptr += bytes_written; |
209 | } |
210 | } |
211 | |
212 | /***************************************************************************** |
213 | * |
214 | * Prints the output. |
215 | * |
216 | *****************************************************************************/ |
217 | |
218 | void vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) |
219 | { |
220 | va_list args; |
221 | |
222 | va_start( args, fmt ); |
223 | vcos_cmd_vprintf( param, fmt, args ); |
224 | va_end( args ); |
225 | } |
226 | |
227 | /***************************************************************************** |
228 | * |
229 | * Prints the arguments which were on the command line prior to ours. |
230 | * |
231 | *****************************************************************************/ |
232 | |
233 | static void print_argument_prefix( VCOS_CMD_PARAM_T *param ) |
234 | { |
235 | int arg_idx; |
236 | |
237 | for ( arg_idx = 0; ¶m->argv_orig[arg_idx] != param->argv; arg_idx++ ) |
238 | { |
239 | vcos_cmd_printf( param, "%s " , param->argv_orig[arg_idx] ); |
240 | } |
241 | } |
242 | |
243 | /***************************************************************************** |
244 | * |
245 | * Prints an error message, prefixed by the command chain required to get |
246 | * to where we're at. |
247 | * |
248 | *****************************************************************************/ |
249 | |
250 | void vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) |
251 | { |
252 | va_list args; |
253 | |
254 | print_argument_prefix( param ); |
255 | |
256 | va_start( args, fmt ); |
257 | vcos_cmd_vprintf( param, fmt, args ); |
258 | va_end( args ); |
259 | vcos_cmd_printf( param, "\n" ); |
260 | } |
261 | |
262 | /**************************************************************************** |
263 | * |
264 | * usage - prints command usage for an array of commands. |
265 | * |
266 | ***************************************************************************/ |
267 | |
268 | static void usage( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry ) |
269 | { |
270 | int cmd_idx; |
271 | int nameWidth = 0; |
272 | int argsWidth = 0; |
273 | VCOS_CMD_T *scan_entry; |
274 | |
275 | vcos_cmd_printf( param, "Usage: " ); |
276 | print_argument_prefix( param ); |
277 | vcos_cmd_printf( param, "command [args ...]\n" ); |
278 | vcos_cmd_printf( param, "\n" ); |
279 | vcos_cmd_printf( param, "Where command is one of the following:\n" ); |
280 | |
281 | for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ ) |
282 | { |
283 | int aw; |
284 | int nw; |
285 | |
286 | scan_entry = &cmd_entry[cmd_idx]; |
287 | |
288 | nw = vcos_strlen( scan_entry->name ); |
289 | aw = vcos_strlen( scan_entry->args ); |
290 | |
291 | if ( nw > nameWidth ) |
292 | { |
293 | nameWidth = nw; |
294 | } |
295 | if ( aw > argsWidth ) |
296 | { |
297 | argsWidth = aw; |
298 | } |
299 | } |
300 | |
301 | for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ ) |
302 | { |
303 | scan_entry = &cmd_entry[cmd_idx]; |
304 | |
305 | vcos_cmd_printf( param, " %-*s %-*s - %s\n" , |
306 | nameWidth, scan_entry->name, |
307 | argsWidth, scan_entry->args, |
308 | scan_entry->descr ); |
309 | } |
310 | } |
311 | |
312 | /**************************************************************************** |
313 | * |
314 | * Prints the usage for the current command. |
315 | * |
316 | ***************************************************************************/ |
317 | |
318 | void vcos_cmd_usage( VCOS_CMD_PARAM_T *param ) |
319 | { |
320 | VCOS_CMD_T *cmd_entry; |
321 | |
322 | cmd_entry = param->cmd_entry; |
323 | |
324 | if ( cmd_entry->sub_cmd_entry != NULL ) |
325 | { |
326 | /* This command is command with sub-commands */ |
327 | |
328 | usage( param, param->cmd_entry->sub_cmd_entry ); |
329 | } |
330 | else |
331 | { |
332 | vcos_cmd_printf( param, "Usage: " ); |
333 | print_argument_prefix( param ); |
334 | vcos_cmd_printf( param, "%s %s - %s\n" , |
335 | param->argv[0], |
336 | param->cmd_entry->args, |
337 | param->cmd_entry->descr ); |
338 | } |
339 | } |
340 | |
341 | /***************************************************************************** |
342 | * |
343 | * Command to print out the help |
344 | * |
345 | * This help command is only called from the main menu. |
346 | * |
347 | *****************************************************************************/ |
348 | |
349 | static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param ) |
350 | { |
351 | VCOS_CMD_T *found_entry; |
352 | |
353 | #if 0 |
354 | { |
355 | int arg_idx; |
356 | |
357 | vcos_log_trace( "%s: argc = %d" , __func__, param->argc ); |
358 | for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ ) |
359 | { |
360 | vcos_log_trace( "%s: argv[%d] = '%s'" , __func__, arg_idx, param->argv[arg_idx] ); |
361 | } |
362 | } |
363 | #endif |
364 | |
365 | /* If there is an argument after the word help, then we want to print |
366 | * help for that command. |
367 | */ |
368 | |
369 | if ( param->argc == 1 ) |
370 | { |
371 | if ( param->cmd_parent_entry == cmd_globals.cmd_entry ) |
372 | { |
373 | /* Bare help - print the command usage for the root */ |
374 | |
375 | usage( param, cmd_globals.cmd_entry ); |
376 | return VCOS_SUCCESS; |
377 | } |
378 | |
379 | /* For all other cases help requires an argument */ |
380 | |
381 | vcos_cmd_error( param, "%s requires an argument" , param->argv[0] ); |
382 | return VCOS_EINVAL; |
383 | } |
384 | |
385 | /* We were given an argument. */ |
386 | |
387 | if (( found_entry = find_cmd( param->cmd_parent_entry, param->argv[1] )) != NULL ) |
388 | { |
389 | /* Make it look like the command that was specified is the one that's |
390 | * currently running |
391 | */ |
392 | |
393 | vcos_cmd_printf( param, "Usage: " ); |
394 | print_argument_prefix( param ); |
395 | vcos_cmd_printf( param, "%s %s - %s\n" , |
396 | param->argv[1], |
397 | found_entry->args, |
398 | found_entry->descr ); |
399 | |
400 | return VCOS_SUCCESS; |
401 | } |
402 | |
403 | vcos_cmd_error( param, "- unrecognized command: '%s'" , param->argv[1] ); |
404 | return VCOS_ENOENT; |
405 | } |
406 | |
407 | /***************************************************************************** |
408 | * |
409 | * Command to print out the version/build information. |
410 | * |
411 | *****************************************************************************/ |
412 | |
413 | #ifdef HAVE_VCOS_VERSION |
414 | |
415 | static VCOS_STATUS_T version_cmd( VCOS_CMD_PARAM_T *param ) |
416 | { |
417 | static const char* copyright = "Copyright (c) 2011 Broadcom" ; |
418 | |
419 | vcos_cmd_printf( param, "%s %s\n%s\nversion %s\nhost %s" , |
420 | vcos_get_build_date(), |
421 | vcos_get_build_time(), |
422 | copyright, |
423 | vcos_get_build_version(), |
424 | vcos_get_build_hostname() ); |
425 | |
426 | return VCOS_SUCCESS; |
427 | } |
428 | |
429 | #endif |
430 | |
431 | /***************************************************************************** |
432 | * |
433 | * Internal commands |
434 | * |
435 | *****************************************************************************/ |
436 | |
437 | static VCOS_CMD_T cmd_help = { "help" , "[command]" , help_cmd, NULL, "Prints command help information" }; |
438 | |
439 | #ifdef HAVE_VCOS_VERSION |
440 | static VCOS_CMD_T cmd_version = { "version" , "" , version_cmd, NULL, "Prints build/version information" }; |
441 | #endif |
442 | |
443 | /***************************************************************************** |
444 | * |
445 | * Walks the command table and executes the commands |
446 | * |
447 | *****************************************************************************/ |
448 | |
449 | static VCOS_STATUS_T execute_cmd( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry ) |
450 | { |
451 | const char *cmdStr; |
452 | VCOS_CMD_T *found_entry; |
453 | |
454 | #if 0 |
455 | { |
456 | int arg_idx; |
457 | |
458 | vcos_cmd_printf( param, "%s: argc = %d" , __func__, param->argc ); |
459 | for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ ) |
460 | { |
461 | vcos_cmd_printf( param, " argv[%d] = '%s'" , arg_idx, param->argv[arg_idx] ); |
462 | } |
463 | vcos_cmd_printf( param, "\n" ); |
464 | } |
465 | #endif |
466 | |
467 | if ( param->argc <= 1 ) |
468 | { |
469 | /* No command specified */ |
470 | |
471 | vcos_cmd_error( param, "%s - no command specified" , param->argv[0] ); |
472 | return VCOS_EINVAL; |
473 | } |
474 | |
475 | /* argv[0] is the command/program that caused us to get invoked, so we strip |
476 | * it off. |
477 | */ |
478 | |
479 | param->argc--; |
480 | param->argv++; |
481 | param->cmd_parent_entry = cmd_entry; |
482 | |
483 | /* Not the help command, scan for the command and execute it. */ |
484 | |
485 | cmdStr = param->argv[0]; |
486 | |
487 | if (( found_entry = find_cmd( cmd_entry, cmdStr )) != NULL ) |
488 | { |
489 | if ( found_entry->sub_cmd_entry != NULL ) |
490 | { |
491 | return execute_cmd( param, found_entry->sub_cmd_entry ); |
492 | } |
493 | |
494 | param->cmd_entry = found_entry; |
495 | return found_entry->cmd_fn( param ); |
496 | } |
497 | |
498 | /* Unrecognized command - check to see if it was the help command */ |
499 | |
500 | if ( vcos_strcmp( cmdStr, cmd_help.name ) == 0 ) |
501 | { |
502 | return help_cmd( param ); |
503 | } |
504 | |
505 | vcos_cmd_error( param, "- unrecognized command: '%s'" , cmdStr ); |
506 | return VCOS_ENOENT; |
507 | } |
508 | |
509 | /***************************************************************************** |
510 | * |
511 | * Initializes the command line parser. |
512 | * |
513 | *****************************************************************************/ |
514 | |
515 | static void vcos_cmd_init( void ) |
516 | { |
517 | vcos_mutex_create( &cmd_globals.lock, "vcos_cmd" ); |
518 | |
519 | cmd_globals.num_cmd_entries = 0; |
520 | cmd_globals.num_cmd_alloc = 0; |
521 | cmd_globals.cmd_entry = NULL; |
522 | |
523 | #ifdef HAVE_VCOS_VERSION |
524 | vcos_keep_static_strings = vcos_get_build_strings; |
525 | #endif |
526 | } |
527 | |
528 | /***************************************************************************** |
529 | * |
530 | * Shuts down the command line parser. |
531 | * |
532 | *****************************************************************************/ |
533 | |
534 | void vcos_cmd_shutdown( void ) |
535 | { |
536 | vcos_mutex_delete( &cmd_globals.lock ); |
537 | |
538 | vcos_free( cmd_globals.cmd_entry ); |
539 | cmd_globals.cmd_entry = NULL; |
540 | } |
541 | |
542 | /***************************************************************************** |
543 | * |
544 | * Command line processor. |
545 | * |
546 | *****************************************************************************/ |
547 | |
548 | VCOS_STATUS_T vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf ) |
549 | { |
550 | VCOS_STATUS_T rc = VCOS_EINVAL; |
551 | VCOS_CMD_PARAM_T param; |
552 | |
553 | vcos_once( &cmd_globals.initialized, vcos_cmd_init ); |
554 | |
555 | param.argc = argc; |
556 | param.argv = param.argv_orig = argv; |
557 | |
558 | param.use_log = 0; |
559 | param.result_size = result_size; |
560 | param.result_ptr = result_buf; |
561 | param.result_buf = result_buf; |
562 | |
563 | result_buf[0] = '\0'; |
564 | |
565 | vcos_mutex_lock( &cmd_globals.lock ); |
566 | |
567 | rc = execute_cmd( ¶m, cmd_globals.cmd_entry ); |
568 | |
569 | if ( param.use_log ) |
570 | { |
571 | cmd_log_results( ¶m ); |
572 | vcos_snprintf( result_buf, result_size, "results logged" ); |
573 | } |
574 | else |
575 | if ( cmd_globals.log_category != NULL ) |
576 | { |
577 | if ( result_buf[0] != '\0' ) |
578 | { |
579 | /* There is a partial line still buffered. */ |
580 | |
581 | vcos_cmd_printf( ¶m, "\n" ); |
582 | } |
583 | } |
584 | |
585 | vcos_mutex_unlock( &cmd_globals.lock ); |
586 | |
587 | return rc; |
588 | } |
589 | |
590 | /***************************************************************************** |
591 | * |
592 | * Registers a command entry with the command line processor |
593 | * |
594 | *****************************************************************************/ |
595 | |
596 | VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry ) |
597 | { |
598 | VCOS_STATUS_T rc; |
599 | VCOS_UNSIGNED new_num_cmd_alloc; |
600 | VCOS_CMD_T *new_cmd_entry; |
601 | VCOS_CMD_T *old_cmd_entry; |
602 | VCOS_CMD_T *scan_entry; |
603 | |
604 | vcos_once( &cmd_globals.initialized, vcos_cmd_init ); |
605 | |
606 | vcos_assert( cmd_entry != NULL ); |
607 | vcos_assert( cmd_entry->name != NULL ); |
608 | |
609 | vcos_log_trace( "%s: cmd '%s'" , __FUNCTION__, cmd_entry->name ); |
610 | |
611 | vcos_assert( cmd_entry->args != NULL ); |
612 | vcos_assert(( cmd_entry->cmd_fn != NULL ) || ( cmd_entry->sub_cmd_entry != NULL )); |
613 | vcos_assert( cmd_entry->descr != NULL ); |
614 | |
615 | /* We expect vcos_cmd_init to be called before vcos_logging_init, so we |
616 | * need to defer registering our logging category until someplace |
617 | * like right here. |
618 | */ |
619 | |
620 | if ( vcos_cmd_log_category.name == NULL ) |
621 | { |
622 | /* |
623 | * If you're using the command interface, you pretty much always want |
624 | * log messages from this file to show up. So we change the default |
625 | * from ERROR to be the more reasonable INFO level. |
626 | */ |
627 | |
628 | vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO); |
629 | vcos_log_register("vcos_cmd" , &vcos_cmd_log_category); |
630 | |
631 | /* We register a help command so that it shows up in the usage. */ |
632 | |
633 | vcos_cmd_register( &cmd_help ); |
634 | #ifdef HAVE_VCOS_VERSION |
635 | vcos_cmd_register( &cmd_version ); |
636 | #endif |
637 | } |
638 | |
639 | vcos_mutex_lock( &cmd_globals.lock ); |
640 | |
641 | if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc ) |
642 | { |
643 | if ( cmd_globals.num_cmd_alloc == 0 ) |
644 | { |
645 | /* We haven't allocated a table yet */ |
646 | } |
647 | |
648 | /* The number 8 is rather arbitrary. */ |
649 | |
650 | new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8; |
651 | |
652 | /* The + 1 is to ensure that we always have a NULL entry at the end. */ |
653 | |
654 | new_cmd_entry = (VCOS_CMD_T *)vcos_calloc( new_num_cmd_alloc + 1, sizeof( *cmd_entry ), "vcos_cmd_entries" ); |
655 | if ( new_cmd_entry == NULL ) |
656 | { |
657 | rc = VCOS_ENOMEM; |
658 | goto out; |
659 | } |
660 | memcpy( new_cmd_entry, cmd_globals.cmd_entry, cmd_globals.num_cmd_entries * sizeof( *cmd_entry )); |
661 | cmd_globals.num_cmd_alloc = new_num_cmd_alloc; |
662 | old_cmd_entry = cmd_globals.cmd_entry; |
663 | cmd_globals.cmd_entry = new_cmd_entry; |
664 | vcos_free( old_cmd_entry ); |
665 | } |
666 | |
667 | if ( cmd_globals.num_cmd_entries == 0 ) |
668 | { |
669 | /* This is the first command being registered */ |
670 | |
671 | cmd_globals.cmd_entry[0] = *cmd_entry; |
672 | } |
673 | else |
674 | { |
675 | /* Keep the list in alphabetical order. We start at the end and work backwards |
676 | * shuffling entries up one until we find an insertion point. |
677 | */ |
678 | |
679 | for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1]; |
680 | scan_entry >= cmd_globals.cmd_entry; scan_entry-- ) |
681 | { |
682 | if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 ) |
683 | { |
684 | /* We found an insertion point. */ |
685 | |
686 | break; |
687 | } |
688 | |
689 | scan_entry[1] = scan_entry[0]; |
690 | } |
691 | scan_entry[1] = *cmd_entry; |
692 | } |
693 | cmd_globals.num_cmd_entries++; |
694 | |
695 | rc = VCOS_SUCCESS; |
696 | |
697 | out: |
698 | |
699 | vcos_mutex_unlock( &cmd_globals.lock ); |
700 | return rc; |
701 | } |
702 | |
703 | /***************************************************************************** |
704 | * |
705 | * Registers multiple commands. |
706 | * |
707 | *****************************************************************************/ |
708 | |
709 | VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry ) |
710 | { |
711 | VCOS_STATUS_T status; |
712 | |
713 | while ( cmd_entry->name != NULL ) |
714 | { |
715 | if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS ) |
716 | { |
717 | return status; |
718 | } |
719 | cmd_entry++; |
720 | } |
721 | return VCOS_SUCCESS; |
722 | } |
723 | |
724 | |