415 lines
9 KiB
C
415 lines
9 KiB
C
/*
|
|
* device.c -- cawf(1) output device support functions
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1991 Purdue University Research Foundation,
|
|
* West Lafayette, Indiana 47907. All rights reserved.
|
|
*
|
|
* Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
|
|
* University Computing Center. Not derived from licensed software;
|
|
* derived from awf(1) by Henry Spencer of the University of Toronto.
|
|
*
|
|
* Permission is granted to anyone to use this software for any
|
|
* purpose on any computer system, and to alter it and redistribute
|
|
* it freely, subject to the following restrictions:
|
|
*
|
|
* 1. The author is not responsible for any consequences of use of
|
|
* this software, even if they arise from flaws in it.
|
|
*
|
|
* 2. The origin of this software must not be misrepresented, either
|
|
* by explicit claim or by omission. Credits must appear in the
|
|
* documentation.
|
|
*
|
|
* 3. Altered versions must be plainly marked as such, and must not
|
|
* be misrepresented as being the original software. Credits must
|
|
* appear in the documentation.
|
|
*
|
|
* 4. This notice may not be removed or altered.
|
|
*/
|
|
|
|
#include "cawf.h"
|
|
#include <ctype.h>
|
|
|
|
_PROTOTYPE(static unsigned char *Convstr,(char *s, int *len));
|
|
_PROTOTYPE(static int Convfont,(char *nm, char *s, char **fn,
|
|
unsigned char **fi));
|
|
|
|
#ifndef UNIX
|
|
#define strcasecmp strcmpi
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
* Convstr(s, len) - convert a string
|
|
*/
|
|
|
|
static unsigned char *
|
|
Convstr(s, len)
|
|
char *s; /* input string */
|
|
int *len; /* length of result */
|
|
{
|
|
int c; /* character assembly */
|
|
unsigned char *cp; /* temporary character pointer */
|
|
char *em; /* error message */
|
|
int i; /* temporary index */
|
|
int l; /* length */
|
|
unsigned char *r; /* result string */
|
|
/*
|
|
* Make space for the result.
|
|
*/
|
|
if ((r = (unsigned char *)malloc(strlen((char *)s) + 1)) == NULL) {
|
|
(void) fprintf(stderr, "%s: out of string space at %s\n",
|
|
Pname, s);
|
|
return(NULL);
|
|
}
|
|
/*
|
|
* Copy the input string to the result, processing '\\' escapes.
|
|
*/
|
|
for (cp = r, l = 0; *s;) {
|
|
switch (*s) {
|
|
|
|
case '\\':
|
|
s++;
|
|
if (*s >= '0' && *s <= '7') {
|
|
/*
|
|
* '\xxx' -- octal form
|
|
*/
|
|
for (c = i = 0; i < 3; i++, s++) {
|
|
if (*s < '0' || *s > '7') {
|
|
em = "non-octal char";
|
|
bad_string:
|
|
(void) fprintf(stderr,
|
|
"%s: %s : %s\n",
|
|
Pname, em, (char *)r);
|
|
return(NULL);
|
|
}
|
|
c = (c << 3) + *s - '0';
|
|
}
|
|
if (c > 0377) {
|
|
em = "octal char > 0377";
|
|
goto bad_string;
|
|
}
|
|
*cp++ = c;
|
|
l++;
|
|
} else if (*s == 'x') {
|
|
/*
|
|
* '\xyy' -- hexadecimal form
|
|
*/
|
|
s++;
|
|
for (c = i = 0; i < 2; i++, s++) {
|
|
#if defined(__STDC__)
|
|
if ( ! isalpha(*s) && ! isdigit(*s))
|
|
#else
|
|
if ( ! isascii(*s) && ! isalpha(*s)
|
|
&& ! isdigit(*s))
|
|
#endif
|
|
{
|
|
non_hex_char:
|
|
em = "non-hex char";
|
|
goto bad_string;
|
|
}
|
|
c = c << 4;
|
|
if (*s >= '0' && *s <= '9')
|
|
c += *s - '0';
|
|
else if ((*s >= 'a' && *s <= 'f')
|
|
|| (*s >= 'A' && *s <= 'F'))
|
|
c += *s + 10 -
|
|
(isupper(*s) ? 'A' : 'a');
|
|
else
|
|
goto non_hex_char;
|
|
}
|
|
*cp++ = (unsigned char)c;
|
|
l++;
|
|
} else if (*s == 'E' || *s == 'e') {
|
|
/*
|
|
* '\E' or '\e' -- ESCape
|
|
*/
|
|
*cp++ = ESC;
|
|
l++;
|
|
s++;
|
|
} else if (*s == '\0') {
|
|
em = "no char after \\";
|
|
goto bad_string;
|
|
} else {
|
|
/*
|
|
* escaped character (for some reason)
|
|
*/
|
|
*cp++ = *s++;
|
|
l++;
|
|
}
|
|
break;
|
|
/*
|
|
* Copy a "normal" character.
|
|
*/
|
|
default:
|
|
*cp++ = *s++;
|
|
l++;
|
|
}
|
|
}
|
|
*cp = '\0';
|
|
*len = l;
|
|
return(r);
|
|
}
|
|
|
|
|
|
/*
|
|
* Convfont(nm, s, fn, fi) - convert a font for a device
|
|
*/
|
|
|
|
static int
|
|
Convfont(nm, s, fn, fi)
|
|
char *nm; /* output device name */
|
|
char *s; /* font definition string */
|
|
char **fn; /* font name address */
|
|
unsigned char **fi; /* initialization string address */
|
|
{
|
|
char *cp; /* temporary character pointer */
|
|
int len; /* length */
|
|
/*
|
|
* Get the font name, allocate space for it and allocate space for
|
|
* a font structure.
|
|
*/
|
|
if ((cp = strchr(s, '=')) == NULL) {
|
|
(void) fprintf(stderr, "%s: bad %s font line format: %s\n",
|
|
Pname, nm, s);
|
|
return(0);
|
|
}
|
|
if ((*fn = (char *)malloc(cp - s + 1)) == NULL) {
|
|
(void) fprintf(stderr, "%s: no space for %s font name %s\n",
|
|
Pname, nm, s);
|
|
return(0);
|
|
}
|
|
(void) strncpy(*fn, s, cp - s);
|
|
(*fn)[cp - s] = '\0';
|
|
/*
|
|
* Assmble the font initialization string.
|
|
*/
|
|
if ((*fi = Convstr(cp + 1, &len)) == NULL)
|
|
return(0);
|
|
return(len);
|
|
}
|
|
|
|
|
|
/*
|
|
* Defdev() - define the output device
|
|
*/
|
|
|
|
int
|
|
Defdev()
|
|
{
|
|
unsigned char *fi = NULL; /* last font initialization string */
|
|
char *fn = NULL; /* font name */
|
|
int fd = 0; /* found-device flag */
|
|
FILE *fs; /* file stream */
|
|
int err = 0; /* errror count */
|
|
int i; /* temporary index */
|
|
int len; /* length */
|
|
char line[MAXLINE]; /* line buffer */
|
|
char *p; /* output device configuration file */
|
|
char *s; /* temporary string pointer */
|
|
/*
|
|
* Check for the built-in devices, ANSI, NONE or NORMAL (default).
|
|
*/
|
|
Fstr.b = Fstr.i = Fstr.it = Fstr.r = NULL;
|
|
Fstr.bl = Fstr.il = Fstr.itl = Fstr.rl = 0;
|
|
if (Device == NULL || strcasecmp(Device, "normal") == 0) {
|
|
Fontctl = 0;
|
|
check_font:
|
|
if (Devfont) {
|
|
(void) fprintf(stderr,
|
|
"%s: font %s for device %s illegal\n",
|
|
Pname, Devfont, Device ? Device : "NORMAL");
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
Fontctl = 1;
|
|
if (strcasecmp(Device, "ansi") == 0) {
|
|
Fstr.b = Newstr((unsigned char *)"x[1m");
|
|
Fstr.it = Newstr((unsigned char *)"x[4m");
|
|
Fstr.r = Newstr((unsigned char *)"x[0m");
|
|
Fstr.b[0] = Fstr.it[0] = Fstr.r[0] = ESC;
|
|
Fstr.bl = Fstr.itl = Fstr.rl = 4;
|
|
goto check_font;
|
|
}
|
|
if (strcasecmp(Device, "none") == 0)
|
|
goto check_font;
|
|
/*
|
|
* If a device configuration file path is supplied, use it.
|
|
*/
|
|
if (Devconf)
|
|
p = Devconf;
|
|
else {
|
|
|
|
/*
|
|
* Use the CAWFLIB environment if it is defined.
|
|
*/
|
|
if ((p = getenv("CAWFLIB")) == NULL)
|
|
p = CAWFLIB;
|
|
len = strlen(p) + 1 + strlen(DEVCONFIG) + 1;
|
|
if ((s = (char *)malloc(len)) == NULL) {
|
|
(void) fprintf(stderr, "%s: no space for %s name\n",
|
|
Pname, DEVCONFIG);
|
|
return(1);
|
|
}
|
|
(void) sprintf(s, "%s/%s", p, DEVCONFIG);
|
|
p = s;
|
|
}
|
|
/*
|
|
* Open the configuration file.
|
|
*/
|
|
#ifdef UNIX
|
|
if ((fs = fopen(p, "r")) == NULL)
|
|
#else
|
|
if ((fs = fopen(p, "rt")) == NULL)
|
|
#endif
|
|
{
|
|
(void) fprintf(stderr, "%s: can't open config file: %s\n",
|
|
Pname, p);
|
|
return(1);
|
|
}
|
|
*line = ' ';
|
|
/*
|
|
* Look for a device definition line -- a line that begins with a name.
|
|
*/
|
|
while ( ! feof(fs)) {
|
|
if (*line == '\t' || *line == '#' || *line == ' ') {
|
|
(void) fgets(line, MAXLINE, fs);
|
|
continue;
|
|
}
|
|
if ((s = strrchr(line, '\n')) != NULL)
|
|
*s = '\0';
|
|
else
|
|
line[MAXLINE-1] = '\0';
|
|
/*
|
|
* Match device name.
|
|
*/
|
|
if (strcmp(Device, line) != 0) {
|
|
(void) fgets(line, MAXLINE, fs);
|
|
continue;
|
|
}
|
|
fd = 1;
|
|
/*
|
|
* Read the parameter lines for the device.
|
|
*/
|
|
while (fgets(line, MAXLINE, fs) != NULL) {
|
|
if (*line == ' ') {
|
|
for (i = 1; line[i] == ' '; i++)
|
|
;
|
|
} else if (*line == '\t')
|
|
i = 1;
|
|
else
|
|
break;
|
|
#if defined(__STDC__)
|
|
if ( ! isalpha(line[i])
|
|
#else
|
|
if ( ! isascii(line[i]) || ! isalpha(line[i])
|
|
#endif
|
|
|| line[i+1] != '=')
|
|
break;
|
|
if ((s = strrchr(line, '\n')) != NULL)
|
|
*s = '\0';
|
|
else
|
|
line[MAXLINE-1] = '\0';
|
|
switch (line[i]) {
|
|
/*
|
|
* \tb=<bolding_string>
|
|
*/
|
|
case 'b':
|
|
if (Fstr.b != NULL) {
|
|
(void) fprintf(stderr,
|
|
"%s: dup bold for %s in %s: %s\n",
|
|
Pname, Device, p, line);
|
|
(void) free(Fstr.b);
|
|
Fstr.b = NULL;
|
|
}
|
|
if ((Fstr.b = Convstr(&line[i+2], &Fstr.bl))
|
|
== NULL)
|
|
err++;
|
|
break;
|
|
/*
|
|
* \ti=<italicization_string>
|
|
*/
|
|
case 'i':
|
|
if (Fstr.it != NULL) {
|
|
(void) fprintf(stderr,
|
|
"%s: dup italic for %s in %s: %s\n",
|
|
Pname, Device, p, line);
|
|
(void) free(Fstr.it);
|
|
Fstr.it = NULL;
|
|
}
|
|
if ((Fstr.it = Convstr(&line[i+2], &Fstr.itl))
|
|
== NULL)
|
|
err++;
|
|
break;
|
|
/*
|
|
* \tr=<return_to_Roman_string>
|
|
*/
|
|
case 'r':
|
|
if (Fstr.r != NULL) {
|
|
(void) fprintf(stderr,
|
|
"%s: dup roman for %s in %s: %s\n",
|
|
Pname, Device, p, line);
|
|
(void) free(Fstr.r);
|
|
Fstr.r = NULL;
|
|
}
|
|
if ((Fstr.r = Convstr(&line[i+2], &Fstr.rl))
|
|
== NULL)
|
|
err++;
|
|
break;
|
|
/*
|
|
* \tf=<font_name>=<font_initialization_string>
|
|
*/
|
|
case 'f':
|
|
if ( ! Devfont || Fstr.i)
|
|
break;
|
|
if ((i = Convfont(Device, &line[i+2], &fn, &fi))
|
|
< 0)
|
|
err++;
|
|
else if (fn && strcmp(Devfont, fn) == 0) {
|
|
Fstr.i = fi;
|
|
Fstr.il = i;
|
|
fi = NULL;
|
|
}
|
|
if (fn) {
|
|
(void) free(fn);
|
|
fn = NULL;
|
|
}
|
|
if (fi) {
|
|
(void) free((char *)fi);
|
|
fi = NULL;
|
|
}
|
|
break;
|
|
/*
|
|
* ????
|
|
*/
|
|
default:
|
|
(void) fprintf(stderr,
|
|
"%s: unknown device %s line: %s\n",
|
|
Pname, Device, line);
|
|
err++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
(void) fclose(fs);
|
|
if (err)
|
|
return(1);
|
|
/*
|
|
* See if the device stanza was located and the font exists.
|
|
*/
|
|
if ( ! fd) {
|
|
(void) fprintf(stderr, "%s: can't find device %s in %s\n",
|
|
Pname, Device, p);
|
|
return(1);
|
|
}
|
|
if (Devfont && ! Fstr.i) {
|
|
(void) fprintf(stderr,
|
|
"%s: font %s for device %s not found in %s\n",
|
|
Pname, Devfont, Device, p);
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|