<commit_before>#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>

#if CPUINFO_MOCK
	#include <cpuinfo-mock.h>
#endif
#include <linux/api.h>
#include <log.h>


/*
 * Size, in chars, of the on-stack buffer used for parsing cpu lists.
 * This is also the limit on the length of a single entry
 * (<cpu-number> or <cpu-number-start>-<cpu-number-end>)
 * in the cpu list.
 */
#define BUFFER_SIZE 256


/* Locale-independent */
inline static bool is_whitespace(char c) {
	switch (c) {
		case ' ':
		case '\t':
		case '\n':
		case '\r':
			return true;
		default:
			return false;
	}
}

inline static const char* parse_number(const char* string, const char* end, uint32_t number_ptr[restrict static 1]) {
	uint32_t number = 0;
	while (string != end) {
		const uint32_t digit = (uint32_t) (*string) - (uint32_t) '0';
		if (digit >= 10) {
			return string;
		}
		number = number * UINT32_C(10) + digit;
		string += 1;
	}
	*number_ptr = number;
	return end;
}

inline static bool parse_entry(const char* entry_start, const char* entry_end, cpuinfo_cpulist_callback callback, void* context) {
	/* Skip whitespace at the beginning of an entry */
	for (; entry_start != entry_end; entry_start++) {
		if (!is_whitespace(*entry_start)) {
			break;
		}
	}
	/* Skip whitespace at the end of an entry */
	for (; entry_end != entry_start; entry_end--) {
		if (!is_whitespace(entry_end[-1])) {
			break;
		}
	}

	const size_t entry_length = (size_t) (entry_end - entry_start);
	if (entry_length == 0) {
		cpuinfo_log_warning("unexpected zero-length cpu list entry ignored");
		return false;
	}

	#if CPUINFO_LOG_DEBUG_PARSERS
		cpuinfo_log_debug("parse cpu list entry \"%.*s\" (%zu chars)", (int) entry_length, entry_start, entry_length);
	#endif
	uint32_t first_cpu, last_cpu;

	const char* number_end = parse_number(entry_start, entry_end, &first_cpu);
	if (number_end == entry_start) {
		/* Failed to parse the number; ignore the entry */
		cpuinfo_log_warning("invalid character '%c' in the cpu list entry \"%.*s\": entry is ignored",<commit_msg>Fix bug in parsing cpulists on Linux<commit_after>#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>

#if CPUINFO_MOCK
	#include <cpuinfo-mock.h>
#endif
#include <linux/api.h>
#include <log.h>


/*
 * Size, in chars, of the on-stack buffer used for parsing cpu lists.
 * This is also the limit on the length of a single entry
 * (<cpu-number> or <cpu-number-start>-<cpu-number-end>)
 * in the cpu list.
 */
#define BUFFER_SIZE 256


/* Locale-independent */
inline static bool is_whitespace(char c) {
	switch (c) {
		case ' ':
		case '\t':
		case '\n':
		case '\r':
			return true;
		default:
			return false;
	}
}

inline static const char* parse_number(const char* string, const char* end, uint32_t number_ptr[restrict static 1]) {
	uint32_t number = 0;
	while (string != end) {
		const uint32_t digit = (uint32_t) (*string) - (uint32_t) '0';
		if (digit >= 10) {
			break;
		}
		number = number * UINT32_C(10) + digit;
		string += 1;
	}
	*number_ptr = number;
	return string;
}

inline static bool parse_entry(const char* entry_start, const char* entry_end, cpuinfo_cpulist_callback callback, void* context) {
	/* Skip whitespace at the beginning of an entry */
	for (; entry_start != entry_end; entry_start++) {
		if (!is_whitespace(*entry_start)) {
			break;
		}
	}
	/* Skip whitespace at the end of an entry */
	for (; entry_end != entry_start; entry_end--) {
		if (!is_whitespace(entry_end[-1])) {
			break;
		}
	}

	const size_t entry_length = (size_t) (entry_end - entry_start);
	if (entry_length == 0) {
		cpuinfo_log_warning("unexpected zero-length cpu list entry ignored");
		return false;
	}

	#if CPUINFO_LOG_DEBUG_PARSERS
		cpuinfo_log_debug("parse cpu list entry \"%.*s\" (%zu chars)", (int) entry_length, entry_start, entry_length);
	#endif
	uint32_t first_cpu, last_cpu;

	const char* number_end = parse_number(entry_start, entry_end, &first_cpu);
	if (number_end == entry_start) {
		/* Failed to parse the number; ignore the entry */
		cpuinfo_log_warning("invalid character '%c' in the cpu list entry \"%.*s\": entry is ignored",
{'fraction_non_alphanumeric': 0.13907888736890106, 'fraction_numerical': 0.012311901504787962, 'mean_word_length': 4.065819861431871, 'pattern_counts': {'":': 2, '<': 35, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '7278108', 'n_tokens_mistral': 1711, 'n_tokens_neox': 1585, 'n_words': 466}