1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */ 34 35 #include "stdio.h" 36 #include "string.h" 37 #include "errno.h" 38 #include "stdlib.h" 39 #include "unistd.h" 40 41 #include "lp.h" 42 #include "filters.h" 43 44 _FILTER *filters; 45 46 size_t nfilters; 47 48 static int getfields (int, char *[], char *, int, int, char *); 49 static int fs_cmp(const void *, const void *); 50 51 /** 52 ** loadfilters() - READ FILTERS FROM FILTER TABLE INTO INTERNAL STRUCTURE 53 **/ 54 55 int 56 loadfilters(char *file) 57 { 58 register _FILTER *pf; 59 int fd; 60 char *filt[FL_MAX], 61 buf[3 * BUFSIZ]; 62 size_t nalloc; 63 64 if (filters) { 65 nalloc = nfilters; 66 trash_filters (); 67 } else 68 nalloc = FL_MAX_GUESS; 69 70 if ((fd = open_filtertable(file, "r")) < 0) 71 return (-1); 72 73 /* 74 * Preallocate space for the internal filter table. 75 * Our guess is the number of filters previously read in, 76 * if any have been read in before (see above). 77 */ 78 filters = (_FILTER *)Malloc((nalloc + 1) * sizeof(_FILTER)); 79 if (!filters) { 80 close(fd); 81 errno = ENOMEM; 82 return (-1); 83 } 84 85 for ( 86 pf = filters, nfilters = 0; 87 getfields(fd, filt, buf, sizeof(buf), FL_MAX, FL_SEP) != -1; 88 pf++ 89 ) { 90 91 char **list; 92 93 /* 94 * Allocate more space if needed. 95 */ 96 if (++nfilters > nalloc) { 97 nalloc = nfilters; 98 filters = (_FILTER *)Realloc( 99 filters, 100 (nalloc + 1) * sizeof(_FILTER) 101 ); 102 if (!filters) { 103 close(fd); 104 errno = ENOMEM; 105 return (-1); 106 } 107 pf = &filters[nfilters - 1]; 108 } 109 110 #define DFLT(X) (filt[X] && *filt[X]? filt[X] : NAME_ANY) 111 112 pf->name = Strdup(filt[FL_NAME]); 113 pf->type = s_to_filtertype(filt[FL_TYPE]); 114 pf->command = Strdup(filt[FL_CMD]); 115 116 pf->printers = getlist(DFLT(FL_PRTRS), LP_WS, LP_SEP); 117 118 list = getlist(DFLT(FL_PTYPS), LP_WS, LP_SEP); 119 pf->printer_types = sl_to_typel(list); 120 freelist (list); 121 122 list = getlist(DFLT(FL_ITYPS), LP_WS, LP_SEP); 123 pf->input_types = sl_to_typel(list); 124 freelist (list); 125 126 list = getlist(DFLT(FL_OTYPS), LP_WS, LP_SEP); 127 pf->output_types = sl_to_typel(list); 128 freelist (list); 129 130 /* 131 * Note the use of "" instead of LP_WS. The 132 * "sl_to_templatel()" routine will take care 133 * of stripping leading blanks. Stripping trailing 134 * blanks would be nice but shouldn't matter. 135 */ 136 137 /* quote reason #3 (in "getlist()") */ 138 list = getlist(filt[FL_TMPS], "", LP_SEP); 139 140 /* quote reason #4 (in "s_to_template()") */ 141 pf->templates = sl_to_templatel(list); 142 freelist (list); 143 144 } 145 if (errno != 0) { 146 int save_errno = errno; 147 148 free_filter (pf); 149 close(fd); 150 errno = save_errno; 151 return (-1); 152 } 153 close(fd); 154 155 /* 156 * If we have more space allocated than we need, 157 * return the extra. 158 */ 159 if (nfilters != nalloc) { 160 filters = (_FILTER *)Realloc( 161 filters, 162 (nfilters + 1) * sizeof(_FILTER) 163 ); 164 if (!filters) { 165 errno = ENOMEM; 166 return (-1); 167 } 168 } 169 filters[nfilters].name = 0; 170 171 /* 172 * Sort the filters, putting ``fast'' filters before 173 * ``slow'' filters. This preps the list for "insfilter()" 174 * so that it can easily pick fast filters over otherwise 175 * equivalent slow filters. This sorting is done every 176 * time we read in the table; one might think that if 177 * "putfilter()" would insert in the correct order then 178 * the table, when written out to disk, would be sorted 179 * already--removing the need to sort it here. We don't 180 * take that approach, because (1) sorting it isn't that 181 * expensive and (2) someone might tamper with the table 182 * file. 183 */ 184 qsort ((char *)filters, nfilters, sizeof(_FILTER), fs_cmp); 185 186 return (0); 187 } 188 189 /** 190 ** getfields() - PARSE NON-COMMENT LINE FROM FILE INTO FIELDS 191 **/ 192 193 static int 194 getfields(int fd, char *fields[], char *buf, int bufsiz, int max, char *seps) 195 { 196 register char *p, 197 *q; 198 199 register int n = 0; 200 enum ParsingMode {CHECK_LEAD_DBL_QUOTE, NORMAL_PARSING, LITERAL_READ} eMode; 201 errno = 0; 202 while (fdgets(buf, bufsiz, fd) != NULL) { 203 buf[strlen(buf) - 1] = 0; 204 p = buf + strspn(buf, " \t"); 205 if (*p && *p != '#') { 206 for (eMode = CHECK_LEAD_DBL_QUOTE, fields[n++] = q = p; *p; ) { 207 switch (eMode) { 208 case CHECK_LEAD_DBL_QUOTE: /* check for leading double quote */ 209 if (*p == '"') { 210 eMode = LITERAL_READ; 211 p++; 212 break; 213 } 214 eMode = NORMAL_PARSING; 215 /* drop through to NORMAL_PARSING case */ 216 217 case NORMAL_PARSING: /* default legacy editing */ 218 if (*p == '\\') { 219 if ( 220 /* quote reason #1 */ p[1] == '\\' 221 /* quote reason #2 */ || strchr(seps, p[1]) 222 ) 223 p++; 224 *q++ = *p++; 225 } else if (strchr(seps, *p)) { 226 *q++ = 0; 227 p++; 228 if (n < max) { 229 fields[n++] = q; 230 eMode = CHECK_LEAD_DBL_QUOTE; 231 } 232 } else 233 *q++ = *p++; 234 break; 235 236 case LITERAL_READ: /* read literally until another double quote */ 237 if (*p == '\\' && p[1] == '"') { /* embedded double quote */ 238 p++; 239 *q++ = *p++; 240 } else if (*p == '"') { /* end of literal read */ 241 p++; 242 eMode = NORMAL_PARSING; 243 } else { 244 *q++ = *p++; /* capture as is */ 245 } 246 break; 247 } 248 } 249 *q = 0; 250 while (n < max) 251 fields[n++] = ""; 252 return (n); 253 } 254 } 255 return (-1); 256 } 257 258 /** 259 ** fs_cmp() - COMPARE TWO FILTERS BY "FILTERTYPE" 260 **/ 261 262 static int 263 fs_cmp(const void *pfa, const void *pfb) 264 { 265 if (((_FILTER *)pfa)->type == ((_FILTER *)pfb)->type) 266 return (0); 267 else if (((_FILTER *)pfa)->type == fl_fast) 268 return (-1); 269 else 270 return (1); 271 } 272