mirror of
https://git.planet-casio.com/Lephenixnoir/fxsdk.git
synced 2024-12-29 13:03:37 +01:00
9d30377d90
This commit rewrites the entire device management layer of fxlink on the libusb side, providing new abstractions that support live/async device management, including communication. This system is put to use in a new TUI interactive mode (fxlink -t) which can run in the background, connects to calculators automatically without interfering with file transfer tools, and is much more detailed in its interface than the previous interactive mode (fxlink -i). The TUI mode will also soon be extended to support sending data.
180 lines
4.6 KiB
C
180 lines
4.6 KiB
C
//---------------------------------------------------------------------------//
|
|
// ==>/[_]\ fxlink: A community communication tool for CASIO calculators. //
|
|
// |:::| Made by Lephe' as part of the fxSDK. //
|
|
// \___/ License: MIT <https://opensource.org/licenses/MIT> //
|
|
//---------------------------------------------------------------------------//
|
|
|
|
#include <fxlink/filter.h>
|
|
#include <fxlink/logging.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
//---
|
|
// Filter parser
|
|
//---
|
|
|
|
/* Identify property separating characters to be skipped */
|
|
static bool issep(int c)
|
|
{
|
|
return (c == ' ' || c == '\t' || c == '\n' || c == ',');
|
|
}
|
|
/* Identify valid word characters for the filter */
|
|
static bool isword(int c)
|
|
{
|
|
return c && !strchr(" \t\n,=", c);
|
|
}
|
|
/* Copy the next word in the string, assumes word is non-empty */
|
|
static char *read_word(char const **input)
|
|
{
|
|
char const *str = *input;
|
|
while(**input && isword(**input)) (*input)++;
|
|
return strndup(str, *input - str);
|
|
}
|
|
|
|
/* Reads a property from the input source. Advances *input and sets *name and
|
|
*value to newly-allocated copies of the name and (optional) value of the
|
|
property (T_PROP). Both should be free()'d after use. At the end of the
|
|
input, returns false and sets *name = *value = NULL. */
|
|
static bool read_property(char const **input, char **name, char **value)
|
|
{
|
|
*name = *value = NULL;
|
|
|
|
while(issep(**input))
|
|
(*input)++;
|
|
if(!**input)
|
|
return false;
|
|
|
|
if(!isword(**input)) {
|
|
elog("expected property name in filter, found '%c'; stopping\n",
|
|
**input);
|
|
return false;
|
|
}
|
|
*name = read_word(input);
|
|
|
|
if(**input == '=') {
|
|
(*input)++;
|
|
*value = read_word(input);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
struct fxlink_filter *fxlink_filter_parse(char const *input)
|
|
{
|
|
char *name=NULL, *value=NULL;
|
|
struct fxlink_filter *filter = calloc(1, sizeof *filter);
|
|
if(!filter)
|
|
return NULL;
|
|
|
|
while(read_property(&input, &name, &value)) {
|
|
/* Add a new property to the current option */
|
|
if(!strcmp(name, "p7") && !value)
|
|
filter->p7 = true;
|
|
else if(!strcmp(name, "mass_storage") && !value)
|
|
filter->mass_storage = true;
|
|
else if(!strcmp(name, "series_cg") && !value)
|
|
filter->series_cg = true;
|
|
else if(!strcmp(name, "series_g3") && !value)
|
|
filter->series_g3 = true;
|
|
else if(!strcmp(name, "intf_fxlink") && !value)
|
|
filter->intf_fxlink = true;
|
|
else if(!strcmp(name, "intf_cesg502") && !value)
|
|
filter->intf_cesg502 = true;
|
|
else if(!strcmp(name, "serial") && value)
|
|
filter->serial = strdup(value);
|
|
else if(!strcmp(name, "serial_number") && value) // Old name
|
|
filter->serial = strdup(value);
|
|
else wlog("ignoring invalid filter property: '%s' (%s value)\n",
|
|
name, value ? "with" : "without");
|
|
|
|
free(name);
|
|
free(value);
|
|
}
|
|
return filter;
|
|
}
|
|
|
|
//---
|
|
// Filtering API
|
|
//---
|
|
|
|
void fxlink_filter_clean_libusb(struct fxlink_filter *filter)
|
|
{
|
|
if(!filter)
|
|
return;
|
|
|
|
/* Suppress series_cg and series_g3, which are based off the SCSI metadata
|
|
provided only to UDisks2 */
|
|
if(filter->series_cg) {
|
|
wlog("ignoring series_cg in libusb filter (cannot be detected)\n");
|
|
filter->series_cg = false;
|
|
}
|
|
if(filter->series_g3) {
|
|
wlog("ignoring series_g3 in libusb filter (cannot be detected)\n");
|
|
filter->series_g3 = false;
|
|
}
|
|
}
|
|
|
|
void fxlink_filter_clean_udisks2(struct fxlink_filter *filter)
|
|
{
|
|
/* Every property can be used */
|
|
(void)filter;
|
|
}
|
|
|
|
bool fxlink_filter_match(
|
|
struct fxlink_filter const *props,
|
|
struct fxlink_filter const *filter)
|
|
{
|
|
/* No filter is a pass-through */
|
|
if(!filter)
|
|
return true;
|
|
|
|
if(filter->p7 && !props->p7)
|
|
return false;
|
|
if(filter->mass_storage && !props->mass_storage)
|
|
return false;
|
|
if(filter->intf_fxlink && !props->intf_fxlink)
|
|
return false;
|
|
if(filter->intf_cesg502 && !props->intf_cesg502)
|
|
return false;
|
|
if(filter->series_cg && !props->series_cg)
|
|
return false;
|
|
if(filter->series_g3 && !props->series_g3)
|
|
return false;
|
|
if(filter->serial &&
|
|
(!props->serial || strcmp(filter->serial, props->serial)))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void fxlink_filter_print(FILE *fp, struct fxlink_filter const *filter)
|
|
{
|
|
#define output(...) { \
|
|
if(sep) fprintf(fp, ", "); \
|
|
fprintf(fp, __VA_ARGS__); \
|
|
sep = true; \
|
|
}
|
|
|
|
bool sep = false;
|
|
if(filter->p7)
|
|
output("p7");
|
|
if(filter->mass_storage)
|
|
output("mass_storage");
|
|
if(filter->intf_fxlink)
|
|
output("intf_fxlink");
|
|
if(filter->intf_cesg502)
|
|
output("intf_cesg502");
|
|
if(filter->series_cg)
|
|
output("series_cg");
|
|
if(filter->series_g3)
|
|
output("series_g3");
|
|
if(filter->serial)
|
|
output("serial=%s", filter->serial);
|
|
}
|
|
|
|
void fxlink_filter_free(struct fxlink_filter *filter)
|
|
{
|
|
if(filter)
|
|
free(filter->serial);
|
|
free(filter);
|
|
}
|