[9] | 1 | /*
|
---|
| 2 | * device.c -- cawf(1) output device support functions
|
---|
| 3 | */
|
---|
| 4 |
|
---|
| 5 | /*
|
---|
| 6 | * Copyright (c) 1991 Purdue University Research Foundation,
|
---|
| 7 | * West Lafayette, Indiana 47907. All rights reserved.
|
---|
| 8 | *
|
---|
| 9 | * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
|
---|
| 10 | * University Computing Center. Not derived from licensed software;
|
---|
| 11 | * derived from awf(1) by Henry Spencer of the University of Toronto.
|
---|
| 12 | *
|
---|
| 13 | * Permission is granted to anyone to use this software for any
|
---|
| 14 | * purpose on any computer system, and to alter it and redistribute
|
---|
| 15 | * it freely, subject to the following restrictions:
|
---|
| 16 | *
|
---|
| 17 | * 1. The author is not responsible for any consequences of use of
|
---|
| 18 | * this software, even if they arise from flaws in it.
|
---|
| 19 | *
|
---|
| 20 | * 2. The origin of this software must not be misrepresented, either
|
---|
| 21 | * by explicit claim or by omission. Credits must appear in the
|
---|
| 22 | * documentation.
|
---|
| 23 | *
|
---|
| 24 | * 3. Altered versions must be plainly marked as such, and must not
|
---|
| 25 | * be misrepresented as being the original software. Credits must
|
---|
| 26 | * appear in the documentation.
|
---|
| 27 | *
|
---|
| 28 | * 4. This notice may not be removed or altered.
|
---|
| 29 | */
|
---|
| 30 |
|
---|
| 31 | #include "cawf.h"
|
---|
| 32 | #include <ctype.h>
|
---|
| 33 |
|
---|
| 34 | _PROTOTYPE(static unsigned char *Convstr,(char *s, int *len));
|
---|
| 35 | _PROTOTYPE(static int Convfont,(char *nm, char *s, char **fn,
|
---|
| 36 | unsigned char **fi));
|
---|
| 37 |
|
---|
| 38 | #ifndef UNIX
|
---|
| 39 | #define strcasecmp strcmpi
|
---|
| 40 | #endif
|
---|
| 41 |
|
---|
| 42 |
|
---|
| 43 |
|
---|
| 44 | /*
|
---|
| 45 | * Convstr(s, len) - convert a string
|
---|
| 46 | */
|
---|
| 47 |
|
---|
| 48 | static unsigned char *
|
---|
| 49 | Convstr(s, len)
|
---|
| 50 | char *s; /* input string */
|
---|
| 51 | int *len; /* length of result */
|
---|
| 52 | {
|
---|
| 53 | int c; /* character assembly */
|
---|
| 54 | unsigned char *cp; /* temporary character pointer */
|
---|
| 55 | char *em; /* error message */
|
---|
| 56 | int i; /* temporary index */
|
---|
| 57 | int l; /* length */
|
---|
| 58 | unsigned char *r; /* result string */
|
---|
| 59 | /*
|
---|
| 60 | * Make space for the result.
|
---|
| 61 | */
|
---|
| 62 | if ((r = (unsigned char *)malloc(strlen((char *)s) + 1)) == NULL) {
|
---|
| 63 | (void) fprintf(stderr, "%s: out of string space at %s\n",
|
---|
| 64 | Pname, s);
|
---|
| 65 | return(NULL);
|
---|
| 66 | }
|
---|
| 67 | /*
|
---|
| 68 | * Copy the input string to the result, processing '\\' escapes.
|
---|
| 69 | */
|
---|
| 70 | for (cp = r, l = 0; *s;) {
|
---|
| 71 | switch (*s) {
|
---|
| 72 |
|
---|
| 73 | case '\\':
|
---|
| 74 | s++;
|
---|
| 75 | if (*s >= '0' && *s <= '7') {
|
---|
| 76 | /*
|
---|
| 77 | * '\xxx' -- octal form
|
---|
| 78 | */
|
---|
| 79 | for (c = i = 0; i < 3; i++, s++) {
|
---|
| 80 | if (*s < '0' || *s > '7') {
|
---|
| 81 | em = "non-octal char";
|
---|
| 82 | bad_string:
|
---|
| 83 | (void) fprintf(stderr,
|
---|
| 84 | "%s: %s : %s\n",
|
---|
| 85 | Pname, em, (char *)r);
|
---|
| 86 | return(NULL);
|
---|
| 87 | }
|
---|
| 88 | c = (c << 3) + *s - '0';
|
---|
| 89 | }
|
---|
| 90 | if (c > 0377) {
|
---|
| 91 | em = "octal char > 0377";
|
---|
| 92 | goto bad_string;
|
---|
| 93 | }
|
---|
| 94 | *cp++ = c;
|
---|
| 95 | l++;
|
---|
| 96 | } else if (*s == 'x') {
|
---|
| 97 | /*
|
---|
| 98 | * '\xyy' -- hexadecimal form
|
---|
| 99 | */
|
---|
| 100 | s++;
|
---|
| 101 | for (c = i = 0; i < 2; i++, s++) {
|
---|
| 102 | #if defined(__STDC__)
|
---|
| 103 | if ( ! isalpha(*s) && ! isdigit(*s))
|
---|
| 104 | #else
|
---|
| 105 | if ( ! isascii(*s) && ! isalpha(*s)
|
---|
| 106 | && ! isdigit(*s))
|
---|
| 107 | #endif
|
---|
| 108 | {
|
---|
| 109 | non_hex_char:
|
---|
| 110 | em = "non-hex char";
|
---|
| 111 | goto bad_string;
|
---|
| 112 | }
|
---|
| 113 | c = c << 4;
|
---|
| 114 | if (*s >= '0' && *s <= '9')
|
---|
| 115 | c += *s - '0';
|
---|
| 116 | else if ((*s >= 'a' && *s <= 'f')
|
---|
| 117 | || (*s >= 'A' && *s <= 'F'))
|
---|
| 118 | c += *s + 10 -
|
---|
| 119 | (isupper(*s) ? 'A' : 'a');
|
---|
| 120 | else
|
---|
| 121 | goto non_hex_char;
|
---|
| 122 | }
|
---|
| 123 | *cp++ = (unsigned char)c;
|
---|
| 124 | l++;
|
---|
| 125 | } else if (*s == 'E' || *s == 'e') {
|
---|
| 126 | /*
|
---|
| 127 | * '\E' or '\e' -- ESCape
|
---|
| 128 | */
|
---|
| 129 | *cp++ = ESC;
|
---|
| 130 | l++;
|
---|
| 131 | s++;
|
---|
| 132 | } else if (*s == '\0') {
|
---|
| 133 | em = "no char after \\";
|
---|
| 134 | goto bad_string;
|
---|
| 135 | } else {
|
---|
| 136 | /*
|
---|
| 137 | * escaped character (for some reason)
|
---|
| 138 | */
|
---|
| 139 | *cp++ = *s++;
|
---|
| 140 | l++;
|
---|
| 141 | }
|
---|
| 142 | break;
|
---|
| 143 | /*
|
---|
| 144 | * Copy a "normal" character.
|
---|
| 145 | */
|
---|
| 146 | default:
|
---|
| 147 | *cp++ = *s++;
|
---|
| 148 | l++;
|
---|
| 149 | }
|
---|
| 150 | }
|
---|
| 151 | *cp = '\0';
|
---|
| 152 | *len = l;
|
---|
| 153 | return(r);
|
---|
| 154 | }
|
---|
| 155 |
|
---|
| 156 |
|
---|
| 157 | /*
|
---|
| 158 | * Convfont(nm, s, fn, fi) - convert a font for a device
|
---|
| 159 | */
|
---|
| 160 |
|
---|
| 161 | static int
|
---|
| 162 | Convfont(nm, s, fn, fi)
|
---|
| 163 | char *nm; /* output device name */
|
---|
| 164 | char *s; /* font definition string */
|
---|
| 165 | char **fn; /* font name address */
|
---|
| 166 | unsigned char **fi; /* initialization string address */
|
---|
| 167 | {
|
---|
| 168 | char *cp; /* temporary character pointer */
|
---|
| 169 | int len; /* length */
|
---|
| 170 | /*
|
---|
| 171 | * Get the font name, allocate space for it and allocate space for
|
---|
| 172 | * a font structure.
|
---|
| 173 | */
|
---|
| 174 | if ((cp = strchr(s, '=')) == NULL) {
|
---|
| 175 | (void) fprintf(stderr, "%s: bad %s font line format: %s\n",
|
---|
| 176 | Pname, nm, s);
|
---|
| 177 | return(0);
|
---|
| 178 | }
|
---|
| 179 | if ((*fn = (char *)malloc(cp - s + 1)) == NULL) {
|
---|
| 180 | (void) fprintf(stderr, "%s: no space for %s font name %s\n",
|
---|
| 181 | Pname, nm, s);
|
---|
| 182 | return(0);
|
---|
| 183 | }
|
---|
| 184 | (void) strncpy(*fn, s, cp - s);
|
---|
| 185 | (*fn)[cp - s] = '\0';
|
---|
| 186 | /*
|
---|
| 187 | * Assmble the font initialization string.
|
---|
| 188 | */
|
---|
| 189 | if ((*fi = Convstr(cp + 1, &len)) == NULL)
|
---|
| 190 | return(0);
|
---|
| 191 | return(len);
|
---|
| 192 | }
|
---|
| 193 |
|
---|
| 194 |
|
---|
| 195 | /*
|
---|
| 196 | * Defdev() - define the output device
|
---|
| 197 | */
|
---|
| 198 |
|
---|
| 199 | int
|
---|
| 200 | Defdev()
|
---|
| 201 | {
|
---|
| 202 | unsigned char *fi = NULL; /* last font initialization string */
|
---|
| 203 | char *fn = NULL; /* font name */
|
---|
| 204 | int fd = 0; /* found-device flag */
|
---|
| 205 | FILE *fs; /* file stream */
|
---|
| 206 | int err = 0; /* errror count */
|
---|
| 207 | int i; /* temporary index */
|
---|
| 208 | int len; /* length */
|
---|
| 209 | char line[MAXLINE]; /* line buffer */
|
---|
| 210 | char *p; /* output device configuration file */
|
---|
| 211 | char *s; /* temporary string pointer */
|
---|
| 212 | /*
|
---|
| 213 | * Check for the built-in devices, ANSI, NONE or NORMAL (default).
|
---|
| 214 | */
|
---|
| 215 | Fstr.b = Fstr.i = Fstr.it = Fstr.r = NULL;
|
---|
| 216 | Fstr.bl = Fstr.il = Fstr.itl = Fstr.rl = 0;
|
---|
| 217 | if (Device == NULL || strcasecmp(Device, "normal") == 0) {
|
---|
| 218 | Fontctl = 0;
|
---|
| 219 | check_font:
|
---|
| 220 | if (Devfont) {
|
---|
| 221 | (void) fprintf(stderr,
|
---|
| 222 | "%s: font %s for device %s illegal\n",
|
---|
| 223 | Pname, Devfont, Device ? Device : "NORMAL");
|
---|
| 224 | return(1);
|
---|
| 225 | }
|
---|
| 226 | return(0);
|
---|
| 227 | }
|
---|
| 228 | Fontctl = 1;
|
---|
| 229 | if (strcasecmp(Device, "ansi") == 0) {
|
---|
| 230 | Fstr.b = Newstr((unsigned char *)"x[1m");
|
---|
| 231 | Fstr.it = Newstr((unsigned char *)"x[4m");
|
---|
| 232 | Fstr.r = Newstr((unsigned char *)"x[0m");
|
---|
| 233 | Fstr.b[0] = Fstr.it[0] = Fstr.r[0] = ESC;
|
---|
| 234 | Fstr.bl = Fstr.itl = Fstr.rl = 4;
|
---|
| 235 | goto check_font;
|
---|
| 236 | }
|
---|
| 237 | if (strcasecmp(Device, "none") == 0)
|
---|
| 238 | goto check_font;
|
---|
| 239 | /*
|
---|
| 240 | * If a device configuration file path is supplied, use it.
|
---|
| 241 | */
|
---|
| 242 | if (Devconf)
|
---|
| 243 | p = Devconf;
|
---|
| 244 | else {
|
---|
| 245 |
|
---|
| 246 | /*
|
---|
| 247 | * Use the CAWFLIB environment if it is defined.
|
---|
| 248 | */
|
---|
| 249 | if ((p = getenv("CAWFLIB")) == NULL)
|
---|
| 250 | p = CAWFLIB;
|
---|
| 251 | len = strlen(p) + 1 + strlen(DEVCONFIG) + 1;
|
---|
| 252 | if ((s = (char *)malloc(len)) == NULL) {
|
---|
| 253 | (void) fprintf(stderr, "%s: no space for %s name\n",
|
---|
| 254 | Pname, DEVCONFIG);
|
---|
| 255 | return(1);
|
---|
| 256 | }
|
---|
| 257 | (void) sprintf(s, "%s/%s", p, DEVCONFIG);
|
---|
| 258 | p = s;
|
---|
| 259 | }
|
---|
| 260 | /*
|
---|
| 261 | * Open the configuration file.
|
---|
| 262 | */
|
---|
| 263 | #ifdef UNIX
|
---|
| 264 | if ((fs = fopen(p, "r")) == NULL)
|
---|
| 265 | #else
|
---|
| 266 | if ((fs = fopen(p, "rt")) == NULL)
|
---|
| 267 | #endif
|
---|
| 268 | {
|
---|
| 269 | (void) fprintf(stderr, "%s: can't open config file: %s\n",
|
---|
| 270 | Pname, p);
|
---|
| 271 | return(1);
|
---|
| 272 | }
|
---|
| 273 | *line = ' ';
|
---|
| 274 | /*
|
---|
| 275 | * Look for a device definition line -- a line that begins with a name.
|
---|
| 276 | */
|
---|
| 277 | while ( ! feof(fs)) {
|
---|
| 278 | if (*line == '\t' || *line == '#' || *line == ' ') {
|
---|
| 279 | (void) fgets(line, MAXLINE, fs);
|
---|
| 280 | continue;
|
---|
| 281 | }
|
---|
| 282 | if ((s = strrchr(line, '\n')) != NULL)
|
---|
| 283 | *s = '\0';
|
---|
| 284 | else
|
---|
| 285 | line[MAXLINE-1] = '\0';
|
---|
| 286 | /*
|
---|
| 287 | * Match device name.
|
---|
| 288 | */
|
---|
| 289 | if (strcmp(Device, line) != 0) {
|
---|
| 290 | (void) fgets(line, MAXLINE, fs);
|
---|
| 291 | continue;
|
---|
| 292 | }
|
---|
| 293 | fd = 1;
|
---|
| 294 | /*
|
---|
| 295 | * Read the parameter lines for the device.
|
---|
| 296 | */
|
---|
| 297 | while (fgets(line, MAXLINE, fs) != NULL) {
|
---|
| 298 | if (*line == ' ') {
|
---|
| 299 | for (i = 1; line[i] == ' '; i++)
|
---|
| 300 | ;
|
---|
| 301 | } else if (*line == '\t')
|
---|
| 302 | i = 1;
|
---|
| 303 | else
|
---|
| 304 | break;
|
---|
| 305 | #if defined(__STDC__)
|
---|
| 306 | if ( ! isalpha(line[i])
|
---|
| 307 | #else
|
---|
| 308 | if ( ! isascii(line[i]) || ! isalpha(line[i])
|
---|
| 309 | #endif
|
---|
| 310 | || line[i+1] != '=')
|
---|
| 311 | break;
|
---|
| 312 | if ((s = strrchr(line, '\n')) != NULL)
|
---|
| 313 | *s = '\0';
|
---|
| 314 | else
|
---|
| 315 | line[MAXLINE-1] = '\0';
|
---|
| 316 | switch (line[i]) {
|
---|
| 317 | /*
|
---|
| 318 | * \tb=<bolding_string>
|
---|
| 319 | */
|
---|
| 320 | case 'b':
|
---|
| 321 | if (Fstr.b != NULL) {
|
---|
| 322 | (void) fprintf(stderr,
|
---|
| 323 | "%s: dup bold for %s in %s: %s\n",
|
---|
| 324 | Pname, Device, p, line);
|
---|
| 325 | (void) free(Fstr.b);
|
---|
| 326 | Fstr.b = NULL;
|
---|
| 327 | }
|
---|
| 328 | if ((Fstr.b = Convstr(&line[i+2], &Fstr.bl))
|
---|
| 329 | == NULL)
|
---|
| 330 | err++;
|
---|
| 331 | break;
|
---|
| 332 | /*
|
---|
| 333 | * \ti=<italicization_string>
|
---|
| 334 | */
|
---|
| 335 | case 'i':
|
---|
| 336 | if (Fstr.it != NULL) {
|
---|
| 337 | (void) fprintf(stderr,
|
---|
| 338 | "%s: dup italic for %s in %s: %s\n",
|
---|
| 339 | Pname, Device, p, line);
|
---|
| 340 | (void) free(Fstr.it);
|
---|
| 341 | Fstr.it = NULL;
|
---|
| 342 | }
|
---|
| 343 | if ((Fstr.it = Convstr(&line[i+2], &Fstr.itl))
|
---|
| 344 | == NULL)
|
---|
| 345 | err++;
|
---|
| 346 | break;
|
---|
| 347 | /*
|
---|
| 348 | * \tr=<return_to_Roman_string>
|
---|
| 349 | */
|
---|
| 350 | case 'r':
|
---|
| 351 | if (Fstr.r != NULL) {
|
---|
| 352 | (void) fprintf(stderr,
|
---|
| 353 | "%s: dup roman for %s in %s: %s\n",
|
---|
| 354 | Pname, Device, p, line);
|
---|
| 355 | (void) free(Fstr.r);
|
---|
| 356 | Fstr.r = NULL;
|
---|
| 357 | }
|
---|
| 358 | if ((Fstr.r = Convstr(&line[i+2], &Fstr.rl))
|
---|
| 359 | == NULL)
|
---|
| 360 | err++;
|
---|
| 361 | break;
|
---|
| 362 | /*
|
---|
| 363 | * \tf=<font_name>=<font_initialization_string>
|
---|
| 364 | */
|
---|
| 365 | case 'f':
|
---|
| 366 | if ( ! Devfont || Fstr.i)
|
---|
| 367 | break;
|
---|
| 368 | if ((i = Convfont(Device, &line[i+2], &fn, &fi))
|
---|
| 369 | < 0)
|
---|
| 370 | err++;
|
---|
| 371 | else if (fn && strcmp(Devfont, fn) == 0) {
|
---|
| 372 | Fstr.i = fi;
|
---|
| 373 | Fstr.il = i;
|
---|
| 374 | fi = NULL;
|
---|
| 375 | }
|
---|
| 376 | if (fn) {
|
---|
| 377 | (void) free(fn);
|
---|
| 378 | fn = NULL;
|
---|
| 379 | }
|
---|
| 380 | if (fi) {
|
---|
| 381 | (void) free((char *)fi);
|
---|
| 382 | fi = NULL;
|
---|
| 383 | }
|
---|
| 384 | break;
|
---|
| 385 | /*
|
---|
| 386 | * ????
|
---|
| 387 | */
|
---|
| 388 | default:
|
---|
| 389 | (void) fprintf(stderr,
|
---|
| 390 | "%s: unknown device %s line: %s\n",
|
---|
| 391 | Pname, Device, line);
|
---|
| 392 | err++;
|
---|
| 393 | }
|
---|
| 394 | }
|
---|
| 395 | break;
|
---|
| 396 | }
|
---|
| 397 | (void) fclose(fs);
|
---|
| 398 | if (err)
|
---|
| 399 | return(1);
|
---|
| 400 | /*
|
---|
| 401 | * See if the device stanza was located and the font exists.
|
---|
| 402 | */
|
---|
| 403 | if ( ! fd) {
|
---|
| 404 | (void) fprintf(stderr, "%s: can't find device %s in %s\n",
|
---|
| 405 | Pname, Device, p);
|
---|
| 406 | return(1);
|
---|
| 407 | }
|
---|
| 408 | if (Devfont && ! Fstr.i) {
|
---|
| 409 | (void) fprintf(stderr,
|
---|
| 410 | "%s: font %s for device %s not found in %s\n",
|
---|
| 411 | Pname, Devfont, Device, p);
|
---|
| 412 | return(1);
|
---|
| 413 | }
|
---|
| 414 | return(0);
|
---|
| 415 | }
|
---|