NetBSD/usr.bin/tset/map.c

234 lines
5.7 KiB
C

/* $NetBSD: map.c,v 1.13 2011/09/06 18:34:12 joerg Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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
#if 0
static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/9/93";
#endif
__RCSID("$NetBSD: map.c,v 1.13 2011/09/06 18:34:12 joerg Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <term.h>
#include <termios.h>
#include "extern.h"
static int baudrate(char *);
/* Baud rate conditionals for mapping. */
#define GT 0x01
#define EQ 0x02
#define LT 0x04
#define NOT 0x08
#define GE (GT | EQ)
#define LE (LT | EQ)
typedef struct map {
struct map *next; /* Linked list of maps. */
const char *porttype; /* Port type, or "" for any. */
const char *type; /* Terminal type to select. */
int conditional; /* Baud rate conditionals bitmask. */
int speed; /* Baud rate to compare against. */
} MAP;
static MAP *cur, *maplist;
/*
* Syntax for -m:
* [port-type][test baudrate]:terminal-type
* The baud rate tests are: >, <, @, =, !
*/
void
add_mapping(const char *port, char *arg)
{
MAP *mapp;
char *copy, *p, *termp;
copy = strdup(arg);
mapp = malloc((u_int)sizeof(MAP));
if (copy == NULL || mapp == NULL)
err(1, "malloc");
mapp->next = NULL;
if (maplist == NULL)
cur = maplist = mapp;
else {
cur->next = mapp;
cur = mapp;
}
mapp->porttype = arg;
mapp->conditional = 0;
arg = strpbrk(arg, "><@=!:");
if (arg == NULL) { /* [?]term */
mapp->type = mapp->porttype;
mapp->porttype = NULL;
goto done;
}
if (arg == mapp->porttype) /* [><@=! baud]:term */
mapp->porttype = termp = NULL;
else
termp = arg;
for (;; ++arg) /* Optional conditionals. */
switch(*arg) {
case '<':
if (mapp->conditional & GT)
goto badmopt;
mapp->conditional |= LT;
break;
case '>':
if (mapp->conditional & LT)
goto badmopt;
mapp->conditional |= GT;
break;
case '@':
case '=': /* Not documented. */
mapp->conditional |= EQ;
break;
case '!':
mapp->conditional |= NOT;
break;
default:
goto next;
}
next: if (*arg == ':') {
if (mapp->conditional)
goto badmopt;
++arg;
} else { /* Optional baudrate. */
arg = strchr(p = arg, ':');
if (arg == NULL)
goto badmopt;
*arg++ = '\0';
mapp->speed = baudrate(p);
}
if (*arg == '\0') /* Non-optional type. */
goto badmopt;
mapp->type = arg;
/* Terminate porttype, if specified. */
if (termp != NULL)
*termp = '\0';
/* If a NOT conditional, reverse the test. */
if (mapp->conditional & NOT)
mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
/* If user specified a port with an option flag, set it. */
done: if (port) {
if (mapp->porttype)
badmopt: errx(1, "illegal -m option format: %s", copy);
mapp->porttype = port;
}
#ifdef MAPDEBUG
(void)printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
(void)printf("type: %s\n", mapp->type);
(void)printf("conditional: ");
p = "";
if (mapp->conditional & GT) {
(void)printf("GT");
p = "/";
}
if (mapp->conditional & EQ) {
(void)printf("%sEQ", p);
p = "/";
}
if (mapp->conditional & LT)
(void)printf("%sLT", p);
(void)printf("\nspeed: %d\n", mapp->speed);
#endif
free(copy);
}
/*
* Return the type of terminal to use for a port of type 'type', as specified
* by the first applicable mapping in 'map'. If no mappings apply, return
* 'type'.
*/
const char *
mapped(const char *type)
{
MAP *mapp;
int match;
match = 0;
for (mapp = maplist; mapp; mapp = mapp->next)
if (mapp->porttype == NULL || !strcmp(mapp->porttype, type)) {
switch (mapp->conditional) {
case 0: /* No test specified. */
match = 1;
break;
case EQ:
match = (ospeed == mapp->speed);
break;
case GE:
match = (ospeed >= mapp->speed);
break;
case GT:
match = (ospeed > mapp->speed);
break;
case LE:
match = (ospeed <= mapp->speed);
break;
case LT:
match = (ospeed < mapp->speed);
break;
}
if (match)
return (mapp->type);
}
/* No match found; return given type. */
return (type);
}
static int
baudrate(char *rate)
{
/* The baudrate number can be preceded by a 'B', which is ignored. */
if (*rate == 'B')
++rate;
return (atoi(rate));
}