summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2005-02-07 14:29:11 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2005-02-07 14:29:11 +0000
commit968ced4fb7bf97052f93cb0a1de75ef4355b24f5 (patch)
tree876b4003c63250e983ad2942a2b941d1eb2cc262
parent97622f8be15bea33710bb1fc47c2af10447cb129 (diff)
Levels should be between AUDIO_MIN_GAIN and AUDIO_MAX_GAIN inclusive
Truncate specified level to be within this range and avoid wrapping. Idea from espie@, OK henning@
-rw-r--r--usr.bin/mixerctl/mixerctl.c92
1 files changed, 41 insertions, 51 deletions
diff --git a/usr.bin/mixerctl/mixerctl.c b/usr.bin/mixerctl/mixerctl.c
index a1a281c0dac..9d48f8f0696 100644
--- a/usr.bin/mixerctl/mixerctl.c
+++ b/usr.bin/mixerctl/mixerctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mixerctl.c,v 1.19 2005/02/02 08:08:33 otto Exp $ */
+/* $OpenBSD: mixerctl.c,v 1.20 2005/02/07 14:29:10 millert Exp $ */
/* $NetBSD: mixerctl.c,v 1.11 1998/04/27 16:55:23 augustss Exp $ */
/*
@@ -45,14 +45,17 @@
#include <sys/audioio.h>
#include <err.h>
+#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-void catstr(char *, char *, char *);
struct field *findfield(char *);
+void adjlevel(char **, u_char *, int);
+void catstr(char *, char *, char *);
void prfield(struct field *, char *, int);
void rdfield(int, struct field *, char *);
__dead void usage(void);
@@ -139,11 +142,38 @@ prfield(struct field *p, char *sep, int prvalset)
}
void
+adjlevel(char **p, u_char *olevel, int more)
+{
+ char *ep, *cp = *p;
+ long inc;
+ u_char level;
+
+ if (*cp != '+' && *cp != '-')
+ *olevel = 0; /* absolute setting */
+
+ errno = 0;
+ inc = strtol(cp, &ep, 10);
+ if (*cp == '\0' || (*ep != '\0' && *ep != ',') ||
+ (errno == ERANGE && (inc == LONG_MAX || inc == LONG_MIN)))
+ errx(1, "Bad number %s", cp);
+ if (*ep == ',' && !more)
+ errx(1, "Too many values");
+ *p = ep;
+
+ if (inc < AUDIO_MIN_GAIN - *olevel)
+ level = AUDIO_MIN_GAIN;
+ else if (inc > AUDIO_MAX_GAIN - *olevel)
+ level = AUDIO_MAX_GAIN;
+ else
+ level = *olevel + inc;
+ *olevel = level;
+}
+
+void
rdfield(int fd, struct field *p, char *q)
{
mixer_ctrl_t *m, oldval;
- int v, v0, v1, mask;
- int i;
+ int i, mask;
char *s;
oldval = *p->valp;
@@ -161,7 +191,7 @@ rdfield(int fd, struct field *p, char *q)
break;
case AUDIO_MIXER_SET:
mask = 0;
- for (v = 0; q && *q; q = s) {
+ for (; q && *q; q = s) {
if ((s = strchr(q, ',')) != NULL)
*s++ = 0;
for (i = 0; i < p->infp->un.s.num_mem; i++)
@@ -176,53 +206,13 @@ rdfield(int fd, struct field *p, char *q)
break;
case AUDIO_MIXER_VALUE:
if (m->un.value.num_channels == 1) {
- if (sscanf(q, "%d", &v) == 1) {
- switch (*q) {
- case '+':
- case '-':
- m->un.value.level[0] += v;
- break;
- default:
- m->un.value.level[0] = v;
- break;
- }
- } else
- errx(1, "Bad number %s", q);
+ adjlevel(&q, &m->un.value.level[0], 0);
} else {
- if (sscanf(q, "%d,%d", &v0, &v1) == 2) {
- switch (*q) {
- case '+':
- case '-':
- m->un.value.level[0] += v0;
- break;
- default:
- m->un.value.level[0] = v0;
- break;
- }
- s = strchr(q, ',') + 1;
- switch (*s) {
- case '+':
- case '-':
- m->un.value.level[1] += v1;
- break;
- default:
- m->un.value.level[1] = v1;
- break;
- }
- } else if (sscanf(q, "%d", &v) == 1) {
- switch (*q) {
- case '+':
- case '-':
- m->un.value.level[0] += v;
- m->un.value.level[1] += v;
- break;
- default:
- m->un.value.level[0] = v;
- m->un.value.level[1] = v;
- break;
- }
- } else
- errx(1, "Bad numbers %s", q);
+ adjlevel(&q, &m->un.value.level[0], 1);
+ if (*q++ == ',')
+ adjlevel(&q, &m->un.value.level[1], 0);
+ else
+ m->un.value.level[1] = m->un.value.level[0];
}
break;
default: