mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
After including the use of glib we might as well replace inih with the glib key file parser. All configuraiton file parsing has been reworked and also the options parsing has been cleaned up, resulting in better and stricter configuration file and option value checks. Compared to old, configuration files now requires any default configurations to be put in a group/section named [default]. Configuration file keywords such as "enable", "disable", "on", "off", "yes", "no", "0", "1" have been retired. Now only "true" and "false" apply to boolean configuration options. This is done to simplify things and avoid any confusion. The pattern option feature has been reworked so now the user can now access the full match string and any matching subexpression using the %mN syntax. For example: [usb devices] pattern = usb([0-9]*) device = /dev/ttyUSB%m1 Then when using tio: $ tio usb12 %m0 = 'usb12' // Full match string %m1 = 12 // First match subexpression Which results in device = /dev/ttyUSB12
251 lines
5.8 KiB
C
251 lines
5.8 KiB
C
/*
|
|
* tio - a serial device I/O tool
|
|
*
|
|
* Copyright (c) 2014-2022 Martin Lund
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
#define __STDC_WANT_LIB_EXT2__ 1 // To access vasprintf
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <libgen.h>
|
|
#include "options.h"
|
|
#include "print.h"
|
|
#include "error.h"
|
|
#include "fs.h"
|
|
|
|
#define IS_ESC_CSI_INTERMEDIATE_CHAR(c) ((c >= 0x20) && (c <= 0x3F))
|
|
#define IS_ESC_END_CHAR(c) ((c >= 0x30) && (c <= 0x7E))
|
|
#define IS_CTRL_CHAR(c) ((c >= 0x00) && (c <= 0x1F))
|
|
|
|
static FILE *fp = NULL;
|
|
static char file_buffer[BUFSIZ];
|
|
static const char *log_filename = NULL;
|
|
|
|
static char *date_time(void)
|
|
{
|
|
static char date_time_string[50];
|
|
struct tm *tm;
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
tm = localtime(&tv.tv_sec);
|
|
strftime(date_time_string, sizeof(date_time_string), "%Y-%m-%dT%H:%M:%S", tm);
|
|
|
|
return date_time_string;
|
|
}
|
|
|
|
int log_open(const char *filename)
|
|
{
|
|
char *automatic_filename;
|
|
char *dir_plus_automatic_filename;
|
|
|
|
if (filename == NULL)
|
|
{
|
|
// Generate filename if none provided
|
|
if (option.auto_connect == AUTO_CONNECT_DIRECT)
|
|
{
|
|
// File name format ("tio_TARGET_YYYY-MM-DDTHH:MM:SS.log")
|
|
asprintf(&automatic_filename, "tio_%s_%s.log", basename((char *)option.target), date_time());
|
|
}
|
|
else
|
|
{
|
|
// If using 'new' or 'latest' autoconnect strategy we simply use strategy
|
|
// name to name autogenerated log name as device names may vary
|
|
asprintf(&automatic_filename, "tio_%s_%s.log",
|
|
option_auto_connect_state_to_string(option.auto_connect),
|
|
date_time());
|
|
}
|
|
|
|
if (option.log_directory != NULL)
|
|
{
|
|
if (fs_dir_exists(option.log_directory) == false)
|
|
{
|
|
tio_error_printf("Log directory not found");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
asprintf(&dir_plus_automatic_filename, "%s/%s", option.log_directory, automatic_filename);
|
|
filename = dir_plus_automatic_filename;
|
|
}
|
|
else
|
|
{
|
|
filename = automatic_filename;
|
|
}
|
|
}
|
|
|
|
log_filename = filename;
|
|
|
|
// Open log file
|
|
if (option.log_append)
|
|
{
|
|
// Append to existing log file
|
|
fp = fopen(filename, "a+");
|
|
}
|
|
else
|
|
{
|
|
// Truncate existing log file
|
|
fp = fopen(filename, "w+");
|
|
}
|
|
if (fp == NULL)
|
|
{
|
|
tio_warning_printf("Could not open log file %s (%s)", filename, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
// Enable line buffering
|
|
setvbuf(fp, file_buffer, _IOLBF, BUFSIZ);
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool log_strip(char c)
|
|
{
|
|
static char previous_char = 0;
|
|
static bool esc_sequence = false;
|
|
bool strip = false;
|
|
|
|
/* Detect if character should be stripped or not */
|
|
switch (c)
|
|
{
|
|
case 0xa:
|
|
/* Line feed / new line */
|
|
/* Reset ESC sequence just in case something went wrong with the
|
|
* escape sequence parsing. */
|
|
esc_sequence = false;
|
|
break;
|
|
|
|
case 0x1b:
|
|
/* Escape */
|
|
strip = true;
|
|
break;
|
|
|
|
case 0x5b:
|
|
/* Left bracket */
|
|
if (previous_char == 0x1b)
|
|
{
|
|
// Start of ESC sequence
|
|
esc_sequence = true;
|
|
strip = true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (IS_CTRL_CHAR(c))
|
|
{
|
|
/* Strip ASCII control characters */
|
|
strip = true;
|
|
break;
|
|
}
|
|
else
|
|
if ((esc_sequence) && (IS_ESC_CSI_INTERMEDIATE_CHAR(c)))
|
|
{
|
|
strip = true;
|
|
break;
|
|
}
|
|
else
|
|
if ((esc_sequence) && (IS_ESC_END_CHAR(c)))
|
|
{
|
|
esc_sequence = false;
|
|
strip = true;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
previous_char = c;
|
|
|
|
return strip;
|
|
}
|
|
|
|
void log_printf(const char *format, ...)
|
|
{
|
|
if (fp == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
char *line;
|
|
|
|
va_list(args);
|
|
va_start(args, format);
|
|
vasprintf(&line, format, args);
|
|
va_end(args);
|
|
|
|
fwrite(line, strlen(line), 1, fp);
|
|
|
|
free(line);
|
|
}
|
|
|
|
void log_putc(char c)
|
|
{
|
|
if (fp == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (option.output_mode == OUTPUT_MODE_HEX)
|
|
{
|
|
fprintf(fp, "%02x ", (unsigned char) c);
|
|
}
|
|
else
|
|
{
|
|
if (option.log_strip)
|
|
{
|
|
if (log_strip(c) == false)
|
|
{
|
|
fputc(c, fp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fputc(c, fp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void log_close(void)
|
|
{
|
|
if (fp != NULL)
|
|
{
|
|
fclose(fp);
|
|
fp = NULL;
|
|
log_filename = NULL;
|
|
}
|
|
}
|
|
|
|
void log_exit(void)
|
|
{
|
|
if ((option.log) && (log_filename != NULL))
|
|
{
|
|
tio_printf("Saved log to file %s", log_filename);
|
|
log_close();
|
|
}
|
|
}
|
|
|
|
const char *log_get_filename(void)
|
|
{
|
|
return log_filename;
|
|
}
|