~peter-pearse/ubuntu/natty/pciutils/prop001

« back to all changes in this revision

Viewing changes to lib/names-parse.c

  • Committer: Bazaar Package Importer
  • Author(s): Anibal Monsalve Salazar
  • Date: 2008-04-29 16:23:38 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080429162338-v20040rx66khbl7v
Tags: 1:3.0.0-3
libpci-dev conflicts with pciutils-dev. Closes: #478290

Show diffs side-by-side

added added

removed removed

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