Загрузка данных
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_TOKENS 128
#define MAX_TOKEN_LEN 512
#define STATS_FILE "chown_stats.txt"
typedef struct {
char tokens[MAX_TOKENS][MAX_TOKEN_LEN];
int token_count;
} ParsedCommand;
typedef struct {
int success_count;
int failed_count;
} CheckStats;
static void trim_and_clean(const char *src, char *dst) {
int i = 0, j = 0;
int in_space = 1;
while (src[i] != '\0') {
if (isspace((unsigned char)src[i])) {
if (!in_space) {
dst[j++] = ' ';
in_space = 1;
}
} else {
dst[j++] = src[i];
in_space = 0;
}
i++;
}
if (j > 0 && dst[j - 1] == ' ') {
j--;
}
dst[j] = '\0';
}
ParsedCommand parse_chown_command(const char *cmd_line) {
ParsedCommand cmd;
cmd.token_count = 0;
char cleaned[4096];
trim_and_clean(cmd_line, cleaned);
char *token = strtok(cleaned, " ");
while (token != NULL && cmd.token_count < MAX_TOKENS) {
strncpy(cmd.tokens[cmd.token_count], token, MAX_TOKEN_LEN - 1);
cmd.tokens[cmd.token_count][MAX_TOKEN_LEN - 1] = '\0';
cmd.token_count++;
token = strtok(NULL, " ");
}
return cmd;
}
int check_command(const ParsedCommand *cmd) {
if (cmd->token_count == 0) return 0;
return (strcmp(cmd->tokens[0], "chown") == 0);
}
static int is_valid_name(const char *s) {
int len = strlen(s);
if (len == 0) return 0;
int all_digits = 1;
for (int i = 0; i < len; i++) {
if (!isdigit((unsigned char)s[i])) {
all_digits = 0;
}
if (!isalnum((unsigned char)s[i]) && s[i] != '-') {
return 0;
}
}
if (all_digits) return 1;
if (isdigit((unsigned char)s[0])) return 0;
return 1;
}
static int validate_spec(const char *spec) {
char buf[MAX_TOKEN_LEN];
strncpy(buf, spec, MAX_TOKEN_LEN - 1);
buf[MAX_TOKEN_LEN - 1] = '\0';
char *colon = strchr(buf, ':');
if (colon == NULL) {
return is_valid_name(buf);
} else {
*colon = '\0';
char *owner_part = buf;
char *group_part = colon + 1;
if (strchr(group_part, ':') != NULL) return 0;
if (strlen(owner_part) == 0 && strlen(group_part) == 0) return 0;
int valid = 1;
if (strlen(owner_part) > 0) valid = valid && is_valid_name(owner_part);
if (strlen(group_part) > 0) valid = valid && is_valid_name(group_part);
return valid;
}
}
int check_keys(const ParsedCommand *cmd, int *has_help_version, int *has_reference_key, int *key_end_index) {
*has_help_version = 0;
*has_reference_key = 0;
*key_end_index = 1;
while (*key_end_index < cmd->token_count) {
const char *tok = cmd->tokens[*key_end_index];
if (tok[0] == '-') {
if (strcmp(tok, "-") == 0 || strcmp(tok, "--") == 0) {
return 0;
}
if (strncmp(tok, "--", 2) == 0) {
if (strcmp(tok, "--help") == 0 || strcmp(tok, "--version") == 0) {
*has_help_version = 1;
} else if (strcmp(tok, "--changes") == 0 || strcmp(tok, "--silent") == 0 ||
strcmp(tok, "--quiet") == 0 || strcmp(tok, "--verbose") == 0 ||
strcmp(tok, "--dereference") == 0 || strcmp(tok, "--no-dereference") == 0 ||
strcmp(tok, "--no-preserve-root") == 0 || strcmp(tok, "--preserve-root") == 0) {
// Валидные длинные ключи
} else if (strncmp(tok, "--from=", 7) == 0) {
if (!validate_spec(tok + 7)) return 0;
} else if (strncmp(tok, "--reference=", 12) == 0) {
if (strlen(tok) <= 12) return 0;
*has_reference_key = 1;
} else {
return 0;
}
} else {
int len = strlen(tok);
for (int j = 1; j < len; j++) {
char c = tok[j];
if (c != 'c' && c != 'f' && c != 'v' && c != 'h' &&
c != 'R' && c != 'H' && c != 'L' && c != 'P') {
return 0;
}
}
}
(*key_end_index)++;
} else {
break;
}
}
return 1;
}
int check_arguments(const ParsedCommand *cmd, int key_end_index, int has_help_version, int has_reference_key) {
if (has_help_version) return 1;
int rem = cmd->token_count - key_end_index;
if (has_reference_key) {
return (rem >= 1);
} else {
if (rem < 2) return 0;
return validate_spec(cmd->tokens[key_end_index]);
}
}
void load_stats_from_file(CheckStats *stats) {
FILE *f = fopen(STATS_FILE, "r");
int total_dummy; // Буфер для считывания сохраненного третьего значения
if (!f) {
stats->success_count = 0;
stats->failed_count = 0;
return;
}
if (fscanf(f, "%d %d %d", &stats->success_count, &stats->failed_count, &total_dummy) != 3) {
stats->success_count = 0;
stats->failed_count = 0;
}
fclose(f);
}
void save_stats_to_file(const CheckStats *stats) {
FILE *f = fopen(STATS_FILE, "w");
if (f) {
// Записываем три значения через пробел
fprintf(f, "%d %d %d\n", stats->success_count, stats->failed_count, stats->success_count + stats->failed_count);
fclose(f);
}
}
int main() {
char line[4096];
CheckStats stats;
while (fgets(line, sizeof(line), stdin)) {
line[strcspn(line, "\r\n")] = '\0';
if (strlen(line) == 0) continue;
if (strcmp(line, "getstats") == 0) {
load_stats_from_file(&stats);
printf("%d %d %d\n", stats.success_count, stats.failed_count, stats.success_count + stats.failed_count);
fflush(stdout);
continue;
}
if (strcmp(line, "getsuccess") == 0) {
load_stats_from_file(&stats);
printf("%d\n", stats.success_count);
fflush(stdout);
continue;
}
if (strcmp(line, "getfailed") == 0) {
load_stats_from_file(&stats);
printf("%d\n", stats.failed_count);
fflush(stdout);
continue;
}
if (strcmp(line, "resetstats") == 0) {
stats.success_count = 0;
stats.failed_count = 0;
save_stats_to_file(&stats);
printf("\n");
fflush(stdout);
continue;
}
ParsedCommand cmd = parse_chown_command(line);
int valid = check_command(&cmd);
int has_help_version = 0, has_reference_key = 0, key_end_index = 1;
if (valid) {
valid = check_keys(&cmd, &has_help_version, &has_reference_key, &key_end_index);
}
if (valid) {
valid = check_arguments(&cmd, key_end_index, has_help_version, has_reference_key);
}
load_stats_from_file(&stats);
if (valid) {
stats.success_count++;
printf("True\n");
} else {
stats.failed_count++;
printf("False\n");
}
save_stats_to_file(&stats);
fflush(stdout);
}
return 0;
}