1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
|
# -*- coding: utf-8 -*-
#
# File: portato/eix/_parser.pyx
# This file is part of the Portato-Project, a graphical portage-frontend.
#
# Copyright (C) 2006-2009 René 'Necoro' Neumann
# This is free software. You may redistribute copies of it under the terms of
# the GNU General Public License version 2.
# There is NO WARRANTY, to the extent permitted by law.
#
# Written by René 'Necoro' Neumann <necoro@necoro.net>
"""
The cache file supports different types of data.
In this module (nearly) all of these types have a corresponding function.
For the exact way all the functions work, have a look at the eix format description.
"""
__docformat__ = "restructuredtext"
cdef extern from "stdio.h":
ctypedef struct FILE:
pass
int fgetc(FILE* stream)
long ftell(FILE* stream)
int fseek(FILE* stream, long offset, int whence)
int EOF
int SEEK_CUR
cdef extern from "Python.h":
FILE* PyFile_AsFile(object)
ctypedef unsigned char UChar
ctypedef long long LLong
from portato.eix.exceptions import EndOfFileException
#
# Helper
#
cdef int _get_byte (FILE* file) except -1:
cdef int c = fgetc(file)
if c == EOF:
raise EndOfFileException
return c
#
# Base Types
#
cdef LLong _number (object pfile):
cdef UChar n
cdef LLong value
cdef int i
cdef unsigned short count = 1
cdef FILE* file = PyFile_AsFile(pfile)
n = <UChar>_get_byte(file)
if n < 0xFF:
return <LLong>n
else:
n = <UChar>_get_byte(file)
while (n == 0xFF):
count += 1
n = <UChar>_get_byte(file)
if n == 0:
value = <LLong>0xFF # 0xFF is encoded as 0xFF 0x00
count -= 1
else:
value = <LLong>n
for i in range(count):
value = (value << 8) | <LLong>(_get_byte(file))
return value
def number (file):
"""
Returns a number.
:param file: The file to read from
:type file: file
:rtype: int
"""
return _number(file)
def vector (file, get_type, nelems = None):
"""
Returns a vector of elements.
:Parameters:
file : file
The file to read from.
get_type : function(file, bool)
The function determining type of the elements.
nelems : int
Normally the eix-Vector has the number of elements as the first argument.
If for some reason this is not the case, you can pass it in here.
:rtype: list
"""
cdef LLong n
cdef LLong i
if nelems is None:
n = _number(file)
else:
n = nelems
return [get_type(file) for i in range(n)]
def string (file):
"""
Returns a string.
:param file: The file to read from
:type file: file
:rtype: str
"""
nelems = _number(file)
s = file.read(nelems)
if len(s) != nelems:
raise EndOfFileException, file.name
return s
#
# Complex Types
#
cdef class overlay:
"""
Represents an overlay object.
:IVariables:
path : string
The path to the overlay
label : string
The label/name of the overlay
"""
cdef readonly object path
cdef readonly object label
def __init__ (self, file):
"""
:param file: The file to read from
:type file: file
"""
self.path = string(file)
self.label = string(file)
cdef class header:
"""
Represents the header of the cache.
:IVariables:
version : int
The version of the cache file.
ncats : int
The number of categories.
overlays : `overlay` []
The list of overlays.
provide : string[]
A list of "PROVIDE" values.
licenses : string[]
The list of licenses.
keywords : string[]
The list of keywords.
useflags : string[]
The list of useflags.
slots : string[]
The list of slots different from "0".
sets : string[]
The names of world sets are the names (without leading @) of the world sets stored in /var/lib/portage/world_sets.
If SAVE_WORLD=false, the list is empty.
"""
cdef readonly object version
cdef readonly object ncats
cdef readonly object overlays
cdef readonly object provide
cdef readonly object licenses
cdef readonly object keywords
cdef readonly object useflags
cdef readonly object slots
cdef readonly object sets
def __init__ (self, file):
"""
:param file: The file to read from
:type file: file
"""
self.version = _number(file)
self.ncats = _number(file)
self.overlays = vector(file, overlay)
self.provide = vector(file, string)
self.licenses = vector(file, string)
self.keywords = vector(file, string)
self.useflags = vector(file, string)
self.slots = vector(file, string)
self.sets = vector(file, string)
cdef class package:
"""
The representation of one package.
Currently, version information is not parsed and stored.
So you can gain general infos only.
:IVariables:
name : string
The name of the package.
description : string
Description of the package.
homepage : string
The homepage of the package.
provide : int[]
The indices of `header.provide` representing the PROVIDE value of the package.
license : int
The index of `header.licenses` representing the license of the package.
useflags : int[]
The indices of `header.useflags` representing the IUSE value of the package.
"""
cdef LLong _offset
cdef readonly object name
cdef readonly object description
#cdef readonly object provide
#cdef readonly object homepage
#cdef readonly object license
#cdef readonly object useflags
def __init__ (self, file):
"""
:param file: The file to read from
:type file: file
"""
cdef FILE* cfile = PyFile_AsFile(file)
cdef long after_offset
self._offset = _number(file)
after_offset = ftell(cfile)
self.name = string(file)
self.description = string(file)
# skip the rest, as it is currently unneeded
#self.provide = vector(file, number)
#self.homepage = string(file)
#self.license = number(file)
#self.useflags = vector(file, number)
# self.versions = LE(typed_vector(version))
# for the moment just skip the versions
fseek(cfile, self._offset - (ftell(cfile) - after_offset), SEEK_CUR)
cdef class category:
"""
Represents a whole category.
:IVariables:
name : string
The category name.
packages : `package` []
All the packages of the category.
"""
cdef readonly object name
cdef readonly object packages
def __init__ (self, file):
"""
:param file: The file to read from
:type file: file
"""
self.name = string(file)
self.packages = vector(file, package)
|