]> git.sesse.net Git - mlt/blob - src/valerie/valerie.c
Threading considerations and DVCP WIPE introduced
[mlt] / src / valerie / valerie.c
1 /*
2  * valerie.c -- High Level Client API for miracle
3  * Copyright (C) 2002-2003 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 "valerie.h"
29 #include "valerie_tokeniser.h"
30 #include "valerie_util.h"
31
32 /** Initialise the valerie structure.
33 */
34
35 valerie valerie_init( valerie_parser parser )
36 {
37         valerie this = malloc( sizeof( valerie_t ) );
38         if ( this != NULL )
39         {
40                 memset( this, 0, sizeof( valerie_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 valerie_set_last_response( valerie this, valerie_response response )
50 {
51         if ( this != NULL )
52         {
53                 if ( this->last_response != NULL )
54                         valerie_response_close( this->last_response );
55                 this->last_response = response;
56         }
57 }
58
59 /** Connect to the parser.
60 */
61
62 valerie_error_code valerie_connect( valerie this )
63 {
64         valerie_error_code error = valerie_server_unavailable;
65         valerie_response response = valerie_parser_connect( this->parser );
66         if ( response != NULL )
67         {
68                 valerie_set_last_response( this, response );
69                 if ( valerie_response_get_error_code( response ) == 100 )
70                         error = valerie_ok;
71         }
72         return error;
73 }
74
75 /** Interpret a non-context sensitive error code.
76 */
77
78 static valerie_error_code valerie_get_error_code( valerie this, valerie_response response )
79 {
80         valerie_error_code error = valerie_server_unavailable;
81         switch( valerie_response_get_error_code( response ) )
82         {
83                 case -1:
84                         error = valerie_server_unavailable;
85                         break;
86                 case -2:
87                         error = valerie_no_response;
88                         break;
89                 case 200:
90                 case 201:
91                 case 202:
92                         error = valerie_ok;
93                         break;
94                 case 400:
95                         error = valerie_invalid_command;
96                         break;
97                 case 401:
98                         error = valerie_server_timeout;
99                         break;
100                 case 402:
101                         error = valerie_missing_argument;
102                         break;
103                 case 403:
104                         error = valerie_unit_unavailable;
105                         break;
106                 case 404:
107                         error = valerie_invalid_file;
108                         break;
109                 default:
110                 case 500:
111                         error = valerie_unknown_error;
112                         break;
113         }
114         return error;
115 }
116
117 /** Execute a command.
118 */
119
120 valerie_error_code valerie_execute( valerie this, size_t size, char *format, ... )
121 {
122         valerie_error_code error = valerie_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                         valerie_response response = valerie_parser_execute( this->parser, command );
131                         valerie_set_last_response( this, response );
132                         error = valerie_get_error_code( this, response );
133                 }
134                 else
135                 {
136                         error = valerie_invalid_command;
137                 }
138                 va_end( list );
139         }
140         else
141         {
142                 error = valerie_malloc_failed;
143         }
144         free( command );
145         return error;
146 }
147
148 /** Execute a command.
149 */
150
151 valerie_error_code valerie_receive( valerie this, char *doc, size_t size, char *format, ... )
152 {
153         valerie_error_code error = valerie_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                         valerie_response response = valerie_parser_received( this->parser, command, doc );
162                         valerie_set_last_response( this, response );
163                         error = valerie_get_error_code( this, response );
164                 }
165                 else
166                 {
167                         error = valerie_invalid_command;
168                 }
169                 va_end( list );
170         }
171         else
172         {
173                 error = valerie_malloc_failed;
174         }
175         free( command );
176         return error;
177 }
178
179 /** Execute a command.
180 */
181
182 valerie_error_code valerie_push( valerie this, mlt_service service, size_t size, char *format, ... )
183 {
184         valerie_error_code error = valerie_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                         valerie_response response = valerie_parser_push( this->parser, command, service );
193                         valerie_set_last_response( this, response );
194                         error = valerie_get_error_code( this, response );
195                 }
196                 else
197                 {
198                         error = valerie_invalid_command;
199                 }
200                 va_end( list );
201         }
202         else
203         {
204                 error = valerie_malloc_failed;
205         }
206         free( command );
207         return error;
208 }
209
210 /** Set a global property.
211 */
212
213 valerie_error_code valerie_set( valerie this, char *property, char *value )
214 {
215         return valerie_execute( this, 1024, "SET %s=%s", property, value );
216 }
217
218 /** Get a global property.
219 */
220
221 valerie_error_code valerie_get( valerie this, char *property, char *value, int length )
222 {
223         valerie_error_code error = valerie_execute( this, 1024, "GET %s", property );
224         if ( error == valerie_ok )
225         {
226                 valerie_response response = valerie_get_last_response( this );
227                 strncpy( value, valerie_response_get_line( response, 1 ), length );
228         }
229         return error;
230 }
231
232 /** Run a script.
233 */
234
235 valerie_error_code valerie_run( valerie this, char *file )
236 {
237         return valerie_execute( this, 10240, "RUN \"%s\"", file );
238 }
239
240 /** Add a unit.
241 */
242
243 valerie_error_code valerie_unit_add( valerie this, char *guid, int *unit )
244 {
245         valerie_error_code error = valerie_execute( this, 1024, "UADD %s", guid );
246         if ( error == valerie_ok )
247         {
248                 int length = valerie_response_count( this->last_response );
249                 char *line = valerie_response_get_line( this->last_response, length - 1 );
250                 if ( line == NULL || sscanf( line, "U%d", unit ) != 1 )
251                         error = valerie_unit_creation_failed;
252         }
253         else
254         {
255                 if ( error == valerie_unknown_error )
256                         error = valerie_unit_creation_failed;
257         }
258         return error;
259 }
260
261 /** Load a file on the specified unit.
262 */
263
264 valerie_error_code valerie_unit_load( valerie this, int unit, char *file )
265 {
266         return valerie_execute( this, 10240, "LOAD U%d \"%s\"", unit, file );
267 }
268
269 static void valerie_interpret_clip_offset( char *output, valerie_clip_offset offset, int clip )
270 {
271         switch( offset )
272         {
273                 case valerie_absolute:
274                         sprintf( output, "%d", clip );
275                         break;
276                 case valerie_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 valerie_error_code valerie_unit_load_clipped( valerie this, int unit, char *file, int32_t in, int32_t out )
289 {
290         return valerie_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 valerie_error_code valerie_unit_load_back( valerie this, int unit, char *file )
297 {
298         return valerie_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 valerie_error_code valerie_unit_load_back_clipped( valerie this, int unit, char *file, int32_t in, int32_t out )
305 {
306         return valerie_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 valerie_error_code valerie_unit_append( valerie this, int unit, char *file, int32_t in, int32_t out )
313 {
314         return valerie_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 valerie_error_code valerie_unit_receive( valerie this, int unit, char *command, char *doc )
321 {
322         return valerie_receive( this, doc, 10240, "PUSH U%d %s", unit, command );
323 }
324
325 /** Push a service on to a unit.
326 */
327
328 valerie_error_code valerie_unit_push( valerie this, int unit, char *command, mlt_service service )
329 {
330         return valerie_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 valerie_error_code valerie_unit_clean( valerie this, int unit )
337 {
338         return valerie_execute( this, 1024, "CLEAN U%d", unit );
339 }
340
341 /** Clear the unit - this function removes all clips.
342 */
343
344 valerie_error_code valerie_unit_clear( valerie this, int unit )
345 {
346         return valerie_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 valerie_error_code valerie_unit_wipe( valerie this, int unit )
353 {
354         return valerie_execute( this, 1024, "WIPE U%d", unit );
355 }
356
357 /** Move clips on the units playlist.
358 */
359
360 valerie_error_code valerie_unit_clip_move( valerie this, int unit, valerie_clip_offset src_offset, int src, valerie_clip_offset dest_offset, int dest )
361 {
362         char temp1[ 100 ];
363         char temp2[ 100 ];
364         valerie_interpret_clip_offset( temp1, src_offset, src );
365         valerie_interpret_clip_offset( temp2, dest_offset, dest );
366         return valerie_execute( this, 1024, "MOVE U%d %s %s", unit, temp1, temp2 );
367 }
368
369 /** Remove clip at the specified position.
370 */
371
372 valerie_error_code valerie_unit_clip_remove( valerie this, int unit, valerie_clip_offset offset, int clip )
373 {
374         char temp[ 100 ];
375         valerie_interpret_clip_offset( temp, offset, clip );
376         return valerie_execute( this, 1024, "REMOVE U%d %s", unit, temp );
377 }
378
379 /** Remove the currently playing clip.
380 */
381
382 valerie_error_code valerie_unit_remove_current_clip( valerie this, int unit )
383 {
384         return valerie_execute( this, 1024, "REMOVE U%d", unit );
385 }
386
387 /** Insert clip at the specified position.
388 */
389
390 valerie_error_code valerie_unit_clip_insert( valerie this, int unit, valerie_clip_offset offset, int clip, char *file, int32_t in, int32_t out )
391 {
392         char temp[ 100 ];
393         valerie_interpret_clip_offset( temp, offset, clip );
394         return valerie_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 valerie_error_code valerie_unit_play( valerie this, int unit )
401 {
402         return valerie_execute( this, 1024, "PLAY U%d 1000", unit );
403 }
404
405 /** Play the unit at specified speed.
406 */
407
408 valerie_error_code valerie_unit_play_at_speed( valerie this, int unit, int speed )
409 {
410         return valerie_execute( this, 10240, "PLAY U%d %d", unit, speed );
411 }
412
413 /** Stop playback on the specified unit.
414 */
415
416 valerie_error_code valerie_unit_stop( valerie this, int unit )
417 {
418         return valerie_execute( this, 1024, "STOP U%d", unit );
419 }
420
421 /** Pause playback on the specified unit.
422 */
423
424 valerie_error_code valerie_unit_pause( valerie this, int unit )
425 {
426         return valerie_execute( this, 1024, "PAUSE U%d", unit );
427 }
428
429 /** Rewind the specified unit.
430 */
431
432 valerie_error_code valerie_unit_rewind( valerie this, int unit )
433 {
434         return valerie_execute( this, 1024, "REW U%d", unit );
435 }
436
437 /** Fast forward the specified unit.
438 */
439
440 valerie_error_code valerie_unit_fast_forward( valerie this, int unit )
441 {
442         return valerie_execute( this, 1024, "FF U%d", unit );
443 }
444
445 /** Step by the number of frames on the specified unit.
446 */
447
448 valerie_error_code valerie_unit_step( valerie this, int unit, int32_t step )
449 {
450         return valerie_execute( this, 1024, "STEP U%d %d", unit, step );
451 }
452
453 /** Goto the specified frame on the specified unit.
454 */
455
456 valerie_error_code valerie_unit_goto( valerie this, int unit, int32_t position )
457 {
458         return valerie_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 valerie_error_code valerie_unit_clip_goto( valerie this, int unit, valerie_clip_offset offset, int clip, int32_t position )
465 {
466         char temp[ 100 ];
467         valerie_interpret_clip_offset( temp, offset, clip );
468         return valerie_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 valerie_error_code valerie_unit_set_in( valerie this, int unit, int32_t in )
475 {
476         return valerie_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 valerie_error_code valerie_unit_clip_set_in( valerie this, int unit, valerie_clip_offset offset, int clip, int32_t in )
483 {
484         char temp[ 100 ];
485         valerie_interpret_clip_offset( temp, offset, clip );
486         return valerie_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 valerie_error_code valerie_unit_set_out( valerie this, int unit, int32_t out )
493 {
494         return valerie_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 valerie_error_code valerie_unit_clip_set_out( valerie this, int unit, valerie_clip_offset offset, int clip, int32_t in )
501 {
502         char temp[ 100 ];
503         valerie_interpret_clip_offset( temp, offset, clip );
504         return valerie_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 valerie_error_code valerie_unit_clear_in( valerie this, int unit )
511 {
512         return valerie_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 valerie_error_code valerie_unit_clear_out( valerie this, int unit )
519 {
520         return valerie_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 valerie_error_code valerie_unit_clear_in_out( valerie this, int unit )
527 {
528         valerie_error_code error = valerie_unit_clear_out( this, unit );
529         if ( error == valerie_ok )
530                 error = valerie_unit_clear_in( this, unit );
531         return error;
532 }
533
534 /** Set a unit configuration property.
535 */
536
537 valerie_error_code valerie_unit_set( valerie this, int unit, char *name, char *value )
538 {
539         return valerie_execute( this, 1024, "USET U%d %s=%s", unit, name, value );
540 }
541
542 /** Get a unit configuration property.
543 */
544
545 valerie_error_code valerie_unit_get( valerie this, int unit, char *name )
546 {
547         return valerie_execute( this, 1024, "UGET U%d %s", unit, name );
548 }
549
550 /** Get a units status.
551 */
552
553 valerie_error_code valerie_unit_status( valerie this, int unit, valerie_status status )
554 {
555         valerie_error_code error = valerie_execute( this, 1024, "USTA U%d", unit );
556         int error_code = valerie_response_get_error_code( this->last_response );
557
558         memset( status, 0, sizeof( valerie_status_t ) );
559         status->unit = unit;
560         if ( error_code == 202 && valerie_response_count( this->last_response ) == 2 )
561                 valerie_status_parse( status, valerie_response_get_line( this->last_response, 1 ) );
562         else if ( error_code == 403 )
563                 status->status = unit_undefined;
564
565         return error;
566 }
567
568 /** Transfer the current settings of unit src to unit dest.
569 */
570
571 valerie_error_code valerie_unit_transfer( valerie this, int src, int dest )
572 {
573         return valerie_execute( this, 1024, "XFER U%d U%d", src, dest );
574 }
575
576 /** Obtain the parsers notifier.
577 */
578
579 valerie_notifier valerie_get_notifier( valerie this )
580 {
581         if ( this != NULL )
582                 return valerie_parser_get_notifier( this->parser );
583         else
584                 return NULL;
585 }
586
587 /** List the contents of the specified directory.
588 */
589
590 valerie_dir valerie_dir_init( valerie this, char *directory )
591 {
592         valerie_dir dir = malloc( sizeof( valerie_dir_t ) );
593         if ( dir != NULL )
594         {
595                 memset( dir, 0, sizeof( valerie_dir_t ) );
596                 dir->directory = strdup( directory );
597                 dir->response = valerie_parser_executef( this->parser, "CLS \"%s\"", directory );
598         }
599         return dir;
600 }
601
602 /** Return the error code associated to the dir.
603 */
604
605 valerie_error_code valerie_dir_get_error_code( valerie_dir dir )
606 {
607         if ( dir != NULL )
608                 return valerie_get_error_code( NULL, dir->response );
609         else
610                 return valerie_malloc_failed;
611 }
612
613 /** Get a particular file entry in the directory.
614 */
615
616 valerie_error_code valerie_dir_get( valerie_dir dir, int index, valerie_dir_entry entry )
617 {
618         valerie_error_code error = valerie_ok;
619         memset( entry, 0, sizeof( valerie_dir_entry_t ) );
620         if ( index < valerie_dir_count( dir ) )
621         {
622                 char *line = valerie_response_get_line( dir->response, index + 1 );
623                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
624                 valerie_tokeniser_parse_new( tokeniser, line, " " );
625
626                 if ( valerie_tokeniser_count( tokeniser ) > 0 )
627                 {
628                         valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 0 ), '\"' );
629                         strcpy( entry->full, dir->directory );
630                         if ( entry->full[ strlen( entry->full ) - 1 ] != '/' )
631                                 strcat( entry->full, "/" );
632                         strcpy( entry->name, valerie_tokeniser_get_string( tokeniser, 0 ) );
633                         strcat( entry->full, entry->name );
634
635                         switch ( valerie_tokeniser_count( tokeniser ) )
636                         {
637                                 case 1:
638                                         entry->dir = 1;
639                                         break;
640                                 case 2:
641                                         entry->size = strtoull( valerie_tokeniser_get_string( tokeniser, 1 ), NULL, 10 );
642                                         break;
643                                 default:
644                                         error = valerie_invalid_file;
645                                         break;
646                         }
647                 }
648                 valerie_tokeniser_close( tokeniser );
649         }
650         return error;
651 }
652
653 /** Get the number of entries in the directory
654 */
655
656 int valerie_dir_count( valerie_dir dir )
657 {
658         if ( dir != NULL && valerie_response_count( dir->response ) >= 2 )
659                 return valerie_response_count( dir->response ) - 2;
660         else
661                 return -1;
662 }
663
664 /** Close the directory structure.
665 */
666
667 void valerie_dir_close( valerie_dir dir )
668 {
669         if ( dir != NULL )
670         {
671                 free( dir->directory );
672                 valerie_response_close( dir->response );
673                 free( dir );
674         }
675 }
676
677 /** List the playlist of the specified unit.
678 */
679
680 valerie_list valerie_list_init( valerie this, int unit )
681 {
682         valerie_list list = calloc( 1, sizeof( valerie_list_t ) );
683         if ( list != NULL )
684         {
685                 list->response = valerie_parser_executef( this->parser, "LIST U%d", unit );
686                 if ( valerie_response_count( list->response ) >= 2 )
687                         list->generation = atoi( valerie_response_get_line( list->response, 1 ) );
688         }
689         return list;
690 }
691
692 /** Return the error code associated to the list.
693 */
694
695 valerie_error_code valerie_list_get_error_code( valerie_list list )
696 {
697         if ( list != NULL )
698                 return valerie_get_error_code( NULL, list->response );
699         else
700                 return valerie_malloc_failed;
701 }
702
703 /** Get a particular file entry in the list.
704 */
705
706 valerie_error_code valerie_list_get( valerie_list list, int index, valerie_list_entry entry )
707 {
708         valerie_error_code error = valerie_ok;
709         memset( entry, 0, sizeof( valerie_list_entry_t ) );
710         if ( index < valerie_list_count( list ) )
711         {
712                 char *line = valerie_response_get_line( list->response, index + 2 );
713                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
714                 valerie_tokeniser_parse_new( tokeniser, line, " " );
715
716                 if ( valerie_tokeniser_count( tokeniser ) > 0 )
717                 {
718                         entry->clip = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
719                         valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 1 ), '\"' );
720                         strcpy( entry->full, valerie_tokeniser_get_string( tokeniser, 1 ) );
721                         entry->in = atol( valerie_tokeniser_get_string( tokeniser, 2 ) );
722                         entry->out = atol( valerie_tokeniser_get_string( tokeniser, 3 ) );
723                         entry->max = atol( valerie_tokeniser_get_string( tokeniser, 4 ) );
724                         entry->size = atol( valerie_tokeniser_get_string( tokeniser, 5 ) );
725                         entry->fps = atof( valerie_tokeniser_get_string( tokeniser, 6 ) );
726                 }
727                 valerie_tokeniser_close( tokeniser );
728         }
729         return error;
730 }
731
732 /** Get the number of entries in the list
733 */
734
735 int valerie_list_count( valerie_list list )
736 {
737         if ( list != NULL && valerie_response_count( list->response ) >= 3 )
738                 return valerie_response_count( list->response ) - 3;
739         else
740                 return -1;
741 }
742
743 /** Close the list structure.
744 */
745
746 void valerie_list_close( valerie_list list )
747 {
748         if ( list != NULL )
749         {
750                 valerie_response_close( list->response );
751                 free( list );
752         }
753 }
754
755 /** List the currently connected nodes.
756 */
757
758 valerie_nodes valerie_nodes_init( valerie this )
759 {
760         valerie_nodes nodes = malloc( sizeof( valerie_nodes_t ) );
761         if ( nodes != NULL )
762         {
763                 memset( nodes, 0, sizeof( valerie_nodes_t ) );
764                 nodes->response = valerie_parser_executef( this->parser, "NLS" );
765         }
766         return nodes;
767 }
768
769 /** Return the error code associated to the nodes list.
770 */
771
772 valerie_error_code valerie_nodes_get_error_code( valerie_nodes nodes )
773 {
774         if ( nodes != NULL )
775                 return valerie_get_error_code( NULL, nodes->response );
776         else
777                 return valerie_malloc_failed;
778 }
779
780 /** Get a particular node entry.
781 */
782
783 valerie_error_code valerie_nodes_get( valerie_nodes nodes, int index, valerie_node_entry entry )
784 {
785         valerie_error_code error = valerie_ok;
786         memset( entry, 0, sizeof( valerie_node_entry_t ) );
787         if ( index < valerie_nodes_count( nodes ) )
788         {
789                 char *line = valerie_response_get_line( nodes->response, index + 1 );
790                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
791                 valerie_tokeniser_parse_new( tokeniser, line, " " );
792
793                 if ( valerie_tokeniser_count( tokeniser ) == 3 )
794                 {
795                         entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
796                         strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 1 ), sizeof( entry->guid ) );
797                         valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 2 ), '\"' );
798                         strncpy( entry->name, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->name ) );
799                 }
800
801                 valerie_tokeniser_close( tokeniser );
802         }
803         return error;
804 }
805
806 /** Get the number of nodes
807 */
808
809 int valerie_nodes_count( valerie_nodes nodes )
810 {
811         if ( nodes != NULL && valerie_response_count( nodes->response ) >= 2 )
812                 return valerie_response_count( nodes->response ) - 2;
813         else
814                 return -1;
815 }
816
817 /** Close the nodes structure.
818 */
819
820 void valerie_nodes_close( valerie_nodes nodes )
821 {
822         if ( nodes != NULL )
823         {
824                 valerie_response_close( nodes->response );
825                 free( nodes );
826         }
827 }
828
829 /** List the currently defined units.
830 */
831
832 valerie_units valerie_units_init( valerie this )
833 {
834         valerie_units units = malloc( sizeof( valerie_units_t ) );
835         if ( units != NULL )
836         {
837                 memset( units, 0, sizeof( valerie_units_t ) );
838                 units->response = valerie_parser_executef( this->parser, "ULS" );
839         }
840         return units;
841 }
842
843 /** Return the error code associated to the nodes list.
844 */
845
846 valerie_error_code valerie_units_get_error_code( valerie_units units )
847 {
848         if ( units != NULL )
849                 return valerie_get_error_code( NULL, units->response );
850         else
851                 return valerie_malloc_failed;
852 }
853
854 /** Get a particular unit entry.
855 */
856
857 valerie_error_code valerie_units_get( valerie_units units, int index, valerie_unit_entry entry )
858 {
859         valerie_error_code error = valerie_ok;
860         memset( entry, 0, sizeof( valerie_unit_entry_t ) );
861         if ( index < valerie_units_count( units ) )
862         {
863                 char *line = valerie_response_get_line( units->response, index + 1 );
864                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
865                 valerie_tokeniser_parse_new( tokeniser, line, " " );
866
867                 if ( valerie_tokeniser_count( tokeniser ) == 4 )
868                 {
869                         entry->unit = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) + 1 );
870                         entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 1 ) );
871                         strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->guid ) );
872                         entry->online = atoi( valerie_tokeniser_get_string( tokeniser, 3 ) );
873                 }
874
875                 valerie_tokeniser_close( tokeniser );
876         }
877         return error;
878 }
879
880 /** Get the number of units
881 */
882
883 int valerie_units_count( valerie_units units )
884 {
885         if ( units != NULL && valerie_response_count( units->response ) >= 2 )
886                 return valerie_response_count( units->response ) - 2;
887         else
888                 return -1;
889 }
890
891 /** Close the units structure.
892 */
893
894 void valerie_units_close( valerie_units units )
895 {
896         if ( units != NULL )
897         {
898                 valerie_response_close( units->response );
899                 free( units );
900         }
901 }
902
903 /** Get the response of the last command executed.
904 */
905
906 valerie_response valerie_get_last_response( valerie this )
907 {
908         return this->last_response;
909 }
910
911 /** Obtain a printable message associated to the error code provided.
912 */
913
914 char *valerie_error_description( valerie_error_code error )
915 {
916         char *msg = "Unrecognised error";
917         switch( error )
918         {
919                 case valerie_ok:
920                         msg = "OK";
921                         break;
922                 case valerie_malloc_failed:
923                         msg = "Memory allocation error";
924                         break;
925                 case valerie_unknown_error:
926                         msg = "Unknown error";
927                         break;
928                 case valerie_no_response:
929                         msg = "No response obtained";
930                         break;
931                 case valerie_invalid_command:
932                         msg = "Invalid command";
933                         break;
934                 case valerie_server_timeout:
935                         msg = "Communications with server timed out";
936                         break;
937                 case valerie_missing_argument:
938                         msg = "Missing argument";
939                         break;
940                 case valerie_server_unavailable:
941                         msg = "Unable to communicate with server";
942                         break;
943                 case valerie_unit_creation_failed:
944                         msg = "Unit creation failed";
945                         break;
946                 case valerie_unit_unavailable:
947                         msg = "Unit unavailable";
948                         break;
949                 case valerie_invalid_file:
950                         msg = "Invalid file";
951                         break;
952                 case valerie_invalid_position:
953                         msg = "Invalid position";
954                         break;
955         }
956         return msg;
957 }
958
959 /** Close the valerie structure.
960 */
961
962 void valerie_close( valerie this )
963 {
964         if ( this != NULL )
965         {
966                 valerie_set_last_response( this, NULL );
967                 free( this );
968         }
969 }