/*      $NetBSD: iteconfig.c,v 1.10 2018/01/23 21:06:25 sevan Exp $     */
/*
* Copyright (c) 1994 Christian E. Hopps
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*      This product includes software developed by Christian E. Hopps
* 4. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: iteconfig.c,v 1.10 2018/01/23 21:06:25 sevan Exp $");
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/queue.h>

#if !defined(amiga) && !defined(atari)
#error "This source is not suitable for this architecture!"
#endif

#if defined(amiga)
#include <amiga/dev/grfabs_reg.h>
#include <amiga/dev/viewioctl.h>
#include <amiga/dev/iteioctl.h>
#endif /* defined(amiga)        */

#if defined(atari)
#include <atari/dev/grfabs_reg.h>
#include <atari/dev/viewioctl.h>
#include <atari/dev/iteioctl.h>
#endif /* defined(atari)        */

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include "pathnames.h"

int     initialize(const char *, struct itewinsize *, struct itebell *,
                       struct itewinsize *, struct itebell *);
void    printcmap(colormap_t *, int);
void    xioctl(int, int, void *);
colormap_t *xgetcmap(int, int);
long    xstrtol(char *);
static void     usage(void) __dead;

int
main(int argc, char *argv[])
{
       struct itewinsize is, newis;
       struct itebell ib, newib;
       struct winsize ws;
       colormap_t *cm;
       const char *file = _PATH_CONSOLE;
       int ch, fd, i, iflag, max_colors, did_reset;
       long val;

       iflag = 0;
       did_reset = 0;

       fd = initialize(_PATH_CONSOLE, &is, &ib, &newis, &newib);

       while ((ch = getopt(argc, argv, "D:H:P:T:V:W:X:Y:d:f:h:ip:t:v:w:x:y:"))
           != -1) {
               switch (ch) {
               case 'D':               /* undocumented backward compat */
               case 'd':
                       newis.depth = xstrtol(optarg);
                       break;
               case 'f':
                       if (did_reset)
                               break;
                       if (fd != -1)
                               close(fd);
                       file = optarg;
                       fd = initialize(optarg, &is, &ib, &newis, &newib);
                       did_reset = optreset = optind = 1;
                       break;
               case 'H':               /* undocumented backward compat */
               case 'h':
                       newis.height = xstrtol(optarg);
                       break;
               case 'i':
                       iflag = 1;
                       break;
               case 'p':
                       newib.pitch = xstrtol(optarg);
                       break;
               case 't':
                       newib.msec = xstrtol(optarg);
                       break;
               case 'V':               /* undocumented backward compat */
               case 'v':
                       newib.volume = xstrtol(optarg);
                       break;
               case 'W':               /* undocumented backward compat */
               case 'w':
                       newis.width = xstrtol(optarg);
                       break;
               case 'X':               /* undocumented backward compat */
               case 'x':
                       newis.x = xstrtol(optarg);
                       break;
               case 'Y':               /* undocumented backward compat */
               case 'y':
                       newis.y = xstrtol(optarg);
                       break;
               case '?':
               default:
                       usage();
                       /* NOTREACHED */
               }
       }
       argc -= optind;
       argv += optind;
       if(fd == -1)
               err(1, "open \"%s\"", file);

       if (memcmp(&newis, &is, sizeof(is))) {
               xioctl(fd, ITEIOCSWINSZ, &newis);
               xioctl(fd, ITEIOCGWINSZ, &is);
       }
       if (memcmp(&newib, &ib, sizeof(ib))) {
               xioctl(fd, ITEIOCSBELL, &newib);
               xioctl(fd, ITEIOCGBELL, &ib);
       }

       /*
        * get, set and get colors again
        */
       i = 0;
       max_colors = 1 << is.depth;
       cm = xgetcmap(fd, max_colors);
       while (argc--) {
               val = xstrtol(*argv++);
               if (i >= max_colors) {
                       warnx("warning: too many colors");
                       break;
               }
               cm->entry[i] = val;
               i++;
       }
       xioctl(fd, VIOCSCMAP, cm);
       free(cm);
       cm = xgetcmap(fd, max_colors);

       /* do tty stuff to get it to register the changes. */
       xioctl(fd, TIOCGWINSZ, &ws);

       if (iflag) {
               printf("tty size: rows %d cols %d\n", ws.ws_row, ws.ws_col);
               printf("ite size: w: %d  h: %d  d: %d  [x: %d  y: %d]\n",
                   is.width, is.height, is.depth, is.x, is.y);
               printf("ite bell: vol: %d  millisec: %d  pitch: %d\n",
                   ib.volume, ib.msec, ib.pitch);
               printcmap(cm, ws.ws_col);
       }
       close(fd);
       exit(0);
}

void
xioctl(int fd, int cmd, void *addr)
{
       if (ioctl(fd, cmd, addr) == -1)
               err(1, "ioctl");
}

long
xstrtol(char *s)
{
       long rv;

       errno = 0;
       rv = strtol(s, NULL, 0);
       if (errno == ERANGE && (rv == LONG_MIN || rv == LONG_MAX))
               err(1, "bad format: \"%s\"", s);
       return(rv);
}

colormap_t *
xgetcmap(int fd, int ncolors)
{
       colormap_t *cm;

       cm = malloc(sizeof(colormap_t) + ncolors * sizeof(u_long));
       if (cm == NULL)
               err(1, "malloc");
       cm->first = 0;
       cm->size = ncolors;
       cm->entry = (u_long *) & cm[1];
       xioctl(fd, VIOCGCMAP, cm);
       return(cm);
}

void
printcmap(colormap_t *cm, int ncols)
{
       int i, nel;

       switch (cm->type) {
       case CM_MONO:
               printf("monochrome");
               return;
       case CM_COLOR:
               printf("color levels: red: %d  green: %d  blue: %d",
                   cm->red_mask + 1, cm->green_mask + 1, cm->blue_mask + 1);
               break;
       case CM_GREYSCALE:
               printf("greyscale levels: %d", cm->grey_mask + 1);
               break;
       }
       printf("\n");

       nel = ncols / 11 - 1;
       for (i = 0; i < cm->size; i++) {
               printf("0x%08lx ", cm->entry[i]);
               if ((i + 1) % nel == 0)
                       printf("\n");
       }
       if ((i + 1) % nel)
               printf("\n");
}

int
initialize(file, is, ib, newis, newib)
       const char      *file;
       struct itewinsize *is, *newis;
       struct itebell *ib, *newib;
{
       int fd;

       fd = open(file, O_RDONLY | O_NONBLOCK);
       if (fd == -1)
               return(-1);

       xioctl(fd, ITEIOCGWINSZ, is);
       xioctl(fd, ITEIOCGBELL, ib);

       memcpy(newis, is, sizeof(*is));
       memcpy(newib, ib, sizeof(*ib));
       return(fd);
}

static void
usage(void)
{
       fprintf(stderr, "%s\n\t\t%s\n\t\t%s\n",
           "usage: iteconfig [-i] [-f file] [-v volume] [-p pitch] [-t msec]",
           "[-w width] [-h height] [-d depth] [-x off] [-y off]",
           "[color ...]");
       exit(1);
}