#include #include #include #include #include #include #include "script_parser.h" #include "debug.h" #define ITEM_NAME_MAX_LEN 32 #define KEY_MAX_LEN 32 #define VALUE_MAX_LEN 128 #define ITEM_MAX_COUNT 128 #define LINE_MAX_LEN 512 #define LINE_ERROR -1 #define LINE_COMMENT 0 #define LINE_NULL 1 #define LINE_MAINKEY 2 #define LINE_SUBKEY 3 #define DATA_TYPE_SINGLE_WORD 1 #define DATA_TYPE_STRING 2 #define DATA_TYPE_MULTI_WORD 3 #define DATA_TYPE_GPIO 4 struct script_head { int mainkey_cnt; int version[3]; }; struct script_item { char name[32]; int length; int offset; }; /* * get value data type. */ static int __get_str2int(char *buf, int value[]) { char *src; char ch; unsigned int temp; int sign; int i; int idx; char str[128]; src = buf; if (strncasecmp(src, "port:p", 6) == 0) { /* handle gpio */ src += 6; if (strncasecmp(src, "ower", 4) == 0) { value[0] = 0xffff; src += 4; } else { ch = *src++; if (islower(ch)) value[0] = ch - 'a' + 1; else if (isupper(ch)) value[0] = ch - 'A' + 1; else return -1; } temp = 0; ch = *src++; while (ch != '<') { if (isdigit(ch)) { temp = temp * 10 + (ch - '0'); ch = *src++; } else if (ch == '\0') { src--; break; } else { return -1; } } value[1] = temp; idx = 2; ch = *src++; while (ch != '\0') { i = 0; memset(str, 0, sizeof(str)); while (ch != '>') { if (isupper(ch)) ch = tolower(ch); str[i++] = ch; ch = *src++; } if (strcmp(str, "default") == 0 || strcmp(str, "none") == 0 || strcmp(str, "null") == 0 || strcmp(str, "-1") == 0) { value[idx] = -1; } else { i = 0; ch = str[i++]; temp = 0; if (ch == '-') { sign = -1; ch = str[i++]; } else { sign = 1; } while (ch != '\0') { if (isdigit(ch)) temp = temp * 10 + (ch - '0'); else return -1; ch = str[i++]; } value[idx] = temp * sign; } idx++; ch = *src++; if (ch == '<') { ch = *src++; } else if (ch == '\0') { ; } else { return -1; } } switch (idx) { case 3: value[3] = -1; case 4: value[4] = -1; case 5: value[5] = -1; case 6: break; default: return -1; } return DATA_TYPE_GPIO; } else if (strncasecmp(src, "string:", 7) == 0) { src += 7; idx = 0; while (src[idx] != '\0') { idx++; if (idx > 127) break; } if (idx & 0x03) idx = (idx & (~0x03)) + 4; value[0] = idx >> 2; value[1] = 1; return DATA_TYPE_STRING; } else if (src[0] == '"') { src += 1; idx = 0; while (src[idx] != '"') { idx++; if (idx > 127) break; } src[idx] = '\0'; if (idx & 0x03) idx = (idx & (~0x03)) + 4; value[0] = idx >> 2; value[1] = 2; return DATA_TYPE_STRING; } else if (isdigit(src[0]) && (src[1] == 'x' || src[2] == 'X')) { temp = 0; ch = *src++; while (ch != '\0') { if (isdigit(ch)) { temp = temp * 16 + (ch - '0'); ch = *src++; } else if (isupper(ch)) { temp = temp * 16 + (ch - 'A' + 10); ch = *src++; } else if (islower(ch)) { temp = temp * 16 + (ch - 'a' + 10); ch = *src++; } else { break; } } value[0] = temp; return DATA_TYPE_SINGLE_WORD; } else if (isdigit(src[0]) || (isdigit(src[1]) && src[0] == '-')) { if (src[0] == '-') { sign = -1; ch = *src++; } else { sign = 1; } temp = 0; ch = *src++; while (ch != '\0') { if (isdigit(ch)) { temp = temp * 10 + (ch - '0'); ch = *src++; } else { break; } } value[0] = temp * sign; return DATA_TYPE_SINGLE_WORD; } else { idx = 0; while (src[idx] != '\0') { idx++; if (idx > 127) break; } if (idx & 0x03) idx = (idx & (~0x03)) + 4; value[0] = idx >> 2; return DATA_TYPE_STRING; } } /* * get key[32] and value[128], end with '\0'. * \retval -1 empty line. * \retval 0 OK */ static int __get_key_value(char *buf, char *key, char *value) { char *src; int key_idx; int value_idx; /* check line */ src = buf; key_idx = value_idx = 0; while (1) { if (*src == ' ' || *src == '\t') { src++; } else if (*src == 0x0a || *src == 0x0d) { key[key_idx] = '\0'; value[value_idx] = '\0'; return -1; } else { break; } } /* get key */ while (*src != '=') { key[key_idx++] = *src++; if (key_idx >= 31) { key[key_idx] = '\0'; break; } } for (key_idx--; key_idx > 0; key_idx--) { if (key[key_idx] == ' ' || key[key_idx] == '\t') { key[key_idx] = '\0'; } else { key[key_idx + 1] = '\0'; break; } } for (; *src != '='; src++); /* check line */ src++; while (1) { if (*src == ' ' || *src == '\t') { src++; } else if (*src == 0x0a || *src == 0x0d) { value[value_idx] = '\0'; return 0; } else { break; } } /* get value */ while (*src != 0x0a && *src != 0x0d) { value[value_idx++] = *src++; if (value_idx >= 127) { value[value_idx] = '\0'; break; } } for (value_idx--; value_idx > 0; value_idx--) { if (value[value_idx] == ' ' || value[value_idx] == '\t') { value[value_idx] = '\0'; } else { value[value_idx + 1] = '\0'; break; } } return 0; } static int __fill_mainkey(char *buf, struct script_item *item) { char *src; char ch; int i; src = buf + 1; for (ch = *src++, i = 0; ch != ']'; i++, ch = *src++) { item->name[i] = ch; if (i + 1 >= ITEM_NAME_MAX_LEN) { item->name[i] = '\0'; break; } } if (item->name[0] == '\0') return -1; return 0; } static int __getline(char *buf, int len, int *flag) { char *src; char ch; char prev_ch; int line_len; /* get line flag */ src = buf; ch = *src++; switch (ch) { case ';': *flag = LINE_COMMENT; break; case 0x0a: case 0x0d: *flag = LINE_NULL; break; case '[': *flag = LINE_MAINKEY; break; default: *flag = LINE_SUBKEY; break; } /* get line length */ if (*flag == LINE_NULL) { ch = *src++; if (ch == 0x0a) return 2; else return 1; } ch = *src++; line_len = 1; while (line_len < len) { if (ch == 0x0a || ch == 0x0d) break; ch = *src++; line_len++; if (line_len >= LINE_MAX_LEN) { *flag = LINE_ERROR; return 0; } } line_len++; prev_ch = ch; ch = *src++; if (prev_ch == 0x0d) { if (ch == 0x0a) line_len++; } return line_len; } static char* __parse_script(char *buf, int len) { char *src; int rest_len, line_num; struct script_item *item_table = NULL; struct script_head head; unsigned int mainkey_idx, subkey_idx; int new_mainkey; char key[KEY_MAX_LEN]; char value[VALUE_MAX_LEN]; char *key_data = NULL, *key_addr; int *value_data = NULL, *value_addr; int value_idx; int fmt_value[8]; unsigned int i; int ret; int shmid; char *script_buf, *pos; db_debug("the length of script is %d\n", len); /* allocate memory for key and value */ item_table = malloc(sizeof(struct script_item) * ITEM_MAX_COUNT); if (item_table == NULL) { db_debug("allocate memory for main key failed(%s)\n", strerror(errno)); ret = -1; goto out; } memset(item_table, 0, sizeof(struct script_item) * ITEM_MAX_COUNT); key_data = malloc(512 * 1024); if (key_data == NULL) { db_debug("allocate memory for key data failed(%s)\n", strerror(errno)); ret = -1; goto out; } memset(key_data, 0, 512 * 1024); key_addr = key_data; value_data = malloc(512 * 1024); if (value_data == NULL) { db_debug("allocate memory for value data failed(%s)\n", strerror(errno)); ret = -1; goto out; } memset(value_data, 0, 512 * 1024); value_addr = value_data; /* parse script main loop */ src = buf; rest_len = len; mainkey_idx = subkey_idx = value_idx = 0; new_mainkey = 0; line_num = 0; while (rest_len) { int line_len; int flag; /* get current line */ line_len = __getline(src, rest_len, &flag); rest_len -= line_len; line_num++; switch (flag) { case LINE_COMMENT: case LINE_NULL: break; case LINE_MAINKEY: /* get main key */ if (__fill_mainkey(src, &item_table[mainkey_idx])) { ret = -1; goto out; } if (new_mainkey) { item_table[mainkey_idx].offset = item_table[mainkey_idx-1].offset + item_table[mainkey_idx-1].length * 10; } else { /* first main key */ new_mainkey = 1; item_table[mainkey_idx].offset = 0; } mainkey_idx++; break; case LINE_SUBKEY: /* get key[32] and value[128] */ memset(key, 0, KEY_MAX_LEN); memset(value, 0, VALUE_MAX_LEN); ret = __get_key_value(src, key, value); if (ret == -1) continue; /* stores key[32], stores value's offset in the next 4 bytes, * stores value's length[31;16] and type[0:15] in the next * next 4 bytes. there are total 40 bytes for one key data. * * the unit of value data length is int */ strcpy(key_addr, key); key_addr += KEY_MAX_LEN; /* get value data type */ memset(fmt_value, 0, sizeof(int) * 8); ret = __get_str2int(value, fmt_value); switch (ret) { case DATA_TYPE_SINGLE_WORD: *value_addr = fmt_value[0]; *(unsigned int *)key_addr = value_idx; key_addr += 4; *(unsigned int *)key_addr = (1 << 0) | (DATA_TYPE_SINGLE_WORD << 16); value_addr++; value_idx++; break; case DATA_TYPE_STRING: if (fmt_value[0]) { if (fmt_value[1] == 1) { strncpy((char *)value_addr, value + sizeof("string:") - 1, fmt_value[0] << 2); } else if (fmt_value[1] == 2) { strncpy((char *)value_addr, value + 1, fmt_value[0] << 2); } else{ strncpy((char *)value_addr, value, fmt_value[0] << 2); } } *(unsigned int *)key_addr = value_idx; key_addr += 4; *(unsigned int *)key_addr = (fmt_value[0] << 0) | (DATA_TYPE_STRING << 16); value_addr += fmt_value[0]; value_idx += fmt_value[0]; break; case DATA_TYPE_GPIO: for (i = 0; i < 6; i++) *value_addr++ = fmt_value[i]; *(unsigned int *)key_addr = value_idx; key_addr += 4; *(unsigned int *)key_addr = (6 << 0) | (DATA_TYPE_GPIO << 16); value_idx += 6; break; default: db_debug("%s: L%d: fix me\n", __func__, __LINE__); } subkey_idx++; key_addr += 4; item_table[mainkey_idx - 1].length++; break; default: db_debug("script format error at line %d\n", line_num); ret = -1; goto out; } src += line_len; } if (mainkey_idx <= 0) { db_debug("mainkey_idx = %d\n", mainkey_idx); ret = -1; goto out; } /* recalc first subkey offset */ for (i = 0; i < mainkey_idx; i++) { item_table[i].offset += (sizeof(struct script_head) >> 2) + ((sizeof(struct script_item) * mainkey_idx) >> 2); } /* recalc every subkey offset */ key_addr = key_data; i = 0; while (i < subkey_idx * 10 * sizeof(int)) { key_addr += ITEM_NAME_MAX_LEN; *(unsigned int *)key_addr += (sizeof(struct script_head) >> 2) + ((sizeof(struct script_item) * mainkey_idx) >> 2) + (subkey_idx * 10); i += 10 * sizeof(int); /* the sizeof each subkey data */ key_addr += 8; } /* init script head */ head.mainkey_cnt = mainkey_idx; head.version[0] = SCRIPT_VERSION0; head.version[1] = SCRIPT_VERSION1; head.version[2] = SCRIPT_VERSION2; /* allocate share memory segment for script buffer */ i = sizeof(struct script_head) + sizeof(struct script_item) * mainkey_idx + 10 * sizeof(int) * subkey_idx + sizeof(int) * value_idx; #if 0 shmid = shmget(IPC_PRIVATE, i, IPC_CREAT | 0666); if (shmid == -1) { db_debug("allocate share memory segment for script buffer " "failed(%s)\n", strerror(errno)); ret = -1; goto out; } db_debug("script shmid = %d\n", shmid); script_buf = pos = shmat(shmid, 0, 0); if (script_buf == (void *)-1) { db_debug("attach the share memory segment failed(%s)\n", strerror(errno)); shmctl(shmid, IPC_RMID, 0); ret = -1; goto out; } #else script_buf = pos = malloc(i); #endif /* stores script buffer */ memcpy(pos, &head, sizeof(struct script_head)); pos += sizeof(struct script_head); memcpy(pos, item_table, sizeof(struct script_item) * mainkey_idx); pos += sizeof(struct script_item) * mainkey_idx; memcpy(pos, key_data, 10 * sizeof(int) * subkey_idx); pos += 10 * sizeof(int) * subkey_idx; memcpy(pos, value_data, sizeof(int) * value_idx); //shmdt(script_buf); // ret = shmid; return script_buf; out: /* free memory */ if (item_table) free(item_table); if (key_data) free(key_data); if (value_data) free(value_data); return NULL; } char * parse_script(const char *name) { FILE *fscript; int len; char *buf; int read_len; int shmid; char *script_buf; if (name == NULL) { db_error("script: invalid file name(null)\n"); return NULL; } /* read script data */ fscript = fopen(name, "rb"); if (fscript == NULL) { db_error("script: can't open %s(%s)\n", name, strerror(errno)); return NULL; } fseek(fscript, 0, SEEK_END); len = ftell(fscript); fseek(fscript, 0, SEEK_SET); buf = malloc(len); if (buf == NULL) { db_error("script: allocate memory for script data failed(%s)\n", strerror(errno)); fclose(fscript); return NULL; } read_len = fread(buf, 1, len, fscript); if (read_len < len) { db_debug("len = %d, read_len = %d, fix me\n", len, read_len); } fclose(fscript); /* parse script */ script_buf = __parse_script(buf, len); free(buf); return script_buf; } void deparse_script(int shmid) { //shmctl(shmid, IPC_RMID, 0); }