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