1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31
32__FBSDID("$FreeBSD$");
33
34#ifndef lint
35static const char sccsid[] = "@(#)map.c	8.1 (Berkeley) 6/9/93";
36#endif
37
38#include <sys/types.h>
39
40#include <err.h>
41#include <stdlib.h>
42#include <string.h>
43#include <termios.h>
44
45#include "extern.h"
46
47extern speed_t Ospeed;
48speed_t	tset_baudrate(char *);
49
50/* Baud rate conditionals for mapping. */
51#define	GT		0x01
52#define	EQ		0x02
53#define	LT		0x04
54#define	NOT		0x08
55#define	GE		(GT | EQ)
56#define	LE		(LT | EQ)
57
58typedef struct map {
59	struct map *next;	/* Linked list of maps. */
60	char *porttype;		/* Port type, or "" for any. */
61	char *type;		/* Terminal type to select. */
62	int conditional;	/* Baud rate conditionals bitmask. */
63	speed_t	speed;		/* Baud	rate to	compare	against. */
64} MAP;
65
66MAP *cur, *maplist;
67
68/*
69 * Syntax for -m:
70 * [port-type][test baudrate]:terminal-type
71 * The baud rate tests are: >, <, @, =, !
72 */
73void
74add_mapping(const char *port, char *arg)
75{
76	MAP *mapp;
77	char *copy, *p, *termp;
78
79	copy = strdup(arg);
80	mapp = malloc(sizeof(MAP));
81	if (copy == NULL || mapp == NULL)
82		errx(1, "malloc");
83	mapp->next = NULL;
84	if (maplist == NULL)
85		cur = maplist = mapp;
86	else {
87		cur->next = mapp;
88		cur =  mapp;
89	}
90
91	mapp->porttype = arg;
92	mapp->conditional = 0;
93
94	arg = strpbrk(arg, "><@=!:");
95
96	if (arg == NULL) {			/* [?]term */
97		mapp->type = mapp->porttype;
98		mapp->porttype = NULL;
99		goto done;
100	}
101
102	if (arg == mapp->porttype)		/* [><@=! baud]:term */
103		termp = mapp->porttype = NULL;
104	else
105		termp = arg;
106
107	for (;; ++arg)				/* Optional conditionals. */
108		switch(*arg) {
109		case '<':
110			if (mapp->conditional & GT)
111				goto badmopt;
112			mapp->conditional |= LT;
113			break;
114		case '>':
115			if (mapp->conditional & LT)
116				goto badmopt;
117			mapp->conditional |= GT;
118			break;
119		case '@':
120		case '=':			/* Not documented. */
121			mapp->conditional |= EQ;
122			break;
123		case '!':
124			mapp->conditional |= NOT;
125			break;
126		default:
127			goto next;
128		}
129
130next:	if (*arg == ':') {
131		if (mapp->conditional)
132			goto badmopt;
133		++arg;
134	} else {				/* Optional baudrate. */
135		arg = index(p = arg, ':');
136		if (arg == NULL)
137			goto badmopt;
138		*arg++ = '\0';
139		mapp->speed = tset_baudrate(p);
140	}
141
142	if (*arg == '\0')			/* Non-optional type. */
143		goto badmopt;
144
145	mapp->type = arg;
146
147	/* Terminate porttype, if specified. */
148	if (termp != NULL)
149		*termp = '\0';
150
151	/* If a NOT conditional, reverse the test. */
152	if (mapp->conditional & NOT)
153		mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
154
155	/* If user specified a port with an option flag, set it. */
156done:	if (port) {
157		if (mapp->porttype)
158badmopt:		errx(1, "illegal -m option format: %s", copy);
159		mapp->porttype = strdup(port);
160	}
161
162#ifdef MAPDEBUG
163	(void)printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
164	(void)printf("type: %s\n", mapp->type);
165	(void)printf("conditional: ");
166	p = "";
167	if (mapp->conditional & GT) {
168		(void)printf("GT");
169		p = "/";
170	}
171	if (mapp->conditional & EQ) {
172		(void)printf("%sEQ", p);
173		p = "/";
174	}
175	if (mapp->conditional & LT)
176		(void)printf("%sLT", p);
177	(void)printf("\nspeed: %d\n", mapp->speed);
178#endif
179}
180
181/*
182 * Return the type of terminal to use for a port of type 'type', as specified
183 * by the first applicable mapping in 'map'.  If no mappings apply, return
184 * 'type'.
185 */
186const char *
187mapped(const char *type)
188{
189	MAP *mapp;
190	int match;
191
192	match = 0;
193	for (mapp = maplist; mapp; mapp = mapp->next)
194		if (mapp->porttype == NULL || !strcmp(mapp->porttype, type)) {
195			switch (mapp->conditional) {
196			case 0:			/* No test specified. */
197				match = 1;
198				break;
199			case EQ:
200				match =	(Ospeed	== mapp->speed);
201				break;
202			case GE:
203				match =	(Ospeed	>= mapp->speed);
204				break;
205			case GT:
206				match =	(Ospeed	> mapp->speed);
207				break;
208			case LE:
209				match =	(Ospeed	<= mapp->speed);
210				break;
211			case LT:
212				match =	(Ospeed	< mapp->speed);
213				break;
214			}
215			if (match)
216				return (mapp->type);
217		}
218	/* No match found; return given type. */
219	return (type);
220}
221
222typedef struct speeds {
223	const char	*string;
224	speed_t	speed;
225} SPEEDS;
226
227SPEEDS speeds[] = {
228	{ "0",		B0 },
229	{ "134.5",	B134 },
230	{ "exta",	B19200 },
231	{ "extb",	B38400 },
232	{ NULL, 0 }
233};
234
235speed_t
236tset_baudrate(char *rate)
237{
238	SPEEDS *sp;
239	speed_t speed;
240
241	/* The baudrate number can be preceded by a 'B', which is ignored. */
242	if (*rate == 'B')
243		++rate;
244
245	for (sp = speeds; sp->string; ++sp)
246		if (!strcasecmp(rate, sp->string))
247			return (sp->speed);
248	speed = atol(rate);
249	if (speed == 0)
250		errx(1, "unknown baud rate %s", rate);
251	return speed;
252}
253