1 /*********************************************************************
2 Arithmetic operations on data structures.
3 This is part of GNU Astronomy Utilities (Gnuastro) package.
4
5 Original author:
6 Mohammad Akhlaghi <mohammad@akhlaghi.org>
7 Contributing author(s):
8 Copyright (C) 2021, Free Software Foundation, Inc.
9
10 Gnuastro is free software: you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation, either version 3 of the License, or (at your
13 option) any later version.
14
15 Gnuastro is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
22 **********************************************************************/
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <errno.h>
27 #include <error.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <gnuastro/list.h>
32
33 #include <gnuastro-internal/checkset.h>
34 #include <gnuastro-internal/arithmetic-set.h>
35
36
37
38
39
40 /* Remove a name from the list of names and return the dataset it points
41 to. */
42 static gal_data_t *
arithmetic_set_remove_name(struct gal_arithmetic_set_params * p,char * name)43 arithmetic_set_remove_name(struct gal_arithmetic_set_params *p,
44 char *name)
45 {
46 gal_data_t *tmp, *removed=NULL, *prev=NULL;
47
48 /* Go over all the given names. */
49 for(tmp=p->named;tmp!=NULL;tmp=tmp->next)
50 {
51 if( !strcmp(tmp->name, name) )
52 {
53 removed=tmp;
54 if(prev) prev->next = tmp->next;
55 else p->named = tmp->next;
56 }
57
58 /* Set this node as the 'prev' pointer. */
59 prev=tmp;
60 }
61
62 /* A small sanity check. */
63 if(removed==NULL)
64 error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
65 "fix the problem. 'removed' must not be NULL at this point",
66 __func__, PACKAGE_BUGREPORT);
67
68 /* Nothing in the list points to it now. So we can safely modify and
69 return it. */
70 free(removed->name);
71 removed->next=NULL;
72 removed->name=NULL;
73 return removed;
74 }
75
76
77
78
79
80 /* Pop a dataset and keep it in the 'named' list for later use. */
81 void
gal_arithmetic_set_name(struct gal_arithmetic_set_params * p,char * token)82 gal_arithmetic_set_name(struct gal_arithmetic_set_params *p, char *token)
83 {
84 gal_data_t *tmp, *tofree;
85 char *varname=&token[ GAL_ARITHMETIC_SET_PREFIX_LENGTH ];
86
87 /* If a dataset with this name already exists, it will be removed/deleted
88 so we can use the name for the newly designated dataset. */
89 for(tmp=p->named; tmp!=NULL; tmp=tmp->next)
90 if( !strcmp(varname, tmp->name) )
91 {
92 tofree=arithmetic_set_remove_name(p, varname);
93 gal_data_free(tofree);
94
95 /* IMPORTANT: we MUST break here! 'tmp' does't point to the right
96 place any more. We can define a 'prev' node and modify it on
97 every attempt, but since there is only one dataset with a given
98 name, that is redundant and will just make the program slow. */
99 break;
100 }
101
102 /* Pop the top operand, then add it to the list of named datasets, but
103 only if it is used in later tokens. If it isn't, free the popped
104 dataset. The latter case (to define a name, but not use it), is
105 obviously a redundant operation, but that is upto the user, we
106 shouldn't worry about it here. We should just have everything in
107 place, so no crashes occur or no extra memory is consumed. */
108 if( p->used_later(p, varname) )
109 {
110 /* Add the top popped operand to the list of names. */
111 gal_list_data_add(&p->named, p->pop(p));
112
113 /* Write the requested name into this dataset. But note that 'name'
114 MUST be already empty. So to be safe, we'll do a sanity check. */
115 if(p->named->name )
116 error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
117 "fix the problem. The 'name' element should be NULL at "
118 "this point, but it isn't", __func__, PACKAGE_BUGREPORT);
119 if(p->named->unit)
120 { free(p->named->unit); p->named->unit=NULL; }
121 if(p->named->comment)
122 { free(p->named->comment); p->named->comment=NULL; }
123 gal_checkset_allocate_copy(varname, &p->named->name);
124 }
125 else
126 {
127 /* Pop the top operand, then free it: for example the user has ran
128 'set-i', but forgot to actually use it (happens a lot due to human
129 error!). */
130 tmp=p->pop(p);
131 gal_data_free(tmp);
132 }
133 }
134
135
136
137
138
139 /* See if a given token is the name of a variable. */
140 int
gal_arithmetic_set_is_name(gal_data_t * named,char * token)141 gal_arithmetic_set_is_name(gal_data_t *named, char *token)
142 {
143 gal_data_t *tmp;
144
145 /* Make sure the variable name hasn't been set before. */
146 for(tmp=named; tmp!=NULL; tmp=tmp->next)
147 if( !strcmp(token, tmp->name) )
148 return 1;
149
150 /* If control reaches here, then there was no match*/
151 return 0;
152 }
153
154
155
156
157
158 /* Return a copy of the named dataset. */
159 gal_data_t *
gal_arithmetic_set_copy_named(struct gal_arithmetic_set_params * p,char * name)160 gal_arithmetic_set_copy_named(struct gal_arithmetic_set_params *p,
161 char *name)
162 {
163 gal_data_t *out=NULL, *tmp;
164
165 /* Find the proper named element to use. */
166 for(tmp=p->named;tmp!=NULL;tmp=tmp->next)
167 {
168 if( !strcmp(tmp->name, name) )
169 {
170 /* If the named operand is used later, then copy it into the
171 output. */
172 if( p->used_later(p, name) )
173 {
174 out=gal_data_copy(tmp);
175 out->next=NULL;
176 if(out->name) { free(out->name); out->name=NULL; }
177 if(out->unit) { free(out->unit); out->unit=NULL; }
178 if(out->comment) { free(out->comment); out->comment=NULL; }
179 }
180
181 /* The named operand is not used any more. Remove it from the list
182 of named datasets and continue. */
183 else out=arithmetic_set_remove_name(p, name);
184 }
185 }
186
187 /* A small sanity check. */
188 if(out==NULL)
189 error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to fix the "
190 "problem. The requested name '%s' couldn't be found in the list",
191 __func__, PACKAGE_BUGREPORT, name);
192
193 /* Return. */
194 return out;
195 }
196