]> git.sesse.net Git - mlt/blob - src/valerie/valerie.c
Minor optimisations, consumer avformat experimentation
[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 /** Set a global property.
149 */
150
151 valerie_error_code valerie_set( valerie this, char *property, char *value )
152 {
153         return valerie_execute( this, 1024, "SET %s=%s", property, value );
154 }
155
156 /** Get a global property.
157 */
158
159 valerie_error_code valerie_get( valerie this, char *property, char *value, int length )
160 {
161         valerie_error_code error = valerie_execute( this, 1024, "GET %s", property );
162         if ( error == valerie_ok )
163         {
164                 valerie_response response = valerie_get_last_response( this );
165                 strncpy( value, valerie_response_get_line( response, 1 ), length );
166         }
167         return error;
168 }
169
170 /** Run a script.
171 */
172
173 valerie_error_code valerie_run( valerie this, char *file )
174 {
175         return valerie_execute( this, 10240, "RUN \"%s\"", file );
176 }
177
178 /** Add a unit.
179 */
180
181 valerie_error_code valerie_unit_add( valerie this, char *guid, int *unit )
182 {
183         valerie_error_code error = valerie_execute( this, 1024, "UADD %s", guid );
184         if ( error == valerie_ok )
185         {
186                 int length = valerie_response_count( this->last_response );
187                 char *line = valerie_response_get_line( this->last_response, length - 1 );
188                 if ( line == NULL || sscanf( line, "U%d", unit ) != 1 )
189                         error = valerie_unit_creation_failed;
190         }
191         else
192         {
193                 if ( error == valerie_unknown_error )
194                         error = valerie_unit_creation_failed;
195         }
196         return error;
197 }
198
199 /** Load a file on the specified unit.
200 */
201
202 valerie_error_code valerie_unit_load( valerie this, int unit, char *file )
203 {
204         return valerie_execute( this, 10240, "LOAD U%d \"%s\"", unit, file );
205 }
206
207 static void valerie_interpret_clip_offset( char *output, valerie_clip_offset offset, int clip )
208 {
209         switch( offset )
210         {
211                 case valerie_absolute:
212                         sprintf( output, "%d", clip );
213                         break;
214                 case valerie_relative:
215                         if ( clip < 0 )
216                                 sprintf( output, "%d", clip );
217                         else
218                                 sprintf( output, "+%d", clip );
219                         break;
220         }
221 }
222
223 /** Load a file on the specified unit with the specified in/out points.
224 */
225
226 valerie_error_code valerie_unit_load_clipped( valerie this, int unit, char *file, int32_t in, int32_t out )
227 {
228         return valerie_execute( this, 10240, "LOAD U%d \"%s\" %d %d", unit, file, in, out );
229 }
230
231 /** Load a file on the specified unit at the end of the current pump.
232 */
233
234 valerie_error_code valerie_unit_load_back( valerie this, int unit, char *file )
235 {
236         return valerie_execute( this, 10240, "LOAD U%d \"!%s\"", unit, file );
237 }
238
239 /** Load a file on the specified unit at the end of the pump with the specified in/out points.
240 */
241
242 valerie_error_code valerie_unit_load_back_clipped( valerie this, int unit, char *file, int32_t in, int32_t out )
243 {
244         return valerie_execute( this, 10240, "LOAD U%d \"!%s\" %d %d", unit, file, in, out );
245 }
246
247 /** Append a file on the specified unit.
248 */
249
250 valerie_error_code valerie_unit_append( valerie this, int unit, char *file, int32_t in, int32_t out )
251 {
252         return valerie_execute( this, 10240, "APND U%d \"%s\" %d %d", unit, file, in, out );
253 }
254
255 /** Clean the unit - this function removes all but the currently playing clip.
256 */
257
258 valerie_error_code valerie_unit_clean( valerie this, int unit )
259 {
260         return valerie_execute( this, 1024, "CLEAN U%d", unit );
261 }
262
263 /** Clear the unit - this function removes all clips.
264 */
265
266 valerie_error_code valerie_unit_clear( valerie this, int unit )
267 {
268         return valerie_execute( this, 1024, "CLEAR U%d", unit );
269 }
270
271 /** Move clips on the units playlist.
272 */
273
274 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 )
275 {
276         char temp1[ 100 ];
277         char temp2[ 100 ];
278         valerie_interpret_clip_offset( temp1, src_offset, src );
279         valerie_interpret_clip_offset( temp2, dest_offset, dest );
280         return valerie_execute( this, 1024, "MOVE U%d %s %s", unit, temp1, temp2 );
281 }
282
283 /** Remove clip at the specified position.
284 */
285
286 valerie_error_code valerie_unit_clip_remove( valerie this, int unit, valerie_clip_offset offset, int clip )
287 {
288         char temp[ 100 ];
289         valerie_interpret_clip_offset( temp, offset, clip );
290         return valerie_execute( this, 1024, "REMOVE U%d %s", unit, temp );
291 }
292
293 /** Remove the currently playing clip.
294 */
295
296 valerie_error_code valerie_unit_remove_current_clip( valerie this, int unit )
297 {
298         return valerie_execute( this, 1024, "REMOVE U%d", unit );
299 }
300
301 /** Insert clip at the specified position.
302 */
303
304 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 )
305 {
306         char temp[ 100 ];
307         valerie_interpret_clip_offset( temp, offset, clip );
308         return valerie_execute( this, 1024, "INSERT U%d \"%s\" %s %d %d", unit, file, temp, in, out );
309 }
310
311 /** Play the unit at normal speed.
312 */
313
314 valerie_error_code valerie_unit_play( valerie this, int unit )
315 {
316         return valerie_execute( this, 1024, "PLAY U%d 1000", unit );
317 }
318
319 /** Play the unit at specified speed.
320 */
321
322 valerie_error_code valerie_unit_play_at_speed( valerie this, int unit, int speed )
323 {
324         return valerie_execute( this, 10240, "PLAY U%d %d", unit, speed );
325 }
326
327 /** Stop playback on the specified unit.
328 */
329
330 valerie_error_code valerie_unit_stop( valerie this, int unit )
331 {
332         return valerie_execute( this, 1024, "STOP U%d", unit );
333 }
334
335 /** Pause playback on the specified unit.
336 */
337
338 valerie_error_code valerie_unit_pause( valerie this, int unit )
339 {
340         return valerie_execute( this, 1024, "PAUSE U%d", unit );
341 }
342
343 /** Rewind the specified unit.
344 */
345
346 valerie_error_code valerie_unit_rewind( valerie this, int unit )
347 {
348         return valerie_execute( this, 1024, "REW U%d", unit );
349 }
350
351 /** Fast forward the specified unit.
352 */
353
354 valerie_error_code valerie_unit_fast_forward( valerie this, int unit )
355 {
356         return valerie_execute( this, 1024, "FF U%d", unit );
357 }
358
359 /** Step by the number of frames on the specified unit.
360 */
361
362 valerie_error_code valerie_unit_step( valerie this, int unit, int32_t step )
363 {
364         return valerie_execute( this, 1024, "STEP U%d %d", unit, step );
365 }
366
367 /** Goto the specified frame on the specified unit.
368 */
369
370 valerie_error_code valerie_unit_goto( valerie this, int unit, int32_t position )
371 {
372         return valerie_execute( this, 1024, "GOTO U%d %d", unit, position );
373 }
374
375 /** Goto the specified frame in the clip on the specified unit.
376 */
377
378 valerie_error_code valerie_unit_clip_goto( valerie this, int unit, valerie_clip_offset offset, int clip, int32_t position )
379 {
380         char temp[ 100 ];
381         valerie_interpret_clip_offset( temp, offset, clip );
382         return valerie_execute( this, 1024, "GOTO U%d %d %s", unit, position, temp );
383 }
384
385 /** Set the in point of the loaded file on the specified unit.
386 */
387
388 valerie_error_code valerie_unit_set_in( valerie this, int unit, int32_t in )
389 {
390         return valerie_execute( this, 1024, "SIN U%d %d", unit, in );
391 }
392
393 /** Set the in point of the clip on the specified unit.
394 */
395
396 valerie_error_code valerie_unit_clip_set_in( valerie this, int unit, valerie_clip_offset offset, int clip, int32_t in )
397 {
398         char temp[ 100 ];
399         valerie_interpret_clip_offset( temp, offset, clip );
400         return valerie_execute( this, 1024, "SIN U%d %d %s", unit, in, temp );
401 }
402
403 /** Set the out point of the loaded file on the specified unit.
404 */
405
406 valerie_error_code valerie_unit_set_out( valerie this, int unit, int32_t out )
407 {
408         return valerie_execute( this, 1024, "SOUT U%d %d", unit, out );
409 }
410
411 /** Set the out point of the clip on the specified unit.
412 */
413
414 valerie_error_code valerie_unit_clip_set_out( valerie this, int unit, valerie_clip_offset offset, int clip, int32_t in )
415 {
416         char temp[ 100 ];
417         valerie_interpret_clip_offset( temp, offset, clip );
418         return valerie_execute( this, 1024, "SOUT U%d %d %s", unit, in, temp );
419 }
420
421 /** Clear the in point of the loaded file on the specified unit.
422 */
423
424 valerie_error_code valerie_unit_clear_in( valerie this, int unit )
425 {
426         return valerie_execute( this, 1024, "SIN U%d -1", unit );
427 }
428
429 /** Clear the out point of the loaded file on the specified unit.
430 */
431
432 valerie_error_code valerie_unit_clear_out( valerie this, int unit )
433 {
434         return valerie_execute( this, 1024, "SOUT U%d -1", unit );
435 }
436
437 /** Clear the in and out points on the loaded file on the specified unit.
438 */
439
440 valerie_error_code valerie_unit_clear_in_out( valerie this, int unit )
441 {
442         valerie_error_code error = valerie_unit_clear_out( this, unit );
443         if ( error == valerie_ok )
444                 error = valerie_unit_clear_in( this, unit );
445         return error;
446 }
447
448 /** Set a unit configuration property.
449 */
450
451 valerie_error_code valerie_unit_set( valerie this, int unit, char *name, char *value )
452 {
453         return valerie_execute( this, 1024, "USET U%d %s=%s", unit, name, value );
454 }
455
456 /** Get a unit configuration property.
457 */
458
459 valerie_error_code valerie_unit_get( valerie this, int unit, char *name )
460 {
461         return valerie_execute( this, 1024, "UGET U%d %s", unit, name );
462 }
463
464 /** Get a units status.
465 */
466
467 valerie_error_code valerie_unit_status( valerie this, int unit, valerie_status status )
468 {
469         valerie_error_code error = valerie_execute( this, 1024, "USTA U%d", unit );
470         int error_code = valerie_response_get_error_code( this->last_response );
471
472         memset( status, 0, sizeof( valerie_status_t ) );
473         status->unit = unit;
474         if ( error_code == 202 && valerie_response_count( this->last_response ) == 2 )
475                 valerie_status_parse( status, valerie_response_get_line( this->last_response, 1 ) );
476         else if ( error_code == 403 )
477                 status->status = unit_undefined;
478
479         return error;
480 }
481
482 /** Transfer the current settings of unit src to unit dest.
483 */
484
485 valerie_error_code valerie_unit_transfer( valerie this, int src, int dest )
486 {
487         return valerie_execute( this, 1024, "XFER U%d U%d", src, dest );
488 }
489
490 /** Obtain the parsers notifier.
491 */
492
493 valerie_notifier valerie_get_notifier( valerie this )
494 {
495         if ( this != NULL )
496                 return valerie_parser_get_notifier( this->parser );
497         else
498                 return NULL;
499 }
500
501 /** List the contents of the specified directory.
502 */
503
504 valerie_dir valerie_dir_init( valerie this, char *directory )
505 {
506         valerie_dir dir = malloc( sizeof( valerie_dir_t ) );
507         if ( dir != NULL )
508         {
509                 memset( dir, 0, sizeof( valerie_dir_t ) );
510                 dir->directory = strdup( directory );
511                 dir->response = valerie_parser_executef( this->parser, "CLS \"%s\"", directory );
512         }
513         return dir;
514 }
515
516 /** Return the error code associated to the dir.
517 */
518
519 valerie_error_code valerie_dir_get_error_code( valerie_dir dir )
520 {
521         if ( dir != NULL )
522                 return valerie_get_error_code( NULL, dir->response );
523         else
524                 return valerie_malloc_failed;
525 }
526
527 /** Get a particular file entry in the directory.
528 */
529
530 valerie_error_code valerie_dir_get( valerie_dir dir, int index, valerie_dir_entry entry )
531 {
532         valerie_error_code error = valerie_ok;
533         memset( entry, 0, sizeof( valerie_dir_entry_t ) );
534         if ( index < valerie_dir_count( dir ) )
535         {
536                 char *line = valerie_response_get_line( dir->response, index + 1 );
537                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
538                 valerie_tokeniser_parse_new( tokeniser, line, " " );
539
540                 if ( valerie_tokeniser_count( tokeniser ) > 0 )
541                 {
542                         valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 0 ), '\"' );
543                         strcpy( entry->full, dir->directory );
544                         if ( entry->full[ strlen( entry->full ) - 1 ] != '/' )
545                                 strcat( entry->full, "/" );
546                         strcpy( entry->name, valerie_tokeniser_get_string( tokeniser, 0 ) );
547                         strcat( entry->full, entry->name );
548
549                         switch ( valerie_tokeniser_count( tokeniser ) )
550                         {
551                                 case 1:
552                                         entry->dir = 1;
553                                         break;
554                                 case 2:
555                                         entry->size = strtoull( valerie_tokeniser_get_string( tokeniser, 1 ), NULL, 10 );
556                                         break;
557                                 default:
558                                         error = valerie_invalid_file;
559                                         break;
560                         }
561                 }
562                 valerie_tokeniser_close( tokeniser );
563         }
564         return error;
565 }
566
567 /** Get the number of entries in the directory
568 */
569
570 int valerie_dir_count( valerie_dir dir )
571 {
572         if ( dir != NULL && valerie_response_count( dir->response ) >= 2 )
573                 return valerie_response_count( dir->response ) - 2;
574         else
575                 return -1;
576 }
577
578 /** Close the directory structure.
579 */
580
581 void valerie_dir_close( valerie_dir dir )
582 {
583         if ( dir != NULL )
584         {
585                 free( dir->directory );
586                 valerie_response_close( dir->response );
587                 free( dir );
588         }
589 }
590
591 /** List the playlist of the specified unit.
592 */
593
594 valerie_list valerie_list_init( valerie this, int unit )
595 {
596         valerie_list list = calloc( 1, sizeof( valerie_list_t ) );
597         if ( list != NULL )
598         {
599                 list->response = valerie_parser_executef( this->parser, "LIST U%d", unit );
600                 if ( valerie_response_count( list->response ) >= 2 )
601                         list->generation = atoi( valerie_response_get_line( list->response, 1 ) );
602         }
603         return list;
604 }
605
606 /** Return the error code associated to the list.
607 */
608
609 valerie_error_code valerie_list_get_error_code( valerie_list list )
610 {
611         if ( list != NULL )
612                 return valerie_get_error_code( NULL, list->response );
613         else
614                 return valerie_malloc_failed;
615 }
616
617 /** Get a particular file entry in the list.
618 */
619
620 valerie_error_code valerie_list_get( valerie_list list, int index, valerie_list_entry entry )
621 {
622         valerie_error_code error = valerie_ok;
623         memset( entry, 0, sizeof( valerie_list_entry_t ) );
624         if ( index < valerie_list_count( list ) )
625         {
626                 char *line = valerie_response_get_line( list->response, index + 2 );
627                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
628                 valerie_tokeniser_parse_new( tokeniser, line, " " );
629
630                 if ( valerie_tokeniser_count( tokeniser ) > 0 )
631                 {
632                         entry->clip = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
633                         valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 1 ), '\"' );
634                         strcpy( entry->full, valerie_tokeniser_get_string( tokeniser, 1 ) );
635                         entry->in = atol( valerie_tokeniser_get_string( tokeniser, 2 ) );
636                         entry->out = atol( valerie_tokeniser_get_string( tokeniser, 3 ) );
637                         entry->max = atol( valerie_tokeniser_get_string( tokeniser, 4 ) );
638                         entry->size = atol( valerie_tokeniser_get_string( tokeniser, 5 ) );
639                         entry->fps = atof( valerie_tokeniser_get_string( tokeniser, 6 ) );
640                 }
641                 valerie_tokeniser_close( tokeniser );
642         }
643         return error;
644 }
645
646 /** Get the number of entries in the list
647 */
648
649 int valerie_list_count( valerie_list list )
650 {
651         if ( list != NULL && valerie_response_count( list->response ) >= 3 )
652                 return valerie_response_count( list->response ) - 3;
653         else
654                 return -1;
655 }
656
657 /** Close the list structure.
658 */
659
660 void valerie_list_close( valerie_list list )
661 {
662         if ( list != NULL )
663         {
664                 valerie_response_close( list->response );
665                 free( list );
666         }
667 }
668
669 /** List the currently connected nodes.
670 */
671
672 valerie_nodes valerie_nodes_init( valerie this )
673 {
674         valerie_nodes nodes = malloc( sizeof( valerie_nodes_t ) );
675         if ( nodes != NULL )
676         {
677                 memset( nodes, 0, sizeof( valerie_nodes_t ) );
678                 nodes->response = valerie_parser_executef( this->parser, "NLS" );
679         }
680         return nodes;
681 }
682
683 /** Return the error code associated to the nodes list.
684 */
685
686 valerie_error_code valerie_nodes_get_error_code( valerie_nodes nodes )
687 {
688         if ( nodes != NULL )
689                 return valerie_get_error_code( NULL, nodes->response );
690         else
691                 return valerie_malloc_failed;
692 }
693
694 /** Get a particular node entry.
695 */
696
697 valerie_error_code valerie_nodes_get( valerie_nodes nodes, int index, valerie_node_entry entry )
698 {
699         valerie_error_code error = valerie_ok;
700         memset( entry, 0, sizeof( valerie_node_entry_t ) );
701         if ( index < valerie_nodes_count( nodes ) )
702         {
703                 char *line = valerie_response_get_line( nodes->response, index + 1 );
704                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
705                 valerie_tokeniser_parse_new( tokeniser, line, " " );
706
707                 if ( valerie_tokeniser_count( tokeniser ) == 3 )
708                 {
709                         entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
710                         strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 1 ), sizeof( entry->guid ) );
711                         valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 2 ), '\"' );
712                         strncpy( entry->name, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->name ) );
713                 }
714
715                 valerie_tokeniser_close( tokeniser );
716         }
717         return error;
718 }
719
720 /** Get the number of nodes
721 */
722
723 int valerie_nodes_count( valerie_nodes nodes )
724 {
725         if ( nodes != NULL && valerie_response_count( nodes->response ) >= 2 )
726                 return valerie_response_count( nodes->response ) - 2;
727         else
728                 return -1;
729 }
730
731 /** Close the nodes structure.
732 */
733
734 void valerie_nodes_close( valerie_nodes nodes )
735 {
736         if ( nodes != NULL )
737         {
738                 valerie_response_close( nodes->response );
739                 free( nodes );
740         }
741 }
742
743 /** List the currently defined units.
744 */
745
746 valerie_units valerie_units_init( valerie this )
747 {
748         valerie_units units = malloc( sizeof( valerie_units_t ) );
749         if ( units != NULL )
750         {
751                 memset( units, 0, sizeof( valerie_units_t ) );
752                 units->response = valerie_parser_executef( this->parser, "ULS" );
753         }
754         return units;
755 }
756
757 /** Return the error code associated to the nodes list.
758 */
759
760 valerie_error_code valerie_units_get_error_code( valerie_units units )
761 {
762         if ( units != NULL )
763                 return valerie_get_error_code( NULL, units->response );
764         else
765                 return valerie_malloc_failed;
766 }
767
768 /** Get a particular unit entry.
769 */
770
771 valerie_error_code valerie_units_get( valerie_units units, int index, valerie_unit_entry entry )
772 {
773         valerie_error_code error = valerie_ok;
774         memset( entry, 0, sizeof( valerie_unit_entry_t ) );
775         if ( index < valerie_units_count( units ) )
776         {
777                 char *line = valerie_response_get_line( units->response, index + 1 );
778                 valerie_tokeniser tokeniser = valerie_tokeniser_init( );
779                 valerie_tokeniser_parse_new( tokeniser, line, " " );
780
781                 if ( valerie_tokeniser_count( tokeniser ) == 4 )
782                 {
783                         entry->unit = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) + 1 );
784                         entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 1 ) );
785                         strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->guid ) );
786                         entry->online = atoi( valerie_tokeniser_get_string( tokeniser, 3 ) );
787                 }
788
789                 valerie_tokeniser_close( tokeniser );
790         }
791         return error;
792 }
793
794 /** Get the number of units
795 */
796
797 int valerie_units_count( valerie_units units )
798 {
799         if ( units != NULL && valerie_response_count( units->response ) >= 2 )
800                 return valerie_response_count( units->response ) - 2;
801         else
802                 return -1;
803 }
804
805 /** Close the units structure.
806 */
807
808 void valerie_units_close( valerie_units units )
809 {
810         if ( units != NULL )
811         {
812                 valerie_response_close( units->response );
813                 free( units );
814         }
815 }
816
817 /** Get the response of the last command executed.
818 */
819
820 valerie_response valerie_get_last_response( valerie this )
821 {
822         return this->last_response;
823 }
824
825 /** Obtain a printable message associated to the error code provided.
826 */
827
828 char *valerie_error_description( valerie_error_code error )
829 {
830         char *msg = "Unrecognised error";
831         switch( error )
832         {
833                 case valerie_ok:
834                         msg = "OK";
835                         break;
836                 case valerie_malloc_failed:
837                         msg = "Memory allocation error";
838                         break;
839                 case valerie_unknown_error:
840                         msg = "Unknown error";
841                         break;
842                 case valerie_no_response:
843                         msg = "No response obtained";
844                         break;
845                 case valerie_invalid_command:
846                         msg = "Invalid command";
847                         break;
848                 case valerie_server_timeout:
849                         msg = "Communications with server timed out";
850                         break;
851                 case valerie_missing_argument:
852                         msg = "Missing argument";
853                         break;
854                 case valerie_server_unavailable:
855                         msg = "Unable to communicate with server";
856                         break;
857                 case valerie_unit_creation_failed:
858                         msg = "Unit creation failed";
859                         break;
860                 case valerie_unit_unavailable:
861                         msg = "Unit unavailable";
862                         break;
863                 case valerie_invalid_file:
864                         msg = "Invalid file";
865                         break;
866                 case valerie_invalid_position:
867                         msg = "Invalid position";
868                         break;
869         }
870         return msg;
871 }
872
873 /** Close the valerie structure.
874 */
875
876 void valerie_close( valerie this )
877 {
878         if ( this != NULL )
879         {
880                 valerie_set_last_response( this, NULL );
881                 free( this );
882         }
883 }