mirror of https://github.com/ericonr/sndio.git
Allow switching between devices without disconnecting clients, again.
The new -F option allows alternate device to be specified. If the device is disconnected, the one given with the last -f or -F options will be used instead. ok mpi@
This commit is contained in:
parent
3935da37f6
commit
441100e812
73
sndiod/dev.c
73
sndiod/dev.c
|
@ -970,7 +970,8 @@ dev_new(char *path, struct aparams *par,
|
|||
return NULL;
|
||||
}
|
||||
d = xmalloc(sizeof(struct dev));
|
||||
d->path = xstrdup(path);
|
||||
d->path_list = NULL;
|
||||
namelist_add(&d->path_list, path);
|
||||
d->num = dev_sndnum++;
|
||||
d->opt_list = NULL;
|
||||
|
||||
|
@ -1175,6 +1176,74 @@ dev_close(struct dev *d)
|
|||
dev_freebufs(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the device, but attempt to migrate everything to a new sndio
|
||||
* device.
|
||||
*/
|
||||
int
|
||||
dev_reopen(struct dev *d)
|
||||
{
|
||||
struct slot *s;
|
||||
long long pos;
|
||||
unsigned int pstate;
|
||||
int delta;
|
||||
|
||||
/* not opened */
|
||||
if (d->pstate == DEV_CFG)
|
||||
return 1;
|
||||
|
||||
/* save state */
|
||||
delta = d->delta;
|
||||
pstate = d->pstate;
|
||||
|
||||
if (!dev_sio_reopen(d))
|
||||
return 0;
|
||||
|
||||
/* reopen returns a stopped device */
|
||||
d->pstate = DEV_INIT;
|
||||
|
||||
/* reallocate new buffers, with new parameters */
|
||||
dev_freebufs(d);
|
||||
dev_allocbufs(d);
|
||||
|
||||
/*
|
||||
* adjust time positions, make anything go back delta ticks, so
|
||||
* that the new device can start at zero
|
||||
*/
|
||||
for (s = d->slot_list; s != NULL; s = s->next) {
|
||||
pos = (long long)s->delta * d->round + s->delta_rem;
|
||||
pos -= (long long)delta * s->round;
|
||||
s->delta_rem = pos % (int)d->round;
|
||||
s->delta = pos / (int)d->round;
|
||||
if (log_level >= 3) {
|
||||
slot_log(s);
|
||||
log_puts(": adjusted: delta -> ");
|
||||
log_puti(s->delta);
|
||||
log_puts(", delta_rem -> ");
|
||||
log_puti(s->delta_rem);
|
||||
log_puts("\n");
|
||||
}
|
||||
|
||||
/* reinitilize the format conversion chain */
|
||||
slot_initconv(s);
|
||||
}
|
||||
if (d->tstate == MMC_RUN) {
|
||||
d->mtc.delta -= delta * MTC_SEC;
|
||||
if (log_level >= 2) {
|
||||
dev_log(d);
|
||||
log_puts(": adjusted mtc: delta ->");
|
||||
log_puti(d->mtc.delta);
|
||||
log_puts("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* start the device if needed */
|
||||
if (pstate == DEV_RUN)
|
||||
dev_wakeup(d);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
dev_ref(struct dev *d)
|
||||
{
|
||||
|
@ -1281,7 +1350,7 @@ dev_del(struct dev *d)
|
|||
}
|
||||
midi_del(d->midi);
|
||||
*p = d->next;
|
||||
xfree(d->path);
|
||||
namelist_clear(&d->path_list);
|
||||
xfree(d);
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ struct dev {
|
|||
#define DEV_INIT 1 /* stopped */
|
||||
#define DEV_RUN 2 /* playin & recording */
|
||||
unsigned int pstate; /* one of above */
|
||||
char *path; /* sio path */
|
||||
struct name *path_list;
|
||||
|
||||
/*
|
||||
* actual parameters and runtime state (i.e. once opened)
|
||||
|
@ -201,6 +201,7 @@ extern struct dev *dev_list;
|
|||
|
||||
void dev_log(struct dev *);
|
||||
void dev_close(struct dev *);
|
||||
int dev_reopen(struct dev *);
|
||||
struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int,
|
||||
unsigned int, unsigned int, unsigned int, unsigned int);
|
||||
struct dev *dev_bynum(int);
|
||||
|
|
|
@ -439,7 +439,8 @@ port_new(char *path, unsigned int mode, int hold)
|
|||
struct port *c;
|
||||
|
||||
c = xmalloc(sizeof(struct port));
|
||||
c->path = xstrdup(path);
|
||||
c->path_list = NULL;
|
||||
namelist_add(&c->path_list, path);
|
||||
c->state = PORT_CFG;
|
||||
c->hold = hold;
|
||||
c->midi = midi_new(&port_midiops, c, mode);
|
||||
|
@ -469,7 +470,7 @@ port_del(struct port *c)
|
|||
#endif
|
||||
}
|
||||
*p = c->next;
|
||||
xfree(c->path);
|
||||
namelist_clear(&c->path_list);
|
||||
xfree(c);
|
||||
}
|
||||
|
||||
|
@ -594,3 +595,15 @@ port_done(struct port *c)
|
|||
if (c->state == PORT_INIT)
|
||||
port_drain(c);
|
||||
}
|
||||
|
||||
int
|
||||
port_reopen(struct port *p)
|
||||
{
|
||||
if (p->state == PORT_CFG)
|
||||
return 1;
|
||||
|
||||
if (!port_mio_reopen(p))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ struct port {
|
|||
#define PORT_DRAIN 2
|
||||
unsigned int state;
|
||||
unsigned int num; /* port serial number */
|
||||
char *path;
|
||||
struct name *path_list;
|
||||
int hold; /* hold the port open ? */
|
||||
struct midi *midi;
|
||||
};
|
||||
|
@ -121,5 +121,6 @@ int port_init(struct port *);
|
|||
void port_done(struct port *);
|
||||
void port_drain(struct port *);
|
||||
int port_close(struct port *);
|
||||
int port_reopen(struct port *);
|
||||
|
||||
#endif /* !defined(MIDI_H) */
|
||||
|
|
|
@ -44,13 +44,68 @@ struct fileops port_mio_ops = {
|
|||
port_mio_hup
|
||||
};
|
||||
|
||||
/*
|
||||
* open the port using one of the provided paths
|
||||
*/
|
||||
static struct mio_hdl *
|
||||
port_mio_openlist(struct port *c, unsigned int mode)
|
||||
{
|
||||
struct mio_hdl *hdl;
|
||||
struct name *n;
|
||||
|
||||
n = c->path_list;
|
||||
while (1) {
|
||||
if (n == NULL)
|
||||
break;
|
||||
hdl = mio_open(n->str, mode, 1);
|
||||
if (hdl != NULL) {
|
||||
if (log_level >= 2) {
|
||||
port_log(c);
|
||||
log_puts(": using ");
|
||||
log_puts(n->str);
|
||||
log_puts("\n");
|
||||
}
|
||||
return hdl;
|
||||
}
|
||||
n = n->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
port_mio_open(struct port *p)
|
||||
{
|
||||
p->mio.hdl = mio_open(p->path, p->midi->mode, 1);
|
||||
p->mio.hdl = port_mio_openlist(p, p->midi->mode);
|
||||
if (p->mio.hdl == NULL)
|
||||
return 0;
|
||||
p->mio.file = file_new(&port_mio_ops, p, p->path, mio_nfds(p->mio.hdl));
|
||||
p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(p->mio.hdl));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open an alternate port. Upon success, close the old port
|
||||
* and continue using the new one.
|
||||
*/
|
||||
int
|
||||
port_mio_reopen(struct port *p)
|
||||
{
|
||||
struct mio_hdl *hdl;
|
||||
|
||||
hdl = port_mio_openlist(p, p->midi->mode);
|
||||
if (hdl == NULL) {
|
||||
if (log_level >= 1) {
|
||||
port_log(p);
|
||||
log_puts(": couldn't open an alternate port\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* close unused device */
|
||||
file_del(p->mio.file);
|
||||
mio_close(p->mio.hdl);
|
||||
|
||||
p->mio.hdl = hdl;
|
||||
p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(hdl));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -128,5 +183,6 @@ port_mio_hup(void *arg)
|
|||
{
|
||||
struct port *p = arg;
|
||||
|
||||
port_close(p);
|
||||
if (!port_reopen(p))
|
||||
port_close(p);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ struct port_mio {
|
|||
};
|
||||
|
||||
int port_mio_open(struct port *);
|
||||
int port_mio_reopen(struct port *);
|
||||
void port_mio_close(struct port *);
|
||||
|
||||
#endif /* !defined(MIOFILE_H) */
|
||||
|
|
112
sndiod/siofile.c
112
sndiod/siofile.c
|
@ -83,6 +83,34 @@ dev_sio_timeout(void *arg)
|
|||
dev_close(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* open the device using one of the provided paths
|
||||
*/
|
||||
static struct sio_hdl *
|
||||
dev_sio_openlist(struct dev *d, unsigned int mode)
|
||||
{
|
||||
struct name *n;
|
||||
struct sio_hdl *hdl;
|
||||
|
||||
n = d->path_list;
|
||||
while (1) {
|
||||
if (n == NULL)
|
||||
break;
|
||||
hdl = sio_open(n->str, mode, 1);
|
||||
if (hdl != NULL) {
|
||||
if (log_level >= 2) {
|
||||
dev_log(d);
|
||||
log_puts(": using ");
|
||||
log_puts(n->str);
|
||||
log_puts("\n");
|
||||
}
|
||||
return hdl;
|
||||
}
|
||||
n = n->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* open the device.
|
||||
*/
|
||||
|
@ -92,15 +120,15 @@ dev_sio_open(struct dev *d)
|
|||
struct sio_par par;
|
||||
unsigned int mode = d->mode & (MODE_PLAY | MODE_REC);
|
||||
|
||||
d->sio.hdl = sio_open(d->path, mode, 1);
|
||||
d->sio.hdl = dev_sio_openlist(d, mode);
|
||||
if (d->sio.hdl == NULL) {
|
||||
if (mode != (SIO_PLAY | SIO_REC))
|
||||
return 0;
|
||||
d->sio.hdl = sio_open(d->path, SIO_PLAY, 1);
|
||||
d->sio.hdl = dev_sio_openlist(d, SIO_PLAY);
|
||||
if (d->sio.hdl != NULL)
|
||||
mode = SIO_PLAY;
|
||||
else {
|
||||
d->sio.hdl = sio_open(d->path, SIO_REC, 1);
|
||||
d->sio.hdl = dev_sio_openlist(d, SIO_REC);
|
||||
if (d->sio.hdl != NULL)
|
||||
mode = SIO_REC;
|
||||
else
|
||||
|
@ -211,7 +239,7 @@ dev_sio_open(struct dev *d)
|
|||
if (!(mode & MODE_REC))
|
||||
d->mode &= ~MODE_REC;
|
||||
sio_onmove(d->sio.hdl, dev_sio_onmove, d);
|
||||
d->sio.file = file_new(&dev_sio_ops, d, d->path, sio_nfds(d->sio.hdl));
|
||||
d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(d->sio.hdl));
|
||||
timo_set(&d->sio.watchdog, dev_sio_timeout, d);
|
||||
return 1;
|
||||
bad_close:
|
||||
|
@ -219,6 +247,79 @@ dev_sio_open(struct dev *d)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open an alternate device. Upon success and if the new device is
|
||||
* compatible with the old one, close the old device and continue
|
||||
* using the new one. The new device is not started.
|
||||
*/
|
||||
int
|
||||
dev_sio_reopen(struct dev *d)
|
||||
{
|
||||
struct sio_par par;
|
||||
struct sio_hdl *hdl;
|
||||
|
||||
hdl = dev_sio_openlist(d, d->mode & (MODE_PLAY | MODE_REC));
|
||||
if (hdl == NULL) {
|
||||
if (log_level >= 1) {
|
||||
dev_log(d);
|
||||
log_puts(": couldn't open an alternate device\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sio_initpar(&par);
|
||||
par.bits = d->par.bits;
|
||||
par.bps = d->par.bps;
|
||||
par.sig = d->par.sig;
|
||||
par.le = d->par.le;
|
||||
par.msb = d->par.msb;
|
||||
if (d->mode & SIO_PLAY)
|
||||
par.pchan = d->pchan;
|
||||
if (d->mode & SIO_REC)
|
||||
par.rchan = d->rchan;
|
||||
par.appbufsz = d->bufsz;
|
||||
par.round = d->round;
|
||||
par.rate = d->rate;
|
||||
if (!sio_setpar(hdl, &par))
|
||||
goto bad_close;
|
||||
if (!sio_getpar(hdl, &par))
|
||||
goto bad_close;
|
||||
|
||||
/* check if new parameters are compatible with old ones */
|
||||
if (par.round != d->round || par.bufsz != d->bufsz ||
|
||||
par.rate != d->rate) {
|
||||
if (log_level >= 1) {
|
||||
dev_log(d);
|
||||
log_puts(": alternate device not compatible\n");
|
||||
}
|
||||
goto bad_close;
|
||||
}
|
||||
|
||||
/* close unused device */
|
||||
timo_del(&d->sio.watchdog);
|
||||
file_del(d->sio.file);
|
||||
sio_close(d->sio.hdl);
|
||||
|
||||
/* update parameters */
|
||||
d->par.bits = par.bits;
|
||||
d->par.bps = par.bps;
|
||||
d->par.sig = par.sig;
|
||||
d->par.le = par.le;
|
||||
d->par.msb = par.msb;
|
||||
if (d->mode & SIO_PLAY)
|
||||
d->pchan = par.pchan;
|
||||
if (d->mode & SIO_REC)
|
||||
d->rchan = par.rchan;
|
||||
|
||||
d->sio.hdl = hdl;
|
||||
d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(hdl));
|
||||
sio_onmove(hdl, dev_sio_onmove, d);
|
||||
return 1;
|
||||
bad_close:
|
||||
sio_close(hdl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dev_sio_close(struct dev *d)
|
||||
{
|
||||
|
@ -493,5 +594,6 @@ dev_sio_hup(void *arg)
|
|||
log_puts(": disconnected\n");
|
||||
}
|
||||
#endif
|
||||
dev_close(d);
|
||||
if (!dev_reopen(d))
|
||||
dev_close(d);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ struct dev_sio {
|
|||
};
|
||||
|
||||
int dev_sio_open(struct dev *);
|
||||
int dev_sio_reopen(struct dev *);
|
||||
void dev_sio_close(struct dev *);
|
||||
void dev_sio_log(struct dev *);
|
||||
void dev_sio_start(struct dev *);
|
||||
|
|
|
@ -29,10 +29,12 @@
|
|||
.Op Fl C Ar min : Ns Ar max
|
||||
.Op Fl c Ar min : Ns Ar max
|
||||
.Op Fl e Ar enc
|
||||
.Op Fl F Ar device
|
||||
.Op Fl f Ar device
|
||||
.Op Fl j Ar flag
|
||||
.Op Fl L Ar addr
|
||||
.Op Fl m Ar mode
|
||||
.Op Fl Q Ar port
|
||||
.Op Fl q Ar port
|
||||
.Op Fl r Ar rate
|
||||
.Op Fl s Ar name
|
||||
|
@ -182,6 +184,18 @@ or
|
|||
Only the signedness and the precision are mandatory.
|
||||
Examples:
|
||||
.Va u8 , s16le , s24le3 , s24le4lsb .
|
||||
.It Fl F Ar device
|
||||
Specify an alternate device to use.
|
||||
If doesn't work, the one given with the last
|
||||
.Fl f
|
||||
or
|
||||
.Fl F
|
||||
options will be used.
|
||||
For instance, specifying a USB device following a
|
||||
PCI device allows
|
||||
.Nm
|
||||
to use the USB one preferably when it's connected
|
||||
and to fall back to the PCI one when it's disconnected.
|
||||
.It Fl f Ar device
|
||||
Add this
|
||||
.Xr sndio 7
|
||||
|
@ -245,6 +259,15 @@ but the same sub-device cannot be used for both recording and monitoring.
|
|||
The default is
|
||||
.Ar play , Ns Ar rec
|
||||
(i.e. full-duplex).
|
||||
.It Fl Q Ar port
|
||||
Specify an alternate MIDI port to use.
|
||||
If doesn't work, the one given with the last
|
||||
.Fl Q
|
||||
or
|
||||
.Fl q
|
||||
options will be used.
|
||||
For instance, this allows to replace a USB MIDI controller without
|
||||
the need to restart programs using it.
|
||||
.It Fl q Ar port
|
||||
Expose the given MIDI port.
|
||||
This allows multiple programs to share the port.
|
||||
|
@ -376,11 +399,15 @@ is
|
|||
If
|
||||
.Nm
|
||||
is sent
|
||||
.Dv SIGHUP ,
|
||||
.Dv SIGINT
|
||||
or
|
||||
.Dv SIGTERM ,
|
||||
it terminates.
|
||||
If
|
||||
.Nm
|
||||
is sent
|
||||
.Dv SIGHUP ,
|
||||
it reopens all audio devices and MIDI ports.
|
||||
.Pp
|
||||
By default, when the program cannot accept
|
||||
recorded data fast enough or cannot provide data to play fast enough,
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
#endif
|
||||
|
||||
void sigint(int);
|
||||
void sighup(int);
|
||||
void opt_ch(int *, int *);
|
||||
void opt_enc(struct aparams *);
|
||||
int opt_mmc(void);
|
||||
|
@ -102,12 +103,13 @@ struct opt *mkopt(char *, struct dev *,
|
|||
int, int, int, int, int, int, int, int);
|
||||
|
||||
unsigned int log_level = 0;
|
||||
volatile sig_atomic_t quit_flag = 0;
|
||||
volatile sig_atomic_t quit_flag = 0, reopen_flag = 0;
|
||||
|
||||
char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] "
|
||||
"[-C min:max] [-c min:max] [-e enc]\n\t"
|
||||
"[-f device] [-j flag] [-L addr] [-m mode] [-q port] [-r rate]\n\t"
|
||||
"[-s name] [-t mode] [-U unit] [-v volume] [-w flag] [-z nframes]\n";
|
||||
"[-C min:max] [-c min:max]\n\t"
|
||||
"[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t"
|
||||
"[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t"
|
||||
"[-v volume] [-w flag] [-z nframes]\n";
|
||||
|
||||
/*
|
||||
* SIGINT handler, it raises the quit flag. If the flag is already set,
|
||||
|
@ -122,6 +124,16 @@ sigint(int s)
|
|||
quit_flag = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGHUP handler, it raises the reopen flag, which requests devices
|
||||
* to be reopened.
|
||||
*/
|
||||
void
|
||||
sighup(int s)
|
||||
{
|
||||
reopen_flag = 1;
|
||||
}
|
||||
|
||||
void
|
||||
opt_ch(int *rcmin, int *rcmax)
|
||||
{
|
||||
|
@ -224,6 +236,7 @@ setsig(void)
|
|||
struct sigaction sa;
|
||||
|
||||
quit_flag = 0;
|
||||
reopen_flag = 0;
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = sigint;
|
||||
|
@ -231,6 +244,7 @@ setsig(void)
|
|||
err(1, "sigaction(int) failed");
|
||||
if (sigaction(SIGTERM, &sa, NULL) == -1)
|
||||
err(1, "sigaction(term) failed");
|
||||
sa.sa_handler = sighup;
|
||||
if (sigaction(SIGHUP, &sa, NULL) == -1)
|
||||
err(1, "sigaction(hup) failed");
|
||||
}
|
||||
|
@ -287,7 +301,8 @@ mkdev(char *path, struct aparams *par,
|
|||
struct dev *d;
|
||||
|
||||
for (d = dev_list; d != NULL; d = d->next) {
|
||||
if (strcmp(d->path, path) == 0)
|
||||
if (d->path_list->next == NULL &&
|
||||
strcmp(d->path_list->str, path) == 0)
|
||||
return d;
|
||||
}
|
||||
if (!bufsz && !round) {
|
||||
|
@ -309,7 +324,8 @@ mkport(char *path, int hold)
|
|||
struct port *c;
|
||||
|
||||
for (c = port_list; c != NULL; c = c->next) {
|
||||
if (strcmp(c->path, path) == 0)
|
||||
if (c->path_list->next == NULL &&
|
||||
strcmp(c->path_list->str, path) == 0)
|
||||
return c;
|
||||
}
|
||||
c = port_new(path, MODE_MIDIMASK, hold);
|
||||
|
@ -375,7 +391,8 @@ main(int argc, char **argv)
|
|||
mode = MODE_PLAY | MODE_REC;
|
||||
tcpaddr_list = NULL;
|
||||
|
||||
while ((c = getopt(argc, argv, "a:b:c:C:de:f:j:L:m:q:r:s:t:U:v:w:x:z:")) != -1) {
|
||||
while ((c = getopt(argc, argv,
|
||||
"a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
log_level++;
|
||||
|
@ -432,6 +449,11 @@ main(int argc, char **argv)
|
|||
case 'q':
|
||||
mkport(optarg, hold);
|
||||
break;
|
||||
case 'Q':
|
||||
if (port_list == NULL)
|
||||
errx(1, "-Q %s: no ports defined", optarg);
|
||||
namelist_add(&port_list->path_list, optarg);
|
||||
break;
|
||||
case 'a':
|
||||
hold = opt_onoff();
|
||||
break;
|
||||
|
@ -452,6 +474,11 @@ main(int argc, char **argv)
|
|||
mkdev(optarg, &par, 0, bufsz, round,
|
||||
rate, hold, autovol);
|
||||
break;
|
||||
case 'F':
|
||||
if (dev_list == NULL)
|
||||
errx(1, "-F %s: no devices defined", optarg);
|
||||
namelist_add(&dev_list->path_list, optarg);
|
||||
break;
|
||||
default:
|
||||
fputs(usagestr, stderr);
|
||||
return 1;
|
||||
|
@ -519,6 +546,13 @@ main(int argc, char **argv)
|
|||
for (;;) {
|
||||
if (quit_flag)
|
||||
break;
|
||||
if (reopen_flag) {
|
||||
reopen_flag = 0;
|
||||
for (d = dev_list; d != NULL; d = d->next)
|
||||
dev_reopen(d);
|
||||
for (p = port_list; p != NULL; p = p->next)
|
||||
port_reopen(p);
|
||||
}
|
||||
if (!file_poll())
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -188,3 +188,30 @@ xstrdup(char *s)
|
|||
memcpy(p, s, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy and append the given string to the name list
|
||||
*/
|
||||
void
|
||||
namelist_add(struct name **list, char *str)
|
||||
{
|
||||
struct name *n;
|
||||
size_t size;
|
||||
|
||||
size = strlen(str) + 1;
|
||||
n = xmalloc(sizeof(struct name) + size);
|
||||
memcpy(n->str, str, size);
|
||||
n->next = *list;
|
||||
*list = n;
|
||||
}
|
||||
|
||||
void
|
||||
namelist_clear(struct name **list)
|
||||
{
|
||||
struct name *n;
|
||||
|
||||
while ((n = *list) != NULL) {
|
||||
*list = n->next;
|
||||
xfree(n);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
struct name {
|
||||
struct name *next;
|
||||
char str[];
|
||||
};
|
||||
|
||||
void log_puts(char *);
|
||||
void log_putx(unsigned long);
|
||||
void log_putu(unsigned long);
|
||||
|
@ -31,6 +36,9 @@ void *xmalloc(size_t);
|
|||
char *xstrdup(char *);
|
||||
void xfree(void *);
|
||||
|
||||
void namelist_add(struct name **, char *);
|
||||
void namelist_clear(struct name **);
|
||||
|
||||
/*
|
||||
* Log levels:
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue