CR2RE Pipeline Reference Manual 1.7.0
irplib_plugin.c
1/* $Id: irplib_plugin.c,v 1.40 2013-08-22 17:44:56 cgarcia Exp $
2 *
3 * This file is part of the irplib package
4 * Copyright (C) 2002,2003 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: cgarcia $
23 * $Date: 2013-08-22 17:44:56 $
24 * $Revision: 1.40 $
25 * $Name: not supported by cvs2svn $
26 */
27
28/*-----------------------------------------------------------------------------
29 Includes
30 -----------------------------------------------------------------------------*/
31
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "irplib_plugin.h"
37
38#include "irplib_utils.h" /* irplib_reset() */
39
40#include <string.h>
41#include <stdlib.h>
42#include <assert.h>
43
44/*----------------------------------------------------------------------------*/
54/*----------------------------------------------------------------------------*/
55
56/*-----------------------------------------------------------------------------
57 Defines
58 -----------------------------------------------------------------------------*/
59
60/* Maximum line length in SOF-file */
61#ifndef LINE_LEN_MAX
62#define LINE_LEN_MAX 1023
63#endif
64
65#define LINE_SCAN_FMT \
66 "%" CPL_STRINGIFY(LINE_LEN_MAX) "s " \
67 "%" CPL_STRINGIFY(LINE_LEN_MAX) "s " \
68 "%" CPL_STRINGIFY(LINE_LEN_MAX) "s"
69
70/* This device provides quite-random data */
71#define DEV_RANDOM "/dev/urandom"
72
73/* Copied from cpl_tools.h */
74#define recipe_assert(bool) \
75 ((bool) ? (cpl_msg_debug(cpl_func, \
76 "OK in " __FILE__ \
77 " line %d (CPL-error state: '%s' in %s): %s", \
78 __LINE__, cpl_error_get_message(), \
79 cpl_error_get_where(), #bool), \
80 0) \
81 : (cpl_msg_error(cpl_func, \
82 "Failure in " __FILE__ \
83 " line %d (CPL-error state: '%s' in %s): %s", \
84 __LINE__, cpl_error_get_message(), \
85 cpl_error_get_where(), #bool), \
86 1))
87
88
89/*-----------------------------------------------------------------------------
90 Private Function prototypes
91 -----------------------------------------------------------------------------*/
92
93static const cpl_parameter *irplib_parameterlist_get(const cpl_parameterlist *,
94 const char *,
95 const char *,
96 const char *);
97
98static void recipe_parameterlist_set(cpl_parameterlist *);
99static cpl_boolean
100irplib_plugin_has_sof_from_env(const cpl_plugin *, const char *);
101
102static void recipe_frameset_load(cpl_frameset *, const char *);
103
104static void
105recipe_sof_test_devfile(cpl_plugin *, const char *, size_t, const char *[]);
106static void recipe_sof_test_image_empty(cpl_plugin *, size_t, const char *[]);
107static void recipe_sof_test_local(cpl_plugin *);
108static void recipe_sof_test_from_env(cpl_plugin *);
109static void recipe_frameset_empty(cpl_frameset *);
110static void recipe_frameset_test_frame(const cpl_frame *);
111static void
112recipe_frameset_test_frameset_diff(const cpl_frameset *, const cpl_frameset *);
113
114static cpl_errorstate inistate;
115
117
118/*-----------------------------------------------------------------------------
119 Function definitions
120 -----------------------------------------------------------------------------*/
121
122/*----------------------------------------------------------------------------*/
132/*----------------------------------------------------------------------------*/
133const char *
134irplib_parameterlist_get_string(const cpl_parameterlist *self,
135 const char *instrume,
136 const char *recipe,
137 const char *parameter)
138{
139 const cpl_parameter *par =
140 irplib_parameterlist_get(self, instrume, recipe, parameter);
141
142 if (par == NULL) {
143 (void)cpl_error_set_where(cpl_func);
144
145 return NULL;
146 }
147 else {
148 const char *value = cpl_parameter_get_string(par);
149
150 if (value == NULL)
151 (void)cpl_error_set_where(cpl_func);
152
153 return value;
154 }
155}
156
157/*----------------------------------------------------------------------------*/
167/*----------------------------------------------------------------------------*/
168cpl_boolean
169irplib_parameterlist_get_bool(const cpl_parameterlist *self,
170 const char *instrume,
171 const char *recipe,
172 const char *parameter)
173{
174 const cpl_parameter *par =
175 irplib_parameterlist_get(self, instrume, recipe, parameter);
176
177 if (par == NULL) {
178 (void)cpl_error_set_where(cpl_func);
179
180 return CPL_FALSE;
181 }
182 else {
183 cpl_errorstate prestate = cpl_errorstate_get();
184 const cpl_boolean value = cpl_parameter_get_bool(par);
185
186 if (!cpl_errorstate_is_equal(prestate))
187 (void)cpl_error_set_where(cpl_func);
188
189 return value;
190 }
191}
192
193
194/*----------------------------------------------------------------------------*/
204/*----------------------------------------------------------------------------*/
205int
206irplib_parameterlist_get_int(const cpl_parameterlist *self,
207 const char *instrume,
208 const char *recipe,
209 const char *parameter)
210{
211 const cpl_parameter *par =
212 irplib_parameterlist_get(self, instrume, recipe, parameter);
213
214 if (par == NULL) {
215 (void)cpl_error_set_where(cpl_func);
216
217 return 0;
218 }
219 else {
220 cpl_errorstate prestate = cpl_errorstate_get();
221 const int value = cpl_parameter_get_int(par);
222
223 if (!cpl_errorstate_is_equal(prestate))
224 (void)cpl_error_set_where(cpl_func);
225
226 return value;
227 }
228}
229
230/*----------------------------------------------------------------------------*/
240/*----------------------------------------------------------------------------*/
241double
242irplib_parameterlist_get_double(const cpl_parameterlist *self,
243 const char *instrume,
244 const char *recipe,
245 const char *parameter)
246{
247 const cpl_parameter *par =
248 irplib_parameterlist_get(self, instrume, recipe, parameter);
249
250 if (par == NULL) {
251 (void)cpl_error_set_where(cpl_func);
252
253 return 0.0;
254 }
255 else {
256 cpl_errorstate prestate = cpl_errorstate_get();
257 const double value = cpl_parameter_get_double(par);
258
259 if (!cpl_errorstate_is_equal(prestate))
260 (void)cpl_error_set_where(cpl_func);
261
262 return value;
263 }
264}
265
266/*----------------------------------------------------------------------------*/
280/*----------------------------------------------------------------------------*/
281cpl_error_code
282irplib_parameterlist_set_string(cpl_parameterlist *self,
283 const char *instrume,
284 const char *recipe,
285 const char *parameter,
286 const char *defvalue,
287 const char *alias,
288 const char *context,
289 const char *man)
290{
291 cpl_error_code error;
292 cpl_parameter *par;
293 char *paramname = cpl_sprintf("%s.%s.%s", instrume, recipe, parameter);
294
295 cpl_ensure_code(paramname != NULL, cpl_error_get_code());
296
297 par = cpl_parameter_new_value(paramname, CPL_TYPE_STRING, man, context,
298 defvalue);
299 cpl_free(paramname);
300
301 cpl_ensure_code(par != NULL, cpl_error_get_code());
302
303 error = cpl_parameter_set_alias(par, CPL_PARAMETER_MODE_CLI,
304 alias ? alias : parameter);
305 cpl_ensure_code(!error, error);
306
307 error = cpl_parameter_disable(par, CPL_PARAMETER_MODE_ENV);
308 cpl_ensure_code(!error, error);
309
310 error = cpl_parameterlist_append(self, par);
311 cpl_ensure_code(!error, error);
312
313 return CPL_ERROR_NONE;
314}
315
316
317/*----------------------------------------------------------------------------*/
331/*----------------------------------------------------------------------------*/
332cpl_error_code
333irplib_parameterlist_set_bool(cpl_parameterlist *self,
334 const char *instrume,
335 const char *recipe,
336 const char *parameter,
337 cpl_boolean defvalue,
338 const char *alias,
339 const char *context,
340 const char *man)
341{
342 cpl_error_code error;
343 cpl_parameter *par;
344 char *paramname = cpl_sprintf("%s.%s.%s", instrume, recipe, parameter);
345
346 cpl_ensure_code(paramname != NULL, cpl_error_get_code());
347
348 par = cpl_parameter_new_value(paramname, CPL_TYPE_BOOL, man, context,
349 defvalue);
350 cpl_free(paramname);
351
352 cpl_ensure_code(par != NULL, cpl_error_get_code());
353
354 error = cpl_parameter_set_alias(par, CPL_PARAMETER_MODE_CLI,
355 alias ? alias : parameter);
356 cpl_ensure_code(!error, error);
357
358 error = cpl_parameter_disable(par, CPL_PARAMETER_MODE_ENV);
359 cpl_ensure_code(!error, error);
360
361 error = cpl_parameterlist_append(self, par);
362 cpl_ensure_code(!error, error);
363
364 return CPL_ERROR_NONE;
365}
366
367
368/*----------------------------------------------------------------------------*/
382/*----------------------------------------------------------------------------*/
383cpl_error_code
384irplib_parameterlist_set_int(cpl_parameterlist *self,
385 const char *instrume,
386 const char *recipe,
387 const char *parameter,
388 int defvalue,
389 const char *alias,
390 const char *context,
391 const char *man)
392{
393 cpl_error_code error;
394 cpl_parameter *par;
395 char *paramname = cpl_sprintf("%s.%s.%s", instrume, recipe, parameter);
396
397 cpl_ensure_code(paramname != NULL, cpl_error_get_code());
398
399 par = cpl_parameter_new_value(paramname, CPL_TYPE_INT, man, context,
400 defvalue);
401 cpl_free(paramname);
402
403 cpl_ensure_code(par != NULL, cpl_error_get_code());
404
405 error = cpl_parameter_set_alias(par, CPL_PARAMETER_MODE_CLI,
406 alias ? alias : parameter);
407 cpl_ensure_code(!error, error);
408
409 error = cpl_parameter_disable(par, CPL_PARAMETER_MODE_ENV);
410 cpl_ensure_code(!error, error);
411
412 error = cpl_parameterlist_append(self, par);
413 cpl_ensure_code(!error, error);
414
415 return CPL_ERROR_NONE;
416}
417
418
419/*----------------------------------------------------------------------------*/
433/*----------------------------------------------------------------------------*/
434cpl_error_code
435irplib_parameterlist_set_double(cpl_parameterlist *self,
436 const char *instrume,
437 const char *recipe,
438 const char *parameter,
439 double defvalue,
440 const char *alias,
441 const char *context,
442 const char *man)
443{
444 cpl_error_code error;
445 cpl_parameter *par;
446 char *paramname = cpl_sprintf("%s.%s.%s", instrume, recipe, parameter);
447
448 cpl_ensure_code(paramname != NULL, cpl_error_get_code());
449
450 par = cpl_parameter_new_value(paramname, CPL_TYPE_DOUBLE, man, context,
451 defvalue);
452 cpl_free(paramname);
453
454 cpl_ensure_code(par != NULL, cpl_error_get_code());
455
456 error = cpl_parameter_set_alias(par, CPL_PARAMETER_MODE_CLI,
457 alias ? alias : parameter);
458 cpl_ensure_code(!error, error);
459
460 error = cpl_parameter_disable(par, CPL_PARAMETER_MODE_ENV);
461 cpl_ensure_code(!error, error);
462
463 error = cpl_parameterlist_append(self, par);
464 cpl_ensure_code(!error, error);
465
466 return CPL_ERROR_NONE;
467}
468
469
470/*----------------------------------------------------------------------------*/
484/*----------------------------------------------------------------------------*/
485int
486irplib_plugin_test(cpl_pluginlist *self, size_t nstr, const char *astr[])
487{
488 cpl_plugin *plugin;
489 int (*recipe_create)(cpl_plugin *);
490 int (*recipe_exec)(cpl_plugin *);
491 int (*recipe_deinit)(cpl_plugin *);
492 FILE *stream;
493 cpl_boolean is_debug;
494
495
496 is_debug = cpl_msg_get_level() <= CPL_MSG_DEBUG ? CPL_TRUE : CPL_FALSE;
497
498 /* Modified from CPL unit tests */
499 stream = is_debug ? stdout : fopen("/dev/null", "a");
500
501 inistate = cpl_errorstate_get();
502
503 assert(nstr == 0 || astr != NULL);
504
505 plugin = cpl_pluginlist_get_first(self);
506
507 if (plugin == NULL) {
508 cpl_msg_warning(cpl_func, "With an empty pluginlist, "
509 "no tests can be made");
510 return 0;
511 }
512
513 cpl_plugin_dump(plugin, stream);
514
515 recipe_create = cpl_plugin_get_init(plugin);
516 cpl_test(recipe_create != NULL);
517
518 recipe_exec = cpl_plugin_get_exec(plugin);
519 cpl_test(recipe_exec != NULL);
520
521 recipe_deinit = cpl_plugin_get_deinit(plugin);
522 cpl_test(recipe_deinit != NULL);
523
524 /* Only plugins of type recipe are tested (further) */
525 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
526 cpl_msg_warning(cpl_func, "This plugin is not of type recipe, "
527 "cannot test further");
528 return 0;
529 }
530
531 if (recipe_create != NULL && recipe_exec != NULL && recipe_deinit != NULL) {
532 cpl_error_code error;
533 cpl_recipe *recipe;
534
535 cpl_test_zero(recipe_create(plugin));
536
537 recipe = (cpl_recipe *)plugin;
538
539 cpl_test_nonnull(recipe->parameters);
540
541 recipe_parameterlist_set(recipe->parameters);
542
543 cpl_parameterlist_dump(recipe->parameters, stream);
544
545 recipe->frames = cpl_frameset_new();
546
547 if (irplib_plugin_has_sof_from_env(plugin, "RECIPE_SOF_PATH")) {
548 recipe_sof_test_from_env(plugin);
549 }
550 else {
551 const cpl_msg_severity msg_level = cpl_msg_get_level();
552
553 /* Unless the CPL_MSG_LEVEL has been explicitly set, turn off
554 terminal messaging completely while inside this function */
555 if (getenv("CPL_MSG_LEVEL") == NULL)
556 cpl_msg_set_level(CPL_MSG_OFF);
557
558 cpl_msg_info(cpl_func,
559 "Checking handling of pre-existing CPL error "
560 "state - may produce warning(s)/error(s):");
561 cpl_error_set(cpl_func, CPL_ERROR_EOL);
562 /* Call recipe and expect non-zero return code */
563 cpl_test(recipe_exec(plugin));
564 /* Expect also the CPL error code to be preserved */
565 cpl_test_error(CPL_ERROR_EOL);
566
567 cpl_msg_info(cpl_func, "Checking handling of empty frameset - "
568 "may produce warning(s)/error(s):");
569 /* Call recipe and expect non-zero return code */
570 cpl_test(recipe_exec(plugin));
571 error = cpl_error_get_code();
572 /* Expect also the CPL error code to be set */
573 cpl_test_error(error);
574 cpl_test(error);
575
576 cpl_msg_info(cpl_func, "Checking handling of dummy frameset - "
577 "may produce warning(s)/error(s):");
578 do {
579 cpl_frame *f = cpl_frame_new();
580 error = cpl_frame_set_filename(f, "/dev/null");
581 cpl_test_eq_error(error, CPL_ERROR_NONE);
582 error = cpl_frame_set_tag(f, "RECIPE_DUMMY_TAG");
583 cpl_test_eq_error(error, CPL_ERROR_NONE);
584 error = cpl_frameset_insert(recipe->frames, f);
585 cpl_test_eq_error(error, CPL_ERROR_NONE);
586
587 /* Call recipe and expect non-zero return code */
588 cpl_test(recipe_exec(plugin));
589 error = cpl_error_get_code();
590 /* Expect also the CPL error code to be set */
591 cpl_test_error(error);
592 cpl_test(error);
593
594 error = cpl_frameset_erase_frame(recipe->frames, f);
595 cpl_test_eq_error(error, CPL_ERROR_NONE);
596
597 } while (0);
598
599#ifdef IRPLIB_TEST_RANDOM_SOF
600 recipe_sof_test_devfile(plugin, DEV_RANDOM, nstr, astr);
601#endif
602
603 recipe_sof_test_devfile(plugin, "/dev/null", nstr, astr);
604
605 recipe_sof_test_devfile(plugin, ".", nstr, astr);
606
607 recipe_sof_test_image_empty(plugin, nstr, astr);
608
609 recipe_sof_test_local(plugin);
610
611 cpl_msg_set_level(msg_level);
612 }
613
614 cpl_frameset_delete(recipe->frames);
615
616 error = recipe_deinit(plugin);
617 cpl_test_eq_error(error, CPL_ERROR_NONE);
618 }
619
620 if (stream != stdout)
621 fclose(stream);
622
623 return 0;
624}
625
627
628/*----------------------------------------------------------------------------*/
638/*----------------------------------------------------------------------------*/
639static void
640recipe_parameterlist_set(cpl_parameterlist *self)
641{
642 cpl_parameter *p = cpl_parameterlist_get_first(self);
643
644 for (; p != NULL; p = cpl_parameterlist_get_next(self)) {
645 const char *envvar;
646 const char *svalue;
647
648 /* FIXME: Needed ? */
649 if (cpl_parameter_get_default_flag(p))
650 continue;
651
652 cpl_msg_debug(cpl_func, __FILE__ " line %u: OK", __LINE__);
653
654 envvar = cpl_parameter_get_alias(p, CPL_PARAMETER_MODE_ENV);
655 svalue = envvar ? getenv(envvar) : NULL;
656
657 switch (cpl_parameter_get_type(p)) {
658 case CPL_TYPE_BOOL: {
659 const int value =
660 svalue ? atoi(svalue) : cpl_parameter_get_default_bool(p);
661 cpl_parameter_set_bool(p, value);
662 break;
663 }
664 case CPL_TYPE_INT: {
665 const int value =
666 svalue ? atoi(svalue) : cpl_parameter_get_default_int(p);
667 cpl_parameter_set_int(p, value);
668 break;
669 }
670 case CPL_TYPE_DOUBLE: {
671 const double value =
672 svalue ? atof(svalue) : cpl_parameter_get_default_double(p);
673 cpl_parameter_set_double(p, value);
674 break;
675 }
676 case CPL_TYPE_STRING: {
677 const char *s_default = cpl_parameter_get_default_string(p);
678 /* Replace NULL with "" */
679 const char *value =
680 svalue ? svalue : (s_default ? s_default : "");
681 cpl_parameter_set_string(p, value);
682 break;
683 }
684
685 default:
686 assert(0); /* It is a testing error to reach this point */
687 }
688 }
689}
690
691
692/*----------------------------------------------------------------------------*/
702/*----------------------------------------------------------------------------*/
703static void
704recipe_sof_test_devfile(cpl_plugin *plugin,
705 const char *filename,
706 size_t nstr,
707 const char *astr[])
708{
709 cpl_recipe *recipe = (cpl_recipe *)plugin;
710 int (*recipe_exec)(cpl_plugin *);
711 cpl_frameset *copy;
712 cpl_error_code error;
713 size_t i;
714
715
716 if (nstr < 1)
717 return;
718 if (filename == NULL)
719 return;
720
721 cpl_msg_info(cpl_func, "Testing recipe with %u %s as input ",
722 (unsigned)nstr, filename);
723
724 for (i = 0; i < nstr; i++) {
725 cpl_frame *f = cpl_frame_new();
726
727 error = cpl_frame_set_filename(f, filename);
728 cpl_test_eq_error(error, CPL_ERROR_NONE);
729
730 error = cpl_frame_set_tag(f, astr[i]);
731 cpl_test_eq_error(error, CPL_ERROR_NONE);
732
733 error = cpl_frameset_insert(recipe->frames, f);
734 cpl_test_eq_error(error, CPL_ERROR_NONE);
735 }
736
737 copy = cpl_frameset_duplicate(recipe->frames);
738
739 recipe_exec = cpl_plugin_get_exec(plugin);
740 cpl_test(recipe_exec != NULL);
741
742 if (recipe_exec != NULL) {
743 /* Call recipe and expect non-zero return code */
744 cpl_test(recipe_exec(plugin));
745 error = cpl_error_get_code();
746 /* Expect also the CPL error code to be set */
747 cpl_test_error(error);
748 cpl_test(error);
749
750 recipe_frameset_test_frameset_diff(recipe->frames, copy);
751
752 recipe_frameset_empty(recipe->frames);
753 }
754
755 cpl_frameset_delete(copy);
756
757 return;
758}
759
760/*----------------------------------------------------------------------------*/
767/*----------------------------------------------------------------------------*/
768static void
769recipe_sof_test_image_empty(cpl_plugin *plugin, size_t nstr, const char *astr[])
770{
771 cpl_recipe *recipe = (cpl_recipe *)plugin;
772 int (*recipe_exec)(cpl_plugin *);
773 cpl_frameset *copy;
774 cpl_error_code error;
775 size_t i;
776 cpl_image *iempty;
777
778
779 if (nstr < 1)
780 return;
781
782 cpl_msg_info(cpl_func, "Testing recipe with %u empty images as input ",
783 (unsigned)nstr);
784
785 iempty = cpl_image_new(13, 17, CPL_TYPE_FLOAT);
786 cpl_test_nonnull(iempty);
787
788 for (i = 0; i < nstr; i++) {
789 cpl_frame *f = cpl_frame_new();
790 char *rawname =
791 cpl_sprintf("%s-raw%05u.fits", cpl_plugin_get_name(plugin),
792 (unsigned)(i + 1));
793
794 error = cpl_image_save(iempty, rawname, CPL_BPP_IEEE_FLOAT, NULL,
795 CPL_IO_DEFAULT);
796 cpl_test_eq_error(error, CPL_ERROR_NONE);
797
798 error = cpl_frame_set_filename(f, rawname);
799 cpl_test_eq_error(error, CPL_ERROR_NONE);
800
801 error = cpl_frame_set_tag(f, astr[i]);
802 cpl_test_eq_error(error, CPL_ERROR_NONE);
803
804 error = cpl_frameset_insert(recipe->frames, f);
805 cpl_test_eq_error(error, CPL_ERROR_NONE);
806
807 cpl_free(rawname);
808 }
809 cpl_image_delete(iempty);
810
811 copy = cpl_frameset_duplicate(recipe->frames);
812
813 recipe_exec = cpl_plugin_get_exec(plugin);
814 cpl_test(recipe_exec != NULL);
815
816 if (recipe_exec != NULL) {
817 const cpl_frame *frame;
818 cpl_frameset_iterator *iterator = NULL;
819 int retstat;
820
821 /* Call recipe and expect consistency between return code and
822 CPL error */
823
824 retstat = recipe_exec(plugin);
825 error = cpl_error_get_code();
826 /* Expect also the CPL error code to be set */
827 if (error == 0) {
828 cpl_test_zero(retstat);
829 }
830 else {
831 cpl_test(retstat);
832 }
833 cpl_test_error(error);
834
835 recipe_frameset_test_frameset_diff(recipe->frames, copy);
836
837 for (frame = irplib_frameset_get_first_const(&iterator, recipe->frames);
838 frame != NULL; frame = irplib_frameset_get_next_const(iterator)) {
839 cpl_test_zero(remove(cpl_frame_get_filename(frame)));
840 }
841 cpl_frameset_iterator_delete(iterator);
842
843 recipe_frameset_empty(recipe->frames);
844 }
845
846 cpl_frameset_delete(copy);
847
848 return;
849}
850
851
852/*----------------------------------------------------------------------------*/
860/*----------------------------------------------------------------------------*/
861cpl_boolean
862irplib_plugin_has_sof_from_env(const cpl_plugin *plugin, const char *envname)
863{
864 const char *recipename = cpl_plugin_get_name(plugin);
865 const char *sof_path = envname ? getenv(envname) : NULL;
866 cpl_frameset *frames;
867 char *sof_name;
868 const cpl_frame *ffirst;
869
870 cpl_ensure(plugin != NULL, CPL_ERROR_NULL_INPUT, CPL_FALSE);
871 cpl_ensure(envname != NULL, CPL_ERROR_NULL_INPUT, CPL_FALSE);
872 cpl_ensure(recipename != NULL, CPL_ERROR_DATA_NOT_FOUND, CPL_FALSE);
873 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), CPL_FALSE);
874
875 if (sof_path == NULL)
876 return CPL_FALSE;
877
878 sof_name = cpl_sprintf("%s/%s.sof", sof_path, recipename);
879
880 frames = cpl_frameset_new();
881 recipe_frameset_load(frames, sof_name);
882
883 ffirst = cpl_frameset_get_position_const(frames, 0);
884
885 cpl_free(sof_name);
886 cpl_frameset_delete(frames);
887
888 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), CPL_FALSE);
889
890 return ffirst ? CPL_TRUE : CPL_FALSE;
891}
892
893/*----------------------------------------------------------------------------*/
900/*----------------------------------------------------------------------------*/
901static void
902recipe_sof_test_from_env(cpl_plugin *plugin)
903{
904 cpl_recipe *recipe = (cpl_recipe *)plugin;
905 const char *recipename = cpl_plugin_get_name(plugin);
906 const char *var_name = "RECIPE_SOF_PATH";
907 const char *sof_path = getenv(var_name);
908
909 char *sof_name;
910
911 if (sof_path == NULL) {
912 cpl_msg_warning(cpl_func,
913 "Environment variable %s is unset: "
914 "No SOFs to check",
915 var_name);
916 return;
917 }
918
919 cpl_msg_debug(cpl_func, "Checking for SOFs in %s", sof_path);
920
921 cpl_test_nonnull(recipename);
922 if (recipename == NULL)
923 return;
924
925 sof_name = cpl_sprintf("%s/%s.sof", sof_path, recipename);
926
927 cpl_msg_debug(cpl_func, "Checking for SOF %s", sof_name);
928
929 recipe_frameset_load(recipe->frames, sof_name);
930
931 if (!cpl_frameset_is_empty(recipe->frames)) {
932 int (*recipe_exec)(cpl_plugin *);
933 cpl_frameset *copy = cpl_frameset_duplicate(recipe->frames);
934
935 recipe_exec = cpl_plugin_get_exec(plugin);
936 cpl_test(recipe_exec != NULL);
937
938 if (recipe_exec != NULL) {
939 cpl_error_code error;
940 cpl_msg_info(cpl_func, "Checking handling of SOF: %s", sof_name);
941
942 /* Call recipe and expect zero return code */
943 cpl_test_zero(recipe_exec(plugin));
944 /* Expect also the CPL error code to be clear */
945 cpl_test_error(CPL_ERROR_NONE);
946
947 error = cpl_dfs_update_product_header(recipe->frames);
948 cpl_test_eq_error(error, CPL_ERROR_NONE);
949
950 recipe_frameset_test_frameset_diff(recipe->frames, copy);
951
952 recipe_frameset_empty(recipe->frames);
953 }
954
955 cpl_frameset_delete(copy);
956 }
957
958 cpl_free(sof_name);
959
960 return;
961}
962
963
964/*----------------------------------------------------------------------------*/
971/*----------------------------------------------------------------------------*/
972static void
973recipe_sof_test_local(cpl_plugin *plugin)
974{
975 cpl_recipe *recipe = (cpl_recipe *)plugin;
976 const char *recipename = cpl_plugin_get_name(plugin);
977 char *sof_name = cpl_sprintf("%s.sof", recipename);
978
979 cpl_msg_debug(cpl_func, "Checking for SOF %s", sof_name);
980
981 recipe_frameset_load(recipe->frames, sof_name);
982
983 if (!cpl_frameset_is_empty(recipe->frames)) {
984 int (*recipe_exec)(cpl_plugin *);
985 cpl_frameset *copy = cpl_frameset_duplicate(recipe->frames);
986
987 recipe_exec = cpl_plugin_get_exec(plugin);
988 cpl_test(recipe_exec != NULL);
989
990 if (recipe_exec != NULL) {
991 cpl_error_code error;
992
993 cpl_msg_info(cpl_func, "Checking handling of SOF: %s", sof_name);
994
995 /* Call recipe and expect zero return code */
996 cpl_test_zero(recipe_exec(plugin));
997 /* Expect also the CPL error code to be clear */
998 cpl_test_error(CPL_ERROR_NONE);
999
1000 error = cpl_dfs_update_product_header(recipe->frames);
1001 cpl_test_eq_error(error, CPL_ERROR_NONE);
1002
1003 recipe_frameset_test_frameset_diff(recipe->frames, copy);
1004
1005 recipe_frameset_empty(recipe->frames);
1006 }
1007
1008 cpl_frameset_delete(copy);
1009 }
1010
1011 cpl_free(sof_name);
1012
1013 return;
1014}
1015
1016
1017/**********************************************************************/
1031/**********************************************************************/
1032
1033static void
1034recipe_frameset_load(cpl_frameset *set, const char *name)
1035{
1036 FILE *fp;
1037 char line[LINE_LEN_MAX + 1];
1038 char path[LINE_LEN_MAX + 1], group[LINE_LEN_MAX + 1], tag[LINE_LEN_MAX + 1];
1039 int line_number;
1040
1041 assert(set != NULL);
1042 assert(name != NULL);
1043
1044 fp = fopen(name, "r");
1045 if (fp == NULL) {
1046 cpl_msg_debug(cpl_func, "Unable to open SOF file '%s'", name);
1047 return;
1048 }
1049
1050 /* Loop over all the lines in the set-of-frames file */
1051 for (line_number = 0; fgets(line, LINE_LEN_MAX, fp); line_number++) {
1052 cpl_frame_group grp;
1053 cpl_frame *frame;
1054 int n;
1055
1056 if (line[0] == '#')
1057 continue;
1058
1059 n = sscanf(line, LINE_SCAN_FMT, path, tag, group);
1060
1061 if (n < 1) {
1062 cpl_msg_warning(cpl_func, "Spurious line no. %d in %s: %s",
1063 line_number, name, line);
1064 break;
1065 }
1066
1067 /* Allocate a new frame */
1068 frame = cpl_frame_new();
1069
1070 /* Set the filename component of the frame */
1071 cpl_frame_set_filename(frame, path);
1072
1073 /* Set the tag component of the frame (or set a default) */
1074 cpl_frame_set_tag(frame, n == 1 ? "" : tag);
1075
1076 cpl_frameset_insert(set, frame);
1077
1078 /* Set the group component of the frame (or set a default) */
1079 if (n < 3)
1080 continue;
1081
1082 if (!strcmp(group, CPL_FRAME_GROUP_RAW_ID))
1083 grp = CPL_FRAME_GROUP_RAW;
1084 else if (!strcmp(group, CPL_FRAME_GROUP_CALIB_ID))
1085 grp = CPL_FRAME_GROUP_CALIB;
1086 else if (!strcmp(group, CPL_FRAME_GROUP_PRODUCT_ID))
1087 grp = CPL_FRAME_GROUP_PRODUCT;
1088 else
1089 grp = CPL_FRAME_GROUP_NONE;
1090
1091 cpl_frame_set_group(frame, grp);
1092 }
1093
1094 fclose(fp);
1095
1096 return;
1097}
1098
1099
1100/*----------------------------------------------------------------------------*/
1110/*----------------------------------------------------------------------------*/
1111static const cpl_parameter *
1112irplib_parameterlist_get(const cpl_parameterlist *self,
1113 const char *instrume,
1114 const char *recipe,
1115 const char *parameter)
1116{
1117 char *paramname;
1118 const cpl_parameter *par;
1119
1120
1121 cpl_ensure(instrume != NULL, CPL_ERROR_NULL_INPUT, NULL);
1122 cpl_ensure(recipe != NULL, CPL_ERROR_NULL_INPUT, NULL);
1123 cpl_ensure(parameter != NULL, CPL_ERROR_NULL_INPUT, NULL);
1124
1125 paramname = cpl_sprintf("%s.%s.%s", instrume, recipe, parameter);
1126
1127 par = cpl_parameterlist_find_const(self, paramname);
1128
1129 if (par == NULL)
1130 (void)cpl_error_set_message(cpl_func,
1131 cpl_error_get_code()
1132 ? cpl_error_get_code()
1133 : CPL_ERROR_DATA_NOT_FOUND,
1134 "%s", paramname);
1135
1136 cpl_free(paramname);
1137
1138 return par;
1139}
1140
1141
1142/*----------------------------------------------------------------------------*/
1168/*----------------------------------------------------------------------------*/
1169static void
1170recipe_frameset_empty(cpl_frameset *self)
1171{
1172 cpl_size i, n;
1173
1174 if (self == NULL) {
1175 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
1176 return;
1177 }
1178
1179 n = cpl_frameset_get_size(self);
1180 for (i = 0; i < n; ++i) {
1181 cpl_frame *f = cpl_frameset_get_position(self, n - 1 - i);
1182 cpl_frameset_erase_frame(self, f);
1183 }
1184}
1185
1186
1187/*----------------------------------------------------------------------------*/
1207/*----------------------------------------------------------------------------*/
1208static void
1209recipe_frameset_test_frame(const cpl_frame *self)
1210{
1211 cpl_msg_info(cpl_func, "Validating new frame: %s",
1212 cpl_frame_get_filename(self));
1213
1214 cpl_test_nonnull(self);
1215
1216 /* Frame must be tagged */
1217 cpl_test_nonnull(cpl_frame_get_tag(self));
1218
1219 /* New frames must be products */
1220 cpl_test_eq(cpl_frame_get_group(self), CPL_FRAME_GROUP_PRODUCT);
1221
1222 if (cpl_frame_get_type(self) != CPL_FRAME_TYPE_PAF) {
1223 /* All but PAF (?) must be FITS */
1224 cpl_test_fits(cpl_frame_get_filename(self));
1225 }
1226 else {
1227 /* Frame must at least have a filename */
1228 cpl_test_nonnull(cpl_frame_get_filename(self));
1229 }
1230}
1231
1232/*----------------------------------------------------------------------------*/
1253/*----------------------------------------------------------------------------*/
1254static void
1255recipe_frameset_test_frameset_diff(const cpl_frameset *self,
1256 const cpl_frameset *other)
1257{
1258 cpl_frameset_iterator *it1 = NULL;
1259 cpl_frameset_iterator *it2 = NULL;
1260 const cpl_frame *frame = irplib_frameset_get_first_const(&it2, other);
1261
1262 /* First verify that filenames in other are non-NULL */
1263 for (; frame != NULL; frame = irplib_frameset_get_next_const(it2)) {
1264 const char *file = cpl_frame_get_filename(frame);
1265
1266 if (file == NULL) {
1267 cpl_test_nonnull(cpl_frame_get_filename(frame));
1268 break;
1269 }
1270 }
1271 cpl_frameset_iterator_delete(it2);
1272 it2 = NULL;
1273 if (frame != NULL)
1274 return;
1275
1276 frame = irplib_frameset_get_first_const(&it1, self);
1277
1278 for (; frame != NULL; frame = irplib_frameset_get_next_const(it1)) {
1279 const cpl_frame *cmp;
1280 const char *file = cpl_frame_get_filename(frame);
1281
1282 if (file == NULL) {
1283 cpl_test_nonnull(cpl_frame_get_filename(frame));
1284 continue;
1285 }
1286
1287 cmp = irplib_frameset_get_first_const(&it2, other);
1288 for (; cmp != NULL; cmp = irplib_frameset_get_next_const(it2)) {
1289 const char *cfile = cpl_frame_get_filename(cmp);
1290
1291 if (!strcmp(file, cfile))
1292 break;
1293 }
1294 cpl_frameset_iterator_delete(it2);
1295 it2 = NULL;
1296 if (cmp == NULL) {
1297 /* frame is new */
1298
1299 cpl_test_eq(cpl_frame_get_group(frame), CPL_FRAME_GROUP_PRODUCT);
1300 recipe_frameset_test_frame(frame);
1301 }
1302 }
1303
1304 cpl_frameset_iterator_delete(it1);
1305}