Skip to content

Commit f15c39b

Browse files
author
Raymond McCrae
committed
Refactor CHTMLSAXParser.c
1 parent 5f08d4e commit f15c39b

File tree

5 files changed

+75
-63
lines changed

5 files changed

+75
-63
lines changed

Package.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ let package = Package(
2424
.target(
2525
name: "CHTMLSAXParser",
2626
dependencies: []),
27-
// .testTarget(
28-
// name: "HTMLSAXParserTests",
29-
// dependencies: ["HTMLSAXParser"]),
27+
.testTarget(
28+
name: "HTMLSAXParserTests",
29+
dependencies: ["HTMLSAXParser"],
30+
path: "Tests",
31+
),
3032
]
3133
)

Sources/CHTMLSAXParser/CHTMLSAXParser.c

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,11 @@
2525
HTMLParserWrappedErrorSAXFunc htmlparser_global_error_sax_func;
2626
HTMLParserWrappedWarningSAXFunc htmlparser_global_warning_sax_func;
2727

28-
/**
29-
The global error handling function for the module. This function will format the
30-
message into a single string before calling the wrapped error function.
31-
*/
32-
static void htmlparser_error_sax_handler(void *ctx, const char *msg, ...) {
33-
va_list vl;
28+
static char* formatstr(const char *format, va_list args) {
3429
int consumed = 0;
3530
size_t buffer_size = 0;
3631
char *buffer = NULL;
32+
va_list vl;
3733

3834
do {
3935
if (consumed > buffer_size) {
@@ -42,64 +38,66 @@ static void htmlparser_error_sax_handler(void *ctx, const char *msg, ...) {
4238
else {
4339
buffer_size += 100;
4440
}
45-
if (buffer == NULL) {
46-
buffer = malloc(buffer_size);
47-
}
48-
else {
49-
buffer = realloc(buffer, buffer_size);
50-
}
41+
buffer = realloc(buffer, buffer_size);
5142

5243
// Check buffer is not null in case malloc / realloc failed.
5344
if (buffer != NULL) {
54-
va_start(vl, msg);
55-
consumed = vsnprintf(buffer, buffer_size, msg, vl);
45+
va_copy(vl, args);
46+
consumed = vsnprintf(buffer, buffer_size, format, vl);
5647
va_end(vl);
5748
}
5849
} while (buffer != NULL && consumed > 0 && consumed >= buffer_size);
5950

6051
if (buffer != NULL) {
61-
if (consumed > 0 && consumed < buffer_size && htmlparser_global_error_sax_func != NULL) {
62-
htmlparser_global_error_sax_func(ctx, buffer);
52+
if (consumed > 0 && consumed < buffer_size) {
53+
return buffer;
6354
}
6455

6556
free(buffer);
6657
}
58+
59+
return NULL;
60+
}
61+
62+
/**
63+
The global error handling function for the module. This function will format the
64+
message into a single string before calling the wrapped error function.
65+
*/
66+
static void htmlparser_error_sax_handler(void *ctx, const char *msg, ...) {
67+
va_list vl;
68+
char *formatted_msg = NULL;
69+
70+
if (htmlparser_global_error_sax_func == NULL) {
71+
return;
72+
}
73+
74+
va_start(vl, msg);
75+
formatted_msg = formatstr(msg, vl);
76+
va_end(vl);
77+
78+
htmlparser_global_error_sax_func(ctx, formatted_msg);
79+
80+
if (formatted_msg != NULL) {
81+
free(formatted_msg);
82+
}
6783
}
6884

6985
static void htmlparser_warning_sax_handler(void *ctx, const char *msg, ...) {
7086
va_list vl;
71-
int consumed = 0;
72-
size_t buffer_size = 0;
73-
char *buffer = NULL;
87+
char *formatted_msg = NULL;
7488

75-
do {
76-
if (consumed > buffer_size) {
77-
buffer_size = consumed + 1; // Add 1 for the null character
78-
}
79-
else {
80-
buffer_size += 100;
81-
}
82-
if (buffer == NULL) {
83-
buffer = malloc(buffer_size);
84-
}
85-
else {
86-
buffer = realloc(buffer, buffer_size);
87-
}
89+
if (htmlparser_global_warning_sax_func == NULL) {
90+
return;
91+
}
8892

89-
// Check buffer is not null in case malloc / realloc failed.
90-
if (buffer != NULL) {
91-
va_start(vl, msg);
92-
consumed = vsnprintf(buffer, buffer_size, msg, vl);
93-
va_end(vl);
94-
}
95-
} while (buffer != NULL && consumed > 0 && consumed >= buffer_size);
93+
va_start(vl, msg);
94+
formatted_msg = formatstr(msg, vl);
95+
va_end(vl);
9696

97-
if (buffer != NULL) {
98-
if (consumed > 0 && consumed < buffer_size && htmlparser_global_warning_sax_func != NULL) {
99-
htmlparser_global_warning_sax_func(ctx, buffer);
100-
}
97+
htmlparser_global_warning_sax_func(ctx, formatted_msg);
10198

102-
free(buffer);
99+
if (formatted_msg != NULL) {
100+
free(formatted_msg);
103101
}
104102
}
105103

Sources/HTMLSAXParser/HTMLSAXParser+libxml2.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,17 @@ internal extension HTMLSAXParser {
363363
private static let globalErrorHandler: HTMLParserWrappedErrorSAXFunc = {
364364
// We only want to set this global once ever. Regardless of the number of instances of parsers.
365365
htmlparser_global_error_sax_func = {context, message in
366-
guard let context = context, let message = message else {
366+
guard let context = context else {
367367
return
368368
}
369369

370-
let messageString = String(cString: message).trimmingCharacters(in: .whitespacesAndNewlines)
370+
let messageString: String
371+
if let message = message {
372+
messageString = String(cString: message).trimmingCharacters(in: .whitespacesAndNewlines)
373+
}
374+
else {
375+
messageString = ""
376+
}
371377
let handlerContext: HandlerContext = Unmanaged<HandlerContext>.fromOpaque(context).takeUnretainedValue()
372378
handlerContext.handler(handlerContext, .error(message: messageString))
373379
}
@@ -376,11 +382,17 @@ internal extension HTMLSAXParser {
376382
private static let globalWarningHandler: HTMLParserWrappedWarningSAXFunc = {
377383
// We only want to set this global once ever. Regardless of the number of instances of parsers.
378384
htmlparser_global_warning_sax_func = { context, message in
379-
guard let context = context, let message = message else {
385+
guard let context = context else {
380386
return
381387
}
382388

383-
let messageString = String(cString: message).trimmingCharacters(in: .whitespacesAndNewlines)
389+
let messageString: String
390+
if let message = message {
391+
messageString = String(cString: message).trimmingCharacters(in: .whitespacesAndNewlines)
392+
}
393+
else {
394+
messageString = ""
395+
}
384396
let handlerContext: HandlerContext = Unmanaged<HandlerContext>.fromOpaque(context).takeUnretainedValue()
385397
handlerContext.handler(handlerContext, .warning(message: messageString))
386398
}

Sources/HTMLSAXParser/HTMLSAXParser.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,21 +109,21 @@ open class HTMLSAXParser {
109109
public typealias EventHandler = (HTMLSAXParseContext, Event) -> Void
110110

111111
/// The parse options the html parser was initialised with.
112-
public let parseOptions: ParseOptions
112+
open let parseOptions: ParseOptions
113113

114114
public init(parseOptions: ParseOptions = .`default`) {
115115
self.parseOptions = parseOptions
116116
}
117117

118118
/**
119119
Parse a string containing HTML content, calling the events on the handler
120-
supplied. Desite the handler being marked as escaping the parse method will
120+
supplied. Despite the handler being marked as escaping the parse method will
121121
operate synchronously.
122122

123-
Note that should your handler require to use the location information, it
124-
should invoke the `LocationClosure` within the scope of the event call
125-
and not store the `LocationClosure`. You may safely store the returned
126-
`Location` struct out with the scope of event call.
123+
Note that your handler should not retain references to the HTMLSAXParseContext
124+
instance passed to it beyond the scope of the call. Additionally you should only
125+
access the HTMLSAXParseContext instance from the dispatch queue that called your
126+
event handler closure.
127127

128128
- Parameter string: The string containing the HTML content.
129129
- Parameter handler: The event handler closure that will be called during parsing.
@@ -140,13 +140,13 @@ open class HTMLSAXParser {
140140
/**
141141
Parse a data representation of HTML content, calling the events on the handler
142142
supplied. The data will be interpreted using the encoding if supplied. If no
143-
encoding is given then the parser will attempt to detect the encoding. Desite
143+
encoding is given then the parser will attempt to detect the encoding. Despite
144144
the handler being marked as escaping the parse method will operate synchronously.
145145

146-
Note that should your handler require to use the location information, it
147-
should invoke the `LocationClosure` within the scope of the event call
148-
and not store the `LocationClosure`. You may safely store the returned
149-
`Location` struct out with the scope of event call.
146+
Note that your handler should not retain references to the HTMLSAXParseContext
147+
instance passed to it beyond the scope of the call. Additionally you should only
148+
access the HTMLSAXParseContext instance from the dispatch queue that called your
149+
event handler closure.
150150

151151
- Parameter data: The data containing the HTML content.
152152
- Parameter encoding: The character encoding to interpret the data. If no encoding

Tests/HTMLSAXParser/HTMLParserTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class HTMLParserTests: XCTestCase {
108108
try parser.parse(string: "<hello<") { (context, event) in
109109
switch event {
110110
case let .error(message):
111-
print("Error")
111+
print("Error: \(message)")
112112
default:
113113
break
114114
}

0 commit comments

Comments
 (0)