xref: /aosp_15_r20/external/cpuinfo/src/linux/multiline.c (revision 2b54f0db79fd8303838913b20ff3780cddaa909f)
1*2b54f0dbSXin Li #include <stdbool.h>
2*2b54f0dbSXin Li #include <stdint.h>
3*2b54f0dbSXin Li #include <stdlib.h>
4*2b54f0dbSXin Li #include <string.h>
5*2b54f0dbSXin Li #include <alloca.h>
6*2b54f0dbSXin Li #include <errno.h>
7*2b54f0dbSXin Li 
8*2b54f0dbSXin Li #include <sys/types.h>
9*2b54f0dbSXin Li #include <sys/stat.h>
10*2b54f0dbSXin Li #include <unistd.h>
11*2b54f0dbSXin Li #include <fcntl.h>
12*2b54f0dbSXin Li 
13*2b54f0dbSXin Li #if CPUINFO_MOCK
14*2b54f0dbSXin Li 	#include <cpuinfo-mock.h>
15*2b54f0dbSXin Li #endif
16*2b54f0dbSXin Li #include <linux/api.h>
17*2b54f0dbSXin Li #include <cpuinfo/log.h>
18*2b54f0dbSXin Li 
19*2b54f0dbSXin Li 
cpuinfo_linux_parse_multiline_file(const char * filename,size_t buffer_size,cpuinfo_line_callback callback,void * context)20*2b54f0dbSXin Li bool cpuinfo_linux_parse_multiline_file(const char* filename, size_t buffer_size, cpuinfo_line_callback callback, void* context)
21*2b54f0dbSXin Li {
22*2b54f0dbSXin Li 	int file = -1;
23*2b54f0dbSXin Li 	bool status = false;
24*2b54f0dbSXin Li 	char* buffer = (char*) alloca(buffer_size);
25*2b54f0dbSXin Li 
26*2b54f0dbSXin Li #if CPUINFO_MOCK
27*2b54f0dbSXin Li 	file = cpuinfo_mock_open(filename, O_RDONLY);
28*2b54f0dbSXin Li #else
29*2b54f0dbSXin Li 	file = open(filename, O_RDONLY);
30*2b54f0dbSXin Li #endif
31*2b54f0dbSXin Li 	if (file == -1) {
32*2b54f0dbSXin Li 		cpuinfo_log_info("failed to open %s: %s", filename, strerror(errno));
33*2b54f0dbSXin Li 		goto cleanup;
34*2b54f0dbSXin Li 	}
35*2b54f0dbSXin Li 
36*2b54f0dbSXin Li 	/* Only used for error reporting */
37*2b54f0dbSXin Li 	size_t position = 0;
38*2b54f0dbSXin Li 	uint64_t line_number = 1;
39*2b54f0dbSXin Li 	const char* buffer_end = &buffer[buffer_size];
40*2b54f0dbSXin Li 	char* data_start = buffer;
41*2b54f0dbSXin Li 	ssize_t bytes_read;
42*2b54f0dbSXin Li 	do {
43*2b54f0dbSXin Li #if CPUINFO_MOCK
44*2b54f0dbSXin Li 		bytes_read = cpuinfo_mock_read(file, data_start, (size_t) (buffer_end - data_start));
45*2b54f0dbSXin Li #else
46*2b54f0dbSXin Li 		bytes_read = read(file, data_start, (size_t) (buffer_end - data_start));
47*2b54f0dbSXin Li #endif
48*2b54f0dbSXin Li 		if (bytes_read < 0) {
49*2b54f0dbSXin Li 			cpuinfo_log_info("failed to read file %s at position %zu: %s",
50*2b54f0dbSXin Li 				filename, position, strerror(errno));
51*2b54f0dbSXin Li 			goto cleanup;
52*2b54f0dbSXin Li 		}
53*2b54f0dbSXin Li 
54*2b54f0dbSXin Li 		position += (size_t) bytes_read;
55*2b54f0dbSXin Li 		const char* data_end = data_start + (size_t) bytes_read;
56*2b54f0dbSXin Li 		const char* line_start = buffer;
57*2b54f0dbSXin Li 
58*2b54f0dbSXin Li 		if (bytes_read == 0) {
59*2b54f0dbSXin Li 			/* No more data in the file: process the remaining text in the buffer as a single entry */
60*2b54f0dbSXin Li 			const char* line_end = data_end;
61*2b54f0dbSXin Li 			if (!callback(line_start, line_end, context, line_number)) {
62*2b54f0dbSXin Li 				goto cleanup;
63*2b54f0dbSXin Li 			}
64*2b54f0dbSXin Li 		} else {
65*2b54f0dbSXin Li 			const char* line_end;
66*2b54f0dbSXin Li 			do {
67*2b54f0dbSXin Li 				/* Find the end of the entry, as indicated by newline character ('\n') */
68*2b54f0dbSXin Li 				for (line_end = line_start; line_end != data_end; line_end++) {
69*2b54f0dbSXin Li 					if (*line_end == '\n') {
70*2b54f0dbSXin Li 						break;
71*2b54f0dbSXin Li 					}
72*2b54f0dbSXin Li 				}
73*2b54f0dbSXin Li 
74*2b54f0dbSXin Li 				/*
75*2b54f0dbSXin Li 				 * If we located separator at the end of the entry, parse it.
76*2b54f0dbSXin Li 				 * Otherwise, there may be more data at the end; read the file once again.
77*2b54f0dbSXin Li 				 */
78*2b54f0dbSXin Li 				if (line_end != data_end) {
79*2b54f0dbSXin Li 					if (!callback(line_start, line_end, context, line_number++)) {
80*2b54f0dbSXin Li 						goto cleanup;
81*2b54f0dbSXin Li 					}
82*2b54f0dbSXin Li 					line_start = line_end + 1;
83*2b54f0dbSXin Li 				}
84*2b54f0dbSXin Li 			} while (line_end != data_end);
85*2b54f0dbSXin Li 
86*2b54f0dbSXin Li 			/* Move remaining partial line data at the end to the beginning of the buffer */
87*2b54f0dbSXin Li 			const size_t line_length = (size_t) (line_end - line_start);
88*2b54f0dbSXin Li 			memmove(buffer, line_start, line_length);
89*2b54f0dbSXin Li 			data_start = &buffer[line_length];
90*2b54f0dbSXin Li 		}
91*2b54f0dbSXin Li 	} while (bytes_read != 0);
92*2b54f0dbSXin Li 
93*2b54f0dbSXin Li 	/* Commit */
94*2b54f0dbSXin Li 	status = true;
95*2b54f0dbSXin Li 
96*2b54f0dbSXin Li cleanup:
97*2b54f0dbSXin Li 	if (file != -1) {
98*2b54f0dbSXin Li #if CPUINFO_MOCK
99*2b54f0dbSXin Li 		cpuinfo_mock_close(file);
100*2b54f0dbSXin Li #else
101*2b54f0dbSXin Li 		close(file);
102*2b54f0dbSXin Li #endif
103*2b54f0dbSXin Li 		file = -1;
104*2b54f0dbSXin Li 	}
105*2b54f0dbSXin Li 	return status;
106*2b54f0dbSXin Li }
107