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