mrfioc2  2.3.0
linkoptions.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven Science Associates, as Operator of
3 * Brookhaven National Laboratory.
4 * mrfioc2 is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 /*
8  * Author: Michael Davidsaver <mdavidsaver@gmail.com>
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <limits.h>
16 #include <math.h>
17 
18 #include <dbDefs.h>
19 #include <epicsTypes.h>
20 #include <epicsString.h>
21 #include <macLib.h>
22 
23 #define epicsExportSharedSymbols
24 #include "linkoptions.h"
25 
26 #ifndef HUGE_VALF
27 # define HUGE_VALF HUGE_VAL
28 #endif
29 #ifndef HUGE_VALL
30 # define HUGE_VALL (-(HUGE_VAL))
31 #endif
32 
33 /*
34  * Parse the value 'val' according to the type named in 'opt->optType'
35  * and store the result at 'user + opt->offset'.
36  */
37 static
38 int
39 store_value(const linkOptionDef* opt, void* user, const char* val, int options)
40 {
41  epicsUInt32 *ival;
42  unsigned long int lival;
43  int *eval;
44  const linkOptionEnumType *emap;
45  double *dval;
46  char *sval;
47  char *end;
48 
49  (void)options; /* unused */
50 
51  switch(opt->optType) {
52  case linkOptionInt32:
53  if (opt->size<sizeof(epicsUInt32)) {
54  fprintf(stderr, "Provide storage (%u bytes) is too small for Int32 (%lu)\n",
55  opt->size, (unsigned long)sizeof(epicsUInt32));
56  return -1;
57  }
58  ival=(epicsUInt32*)( (char*)user + opt->offset );
59 
60  lival = strtoul(val, &end, 0);
61  /* test for the myriad error conditions which strtol may use */
62  if ( lival==ULONG_MAX || end==val )
63  {
64  fprintf(stderr,"value %s can't be converted for integer key %s\n",val,opt->name);
65  return -1;
66  }
67 
68  *ival = (epicsUInt32)lival;
69 
70  break;
71  case linkOptionDouble:
72  if (opt->size<sizeof(double)) {
73  fprintf(stderr, "Provide storage (%u bytes) is too small for double (%lu)\n",
74  opt->size, (unsigned long)sizeof(double));
75  return -1;
76  }
77  dval=(double*)( (char*)user + opt->offset );
78 
79  *dval = strtod(val, &end);
80  /* Indicates errors in the same manner as strtol */
81  if ( *dval==HUGE_VALF || *dval==HUGE_VALL || end==val )
82  {
83  fprintf(stderr,"value %s can't be converted for double key %s\n",val,opt->name);
84  return -1;
85  }
86  break;
87  case linkOptionEnum:
88  if (opt->size<sizeof(int)) {
89  fprintf(stderr, "Provide storage (%u bytes) is too small for enum (%lu)\n",
90  opt->size, (unsigned long)sizeof(int));
91  return -1;
92  }
93  eval=(int*)( (char*)user + opt->offset );
94 
95  for(emap=opt->Enums; emap && emap->name; emap++) {
96  if ( strcmp(emap->name, val)==0 ) {
97  *eval=emap->value;
98  break;
99  }
100  }
101 
102  if( !emap || !emap->name ) {
103  fprintf(stderr,"%s is not a valid value for the Enum %s\n",
104  val, opt->name);
105  return -1;
106  }
107 
108  break;
109  case linkOptionString:
110  if (opt->size<sizeof(char*)) {
111  /* Catch if someone has given us a char* instead of a char[]
112  * Also means that char buffers must be >4.
113  */
114  fprintf(stderr, "Provide storage (%u bytes) is too small for string (>= %lu)\n",
115  opt->size, (unsigned long)sizeof(char*));
116  return -1;
117  }
118  sval=( (char*)user + opt->offset );
119 
120  strncpy(sval, val, opt->size-1);
121  sval[opt->size-1]='\0';
122  break;
123  case linkOptionInvalid:
124  fprintf(stderr,"Can't store \'%s\' for %s as the storage type is not defined\n",
125  val,opt->name);
126  return -1;
127  break;
128  }
129 
130  return 0;
131 }
132 
133 int
134 epicsShareAPI
135 linkOptionsStore(const linkOptionDef* opts, void* user, const char* str, int options)
136 {
137  MAC_HANDLE handle; /* only .debug is used */
138 
139  int status=0;
140  size_t i;
141  epicsUInt32 *found;
142  const linkOptionDef *cur;
143  char **pairs=NULL, **arg;
144 
145  for(i=0, cur=opts; cur && cur->name; i++, cur++) {}
146 
147  /* Bit array to find missing required keys */
148  found=calloc( (i/32)+1, sizeof(epicsUInt32) );
149  if (!found) {
150  fprintf(stderr,"store_options: calloc failed\n");
151  status=-1;
152  goto errbitarray;
153  }
154 
155  memset((void*)&handle, 0, sizeof(handle));
156 
157  if (options&LINKOPTIONDEBUG)
158  handle.debug=0xff;
159 
160  /* Parses 'str' and stores the result in the array pairs.
161  * The length of pairs is twice the number of pairs found.
162  * Each even element is a key, each odd element is a value.
163  *
164  * Pair N is (pairs[2*N], pairs[2*N+1])
165  *
166  * After the last pair is a (NULL, NULL)
167  */
168  if (macParseDefns(&handle, str, &pairs)<0) {
169  status=-1;
170  goto errparse;
171  }
172 
173  for (arg=pairs; arg && arg[0]; arg+=2) {
174  int match=0;
175 
176  if (options&LINKOPTIONDEBUG)
177  printf("key %s\n",arg[0]);
178 
179  for (i=0, cur=opts; !match && cur && cur->name; i++, cur++) {
180 
181  if (options&LINKOPTIONDEBUG)
182  fprintf(stderr,"For option: %s\n",cur->name);
183 
184  if( strcmp(arg[0], cur->name)!=0 )
185  continue;
186  match=1;
187 
188  if (found[i/32]&(1<<(i%32)) && !cur->overwrite) {
189  fprintf(stderr,"Option %s was already given\n",cur->name);
190  status=-1;
191  goto errsemantix;
192  }
193 
194  found[i/32] |= 1<<(i%32);
195 
196  status=store_value(cur, user, arg[1], options);
197  if (status)
198  goto errsemantix;
199  }
200 
201  if(!match) {
202  printf("Warning: ignoring unknown INP/OUT option %s=\n", arg[0]);
203  }
204  }
205 
206  for (i=0, cur=opts; cur && cur->name; i++, cur++) {
207 
208  if ( !(found[i/32]&(1<<(i%32))) && cur->required ) {
209  fprintf(stderr,"Missing required option %s\n",cur->name);
210  status=-1;
211  goto errsemantix;
212  }
213  }
214 
215 errsemantix:
216  free((void*)pairs);
217 errparse:
218  free(found);
219 errbitarray:
220  return status;
221 }
222 
223 epicsShareFunc
224 const char*
225 epicsShareAPI
226 linkOptionsEnumString(const linkOptionEnumType *emap, int i, const char* def)
227 {
228  for(; emap && emap->name; emap++) {
229  if ( i == emap->value ) {
230  return emap->name;
231  }
232  }
233  return def;
234 }
#define HUGE_VALF
Definition: linkoptions.c:27
epicsShareFunc const char *epicsShareAPI linkOptionsEnumString(const linkOptionEnumType *emap, int i, const char *def)
Return the string associated with Enum &#39;i&#39;.
Definition: linkoptions.c:226
int epicsShareAPI linkOptionsStore(const linkOptionDef *opts, void *user, const char *str, int options)
Parse a string a store the result.
Definition: linkoptions.c:135
#define LINKOPTIONDEBUG
Definition: linkoptions.h:114
#define HUGE_VALL
Definition: linkoptions.c:30
Hardware link parsing and storage.