Tizen 2.1 base
[platform/upstream/hplip.git] / io / hpmud / model.c
1 /*****************************************************************************\
2
3   model.c - model parser for hplip devices 
4  
5   (c) 2006-2007 Copyright Hewlett-Packard Development Company, LP
6
7   Permission is hereby granted, free of charge, to any person obtaining a copy 
8   of this software and associated documentation files (the "Software"), to deal 
9   in the Software without restriction, including without limitation the rights 
10   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
11   of the Software, and to permit persons to whom the Software is furnished to do 
12   so, subject to the following conditions:
13
14   The above copyright notice and this permission notice shall be included in all
15   copies or substantial portions of the Software.
16
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
18   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
19   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
20   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
21   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 \*****************************************************************************/
25
26 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE
28 #endif
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdarg.h>
38 #include "list.h"
39 #include "hpmud.h"
40 #include "hpmudi.h"
41
42 #define SECTION_SIZE 4096 /* Rough estimate of key/value section size in bytes. */
43
44 typedef struct
45 {
46   char *name;
47   char *incFile; 
48   int valueSize;  /* size of list in bytes */
49   char *value;    /* list of key/value pairs */
50   struct list_head list;
51 } LabelRecord;
52
53 static LabelRecord head;   /* list of labels from include files */
54 static char homedir[255] = "";
55
56 static int GetPair(char *buf, int buf_len, char *key, char *value, char **tail)
57 {
58    int i=0, j;
59
60    key[0] = 0;
61    value[0] = 0;
62
63    if (buf[i] == '#')
64    {
65       for (; buf[i] != '\n' && i < buf_len; i++);  /* eat comment line */
66       if (buf[i] == '\n')
67          i++;   /* bump past '\n' */
68    }
69
70    j = 0;
71    while ((buf[i] != '=') && (i < buf_len) && (j < HPMUD_LINE_SIZE))
72       key[j++] = buf[i++];
73    for (j--; key[j] == ' ' && j > 0; j--);  /* eat white space before = */
74    key[++j] = 0;
75
76    if (buf[i] == '=')
77       for (i++; buf[i] == ' ' && i < buf_len; i++);  /* eat white space after = */
78
79    j = 0;
80    while ((buf[i] != '\n') && (i < buf_len) && (j < HPMUD_LINE_SIZE))
81       value[j++] = buf[i++];
82    for (j--; value[j] == ' ' && j > 0; j--);  /* eat white space before \n */
83    value[++j] = 0;
84
85    if (buf[i] == '\n')
86      i++;   /* bump past '\n' */
87
88    if (tail != NULL)
89       *tail = buf + i;  /* tail points to next line */
90
91    return i;
92 }
93
94 static int ReadConfig()
95 {
96    char key[HPMUD_LINE_SIZE];
97    char value[HPMUD_LINE_SIZE];
98    char rcbuf[255];
99    char section[32];
100    char *tail;
101    FILE *inFile = NULL;
102    int stat=1;
103
104    homedir[0] = 0;
105         
106    if((inFile = fopen(CONFDIR "/hplip.conf", "r")) == NULL) 
107    {
108       BUG("unable to open %s: %m\n", CONFDIR "/hplip.conf");
109       goto bugout;
110    } 
111
112    section[0] = 0;
113
114    /* Read the config file */
115    while ((fgets(rcbuf, sizeof(rcbuf), inFile) != NULL))
116    {
117       if (rcbuf[0] == '[')
118       {
119          strncpy(section, rcbuf, sizeof(section)); /* found new section */
120          continue;
121       }
122
123       GetPair(rcbuf, strlen(rcbuf), key, value, &tail);
124
125       if ((strncasecmp(section, "[dirs]", 6) == 0) && (strcasecmp(key, "home") == 0))
126       {
127          strncpy(homedir, value, sizeof(homedir));
128          break;  /* done */
129       }
130    }
131         
132    stat = 0;
133
134 bugout:        
135    if (inFile != NULL)
136       fclose(inFile);
137          
138    return stat;
139 }
140
141 /* Find last occurance of y in x. */
142 static char *strrstr(const char *x, const char *y) 
143 {
144    char *prev=NULL, *next;
145
146    if (*y == '\0')
147       return strchr(x, '\0');
148
149    while ((next = strstr(x, y)) != NULL)
150    {
151       prev = next;
152       x = next + 1;
153    }
154    return prev;
155 }
156
157 static int CopyLabel(char *label, char *buf, int bufSize)
158 {
159    struct list_head *p;
160    LabelRecord *pl;
161    int i=0, found=0;
162
163    /* Look for label. */
164    list_for_each(p, &head.list)
165    {
166       pl = list_entry(p, LabelRecord, list);
167       if (strcasecmp(pl->name, label) == 0)
168       {
169          found = 1;    /* found label */
170          break;
171       }
172    }
173
174    if (!found)
175    {
176       BUG("error undefined label %s\n", label);
177       goto bugout;
178    }
179
180    if (pl->valueSize > bufSize)
181    {
182       BUG("error label %s size=%d buf=%d\n", label, pl->valueSize, bufSize);
183       goto bugout;
184    }
185
186    memcpy(buf, pl->value, pl->valueSize);
187    i=pl->valueSize;
188
189 bugout:
190    return i;
191 }
192
193 static int ResolveAttributes(FILE *fp, char *attr, int attrSize)
194 {
195    char label[128];
196    int i=0, j, ch;
197
198    /* Process each key/value line. */
199    ch = fgetc(fp);
200    while (ch != EOF)
201    {
202       if (ch == '[')
203       {
204          ungetc(ch, fp);     /* found new section, done with current section */
205          break;         
206       }
207
208       if (ch == '#' || ch == ' ')
209       {
210          while ((ch = fgetc(fp)) != '\n' && ch != EOF);  /* skip line */
211       }
212       else if (ch == '\n')
213       {
214          /* skip blank line */
215       }
216       else if (ch == '%')
217       {
218          j=0;
219          while ((ch = fgetc(fp)) != '\n' && ch != EOF)  /* get label */
220          {
221             if (j < sizeof(label)-1)
222                label[j++] = ch;
223          }
224          label[j-1] = 0;
225          i += CopyLabel(label, attr+i, attrSize-i);
226       }
227       else
228       {
229          if (i < attrSize-1)
230             attr[i++] = ch;
231          while ((ch = fgetc(fp)) != '\n' && ch != EOF)  /* get key/value line */
232          {
233             if (i < attrSize-1)
234                attr[i++] = ch;
235          }
236          if (i < attrSize-1)
237             attr[i++] = '\n';
238       }
239
240       if (ch == '\n')
241          ch = fgetc(fp);   /* bump to next line */
242       continue;
243    }
244
245    attr[i] = 0;   /* terminate string */
246
247    return i;
248 }
249 static int RegisterLabel(FILE *fp, char *incFile, char *label)
250 {
251    struct list_head *p;
252    LabelRecord *pl;
253    char buf[SECTION_SIZE];
254    int i=0, stat=1, ch;
255
256    /* Look for duplicate label. */
257    list_for_each(p, &head.list)
258    {
259       pl = list_entry(p, LabelRecord, list);
260       if (strcasecmp(pl->name, label) == 0)
261       {
262          BUG("error duplicate label %s\n", label);
263          goto bugout;
264       }
265    }
266
267    if ((pl = (LabelRecord *)malloc(sizeof(LabelRecord))) == NULL)
268    {
269       BUG("unable to creat label record: %m\n");
270       goto bugout;
271    }
272
273    pl->incFile = strdup(incFile);
274    pl->name = strdup(label);
275
276    /* Process each key/value line. */
277    ch = fgetc(fp);
278    while (ch != EOF)
279    {
280       if (ch == '[')
281       {
282          ungetc(ch, fp);     /* found new section, done with label */
283          break;         
284       }
285
286       if (ch == '#' || ch == ' ')
287       {
288          while ((ch = fgetc(fp)) != '\n' && ch != EOF);  /* skip line */
289       }
290       else if (ch == '\n')
291       {
292          /* skip blank line */
293       }
294       else
295       {
296          if (i < SECTION_SIZE-1)
297             buf[i++] = ch;
298          while ((ch = fgetc(fp)) != '\n' && ch != EOF)  /* get key/value line */
299          {
300             if (i < SECTION_SIZE-1)
301                buf[i++] = ch;
302          }
303          if (i < SECTION_SIZE-1)
304             buf[i++] = '\n';
305       }
306
307       if (ch == '\n')
308          ch = fgetc(fp);   /* bump to next line */
309       continue;
310    }
311
312    buf[i] = 0;   /* terminate string */
313
314    pl->value = strdup(buf);
315    pl->valueSize = i;  /* size does not include zero termination */
316
317    list_add(&(pl->list), &(head.list));
318    stat = 0;
319
320 bugout:
321
322    return stat;
323 }
324
325 static int UnRegisterLabel(LabelRecord *pl)
326 {
327    if (pl->incFile)
328       free(pl->incFile);
329    if (pl->name)
330       free(pl->name);
331    if (pl->value)
332       free(pl->value);
333    list_del(&(pl->list));
334    free(pl);
335    return 0;
336 }
337
338 static int DelList()
339 {
340    struct list_head *p, *n;
341    LabelRecord *pl;
342  
343    /* Remove each label. */
344    list_for_each_safe(p, n, &head.list)
345    {
346       pl = list_entry(p, LabelRecord, list);
347       UnRegisterLabel(pl);
348    }
349    return 0;
350 }
351
352 /* Parse *.inc file. */
353 static int ParseInc(char *incFile)
354 {
355    FILE *fp=NULL;
356    struct list_head *p;
357    LabelRecord *pl;
358    char rcbuf[255];
359    char section[128];
360    int stat=1, n;
361
362    /* Look for duplicate include file. */
363    list_for_each(p, &head.list)
364    {
365       pl = list_entry(p, LabelRecord, list);
366       if (strcmp(pl->incFile, incFile) == 0)
367       {
368          BUG("error duplicate include file %s\n", incFile);
369          goto bugout;
370       }
371    }
372
373    if ((fp = fopen(incFile, "r")) == NULL)
374    {
375       BUG("open %s failed: %m\n", incFile);
376       goto bugout;
377    }
378
379    section[0] = 0;
380
381    /* Read the *.inc file, check each line for new label. */
382    while ((fgets(rcbuf, sizeof(rcbuf), fp) != NULL))
383    {
384       if (rcbuf[0] == '[')
385       {
386          strncpy(section, rcbuf+1, sizeof(section)); /* found new section */
387          n = strlen(section);
388          section[n-2]=0; /* remove ']' and CR */
389          RegisterLabel(fp, incFile, section);
390       }
391    }
392
393    stat = 0;
394
395 bugout:
396    if (fp)
397       fclose(fp);
398    return stat;
399 }
400
401 /* Parse *.dat file. */
402 static int ParseFile(char *datFile, char *model, char *attr, int attrSize, int *bytes_read)
403 {
404    FILE *fp;
405    char rcbuf[255];
406    char section[128];
407    char file[128];
408    int found=0, n;
409
410    if ((fp = fopen(datFile, "r")) == NULL)
411       goto bugout;
412
413    section[0] = 0;
414
415    /* Read the *.dat file, check each line for model match. */
416    while ((fgets(rcbuf, sizeof(rcbuf), fp) != NULL))
417    {
418       if (rcbuf[0] == '[')
419       {
420          strncpy(section, rcbuf+1, sizeof(section)); /* found new section */
421          n = strlen(section);
422          section[n-2]=0; /* remove ']' and CR */
423          if (strcasecmp(model, section) == 0)
424          {
425             /* Found model match. */
426             *bytes_read = ResolveAttributes(fp, attr, attrSize); 
427             found = 1; 
428             break;
429          }
430       }
431       else if (strncmp(rcbuf, "%include", 8) == 0)
432       {
433          strncpy(file, datFile, sizeof(file));        /* get dirname from *.dat file */
434          n = strrstr(file, "/") - file + 1;
435          strncpy(file+n, rcbuf+9, sizeof(file)-n);      /* concatenate include filename to dirname */
436          n = strlen(file);
437          file[n-1]=0;        /* remove CR */
438          ParseInc(file);
439       }
440    }
441
442 bugout:
443    if (fp)
444       fclose(fp);
445
446    return found;
447 }
448
449 /* Parse and convert all known key value pairs in buffer. Do sanity check on values. */
450 static int parse_key_value_pair(char *buf, int len, struct hpmud_model_attributes *ma)
451 {
452    char key[HPMUD_LINE_SIZE];
453    char value[HPMUD_LINE_SIZE];
454    char *tail, *tail2;
455    int i=0, ret=HPMUD_R_OK;
456
457    ma->prt_mode = HPMUD_RAW_MODE;
458    ma->mfp_mode = HPMUD_DOT4_MODE;
459    ma->scantype = 0;
460    ma->statustype = HPMUD_STATUSTYPE_SFIELD;
461    ma->support = HPMUD_SUPPORT_TYPE_NONE;
462
463    if (buf == NULL)
464       return HPMUD_R_OK;    /* initialize ma */
465
466    tail = buf;
467
468    while (i < len)
469    {
470       i += GetPair(tail, len-i, key, value, &tail);
471
472       if (strcasecmp(key, "io-mode") == 0)
473       {
474          ma->prt_mode = strtol(value, &tail2, 10);      /* uni | raw | mlc */
475       }
476       else if (strcasecmp(key, "io-mfp-mode") == 0)
477       {
478          ma->mfp_mode = strtol(value, &tail2, 10);      /* mfc | dot4 */
479       }
480       else if(strcasecmp(key, "scan-type") == 0)
481       {
482          ma->scantype = strtol(value, &tail2, 10); /*SCL, PML, SOAP, MARVELL, LEDM*/
483       }
484       else if(strcasecmp(key, "scan-src") == 0)
485       {
486          ma->scansrc = strtol(value, &tail2, 10); /*Flatbed, ADF, Camera or combination of these*/
487       }
488       else if(strcasecmp(key, "status-type") == 0)
489       {
490          ma->statustype = strtol(value, &tail2, 10);
491       }
492       else if(strcasecmp(key, "support-type") == 0)
493       {
494          ma->support = strtol(value, &tail2, 10);
495       }
496       else if(strcasecmp(key, "plugin") == 0)
497       {
498          ma->plugin = strtol(value, &tail2, 10);
499       }
500       else
501       {
502          /* Unknown keys are ignored (R_AOK). */
503       }
504    }  // end while (i < len)
505
506    return ret;
507 }
508
509 /* Request device model attributes for URI. Return all attributes. */
510 enum HPMUD_RESULT hpmud_get_model_attributes(char *uri, char *attr, int attrSize, int *bytes_read)
511 {
512    char sz[256];
513    char model[256];
514    int found;
515    enum HPMUD_RESULT stat = HPMUD_R_DATFILE_ERROR;
516
517    memset(attr, 0, attrSize);
518
519    INIT_LIST_HEAD(&head.list);
520
521    if (homedir[0] == 0)    
522       ReadConfig();
523
524    hpmud_get_uri_model(uri, model, sizeof(model));
525
526    /* Search /data/models.dat file for specified model. */
527    snprintf(sz, sizeof(sz), "%s/data/models/models.dat", homedir);
528    found = ParseFile(sz, model, attr, attrSize, bytes_read);   /* save any labels in *.inc files */
529
530    if (!found)
531    {
532       BUG("no %s attributes found in %s\n", model, sz);  
533
534       DelList();   /* Unregister all labels. */
535
536       /* Search /data/models/unreleased/unreleased.dat file for specified model. */
537       snprintf(sz, sizeof(sz), "%s/data/models/unreleased/unreleased.dat", homedir);
538       found = ParseFile(sz, model, attr, attrSize, bytes_read);   /* save any *.inc files */
539    }
540
541    if (!found)
542    {  
543       BUG("no %s attributes found in %s\n", model, sz);  
544       goto bugout;
545    }  
546
547    stat = HPMUD_R_OK;
548
549 bugout:   
550    DelList();  /* Unregister all labels. */
551    return stat;
552 }
553
554 /* Request device model attributes for URI. Return filled in hpmud_model_attributes structure. */
555 enum HPMUD_RESULT hpmud_query_model(char *uri, struct hpmud_model_attributes *ma)
556 {
557    char buf[SECTION_SIZE];
558    int len;
559    enum HPMUD_RESULT stat = HPMUD_R_DATFILE_ERROR;
560
561    parse_key_value_pair(NULL, 0, ma);  /* set ma defaults */
562
563    if (hpmud_get_model_attributes(uri, buf, sizeof(buf), &len) != 0)
564       goto bugout;  /* model not found, return ma defaults */
565
566    parse_key_value_pair(buf, len, ma);
567
568    stat=HPMUD_R_OK;
569
570 bugout:
571
572    return stat;
573 }
574
575 /* Get value for specified section and key from hplip.conf. */
576 enum HPMUD_RESULT hpmud_get_conf(const char *section, const char *key, char *value, int value_size)
577 {
578    return hpmud_get_key_value(CONFDIR "/hplip.conf", section, key, value, value_size);
579 }
580
581 /* Get value for specified section and key from specified file. */
582 enum HPMUD_RESULT hpmud_get_key_value(const char *file, const char *section, const char *key, char *value, int value_size)
583 {
584    char new_key[HPMUD_LINE_SIZE];
585    char new_value[HPMUD_LINE_SIZE];
586    char rcbuf[255];
587    char new_section[32];
588    char *tail;
589    FILE *inFile;
590    enum HPMUD_RESULT stat = HPMUD_R_DATFILE_ERROR;
591    int i,j;
592
593    if((inFile = fopen(file, "r")) == NULL) 
594    {
595       BUG("unable to open %s: %m\n", file);
596       goto bugout;
597    } 
598
599    new_section[0] = 0;
600
601    /* Read the config file */
602    while ((fgets(rcbuf, sizeof(rcbuf), inFile) != NULL))
603    {
604       if (rcbuf[0] == '[')
605       {
606          i = j = 0;
607          while ((rcbuf[i] != ']') && (j < (sizeof(new_section)-2)))
608             new_section[j++] = rcbuf[i++];
609          new_section[j++] = rcbuf[i++];   /* ']' */
610          new_section[j] = 0;        /* zero terminate */
611          continue;
612       }
613
614       GetPair(rcbuf, strlen(rcbuf), new_key, new_value, &tail);
615
616       if ((strcasecmp(new_section, section) == 0) && (strcasecmp(new_key, key) == 0))
617       {
618          strncpy(value, new_value, value_size);
619          stat = HPMUD_R_OK;
620          break;  /* done */
621       }
622    }
623
624    if (stat != HPMUD_R_OK)
625       BUG("unable to find %s %s in %s\n", section, key, file);
626         
627 bugout:        
628    if (inFile != NULL)
629       fclose(inFile);
630          
631    return stat;
632 }
633