Skip to content

Commit 0818423

Browse files
committed
Rewrite macro 'with-curl-easy'
Use a variable to initialize the curl handler, instead of creating the class inside the macro. This allows to subclass `<curl-easy>`. with-curl-easy(curl = make(<curl-easy>)) curl.curl-url := "http://example.com"; curl.curl-verbose := #f; curl-easy-perform(curl); end; Now is possible to pass options to the macro. It makes less verbose the code. with-curl-easy(curl = make(<curl-easy>), url = "http://example.com", verbose = #f) curl-easy-perform(curl) end;
1 parent 1a8f655 commit 0818423

13 files changed

+161
-104
lines changed

documentation/source/introduction.rst

+44-20
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ In libcurl, you create a handle using `curl_easy_init
3434
<https://curl.se/libcurl/c/curl_easy_init.html>`_. In the Open Dylan
3535
wrapper, you create an object of the :class:`<curl-easy>` class.
3636

37-
.. code-block:: c
37+
.. code-block:: C
3838
:caption: C example
3939
4040
CURL *curl = curl_easy_init();
@@ -43,17 +43,23 @@ wrapper, you create an object of the :class:`<curl-easy>` class.
4343
curl_easy_cleanup(curl);
4444
}
4545
46+
The macro :macro:`with-curl-easy` handles both initialization and
47+
automatic cleanup when it is no longer accessible. If initialization
48+
fails, a :class:`<curl-init-error>` exception is raised.
49+
4650
.. code-block:: dylan
4751
:caption: Dylan example
4852
49-
with-curl-easy (curl)
50-
...
53+
block ()
54+
with-curl-easy (curl = make(<curl-easy>))
55+
// perform request
56+
// gather information about the request
57+
end;
58+
exception (err :: <curl-init-error>)
59+
format-err("Error initializing curl: %s\n",
60+
err.curl-error-message)
5161
end;
5262
53-
The macro :macro:`with-curl-easy` handles both initialization and
54-
automatic cleanup when it is no longer accessible. If initialization
55-
fails, a :class:`<curl-init-error>` exception is raised.
56-
5763
Setting Parameters
5864
^^^^^^^^^^^^^^^^^^
5965

@@ -87,19 +93,36 @@ handled either immediately at the point of the operation or deferred
8793
to another method for centralized error handling.
8894

8995
.. code-block:: dylan
90-
:caption: In Dylan errors can be captured in a block somewhere.
96+
:caption: In Dylan errors can be captured in a block.
9197
92-
with-curl-easy (curl)
93-
curl.curl-url := "https://example.com";
94-
end;
98+
block ()
99+
with-curl-easy (curl = make(<curl-easy>))
100+
curl.curl-url := "https://example.com";
101+
// perform request
102+
// gather information
103+
end;
104+
exception (err :: <curl-option-error>)
105+
format-err("Error setting option: %s\n",
106+
err.curl-error-message)
107+
end block;
108+
109+
If you need to set a lot of options, you can pass them to the
110+
:macro:`with-curl-easy` with less verbosity.
95111

96-
...
112+
.. code-block:: dylan
97113
98114
block ()
99-
// somewhere in the code an option is incorrect
100-
// and is handled here
115+
with-curl-easy (curl = make(<curl-easy>),
116+
url = "https://example.org",
117+
ssl-verifypeer = #f,
118+
ssl-verifyhost = 1,
119+
ca-cache-timeout = 604800)
120+
// perform request
121+
// gather information
122+
end with-curl-easy;
101123
exception (err :: <curl-option-error>)
102-
format-err("Error setting option: %s\n", err.curl-error-message)
124+
format-err("Error setting option: %s\n",
125+
err.curl-error-message)
103126
end block;
104127
105128
Performing the Request
@@ -125,11 +148,12 @@ In Opendylan :func:`curl-perform` raises a
125148
.. code-block:: dylan
126149
:caption: Dylan example
127150
128-
block ()
151+
block ()
129152
curl-easy-perform(curl);
130153
format-out("Request completed successfully.\n")
131154
exception (err :: <curl-perform-error>)
132-
format-err("Curl failed: %s\n", curl.curl-error-message)
155+
format-err("Curl failed: %s\n",
156+
curl.curl-error-message)
133157
end block;
134158
135159
Retrieving Information
@@ -166,11 +190,11 @@ wrapper, you access the information directly using property syntax.
166190
:caption: Dylan Example
167191
168192
block ()
169-
with-curl-easy (curl)
170-
curl.curl-url := "https://example.com/";
193+
with-curl-easy (curl = make(<curl>),
194+
url = "https://example.com/")
171195
curl-easy-perform(curl);
172196
format-out("Time: %d", curl.total-time)
173-
end
197+
end;
174198
exception (err :: <curl-info-error>)
175199
format-err("curl easy getinfo failed: %s\n",
176200
err.curl-error-message)

documentation/source/reference.rst

+20-6
Original file line numberDiff line numberDiff line change
@@ -153,22 +153,36 @@ Macros
153153

154154
:macrocall:
155155
.. parsed-literal::
156-
with-curl-easy (*name*) body end
156+
with-curl-easy (*variable* = *expression*, *option* = *value*, ...) body end
157157
158158
:example:
159159

160160
.. code-block:: dylan
161+
:caption: Simple macro form
161162
162-
with-curl-easy (curl)
163-
curl.url := "example.com";
164-
curl-easy-perform(curl);
165-
end;
163+
with-curl-easy (curl = make(<curl-easy>))
164+
curl.curl-url := "http://example.com";
165+
curl-easy-perform(curl);
166+
end;
167+
168+
:example:
169+
170+
.. code-block:: dylan
171+
:caption: Passing options to macro
172+
173+
with-curl-easy (curl = make(<curl-easy>),
174+
url = "http://example.com",
175+
verbose = #t)
176+
curl-easy-perform(curl);
177+
end;
166178
167179
:signals:
168180

169181
:class:`<curl-init-error>` if the curl handle could not be
170182
initialized.
171183

184+
:class:`<curl-option-error>` if an option is incorrect.
185+
172186
:discussion:
173187

174188
This macro is more or less equivalent to:
@@ -214,7 +228,7 @@ Macros
214228
215229
with-curl-global ($curl-global-all)
216230
with-curl-easy (curl)
217-
curl.url := "https://example.com";
231+
curl.curl-url := "https://example.com";
218232
curl-easy-perform(curl);
219233
// do staff
220234
end;

src/curl-easy-module.dylan

+5-1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ define module curl-easy
342342
$curl-progress-callback;
343343

344344
// Curl options
345+
create
346+
*curl-options*;
345347

346348
create
347349
<curlopt-stringpoint>,
@@ -731,9 +733,11 @@ end module curl-easy;
731733

732734
define module curl-easy-impl
733735
use curl-easy;
734-
736+
735737
use common-dylan;
736738
use c-ffi;
739+
use format;
740+
use format-out;
737741

738742
export
739743
*curl-library-initialized?*;

src/curl-easy.dylan

+25-11
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,8 @@ define macro with-curl-global
524524
block ()
525525
?body
526526
cleanup
527-
curl-library-cleanup()
528-
end block }
527+
curl-library-cleanup()
528+
end block }
529529
end macro;
530530

531531
define C-function curl-slist-append
@@ -548,18 +548,28 @@ define C-function curl-version
548548
c-name: "curl_version";
549549
end C-function;
550550

551+
define macro set-curl-options
552+
{ set-curl-options (?curl:variable) }
553+
=> { ?curl }
554+
{ set-curl-options (?curl:variable, ?option:name = ?value:expression, ?more:*) }
555+
=> { "curl-" ## ?option ## "-setter"(?value, ?curl);
556+
set-curl-options(?curl, ?more) }
557+
end macro set-curl-options;
558+
551559
define macro with-curl-easy
552-
{ with-curl-easy (?curl:name) ?body:body end }
553-
=> { let ?curl = #f;
560+
{ with-curl-easy (?curl:variable = ?handler:expression, ?options:*) ?body:body end }
561+
=> { let _curl = #f;
554562
block ()
555-
?curl := make(<curl-easy>);
556-
?body
557-
cleanup
558-
if (?curl)
559-
curl-easy-cleanup(?curl)
560-
end;
563+
_curl := ?handler;
564+
let ?curl :: <curl-easy> = _curl;
565+
set-curl-options(?curl, ?options);
566+
?body
567+
cleanup
568+
if (_curl)
569+
curl-easy-cleanup(_curl)
570+
end;
561571
end block }
562-
end macro;
572+
end macro with-curl-easy;
563573

564574
///////////////////////////////////////////////////////////////////////////////
565575
//
@@ -884,11 +894,15 @@ define constant $curlopttype-boolean = $curlopttype-long;
884894
//
885895
//////////////////////////////////////////////////////////////////////////////
886896

897+
define variable *curl-options* = 0;
898+
887899
define macro curlopt-definer
888900
{ define curlopt ?type:name ?id:name = ?number:expression }
889901
=> { define constant "$curlopt-" ## ?id
890902
= "$curlopttype-" ## ?type + ?number;
891903

904+
*curl-options* := *curl-options* + 1;
905+
892906
define method "curl-" ## ?id ## "-setter"
893907
(option :: "<curlopt-" ## ?type ## ">", curl :: <curl-easy>)
894908
=> (option :: "<curlopt-" ## ?type ## ">")

src/library.dylan

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ define library dylan-curl
77

88
use common-dylan;
99
use c-ffi;
10+
use io;
1011
end library;

tests/test-chkspeed.dylan

+11-11
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ define test test-chkspeed (tags: #("io", "slow"))
1919
0
2020
end;
2121
let url = "http://ipv4.download.thinkbroadband.com";
22+
let filename = "5MB.zip";
2223
block ()
2324
with-curl-global ($curl-global-default)
24-
with-curl-easy (curl)
25-
let filename = "5MB.zip";
26-
curl.curl-url := concatenate(url, "/", filename);
27-
curl.curl-useragent := "dylan-curl-speedchecker/1.0";
28-
curl.curl-writefunction := $curl-write-callback;
29-
curl.curl-xferinfofunction := $curl-progress-callback;
30-
curl.curl-noprogress := #f;
31-
with-open-file (stream = filename, direction: #"output", if-exists: #"replace")
32-
dynamic-bind(*curl-write-callback* = handle-download)
33-
dynamic-bind(*curl-progress-callback* = progress-callback)
34-
register-c-dylan-object(stream);
25+
with-curl-easy (curl = make(<curl-easy>),
26+
url = concatenate(url, "/", filename),
27+
useragent = "dylan-curl-speedchecker/1.0",
28+
writefunction = $curl-write-callback,
29+
xferinfofunction = $curl-progress-callback,
30+
noprogress = #f)
31+
with-open-file (stream = filename, direction: #"output", if-exists: #"replace")
32+
dynamic-bind(*curl-write-callback* = handle-download)
33+
dynamic-bind(*curl-progress-callback* = progress-callback)
34+
register-c-dylan-object(stream);
3535
curl.curl-writedata := export-c-dylan-object(stream);
3636
curl-easy-perform(curl);
3737
unregister-c-dylan-object(stream);

tests/test-debug-callback.dylan

+5-5
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ end function;
3636
define test test-debug-callback (tags: #("io"))
3737
block ()
3838
with-curl-global ($curl-global-default)
39-
with-curl-easy (curl)
39+
with-curl-easy (curl = make(<curl-easy>),
40+
url = "https://example.com/",
41+
verbose = #t, // verbose to use debug-callback
42+
debugfunction = $curl-debug-callback)
4043
dynamic-bind (*curl-debug-callback* = dump-debug-callback)
41-
curl.curl-url := "https://example.com/";
42-
curl.curl-verbose := #t; // verbose to use debug-callback
43-
curl.curl-debugfunction := $curl-debug-callback;
44-
curl-easy-perform(curl);
44+
curl-easy-perform(curl);
4545
end dynamic-bind;
4646
assert-true(#t);
4747
end with-curl-easy;

tests/test-escape-unescape.dylan

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Copyright: Copyright (C) 2025, Dylan Hackers. All rights reserved.
44

55
define test test-curl-easy-escape ()
66
with-curl-global ($curl-global-default)
7-
with-curl-easy (curl)
7+
with-curl-easy (curl = make(<curl-easy>))
88
let data = "data to convert";
99
let expected = "data%20to%20convert";
1010
let output1 = curl-easy-escape(curl, data, length: 15);
@@ -17,18 +17,18 @@ end test;
1717

1818
define test test-curl-easy-unescape ()
1919
with-curl-global ($curl-global-default)
20-
with-curl-easy (curl)
20+
with-curl-easy (curl = make(<curl-easy>))
2121
let escaped = "%63%75%72%6c";
2222
let expected = "curl";
2323
let expected-length = 4;
2424
let (decoded, decoded-length)
25-
= curl-easy-unescape(curl, escaped, length: 12);
25+
= curl-easy-unescape(curl, escaped, length: 12);
2626
assert-equal(expected, decoded,
2727
"Decoded string is as expected");
2828
assert-equal(expected-length, decoded-length,
2929
"Decoded length is as expected");
3030
let (decoded, decoded-length)
31-
= curl-easy-unescape(curl, escaped);
31+
= curl-easy-unescape(curl, escaped);
3232
assert-equal(expected, decoded);
3333
assert-equal(expected-length, decoded-length);
3434
end with-curl-easy;

tests/test-get-simple-http-page.dylan

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ Copyright: Copyright (C) 2025, Dylan Hackers. All rights reserved.
66

77
define test test-get-simple-http-page (tags: #("io"))
88
block ()
9-
with-curl-global($curl-global-default)
10-
with-curl-easy (curl)
11-
curl.curl-url := "https://example.com/";
12-
curl.curl-followlocation := 1;
13-
curl-easy-perform(curl);
14-
assert-true(#t);
15-
end;
16-
end;
9+
with-curl-global ($curl-global-default)
10+
with-curl-easy (curl = make(<curl-easy>),
11+
url = "https://example.com",
12+
followlocation = 1)
13+
curl-easy-perform(curl);
14+
assert-true(#t);
15+
end with-curl-easy;
16+
end with-curl-global;
1717
exception (err :: <curl-error>)
1818
format-out("Curl failed: %s\n", err.curl-error-message);
1919
end block;

tests/test-getinfo-cainfo.dylan

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ Copyright: Copyright (C) 2025, Dylan Hackers. All rights reserved.
55
define test test-getinfo-cainfo ()
66
block ()
77
with-curl-global ($curl-global-default)
8-
with-curl-easy (curl)
9-
curl.curl-cainfo := "/etc/ssl/certs/SecureTrust_CA.pem";
10-
let cainfo = curl.curl-cainfo;
11-
format-out("default ca info path: '%s'\n", cainfo);
12-
assert-true(#t);
8+
with-curl-easy (curl = make(<curl-easy>),
9+
cainfo = "/etc/ssl/certs/SecureTrust_CA.pem")
10+
let cainfo = curl.curl-cainfo;
11+
format-out("default ca info path: '%s'\n", cainfo);
12+
assert-true(#t);
1313
end with-curl-easy;
1414
end with-curl-global;
1515
exception (err :: <curl-error>)

0 commit comments

Comments
 (0)