root/sys/arch/x68k/usr.bin/bellctrl/bellctrl.c
/*      $NetBSD: bellctrl.c,v 1.13 2011/08/25 17:00:55 christos Exp $   */

/*
 * bellctrl - OPM bell controller (for NetBSD/X680x0)
 * Copyright (c)1995 ussy.
 */

#include <sys/cdefs.h>
__RCSID("$NetBSD: bellctrl.c,v 1.13 2011/08/25 17:00:55 christos Exp $");

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <machine/opmbellio.h>

#define DEFAULT -1

#define nextarg(i, argv) \
        argv[i]; \
        if (i >= argc) \
                break; \

static int bell_setting;
static struct opm_voice voice;

static struct opm_voice bell_voice = DEFAULT_BELL_VOICE;

static struct bell_info values = {
        DEFAULT, DEFAULT, DEFAULT
};

/* function prototype */
static int is_number(const char *, int);
static void set_bell_vol(int);
static void set_bell_pitch(int);
static void set_bell_dur(int);
static void set_voice_param(const char *, int);
static void set_bell_param(void);
static void usage(void) __dead;

int
main(int argc, char **argv)
{
        const char *arg;
        int percent;
        int i;

        bell_setting = 0;

        if (argc < 2)
                usage();

        for (i = 1; i < argc; ) {
                arg = argv[i++];
                if (strcmp(arg, "-b") == 0) {
                        /* turn off bell */
                        set_bell_vol(0);
                } else if (strcmp(arg, "b") == 0) {
                        /* set bell to default */
                        percent = DEFAULT;

                        if (i >= argc) {
                                /* set bell to default */
                                set_bell_vol(percent);
                                /* set pitch to default */
                                set_bell_pitch(percent);
                                /* set duration to default */
                                set_bell_dur(percent);
                                break;
                        }
                        arg = nextarg(i, argv);
                        if (strcmp(arg, "on") == 0) {
                                /*
                                 * let it stay that way
                                 */
                                /* set bell on */
                                set_bell_vol(BELL_VOLUME);
                                /* set pitch to default */
                                set_bell_pitch(BELL_PITCH);
                                /* set duration to default */
                                set_bell_dur(BELL_DURATION);
                                i++;
                        } else if (strcmp(arg, "off") == 0) {
                                /* turn the bell off */
                                percent = 0;
                                set_bell_vol(percent);
                                i++;
                        } else if (is_number(arg, MAXBVOLUME)) {
                                /*
                                 * If volume is given
                                 */
                                /* set bell appropriately */
                                percent = atoi(arg);

                                set_bell_vol(percent);
                                i++;

                                arg = nextarg(i, argv);

                                /* if pitch is given */
                                if (is_number(arg, MAXBPITCH)) {
                                        /* set the bell */
                                        set_bell_pitch(atoi(arg));
                                        i++;

                                        arg = nextarg(i, argv);
                                        /* If duration is given */
                                        if (is_number(arg, MAXBTIME)) {
                                                /* set the bell */
                                                set_bell_dur(atoi(arg));
                                                i++;
                                        }
                                }
                        } else {
                                /* set bell to default */
                                set_bell_vol(BELL_VOLUME);
                        }
                } else if (strcmp(arg, "v") == 0) {
                        /*
                         * set voice parameter
                         */
                        if (i >= argc) {
                                arg = "default";
                        } else {
                                arg = nextarg(i, argv);
                        }
                        set_voice_param(arg, 1);
                        i++;
                } else if (strcmp(arg, "-v") == 0) {
                        /*
                         * set voice parameter
                         */
                        if (i >= argc) {
                                warnx("Missing -v argument");
                                usage();
                        }
                        arg = nextarg(i, argv);
                        set_voice_param(arg, 0);
                        i++;
                } else {
                        warnx("Unknown option %s", arg);
                        usage();
                }
        }

        if (bell_setting)
                set_bell_param();

        exit(0);
}

static int
is_number(const char *arg, int maximum)
{
        const char *p;

        if (arg[0] == '-' && arg[1] == '1' && arg[2] == '\0')
                return 1;
        for (p = arg; isdigit((unsigned char)*p); p++)
                ;
        if (*p || atoi(arg) > maximum)
                return 0;

        return 1;
}

static void
set_bell_vol(int percent)
{
        values.volume = percent;
        bell_setting++;
}

static void
set_bell_pitch(int pitch)
{
        values.pitch = pitch;
        bell_setting++;
}

static void
set_bell_dur(int duration)
{
        values.msec = duration;
        bell_setting++;
}

static void
set_voice_param(const char *path, int flag)
{
        int fd;

        if (flag) {
                memcpy(&voice, &bell_voice, sizeof(bell_voice));
        } else {
                if ((fd = open(path, 0)) >= 0) {
                        if (read(fd, &voice, sizeof(voice)) != sizeof(voice))
                                err(1, "cannot read voice parameter");
                        close(fd);
                } else {
                        err(1, "cannot open voice parameter");
                }
        }

        if ((fd = open("/dev/bell", O_RDWR)) < 0)
                err(1, "cannot open /dev/bell");
        if (ioctl(fd, BELLIOCSVOICE, &voice))
                err(1, "ioctl BELLIOCSVOICE failed");

        close(fd);
}

static void
set_bell_param(void)
{
        int fd;
        struct bell_info param;

        if ((fd = open("/dev/bell", O_RDWR)) < 0)
                err(1, "cannot open /dev/bell");
        if (ioctl(fd, BELLIOCGPARAM, &param))
                err(1, "ioctl BELLIOCGPARAM failed");

        if (values.volume == DEFAULT)
                values.volume = param.volume;
        if (values.pitch == DEFAULT)
                values.pitch = param.pitch;
        if (values.msec == DEFAULT)
                values.msec = param.msec;

        if (ioctl(fd, BELLIOCSPARAM, &values))
                err(1, "ioctl BELLIOCSPARAM failed");

        close(fd);
}

static void
usage(void)
{
        fprintf(stderr, "Usage: %s option ...\n", getprogname());
        fprintf(stderr, "       To turn bell off:\n");
        fprintf(stderr, "\t-b                           b off"
                        "                          b 0\n");
        fprintf(stderr, "       To set bell volume, pitch and duration:\n");
        fprintf(stderr, "\t b [vol [pitch [dur]]]                 b on\n");
        fprintf(stderr, "       To restore default voice parameter:\n");
        fprintf(stderr, "\t v default\n");
        fprintf(stderr, "       To set voice parameter:\n");
        fprintf(stderr, "\t-v voicefile\n");
        exit(0);
}