make_driver_db_cups.cpp
00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (c) 2001 Michael Goffioul <kdeprint@swing.be> 00004 * Copyright (c) 2014 Timothy Pearson <kb9vqf@pearsoncomputing.net> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License version 2 as published by the Free Software Foundation. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 **/ 00020 00021 #include <config.h> 00022 #ifndef _GNU_SOURCE 00023 #define _GNU_SOURCE /* Needed for getline */ 00024 #endif 00025 #include <stdio.h> 00026 #include <stdlib.h> 00027 #include <string.h> 00028 #include <sys/types.h> 00029 #include <sys/stat.h> 00030 #include <dirent.h> 00031 #include <unistd.h> 00032 #include <ctype.h> 00033 #include <zlib.h> 00034 00035 #include <tqstringlist.h> 00036 #include <tqlocale.h> 00037 00038 extern "C" { 00039 #include "driverparse.h" 00040 } 00041 00042 #define PROCESS_PPD_FILE_CONTENTS \ 00043 memset(value,0,256); \ 00044 c1 = strchr(line,':'); \ 00045 if (c1) \ 00046 { \ 00047 c2 = strchr(c1,'"'); \ 00048 if (c2) \ 00049 { \ 00050 c2++; \ 00051 c1 = strchr(c2,'"'); \ 00052 if (c1) strlcpy(value,c2,c1-c2+1); \ 00053 } \ 00054 else \ 00055 { \ 00056 c1++; \ 00057 while (*c1 && isspace(*c1)) \ 00058 c1++; \ 00059 if (!*c1) \ 00060 continue; \ 00061 c2 = line+strlen(line)-1; /* point to \n */ \ 00062 while (*c2 && isspace(*c2)) \ 00063 c2--; \ 00064 strlcpy(value,c1,c2-c1+2); \ 00065 } \ 00066 } \ 00067 count++; \ 00068 if (strncmp(line,"*Manufacturer:",14) == 0) fprintf(output_file,"MANUFACTURER=%s\n",value); \ 00069 else if (strncmp(line,"*ShortNickName:",15) == 0) fprintf(output_file,"MODEL=%s\n",value); \ 00070 else if (strncmp(line,"*ModelName:",11) == 0) fprintf(output_file,"MODELNAME=%s\n",value); \ 00071 else if (strncmp(line,"*NickName:",10) == 0) strncat(desc,value,255-strlen(desc)); \ 00072 else if (strncmp(line,"*pnpManufacturer:",17) == 0) fprintf(output_file,"PNPMANUFACTURER=%s\n",value); \ 00073 else if (strncmp(line,"*pnpModel:",10) == 0) fprintf(output_file,"PNPMODEL=%s\n",value); \ 00074 else if (strncmp(line,"*LanguageVersion:",17) == 0) strncat(langver,value,63-strlen(langver)); \ 00075 else count--; \ 00076 /* Either we got everything we needed, or we encountered an "OpenUI" directive \ 00077 * and it's reasonable to assume that there's no needed info further in the file, \ 00078 * just stop here */ \ 00079 if (count >= 7 || strncmp(line, "*OpenUI", 7) == 0) \ 00080 { \ 00081 if (strlen(langver) > 0) \ 00082 { \ 00083 strncat(desc, " [", 255-strlen(desc)); \ 00084 strncat(desc, langver, 255-strlen(desc)); \ 00085 strncat(desc, "]", 255-strlen(desc)); \ 00086 } \ 00087 if (strlen(desc) > 0) \ 00088 fprintf(output_file, "DESCRIPTION=%s\n", desc); \ 00089 break; \ 00090 } 00091 00092 void initPpd(const char *dirname) 00093 { 00094 struct stat stat_res; 00095 if (stat(dirname, &stat_res) == -1) { 00096 fprintf(stderr, "Can't open drivers directory : %s\n", dirname); 00097 return; 00098 } 00099 00100 if (S_ISDIR(stat_res.st_mode)) { 00101 DIR *dir = opendir(dirname); 00102 struct dirent *entry; 00103 char buffer[4096] = {0}; 00104 char drFile[256]; 00105 int len = strlen(dirname); 00106 00107 if (dir == NULL) 00108 { 00109 fprintf(stderr, "Can't open drivers directory : %s\n", dirname); 00110 return; 00111 } 00112 while ((entry=readdir(dir)) != NULL) 00113 { 00114 if (strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0) 00115 { 00116 continue; 00117 } 00118 if (len+strlen(entry->d_name)+1 < 4096) 00119 { 00120 struct stat st; 00121 00122 strcpy(buffer,dirname); 00123 strcat(buffer,"/"); 00124 strcat(buffer,entry->d_name); 00125 if (stat(buffer,&st) == 0) 00126 { 00127 if (S_ISDIR(st.st_mode)) 00128 { 00129 initPpd(buffer); 00130 } 00131 else if (S_ISREG(st.st_mode)) 00132 { 00133 char *c = strrchr(buffer,'.'); 00134 snprintf(drFile, 255, "ppd:%s", buffer); 00135 if (c && strncmp(c,".ppd",4) == 0) 00136 { 00137 addFile(drFile, "", ""); 00138 } 00139 else if (c && strncmp(c, ".gz", 3) == 0) 00140 { /* keep also compressed driver files */ 00141 while (c != buffer) 00142 { 00143 if (*(--c) == '.') break; 00144 } 00145 if (*c == '.' && strncmp(c, ".ppd",4) == 0) 00146 { 00147 addFile(drFile, "", ""); 00148 } 00149 } 00150 } 00151 } 00152 } 00153 } 00154 closedir(dir); 00155 } 00156 else if (access(dirname, X_OK) != -1) { 00157 char *filename; 00158 int n = strlen(dirname)+strlen(" list"); 00159 filename = (char*)malloc(n*sizeof(char)+1); 00160 memset(filename,0,n); 00161 strcat(filename, dirname); 00162 strcat(filename, " list"); 00163 00164 FILE* file = popen(filename, "r"); 00165 if (file) { 00166 char * line = NULL; 00167 size_t len = 0; 00168 ssize_t read; 00169 while ((read = getline(&line, &len, file)) != -1) { 00170 char * pos1 = strstr(line, "\""); 00171 if (pos1 != NULL) { 00172 char * pos2 = strstr(pos1 + 1, "\""); 00173 if (pos2 != NULL) { 00174 *pos2 = 0; 00175 char * pos3 = strstr(pos1 + 1, ":"); 00176 if (pos3 != NULL) { 00177 char *ppduri; 00178 int n2 = strlen("compressed-ppd:")+strlen(pos3+1); 00179 ppduri = (char*)malloc(n2*sizeof(char)+1); 00180 memset(ppduri,0,n2); 00181 strcat(ppduri, "compressed-ppd:"); 00182 strcat(ppduri, pos3+1); 00183 addFile(ppduri, dirname, pos2+1); 00184 free(ppduri); 00185 ppduri = NULL; 00186 } 00187 } 00188 } 00189 } 00190 if (line) { 00191 free(line); 00192 } 00193 00194 pclose(file); 00195 } 00196 else { 00197 fprintf(stderr, "Can't execute compressed driver handler : %s\n", dirname); 00198 } 00199 00200 free(filename); 00201 filename = NULL; 00202 } 00203 else { 00204 fprintf(stderr, "Can't open drivers directory : %s\n", dirname); 00205 return; 00206 } 00207 } 00208 00209 void initCompressedPpd(const char *dirname) 00210 { 00211 // HACK 00212 // The initPpd function actually handles the compressed PPDs as well, so do nothing here 00213 // If we were to rerun initPpd here then all drivers would be duplicated! 00214 } 00215 00216 int parsePpdFile(const char *filename, const char * /*origin*/, const char * /*metadata*/, FILE *output_file) 00217 { 00218 gzFile ppd_file; 00219 char line[4096], value[256], langver[64] = {0}, desc[256] = {0}; 00220 char *c1, *c2; 00221 int count = 0; 00222 00223 ppd_file = gzopen(filename,"r"); 00224 if (ppd_file == NULL) 00225 { 00226 fprintf(stderr, "Can't open driver file : %s\n", filename); 00227 return 0; 00228 } 00229 fprintf(output_file,"FILE=ppd:%s\n",filename); 00230 00231 while (gzgets(ppd_file,line,4095) != Z_NULL) 00232 { 00233 PROCESS_PPD_FILE_CONTENTS 00234 } 00235 fprintf(output_file,"\n"); 00236 00237 gzclose(ppd_file); 00238 return 1; 00239 } 00240 00241 int parseCompressedPpdFile(const char *ppdfilename, const char *origin, const char *metadata, FILE *output_file) 00242 { 00243 char value[256], langver[64] = {0}, desc[256] = {0}; 00244 char *c1, *c2; 00245 int count = 0; 00246 00247 bool useFallbackExtractionMethod = false; 00248 00249 if (strlen(metadata) > 0) { 00250 TQString metadataProcessed(metadata); 00251 metadataProcessed = metadataProcessed.stripWhiteSpace(); 00252 TQStringList metadataList = TQStringList::split(" ", metadataProcessed, TRUE); 00253 TQLocale ppdLanguage(metadataList[0]); 00254 TQString languageVersion = TQLocale::languageToString(ppdLanguage.language()); 00255 metadataList = TQStringList::split("\" \"", metadataProcessed, TRUE); 00256 TQString description = metadataList[1]; 00257 00258 int pos = metadataProcessed.find("MFG:"); 00259 if (pos < 0) { 00260 pos = metadataProcessed.find("MANUFACTURER:"); 00261 } 00262 if (pos >= 0) { 00263 TQString manufacturer; 00264 TQString model; 00265 TQString modelName; 00266 TQString pnpManufacturer; 00267 TQString pnpModel; 00268 TQString driver; 00269 TQStringList metadataList = TQStringList::split(";", metadataProcessed.mid(pos), TRUE); 00270 for (TQStringList::Iterator it = metadataList.begin(); it != metadataList.end(); ++it) { 00271 TQStringList kvPair = TQStringList::split(":", *it, TRUE); 00272 if ((kvPair[0].upper() == "MFG") || (kvPair[0].upper() == "MANUFACTURER")) { 00273 manufacturer = kvPair[1]; 00274 } 00275 else if ((kvPair[0].upper() == "MDL") ||(kvPair[0].upper() == "MODEL")) { 00276 modelName = kvPair[1]; 00277 } 00278 // else if (kvPair[0].upper() == "PNPMANUFACTURER") { 00279 // pnpManufacturer = kvPair[1]; 00280 // } 00281 // else if (kvPair[0].upper() == "PNPMODEL") { 00282 // pnpModel = kvPair[1]; 00283 // } 00284 else if ((kvPair[0].upper() == "DRV") || (kvPair[0].upper() == "DRIVER")) { 00285 driver = kvPair[1]; 00286 } 00287 } 00288 00289 manufacturer = manufacturer.stripWhiteSpace(); 00290 modelName = modelName.stripWhiteSpace(); 00291 driver = driver.stripWhiteSpace(); 00292 00293 TQStringList driverList = TQStringList::split(",", driver, TRUE); 00294 driver = driverList[0]; 00295 if (driver.startsWith("D")) { 00296 driver = driver.mid(1); 00297 driver = driver.stripWhiteSpace(); 00298 } 00299 model = manufacturer + " " + modelName + " " + driver; 00300 description = description + " [" + languageVersion + "]"; 00301 00302 fprintf(output_file,"FILE=compressed-ppd:%s:%s\n", origin, ppdfilename); 00303 00304 fprintf(output_file,"MANUFACTURER=%s\n",manufacturer.ascii()); 00305 fprintf(output_file,"MODELNAME=%s\n",modelName.ascii()); 00306 fprintf(output_file,"MODEL=%s\n",model.ascii()); 00307 if (pnpManufacturer.length() > 0) { 00308 fprintf(output_file,"PNPMANUFACTURER=%s\n",pnpManufacturer.ascii()); 00309 } 00310 if (pnpModel.length() > 0) { 00311 fprintf(output_file,"PNPMODEL=%s\n",pnpModel.ascii()); 00312 } 00313 if (description.length() > 0) { 00314 fprintf(output_file,"DESCRIPTION=%s\n",description.ascii()); 00315 } 00316 } 00317 else { 00318 useFallbackExtractionMethod = true; 00319 } 00320 } 00321 00322 if (useFallbackExtractionMethod) { 00323 char *filename; 00324 int n = strlen(origin)+strlen(" cat ")+strlen(ppdfilename); 00325 filename = (char*)malloc(n*sizeof(char)+1); 00326 memset(filename,0,n); 00327 strcat(filename, origin); 00328 strcat(filename, " cat "); 00329 strcat(filename, ppdfilename); 00330 00331 FILE* file = popen(filename, "r"); 00332 if (file) { 00333 char * line = NULL; 00334 size_t len = 0; 00335 ssize_t read; 00336 00337 fprintf(output_file,"FILE=compressed-ppd:%s:%s\n", origin, ppdfilename); 00338 00339 while ((read = getline(&line, &len, file)) != -1) { 00340 PROCESS_PPD_FILE_CONTENTS 00341 } 00342 if (line) { 00343 free(line); 00344 } 00345 00346 pclose(file); 00347 } 00348 else { 00349 fprintf(stderr, "Can't open driver file : %s\n", ppdfilename); 00350 return 0; 00351 } 00352 00353 free(filename); 00354 filename = NULL; 00355 } 00356 00357 return 1; 00358 } 00359 00360 int main(int argc, char *argv[]) 00361 { 00362 registerHandler("ppd:", initPpd, parsePpdFile); 00363 registerHandler("compressed-ppd:", initCompressedPpd, parseCompressedPpdFile); 00364 initFoomatic(); 00365 return execute(argc, argv); 00366 }