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