4 Copyright (C) 2020 by Pawel Soja <kernel32.pl@gmail.com>
5 Copyright (C) 2003 - 2020 Jasem Mutlaq
6 Copyright (C) 2003 - 2006 Elwood C. Downey
8 This library is free software;
9 you can redistribute it and / or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation;
13 version 2.1 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT
ANY WARRANTY;
17 without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License
for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with
this library;
23 if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
41 #include <sys/types.h>
77 static pthread_mutex_t rosc_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static ROSC *propCache = NULL;
80 static int nPropCache = 0;
82 static ROSC *rosc_new()
84 assert_mem(propCache = (
ROSC *)(realloc(propCache, (nPropCache + 1) *
sizeof *propCache)));
85 return &propCache[nPropCache++];
88 static void rosc_add(
const char *propName,
const char *devName,
IPerm perm,
const void *ptr,
int type)
90 ROSC *SC = rosc_new();
99 static ROSC *rosc_find(
const char *propName,
const char *devName)
101 for (
int i = 0; i < nPropCache; i++)
102 if (!strcmp(propName, propCache[i].propName) && !strcmp(devName, propCache[i].devName))
103 return &propCache[i];
108 static void rosc_add_unique(
const char *propName,
const char *devName,
IPerm perm,
const void *ptr,
int type)
110 pthread_mutex_lock(&rosc_mutex);
112 if (rosc_find(propName, devName) == NULL)
113 rosc_add(propName, devName, perm, ptr,
type);
115 pthread_mutex_unlock(&rosc_mutex);
121 void IDDeleteVA(
const char *dev,
const char *name,
const char *fmt, va_list ap)
132 void IDDelete(
const char *dev,
const char *name,
const char *fmt, ...)
143 void IDSnoopDevice(
const char *snooped_device,
const char *snooped_property)
146 if (snooped_device && snooped_device[0])
163 if (snooped_device && snooped_device[0])
189 if (!strcmp(rtag,
"getProperties"))
198 fprintf(stderr,
"%s: getProperties missing version\n",
me);
204 fprintf(stderr,
"%s: client version %g > %g\n",
me, v,
INDIV);
216 pthread_mutex_lock(&rosc_mutex);
219 pthread_mutex_unlock(&rosc_mutex);
259 if (!strcmp(rtag,
"setNumberVector") || !strcmp(rtag,
"setTextVector") || !strcmp(rtag,
"setLightVector") ||
260 !strcmp(rtag,
"setSwitchVector") || !strcmp(rtag,
"setBLOBVector") || !strcmp(rtag,
"defNumberVector") ||
261 !strcmp(rtag,
"defTextVector") || !strcmp(rtag,
"defLightVector") || !strcmp(rtag,
"defSwitchVector") ||
262 !strcmp(rtag,
"defBLOBVector") || !strcmp(rtag,
"message") || !strcmp(rtag,
"delProperty"))
270 if (
crackDN(root, &dev, &name, msg) < 0)
273 pthread_mutex_lock(&rosc_mutex);
274 if (rosc_find(name, dev) == NULL)
276 pthread_mutex_unlock(&rosc_mutex);
277 snprintf(msg,
MAXRBUF,
"Property %s is not defined in %s.", name, dev);
280 pthread_mutex_unlock(&rosc_mutex);
283 for (
int i = 0; i < nPropCache; i++)
285 if (!strcmp(propCache[i].propName, name) && !strcmp(propCache[i].devName, dev))
287 if (propCache[i].perm ==
IP_RO)
289 snprintf(msg,
MAXRBUF,
"Cannot set read-only property %s", name);
299 if (!strcmp(rtag,
"newNumberVector"))
301 static double *doubles = NULL;
302 static char **names = NULL;
311 if (strcmp(
tagXMLEle(ep),
"oneNumber") == 0)
320 assert_mem(doubles = (
double *)realloc(doubles, maxn *
sizeof *doubles));
321 assert_mem(names = (
char **)realloc(names, maxn *
sizeof *names));
332 indi_locale_C_numeric_pop(orig);
338 IDMessage(dev,
"[ERROR] %s: newNumberVector with no valid members", name);
342 if (!strcmp(rtag,
"newSwitchVector"))
345 static char **names = NULL;
352 if (strcmp(
tagXMLEle(ep),
"oneSwitch") == 0)
361 assert_mem(names = (
char **)realloc(names, maxn *
sizeof *names));
385 IDMessage(dev,
"[ERROR] %s: newSwitchVector with no valid members", name);
389 if (!strcmp(rtag,
"newTextVector"))
391 static char **texts = NULL;
392 static char **names = NULL;
398 if (strcmp(
tagXMLEle(ep),
"oneText") == 0)
406 assert_mem(texts = (
char **)realloc(texts, maxn *
sizeof *texts));
407 assert_mem(names = (
char **)realloc(names, maxn *
sizeof *names));
420 IDMessage(dev,
"[ERROR] %s: set with no valid members", name);
424 if (!strcmp(rtag,
"newBLOBVector"))
426 static char **blobs = NULL;
427 static char **names = NULL;
428 static char **formats = NULL;
429 static int *blobsizes = NULL;
430 static int *sizes = NULL;
437 if (strcmp(
tagXMLEle(ep),
"oneBLOB") == 0)
448 assert_mem(blobs = (
char **)realloc(blobs, maxn *
sizeof *blobs));
449 assert_mem(names = (
char **)realloc(names, maxn *
sizeof *names));
450 assert_mem(formats = (
char **)realloc(formats, maxn *
sizeof *formats));
451 assert_mem(sizes = (
int *)realloc(sizes, maxn *
sizeof *sizes));
452 assert_mem(blobsizes = (
int *)realloc(blobsizes, maxn *
sizeof *blobsizes));
459 assert_mem(blobs[n] = (
char*)malloc(3 * bloblen / 4));
472 ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
473 for (
int i = 0; i < n; i++)
477 IDMessage(dev,
"[ERROR] %s: newBLOBVector with no valid members", name);
481 sprintf(msg,
"Unknown command: %s", rtag);
485 int IUReadConfig(
const char *filename,
const char *dev,
const char *property,
int silent,
char errmsg[])
488 XMLEle *root = NULL, *fproot = NULL;
503 snprintf(errmsg,
MAXRBUF,
"Unable to parse config XML: %s", whynot);
508 if (
nXMLEle(fproot) > 0 && silent != 1)
509 IDMessage(dev,
"[INFO] Loading device configuration...");
514 if (
crackDN(root, &rdev, &rname, errmsg) < 0)
522 if (strcmp(dev, rdev))
525 if ((property && !strcmp(property, rname)) || property == NULL)
533 if (
nXMLEle(fproot) > 0 && silent != 1)
534 IDMessage(dev,
"[INFO] Device configuration applied.");
547 strncpy(configFileName, source_config,
MAXRBUF);
550 if (getenv(
"INDICONFIG"))
551 strncpy(configFileName, getenv(
"INDICONFIG"),
MAXRBUF);
553 snprintf(configFileName,
MAXRBUF,
"%s/.indi/%s_config.xml", getenv(
"HOME"), dev);
557 strncpy(configDefaultFileName, dest_config,
MAXRBUF);
558 else if (getenv(
"INDICONFIG"))
559 snprintf(configDefaultFileName,
MAXRBUF,
"%s.default", getenv(
"INDICONFIG"));
561 snprintf(configDefaultFileName,
MAXRBUF,
"%s/.indi/%s_config.xml.default", getenv(
"HOME"), dev);
564 if (access(configDefaultFileName, F_OK))
566 FILE *fpin = fopen(configFileName,
"r");
569 FILE *fpout = fopen(configDefaultFileName,
"w");
573 while ((ch = getc(fpin)) != EOF)
595 XMLEle *root = NULL, *fproot = NULL;
598 int propertyFound = 0;
617 if (
crackDN(root, &rdev, &rname, errmsg) < 0)
625 if (strcmp(property->
device, rdev))
628 if (!strcmp(property->
name, rname))
632 int oneSwitchIndex = 0;
634 for (oneSwitch =
nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch =
nextXMLEle(root, 0), oneSwitchIndex++)
638 *index = oneSwitchIndex;
650 return (propertyFound ? 0 : -1);
656 XMLEle *root = NULL, *fproot = NULL;
677 if (
crackDN(root, &rdev, &rname, errmsg) < 0)
685 if (strcmp(dev, rdev))
688 if ((property && !strcmp(property, rname)) || property == NULL)
708 return (valueFound == 1 ? 0 : -1);
714 XMLEle *root = NULL, *fproot = NULL;
735 if (
crackDN(root, &rdev, &rname, errmsg) < 0)
743 if (strcmp(dev, rdev))
746 if ((property && !strcmp(property, rname)) || property == NULL)
749 int currentIndex = 0;
750 for (oneSwitch =
nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch =
nextXMLEle(root, 0), currentIndex++)
755 *index = currentIndex;
768 return (valueFound == 1 ? 0 : -1);
774 XMLEle *root = NULL, *fproot = NULL;
795 if (
crackDN(root, &rdev, &rname, errmsg) < 0)
803 if (strcmp(dev, rdev))
806 if ((property && !strcmp(property, rname)) || property == NULL)
809 int currentIndex = 0;
810 for (oneSwitch =
nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch =
nextXMLEle(root, 0), currentIndex++)
834 XMLEle *root = NULL, *fproot = NULL;
855 if (
crackDN(root, &rdev, &rname, errmsg) < 0)
863 if (strcmp(dev, rdev))
866 if ((property && !strcmp(property, rname)) || property == NULL)
886 return (valueFound == 1 ? 0 : -1);
889 int IUGetConfigText(
const char *dev,
const char *property,
const char *member,
char *value,
int len)
892 XMLEle *root = NULL, *fproot = NULL;
913 if (
crackDN(root, &rdev, &rname, errmsg) < 0)
921 if (strcmp(dev, rdev))
924 if ((property && !strcmp(property, rname)) || property == NULL)
944 return (valueFound == 1 ? 0 : -1);
973 snprintf(configDir,
MAXRBUF,
"%s/.indi/", getenv(
"HOME"));
976 strncpy(configFileName, filename,
MAXRBUF);
979 if (getenv(
"INDICONFIG"))
980 strncpy(configFileName, getenv(
"INDICONFIG"),
MAXRBUF);
982 snprintf(configFileName,
MAXRBUF,
"%s%s_config.xml", configDir, dev);
985 if (remove(configFileName) != 0)
987 snprintf(errmsg,
MAXRBUF,
"Unable to purge configuration file %s. Error %s", configFileName, strerror(
errno));
994 FILE *
IUGetConfigFP(
const char *filename,
const char *dev,
const char *mode,
char errmsg[])
1001 snprintf(configDir,
MAXRBUF,
"%s/.indi/", getenv(
"HOME"));
1004 strncpy(configFileName, filename,
MAXRBUF);
1007 if (getenv(
"INDICONFIG"))
1008 strncpy(configFileName, getenv(
"INDICONFIG"),
MAXRBUF);
1010 snprintf(configFileName,
MAXRBUF,
"%s%s_config.xml", configDir, dev);
1013 if (stat(configDir, &st) != 0)
1015 if (
mkdir(configDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0)
1017 snprintf(errmsg,
MAXRBUF,
"Unable to create config directory. Error %s: %s", configDir, strerror(
errno));
1022 stat(configFileName, &st);
1024 if ( (st.st_uid == 0 && getuid() != 0) || (st.st_gid == 0 && getgid() != 0) )
1027 "Config file is owned by root! This will lead to serious errors. To fix this, run: sudo chown -R $USER:$USER ~/.indi",
1032 fp = fopen(configFileName, mode);
1035 snprintf(errmsg,
MAXRBUF,
"Unable to open config file. Error loading file %s: %s", configFileName,
1055 IDMessage(dev,
"[INFO] Saving device configuration...");
1060 IDMessage(dev,
"[INFO] Device configuration saved.");
1259 static long lastBlobPingUid = 0;
1260 #define BLOB_PING_PATTERN "SetBLOB/%ld"
1268 if (lastBlobPingUid) {
1312 assert(svp != NULL &&
"IUUpdateSwitch SVP is NULL");
1321 for (
int i = 0; i < n; i++)
1328 IDSetSwitch(svp,
"Error: %s is not a member of %s (%s) property.", names[i], svp->
label, svp->
name);
1339 for (
int i = 0; i < svp->
nsp; i++)
1352 IDSetSwitch(svp,
"Error: invalid state switch for property %s (%s). %s.", svp->
label, svp->
name,
1353 t_count == 0 ?
"No switch is on" :
"Too many switches are on");
1364 assert(nvp != NULL &&
"IUUpdateNumber NVP is NULL");
1366 for (
int i = 0; i < n; i++)
1372 IDSetNumber(nvp,
"Error: %s is not a member of %s (%s) property.", names[i], nvp->
label, nvp->
name);
1376 if (values[i] < np->min || values[i] > np->max)
1379 IDSetNumber(nvp,
"Error: Invalid range for %s (%s). Valid range is from %g to %g. Requested value is %g",
1380 np->label, np->name, np->min, np->max, values[i]);
1386 for (
int i = 0; i < n; i++)
1389 np->value = values[i];
1398 assert(tvp != NULL &&
"IUUpdateText TVP is NULL");
1400 for (
int i = 0; i < n; i++)
1406 IDSetText(tvp,
"Error: %s is not a member of %s (%s) property.", names[i], tvp->
label, tvp->
name);
1412 for (
int i = 0; i < n; i++)
1425 assert(bvp != NULL &&
"IUUpdateBLOB BVP is NULL");
1427 for (
int i = 0; i < n; i++)
1433 IDSetBLOB(bvp,
"Error: %s is not a member of %s (%s) property.", names[i], bvp->
label, bvp->
name);
1439 for (
int i = 0; i < n; i++)
1442 IUSaveBLOB(bp, sizes[i], blobsizes[i], blobs[i], formats[i]);
int from64tobits_fast(char *out, const char *in, int inlen)
void ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Update data of an existing blob vector property.
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Update the value of an existing text vector property.
void ISGetProperties(const char *dev)
Get Device Properties.
void ISSnoopDevice(XMLEle *root)
Function defined by Drivers that is called when another Driver it is snooping (by having previously c...
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
#define assert_mem(p)
Bails out if memory pointer is 0. Prints file and function.
IPerm
Permission hint, with respect to client.
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
Implementations for common driver routines.
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
int IUSaveBLOB(IBLOB *bp, int size, int blobsize, char *blob, char *format)
Function to save blob metadata in the corresponding blob.
IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
Find an IBLOB member in a vector BLOB property.
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Interface to the reference INDI C API device implementation on the Device Driver side.
BLOBHandling
How drivers handle BLOBs incoming from snooping drivers.
void IDMessageVA(const char *dev, const char *fmt, va_list ap)
int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Update all BLOB members in a BLOB vector property.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
void IDDefSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
void IDSnoopBLOBs(const char *snooped_device, const char *snooped_property, BLOBHandling bh)
Function a Driver calls to control whether they will receive BLOBs from snooped devices.
void IDDefNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
void IDSetLight(const ILightVectorProperty *lvp, const char *fmt,...)
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
void IDDelete(const char *dev, const char *name, const char *fmt,...)
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
void IDDefTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
void IDSetBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
#define BLOB_PING_PATTERN
void IUSaveConfigTag(FILE *fp, int ctag, const char *dev, int silent)
Add opening or closing tag to a configuration file. A configuration file root XML element is <INDIDri...
int IUGetConfigOnSwitch(const ISwitchVectorProperty *property, int *index)
IUGetConfigOnSwitch Opens configuration file and reads a single switch vector property to find the in...
int IUGetConfigOnSwitchName(const char *dev, const char *property, char *name, size_t size)
IUGetConfigOnSwitchLabel Opens configuration file and returns the name of the ON switch property,...
int IUGetConfigText(const char *dev, const char *property, const char *member, char *value, int len)
IUGetConfigText Opens configuration file and reads single text property.
void IDSetTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
void waitPingReply(const char *)
int IUGetConfigNumber(const char *dev, const char *property, const char *member, double *value)
IUGetConfigNumber Opens configuration file and reads single number property.
int IUReadConfig(const char *filename, const char *dev, const char *property, int silent, char errmsg[])
Loads and processes a configuration file. Once a configuration file is successful loaded,...
void IDDefLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
void IDMessage(const char *dev, const char *fmt,...)
void IDDeleteVA(const char *dev, const char *name, const char *fmt, va_list ap)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
int IUPurgeConfig(const char *filename, const char *dev, char errmsg[])
void IDDefBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
int IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
Copies an existing configuration file into a default configuration file. If no default configuration ...
int IUGetConfigOnSwitchIndex(const char *dev, const char *property, int *index)
IUGetConfigOnSwitchIndex Opens configuration file and reads single switch property to find ON switch ...
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
void IDDefNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
void IDDefText(const ITextVectorProperty *tvp, const char *fmt,...)
int dispatch(XMLEle *root, char msg[])
void IDDefLight(const ILightVectorProperty *lvp, const char *fmt,...)
void IDDefBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
int IUGetConfigSwitch(const char *dev, const char *property, const char *member, ISState *value)
IUGetConfigSwitch Opens configuration file and reads single switch property.
FILE * IUGetConfigFP(const char *filename, const char *dev, const char *mode, char errmsg[])
Open a configuration file for writing and return a configuration file FILE pointer.
void IDSetLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
void IDDefSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
void driverio_init(driverio *dio)
void driverio_finish(driverio *dio)
void IUUserIOSetLightVA(const userio *io, void *user, const ILightVectorProperty *lvp, const char *fmt, va_list ap)
void IUUserIODefLightVA(const userio *io, void *user, const ILightVectorProperty *lvp, const char *fmt, va_list ap)
void IUUserIOUpdateMinMax(const userio *io, void *user, const INumberVectorProperty *nvp)
void IUUserIODefBLOBVA(const userio *io, void *user, const IBLOBVectorProperty *b, const char *fmt, va_list ap)
void IUUserIODeleteVA(const userio *io, void *user, const char *dev, const char *name, const char *fmt, va_list ap)
void IUUserIOSetSwitchVA(const userio *io, void *user, const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
void IUUserIODefTextVA(const userio *io, void *user, const ITextVectorProperty *tvp, const char *fmt, va_list ap)
void IUUserIOSetNumberVA(const userio *io, void *user, const INumberVectorProperty *nvp, const char *fmt, va_list ap)
void IUUserIODefSwitchVA(const userio *io, void *user, const ISwitchVectorProperty *s, const char *fmt, va_list ap)
void IUUserIOSetBLOBVA(const userio *io, void *user, const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
void IUUserIOEnableBLOB(const userio *io, void *user, const char *dev, const char *name, BLOBHandling blobH)
void IUUserIOPingRequest(const userio *io, void *user, const char *pingUid)
void IDUserIOMessageVA(const userio *io, void *user, const char *dev, const char *fmt, va_list ap)
void IUUserIOSetTextVA(const userio *io, void *user, const ITextVectorProperty *tvp, const char *fmt, va_list ap)
void IUUserIOConfigTag(const userio *io, void *user, int ctag)
void IUUserIOGetProperties(const userio *io, void *user, const char *dev, const char *name)
void IUUserIODefNumberVA(const userio *io, void *user, const INumberVectorProperty *n, const char *fmt, va_list ap)
int nXMLEle(XMLEle *ep)
Return the number of nested XML elements in a parent XML element.
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
LilXML * newLilXML()
Create a new lilxml parser.
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
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.
void delLilXML(LilXML *lp)
Delete a lilxml parser.
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
std::vector< uint8_t > buffer
Namespace to encapsulate INDI client, drivers, and mediator classes.
int mkdir(const char *path, mode_t mode)
One Blob (Binary Large Object) descriptor.
char devName[MAXINDIDEVICE]
char propName[MAXINDINAME]
BLOB (Binary Large Object) vector property descriptor.
char device[MAXINDIDEVICE]
Light vector property descriptor.
Number vector property descriptor.
char device[MAXINDIDEVICE]
Switch vector property descriptor.
char device[MAXINDIDEVICE]
Text vector property descriptor.
char device[MAXINDIDEVICE]
const struct userio * userio_file()
void userio_xmlv1(const userio *io, void *user)