19 #include <netinet/in.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
34 {
"defTextVector",
"defText",
"newTextVector",
"oneText" },
35 {
"defNumberVector",
"defNumber",
"newNumberVector",
"oneNumber" },
36 {
"defSwitchVector",
"defSwitch",
"newSwitchVector",
"oneSwitch" },
38 #define NDEFS (sizeof(defs) / sizeof(defs[0]))
41 static char host_def[] =
"localhost";
44 static char *host = host_def;
47 static int directfd = -1;
70 static void usage(
void);
71 static int crackSpec(
int *acp,
char **avp[]);
72 static void openINDIServer(FILE **rfpp, FILE **wfpp);
73 static void listenINDI(FILE *rfp, FILE *wfp);
74 static int finished(
void);
75 static void onAlarm(
int dummy);
76 static int readServerChar(FILE *fp);
77 static void findSet(
XMLEle *root, FILE *fp);
78 static void scanEV(
SetSpec *specp,
char ev[]);
79 static void scanEEVV(
SetSpec *specp,
char *ep,
char ev[]);
80 static void scanEVEV(
SetSpec *specp,
char ev[]);
82 static void sendSpecs(FILE *wfp);
84 int main(
int ac,
char *av[])
94 while (!stop && --ac && **++av ==
'-')
104 fprintf(stderr,
"-d requires open fileno\n");
107 directfd = atoi(*++av);
114 fprintf(stderr,
"Can not combine -d and -h\n");
119 fprintf(stderr,
"-h requires host name\n");
129 fprintf(stderr,
"Can not combine -d and -p\n");
134 fprintf(stderr,
"-p requires tcp port number\n");
144 fprintf(stderr,
"-t requires timeout\n");
147 timeout = atoi(*++av);
163 fprintf(stderr,
"Unknown flag: %c\n", *s);
177 if (!crackSpec(&ac, &av))
184 wfp = fdopen(directfd,
"w");
185 rfp = fdopen(directfd,
"r");
189 fprintf(stderr,
"Direct fd %d: %s\n", directfd, strerror(
errno));
193 fprintf(stderr,
"Using direct fd %d\n", directfd);
197 openINDIServer(&rfp, &wfp);
199 fprintf(stderr,
"Connected to %s on port %d\n", host, port);
214 fprintf(stderr,
"Querying for properties\n");
215 fprintf(wfp,
"<getProperties version='%g'/>\n",
INDIV);
219 listenINDI(rfp, wfp);
227 fprintf(stderr,
"Purpose: set one or more writable INDI properties\n");
228 fprintf(stderr,
"%s\n", GIT_TAG_STRING);
229 fprintf(stderr,
"Usage: %s [options] {[type] spec} ...\n", me);
230 fprintf(stderr,
"Options:\n");
231 fprintf(stderr,
" -d f : use file descriptor f already open to server\n");
232 fprintf(stderr,
" -h h : alternate host, default is %s\n", host_def);
233 fprintf(stderr,
" -p p : alternate port, default is %d\n",
INDIPORT);
234 fprintf(stderr,
" -t t : max time to wait, default is %d secs\n",
TIMEOUT);
235 fprintf(stderr,
" -v : verbose (more are cumulative)\n");
236 fprintf(stderr,
"Each spec optionally preceded by its type is sent without first confirming\n");
237 fprintf(stderr,
"its structure. This is much more efficient but there is no error checking.\n");
238 fprintf(stderr,
"Types are indicated with the following flags:\n");
239 fprintf(stderr,
" -x : Text\n");
240 fprintf(stderr,
" -n : Number\n");
241 fprintf(stderr,
" -s : Switch\n");
242 fprintf(stderr,
"Spec may be either:\n");
243 fprintf(stderr,
" device.property.e1[;e2...]=v1[;v2...]\n");
244 fprintf(stderr,
" or\n");
245 fprintf(stderr,
" device.property.e1=v1[;e2=v2...]\n");
246 fprintf(stderr,
"Exit status:\n");
247 fprintf(stderr,
" 0: all settings successful\n");
248 fprintf(stderr,
" 1: at least one setting was invalid\n");
249 fprintf(stderr,
" 2: real trouble, try repeating with -v\n");
257 static int crackSpec(
int *acp,
char **avp[])
259 char d[128], p[128], ev[2048];
260 char *spec = *avp[0];
264 if ((*acp > 0) && (spec[0] ==
'-'))
278 fprintf(stderr,
"Bad property type: %s\n", spec);
287 fprintf(stderr,
"Missing spec\n");
293 if (sscanf(spec,
"%[^.].%[^.].%[^\n]", d, p, ev) != 3)
295 fprintf(stderr,
"Malformed property spec: %s\n", spec);
301 sets[nsets].
d = strdup(d);
302 sets[nsets].
p = strdup(p);
304 sets[nsets].
ev = NULL;
306 scanEV(&sets[nsets++], ev);
319 static void openINDIServer(FILE **rfpp, FILE **wfpp)
321 struct sockaddr_in serv_addr;
326 hp = gethostbyname(host);
329 perror(
"gethostbyname");
334 (void)memset((
char *)&serv_addr, 0,
sizeof(serv_addr));
335 serv_addr.sin_family = AF_INET;
336 serv_addr.sin_addr.s_addr = ((
struct in_addr *)(hp->h_addr_list[0]))->s_addr;
337 serv_addr.sin_port = htons(port);
338 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
345 if (connect(sockfd, (
struct sockaddr *)&serv_addr,
sizeof(serv_addr)) < 0)
352 *rfpp = fdopen(sockfd,
"r");
353 *wfpp = fdopen(sockfd,
"w");
357 static void listenINDI(FILE *rfp, FILE *wfp)
362 signal(SIGALRM, onAlarm);
377 shutdown(fileno(wfp), SHUT_WR);
384 fprintf(stderr,
"Bad XML from %s/%d: %s\n", host, port, msg);
391 static int finished()
395 for (i = 0; i < nsets; i++)
396 for (j = 0; j < sets[i].
nev; j++)
397 if (!sets[i].ev[j].ok)
405 static void onAlarm(
int dummy)
410 for (i = 0; i < nsets; i++)
411 for (j = 0; j < sets[i].
nev; j++)
412 if (!sets[i].ev[j].ok)
413 fprintf(stderr,
"No %s.%s.%s from %s:%d\n", sets[i].d, sets[i].p, sets[i].ev[j].e, host, port);
418 static int readServerChar(FILE *fp)
427 fprintf(stderr,
"INDI server %s:%d disconnected\n", host, port);
432 fprintf(stderr,
"Read %c\n", c);
438 static void findSet(
XMLEle *root, FILE *fp)
440 char *rtype, *rdev, *rprop;
446 for (t = 0; t < (int)
NDEFS; t++)
448 if (strcmp(rtype, defs[t].defType) == 0)
460 fprintf(stderr,
"Read definition for %s.%s\n", rdev, rprop);
462 for (s = 0; s < nsets; s++)
464 if (!strcmp(rdev, sets[s].d) && !strcmp(rprop, sets[s].p))
470 fprintf(stderr,
"%s.%s is read-only\n", rdev, rprop);
474 for (i = 0; i < sets[s].
nev; i++)
480 sets[s].
ev[i].
ok = 1;
488 sendNew(fp, &defs[t], &sets[s]);
498 fprintf(fp,
"<%s device='%s' name='%s'>\n", dp->
newType, sp->
d, sp->
p);
499 for (i = 0; i < sp->
nev; i++)
502 fprintf(stderr,
" %s.%s.%s <- %s\n", sp->
d, sp->
p, sp->
ev[i].
e, sp->
ev[i].
v);
505 fprintf(fp,
"</%s>\n", dp->
newType);
507 if (feof(fp) || ferror(fp))
509 fprintf(stderr,
"Send error\n");
520 static void scanEV(
SetSpec *specp,
char ev[])
525 fprintf(stderr,
"Scanning assignments %s\n", ev);
527 ep = strchr(ev,
'=');
528 sp = strchr(ev,
';');
532 fprintf(stderr,
"Malformed assignment: %s\n", ev);
537 scanEEVV(specp, ep, ev);
547 static void scanEEVV(
SetSpec *sp,
char *v,
char *e)
549 static char sep[] =
";";
556 char *e0 = strtok_r(e, sep, &ec);
557 char *v0 = strtok_r(v, sep, &vc);
563 fprintf(stderr,
"More values than elements for %s.%s\n", sp->
d, sp->
p);
568 fprintf(stderr,
"More elements than values for %s.%s\n", sp->
d, sp->
p);
573 sp->
ev[sp->
nev].
e = strdup(e0);
574 sp->
ev[sp->
nev].
v = strdup(v0);
576 fprintf(stderr,
"Found assignment %s=%s\n", sp->
ev[sp->
nev].
e, sp->
ev[sp->
nev].
v);
588 static void scanEVEV(
SetSpec *sp,
char ev[])
608 fprintf(stderr,
"Malformed assignment: %s\n", ev);
613 sp->
ev[sp->
nev].
e = strdup(ev);
614 sp->
ev[sp->
nev].
v = strdup(e);
616 fprintf(stderr,
"Found assignment %s=%s\n", sp->
ev[sp->
nev].
e, sp->
ev[sp->
nev].
v);
626 static void sendSpecs(FILE *wfp)
630 for (i = 0; i < nsets; i++)
631 sendNew(wfp, sets[i].dp, &sets[i]);
Constants and Data structure definitions for the interface to the reference INDI C API implementation...
Interface to the reference INDI C API device implementation on the Device Driver side.
LilXML * newLilXML()
Create a new lilxml parser.
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
XMLEle * readXMLEle(LilXML *lp, int newc, char ynot[])
Process an XML one char at a time.
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
A little DOM-style library to handle parsing and processing an XML file.
int main(int ac, char *av[])