]> mj.ucw.cz Git - pciutils.git/blob - lib/names-parse.c
Merge branch 'amiga'
[pciutils.git] / lib / names-parse.c
1 /*
2  *      The PCI Library -- Parsing of the ID list
3  *
4  *      Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *      SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15
16 #include "internal.h"
17 #include "names.h"
18
19 #ifdef PCI_COMPRESSED_IDS
20 #include <zlib.h>
21 typedef gzFile pci_file;
22 #define pci_gets(f, l, s)       gzgets(f, l, s)
23 #define pci_eof(f)              gzeof(f)
24
25 static pci_file pci_open(struct pci_access *a)
26 {
27   pci_file result;
28   size_t len;
29   char *new_name;
30
31   result = gzopen(a->id_file_name, "rb");
32   if (result)
33     return result;
34   len = strlen(a->id_file_name);
35   if (len < 3 || memcmp(a->id_file_name + len - 3, ".gz", 3) != 0)
36     return result;
37   new_name = malloc(len - 2);
38   memcpy(new_name, a->id_file_name, len - 3);
39   new_name[len - 3] = 0;
40   pci_set_name_list_path(a, new_name, 1);
41   return gzopen(a->id_file_name, "rb");
42 }
43
44 #define pci_close(f)            gzclose(f)
45 #define PCI_ERROR(f, err)                                               \
46         if (!err) {                                                     \
47                 int errnum = 0;                                         \
48                 gzerror(f, &errnum);                                    \
49                 if (errnum >= 0) err = NULL;                            \
50                 else if (errnum == Z_ERRNO) err = "I/O error";          \
51                 else err = zError(errnum);                              \
52         }
53 #else
54 typedef FILE * pci_file;
55 #define pci_gets(f, l, s)       fgets(l, s, f)
56 #define pci_eof(f)              feof(f)
57 #define pci_open(a)             fopen(a->id_file_name, "r")
58 #define pci_close(f)            fclose(f)
59 #define PCI_ERROR(f, err)       if (!err && ferror(f))  err = "I/O error";
60 #endif
61
62 static int id_hex(char *p, int cnt)
63 {
64   int x = 0;
65   while (cnt--)
66     {
67       x <<= 4;
68       if (*p >= '0' && *p <= '9')
69         x += (*p - '0');
70       else if (*p >= 'a' && *p <= 'f')
71         x += (*p - 'a' + 10);
72       else if (*p >= 'A' && *p <= 'F')
73         x += (*p - 'A' + 10);
74       else
75         return -1;
76       p++;
77     }
78   return x;
79 }
80
81 static inline int id_white_p(int c)
82 {
83   return (c == ' ') || (c == '\t');
84 }
85
86
87 static const char *id_parse_list(struct pci_access *a, pci_file f, int *lino)
88 {
89   char line[MAX_LINE];
90   char *p;
91   int id1=0, id2=0, id3=0, id4=0;
92   int cat = -1;
93   int nest;
94   static const char parse_error[] = "Parse error";
95
96   *lino = 0;
97   while (pci_gets(f, line, sizeof(line)))
98     {
99       (*lino)++;
100       p = line;
101       while (*p && *p != '\n' && *p != '\r')
102         p++;
103       if (!*p && !pci_eof(f))
104         return "Line too long";
105       *p = 0;
106       if (p > line && (p[-1] == ' ' || p[-1] == '\t'))
107         *--p = 0;
108
109       p = line;
110       while (id_white_p(*p))
111         p++;
112       if (!*p || *p == '#')
113         continue;
114
115       p = line;
116       while (*p == '\t')
117         p++;
118       nest = p - line;
119
120       if (!nest)                                        /* Top-level entries */
121         {
122           if (p[0] == 'C' && p[1] == ' ')               /* Class block */
123             {
124               if ((id1 = id_hex(p+2, 2)) < 0 || !id_white_p(p[4]))
125                 return parse_error;
126               cat = ID_CLASS;
127               p += 5;
128             }
129           else if (p[0] == 'S' && p[1] == ' ')
130             {                                           /* Generic subsystem block */
131               if ((id1 = id_hex(p+2, 4)) < 0 || p[6])
132                 return parse_error;
133               if (!pci_id_lookup(a, 0, ID_VENDOR, id1, 0, 0, 0))
134                 return "Vendor does not exist";
135               cat = ID_GEN_SUBSYSTEM;
136               continue;
137             }
138           else if (p[0] >= 'A' && p[0] <= 'Z' && p[1] == ' ')
139             {                                           /* Unrecognized block (RFU) */
140               cat = ID_UNKNOWN;
141               continue;
142             }
143           else                                          /* Vendor ID */
144             {
145               if ((id1 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
146                 return parse_error;
147               cat = ID_VENDOR;
148               p += 5;
149             }
150           id2 = id3 = id4 = 0;
151         }
152       else if (cat == ID_UNKNOWN)                       /* Nested entries in RFU blocks are skipped */
153         continue;
154       else if (nest == 1)                               /* Nesting level 1 */
155         switch (cat)
156           {
157           case ID_VENDOR:
158           case ID_DEVICE:
159           case ID_SUBSYSTEM:
160             if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
161               return parse_error;
162             p += 5;
163             cat = ID_DEVICE;
164             id3 = id4 = 0;
165             break;
166           case ID_GEN_SUBSYSTEM:
167             if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
168               return parse_error;
169             p += 5;
170             id3 = id4 = 0;
171             break;
172           case ID_CLASS:
173           case ID_SUBCLASS:
174           case ID_PROGIF:
175             if ((id2 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
176               return parse_error;
177             p += 3;
178             cat = ID_SUBCLASS;
179             id3 = id4 = 0;
180             break;
181           default:
182             return parse_error;
183           }
184       else if (nest == 2)                               /* Nesting level 2 */
185         switch (cat)
186           {
187           case ID_DEVICE:
188           case ID_SUBSYSTEM:
189             if ((id3 = id_hex(p, 4)) < 0 || !id_white_p(p[4]) || (id4 = id_hex(p+5, 4)) < 0 || !id_white_p(p[9]))
190               return parse_error;
191             p += 10;
192             cat = ID_SUBSYSTEM;
193             break;
194           case ID_CLASS:
195           case ID_SUBCLASS:
196           case ID_PROGIF:
197             if ((id3 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
198               return parse_error;
199             p += 3;
200             cat = ID_PROGIF;
201             id4 = 0;
202             break;
203           default:
204             return parse_error;
205           }
206       else                                              /* Nesting level 3 or more */
207         return parse_error;
208       while (id_white_p(*p))
209         p++;
210       if (!*p)
211         return parse_error;
212       if (pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_LOCAL))
213         return "Duplicate entry";
214     }
215   return NULL;
216 }
217
218 int
219 pci_load_name_list(struct pci_access *a)
220 {
221   pci_file f;
222   int lino;
223   const char *err;
224
225   pci_free_name_list(a);
226   a->id_load_attempted = 1;
227   if (!(f = pci_open(a)))
228     return 0;
229   err = id_parse_list(a, f, &lino);
230   PCI_ERROR(f, err);
231   pci_close(f);
232   if (err)
233     a->error("%s at %s, line %d\n", err, a->id_file_name, lino);
234   return 1;
235 }
236
237 void
238 pci_free_name_list(struct pci_access *a)
239 {
240   pci_id_cache_flush(a);
241   pci_id_hash_free(a);
242   pci_id_hwdb_free(a);
243   a->id_load_attempted = 0;
244 }
245
246 void
247 pci_set_name_list_path(struct pci_access *a, char *name, int to_be_freed)
248 {
249   if (a->free_id_name)
250     free(a->id_file_name);
251   a->id_file_name = name;
252   a->free_id_name = to_be_freed;
253 }