1 #include <assert.h>
2 #include <limits.h>
3 
4 #include "dmemory.h"
5 #include "cdi.h"
6 #include "cdi_int.h"
7 #include "resource_handle.h"
8 #include "resource_unpack.h"
9 #include "namespace.h"
10 #include "serialize.h"
11 #include "institution.h"
12 
13 
14 typedef struct
15 {
16   int    self;
17   int    used;
18   int    center;
19   int    subcenter;
20   char  *name;
21   char  *longname;
22 }
23 institute_t;
24 
25 
26 static int instituteCompareKernel(institute_t *ip1, institute_t *ip2);
27 static void instituteDestroyP(institute_t *instituteptr);
28 static void   institutePrintP(institute_t *instituteptr, FILE * fp);
29 static int instituteGetPackSize(institute_t *instituteptr, void *context);
30 static void   institutePackP    ( void * instituteptr, void *buf, int size, int *position, void *context );
31 static int    instituteTxCode   ( void );
32 
33 static const resOps instituteOps = {
34   (int (*)(void *, void *))instituteCompareKernel,
35   (void (*)(void *))instituteDestroyP,
36   (void (*)(void *, FILE *))institutePrintP,
37   (int (*)(void *, void *))instituteGetPackSize,
38   institutePackP,
39   instituteTxCode
40 };
41 
42 static
instituteDefaultValue(institute_t * instituteptr)43 void instituteDefaultValue(institute_t *instituteptr)
44 {
45   instituteptr->self       = CDI_UNDEFID;
46   instituteptr->used       = 0;
47   instituteptr->center     = CDI_UNDEFID;
48   instituteptr->subcenter  = CDI_UNDEFID;
49   instituteptr->name       = NULL;
50   instituteptr->longname   = NULL;
51 }
52 
instituteDefaultEntries(void)53 void instituteDefaultEntries(void)
54 {
55   cdiResH resH[]
56     = { institutDef( 98,   0, "ECMWF",     "European Centre for Medium-Range Weather Forecasts"),
57         institutDef(252,   1, "MPIMET",    "Max Planck Institute for Meteorology"),
58         institutDef( 98, 232, "MPIMET",    "Max Planck Institute for Meteorology"),
59         institutDef( 98, 255, "MPIMET",    "Max-Planck-Institute for Meteorology"),
60         institutDef( 78, 255, "DWD",       "Deutscher Wetterdienst"),
61         institutDef( 78,   0, "DWD",       "Deutscher Wetterdienst"),
62         institutDef(215, 255, "MCH",       "MeteoSwiss"),
63         institutDef(  7,   0, "NCEP",      "National Centers for Environmental Prediction"),
64         institutDef(  7,   1, "NCEP",      "National Centers for Environmental Prediction"),
65         institutDef( 60,   0, "NCAR",      "National Center for Atmospheric Research"),
66         institutDef( 74,   0, "METOFFICE", "U.K. Met Office"),
67         institutDef( 97,   0, "ESA",       "European Space Agency"),
68         institutDef( 99,   0, "KNMI",      "Royal Netherlands Meteorological Institute"),
69         institutDef( 80,   0, "CNMC",      "Reparto per la Meteorologia, Rome (REMET)"),
70         // institutDef(  0,   0, "IPSL", "IPSL (Institut Pierre Simon Laplace, Paris, France)");
71   };
72 
73   const size_t n = sizeof(resH)/sizeof(*resH);
74   for (size_t i = 0; i < n ; i++ )
75     reshSetStatus(resH[i], &instituteOps, RESH_IN_USE);
76 }
77 
78 
79 static int
instituteCompareKernel(institute_t * ip1,institute_t * ip2)80 instituteCompareKernel(institute_t *ip1, institute_t *ip2)
81 {
82   int differ = 0;
83 
84   if ( ip1->name )
85     {
86       if ( ip1->center    > 0 && ip2->center    != ip1->center )    differ = 1;
87       if ( ip1->subcenter > 0 && ip2->subcenter != ip1->subcenter ) differ = 1;
88 
89       if ( !differ )
90         {
91           if ( ip2->name )
92             {
93               const size_t len1 = strlen(ip1->name);
94               const size_t len2 = strlen(ip2->name);
95               if ( (len1 != len2) || memcmp(ip2->name, ip1->name, len2) ) differ = 1;
96             }
97         }
98     }
99   else if ( ip1->longname )
100     {
101       if ( ip2->longname )
102         {
103           const size_t len1 = strlen(ip1->longname);
104           const size_t len2 = strlen(ip2->longname);
105           if ( (len1 != len2) || memcmp(ip2->longname, ip1->longname, len2) ) differ = 1;
106         }
107     }
108   else
109     {
110       if ( !( ip2->center    == ip1->center &&
111               ip2->subcenter == ip1->subcenter )) differ = 1;
112       if (ip1->subcenter > 0 && ip1->subcenter != 255 && ip2->subcenter != ip1->subcenter) differ = 1;
113     }
114 
115   return differ;
116 }
117 
118 
119 struct instLoc
120 {
121   institute_t *ip;
122   int id;
123 };
124 
125 static enum cdiApplyRet
findInstitute(int id,void * res,void * data)126 findInstitute(int id, void *res, void *data)
127 {
128   institute_t *ip1 = ((struct instLoc *)data)->ip;
129   institute_t *ip2 = (institute_t*) res;
130   if (ip2->used && !instituteCompareKernel(ip1, ip2))
131     {
132       ((struct instLoc *)data)->id = id;
133       return CDI_APPLY_STOP;
134     }
135   else
136     return CDI_APPLY_GO_ON;
137 }
138 
139 
institutInq(int center,int subcenter,const char * name,const char * longname)140 int institutInq(int center, int subcenter, const char *name, const char *longname)
141 {
142   institute_t ip_ref;
143   ip_ref.self       = CDI_UNDEFID;
144   ip_ref.used       = 0;
145   ip_ref.center     = center;
146   ip_ref.subcenter  = subcenter;
147   ip_ref.name       = (name && name[0]) ? (char *)name : NULL;
148   ip_ref.longname   = (longname && longname[0]) ? (char *)longname : NULL;
149 
150   struct instLoc state = { .ip = &ip_ref, .id = CDI_UNDEFID };
151   cdiResHFilterApply(&instituteOps, findInstitute, &state);
152 
153   return state.id;
154 }
155 
156 static
instituteNewEntry(cdiResH resH,int center,int subcenter,const char * name,const char * longname)157 institute_t *instituteNewEntry(cdiResH resH, int center, int subcenter,
158                                const char *name, const char *longname)
159 {
160   institute_t *instituteptr = (institute_t*) Malloc(sizeof(institute_t));
161   instituteDefaultValue(instituteptr);
162   if (resH == CDI_UNDEFID)
163     instituteptr->self = reshPut(instituteptr, &instituteOps);
164   else
165     {
166       instituteptr->self = resH;
167       reshReplace(resH, instituteptr, &instituteOps);
168     }
169   instituteptr->used = 1;
170   instituteptr->center = center;
171   instituteptr->subcenter = subcenter;
172   if ( name && *name )
173     instituteptr->name = strdupx(name);
174   if (longname && *longname)
175     instituteptr->longname = strdupx(longname);
176   return  instituteptr;
177 }
178 
179 
institutDef(int center,int subcenter,const char * name,const char * longname)180 int institutDef(int center, int subcenter, const char *name, const char *longname)
181 {
182   institute_t *instituteptr = instituteNewEntry(CDI_UNDEFID, center, subcenter, name, longname);
183   return instituteptr->self;
184 }
185 
186 
institutInqCenter(int instID)187 int institutInqCenter(int instID)
188 {
189   institute_t * instituteptr = NULL;
190 
191   if ( instID != CDI_UNDEFID )
192     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
193 
194   return  instituteptr ? instituteptr->center : CDI_UNDEFID;
195 }
196 
197 
institutInqSubcenter(int instID)198 int institutInqSubcenter(int instID)
199 {
200   institute_t * instituteptr = NULL;
201 
202   if ( instID != CDI_UNDEFID )
203     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
204 
205   return instituteptr ? instituteptr->subcenter: CDI_UNDEFID;
206 }
207 
208 
institutInqNamePtr(int instID)209 const char *institutInqNamePtr(int instID)
210 {
211   institute_t * instituteptr = NULL;
212 
213   if ( instID != CDI_UNDEFID )
214     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
215 
216   return instituteptr ? instituteptr->name : NULL;
217 }
218 
219 
institutInqLongnamePtr(int instID)220 const char *institutInqLongnamePtr(int instID)
221 {
222   institute_t * instituteptr = NULL;
223 
224   if ( instID != CDI_UNDEFID )
225     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
226 
227   return instituteptr ? instituteptr->longname : NULL;
228 }
229 
230 static enum cdiApplyRet
activeInstitutes(int id,void * res,void * data)231 activeInstitutes(int id, void *res, void *data)
232 {
233   (void)id;
234   if (res && ((institute_t *)res)->used)
235     ++(*(int *)data);
236   return CDI_APPLY_GO_ON;
237 }
238 
institutInqNumber(void)239 int institutInqNumber(void)
240 {
241   int instNum = 0;
242 
243   cdiResHFilterApply(&instituteOps, activeInstitutes, &instNum);
244   return instNum;
245 }
246 
247 
248 static void
instituteDestroyP(institute_t * instituteptr)249 instituteDestroyP(institute_t *instituteptr)
250 {
251   xassert(instituteptr);
252 
253   int instituteID = instituteptr->self;
254   Free(instituteptr->name);
255   Free(instituteptr->longname);
256   reshRemove(instituteID, &instituteOps);
257   Free(instituteptr);
258 }
259 
260 
institutePrintP(institute_t * ip,FILE * fp)261 static void institutePrintP(institute_t *ip, FILE * fp )
262 {
263   if (ip)
264     fprintf(fp, "#\n"
265             "# instituteID %d\n"
266             "#\n"
267             "self          = %d\n"
268             "used          = %d\n"
269             "center        = %d\n"
270             "subcenter     = %d\n"
271             "name          = %s\n"
272             "longname      = %s\n",
273             ip->self, ip->self, ip->used, ip->center, ip->subcenter,
274             ip->name ? ip->name : "NN",
275             ip->longname ? ip->longname : "NN");
276 }
277 
278 
279 static int
instituteTxCode(void)280 instituteTxCode ( void )
281 {
282   return INSTITUTE;
283 }
284 
285 enum {
286   institute_nints = 5,
287 };
288 
instituteGetPackSize(institute_t * ip,void * context)289 static int instituteGetPackSize(institute_t *ip, void *context)
290 {
291   size_t namelen = strlen(ip->name), longnamelen = strlen(ip->longname);
292   xassert(namelen < INT_MAX && longnamelen < INT_MAX);
293   size_t txsize = (size_t)serializeGetSize(institute_nints, CDI_DATATYPE_INT, context)
294     + (size_t)serializeGetSize((int)namelen + 1, CDI_DATATYPE_TXT, context)
295     + (size_t)serializeGetSize((int)longnamelen + 1, CDI_DATATYPE_TXT, context);
296   xassert(txsize <= INT_MAX);
297   return (int)txsize;
298 }
299 
institutePackP(void * instituteptr,void * buf,int size,int * position,void * context)300 static void institutePackP(void * instituteptr, void *buf, int size, int *position, void *context)
301 {
302   institute_t *p = (institute_t*) instituteptr;
303   int tempbuf[institute_nints];
304   tempbuf[0] = p->self;
305   tempbuf[1] = p->center;
306   tempbuf[2] = p->subcenter;
307   tempbuf[3] = (int)strlen(p->name) + 1;
308   tempbuf[4] = (int)strlen(p->longname) + 1;
309   serializePack(tempbuf, institute_nints, CDI_DATATYPE_INT, buf, size, position, context);
310   serializePack(p->name, tempbuf[3], CDI_DATATYPE_TXT, buf, size, position, context);
311   serializePack(p->longname, tempbuf[4], CDI_DATATYPE_TXT, buf, size, position, context);
312 }
313 
instituteUnpack(void * buf,int size,int * position,int originNamespace,void * context,int force_id)314 int instituteUnpack(void *buf, int size, int *position, int originNamespace,
315                     void *context, int force_id)
316 {
317   int tempbuf[institute_nints];
318   int instituteID;
319   serializeUnpack(buf, size, position, tempbuf, institute_nints, CDI_DATATYPE_INT, context);
320   char *name = (char *) Malloc((size_t)tempbuf[3] + (size_t)tempbuf[4]);
321   char *longname = name + tempbuf[3];
322   serializeUnpack(buf, size, position, name, tempbuf[3], CDI_DATATYPE_TXT, context);
323   serializeUnpack(buf, size, position, longname, tempbuf[4], CDI_DATATYPE_TXT, context);
324   int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
325   institute_t *ip = instituteNewEntry(force_id?targetID:CDI_UNDEFID,
326                                       tempbuf[1], tempbuf[2], name, longname);
327   instituteID = ip->self;
328   xassert(!force_id || instituteID == targetID);
329   Free(name);
330   reshSetStatus(instituteID, &instituteOps,
331                 reshGetStatus(instituteID, &instituteOps) & ~RESH_SYNC_BIT);
332   return instituteID;
333 }
334 
335 /*
336  * Local Variables:
337  * c-file-style: "Java"
338  * c-basic-offset: 2
339  * indent-tabs-mode: nil
340  * show-trailing-whitespace: t
341  * require-trailing-newline: t
342  * End:
343  */
344