diff options
Diffstat (limited to 'erts/etc/win32/init_file.c')
-rw-r--r-- | erts/etc/win32/init_file.c | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/erts/etc/win32/init_file.c b/erts/etc/win32/init_file.c new file mode 100644 index 0000000000..52f6c41d1d --- /dev/null +++ b/erts/etc/win32/init_file.c @@ -0,0 +1,565 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "init_file.h" + +#define ALLOC malloc +#define REALLOC realloc +#define FREE free + +#define CONTEXT_BUFFER_SIZE 1024 + +typedef struct { + HANDLE fd; + int eof; + int num; + int pos; + char buff[CONTEXT_BUFFER_SIZE]; +} FileContext; + +static char *read_one_line(FileContext *fc) +{ + char *buff = ALLOC(10); + int size = 10; + int num = 0; + int skipping; + int escaped; + +#define PUSH(Char) \ + do { \ + if (num == size) { \ + size += 10; \ + buff = REALLOC(buff,size); \ + } \ + buff[num++] = (Char); \ + } while(0) + +#define POP() (buff[--num]) +#define TOP() (buff[(num-1)]) + + skipping = 0; + escaped = 0; + for(;;) { + char current; + if (fc->eof) { + break; + } + if (fc->pos == fc->num) { + if (!ReadFile(fc->fd, fc->buff, CONTEXT_BUFFER_SIZE, + &(fc->num), NULL) || !(fc->num)) { + fc->eof = 1; + break; + } + fc->pos = 0; + } + current = fc->buff[fc->pos]; + ++(fc->pos); + switch (current) { + case ' ': + if (!skipping && num) { + PUSH(current); + } + escaped = 0; + break; + case ';': + if (!skipping) { + if (!escaped) { + skipping = 1; + } else { + PUSH(current); + } + } + escaped = 0; + break; + case '\\': + if (!skipping) { + if (!escaped) { + escaped = 1; + } else { + PUSH(current); + escaped = 0; + } + } + break; + case '\r': + break; + case '\n': + if (!escaped) { + while (num && TOP() == ' ') { + POP(); + } + if (num) { + goto done; + } + } + skipping = 0; + escaped = 0; + break; + default: + if (!skipping) { + PUSH(current); + } + escaped = 0; + break; + } + } + /* EOF comes here */ + while (num && TOP() == ' ') { + POP(); + } + if (!num) { + FREE(buff); + return NULL; + } + done: + PUSH('\0'); + return buff; +#undef PUSH +#undef POP +#undef TOP +} + +static int is_section_header(char *line) +{ + int x = strlen(line); + return (x > 2 && *line == '[' && line[x-1] == ']'); +} + +static int is_key_value(char *line) +{ + char *p = strchr(line,'='); + + return (p != NULL && p > line); +} + +static char *digout_section_name(char *line) + /* Moving it because it shall later be freed. */ +{ + int x = strlen(line); + memmove(line,line+1,x-1); + line[x-2] = '\0'; + return line; +} + +static void digout_key_value(char *line, char **key, char **value) +{ + char *e = strchr(line,'='); + *key = line; + *value = (e+1); + *e = '\0'; + while (*(--e) == ' ') { + *e = '\0'; + } + while (**value == ' ') { + ++(*value); + } +} + +InitFile *load_init_file(char *filename) +{ + HANDLE infile; + InitFile *inif; + InitSection *inis; + InitEntry *inie; + FileContext fc; + char *line; + char **lines; + int size_lines; + int num_lines; + + int i; + + if ( (infile = CreateFile(filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) { + return NULL; + } + + size_lines = 10; + num_lines = 0; + lines = ALLOC(size_lines * sizeof(char *)); + + fc.fd = infile; + fc.eof = 0; + fc.num = 0; + fc.pos = 0; + while ((line = read_one_line(&fc)) != NULL) { + if (num_lines == size_lines) { + size_lines += 10; + lines = REALLOC(lines,size_lines * sizeof(char *)); + } + lines[num_lines] = line; + ++num_lines; + } + CloseHandle(infile); + /* Now check the lines before doing anything else, so that + we don't need any error handling while creating the data + structures */ + /* + The file should contain: + [section] + Key=Value + ... + [section] + ... + */ + i = 0; + while (i < num_lines && is_section_header(lines[i])) { + ++i; + while (i < num_lines && is_key_value(lines[i])) { + ++i; + } + } + if (i < num_lines) { + for (i = 0; i < num_lines; ++i) { + FREE(lines[i]); + } + FREE(lines); + return NULL; + } + + /* So, now we know it's consistent... */ + i = 0; + inif = ALLOC(sizeof(InitFile)); + inif->num_sections = 0; + inif->size_sections = 10; + inif->sections = ALLOC(sizeof(InitSection *) * 10); + while (i < num_lines) { + inis = ALLOC(sizeof(InitSection)); + inis->num_entries = 0; + inis->size_entries = 10; + inis->section_name = digout_section_name(lines[i]); + inis->entries = ALLOC(sizeof(InitEntry *) * 10); + ++i; + while (i < num_lines && is_key_value(lines[i])) { + inie = ALLOC(sizeof(InitEntry)); + digout_key_value(lines[i], &(inie->key), &(inie->value)); + if (inis->num_entries == inis->size_entries) { + inis->size_entries += 10; + inis->entries = + REALLOC(inis->entries, + sizeof(InitEntry *) * inis->size_entries); + } + inis->entries[inis->num_entries] = inie; + ++(inis->num_entries); + ++i; + } + if (inif->num_sections == inif->size_sections) { + inif->size_sections += 10; + inif->sections = + REALLOC(inif->sections, + sizeof(InitSection *) * inif->size_sections); + } + inif->sections[inif->num_sections] = inis; + ++(inif->num_sections); + } + FREE(lines); /* Only the array of strings, not the actual strings, they + are kept in the data structures. */ + return inif; +} + +int store_init_file(InitFile *inif, char *filename) +{ + char *buff; + int size = 10; + int num = 0; + int i,j; + HANDLE outfile; + +#define PUSH(Char) \ + do { \ + if (num == size) { \ + size += 10; \ + buff = REALLOC(buff,size); \ + } \ + buff[num++] = (Char); \ + } while(0) + + if ( (outfile = CreateFile(filename, + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) { + return INIT_FILE_OPEN_ERROR; + } + buff = ALLOC(size); + + for(i = 0; i < inif->num_sections; ++i) { + int len; + int written; + InitSection *inis = inif->sections[i]; + + if (!WriteFile(outfile,"[",1,&written,NULL) || written != 1) { + goto write_error; + } + len = strlen(inis->section_name); + if (!WriteFile(outfile,inis->section_name,len,&written,NULL) || + written != len) { + goto write_error; + } + if (!WriteFile(outfile,"]\n",2,&written,NULL) || written != 2) { + goto write_error; + } + for (j = 0; j < inis->num_entries; ++j) { + InitEntry *inie = inis->entries[j]; + char *p = inie->key; + num = 0; + for (;*p != '\0';++p) { + switch (*p) { + case '\\': + case ';': + PUSH('\\'); + default: + PUSH(*p); + break; + } + } + PUSH('='); + p = inie->value; + for (;*p != '\0';++p) { + switch (*p) { + case '\\': + case ';': + PUSH('\\'); + default: + PUSH(*p); + break; + } + } + PUSH('\n'); + if (!WriteFile(outfile,buff,num,&written,NULL) || written != num) { + goto write_error; + } + } + } + FREE(buff); + CloseHandle(outfile); + return INIT_FILE_NO_ERROR; + write_error: + FREE(buff); + CloseHandle(outfile); + return INIT_FILE_WRITE_ERROR; +#undef PUSH +} + +InitFile *create_init_file(void) +{ + InitFile *inif = ALLOC(sizeof(InitFile)); + inif->num_sections = 0; + inif->size_sections = 10; + inif->sections = ALLOC(sizeof(InitSection *) * 10); + return inif; +} + +InitSection *create_init_section(char *section_name) +{ + InitSection *inis = ALLOC(sizeof(InitSection)); + inis->num_entries = 0; + inis->section_name = ALLOC(sizeof(char) * (strlen(section_name) + 1)); + strcpy(inis->section_name, section_name); + inis->size_entries = 10; + inis->entries = ALLOC(sizeof(InitEntry *) * 10); + return inis; +} + +static void free_init_entry(InitEntry *inie) +{ + FREE(inie->key); + /* Value is part of the same buffer */ + FREE(inie); +} + +void free_init_section(InitSection *inis) +{ + int i; + for (i = 0;i < inis->num_entries; ++i) { + free_init_entry(inis->entries[i]); + } + FREE(inis->entries); + FREE(inis->section_name); + FREE(inis); +} + +void free_init_file(InitFile *inif) +{ + int i; + for (i = 0; i < inif->num_sections; ++i) { + free_init_section(inif->sections[i]); + } + FREE(inif->sections); + FREE(inif); +} + +static int find_init_section(InitFile *inif, char *section_name) +{ + int i; + for (i = 0; i < inif->num_sections; ++i) { + if (!strcmp(inif->sections[i]->section_name, section_name)) { + return i; + } + } + return -1; +} + +int delete_init_section(InitFile *inif, char *section_name) +{ + int i; + + if ((i = find_init_section(inif, section_name)) < 0) { + return INIT_FILE_NOT_PRESENT; + } + + free_init_section(inif->sections[i]); + --(inif->num_sections); + inif->sections[i] = inif->sections[inif->num_sections]; + + return INIT_FILE_PRESENT; +} + +int add_init_section(InitFile *inif, InitSection *inis) +{ + int i; + InitSection *oinis; + if ((i = find_init_section(inif, inis->section_name)) >= 0) { + oinis = inif->sections[i]; + inif->sections[i] = inis; + free_init_section(oinis); + return INIT_FILE_PRESENT; + } + if (inif->num_sections == inif->size_sections) { + inif->size_sections += 10; + inif->sections = REALLOC(inif->sections, + sizeof(InitSection *) * inif->size_sections); + } + inif->sections[inif->num_sections] = inis; + ++(inif->num_sections); + return INIT_FILE_NOT_PRESENT; +} + +InitSection *lookup_init_section(InitFile *inif, char *section_name) +{ + int i; + if ((i = find_init_section(inif,section_name)) < 0) { + return NULL; + } + return inif->sections[i]; +} + +char *nth_init_section_name(InitFile *inif, int n) +{ + if (n >= inif->num_sections) { + return NULL; + } + return inif->sections[n]->section_name; +} + +/* Inefficient... */ +InitSection *copy_init_section(InitSection *inis, char *new_name) +{ + int i; + char *key; + InitSection *ninis = create_init_section(new_name); + i = 0; + while ((key = nth_init_entry_key(inis,i)) != NULL) { + add_init_entry(ninis, key, lookup_init_entry(inis, key)); + ++i; + } + return ninis; +} + +static int find_init_entry(InitSection *inis, char *key) +{ + int i; + for (i = 0; i < inis->num_entries; ++i) { + if (!strcmp(inis->entries[i]->key,key)) { + return i; + } + } + return -1; +} + +int add_init_entry(InitSection *inis, char *key, char *value) +{ + int keylen = strlen(key); + char *buff = ALLOC(sizeof(char) * (keylen + strlen(value) + 2)); + InitEntry *inie; + char *obuff; + int i; + + strcpy(buff,key); + strcpy(buff+keylen+1,value); + + if ((i = find_init_entry(inis,key)) >= 0) { + inie = inis->entries[i]; + FREE(inie->key); + inie->key = buff; + inie->value = buff+keylen+1; + return INIT_FILE_PRESENT; + } + inie = ALLOC(sizeof(InitEntry)); + inie->key = buff; + inie->value = buff+keylen+1; + if (inis->num_entries == inis->size_entries) { + inis->size_entries += 10; + inis->entries = REALLOC(inis->entries, + sizeof(InitEntry *) * inis->size_entries); + } + inis->entries[inis->num_entries] = inie; + ++(inis->num_entries); + return INIT_FILE_NOT_PRESENT; +} + +char *lookup_init_entry(InitSection *inis, char *key) +{ + int i; + if ((i = find_init_entry(inis,key)) < 0) { + return NULL; + } + return inis->entries[i]->value; +} + +char *nth_init_entry_key(InitSection *inis, int n) +{ + if (n >= inis->num_entries) { + return NULL; + } + return inis->entries[n]->key; +} + +int delete_init_entry(InitSection *inis, char *key) +{ + int i; + InitEntry *inie; + if ((i = find_init_entry(inis, key)) < 0) { + return INIT_FILE_NOT_PRESENT; + } + free_init_entry(inis->entries[i]); + --(inis->num_entries); + inis->entries[i] = inis->entries[inis->num_entries]; + return INIT_FILE_PRESENT; +} + |