Skip to content

Commit 1028ef1

Browse files
committed
add sml_error function pointer, allow user to intercept error messages
1 parent 8ca68af commit 1028ef1

10 files changed

Lines changed: 120 additions & 12 deletions

File tree

sml/include/sml/sml_shared.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,16 @@ int sml_buf_optional_is_skipped(sml_buffer *buf);
109109
// Prints arbitrarily byte string to stdout with printf
110110
void hexdump(unsigned char *buffer, size_t buffer_len);
111111

112+
// Allow user to intercept error messages
113+
extern void (*sml_error)(const char *format, ...)
114+
// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
115+
__attribute__((format(printf, 1, 2)));
116+
117+
// default sml_error function, prints message to stderr as before
118+
void sml_error_default(const char *format, ...)
119+
// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
120+
__attribute__((format(printf, 1, 2)));
121+
112122
#ifdef __cplusplus
113123
}
114124
#endif

sml/src/sml_file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ sml_file *sml_file_parse(unsigned char *buffer, size_t buffer_len) {
4949
msg = sml_message_parse(buf);
5050

5151
if (sml_buf_has_errors(buf)) {
52-
fprintf(stderr, "libsml: warning: could not read the whole file\n");
52+
sml_error("warning: could not read the whole file");
5353
break;
5454
}
5555

sml/src/sml_message.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ sml_message_body *sml_message_body_parse(sml_buffer *buf) {
209209
msg_body->data = sml_attention_response_parse(buf);
210210
break;
211211
default:
212-
fprintf(stderr, "libsml: error: message type %04X not yet implemented\n", *(msg_body->tag));
212+
sml_error("error: message type %04X not yet implemented", *(msg_body->tag));
213213
break;
214214
}
215215

@@ -279,8 +279,7 @@ void sml_message_body_write(sml_message_body *message_body, sml_buffer *buf) {
279279
sml_attention_response_write((sml_attention_response *)message_body->data, buf);
280280
break;
281281
default:
282-
fprintf(stderr, "libsml: error: message type %04X not yet implemented\n",
283-
*(message_body->tag));
282+
sml_error("error: message type %04X not yet implemented", *(message_body->tag));
284283
break;
285284
}
286285
}
@@ -334,8 +333,7 @@ void sml_message_body_free(sml_message_body *message_body) {
334333
sml_attention_response_free((sml_attention_response *)message_body->data);
335334
break;
336335
default:
337-
fprintf(stderr, "libsml: NYI: %s for message type %04X\n", __func__,
338-
*(message_body->tag));
336+
sml_error("NYI: %s for message type %04X", __func__, *(message_body->tag));
339337
break;
340338
}
341339
sml_number_free(message_body->tag);

sml/src/sml_shared.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,29 @@
1717
// along with libSML. If not, see <http://www.gnu.org/licenses/>.
1818

1919
#include <sml/sml_shared.h>
20+
#include <stdarg.h>
2021
#include <stdio.h>
2122
#include <string.h>
2223

24+
void (*sml_error)(const char *format, ...);
25+
26+
void sml_error_default(const char *format, ...) {
27+
va_list args;
28+
va_start(args, format);
29+
30+
char *format2 = malloc(9 + strlen(format) + 1 + 1);
31+
strcpy(format2, "libsml: ");
32+
strcat(format2, format);
33+
strcat(format2, "\n");
34+
35+
vfprintf(stderr, format2, args);
36+
37+
free(format2);
38+
}
39+
40+
// http://www.faqs.org/docs/Linux-HOWTO/Program-Library-HOWTO.html#INIT-AND-CLEANUP
41+
void __attribute__((constructor)) sml_init() { sml_error = *sml_error_default; }
42+
2343
int sml_buf_get_next_length(sml_buffer *buf) {
2444
int length = 0;
2545

sml/src/sml_transport.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ size_t sml_read(int fd, fd_set *set, unsigned char *buffer, size_t len) {
4747
if (r < 0) {
4848
if (errno == EINTR || errno == EAGAIN)
4949
continue; // should be ignored
50-
fprintf(stderr, "libsml: sml_read(): read error\n");
50+
sml_error("sml_read(): read error");
5151
return 0;
5252
}
5353
tr += r;
@@ -68,7 +68,7 @@ size_t sml_transport_read(int fd, unsigned char *buffer, size_t max_len) {
6868

6969
if (max_len < 8) {
7070
// prevent buffer overflow
71-
fprintf(stderr, "libsml: error: sml_transport_read(): passed buffer too small!\n");
71+
sml_error("error: sml_transport_read(): passed buffer too small!");
7272
return 0;
7373
}
7474

@@ -104,7 +104,7 @@ size_t sml_transport_read(int fd, unsigned char *buffer, size_t max_len) {
104104
return len;
105105
} else {
106106
// don't read other escaped sequences yet
107-
fprintf(stderr, "libsml: error: unrecognized sequence\n");
107+
sml_error("error: unrecognized sequence");
108108
return 0;
109109
}
110110
}

sml/src/sml_tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ void sml_proc_par_value_write(sml_proc_par_value *value, sml_buffer *buf) {
282282
sml_time_write(value->data.time, buf);
283283
break;
284284
default:
285-
fprintf(stderr, "libsml: error: unknown tag in %s\n", __func__);
285+
sml_error("error: unknown tag in %s", __func__);
286286
}
287287
}
288288

sml/src/sml_value.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ double sml_value_to_double(sml_value *value) {
134134
break;
135135

136136
default:
137-
fprintf(stderr, "libsml: error: unknown type %d in %s\n", value->type, __func__);
137+
sml_error("error: unknown type %d in %s", value->type, __func__);
138138
return 0;
139139
}
140140
}

test/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ OBJS = \
2424
src/sml_file_test.o \
2525
src/sml_open_request_test.o \
2626
src/sml_get_profile_pack_request_test.o \
27-
src/sml_message_test.o
27+
src/sml_message_test.o \
28+
src/sml_error_test.o
2829

2930
test_run: libsml test
3031
@./test

test/src/sml_error_test.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2020 volkszaehler.org
2+
//
3+
// This file is part of libSML.
4+
//
5+
// libSML is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// libSML is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with libSML. If not, see <http://www.gnu.org/licenses/>.
17+
18+
#include "../unity/unity_fixture.h"
19+
#include "test_helper.h"
20+
#include <sml/sml_shared.h>
21+
22+
#include <unistd.h>
23+
24+
TEST_GROUP(sml_error);
25+
26+
TEST_SETUP(sml_error) { }
27+
28+
TEST_TEAR_DOWN(sml_error) { }
29+
30+
TEST(sml_error, default) {
31+
char *tmpfile="./test_sml_error.tmp"; // FIXME: should not be hardcoded
32+
char *test_string="this is a test";
33+
char *expected_output="libsml: this is a test\n";
34+
35+
FILE *capture = fopen(tmpfile, "w");
36+
TEST_ASSERT_NOT_NULL(capture);
37+
int stderr_backup=dup(2); // duplicate old stderr so it won't be closed
38+
dup2(fileno(capture),2); // assign capture-file to stderr
39+
40+
sml_error(test_string);
41+
42+
fclose(capture);
43+
dup2(stderr_backup,2); // restore stderr
44+
close(stderr_backup); // discard backup
45+
46+
size_t len=strlen(expected_output)+1;
47+
char *buf=malloc(len);
48+
49+
capture = fopen(tmpfile, "r");
50+
size_t got=fread(buf,1,len-1,capture);
51+
*(buf+got)=0; // add zero termination
52+
//fprintf(stderr,"got: `%s`\n\n",buf);
53+
fclose(capture);
54+
unlink(tmpfile);
55+
56+
TEST_ASSERT_EQUAL(0, strcmp(expected_output,buf));
57+
58+
free(buf);
59+
}
60+
61+
const char *msg=NULL;
62+
void my_sml_error(const char *format, ... ){
63+
msg=format;
64+
}
65+
66+
TEST(sml_error, custom) {
67+
char *test_string="this is a test";
68+
sml_error = my_sml_error;
69+
sml_error(test_string,1,2,3);
70+
sml_error = sml_error_default;
71+
TEST_ASSERT_NOT_NULL(msg);
72+
TEST_ASSERT_EQUAL(0, strcmp(msg,test_string));
73+
}
74+
75+
TEST_GROUP_RUNNER(sml_error) {
76+
RUN_TEST_CASE(sml_error, default);
77+
RUN_TEST_CASE(sml_error, custom);
78+
}

test/test_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ static void runAllTests() {
3535
RUN_TEST_GROUP(sml_get_profile_pack_request);
3636
RUN_TEST_GROUP(sml_message);
3737
RUN_TEST_GROUP(sml_file);
38+
RUN_TEST_GROUP(sml_error);
3839
}
3940

4041
int main(int argc, char * argv[]) {

0 commit comments

Comments
 (0)