Skip to content

Commit de11687

Browse files
committed
Add typedef parsing
1 parent d69ee4a commit de11687

2 files changed

Lines changed: 93 additions & 1 deletion

File tree

cstruct/c_parser.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,22 @@ def parse_type(tokens: Tokens, __cls__: Type['AbstractCStruct'], byte_order: Opt
160160
return FieldType(kind, c_type, ref, vlen, flexible_array, byte_order, offset)
161161

162162

163+
def parse_typedef(tokens: Tokens, __cls__: Type['AbstractCStruct'], byte_order: Optional[str]) -> None:
164+
field_type = parse_type(tokens, __cls__, byte_order, 0)
165+
vname = tokens.pop()
166+
if field_type.ref is None:
167+
TYPEDEFS[vname] = field_type.c_type
168+
elif field_type.ref.__is_enum__:
169+
TYPEDEFS[vname] = f"enum {field_type.ref.__name__}"
170+
elif field_type.ref.__is_union__:
171+
TYPEDEFS[vname] = f"union {field_type.ref.__name__}"
172+
else:
173+
TYPEDEFS[vname] = f"struct {field_type.ref.__name__}"
174+
t = tokens.pop()
175+
if t != ';':
176+
raise ParserError(f"; expected but {t} found")
177+
178+
163179
def parse_struct_def(
164180
__def__: Union[str, Tokens],
165181
__cls__: Type['AbstractCStruct'],
@@ -174,10 +190,13 @@ def parse_struct_def(
174190
if not tokens:
175191
return None
176192
kind = tokens.pop()
193+
if kind == 'typedef':
194+
parse_typedef(tokens, __cls__, __byte_order__)
195+
return parse_struct_def(tokens, __cls__, __byte_order__, **kargs)
177196
if kind == 'enum':
178197
return parse_enum_def(__def__, **kargs)
179198
if kind not in ['struct', 'union']:
180-
raise ParserError("struct, union, or enum expected - {kind}")
199+
raise ParserError(f"struct, union, or enum expected - {kind}")
181200
__is_union__ = kind == 'union'
182201
vtype = tokens.pop()
183202
if tokens.get() == '{': # Named nested struct

tests/test_typdef.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python
2+
# *****************************************************************************
3+
#
4+
# Copyright (c) 2013-2019 Andrea Bonomi <andrea.bonomi@gmail.com>
5+
#
6+
# Published under the terms of the MIT license.
7+
#
8+
# Permission is hereby granted, free of charge, to any person obtaining a copy
9+
# of this software and associated documentation files (the "Software"), to
10+
# deal in the Software without restriction, including without limitation the
11+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12+
# sell copies of the Software, and to permit persons to whom the Software is
13+
# furnished to do so, subject to the following conditions:
14+
#
15+
# The above copyright notice and this permission notice shall be included in
16+
# all copies or substantial portions of the Software.
17+
#
18+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24+
# IN THE SOFTWARE.
25+
#
26+
# *****************************************************************************
27+
28+
from cstruct import MemCStruct, NATIVE_ORDER
29+
from cstruct.base import TYPEDEFS
30+
31+
class ExitStatus(MemCStruct):
32+
__def__ = """
33+
struct ExitStatus {
34+
short e_termination; /* Process termination status. */
35+
short e_exit; /* Process exit status. */
36+
}
37+
"""
38+
39+
class Utmp(MemCStruct):
40+
__byte_order__ = NATIVE_ORDER
41+
__def__ = """
42+
#define UT_NAMESIZE 32
43+
#define UT_LINESIZE 32
44+
#define UT_HOSTSIZE 256
45+
46+
typedef int pid_t;
47+
typedef long time_t;
48+
typedef unsigned long int ulong;
49+
typedef struct ExitStatus ExitStatus;
50+
51+
struct {
52+
short ut_type; /* Type of record */
53+
pid_t ut_pid; /* PID of login process */
54+
char ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */
55+
char ut_id[4]; /* Terminal name suffix, or inittab(5) ID */
56+
char ut_user[UT_NAMESIZE]; /* Username */
57+
char ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or kernel version for run-level messages */
58+
ExitStatus ut_exit; /* Exit status of a process marked as DEAD_PROCESS; not used by Linux init (1 */
59+
int32_t ut_session; /* Session ID (getsid(2)), used for windowing */
60+
struct {
61+
int32_t tv_sec; /* Seconds */
62+
int32_t tv_usec; /* Microseconds */
63+
} ut_tv; /* Time entry was made */
64+
int32_t ut_addr_v6[4]; /* Internet address of remote host; IPv4 address uses just ut_addr_v6[0] */
65+
char __unused[20]; /* Reserved for future use */
66+
}
67+
"""
68+
69+
def test_typedef():
70+
assert TYPEDEFS['pid_t'] == 'int'
71+
assert TYPEDEFS['time_t'] == 'long'
72+
assert TYPEDEFS['ulong'] == 'unsigned long'
73+
assert TYPEDEFS['ExitStatus'] == 'struct ExitStatus'

0 commit comments

Comments
 (0)