This repository has been archived on 2021-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
modetw/src/calibrate.c

382 lines
8.8 KiB
C

#include <libxml2/libxml/parser.h>
#include <libxml2/libxml/tree.h>
#include <string.h>
#include <iconv.h>
#include <limits.h>
#include "calibrate.h"
#include "file_t.h"
#include "conf.h"
#include "paths.h"
#define BUFFER_SIZE 1000
// For testing only
static const char* paths_xml = "../paths.xml";
static const char* conf = "../modetw.conf";
/**
* Convert the text encoding of a string from UTF8 to chosen encoding.
* @return 1 if error,
* 0 otherwise
*/
static char*
convert_text(const char *text, const char *enc, exception_t *e);
/**
* Replace all occurrences of a given a word in string.
*/
static void
replaceAll(char *str, const char *oldWord, const char *newWord);
/**
* Replace a string of text with another in a text file
* @param file Absolute path to file
* @param before before
* @param after after
* @return 1 if error
* 0 otherwise
*/
static int
replace_text_encoded(const char *file, const char *before, const char *after, exception_t *e);
static char*
convert_text(const char *text, const char *enc, exception_t *e) {
iconv_t to;
size_t len_before, len_after;
char *conv;
to = iconv_open("UTF-8", enc);
len_before = strlen(text);
len_after = 2 * len_before;
conv = calloc(len_after, sizeof(char));
if (iconv(to, &text, &len_before, &conv, &len_after) < 0)
{
printf("Error iconv");
return NULL;
}
iconv_close(iconv);
return conv;
}
/**
* Replace all occurrences of a given a word in string.
*/
static void
replaceAll(char *str, const char *oldWord, const char *newWord)
{
char *pos, temp[BUFFER_SIZE];
int index = 0;
int owlen;
owlen = strlen(oldWord);
/* Repeat till all occurrences are replaced. */
while ((pos = strstr(str, oldWord)) != NULL)
{
// Bakup current line
strcpy(temp, str);
// Index of current found word
index = pos - str;
// Terminate str after word found index
str[index] = '\0';
// Concatenate str with new word
strcat(str, newWord);
// Concatenate str with remaining words after
// oldword found index.
strcat(str, temp + index + owlen);
}
}
static int
replace_text_encoded(const char *file, const char *before, const char *after, exception_t *e)
{
FILE *fPtr, *fTemp;
char buffer[BUFFER_SIZE];
/* Open all required files */
fPtr = fopen(file, "r");
fTemp = fopen("replace.tmp", "w");
/* fopen() return NULL if unable to open file in given mode. */
if (fPtr == NULL || fTemp == NULL)
{
e->type = NO_FILE;
return 1;
}
/*
* Read line from source file and write to destination
* file after replacing given word.
*/
while ((fgets(buffer, BUFFER_SIZE, fPtr)) != NULL)
{
// Replace all occurrence of word from current line
replaceAll(buffer, before, after);
// After replacing write it to temp file.
fputs(buffer, fTemp);
}
/* Close all files to release resource */
fclose(fPtr);
fclose(fTemp);
/* Delete original source file */
remove(file);
/* Rename temp file as original file */
rename("replace.tmp", file);
remove("replace.tmp");
return 0;
}
int calibrate(exception_t *e)
{
/* Verify installation */
if (verify(e) > 0)
{
return 1;
}
/* Modify text */
if (edit(e) > 0)
{
return 1;
}
return 0;
}
static int
parse_file(xmlNode *cur, char* type, exception_t *e) {
file_t *f;
xmlChar *name, *sum;
char abspath[CHAR_MAX];
cur = cur->children;
while (cur != NULL)
{
if (xmlStrEqual(cur->name, (const xmlChar*) "name"))
{
name = xmlNodeGetContent(cur->children);
break;
}
cur = cur->next;
}
sprintf(abspath, "%s/%s", type, name);
while (cur != NULL)
{
if (xmlStrEqual(cur->name, (const xmlChar*) "sum"))
{
sum = xmlNodeGetContent(cur->children);
break;
}
cur = cur->next;
}
f = file_init((char*) abspath, FILEPATH_ABSOLUTE, e);
file_md5_gen(f, e);
file_md5_str(f, e);
if (!strcmp(f->hash_str, (char*) sum))
{
e->type = MD5SUM_VERIFY_FAIL;
file_close(f);
return 1;
}
file_close(f);
return 0;
}
int
parse_group(xmlNode *cur, exception_t *e)
{
char *type = NULL;
cur = cur->children;
while (cur != NULL)
{
if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, (const xmlChar*) "type"))
{
xmlChar *key = NULL; // xmlNodeGetContent(cur);
/* if (cur->type != XML_ELEMENT_NODE) { */
/* e->type = XML_READ_FILE_FAIL; */
/* sprintf(e->msg, "not element node"); */
/* return 1; */
/* } */
/* for (xmlNode *child = cur->children; child; child = child->next) { */
/* if (child->type == XML_ELEMENT_NODE) { */
/* xmlChar *key = xmlNodeGetContent(child); */
/* if (key == NULL) */
/* continue; */
/* if (strlen((char *)key) == 0) { */
/* xmlFree(key); */
/* continue; */
/* } */
/* } */
/* } */
if (key == NULL) {
e->type = XML_READ_FILE_FAIL;
sprintf(e->msg, "key == NULL: node type %i", cur->type);
return 1;
}
if (conf_verify_key(conf, (const char*) key, type) > 0) {
e->type = XML_READ_FILE_FAIL;
sprintf(e->msg, "Conf key fail: %s (%i)", (char*)key, xmlStrlen(key));
xmlFree(key);
return 1;
}
xmlFree(key);
break;
}
cur = cur->next;
}
while (cur != NULL)
{
if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, (const xmlChar*) "file"))
{
if (parse_file(cur, type, e) != 0) return 1;
}
cur = cur->next;
}
free(type);
return 0;
}
static int
parse_file_list(xmlNode *cur, exception_t *e)
{
cur = cur->children;
while (cur != NULL)
{
if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, (const xmlChar*) "group"))
{
if (parse_group(cur, e) != 0) return 1;
}
cur = cur->next;
}
return 0;
}
int
verify(exception_t *e)
{
xmlDoc *doc = NULL;
xmlNode *root_element, *cur_node;
// For testing only
file_t *f = file_init(paths_xml, FILEPATH_RELATIVE, e);
if (!exception_null(e)) return 1;
doc = xmlReadFile(f->name, NULL, 0);
if (doc == NULL)
{
e->type = XML_FILE_MISSING;
file_close(f);
return 1;
}
root_element = xmlDocGetRootElement (doc);
if (root_element->type != XML_ELEMENT_NODE || !xmlStrEqual(root_element->name, (const xmlChar*) "paths"))
{
e->type = XML_READ_FILE_FAIL;
sprintf(e->msg, "XML node %s (!= %s) of node no %i (!= %i)\n", (const char*) root_element->name, "paths", root_element->type, XML_ELEMENT_NODE);
return 1;
}
cur_node = root_element->children;
while (cur_node != NULL)
{
if (cur_node->type == XML_ELEMENT_NODE && xmlStrEqual(cur_node->name, (const xmlChar*) "file_list"))
{
if (parse_file_list(cur_node, e) != 0) {
file_close(f);
return 1;
}
}
cur_node = cur_node->next;
}
file_close(f);
return 0;
}
int
edit(exception_t *e)
{
xmlDoc *doc = NULL;
xmlNode *root_element, *cur_node;
doc = xmlReadFile(paths_xml, NULL, 0);
if (doc == NULL)
{
e->type = XML_FILE_MISSING;
return 1;
}
root_element = xmlDocGetRootElement (doc);
if (strcmp((const char*) root_element->name, "paths"))
{
e->type = XML_READ_FILE_FAIL;
return 1;
}
cur_node = root_element->children;
if (strcmp((const char*) cur_node->name, "edit_list"))
{
e->type = XML_READ_FILE_FAIL;
return 1;
}
char *conf, *dir;
size_t lendir;
conf = ".config/modetw/modetw.conf";
for (xmlNode *a_node = cur_node->children; strcmp((const char*) a_node->name, "group") != 0; a_node=a_node->next)
{
xmlNode *x_group_type = a_node->children;
lendir = strlen((const char*) x_group_type);
conf_verify_key(conf, (const char*) x_group_type, dir);
for (xmlNode *b_node = x_group_type->next; strcmp((const char*) b_node->name, "edit") != 0; b_node=b_node->next)
{
size_t lenpath;
file_t *f;
xmlNode *x_path = b_node->children;
xmlNode *x_before = x_path->next;
xmlNode *x_after = x_before->next;
xmlNode *x_type = x_after->next;
lenpath = strlen(x_path);
char fullpath[lenpath + lendir + 1];
strcat(fullpath, x_group_type);
strcat(fullpath, "/");
strcat(fullpath, x_path);
f = file_init(&fullpath, FILEPATH_ABSOLUTE, e);
replace_text(f, x_before, x_after, x_type, e);
file_close(f);
}
}
return 0;
}
int
replace_text(const char *file, const char *before, const char *after, const char *enc, exception_t *e)
{
if (strcmp(enc, "ASCII") == 0) {
return replace_text_encoded(file, before, after, e);
}
return replace_text_encoded(file, convert_text(before, enc, e), convert_text(after, enc, e), e);
}