1 /*
2 * examples_code_check.c -- Validate the code in EXAMPLES of the man pages
3 *
4 * Exits with a non-zero value if there is a coding error.
5 *
6 * Copyright (C) 2020-2023 Jon Shallow <supjps-libcoap@jpshallow.com>
7 *
8 * SPDX-License-Identifier: BSD-2-Clause
9 *
10 * This file is part of the CoAP library libcoap. Please see README for terms
11 * of use.
12 */
13
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20 #include <errno.h>
21 #include <string.h>
22
23 #ifdef _WIN32
24 #define GCC_OPTIONS "-I../include"
25 #ifndef WEXITSTATUS
26 #define WEXITSTATUS(v) (v & 0xff)
27 #endif /* WEXITSTATUS */
28 #else /* ! _WIN32 */
29 #define GCC_OPTIONS "\
30 -I../include \
31 -std=c99 \
32 -g \
33 -O2 \
34 -pedantic \
35 -Wall \
36 -Wcast-qual \
37 -Wextra \
38 -Wformat-security \
39 -Winline \
40 -Wmissing-declarations \
41 -Wmissing-prototypes \
42 -Wnested-externs \
43 -Wpointer-arith \
44 -Wshadow \
45 -Wstrict-prototypes \
46 -Wswitch-default \
47 -Wswitch-enum \
48 -Wunused \
49 -Wwrite-strings \
50 -Wno-unused-function \
51 -Wno-unused-but-set-variable \
52 -Werror \
53 "
54 #endif /* ! _WIN32 */
55
56 const char *inline_list[] = {
57 "coap_free(",
58 "coap_malloc(",
59 "coap_encode_var_bytes(",
60 "coap_option_clrb(",
61 "coap_option_getb(",
62 "coap_option_setb(",
63 "coap_read(",
64 "coap_run_once(",
65 "coap_write(",
66 };
67
68 const char *define_list[] = {
69 "coap_string_equal(",
70 "coap_binary_equal(",
71 "coap_log(",
72 "coap_log_emerg(",
73 "coap_log_alert(",
74 "coap_log_crit(",
75 "coap_log_err(",
76 "coap_log_warn(",
77 "coap_log_info(",
78 "coap_log_notice(",
79 "coap_log_debug(",
80 "coap_log_oscore(",
81 "coap_dtls_log(",
82 };
83
84 /* xxx *function */
85 const char *pointer_list[] = {
86 "char ",
87 "coap_addr_info_t ",
88 "coap_async_t ",
89 "coap_attr_t ",
90 "coap_bin_const_t ",
91 "coap_binary_t ",
92 "coap_cache_entry_t ",
93 "coap_cache_key_t ",
94 "coap_endpoint_t ",
95 "coap_context_t ",
96 "coap_fixed_point_t ",
97 "coap_oscore_conf_t ",
98 "coap_optlist_t ",
99 "coap_session_t ",
100 "coap_string_t ",
101 "coap_str_const_t ",
102 "coap_opt_iterator_t ",
103 "coap_opt_t ",
104 "coap_pdu_t ",
105 "coap_resource_t ",
106 "coap_subscription_t ",
107 "coap_tls_version_t ",
108 "coap_uri_t ",
109 "const char ",
110 "const coap_address_t ",
111 "const coap_bin_const_t ",
112 "const coap_pdu_t ",
113 };
114
115 /* xxx function */
116 const char *number_list[] = {
117 "coap_log_t ",
118 "coap_pdu_type_t ",
119 "coap_mid_t ",
120 "coap_pdu_code_t ",
121 "coap_proto_t ",
122 "coap_session_state_t ",
123 "coap_session_type_t ",
124 "int ",
125 "uint16_t ",
126 "uint32_t ",
127 "uint64_t ",
128 "unsigned int ",
129 "size_t ",
130 "const uint8_t ",
131 };
132
133 const char *return_void_list[] = {
134 "coap_option_filter_set",
135 "coap_resource_set_userdata",
136 "coap_cache_set_app_data",
137 };
138
139 int exit_code = 0;
140
141 static char name_list[100][100];
142 static unsigned int name_cnt = 0;
143 static char return_list[100][100];
144 static unsigned int return_cnt = 0;
145 static char man_list[400][100];
146 static unsigned int man_cnt = 0;
147
148 static void
check_synopsis(const char *file)149 check_synopsis(const char *file) {
150 char buffer[1024];
151 char file_name[300];
152 FILE *fpcode;
153 int status;
154
155 snprintf(file_name, sizeof(file_name), "tmp/%s-header.c", file);
156 fpcode = fopen(file_name, "w");
157 if (!fpcode) {
158 fprintf(stderr, "fopen: %s: %s (%d)\n", file_name, strerror(errno), errno);
159 exit_code = 1;
160 return;
161 }
162 fprintf(fpcode, "#include <coap3/coap.h>\n");
163 fprintf(fpcode, "#ifdef __GNUC__\n");
164 fprintf(fpcode, "#define U __attribute__ ((unused))\n");
165 fprintf(fpcode, "#else /* not a GCC */\n");
166 fprintf(fpcode, "#define U\n");
167 fprintf(fpcode, "#endif /* GCC */\n");
168 fprintf(fpcode, "\n");
169 fprintf(fpcode, "#include \"%s.h\"\n", file);
170 fclose(fpcode);
171 file_name[strlen(file_name)-1] = '\000';
172 snprintf(buffer, sizeof(buffer),
173 "gcc " GCC_OPTIONS " -c %sc -o %so",
174 file_name, file_name);
175 status = system(buffer);
176 if (WEXITSTATUS(status)) {
177 exit_code = WEXITSTATUS(status);
178 }
179 return;
180 }
181
182 static void
dump_name_synopsis_mismatch(void)183 dump_name_synopsis_mismatch(void) {
184 unsigned int i;
185
186 for (i = 0; i < name_cnt; i++) {
187 if (name_list[i][0] != '\000') {
188 fprintf(stderr, "NAME: %s not in SYNOPSIS or pointer_list[]\n", name_list[i]);
189 exit_code = 1;
190 }
191 }
192 name_cnt = 0;
193 }
194
195 static void
dump_return_synopsis_mismatch(void)196 dump_return_synopsis_mismatch(void) {
197 unsigned int i;
198
199 for (i = 0; i < return_cnt; i++) {
200 if (return_list[i][0] != '\000') {
201 fprintf(stderr, "SYNOPSIS: %s not in RETURN VALUES\n", return_list[i]);
202 exit_code = 1;
203 }
204 }
205 return_cnt = 0;
206 }
207
208 /*
209 * It is assumed for a definition that a leading * and trailing * have been
210 * added to buffer.
211 */
212 static void
decode_synopsis_definition(FILE *fpheader, const char *buffer, int in_synopsis)213 decode_synopsis_definition(FILE *fpheader, const char *buffer, int in_synopsis) {
214 size_t len;
215 char outbuf[1024];
216 const char *cp;
217 const char *ecp;
218 int is_void_func = 0;
219 int is_number_func = 0;
220 int is_inline_func = 0;
221 int is_struct_func = 0;
222 const char *func_start = NULL;
223 int is_struct = 0;
224 unsigned int i;
225
226 if (strncmp(buffer, "*void ", sizeof("*void ")-1) == 0) {
227 if (strncmp(buffer, "*void *", sizeof("*void *")-1) == 0) {
228 func_start = &buffer[sizeof("*void *")-1];
229 } else {
230 is_void_func = 1;
231 func_start = &buffer[sizeof("*void ")-1];
232 }
233 }
234
235 for (i = 0; i < sizeof(number_list)/sizeof(number_list[0]); i++) {
236 if (strncmp(&buffer[1], number_list[i],
237 strlen(number_list[i])) == 0) {
238 if (buffer[1 + strlen(number_list[i])] == '*') {
239 func_start = &buffer[2 + strlen(number_list[i])];
240 } else {
241 is_number_func = 1;
242 func_start = &buffer[1 + strlen(number_list[i])];
243 }
244 break;
245 }
246 }
247
248 for (i = 0; i < sizeof(pointer_list)/sizeof(pointer_list[0]); i++) {
249 if (strncmp(&buffer[1], pointer_list[i],
250 strlen(pointer_list[i])) == 0) {
251 if (buffer[1 + strlen(pointer_list[i])] == '*') {
252 func_start = &buffer[2 + strlen(pointer_list[i])];
253 } else {
254 is_struct_func = i + 1;
255 func_start = &buffer[1 + strlen(pointer_list[i])];
256 }
257 break;
258 }
259 }
260
261 if (strncmp(buffer, "*struct ", sizeof("*struct ")-1) == 0) {
262 is_struct = 1;
263 func_start = &buffer[sizeof("*struct ")-1];
264 }
265
266 if (func_start) {
267 /* see if COAP_STATIC_INLINE function */
268 for (i = 0; i < sizeof(inline_list)/sizeof(inline_list[0]); i++) {
269 if (strncmp(func_start, inline_list[i],
270 strlen(inline_list[i])) == 0) {
271 is_inline_func = 1;
272 break;
273 }
274 }
275 /* see if #define function */
276 for (i = 0; i < sizeof(define_list)/sizeof(define_list[0]); i++) {
277 if (strncmp(func_start, define_list[i], strlen(define_list[i])) == 0) {
278 break;
279 }
280 }
281 if (i != sizeof(define_list)/sizeof(define_list[0]))
282 goto cleanup;
283 }
284
285 /* Need to include use of U for unused parameters just before comma */
286 cp = buffer;
287 ecp = strchr(cp, ',');
288 if (!ecp)
289 ecp = strchr(cp, ')');
290 outbuf[0] = '\000';
291 while (ecp) {
292 len = strlen(outbuf);
293 if (strncmp(cp, "void", ecp-cp) == 0)
294 snprintf(&outbuf[len], sizeof(outbuf)-len, "%*.*s%c",
295 (int)(ecp-cp), (int)(ecp-cp), cp, *ecp);
296 else
297 snprintf(&outbuf[len], sizeof(outbuf)-len, "%*.*s U%c",
298 (int)(ecp-cp), (int)(ecp-cp), cp, *ecp);
299 cp = ecp+1;
300 if (*cp) {
301 ecp = strchr(cp, ',');
302 if (!ecp)
303 ecp = strchr(cp, ')');
304 } else {
305 ecp = NULL;
306 }
307 }
308 if (*cp) {
309 len = strlen(outbuf);
310 snprintf(&outbuf[len], sizeof(outbuf)-len, "%s", cp);
311 }
312
313 len = strlen(outbuf);
314 if (len > 3 && ((outbuf[len-3] == ';' && outbuf[len-2] == '*') ||
315 (outbuf[len-3] == '*' && outbuf[len-2] == ';'))) {
316 if (is_inline_func) {
317 strcpy(&outbuf[len-3], ";\n");
318 }
319 /* Replace ;* or *; with simple function definition */
320 else if (is_void_func) {
321 strcpy(&outbuf[len-3], "{}\n");
322 } else if (is_number_func) {
323 strcpy(&outbuf[len-3], "{return 0;}\n");
324 } else if (is_struct_func) {
325 snprintf(&outbuf[len-3], sizeof(outbuf)-(len-3),
326 "{%s v; memset(&v, 0, sizeof(v)); return v;}\n",
327 pointer_list[is_struct_func - 1]);
328 } else if (is_struct) {
329 strcpy(&outbuf[len-3], ";\n");
330 } else {
331 strcpy(&outbuf[len-3], "{return NULL;}\n");
332 }
333 }
334 if (outbuf[0] == '*') {
335 fprintf(fpheader, "%s", &outbuf[1]);
336 } else {
337 fprintf(fpheader, "%s", outbuf);
338 }
339 cleanup:
340 if (in_synopsis && func_start) {
341 char *wcp = strchr(func_start, '(');
342
343 if (!wcp && is_struct)
344 wcp = strchr(func_start, ';');
345 if (!wcp) {
346 wcp = strchr(func_start, '\n');
347 if (wcp)
348 *wcp = '\000';
349 fprintf(stderr, "SYNOPSIS: function %s issue\n", func_start);
350 return;
351 }
352 *wcp = '\000';
353 for (i = 0; i < name_cnt; i++) {
354 if (strcmp(name_list[i], func_start) == 0) {
355 name_list[i][0] = '\000';
356 break;
357 }
358 }
359 if (i == name_cnt) {
360 fprintf(stderr, "SYNOPSIS: %s not in NAME\n", func_start);
361 exit_code = 1;
362 }
363 if (!is_void_func && !is_struct) {
364 for (i = 0; i < return_cnt; i++) {
365 if (strcmp(func_start, return_list[i]) == 0) {
366 fprintf(stderr, "SYNOPSIS: %s duplicated\n", func_start);
367 break;
368 }
369 }
370 if (i != return_cnt)
371 return;
372 if (i >= (int)(sizeof(return_list)/sizeof(return_list[0]))) {
373 fprintf(stderr, "SYNOPSIS: %s insufficient space (%u >= %u)\n", func_start,
374 i, (int)(sizeof(return_list)/sizeof(return_list[0])));
375 return;
376 }
377 strncpy(return_list[i], func_start, sizeof(return_list[i])-1);
378 return_cnt++;
379 }
380 }
381 return;
382 }
383
384 int
main(int argc, char *argv[])385 main(int argc, char *argv[]) {
386 DIR *pdir;
387 struct dirent *pdir_ent;
388 char buffer[1024];
389 char man_name[1024];
390 int status;
391 size_t i;
392 int man_missing_first = 1;
393
394 if (argc != 2 && argc != 3) {
395 fprintf(stderr, "usage: %s man_directory [libcoap-3.sym_file]\n", argv[0]);
396 exit(1);
397 }
398
399 pdir = opendir(argv[1]);
400 if (pdir == NULL) {
401 fprintf(stderr, "opendir: %s: %s (%d)\n", argv[1], strerror(errno), errno);
402 exit(1);
403 }
404 if (argc == 3) {
405 FILE *fp = fopen(argv[2], "r");
406 char tmp_name[100];
407
408 if (fp == NULL) {
409 fprintf(stderr, "fopen: %s: %s (%d)\n", argv[2], strerror(errno), errno);
410 exit(1);
411 }
412 while (fgets(tmp_name, sizeof(tmp_name), fp) != NULL) {
413 char *cp = strchr(tmp_name, '\n');
414
415 if (cp)
416 *cp = '\000';
417 if (tmp_name[0]) {
418 strncpy(man_list[man_cnt], tmp_name, sizeof(man_list[man_cnt]));
419 man_cnt++;
420 }
421 if (man_cnt == sizeof(man_list) / sizeof(name_list[0])) {
422 fprintf(stderr, "man_list[] too small (%zd) for entries from %s\n",
423 sizeof(man_list) / sizeof(name_list[0]), argv[2]);
424 exit(1);
425 }
426 }
427 fclose(fp);
428 }
429 if (chdir(argv[1]) == -1) {
430 fprintf(stderr, "chdir: %s: %s (%d)\n", argv[1], strerror(errno), errno);
431 exit(1);
432 }
433 #if defined(WIN32) || defined(__MINGW32__)
434 if (mkdir("tmp") == -1 && errno != EEXIST) {
435 fprintf(stderr, "mkdir: %s: %s (%d)\n", "tmp", strerror(errno), errno);
436 exit(1);
437 }
438 #else /* ! WIN32 && ! __MINGW32__ */
439 if (mkdir("tmp", 0777) == -1 && errno != EEXIST) {
440 fprintf(stderr, "mkdir: %s: %s (%d)\n", "tmp", strerror(errno), errno);
441 exit(1);
442 }
443 #endif /* ! WIN32 && ! __MINGW32__ */
444
445 while ((pdir_ent = readdir(pdir)) != NULL) {
446 if (!strncmp(pdir_ent->d_name, "coap_", sizeof("coap_")-1) &&
447 strstr(pdir_ent->d_name, ".txt.in")) {
448 FILE *fp;
449 int skip = 1;
450 int in_examples = 0;
451 int in_synopsis = 0;
452 int in_functions = 0;
453 int in_name = 0;
454 int in_return = 0;
455 int count = 1;
456 char keep_line[1024] = {0};
457 FILE *fpcode = NULL;
458 FILE *fpheader = NULL;
459 char file_name[300];
460 char *cp;
461
462 fprintf(stderr, "Processing: %s\n", pdir_ent->d_name);
463
464 snprintf(man_name, sizeof(man_name), "%s", pdir_ent->d_name);
465 fp = fopen(man_name, "r");
466 if (fp == NULL) {
467 fprintf(stderr, "fopen: %s: %s (%d)\n", man_name, strerror(errno), errno);
468 continue;
469 }
470 cp = strstr(man_name, ".txt.in");
471 if (cp)
472 *cp = '\000';
473 name_cnt = 0;
474 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
475 if (strncmp(buffer, "NAME", sizeof("NAME")-1) == 0) {
476 in_name = 1;
477 continue;
478 }
479 if (strncmp(buffer, "SYNOPSIS", sizeof("SYNOPSIS")-1) == 0) {
480 in_name = 0;
481 in_synopsis = 1;
482 snprintf(file_name, sizeof(file_name), "tmp/%s.h",
483 pdir_ent->d_name);
484 fpheader = fopen(file_name, "w");
485 if (!fpheader) {
486 fprintf(stderr, "fopen: %s: %s (%d)\n", file_name,
487 strerror(errno), errno);
488 goto bad;
489 }
490 continue;
491 }
492 if (strncmp(buffer, "FUNCTIONS", sizeof("FUNCTIONS")-1) == 0) {
493 in_synopsis = 0;
494 dump_name_synopsis_mismatch();
495 in_functions = 1;
496 snprintf(file_name, sizeof(file_name), "tmp/%s.h",
497 pdir_ent->d_name);
498 fpheader = fopen(file_name, "w");
499 if (!fpheader) {
500 fprintf(stderr, "fopen: %s: %s (%d)\n", file_name,
501 strerror(errno), errno);
502 goto bad;
503 }
504 continue;
505 }
506 if (strncmp(buffer, "DESCRIPTION", sizeof("DESCRIPTION")-1) == 0) {
507 in_synopsis = 0;
508 dump_name_synopsis_mismatch();
509 if (fpheader)
510 fclose(fpheader);
511 fpheader = NULL;
512 check_synopsis(pdir_ent->d_name);
513 continue;
514 }
515 if (strncmp(buffer, "RETURN VALUES", sizeof("RETURN VALUES")-1) == 0 ||
516 strncmp(buffer, "RETURN VALUE", sizeof("RETURN VALUE")-1) == 0) {
517 if (in_functions) {
518 if (fpheader)
519 fclose(fpheader);
520 fpheader = NULL;
521 check_synopsis(pdir_ent->d_name);
522 }
523 in_name = 0;
524 in_synopsis = 0;
525 dump_name_synopsis_mismatch();
526 in_functions = 0;
527 in_return = 1;
528 continue;
529 }
530 if (strncmp(buffer, "TESTING", sizeof("TESTING")-1) == 0) {
531 if (in_functions) {
532 if (fpheader)
533 fclose(fpheader);
534 fpheader = NULL;
535 check_synopsis(pdir_ent->d_name);
536 }
537 in_name = 0;
538 in_synopsis = 0;
539 in_functions = 0;
540 in_return = 0;
541 continue;
542 }
543 if (strncmp(buffer, "EXAMPLES", sizeof("EXAMPLES")-1) == 0 ||
544 strncmp(buffer, "EXAMPLE", sizeof("EXAMPLE")-1) == 0) {
545 if (in_functions) {
546 if (fpheader)
547 fclose(fpheader);
548 fpheader = NULL;
549 check_synopsis(pdir_ent->d_name);
550 }
551 in_name = 0;
552 in_synopsis = 0;
553 in_return = 0;
554 dump_name_synopsis_mismatch();
555 dump_return_synopsis_mismatch();
556 in_functions = 0;
557 in_examples = 1;
558 continue;
559 }
560 if (strncmp(buffer, "SEE ALSO", sizeof("SEE ALSO")-1) == 0) {
561 if (in_functions) {
562 if (fpheader)
563 fclose(fpheader);
564 fpheader = NULL;
565 check_synopsis(pdir_ent->d_name);
566 }
567 in_name = 0;
568 in_synopsis = 0;
569 in_return = 0;
570 dump_name_synopsis_mismatch();
571 dump_return_synopsis_mismatch();
572 in_functions = 0;
573 in_examples = 1;
574 break;
575 }
576
577 if (in_name) {
578 /* Working in NAME section */
579 if (buffer[0] == '\n')
580 continue;
581 if (buffer[0] == '-')
582 continue;
583 cp = strchr(buffer, '\n');
584 if (cp)
585 *cp = '\000';
586 cp = strchr(buffer, ',');
587 if (cp)
588 *cp = '\000';
589 if (strcmp(man_name, buffer) == 0)
590 continue;
591 if (strlen(buffer) >= sizeof(name_list[0])) {
592 fprintf(stderr, "NAME: %s is too long (%u >= %u)\n", buffer,
593 (int)strlen(buffer), (int)sizeof(name_list[0]));
594 continue;
595 }
596 for (i = 0; i < name_cnt; i++) {
597 if (strncmp(buffer, name_list[i], sizeof(name_list[i])) == 0) {
598 fprintf(stderr, "NAME: %s duplicated\n", buffer);
599 break;
600 }
601 }
602 if (i != name_cnt)
603 continue;
604 if (i >= (int)(sizeof(name_list)/sizeof(name_list[0]))) {
605 fprintf(stderr, "NAME: %s insufficient space (%zu >= %u)\n", buffer,
606 i, (int)(sizeof(name_list)/sizeof(name_list[0])));
607 continue;
608 }
609 memcpy(name_list[i], buffer, sizeof(name_list[i])-1);
610 name_list[i][sizeof(name_list[i])-1] = '\000';
611 name_cnt++;
612 for (i = 0; i < man_cnt; i++) {
613 if (strncmp(man_list[i], buffer, sizeof(man_list[i])) == 0) {
614 man_list[i][0] = '\000';
615 break;
616 }
617 }
618 }
619
620 if (in_synopsis) {
621 /* Working in SYNOPSIS section */
622 size_t len;
623 char outbuf[1024];
624
625 if (buffer[0] == '*' && buffer[1] != '#') {
626 /* Start of a new entry */
627 snprintf(outbuf, sizeof(outbuf), "%s", buffer);
628 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
629 if (buffer[0] == '\n') {
630 break;
631 }
632 len = strlen(outbuf);
633 outbuf[len-1] = ' ';
634 snprintf(&outbuf[len], sizeof(outbuf) - len, "%s", buffer);
635 }
636 decode_synopsis_definition(fpheader, outbuf, 1);
637 continue;
638 }
639 if (buffer[0] == '\n')
640 continue;
641 if (buffer[0] == '-')
642 continue;
643 if (buffer[0] == 'F') {
644 /* For specific ..... is the end */
645 in_synopsis = 0;
646 if (fpheader)
647 fclose(fpheader);
648 fpheader = NULL;
649 check_synopsis(pdir_ent->d_name);
650 continue;
651 }
652 }
653
654 if (in_functions) {
655 /* Working in FUNCTIONS section */
656 size_t len;
657 char outbuf[1024];
658
659 if (strncmp(buffer, "Prototype:\n", sizeof("Prototype:\n")-1)== 0) {
660 /* Start of a new entry */
661 outbuf[0] = '*';
662 outbuf[1] = '\000';
663 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
664 if (buffer[0] == '\n') {
665 break;
666 }
667 len = strlen(outbuf);
668 if (outbuf[len-1] == '\n')
669 outbuf[len-1] = ' ';
670 snprintf(&outbuf[len], sizeof(outbuf) - len, "%s", buffer);
671 }
672 len = strlen(outbuf);
673 len--;
674 snprintf(&outbuf[len], sizeof(outbuf) - len, "*\n");
675 decode_synopsis_definition(fpheader, outbuf, 0);
676 continue;
677 }
678 }
679
680 if (in_return) {
681 cp = strstr(buffer, "*coap_");
682 while (cp) {
683 char *ecp = strchr(cp+1, '*');
684
685 if (!ecp) {
686 fprintf(stderr, "RETURN VALUES: %s undecipherable\n", cp + 1);
687 exit_code = 1;
688 break;
689 }
690 *ecp = '\000';
691 for (i = 0; i < return_cnt; i++) {
692 if (strcmp(cp+1, return_list[i]) == 0) {
693 return_list[i][0] = '\000';
694 break;
695 }
696 }
697 if (i == return_cnt) {
698 for (i = 0;
699 i < sizeof(return_void_list)/sizeof(return_void_list[0]);
700 i++) {
701 if (strcmp(cp+1, return_void_list[i]) == 0)
702 break;
703 }
704 if (i == sizeof(return_void_list)/sizeof(return_void_list[0])) {
705 fprintf(stderr, "RETURN VALUES: %s not defined in SYNOPSIS\n", cp + 1);
706 exit_code = 1;
707 }
708 }
709 cp = strstr(ecp+1, "*coap_");
710 }
711 }
712
713 if (!in_examples) {
714 continue;
715 }
716 /* Working in EXAMPLES section */
717 if (skip) {
718 if (!strcmp(buffer, "----\n") || !strcmp(buffer, "---\n") ||
719 !strcmp(buffer, "--\n") || !strcmp(buffer, "-\n") ||
720 !strcmp(buffer, "-----\n")) {
721 /* Found start of code */
722 if (strcmp(buffer, "----\n")) {
723 fprintf(stderr,
724 "Unexpected start of code '%.*s' - expected ----\n",
725 (int)strlen(buffer)-1, buffer);
726 }
727 snprintf(file_name, sizeof(file_name), "tmp/%s-%d.c",
728 pdir_ent->d_name, count++);
729 fpcode = fopen(file_name, "w");
730 if (!fpcode) {
731 fprintf(stderr, "fopen: %s: %s (%d)\n", file_name,
732 strerror(errno), errno);
733 goto bad;
734 } else {
735 fprintf(fpcode, "/* %s */\n", keep_line);
736 }
737 skip = 0;
738 fprintf(stderr, "Processing: %s EXAMPLE - '%d'\n",
739 pdir_ent->d_name,
740 count-1);
741 } else if (buffer[0] == '*') {
742 snprintf(keep_line, sizeof(keep_line), "%s", buffer);
743 }
744 continue;
745 }
746 if (!strcmp(buffer, "----\n") || !strcmp(buffer, "---\n") ||
747 !strcmp(buffer, "--\n") || !strcmp(buffer, "-\n") ||
748 !strcmp(buffer, "-----\n")) {
749 /* Found end of code */
750
751 skip = 1;
752 if (fpcode)
753 fclose(fpcode);
754 keep_line[0] = '\000';
755 file_name[strlen(file_name)-1] = '\000';
756 snprintf(buffer, sizeof(buffer),
757 "gcc " GCC_OPTIONS " -c %sc -o %so",
758 file_name, file_name);
759 status = system(buffer);
760 if (WEXITSTATUS(status)) {
761 exit_code = WEXITSTATUS(status);
762 }
763 continue;
764 }
765 if (fpcode) {
766 if (strstr(buffer, "LIBCOAP_API_VERSION")) {
767 fprintf(fpcode, "#include <coap3/coap.h>\n");
768 fprintf(fpcode, "#ifdef __GNUC__\n");
769 fprintf(fpcode, "#define U __attribute__ ((unused))\n");
770 fprintf(fpcode, "#else /* not a GCC */\n");
771 fprintf(fpcode, "#define U\n");
772 fprintf(fpcode, "#endif /* GCC */\n");
773 fprintf(fpcode, "#include \"%s.h\"\n", pdir_ent->d_name);
774 fprintf(fpcode, "#undef U\n");
775 continue;
776 }
777 fprintf(fpcode, "%s", buffer);
778 }
779 }
780 bad:
781 fclose(fp);
782 }
783 }
784 closedir(pdir);
785 for (i = 0; i < man_cnt; i++) {
786 if (man_list[i][0]) {
787 if (man_missing_first) {
788 man_missing_first = 0;
789 fprintf(stderr, "\nMissing man pages (for reference only)\n");
790 }
791 fprintf(stderr, "%s\n", man_list[i]);
792 }
793 }
794 exit(exit_code);
795 }
796