mirror of
https://github.com/obgm/libcoap.git
synced 2026-11-09 02:32:53 +03:00
Set up coap_log_t as an enum, using syslog variable names prefixed by COAP_. Add function coap_dtls_log() for logging information from (D)TLS libraries. Update the log output to have use Lower-case variants for the logging levels to indicate that output is from the (D)TLS library instead of the CoAP library. (D)TLS libraries updated to be consistent in the usage of coap_dtls_set_log_level()/coap_dtls_get_log_level(). Add in coap_log_emerg(), coap_log_alert() etc. as wrappers to reduce the line length required for log entries. Updating all the coap_log() functions to no longer use syslog variants will be a part of a separate PR. Added in the "-V" option to the examples, with an initial default of COAP_LOG_ERR, separating out the CoAP and (D)TLS logging levels. Note: TinyDTLS log output will be consistent when built against a TinyDTLS version that contains support for an external logging handler.
448 lines
13 KiB
C
448 lines
13 KiB
C
/*
|
|
* examples_code_check.c -- Validate the code in EXAMPLES of the man pages
|
|
*
|
|
* Exits with a non-zero value if there is a coding error.
|
|
*
|
|
* Copyright (C) 2020 Jon Shallow <supjps-libcoap@jpshallow.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* This file is part of the CoAP library libcoap. Please see README for terms
|
|
* of use.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#ifdef _WIN32
|
|
#define GCC_OPTIONS "-I../include"
|
|
#else /* ! _WIN32 */
|
|
#define GCC_OPTIONS "\
|
|
-I../include \
|
|
-std=c99 \
|
|
-g \
|
|
-O2 \
|
|
-pedantic \
|
|
-Wall \
|
|
-Wcast-qual \
|
|
-Wextra \
|
|
-Wformat-security \
|
|
-Winline \
|
|
-Wmissing-declarations \
|
|
-Wmissing-prototypes \
|
|
-Wnested-externs \
|
|
-Wpointer-arith \
|
|
-Wshadow \
|
|
-Wstrict-prototypes \
|
|
-Wswitch-default \
|
|
-Wswitch-enum \
|
|
-Wunused \
|
|
-Wwrite-strings \
|
|
-Wno-unused-function \
|
|
-Wno-unused-but-set-variable \
|
|
-Werror \
|
|
"
|
|
#endif /* ! _WIN32 */
|
|
|
|
const char *inline_list[] = {
|
|
"coap_malloc(",
|
|
"coap_free(",
|
|
};
|
|
|
|
const char *define_list[] = {
|
|
"coap_string_equal(",
|
|
"coap_binary_equal(",
|
|
"coap_log(",
|
|
"coap_log_emerg(",
|
|
"coap_log_alert(",
|
|
"coap_log_crit(",
|
|
"coap_log_err(",
|
|
"coap_log_warn(",
|
|
"coap_log_info(",
|
|
"coap_log_notice(",
|
|
"coap_log_debug(",
|
|
"coap_log_oscore(",
|
|
"coap_dtls_log(",
|
|
};
|
|
|
|
const char *struct_list[] = {
|
|
"coap_fixed_point_t ",
|
|
"coap_string_t ",
|
|
"coap_str_const_t ",
|
|
"coap_binary_t ",
|
|
"coap_bin_const_t ",
|
|
"coap_opt_iterator_t ",
|
|
"coap_opt_t ",
|
|
};
|
|
|
|
const char *number_list[] = {
|
|
"coap_log_t ",
|
|
"coap_pdu_type_t ",
|
|
"coap_mid_t ",
|
|
"coap_pdu_code_t ",
|
|
"coap_proto_t ",
|
|
"coap_session_state_t ",
|
|
"coap_session_type_t ",
|
|
"int ",
|
|
"uint16_t ",
|
|
"uint32_t ",
|
|
"uint64_t ",
|
|
"unsigned int ",
|
|
"size_t ",
|
|
"const uint8_t ",
|
|
};
|
|
|
|
int exit_code = 0;
|
|
|
|
static void check_synopsis(const char* file) {
|
|
char buffer[1024];
|
|
char file_name[300];
|
|
FILE *fpcode;
|
|
int status;
|
|
|
|
snprintf(file_name, sizeof (file_name), "tmp/%s-header.c", file);
|
|
fpcode = fopen(file_name, "w");
|
|
if (!fpcode) {
|
|
fprintf(stderr, "fopen: %s: %s (%d)\n", file_name, strerror(errno), errno);
|
|
exit_code = 1;
|
|
return;
|
|
}
|
|
fprintf(fpcode, "#include <coap3/coap.h>\n");
|
|
fprintf(fpcode, "#ifdef __GNUC__\n");
|
|
fprintf(fpcode, "#define U __attribute__ ((unused))\n");
|
|
fprintf(fpcode, "#else /* not a GCC */\n");
|
|
fprintf(fpcode, "#define U\n");
|
|
fprintf(fpcode, "#endif /* GCC */\n");
|
|
fprintf(fpcode, "\n");
|
|
fprintf(fpcode, "#include \"%s.h\"\n", file);
|
|
fclose(fpcode);
|
|
file_name[strlen(file_name)-1] = '\000';
|
|
snprintf (buffer, sizeof (buffer),
|
|
"gcc " GCC_OPTIONS " -c %sc -o %so",
|
|
file_name, file_name);
|
|
status = system(buffer);
|
|
if (WEXITSTATUS(status)) {
|
|
exit_code = WEXITSTATUS(status);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
DIR *pdir;
|
|
struct dirent *pdir_ent;
|
|
char buffer[1024];
|
|
int status;
|
|
|
|
if (argc != 2) {
|
|
fprintf(stderr, "usage: %s man_directory\n", argv[0]);
|
|
exit (1);
|
|
}
|
|
|
|
pdir = opendir(argv[1]);
|
|
if (pdir == NULL) {
|
|
fprintf(stderr, "opendir: %s: %s (%d)\n", argv[1], strerror(errno), errno);
|
|
exit(1);
|
|
}
|
|
if (chdir(argv[1]) == -1) {
|
|
fprintf(stderr, "chdir: %s: %s (%d)\n", argv[1], strerror(errno), errno);
|
|
exit(1);
|
|
}
|
|
if (mkdir("tmp", 0777) == -1 && errno != EEXIST) {
|
|
fprintf(stderr, "mkdir: %s: %s (%d)\n", "tmp", strerror(errno), errno);
|
|
exit(1);
|
|
}
|
|
|
|
while ((pdir_ent = readdir (pdir)) != NULL) {
|
|
if (!strncmp(pdir_ent->d_name, "coap_", sizeof ("coap_")-1) &&
|
|
strstr (pdir_ent->d_name, ".txt.in")) {
|
|
FILE* fp;
|
|
int skip = 1;
|
|
int in_examples = 0;
|
|
int in_synopsis = 0;
|
|
int count = 1;
|
|
char keep_line[1024] = {0};
|
|
FILE* fpcode = NULL;
|
|
FILE* fpheader = NULL;
|
|
char file_name[300];
|
|
int is_void_func = 0;
|
|
int is_number_func = 0;
|
|
int is_inline_func = 0;
|
|
int is_struct_func = 0;
|
|
char *func_start = NULL;
|
|
int is_struct = 0;
|
|
unsigned int i;
|
|
|
|
fprintf(stderr, "Processing: %s\n", pdir_ent->d_name);
|
|
|
|
snprintf(buffer, sizeof (buffer), "%s", pdir_ent->d_name);
|
|
fp = fopen(buffer, "r");
|
|
if (fp == NULL) {
|
|
fprintf(stderr, "fopen: %s: %s (%d)\n", buffer, strerror(errno), errno);
|
|
continue;
|
|
}
|
|
while (fgets(buffer, sizeof (buffer), fp) != NULL) {
|
|
if (strncmp(buffer, "SYNOPSIS", sizeof("SYNOPSIS")-1) == 0) {
|
|
in_synopsis = 1;
|
|
snprintf(file_name, sizeof (file_name), "tmp/%s.h",
|
|
pdir_ent->d_name);
|
|
fpheader = fopen(file_name, "w");
|
|
if (!fpheader) {
|
|
fprintf(stderr, "fopen: %s: %s (%d)\n", file_name,
|
|
strerror(errno), errno);
|
|
goto bad;
|
|
}
|
|
continue;
|
|
}
|
|
if (strncmp(buffer, "DESCRIPTION", sizeof("DESCRIPTION")-1) == 0) {
|
|
in_synopsis = 0;
|
|
if (fpheader)
|
|
fclose(fpheader);
|
|
fpheader = NULL;
|
|
check_synopsis(pdir_ent->d_name);
|
|
continue;
|
|
}
|
|
if (strncmp(buffer, "EXAMPLES", sizeof("EXAMPLES")-1) == 0) {
|
|
in_synopsis = 0;
|
|
in_examples = 1;
|
|
continue;
|
|
}
|
|
if (strncmp(buffer, "SEE ALSO", sizeof("SEE ALSO")-1) == 0) {
|
|
break;
|
|
}
|
|
if (in_synopsis) {
|
|
/* Working in SYNOPSIS section */
|
|
size_t len;
|
|
char outbuf[1024];
|
|
char *cp;
|
|
char *ecp;
|
|
|
|
if (buffer[0] == '\n')
|
|
continue;
|
|
if (buffer[0] == '-')
|
|
continue;
|
|
if (buffer[0] == 'F') {
|
|
/* For specific ..... is the end */
|
|
in_synopsis = 0;
|
|
if (fpheader)
|
|
fclose(fpheader);
|
|
fpheader = NULL;
|
|
check_synopsis(pdir_ent->d_name);
|
|
continue;
|
|
}
|
|
if (buffer[0] == '*' && buffer[1] == '#')
|
|
continue;
|
|
if (buffer[0] == '*') {
|
|
/* start of a new function */
|
|
is_void_func = 0;
|
|
is_number_func = 0;
|
|
is_struct_func = 0;
|
|
is_inline_func = 0;
|
|
is_struct = 0;
|
|
func_start = NULL;
|
|
|
|
if (strncmp(buffer, "*void ", sizeof("*void ")-1) == 0) {
|
|
if (strncmp(buffer, "*void *", sizeof("*void *")-1) == 0) {
|
|
func_start = &buffer[sizeof("*void *")-1];
|
|
}
|
|
else {
|
|
is_void_func = 1;
|
|
func_start = &buffer[sizeof("*void ")-1];
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < sizeof(number_list)/sizeof(number_list[0]); i++) {
|
|
if (strncmp(&buffer[1], number_list[i],
|
|
strlen(number_list[i])) == 0) {
|
|
if (buffer[1 + strlen(number_list[i])] == '*') {
|
|
func_start = &buffer[2 + strlen(number_list[i])];
|
|
}
|
|
else {
|
|
is_number_func = 1;
|
|
func_start = &buffer[1 + strlen(number_list[i])];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < sizeof(struct_list)/sizeof(struct_list[0]); i++) {
|
|
if (strncmp(&buffer[1], struct_list[i],
|
|
strlen(struct_list[i])) == 0) {
|
|
if (buffer[1 + strlen(struct_list[i])] == '*') {
|
|
func_start = &buffer[2 + strlen(struct_list[i])];
|
|
}
|
|
else {
|
|
is_struct_func = i + 1;
|
|
func_start = &buffer[1 + strlen(struct_list[i])];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (strncmp(buffer, "*struct ", sizeof("*struct ")-1) == 0) {
|
|
is_struct = 1;
|
|
}
|
|
}
|
|
|
|
if (func_start) {
|
|
/* see if COAP_STATIC_INLINE function */
|
|
for (i = 0; i < sizeof(inline_list)/sizeof(inline_list[0]); i++) {
|
|
if (strncmp(func_start, inline_list[i],
|
|
strlen(inline_list[i])) == 0) {
|
|
is_inline_func = 1;
|
|
break;
|
|
}
|
|
}
|
|
/* see if #define function */
|
|
for (i = 0; i < sizeof(define_list)/sizeof(define_list[0]); i++) {
|
|
if (strncmp(func_start, define_list[i], strlen(define_list[i])) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i != sizeof(define_list)/sizeof(define_list[0]))
|
|
continue;
|
|
}
|
|
|
|
/* Need to include use of U for unused parameters just before comma */
|
|
cp = buffer;
|
|
ecp = strchr(cp, ',');
|
|
if (!ecp) ecp = strchr(cp, ')');
|
|
outbuf[0] = '\000';
|
|
while (ecp) {
|
|
len = strlen(outbuf);
|
|
if (strncmp(cp, "void", ecp-cp) == 0)
|
|
snprintf(&outbuf[len], sizeof(outbuf)-len, "%*.*s%c",
|
|
(int)(ecp-cp), (int)(ecp-cp), cp, *ecp);
|
|
else
|
|
snprintf(&outbuf[len], sizeof(outbuf)-len, "%*.*s U%c",
|
|
(int)(ecp-cp), (int)(ecp-cp), cp, *ecp);
|
|
cp = ecp+1;
|
|
if(*cp) {
|
|
ecp = strchr(cp, ',');
|
|
if (!ecp) ecp = strchr(cp, ')');
|
|
}
|
|
else {
|
|
ecp = NULL;
|
|
}
|
|
}
|
|
if (*cp) {
|
|
len = strlen(outbuf);
|
|
snprintf(&outbuf[len], sizeof(outbuf)-len, "%s", cp);
|
|
}
|
|
|
|
len = strlen(outbuf);
|
|
if (len > 3 && ((outbuf[len-3] == ';' && outbuf[len-2] == '*') ||
|
|
(outbuf[len-3] == '*' && outbuf[len-2] == ';'))) {
|
|
if (is_inline_func) {
|
|
strcpy(&outbuf[len-3], ";\n");
|
|
}
|
|
/* Replace ;* or ;* with simple function definition */
|
|
else if (is_void_func) {
|
|
strcpy(&outbuf[len-3], "{}\n");
|
|
}
|
|
else if (is_number_func) {
|
|
strcpy(&outbuf[len-3], "{return 0;}\n");
|
|
}
|
|
else if (is_struct_func) {
|
|
snprintf(&outbuf[len-3], sizeof(outbuf)-(len-3),
|
|
"{%s v; memset(&v, 0, sizeof(v)); return v;}\n",
|
|
struct_list[is_struct_func - 1]);
|
|
}
|
|
else if (is_struct) {
|
|
strcpy(&outbuf[len-3], ";\n");
|
|
}
|
|
else {
|
|
strcpy(&outbuf[len-3], "{return NULL;}\n");
|
|
}
|
|
}
|
|
if (outbuf[0] == '*') {
|
|
fprintf(fpheader, "%s", &outbuf[1]);
|
|
}
|
|
else {
|
|
fprintf(fpheader, "%s", outbuf);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!in_examples) {
|
|
continue;
|
|
}
|
|
/* Working in EXAMPLES section */
|
|
if (skip) {
|
|
if (!strcmp(buffer, "----\n") || !strcmp(buffer, "---\n") ||
|
|
!strcmp(buffer, "--\n") || !strcmp(buffer, "-\n") ||
|
|
!strcmp(buffer, "-----\n")) {
|
|
/* Found start of code */
|
|
if (strcmp(buffer, "----\n")) {
|
|
fprintf(stderr,
|
|
"Unexpected start of code '%.*s' - expected ----\n",
|
|
(int)strlen(buffer)-1, buffer);
|
|
}
|
|
snprintf(file_name, sizeof (file_name), "tmp/%s-%d.c",
|
|
pdir_ent->d_name, count++);
|
|
fpcode = fopen(file_name, "w");
|
|
if (!fpcode) {
|
|
fprintf(stderr, "fopen: %s: %s (%d)\n", file_name,
|
|
strerror(errno), errno);
|
|
goto bad;
|
|
}
|
|
else {
|
|
fprintf(fpcode, "/* %s */\n", keep_line);
|
|
}
|
|
skip = 0;
|
|
fprintf(stderr, "Processing: %s EXAMPLE - '%d'\n",
|
|
pdir_ent->d_name,
|
|
count-1);
|
|
}
|
|
else if (buffer[0] == '*') {
|
|
snprintf(keep_line, sizeof (keep_line), "%s", buffer);
|
|
}
|
|
continue;
|
|
}
|
|
if (!strcmp(buffer, "----\n") || !strcmp(buffer, "---\n") ||
|
|
!strcmp(buffer, "--\n") || !strcmp(buffer, "-\n") ||
|
|
!strcmp(buffer, "-----\n")) {
|
|
/* Found end of code */
|
|
|
|
skip = 1;
|
|
if (fpcode) fclose(fpcode);
|
|
keep_line[0] = '\000';
|
|
file_name[strlen(file_name)-1] = '\000';
|
|
snprintf (buffer, sizeof (buffer),
|
|
"gcc " GCC_OPTIONS " -c %sc -o %so",
|
|
file_name, file_name);
|
|
status = system(buffer);
|
|
if (WEXITSTATUS(status)) {
|
|
exit_code = WEXITSTATUS(status);
|
|
}
|
|
continue;
|
|
}
|
|
if (fpcode) {
|
|
if (strstr (buffer, "LIBCOAP_API_VERSION")) {
|
|
fprintf(fpcode, "#include <coap3/coap.h>\n");
|
|
fprintf(fpcode, "#ifdef __GNUC__\n");
|
|
fprintf(fpcode, "#define U __attribute__ ((unused))\n");
|
|
fprintf(fpcode, "#else /* not a GCC */\n");
|
|
fprintf(fpcode, "#define U\n");
|
|
fprintf(fpcode, "#endif /* GCC */\n");
|
|
fprintf(fpcode, "#include \"%s.h\"\n", pdir_ent->d_name);
|
|
fprintf(fpcode, "#undef U\n");
|
|
continue;
|
|
}
|
|
fprintf(fpcode, "%s", buffer);
|
|
}
|
|
}
|
|
bad:
|
|
fclose(fp);
|
|
}
|
|
}
|
|
closedir (pdir);
|
|
exit(exit_code);
|
|
}
|