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 56const 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 68const 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 */ 85const 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 */ 116const 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 133const char *return_void_list[] = { 134 "coap_option_filter_set", 135 "coap_resource_set_userdata", 136 "coap_cache_set_app_data", 137}; 138 139int exit_code = 0; 140 141static char name_list[100][100]; 142static unsigned int name_cnt = 0; 143static char return_list[100][100]; 144static unsigned int return_cnt = 0; 145static char man_list[400][100]; 146static unsigned int man_cnt = 0; 147 148static void 149check_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 182static void 183dump_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 195static void 196dump_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 */ 212static void 213decode_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 } 339cleanup: 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 384int 385main(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 } 780bad: 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