mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-09-05 19:00:16 +00:00
HV:Acrn-hypvervisor Root Directory Clean-up and create misc/ folder for Acrn daemons, services and tools.
This patch is to clean-up acrn-hypervisor root directory, targt only 5 folders under acrn-hypervisor:1.hypervisor,2.devicemodel,3.misc,4.doc,5.build Tracked-On: #3482 Signed-off-by: Terry Zou <terry.zou@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
23
misc/tools/acrn-crashlog/common/Makefile
Normal file
23
misc/tools/acrn-crashlog/common/Makefile
Normal file
@@ -0,0 +1,23 @@
|
||||
objects = log_sys.o \
|
||||
strutils.o \
|
||||
cmdutils.o \
|
||||
fsutils.o
|
||||
|
||||
all: check_obj $(objects)
|
||||
check_obj:
|
||||
@if [ ! -d $(BUILDDIR)/common/obj ]; then \
|
||||
mkdir -p $(BUILDDIR)/common/obj/; \
|
||||
fi
|
||||
|
||||
$(objects):%.o:%.c
|
||||
$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $(BUILDDIR)/common/obj/$@
|
||||
|
||||
.PHONY:clean
|
||||
clean:
|
||||
@echo "Clean objects and binaries"
|
||||
@if [ -d $(BUILDDIR)/common/obj ]; then \
|
||||
find $(BUILDDIR)/common/obj -name "*.o" -exec $(RM) {} \; 2>&1 || exit 0; \
|
||||
fi
|
||||
@if [ -d $(BUILDDIR)/common/obj ]; then \
|
||||
$(RM) -r $(BUILDDIR)/common/obj ; \
|
||||
fi
|
232
misc/tools/acrn-crashlog/common/cmdutils.c
Normal file
232
misc/tools/acrn-crashlog/common/cmdutils.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/wait.h>
|
||||
#include "cmdutils.h"
|
||||
#include "strutils.h"
|
||||
#include "log_sys.h"
|
||||
|
||||
/**
|
||||
* Execute a command described in an array of pointers to null-terminated
|
||||
* strings, and redirect the output to specified file. The file will be
|
||||
* created/truncated if it exists/non-exists. This function will be blocked
|
||||
* until the child process exits.
|
||||
*
|
||||
* @param argv An array of pointers to null-terminated strings that
|
||||
* represent the argument list available to the new program.
|
||||
* The array of pointers must be terminated by a null pointer.
|
||||
* @param outfile File to record command's output, NULL means that this
|
||||
* function doesn't handle command's output.
|
||||
*
|
||||
* @return If a child process could not be created, or its status could not be
|
||||
* retrieved, or it was killed/stopped by signal, the return value
|
||||
* is -1.
|
||||
* If all system calls succeed, then the return value is the
|
||||
* termination status of the child process used to execute command.
|
||||
*/
|
||||
int execv_out2file(char * const argv[], const char *outfile)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
LOGE("fork error (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
int res;
|
||||
int fd = -1;
|
||||
|
||||
if (outfile) {
|
||||
fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
LOGE("open error (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
res = dup2(fd, STDOUT_FILENO);
|
||||
if (res < 0) {
|
||||
close(fd);
|
||||
LOGE("dup2 error (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
res = execvp(argv[0], argv);
|
||||
if (res == -1) {
|
||||
if (fd > 0)
|
||||
close(fd);
|
||||
LOGE("execvp (%s) failed, error (%s)\n", argv[0],
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
pid_t res;
|
||||
int status;
|
||||
int exit_status;
|
||||
|
||||
res = waitpid(pid, &status, 0);
|
||||
if (res == -1) {
|
||||
LOGE("waitpid failed, error (%s)\n", strerror(errno));
|
||||
return res;
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
exit_status = WEXITSTATUS(status);
|
||||
if (!exit_status)
|
||||
LOGI("%s exited, status=0\n", argv[0]);
|
||||
else
|
||||
LOGE("%s exited, status=%d\n", argv[0],
|
||||
exit_status);
|
||||
return exit_status;
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
LOGE("%s killed by signal %d\n", argv[0],
|
||||
WTERMSIG(status));
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
LOGE("%s stopped by signal %d\n", argv[0],
|
||||
WSTOPSIG(status));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command described in format string, and redirect the output
|
||||
* to specified file. The file will be created/truncated if it
|
||||
* exists/non-exists. This function will be blocked until the child process
|
||||
* exits.
|
||||
*
|
||||
* @param outfile File to record command's output, NULL means that this
|
||||
* function doesn't handle command's output.
|
||||
* @param fmt Format string of command.
|
||||
*
|
||||
* @return If a child process could not be created, or its status could not be
|
||||
* retrieved, or it was killed/stopped by signal, the return value
|
||||
* is -1.
|
||||
* If all system calls succeed, then the return value is the
|
||||
* termination status of the child process used to execute command.
|
||||
*/
|
||||
int exec_out2file(const char *outfile, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *cmd;
|
||||
char *start;
|
||||
char *p;
|
||||
int ret;
|
||||
int argc;
|
||||
char **argv;
|
||||
int i = 0;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vasprintf(&cmd, fmt, args);
|
||||
va_end(args);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
strtrim(cmd, ret);
|
||||
argc = strcnt(cmd, ' ') + 1;
|
||||
|
||||
argv = (char **)calloc(argc + 1, sizeof(char *));
|
||||
if (argv == NULL) {
|
||||
free(cmd);
|
||||
LOGE("calloc failed, error (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* string to argv[] */
|
||||
start = cmd;
|
||||
argv[i++] = start;
|
||||
while (start && (p = strchr(start, ' '))) {
|
||||
argv[i++] = p + 1;
|
||||
*p = 0;
|
||||
if (*(p + 1) != '"')
|
||||
start = p + 1;
|
||||
else
|
||||
start = strchr(p + 2, '"');
|
||||
}
|
||||
|
||||
ret = execv_out2file(argv, outfile);
|
||||
|
||||
free(argv);
|
||||
free(cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command described in format string, and redirect the output
|
||||
* to memory. The memory is allocated by this function and needs to be freed
|
||||
* after return.
|
||||
*
|
||||
* @param[out] outmem The pointer to command's output.
|
||||
* @param fmt Format string of command.
|
||||
*
|
||||
* @return the length of command's output if successful, or -1 if not.
|
||||
*/
|
||||
ssize_t exec_out2mem(char **outmem, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *cmd;
|
||||
FILE *pp;
|
||||
char *out = NULL;
|
||||
char *new;
|
||||
char tmp[1024];
|
||||
size_t memsize = 0;
|
||||
size_t newlen = 0;
|
||||
ssize_t len = 0;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vasprintf(&cmd, fmt, args);
|
||||
va_end(args);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
pp = popen(cmd, "r");
|
||||
if (!pp) {
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(tmp, 1024, pp) != NULL) {
|
||||
newlen += strnlen(tmp, 1024);
|
||||
if (newlen + 1 > memsize) {
|
||||
memsize += 1024;
|
||||
new = realloc(out, memsize);
|
||||
if (!new) {
|
||||
if (out) {
|
||||
free(out);
|
||||
out = NULL;
|
||||
}
|
||||
len = -1;
|
||||
goto end;
|
||||
} else {
|
||||
out = new;
|
||||
}
|
||||
}
|
||||
/* fgets read at most 1023 bytes and plus '\0' */
|
||||
memcpy(out + len, tmp, strnlen(tmp, 1024) + 1);
|
||||
|
||||
len = newlen;
|
||||
}
|
||||
|
||||
end:
|
||||
*outmem = out;
|
||||
pclose(pp);
|
||||
free(cmd);
|
||||
|
||||
return len;
|
||||
}
|
1340
misc/tools/acrn-crashlog/common/fsutils.c
Normal file
1340
misc/tools/acrn-crashlog/common/fsutils.c
Normal file
File diff suppressed because it is too large
Load Diff
8
misc/tools/acrn-crashlog/common/include/cmdutils.h
Normal file
8
misc/tools/acrn-crashlog/common/include/cmdutils.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
int execv_out2file(char * const argv[], const char *outfile);
|
||||
int exec_out2file(const char *outfile, const char *fmt, ...);
|
||||
ssize_t exec_out2mem(char **outmem, const char *fmt, ...);
|
135
misc/tools/acrn-crashlog/common/include/fsutils.h
Normal file
135
misc/tools/acrn-crashlog/common/include/fsutils.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __FSUTILS_H__
|
||||
#define __FSUTILS_H__
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define MIN(a, b) (((a) > (b)) ? (b) : (a))
|
||||
|
||||
#define KB (1024)
|
||||
#define MB (KB * KB)
|
||||
#define MAXLINESIZE (PATH_MAX + 128)
|
||||
#define CPBUFFERSIZE (4 * KB)
|
||||
#define PAGE_SIZE (4 * KB)
|
||||
|
||||
struct mm_file_t {
|
||||
char *path;
|
||||
int fd;
|
||||
char *begin;
|
||||
ssize_t size;
|
||||
};
|
||||
|
||||
struct ac_filter_data {
|
||||
const char *str;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static inline int file_exists(const char *filename)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
return (stat(filename, &info) == 0);
|
||||
}
|
||||
|
||||
static inline int directory_exists(const char *path)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
return (stat(path, &info) == 0 && S_ISDIR(info.st_mode));
|
||||
}
|
||||
|
||||
static inline ssize_t get_file_size(const char *filepath)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (filepath == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (stat(filepath, &info) < 0)
|
||||
return -errno;
|
||||
|
||||
return info.st_size;
|
||||
}
|
||||
|
||||
static inline ssize_t get_file_blocks_size(const char *filepath)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (filepath == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (stat(filepath, &info) < 0)
|
||||
return -errno;
|
||||
|
||||
return info.st_blocks * 512;
|
||||
}
|
||||
|
||||
char *mm_get_line(struct mm_file_t *mfile, int line);
|
||||
int mkdir_p(const char *path);
|
||||
int remove_r(const char *dir);
|
||||
int mm_count_lines(struct mm_file_t *mfile);
|
||||
struct mm_file_t *mmap_file(const char *path);
|
||||
void unmap_file(struct mm_file_t *mfile);
|
||||
int do_copy_tail(const char *src, const char *dest, int limit);
|
||||
int do_mv(char *src, char *dest);
|
||||
ssize_t append_file(const char *filename, const char *text, size_t tlen);
|
||||
int replace_file_head(char *filename, char *text);
|
||||
int overwrite_file(const char *filename, const char *value);
|
||||
int readline(int fd, char buffer[MAXLINESIZE]);
|
||||
ssize_t file_read_string(const char *file, char *string, const int size);
|
||||
void file_reset_init(const char *filename);
|
||||
int file_read_int(const char *filename, unsigned int *pcurrent);
|
||||
int file_update_int(const char *filename, unsigned int current,
|
||||
unsigned int max);
|
||||
int do_copy_limit(const char *src, const char *des, size_t limitsize);
|
||||
int space_available(const char *path, int quota);
|
||||
int count_lines_in_file(const char *filename);
|
||||
int read_full_binary_file(const char *path, unsigned long *size,
|
||||
void **data);
|
||||
ssize_t file_read_key_value(char *value, const size_t limit, const char *path,
|
||||
const char *key, size_t klen);
|
||||
ssize_t file_read_key_value_r(char *value, const size_t limit, const char *path,
|
||||
const char *key, size_t klen);
|
||||
int ac_scandir(const char *dirp, struct dirent ***namelist,
|
||||
int (*filter)(const struct dirent *, const void *),
|
||||
const void *farg,
|
||||
int (*compar)(const struct dirent **,
|
||||
const struct dirent **));
|
||||
int filter_filename_substr(const struct dirent *entry, const void *arg);
|
||||
int filter_filename_exactly(const struct dirent *entry, const void *arg);
|
||||
int filter_filename_startswith(const struct dirent *entry,
|
||||
const void *arg);
|
||||
int dir_contains(const char *dir, const char *filename, size_t flen, int exact);
|
||||
int lsdir(const char *dir, char *fullname[], int limit);
|
||||
int find_file(const char *dir, size_t dlen, const char *target_file,
|
||||
size_t tflen, int depth, char *path[], int limit);
|
||||
int dir_blocks_size(const char *dir, size_t dlen, size_t *size);
|
||||
int read_file(const char *path, unsigned long *size, void **data);
|
||||
int is_ac_filefmt(const char *file_fmt);
|
||||
int config_fmt_to_files(const char *file_fmt, char ***out);
|
||||
|
||||
#endif
|
48
misc/tools/acrn-crashlog/common/include/log_sys.h
Normal file
48
misc/tools/acrn-crashlog/common/include/log_sys.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) <2018> Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef __LOG_SYS_H__
|
||||
#define __LOG_SYS_H__
|
||||
|
||||
#include <syslog.h>
|
||||
#include <systemd/sd-journal.h>
|
||||
|
||||
void debug_log(int level, const char *func, int line, ...);
|
||||
|
||||
#define LOG_LEVEL LOG_WARNING
|
||||
|
||||
#ifdef DEBUG_ACRN_CRASHLOG
|
||||
#define LOGE(...) \
|
||||
debug_log(LOG_ERR, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define LOGW(...) \
|
||||
debug_log(LOG_WARNING, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define LOGI(...) \
|
||||
debug_log(LOG_INFO, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define LOGD(...) \
|
||||
debug_log(LOG_DEBUG, __func__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define ac_log(level, ...) \
|
||||
do { \
|
||||
if (level <= LOG_LEVEL) \
|
||||
sd_journal_print(level, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define LOGE(...) \
|
||||
ac_log(LOG_ERR, __VA_ARGS__)
|
||||
|
||||
#define LOGW(...) \
|
||||
ac_log(LOG_WARNING, __VA_ARGS__)
|
||||
|
||||
#define LOGI(...) \
|
||||
ac_log(LOG_INFO, __VA_ARGS__)
|
||||
|
||||
#define LOGD(...) \
|
||||
ac_log(LOG_DEBUG, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif
|
22
misc/tools/acrn-crashlog/common/include/strutils.h
Normal file
22
misc/tools/acrn-crashlog/common/include/strutils.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef __STRUTILS_H__
|
||||
#define __STRUTILS_H__
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#define s_not_expect(res, size) (res < 0 || (size_t)res >= size)
|
||||
|
||||
char *get_line(const char *str, size_t str_size,
|
||||
const char *area, size_t area_size,
|
||||
const char *search_from, size_t *len);
|
||||
ssize_t strlinelen(const char *str, size_t size);
|
||||
char *strrstr(const char *s, const char *str);
|
||||
char *strtrim(char *str, size_t len);
|
||||
int strcnt(char *str, char c);
|
||||
char *strings_ind(char *strings, size_t size, int index, size_t *slen);
|
||||
int str_split_ere(const char *str, size_t slen,
|
||||
const char *fmt, size_t flen, ...);
|
||||
#endif
|
42
misc/tools/acrn-crashlog/common/log_sys.c
Normal file
42
misc/tools/acrn-crashlog/common/log_sys.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) <2018> Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "log_sys.h"
|
||||
|
||||
void debug_log(const int level, const char *func, const int line, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *fmt;
|
||||
char *head;
|
||||
char *msg;
|
||||
|
||||
if (level > LOG_LEVEL)
|
||||
return;
|
||||
|
||||
va_start(args, line);
|
||||
fmt = va_arg(args, char *);
|
||||
if (!fmt) {
|
||||
va_end(args);
|
||||
return;
|
||||
}
|
||||
if (vasprintf(&msg, fmt, args) == -1) {
|
||||
va_end(args);
|
||||
return;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
if (asprintf(&head, "<%-20s%5d>: ", func, line) == -1) {
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
sd_journal_print(level, "%s%s", head, msg);
|
||||
free(msg);
|
||||
free(head);
|
||||
}
|
360
misc/tools/acrn-crashlog/common/strutils.c
Normal file
360
misc/tools/acrn-crashlog/common/strutils.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include "log_sys.h"
|
||||
#include "fsutils.h"
|
||||
|
||||
/**
|
||||
* Find the first line containing specified string in given area.
|
||||
*
|
||||
* @param str A pointer to the string contained by target line.
|
||||
* @param str_size String length of str.
|
||||
* @param area A pointer to the area where target line may be located.
|
||||
* This pointer will be returned if the specified string is in
|
||||
* the first line of area (There is not '\n' located between area
|
||||
* and the head of searched string).
|
||||
* @param area_size String length of area.
|
||||
* @param search_from A pointer where searching starts. It should be greater
|
||||
* than or equal to area, and less than area + area_size.
|
||||
* @param[out] len The length of target line (excludes \n), it only be modified
|
||||
* when function returns successfully.
|
||||
*
|
||||
* @return a pointer to the head of target line within area (it may be greater
|
||||
* than search_from).
|
||||
* NULL will be returned if the specified string is not found in
|
||||
* any lines (lines must end with '\n'. It means the real searching
|
||||
* scope is from search_from to the last '\n' in area).
|
||||
*/
|
||||
char *get_line(const char *str, size_t str_size,
|
||||
const char *area, size_t area_size,
|
||||
const char *search_from, size_t *len)
|
||||
{
|
||||
char *p;
|
||||
char *match;
|
||||
char *tail;
|
||||
ssize_t search_size = area + area_size - search_from;
|
||||
|
||||
if (!str || !str_size || !area || !area_size || !search_from || !len)
|
||||
return NULL;
|
||||
|
||||
if (search_from < area || search_from >= area + area_size ||
|
||||
(size_t)search_size < str_size)
|
||||
return NULL;
|
||||
|
||||
match = memmem(search_from, search_size, str, str_size);
|
||||
if (!match)
|
||||
return NULL;
|
||||
tail = memchr(match + str_size, '\n',
|
||||
area + area_size - match - str_size);
|
||||
if (!tail)
|
||||
return NULL;
|
||||
|
||||
for (p = match; p >= area; p--) {
|
||||
if (*p == '\n') {
|
||||
*len = tail - p - 1;
|
||||
return (char *)(p + 1);
|
||||
}
|
||||
}
|
||||
|
||||
*len = tail - area;
|
||||
return (char *)area;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of line.
|
||||
*
|
||||
* @param str Start address of line.
|
||||
* @param size Size of searched space.
|
||||
*
|
||||
* @return the length of line (excludes \n) if successful, or -1 if not.
|
||||
* This function return -1 if string doesn't contain \n.
|
||||
*/
|
||||
ssize_t strlinelen(const char *str, size_t size)
|
||||
{
|
||||
char *tail;
|
||||
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
tail = memchr(str, '\n', size);
|
||||
if (tail)
|
||||
return tail - str;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the last occurrence of the substring str in the string s.
|
||||
*
|
||||
* @param s Range of search.
|
||||
* @param substr String to be found.
|
||||
*
|
||||
* @return a pointer to the beginning of the substring,
|
||||
* or NULL if the substring is not found.
|
||||
*/
|
||||
char *strrstr(const char *s, const char *substr)
|
||||
{
|
||||
const char *found;
|
||||
const char *p = s;
|
||||
|
||||
while ((found = strstr(p, substr)))
|
||||
p = found + 1;
|
||||
|
||||
if (p != s)
|
||||
return (char *)(p - 1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strtrim(char *str, size_t len)
|
||||
{
|
||||
size_t h_del = 0;
|
||||
size_t reserve;
|
||||
char *p;
|
||||
|
||||
if (!len)
|
||||
return str;
|
||||
|
||||
for (p = str; p < str + len && *p == ' '; p++)
|
||||
h_del++;
|
||||
|
||||
reserve = len - h_del;
|
||||
if (!reserve) {
|
||||
*str = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
for (p = str + len - 1; p >= str && *p == ' '; p--)
|
||||
reserve--;
|
||||
|
||||
memmove(str, str + h_del, reserve);
|
||||
*(str + reserve) = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
int strcnt(char *str, char c)
|
||||
{
|
||||
int cnt = 0;
|
||||
char *p = str;
|
||||
char *found;
|
||||
|
||||
if (!str)
|
||||
return -EINVAL;
|
||||
|
||||
while ((found = strchr(p, c))) {
|
||||
p = found + 1;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
char *strings_ind(char *strings, size_t size, int index, size_t *slen)
|
||||
{
|
||||
int i = 0;
|
||||
size_t len;
|
||||
char *start = strings;
|
||||
char *str_tail;
|
||||
size_t left;
|
||||
|
||||
if (!strings || !size)
|
||||
return NULL;
|
||||
|
||||
str_tail = memchr((void *)strings, '\0', size);
|
||||
if (!str_tail)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
len = str_tail - start;
|
||||
if (i++ == index)
|
||||
break;
|
||||
left = strings + size - str_tail - 1;
|
||||
if (!left)
|
||||
return NULL;
|
||||
start = str_tail + 1;
|
||||
str_tail = memchr((void *)start, '\0', left);
|
||||
if (!str_tail)
|
||||
break;
|
||||
}
|
||||
|
||||
if (slen)
|
||||
*slen = len;
|
||||
return start;
|
||||
}
|
||||
|
||||
static int reg_match(const char *str, const char *pattern,
|
||||
char *matched_sub, size_t matched_space,
|
||||
size_t *end_off)
|
||||
{
|
||||
int err;
|
||||
regex_t reg;
|
||||
char err_msg[128];
|
||||
regmatch_t pm[1];
|
||||
size_t matched_len;
|
||||
|
||||
LOGD("reg: %s\n", pattern);
|
||||
err = regcomp(®, pattern, REG_EXTENDED);
|
||||
if (err) {
|
||||
regerror(err, ®, err_msg, sizeof(err_msg));
|
||||
LOGE("failed to regcomp - %s\n", err_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = regexec(®, str, sizeof(pm)/sizeof(regmatch_t), pm, 0);
|
||||
regfree(®);
|
||||
if (err == REG_NOMATCH) {
|
||||
LOGE("failed to match with reg (%s) str (%s)\n", pattern, str);
|
||||
return -1;
|
||||
}
|
||||
if (pm[0].rm_so == -1)
|
||||
return -1;
|
||||
|
||||
*end_off = pm[0].rm_eo;
|
||||
if (matched_space == 0 || matched_sub == NULL)
|
||||
/* get offset only */
|
||||
return 0;
|
||||
|
||||
matched_len = pm[0].rm_eo - pm[0].rm_so;
|
||||
*(char *)mempcpy(matched_sub, str + pm[0].rm_so,
|
||||
MIN(matched_len, matched_space - 1)) = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *exp_end(const char *fmt, size_t flen, const char *exp_s)
|
||||
{
|
||||
/* supports %[regex..] and %*[regex..] */
|
||||
int flag = 0;
|
||||
const char *p;
|
||||
|
||||
if (exp_s < fmt || exp_s >= fmt + flen)
|
||||
return NULL;
|
||||
|
||||
for (p = exp_s; p < fmt + flen; p++) {
|
||||
if (*p == '[')
|
||||
flag++;
|
||||
|
||||
if (*p == ']') {
|
||||
flag--;
|
||||
if (flag == 0)
|
||||
return (char *)(p + 1);
|
||||
else if (flag < 0)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int exp2reg(const char *s, const char *e, int *ignore_flag, char **reg)
|
||||
{
|
||||
const char *oreg_s;
|
||||
int flag_tmp;
|
||||
char *buf;
|
||||
|
||||
if (memcmp(s, "%*[", 3) == 0) {
|
||||
flag_tmp = 1;
|
||||
oreg_s = s + 3;
|
||||
} else if (memcmp(s, "%[", 2) == 0) {
|
||||
flag_tmp = 0;
|
||||
oreg_s = s + 2;
|
||||
} else {
|
||||
LOGE("invalid exp - exp must start with \"%%[\" or \"%%*[\"\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (oreg_s >= e) {
|
||||
LOGE("invalid exp - exp empty\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = malloc(e - oreg_s + 1);
|
||||
if (!buf) {
|
||||
LOGE("out-of-mem\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[0] = '^';
|
||||
memcpy(&buf[1], oreg_s, e - oreg_s - 1);
|
||||
buf[e - oreg_s] = '\0';
|
||||
|
||||
*reg = buf;
|
||||
*ignore_flag = flag_tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int str_split_ere(const char *str, size_t slen,
|
||||
const char *fmt, size_t flen, ...)
|
||||
{
|
||||
va_list v;
|
||||
char *_str, *_fmt;
|
||||
const char *exp_s, *exp_e;
|
||||
int ignore_flag;
|
||||
char *reg;
|
||||
size_t str_off = 0;
|
||||
size_t off;
|
||||
char *sreq;
|
||||
size_t sreqsize;
|
||||
int ret = 0;
|
||||
|
||||
if (!str || !slen || !fmt || !flen)
|
||||
return ret;
|
||||
|
||||
_str = strndup(str, slen);
|
||||
if (!_str)
|
||||
return ret;
|
||||
_fmt = strndup(fmt, flen);
|
||||
if (!_fmt) {
|
||||
free(_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
va_start(v, flen);
|
||||
/* supports %[regex..] and %*[regex..] */
|
||||
exp_s = _fmt;
|
||||
while (str_off < slen && *exp_s) {
|
||||
exp_e = exp_end(_fmt, flen, exp_s);
|
||||
if (!exp_e) {
|
||||
LOGE("invalid exp - failed to find the end of exp\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (exp2reg(exp_s, exp_e, &ignore_flag, ®) == -1) {
|
||||
LOGE("failed to translate exp to reg\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ignore_flag == 1) {
|
||||
sreq = NULL;
|
||||
sreqsize = 0;
|
||||
} else {
|
||||
sreq = va_arg(v, char *);
|
||||
sreqsize = va_arg(v, size_t);
|
||||
}
|
||||
|
||||
if (reg_match(_str + str_off, reg, sreq, sreqsize,
|
||||
&off) == -1) {
|
||||
LOGE("failed to match reg\n");
|
||||
free(reg);
|
||||
goto out;
|
||||
} else {
|
||||
if (ignore_flag == 0)
|
||||
ret++;
|
||||
}
|
||||
|
||||
exp_s = exp_e;
|
||||
str_off += off;
|
||||
free(reg);
|
||||
}
|
||||
|
||||
out:
|
||||
va_end(v);
|
||||
free(_str);
|
||||
free(_fmt);
|
||||
return ret;
|
||||
}
|
Reference in New Issue
Block a user