<commit_before>/*
 * Copyright (C) 2011 Red Hat, Inc.
 *
 * All rights reserved.
 *
 * Author: <NAME> <<EMAIL>>
 *
 * libqb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * libqb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "os_base.h"
#include <ctype.h>
#ifdef HAVE_LINK_H
#include <link.h>
#endif /* HAVE_LINK_H */
#include <stdarg.h>
#include <pthread.h>
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif /* HAVE_DLFCN_H */
#include <stdarg.h>
#include <string.h>

#include <qb/qbdefs.h>
#include <qb/qblist.h>
#include <qb/qblog.h>
#include <qb/qbutil.h>
#include <qb/qbarray.h>
#include "log_int.h"
#include "util_int.h"
#include <regex.h>

#if defined(QB_NEED_ATTRIBUTE_SECTION_WORKAROUND) && !defined(S_SPLINT_S)
/* following only needed to force these symbols be global
   with ld 2.29: https://bugzilla.redhat.com/1477354 */
struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_START[] = { 0 };
struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_STOP[] = { 0 };
#endif

static struct qb_log_target conf[QB_LOG_TARGET_MAX];
static uint32_t conf_active_max = 0;
static int32_t in_logger = QB_FALSE;
static int32_t logger_inited = QB_FALSE;
static pthread_rwlock_t _listlock;
static qb_log_filter_fn _custom_filter_fn = NULL;

static QB_LIST_DECLARE(dlnames);
static QB_LIST_DECLARE(tags_head);
static QB_LIST_DECLARE(callsite_sections);

struct dlname {
	char *dln_name;
	struct qb_list_head list;
};

struct callsite_section {
	struct qb_log_callsite *start;
	struct qb_log_callsite *stop;
	struct qb_list_head list;
};

static int32_t _log_target_enable(struct qb_log_target *t);
static void _log_target_disable(struct qb_log_target *t);
static void _log_filter_apply(struct callsite_section *sect,
			      uint32_t t, enum qb_log_filter_conf c,
			      enum qb_log_filter_type type,
			      const char *text,
			      regex_t *regex,
			      uint8_t high_priority, uint8_t low_priority);
static void _log_filter_apply_to_cs(struct qb_log_callsite *cs,
				    uint32_t t, enum qb_log_filter_conf c,
				    enum qb_log_filter_type type,
				    const char *text,
				    regex_t *regex,
				    uint8_t high_priority, uint8_t low_priority);

/* deprecated method of getting internal log messages */
static qb_util_log_fn_t old_internal_log_fn = NULL;
void
qb_util_set_log_function(qb_util_log_fn_t fn)
{
	old_internal_log_fn = fn;
}

static void
_log_free_filter(struct qb_log_filter *flt)
{
	if (flt->regex) {
		regfree(flt->regex);
	}
	free(flt->regex);
	free(flt->text);
	free(flt);
}

static int32_t
_cs_matches_filter_(struct qb_log_callsite *cs,
		    enum qb_log_filter_type type,
		    const char *text,
		    regex_t *regex,
		    uint8_t high_priority,
		    uint8_t low_priority)
{
	int32_t match = QB_FALSE;
	const char *offset = NULL;
	const char *next = NULL;

	if (cs->priority > low_priority ||
	    cs->priority < high_priority) {
		return QB_FALSE;
	}
	if (strcmp(text, "*") == 0) {
		return QB_TRUE;
	}

	switch (type) {
	case QB_LOG_FILTER_FILE:
	case QB_LOG_FILTER_FUNCTION:
		next = text;
		do {
			char token[500];
			offset = next;
			next = strchrnul(offset, ',');
			snprintf(token, 499, "%.*s", (int)(next - offset), offset);

			if (type == QB_LOG_FILTER_FILE) {
				match = (strcmp(cs->filename, token) == 0) ? 1 : 0;
			} else {
				match = (strcmp(cs->function, token) == 0) ? 1 : 0;
			}
			if (!match && next[0] != 0) {
				next++;
			}

		} while (match == QB_FALSE && next != NULL && next[0] != 0);
		break;
	case QB_LOG_FILTER_FILE_REGEX:
		next = next ? next : cs->filename;
	case QB_LOG_FILTER_FUNCTION_REGEX:
		next = next ? next : cs->function;
	case QB_LOG_FILTER_FORMAT_REGEX:
		next = next ? next : cs->format;

		if (regex == NULL) {
			return QB_FALSE;<commit_msg>warnings cleanup: log: Wextra -> Wimplicit-fallthrough (GCC7+)<commit_after>/*
 * Copyright (C) 2011 Red Hat, Inc.
 *
 * All rights reserved.
 *
 * Author: <NAME> <<EMAIL>>
 *
 * libqb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * libqb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "os_base.h"
#include <ctype.h>
#ifdef HAVE_LINK_H
#include <link.h>
#endif /* HAVE_LINK_H */
#include <stdarg.h>
#include <pthread.h>
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif /* HAVE_DLFCN_H */
#include <stdarg.h>
#include <string.h>

#include <qb/qbdefs.h>
#include <qb/qblist.h>
#include <qb/qblog.h>
#include <qb/qbutil.h>
#include <qb/qbarray.h>
#include "log_int.h"
#include "util_int.h"
#include <regex.h>

#if defined(QB_NEED_ATTRIBUTE_SECTION_WORKAROUND) && !defined(S_SPLINT_S)
/* following only needed to force these symbols be global
   with ld 2.29: https://bugzilla.redhat.com/1477354 */
struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_START[] = { 0 };
struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_STOP[] = { 0 };
#endif

static struct qb_log_target conf[QB_LOG_TARGET_MAX];
static uint32_t conf_active_max = 0;
static int32_t in_logger = QB_FALSE;
static int32_t logger_inited = QB_FALSE;
static pthread_rwlock_t _listlock;
static qb_log_filter_fn _custom_filter_fn = NULL;

static QB_LIST_DECLARE(dlnames);
static QB_LIST_DECLARE(tags_head);
static QB_LIST_DECLARE(callsite_sections);

struct dlname {
	char *dln_name;
	struct qb_list_head list;
};

struct callsite_section {
	struct qb_log_callsite *start;
	struct qb_log_callsite *stop;
	struct qb_list_head list;
};

static int32_t _log_target_enable(struct qb_log_target *t);
static void _log_target_disable(struct qb_log_target *t);
static void _log_filter_apply(struct callsite_section *sect,
			      uint32_t t, enum qb_log_filter_conf c,
			      enum qb_log_filter_type type,
			      const char *text,
			      regex_t *regex,
			      uint8_t high_priority, uint8_t low_priority);
static void _log_filter_apply_to_cs(struct qb_log_callsite *cs,
				    uint32_t t, enum qb_log_filter_conf c,
				    enum qb_log_filter_type type,
				    const char *text,
				    regex_t *regex,
				    uint8_t high_priority, uint8_t low_priority);

/* deprecated method of getting internal log messages */
static qb_util_log_fn_t old_internal_log_fn = NULL;
void
qb_util_set_log_function(qb_util_log_fn_t fn)
{
	old_internal_log_fn = fn;
}

static void
_log_free_filter(struct qb_log_filter *flt)
{
	if (flt->regex) {
		regfree(flt->regex);
	}
	free(flt->regex);
	free(flt->text);
	free(flt);
}

static int32_t
_cs_matches_filter_(struct qb_log_callsite *cs,
		    enum qb_log_filter_type type,
		    const char *text,
		    regex_t *regex,
		    uint8_t high_priority,
		    uint8_t low_priority)
{
	int32_t match = QB_FALSE;
	const char *offset = NULL;
	const char *next = NULL;

	if (cs->priority > low_priority ||
	    cs->priority < high_priority) {
		return QB_FALSE;
	}
	if (strcmp(text, "*") == 0) {
		return QB_TRUE;
	}

	switch (type) {
	case QB_LOG_FILTER_FILE:
	case QB_LOG_FILTER_FUNCTION:
		next = text;
		do {
			char token[500];
			offset = next;
			next = strchrnul(offset, ',');
			snprintf(token, 499, "%.*s", (int)(next - offset), offset);

			if (type == QB_LOG_FILTER_FILE) {
				match = (strcmp(cs->filename, token) == 0) ? 1 : 0;
			} else {
				match = (strcmp(cs->function, token) == 0) ? 1 : 0;
			}
			if (!match && next[0] != 0) {
				next++;
			}

		} while (match == QB_FALSE && next != NULL && next[0] != 0);
		break;
	case QB_LOG_FILTER_FILE_REGEX:
		next = next ? next : cs->filename;
		/* fallthrough */
	case QB_LOG_FILTER_FUNCTION_REGEX:
		next = next ? next : cs->function;
		/* fallthrough */
	case QB_LOG_FILTER_FORMAT_REGEX:
		next = next ? next : cs->format;

		if (regex == NULL) {
			return QB_FALSE;
{'fraction_non_alphanumeric': 0.1098419291565709, 'fraction_numerical': 0.013499480789200415, 'mean_word_length': 4.119905493207324, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 62, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4752119', 'n_tokens_mistral': 3475, 'n_tokens_neox': 3172, 'n_words': 846}