64,637
社区成员
发帖
与我相关
我的任务
分享
/*
* template.h
*/
#ifndef CSDN_TEMPLATE_H
#define CSDN_TEMPLATE_H
struct template_record;
struct template_record *create_template_record();
void destroy_template_record(struct template_record *record);
int init_template_record(struct template_record *record, char *buffer);
struct template_record *clone_template_record(struct template_record *record);
int replace_template_record(struct template_record *record, char *name, char *value);
void prnt_template_record(struct template_record *record);
void output_template_record(struct template_record *record, char *output_filename);
#endif /* CSDN_TEMPLATE_H */
/*
* template.c
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "mem_alloc.h"
#include "template.h"
#define MAX_TOKEN_NUM 4096
#define VARIABLE_ENTRY_NUM 2048
#define HASH_SLOT_NUM 2048
#define HASH_INDEX(str) ( ELFHash(str, strlen(str)) % (HASH_SLOT_NUM-1) )
struct template_hash_entry {
size_t token_entry;
int did;
size_t next;
};
struct template_record {
char *buffer;
int token_num;
char *tokens[MAX_TOKEN_NUM];
size_t var_map[HASH_SLOT_NUM];
size_t last_entry;
struct template_hash_entry var_array[VARIABLE_ENTRY_NUM];
};
size_t ELFHash(char* str, size_t len) {
size_t hash = 0;
size_t x = 0;
size_t i = 0;
for (i = 0; i < len; str++, i++) {
hash = (hash << 4) + (*str);
if((x = hash & 0xF0000000L) != 0) {
hash ^= (x >> 24);
}
hash &= ~x;
}
return hash;
}
struct template_record *create_template_record() {
int i;
struct template_record *record = NULL;
record = mem_alloc(sizeof(struct template_record));
memset(record, 0, sizeof(struct template_record));
for (i = 0; i < HASH_SLOT_NUM; i++)
record->var_map[i] = -1;
return record;
};
void destroy_template_record(struct template_record *record) {
mem_free(record);
}
int init_template_record(struct template_record *record, char *buffer) {
size_t i = 0, index = 0;
char *ptr, *str;
struct template_hash_entry *entry;
record->buffer = buffer;
ptr = str = record->buffer;
record->tokens[i] = str;
while (*str != '\0') {
while (*ptr != '\0' && *ptr != '$')
ptr++;
if (ptr > str) {
record->tokens[i++] = str;
str = ptr;
}
if (*ptr == '$') {
*ptr++ = '\0';
assert("bad string: '\0' followed '$' !!!"
&& *ptr != '\0');
if (*ptr == '\0')
return -1;
str = ptr;
if (*ptr++ != '$') {
while (*ptr != '\0' && *ptr != '$')
ptr++;
*ptr++ = '\0';
record->tokens[i] = str;
entry = &record->var_array[record->last_entry];
entry->token_entry = i;
index = HASH_INDEX(str);
entry->next = record->var_map[index];
record->var_map[index] = record->last_entry;
record->last_entry++;
i++;
} else {
if (*ptr != '\0' && *ptr == '$') {
ptr++;
record->tokens[i++] = "$$";
}
else
record->tokens[i++] = "$";
}
str = ptr;
}
}
record->token_num = i;
return 0;
}
int replace_template_record(struct template_record *record, char *name, char *value) {
size_t index;
struct template_hash_entry *entry;
int count;
index = record->var_map[HASH_INDEX(name)];
count = 0;
while (index != -1) {
entry = &record->var_array[index];
if (entry->did == 0 && strcmp(record->tokens[entry->token_entry], name) == 0) {
entry->did = 1;
record->tokens[entry->token_entry] = value;
count++;
}
index = entry->next;
}
return count;
}
struct template_record *clone_template_record(struct template_record *record) {
struct template_record *new_record;
new_record = mem_alloc(sizeof(struct template_record));
memcpy(new_record, record, sizeof(struct template_record));
return new_record;
}
void prnt_template_record(struct template_record *record) {
size_t i = 0;
size_t index;
struct template_hash_entry *ptr;
printf("======== tokens ========\n");
printf("token_num: %05d\n", record->token_num);
for (i = 0; i < record->token_num; i++)
printf("[%05d]: %s\n", i, record->tokens[i]);
printf("===== var_map ======\n");
for (i = 0; i < HASH_SLOT_NUM; i++) {
index = record->var_map[i];
if (index != -1) {
ptr = &record->var_array[index];
printf("[%05d]: (%1d, %s, %05d)", i, ptr->did,
record->tokens[ptr->token_entry], ptr->next);
index = ptr->next;
while (index != -1) {
ptr = &record->var_array[index];
printf("->(%1d, %s, %05d)", ptr->did,
record->tokens[ptr->token_entry], ptr->next);
index = ptr->next;
}
printf("\n");
}
}
printf("======== var_array ========\n");
printf("last_entry: %05d\n", record->last_entry);
for (i = 0; i < record->last_entry; i++)
printf("[%05d] (%1d, %s, %05d)\n", i,
record->var_array[i].did,
record->tokens[record->var_array[i].token_entry],
record->var_array[i].next);
}
void output_template_record(struct template_record *record, char *output_filename) {
FILE *fp;
size_t i;
fp = fopen(output_filename, "w+");
for (i = 0; i < record->token_num; i++)
fprintf(fp, "%s",record->tokens[i]);
fclose(fp);
}
/*
* replace.h
*/
#ifndef CSDN_REPLACE_H
#define CSDN_REPLACE_H
struct job_replace {
char *output_filename;
char *template_buffer;
char *variable_buffer;
struct template_record *record_template;
struct variable_record *record_variable;
};
void enqueue_job_queue(struct job_replace *job);
struct job_replace *dequeue_job_queue();
void *task_job(void *arg);
#endif /* CSDN_REPLACE_H */
/*
* replace.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include "mem_alloc.h"
#include "template.h"
#include "variable.h"
#include "replace.h"
#define MAX_JOB_ENTRY_NUM 1024
struct job_queue_entry {
struct job_queue_entry *next;
struct job_queue_entry *prev;
struct job_replace *job;
};
static struct job_queue_entry job_head = {&job_head, &job_head, NULL};
static pthread_mutex_t mutex_queue = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond_queue_empty = PTHREAD_COND_INITIALIZER;;
void enqueue_job_queue(struct job_replace *job) {
struct job_queue_entry *entry;
entry = mem_alloc(sizeof(struct job_queue_entry));
pthread_mutex_lock(&mutex_queue);
entry->job = job;
entry->next = &job_head;
entry->prev = job_head.prev;
entry->prev->next = entry;
pthread_cond_broadcast(&cond_queue_empty);
pthread_mutex_unlock(&mutex_queue);
}
struct job_replace *dequeue_job_queue() {
struct job_queue_entry *entry;
struct job_replace *job;
pthread_mutex_lock(&mutex_queue);
while (job_head.next == &job_head)
pthread_cond_wait(&cond_queue_empty, &mutex_queue);
entry = job_head.next;
job_head.next = entry->next;
entry->next->prev = &job_head;
job = entry->job;
pthread_mutex_unlock(&mutex_queue);
mem_free(entry);
return job;
}
void do_job(struct job_replace *job) {
size_t i, last_entry;
struct variable_entry *entry;
last_entry = job->record_variable->last_entry;
entry = job->record_variable->var_array;
for (i = 0; i < last_entry; i++, entry++)
replace_template_record(job->record_template, entry->name, entry->value);
prnt_template_record(job->record_template);
output_template_record(job->record_template, job->output_filename);
}
void *task_job(void *arg) {
struct job_replace *job;
pthread_detach(pthread_self());
printf("task %d start ...\n", (int)arg);
for (;;) {
job = dequeue_job_queue();
printf("task %d working ...\n", (int)arg);
do_job(job);
mem_free(job->variable_buffer);
mem_free(job->record_template);
mem_free(job->record_variable);
mem_free(job);
}
return (void *)0;
}
#
# Makefile
#
all: test test_template test_variable gen_variable
test: test.o replace.o template.o variable.o mem_alloc.o Makefile
gcc -o test -pthread test.o replace.o template.o variable.o mem_alloc.o
test.o: test.c Makefile
gcc -ggdb -c -o test.o test.c
replace.o: replace.c Makefile
gcc -ggdb -c -o replace.o replace.c
gen_variable: gen_variable.o Makefile
gcc -o gen_variable gen_variable.o
gen_variable.o: gen_variable.c Makefile
gcc -ggdb -c -o gen_variable.o gen_variable.c
test_template: test_template.o template.o mem_alloc.o
gcc -o test_template -pthread test_template.o template.o mem_alloc.o
test_variable: test_variable.o variable.o mem_alloc.o
gcc -o test_variable -pthread test_variable.o variable.o mem_alloc.o
test_template.o: test_template.c Makefile
gcc -ggdb -c -o test_template.o test_template.c
template.o: template.c Makefile
gcc -ggdb -c -o template.o template.c
test_variable.o: test_variable.c Makefile
gcc -ggdb -c -o test_variable.o test_variable.c
variable.o: variable.c Makefile
gcc -ggdb -c -o variable.o variable.c
mem_alloc.o: mem_alloc.c Makefile
gcc -ggdb -c -o mem_alloc.o mem_alloc.c
clean:
rm -f core test test.o replace.o test_template test_template.o template.o \
test_variable test_variable.o variable.o mem_alloc.o
/*
* test.c
*/
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include "mem_alloc.h"
#include "template.h"
#include "variable.h"
#include "replace.h"
#define TEMPLATE_BUFFER_SIZE 100*1024
#define VARIABLE_BUFFER_SIZE 10*1024*1024
static char template_buffer[TEMPLATE_BUFFER_SIZE];
int fill_buffer(void *buffer, size_t size, char *filename) {
int fd;
fd = open(filename, O_RDONLY);
if (fd == -1)
return -1;
if (read(fd, buffer, size) < 0)
return -1;
close(fd);
return 0;
}
int main(int argc, char *argv[]) {
int i;
char *template_filename, *variable_filename;
char *variable_buffer;
struct template_record *record_template, *record_template_template;
struct variable_record *record_variable;
struct job_replace *job;
pthread_t tid;
if (argc < 3) {
printf("usage: ./test T-file V-file-1 [V-file-2] ... [V-file-n]\n");
return -1;
}
template_filename = argv[1];
if (fill_buffer(template_buffer, TEMPLATE_BUFFER_SIZE, template_filename) != 0)
return -1;
if ( (record_template_template = create_template_record()) == NULL)
return -1;
if (init_template_record(record_template_template, template_buffer) != 0) {
free(record_template_template);
return -1;
}
/* create 4 thread */
pthread_create(&tid, NULL, task_job, (void *)0);
pthread_create(&tid, NULL, task_job, (void *)1);
pthread_create(&tid, NULL, task_job, (void *)2);
pthread_create(&tid, NULL, task_job, (void *)3);
/* enqueue job queue */
i = 2;
while ((variable_filename = argv[i++]) != NULL) {
variable_buffer = mem_alloc(VARIABLE_BUFFER_SIZE);
if (fill_buffer(variable_buffer, VARIABLE_BUFFER_SIZE, variable_filename) != 0) {
printf("fill_buffer() with variable_filename: %s failed\n", variable_filename);
mem_free(variable_buffer);
continue;
}
record_variable = create_variable_record();
if ( init_variable_record(record_variable, variable_buffer) != 0) {
printf("bad variable file. filename: %s\n", variable_filename);
mem_free(record_variable);
mem_free(variable_buffer);
continue;
}
record_template = clone_template_record(record_template_template);
job = mem_alloc(sizeof(struct job_replace));
*variable_filename = 'r';
job->output_filename = variable_filename;
job->template_buffer = template_buffer;
job->variable_buffer = variable_buffer;
job->record_template = record_template;
job->record_variable = record_variable;
enqueue_job_queue(job);
}
destroy_template_record(record_template_template);
pthread_exit((void *)0);
return 0;
}
/*
* variable.h
*/
#ifndef CSDN_VARIABLE_H
#define CSDN_VARIABLE_H
#define MAX_VARIABLE_NUM 10*1024*1024
struct variable_entry {
char *name;
char *value;
};
struct variable_record {
char *buffer;
size_t last_entry;
struct variable_entry var_array[MAX_VARIABLE_NUM];
};
struct variable_record *create_variable_record();
void destroy_variable_record(struct variable_record *record);
int init_variable_record(struct variable_record *record, char *buffer);
void prnt_variable_record(struct variable_record *record);
#endif /* CSDN_VARIABLE_H */
/*
* variable.c
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "mem_alloc.h"
#include "variable.h"
struct variable_record *create_variable_record() {
struct variable_record *record = NULL;
record = mem_alloc(sizeof(struct variable_record));
memset(record, 0, sizeof(struct variable_record));
return record;
}
void destroy_variable_record(struct variable_record *record) {
mem_free(record);
}
int init_variable_record(struct variable_record *record, char *buffer) {
struct variable_entry *entry;
char *ptr, *key, *value;
record->buffer = buffer;
ptr = record->buffer;
while (*ptr != 0) {
key = NULL; value = NULL;
/* forward space */
while (*ptr != '\0' && *ptr == ' ')
ptr++;
if (*ptr == '\0' || !isalpha(*ptr))
return -1;
/* key */
key = ptr;
while (isalpha(*ptr))
ptr++;
if (*ptr == ' ') {
*ptr++ = '\0';
while (*ptr != '\0' && *ptr == ' ')
*ptr++ = '\0';
}
if (*ptr != ':')
return -1;
*ptr++ = '\0';
while (*ptr != '\0' && *ptr == ' ')
*ptr++ = '\0';
if (*ptr == '\0' || !isalpha(*ptr))
return -1;
/* value */
value = ptr;
while (isalpha(*ptr))
*ptr++;
if (*ptr == ' ') {
*ptr++ = '\0';
while (*ptr != '\0' && *ptr == ' ')
*ptr++ = '\0';
}
if (*ptr != '\n' && *ptr != '\0')
return -1;
*ptr++ = '\0';
if (key != NULL && value != NULL) {
entry = &record->var_array[record->last_entry++];
entry->name = key;
entry->value = value;
}
}
return 0;
}
void prnt_variable_record(struct variable_record *record) {
size_t i;
struct variable_entry *p;
printf("===== var_array =====\n");
printf("last_entry: %08d\n", record->last_entry);
for (i = 0; i < record->last_entry; i++)
printf("[%08d]: (%s, %s)\n", i, record->var_array[i].name,
record->var_array[i].value);
}
/*
* mem_alloc.h
*/
#ifndef CSDN_MEM_ALLOC_H
#define CSDN_MEM_ALLOC_H
void *mem_alloc(size_t size);
void mem_free(void *ptr);
#endif /* CSDN_MEM_ALLOC_H */
/*
* mem_alloc.c
*/
#include <stdlib.h>
#include <pthread.h>
static pthread_mutex_t mutex_mem = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond_mem = PTHREAD_COND_INITIALIZER;
void *mem_alloc(size_t size) {
void *ptr;
pthread_mutex_lock(&mutex_mem);
while ( (ptr = malloc(size)) == NULL)
pthread_cond_wait(&cond_mem, &mutex_mem);
pthread_mutex_unlock(&mutex_mem);
return ptr;
}
void mem_free(void *ptr) {
pthread_mutex_lock(&mutex_mem);
free(ptr);
pthread_cond_broadcast(&cond_mem);
pthread_mutex_unlock(&mutex_mem);
}