Make mvcp_unit_get actually return property value.
[melted] / src / mvcp / mvcp.c
1 /*
2 * mvcp.c -- High Level Client API for Melted
3 * Copyright (C) 2002-2009 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
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 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /* System header files */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26
27 /* Application header files */
28 #include "mvcp.h"
29 #include "mvcp_tokeniser.h"
30 #include "mvcp_util.h"
31
32 /** Initialise the mvcp structure.
33 */
34
35 mvcp mvcp_init( mvcp_parser parser )
36 {
37 mvcp this = malloc( sizeof( mvcp_t ) );
38 if ( this != NULL )
39 {
40 memset( this, 0, sizeof( mvcp_t ) );
41 this->parser = parser;
42 }
43 return this;
44 }
45
46 /** Set the response structure associated to the last command.
47 */
48
49 static void mvcp_set_last_response( mvcp this, mvcp_response response )
50 {
51 if ( this != NULL )
52 {
53 if ( this->last_response != NULL )
54 mvcp_response_close( this->last_response );
55 this->last_response = response;
56 }
57 }
58
59 /** Connect to the parser.
60 */
61
62 mvcp_error_code mvcp_connect( mvcp this )
63 {
64 mvcp_error_code error = mvcp_server_unavailable;
65 mvcp_response response = mvcp_parser_connect( this->parser );
66 if ( response != NULL )
67 {
68 mvcp_set_last_response( this, response );
69 if ( mvcp_response_get_error_code( response ) == 100 )
70 error = mvcp_ok;
71 }
72 return error;
73 }
74
75 /** Interpret a non-context sensitive error code.
76 */
77
78 static mvcp_error_code mvcp_get_error_code( mvcp this, mvcp_response response )
79 {
80 mvcp_error_code error = mvcp_server_unavailable;
81 switch( mvcp_response_get_error_code( response ) )
82 {
83 case -1:
84 error = mvcp_server_unavailable;
85 break;
86 case -2:
87 error = mvcp_no_response;
88 break;
89 case 200:
90 case 201:
91 case 202:
92 error = mvcp_ok;
93 break;
94 case 400:
95 error = mvcp_invalid_command;
96 break;
97 case 401:
98 error = mvcp_server_timeout;
99 break;
100 case 402:
101 error = mvcp_missing_argument;
102 break;
103 case 403:
104 error = mvcp_unit_unavailable;
105 break;
106 case 404:
107 error = mvcp_invalid_file;
108 break;
109 default:
110 case 500:
111 error = mvcp_unknown_error;
112 break;
113 }
114 return error;
115 }
116
117 /** Execute a command.
118 */
119
120 mvcp_error_code mvcp_execute( mvcp this, size_t size, const char *format, ... )
121 {
122 mvcp_error_code error = mvcp_server_unavailable;
123 char *command = malloc( size );
124 if ( this != NULL && command != NULL )
125 {
126 va_list list;
127 va_start( list, format );
128 if ( vsnprintf( command, size, format, list ) != 0 )
129 {
130 mvcp_response response = mvcp_parser_execute( this->parser, command );
131 mvcp_set_last_response( this, response );
132 error = mvcp_get_error_code( this, response );
133 }
134 else
135 {
136 error = mvcp_invalid_command;
137 }
138 va_end( list );
139 }
140 else
141 {
142 error = mvcp_malloc_failed;
143 }
144 free( command );
145 return error;
146 }
147
148 /** Execute a command.
149 */
150
151 mvcp_error_code mvcp_receive( mvcp this, char *doc, size_t size, const char *format, ... )
152 {
153 mvcp_error_code error = mvcp_server_unavailable;
154 char *command = malloc( size );
155 if ( this != NULL && command != NULL )
156 {
157 va_list list;
158 va_start( list, format );
159 if ( vsnprintf( command, size, format, list ) != 0 )
160 {
161 mvcp_response response = mvcp_parser_received( this->parser, command, doc );
162 mvcp_set_last_response( this, response );
163 error = mvcp_get_error_code( this, response );
164 }
165 else
166 {
167 error = mvcp_invalid_command;
168 }
169 va_end( list );
170 }
171 else
172 {
173 error = mvcp_malloc_failed;
174 }
175 free( command );
176 return error;
177 }
178
179 /** Execute a command.
180 */
181
182 mvcp_error_code mvcp_push( mvcp this, mlt_service service, size_t size, const char *format, ... )
183 {
184 mvcp_error_code error = mvcp_server_unavailable;
185 char *command = malloc( size );
186 if ( this != NULL && command != NULL )
187 {
188 va_list list;
189 va_start( list, format );
190 if ( vsnprintf( command, size, format, list ) != 0 )
191 {
192 mvcp_response response = mvcp_parser_push( this->parser, command, service );
193 mvcp_set_last_response( this, response );
194 error = mvcp_get_error_code( this, response );
195 }
196 else
197 {
198 error = mvcp_invalid_command;
199 }
200 va_end( list );
201 }
202 else
203 {
204 error = mvcp_malloc_failed;
205 }
206 free( command );
207 return error;
208 }
209
210 /** Set a global property.
211 */
212
213 mvcp_error_code mvcp_set( mvcp this, char *property, char *value )
214 {
215 return mvcp_execute( this, 1024, "SET %s=%s", property, value );
216 }
217
218 /** Get a global property.
219 */
220
221 mvcp_error_code mvcp_get( mvcp this, char *property, char *value, int length )
222 {
223 mvcp_error_code error = mvcp_execute( this, 1024, "GET %s", property );
224 if ( error == mvcp_ok )
225 {
226 mvcp_response response = mvcp_get_last_response( this );
227 strncpy( value, mvcp_response_get_line( response, 1 ), length );
228 }
229 return error;
230 }
231
232 /** Run a script.
233 */
234
235 mvcp_error_code mvcp_run( mvcp this, char *file )
236 {
237 return mvcp_execute( this, 10240, "RUN \"%s\"", file );
238 }
239
240 /** Add a unit.
241 */
242
243 mvcp_error_code mvcp_unit_add( mvcp this, char *guid, int *unit )
244 {
245 mvcp_error_code error = mvcp_execute( this, 1024, "UADD %s", guid );
246 if ( error == mvcp_ok )
247 {
248 int length = mvcp_response_count( this->last_response );
249 char *line = mvcp_response_get_line( this->last_response, length - 1 );
250 if ( line == NULL || sscanf( line, "U%d", unit ) != 1 )
251 error = mvcp_unit_creation_failed;
252 }
253 else
254 {
255 if ( error == mvcp_unknown_error )
256 error = mvcp_unit_creation_failed;
257 }
258 return error;
259 }
260
261 /** Load a file on the specified unit.
262 */
263
264 mvcp_error_code mvcp_unit_load( mvcp this, int unit, char *file )
265 {
266 return mvcp_execute( this, 10240, "LOAD U%d \"%s\"", unit, file );
267 }
268
269 static void mvcp_interpret_clip_offset( char *output, mvcp_clip_offset offset, int clip )
270 {
271 switch( offset )
272 {
273 case mvcp_absolute:
274 sprintf( output, "%d", clip );
275 break;
276 case mvcp_relative:
277 if ( clip < 0 )
278 sprintf( output, "%d", clip );
279 else
280 sprintf( output, "+%d", clip );
281 break;
282 }
283 }
284
285 /** Load a file on the specified unit with the specified in/out points.
286 */
287
288 mvcp_error_code mvcp_unit_load_clipped( mvcp this, int unit, char *file, int32_t in, int32_t out )
289 {
290 return mvcp_execute( this, 10240, "LOAD U%d \"%s\" %d %d", unit, file, in, out );
291 }
292
293 /** Load a file on the specified unit at the end of the current pump.
294 */
295
296 mvcp_error_code mvcp_unit_load_back( mvcp this, int unit, char *file )
297 {
298 return mvcp_execute( this, 10240, "LOAD U%d \"!%s\"", unit, file );
299 }
300
301 /** Load a file on the specified unit at the end of the pump with the specified in/out points.
302 */
303
304 mvcp_error_code mvcp_unit_load_back_clipped( mvcp this, int unit, char *file, int32_t in, int32_t out )
305 {
306 return mvcp_execute( this, 10240, "LOAD U%d \"!%s\" %d %d", unit, file, in, out );
307 }
308
309 /** Append a file on the specified unit.
310 */
311
312 mvcp_error_code mvcp_unit_append( mvcp this, int unit, char *file, int32_t in, int32_t out )
313 {
314 return mvcp_execute( this, 10240, "APND U%d \"%s\" %d %d", unit, file, in, out );
315 }
316
317 /** Push a service on to a unit.
318 */
319
320 mvcp_error_code mvcp_unit_receive( mvcp this, int unit, char *command, char *doc )
321 {
322 return mvcp_receive( this, doc, 10240, "PUSH U%d %s", unit, command );
323 }
324
325 /** Push a service on to a unit.
326 */
327
328 mvcp_error_code mvcp_unit_push( mvcp this, int unit, char *command, mlt_service service )
329 {
330 return mvcp_push( this, service, 10240, "PUSH U%d %s", unit, command );
331 }
332
333 /** Clean the unit - this function removes all but the currently playing clip.
334 */
335
336 mvcp_error_code mvcp_unit_clean( mvcp this, int unit )
337 {
338 return mvcp_execute( this, 1024, "CLEAN U%d", unit );
339 }
340
341 /** Clear the unit - this function removes all clips.
342 */
343
344 mvcp_error_code mvcp_unit_clear( mvcp this, int unit )
345 {
346 return mvcp_execute( this, 1024, "CLEAR U%d", unit );
347 }
348
349 /** Wipe the unit - this function removes all clips before the current one.
350 */
351
352 mvcp_error_code mvcp_unit_wipe( mvcp this, int unit )
353 {
354 return mvcp_execute( this, 1024, "WIPE U%d", unit );
355 }
356
357 /** Move clips on the units playlist.
358 */
359
360 mvcp_error_code mvcp_unit_clip_move( mvcp this, int unit, mvcp_clip_offset src_offset, int src, mvcp_clip_offset dest_offset, int dest )
361 {
362 char temp1[ 100 ];
363 char temp2[ 100 ];
364 mvcp_interpret_clip_offset( temp1, src_offset, src );
365 mvcp_interpret_clip_offset( temp2, dest_offset, dest );
366 return mvcp_execute( this, 1024, "MOVE U%d %s %s", unit, temp1, temp2 );
367 }
368
369 /** Remove clip at the specified position.
370 */
371
372 mvcp_error_code mvcp_unit_clip_remove( mvcp this, int unit, mvcp_clip_offset offset, int clip )
373 {
374 char temp[ 100 ];
375 mvcp_interpret_clip_offset( temp, offset, clip );
376 return mvcp_execute( this, 1024, "REMOVE U%d %s", unit, temp );
377 }
378
379 /** Remove the currently playing clip.
380 */
381
382 mvcp_error_code mvcp_unit_remove_current_clip( mvcp this, int unit )
383 {
384 return mvcp_execute( this, 1024, "REMOVE U%d", unit );
385 }
386
387 /** Insert clip at the specified position.
388 */
389
390 mvcp_error_code mvcp_unit_clip_insert( mvcp this, int unit, mvcp_clip_offset offset, int clip, char *file, int32_t in, int32_t out )
391 {
392 char temp[ 100 ];
393 mvcp_interpret_clip_offset( temp, offset, clip );
394 return mvcp_execute( this, 1024, "INSERT U%d \"%s\" %s %d %d", unit, file, temp, in, out );
395 }
396
397 /** Play the unit at normal speed.
398 */
399
400 mvcp_error_code mvcp_unit_play( mvcp this, int unit )
401 {
402 return mvcp_execute( this, 1024, "PLAY U%d 1000", unit );
403 }
404
405 /** Play the unit at specified speed.
406 */
407
408 mvcp_error_code mvcp_unit_play_at_speed( mvcp this, int unit, int speed )
409 {
410 return mvcp_execute( this, 10240, "PLAY U%d %d", unit, speed );
411 }
412
413 /** Stop playback on the specified unit.
414 */
415
416 mvcp_error_code mvcp_unit_stop( mvcp this, int unit )
417 {
418 return mvcp_execute( this, 1024, "STOP U%d", unit );
419 }
420
421 /** Pause playback on the specified unit.
422 */
423
424 mvcp_error_code mvcp_unit_pause( mvcp this, int unit )
425 {
426 return mvcp_execute( this, 1024, "PAUSE U%d", unit );
427 }
428
429 /** Rewind the specified unit.
430 */
431
432 mvcp_error_code mvcp_unit_rewind( mvcp this, int unit )
433 {
434 return mvcp_execute( this, 1024, "REW U%d", unit );
435 }
436
437 /** Fast forward the specified unit.
438 */
439
440 mvcp_error_code mvcp_unit_fast_forward( mvcp this, int unit )
441 {
442 return mvcp_execute( this, 1024, "FF U%d", unit );
443 }
444
445 /** Step by the number of frames on the specified unit.
446 */
447
448 mvcp_error_code mvcp_unit_step( mvcp this, int unit, int32_t step )
449 {
450 return mvcp_execute( this, 1024, "STEP U%d %d", unit, step );
451 }
452
453 /** Goto the specified frame on the specified unit.
454 */
455
456 mvcp_error_code mvcp_unit_goto( mvcp this, int unit, int32_t position )
457 {
458 return mvcp_execute( this, 1024, "GOTO U%d %d", unit, position );
459 }
460
461 /** Goto the specified frame in the clip on the specified unit.
462 */
463
464 mvcp_error_code mvcp_unit_clip_goto( mvcp this, int unit, mvcp_clip_offset offset, int clip, int32_t position )
465 {
466 char temp[ 100 ];
467 mvcp_interpret_clip_offset( temp, offset, clip );
468 return mvcp_execute( this, 1024, "GOTO U%d %d %s", unit, position, temp );
469 }
470
471 /** Set the in point of the loaded file on the specified unit.
472 */
473
474 mvcp_error_code mvcp_unit_set_in( mvcp this, int unit, int32_t in )
475 {
476 return mvcp_execute( this, 1024, "SIN U%d %d", unit, in );
477 }
478
479 /** Set the in point of the clip on the specified unit.
480 */
481
482 mvcp_error_code mvcp_unit_clip_set_in( mvcp this, int unit, mvcp_clip_offset offset, int clip, int32_t in )
483 {
484 char temp[ 100 ];
485 mvcp_interpret_clip_offset( temp, offset, clip );
486 return mvcp_execute( this, 1024, "SIN U%d %d %s", unit, in, temp );
487 }
488
489 /** Set the out point of the loaded file on the specified unit.
490 */
491
492 mvcp_error_code mvcp_unit_set_out( mvcp this, int unit, int32_t out )
493 {
494 return mvcp_execute( this, 1024, "SOUT U%d %d", unit, out );
495 }
496
497 /** Set the out point of the clip on the specified unit.
498 */
499
500 mvcp_error_code mvcp_unit_clip_set_out( mvcp this, int unit, mvcp_clip_offset offset, int clip, int32_t in )
501 {
502 char temp[ 100 ];
503 mvcp_interpret_clip_offset( temp, offset, clip );
504 return mvcp_execute( this, 1024, "SOUT U%d %d %s", unit, in, temp );
505 }
506
507 /** Clear the in point of the loaded file on the specified unit.
508 */
509
510 mvcp_error_code mvcp_unit_clear_in( mvcp this, int unit )
511 {
512 return mvcp_execute( this, 1024, "SIN U%d -1", unit );
513 }
514
515 /** Clear the out point of the loaded file on the specified unit.
516 */
517
518 mvcp_error_code mvcp_unit_clear_out( mvcp this, int unit )
519 {
520 return mvcp_execute( this, 1024, "SOUT U%d -1", unit );
521 }
522
523 /** Clear the in and out points on the loaded file on the specified unit.
524 */
525
526 mvcp_error_code mvcp_unit_clear_in_out( mvcp this, int unit )
527 {
528 mvcp_error_code error = mvcp_unit_clear_out( this, unit );
529 if ( error == mvcp_ok )
530 error = mvcp_unit_clear_in( this, unit );
531 return error;
532 }
533
534 /** Set a unit configuration property.
535 */
536
537 mvcp_error_code mvcp_unit_set( mvcp this, int unit, const char *name, const char *value )
538 {
539 return mvcp_execute( this, 1024, "USET U%d %s=%s", unit, name, value );
540 }
541
542 /** Get a unit configuration property.
543 */
544
545 mvcp_error_code mvcp_unit_get( mvcp this, int unit, char *name, char *value, int length )
546 {
547 mvcp_error_code error = mvcp_execute( this, 1024, "UGET U%d %s", unit, name );
548 if ( error == mvcp_ok )
549 {
550 mvcp_response response = mvcp_get_last_response( this );
551 strncpy( value, mvcp_response_get_line( response, 1 ), length );
552 }
553 return error;
554 }
555
556 /** Get a units status.
557 */
558
559 mvcp_error_code mvcp_unit_status( mvcp this, int unit, mvcp_status status )
560 {
561 mvcp_error_code error = mvcp_execute( this, 1024, "USTA U%d", unit );
562 int error_code = mvcp_response_get_error_code( this->last_response );
563
564 memset( status, 0, sizeof( mvcp_status_t ) );
565 status->unit = unit;
566 if ( error_code == 202 && mvcp_response_count( this->last_response ) == 2 )
567 mvcp_status_parse( status, mvcp_response_get_line( this->last_response, 1 ) );
568 else if ( error_code == 403 )
569 status->status = unit_undefined;
570
571 return error;
572 }
573
574 /** Transfer the current settings of unit src to unit dest.
575 */
576
577 mvcp_error_code mvcp_unit_transfer( mvcp this, int src, int dest )
578 {
579 return mvcp_execute( this, 1024, "XFER U%d U%d", src, dest );
580 }
581
582 /** Obtain the parsers notifier.
583 */
584
585 mvcp_notifier mvcp_get_notifier( mvcp this )
586 {
587 if ( this != NULL )
588 return mvcp_parser_get_notifier( this->parser );
589 else
590 return NULL;
591 }
592
593 /** List the contents of the specified directory.
594 */
595
596 mvcp_dir mvcp_dir_init( mvcp this, const char *directory )
597 {
598 mvcp_dir dir = malloc( sizeof( mvcp_dir_t ) );
599 if ( dir != NULL )
600 {
601 memset( dir, 0, sizeof( mvcp_dir_t ) );
602 dir->directory = strdup( directory );
603 dir->response = mvcp_parser_executef( this->parser, "CLS \"%s\"", directory );
604 }
605 return dir;
606 }
607
608 /** Return the error code associated to the dir.
609 */
610
611 mvcp_error_code mvcp_dir_get_error_code( mvcp_dir dir )
612 {
613 if ( dir != NULL )
614 return mvcp_get_error_code( NULL, dir->response );
615 else
616 return mvcp_malloc_failed;
617 }
618
619 /** Get a particular file entry in the directory.
620 */
621
622 mvcp_error_code mvcp_dir_get( mvcp_dir dir, int index, mvcp_dir_entry entry )
623 {
624 mvcp_error_code error = mvcp_ok;
625 memset( entry, 0, sizeof( mvcp_dir_entry_t ) );
626 if ( index < mvcp_dir_count( dir ) )
627 {
628 char *line = mvcp_response_get_line( dir->response, index + 1 );
629 mvcp_tokeniser tokeniser = mvcp_tokeniser_init( );
630 mvcp_tokeniser_parse_new( tokeniser, line, " " );
631
632 if ( mvcp_tokeniser_count( tokeniser ) > 0 )
633 {
634 mvcp_util_strip( mvcp_tokeniser_get_string( tokeniser, 0 ), '\"' );
635 strcpy( entry->full, dir->directory );
636 if ( entry->full[ strlen( entry->full ) - 1 ] != '/' )
637 strcat( entry->full, "/" );
638 strcpy( entry->name, mvcp_tokeniser_get_string( tokeniser, 0 ) );
639 strcat( entry->full, entry->name );
640
641 switch ( mvcp_tokeniser_count( tokeniser ) )
642 {
643 case 1:
644 entry->dir = 1;
645 break;
646 case 2:
647 entry->size = strtoull( mvcp_tokeniser_get_string( tokeniser, 1 ), NULL, 10 );
648 break;
649 default:
650 error = mvcp_invalid_file;
651 break;
652 }
653 }
654 mvcp_tokeniser_close( tokeniser );
655 }
656 return error;
657 }
658
659 /** Get the number of entries in the directory
660 */
661
662 int mvcp_dir_count( mvcp_dir dir )
663 {
664 if ( dir != NULL && mvcp_response_count( dir->response ) >= 2 )
665 return mvcp_response_count( dir->response ) - 2;
666 else
667 return -1;
668 }
669
670 /** Close the directory structure.
671 */
672
673 void mvcp_dir_close( mvcp_dir dir )
674 {
675 if ( dir != NULL )
676 {
677 free( dir->directory );
678 mvcp_response_close( dir->response );
679 free( dir );
680 }
681 }
682
683 /** List the playlist of the specified unit.
684 */
685
686 mvcp_list mvcp_list_init( mvcp this, int unit )
687 {
688 mvcp_list list = calloc( 1, sizeof( mvcp_list_t ) );
689 if ( list != NULL )
690 {
691 list->response = mvcp_parser_executef( this->parser, "LIST U%d", unit );
692 if ( mvcp_response_count( list->response ) >= 2 )
693 list->generation = atoi( mvcp_response_get_line( list->response, 1 ) );
694 }
695 return list;
696 }
697
698 /** Return the error code associated to the list.
699 */
700
701 mvcp_error_code mvcp_list_get_error_code( mvcp_list list )
702 {
703 if ( list != NULL )
704 return mvcp_get_error_code( NULL, list->response );
705 else
706 return mvcp_malloc_failed;
707 }
708
709 /** Get a particular file entry in the list.
710 */
711
712 mvcp_error_code mvcp_list_get( mvcp_list list, int index, mvcp_list_entry entry )
713 {
714 mvcp_error_code error = mvcp_ok;
715 memset( entry, 0, sizeof( mvcp_list_entry_t ) );
716 if ( index < mvcp_list_count( list ) )
717 {
718 char *line = mvcp_response_get_line( list->response, index + 2 );
719 mvcp_tokeniser tokeniser = mvcp_tokeniser_init( );
720 mvcp_tokeniser_parse_new( tokeniser, line, " " );
721
722 if ( mvcp_tokeniser_count( tokeniser ) > 0 )
723 {
724 entry->clip = atoi( mvcp_tokeniser_get_string( tokeniser, 0 ) );
725 mvcp_util_strip( mvcp_tokeniser_get_string( tokeniser, 1 ), '\"' );
726 strcpy( entry->full, mvcp_tokeniser_get_string( tokeniser, 1 ) );
727 entry->in = atol( mvcp_tokeniser_get_string( tokeniser, 2 ) );
728 entry->out = atol( mvcp_tokeniser_get_string( tokeniser, 3 ) );
729 entry->max = atol( mvcp_tokeniser_get_string( tokeniser, 4 ) );
730 entry->size = atol( mvcp_tokeniser_get_string( tokeniser, 5 ) );
731 entry->fps = atof( mvcp_tokeniser_get_string( tokeniser, 6 ) );
732 }
733 mvcp_tokeniser_close( tokeniser );
734 }
735 return error;
736 }
737
738 /** Get the number of entries in the list
739 */
740
741 int mvcp_list_count( mvcp_list list )
742 {
743 if ( list != NULL && mvcp_response_count( list->response ) >= 3 )
744 return mvcp_response_count( list->response ) - 3;
745 else
746 return -1;
747 }
748
749 /** Close the list structure.
750 */
751
752 void mvcp_list_close( mvcp_list list )
753 {
754 if ( list != NULL )
755 {
756 mvcp_response_close( list->response );
757 free( list );
758 }
759 }
760
761 /** List the currently connected nodes.
762 */
763
764 mvcp_nodes mvcp_nodes_init( mvcp this )
765 {
766 mvcp_nodes nodes = malloc( sizeof( mvcp_nodes_t ) );
767 if ( nodes != NULL )
768 {
769 memset( nodes, 0, sizeof( mvcp_nodes_t ) );
770 nodes->response = mvcp_parser_executef( this->parser, "NLS" );
771 }
772 return nodes;
773 }
774
775 /** Return the error code associated to the nodes list.
776 */
777
778 mvcp_error_code mvcp_nodes_get_error_code( mvcp_nodes nodes )
779 {
780 if ( nodes != NULL )
781 return mvcp_get_error_code( NULL, nodes->response );
782 else
783 return mvcp_malloc_failed;
784 }
785
786 /** Get a particular node entry.
787 */
788
789 mvcp_error_code mvcp_nodes_get( mvcp_nodes nodes, int index, mvcp_node_entry entry )
790 {
791 mvcp_error_code error = mvcp_ok;
792 memset( entry, 0, sizeof( mvcp_node_entry_t ) );
793 if ( index < mvcp_nodes_count( nodes ) )
794 {
795 char *line = mvcp_response_get_line( nodes->response, index + 1 );
796 mvcp_tokeniser tokeniser = mvcp_tokeniser_init( );
797 mvcp_tokeniser_parse_new( tokeniser, line, " " );
798
799 if ( mvcp_tokeniser_count( tokeniser ) == 3 )
800 {
801 entry->node = atoi( mvcp_tokeniser_get_string( tokeniser, 0 ) );
802 strncpy( entry->guid, mvcp_tokeniser_get_string( tokeniser, 1 ), sizeof( entry->guid ) );
803 mvcp_util_strip( mvcp_tokeniser_get_string( tokeniser, 2 ), '\"' );
804 strncpy( entry->name, mvcp_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->name ) );
805 }
806
807 mvcp_tokeniser_close( tokeniser );
808 }
809 return error;
810 }
811
812 /** Get the number of nodes
813 */
814
815 int mvcp_nodes_count( mvcp_nodes nodes )
816 {
817 if ( nodes != NULL && mvcp_response_count( nodes->response ) >= 2 )
818 return mvcp_response_count( nodes->response ) - 2;
819 else
820 return -1;
821 }
822
823 /** Close the nodes structure.
824 */
825
826 void mvcp_nodes_close( mvcp_nodes nodes )
827 {
828 if ( nodes != NULL )
829 {
830 mvcp_response_close( nodes->response );
831 free( nodes );
832 }
833 }
834
835 /** List the currently defined units.
836 */
837
838 mvcp_units mvcp_units_init( mvcp this )
839 {
840 mvcp_units units = malloc( sizeof( mvcp_units_t ) );
841 if ( units != NULL )
842 {
843 memset( units, 0, sizeof( mvcp_units_t ) );
844 units->response = mvcp_parser_executef( this->parser, "ULS" );
845 }
846 return units;
847 }
848
849 /** Return the error code associated to the nodes list.
850 */
851
852 mvcp_error_code mvcp_units_get_error_code( mvcp_units units )
853 {
854 if ( units != NULL )
855 return mvcp_get_error_code( NULL, units->response );
856 else
857 return mvcp_malloc_failed;
858 }
859
860 /** Get a particular unit entry.
861 */
862
863 mvcp_error_code mvcp_units_get( mvcp_units units, int index, mvcp_unit_entry entry )
864 {
865 mvcp_error_code error = mvcp_ok;
866 memset( entry, 0, sizeof( mvcp_unit_entry_t ) );
867 if ( index < mvcp_units_count( units ) )
868 {
869 char *line = mvcp_response_get_line( units->response, index + 1 );
870 mvcp_tokeniser tokeniser = mvcp_tokeniser_init( );
871 mvcp_tokeniser_parse_new( tokeniser, line, " " );
872
873 if ( mvcp_tokeniser_count( tokeniser ) == 4 )
874 {
875 entry->unit = atoi( mvcp_tokeniser_get_string( tokeniser, 0 ) + 1 );
876 entry->node = atoi( mvcp_tokeniser_get_string( tokeniser, 1 ) );
877 strncpy( entry->guid, mvcp_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->guid ) );
878 entry->online = atoi( mvcp_tokeniser_get_string( tokeniser, 3 ) );
879 }
880
881 mvcp_tokeniser_close( tokeniser );
882 }
883 return error;
884 }
885
886 /** Get the number of units
887 */
888
889 int mvcp_units_count( mvcp_units units )
890 {
891 if ( units != NULL && mvcp_response_count( units->response ) >= 2 )
892 return mvcp_response_count( units->response ) - 2;
893 else
894 return -1;
895 }
896
897 /** Close the units structure.
898 */
899
900 void mvcp_units_close( mvcp_units units )
901 {
902 if ( units != NULL )
903 {
904 mvcp_response_close( units->response );
905 free( units );
906 }
907 }
908
909 /** Get the response of the last command executed.
910 */
911
912 mvcp_response mvcp_get_last_response( mvcp this )
913 {
914 return this->last_response;
915 }
916
917 /** Obtain a printable message associated to the error code provided.
918 */
919
920 const char *mvcp_error_description( mvcp_error_code error )
921 {
922 const char *msg = "Unrecognised error";
923 switch( error )
924 {
925 case mvcp_ok:
926 msg = "OK";
927 break;
928 case mvcp_malloc_failed:
929 msg = "Memory allocation error";
930 break;
931 case mvcp_unknown_error:
932 msg = "Unknown error";
933 break;
934 case mvcp_no_response:
935 msg = "No response obtained";
936 break;
937 case mvcp_invalid_command:
938 msg = "Invalid command";
939 break;
940 case mvcp_server_timeout:
941 msg = "Communications with server timed out";
942 break;
943 case mvcp_missing_argument:
944 msg = "Missing argument";
945 break;
946 case mvcp_server_unavailable:
947 msg = "Unable to communicate with server";
948 break;
949 case mvcp_unit_creation_failed:
950 msg = "Unit creation failed";
951 break;
952 case mvcp_unit_unavailable:
953 msg = "Unit unavailable";
954 break;
955 case mvcp_invalid_file:
956 msg = "Invalid file";
957 break;
958 case mvcp_invalid_position:
959 msg = "Invalid position";
960 break;
961 }
962 return msg;
963 }
964
965 /** Close the mvcp structure.
966 */
967
968 void mvcp_close( mvcp this )
969 {
970 if ( this != NULL )
971 {
972 mvcp_set_last_response( this, NULL );
973 free( this );
974 }
975 }