From fd55dac620cf645222538b6cd1b37e0a3df6ad1e Mon Sep 17 00:00:00 2001 From: Haru Date: Fri, 1 Jan 2016 01:46:35 +0100 Subject: Replaced struct script_string_buf definition with a VECTOR - Fixes various signed/unsigned comparisons. Signed-off-by: Haru --- src/map/script.c | 153 ++++++++++++++++++++++++++----------------------------- 1 file changed, 73 insertions(+), 80 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index 07b37571e..27df57236 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -92,29 +92,6 @@ static inline void SETVALUE(unsigned char* buf, int i, int n) { buf[i+2] = GetByte(n, 2); } -static inline void script_string_buf_ensure(struct script_string_buf *buf, size_t ensure) { - if( buf->pos+ensure >= buf->size ) { - do { - buf->size += 512; - } while ( buf->pos+ensure >= buf->size ); - RECREATE(buf->ptr, char, buf->size); - } -} - -static inline void script_string_buf_addb(struct script_string_buf *buf,uint8 b) { - if( buf->pos+1 >= buf->size ) { - buf->size += 512; - RECREATE(buf->ptr, char, buf->size); - } - buf->ptr[buf->pos++] = b; -} - -static inline void script_string_buf_destroy(struct script_string_buf *buf) { - if( buf->ptr ) - aFree(buf->ptr); - memset(buf,0,sizeof(struct script_string_buf)); -} - const char* script_op2name(int op) { #define RETURN_OP_NAME(type) case type: return #type switch( op ) { @@ -1222,7 +1199,6 @@ const char* parse_simpleexpr(const char *p) struct string_translation *st = NULL; const char *start_point = p; bool duplicate = true; - struct script_string_buf *sbuf = &script->parse_simpleexpr_str; do { p++; @@ -1234,12 +1210,14 @@ const char* parse_simpleexpr(const char *p) if( n != 1 ) ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); p += len; - script_string_buf_addb(sbuf, *buf); + VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_str, buf[0]); continue; } else if( *p == '\n' ) { disp_error_message("parse_simpleexpr: unexpected newline @ string",p); } - script_string_buf_addb(sbuf, *p++); + VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_str, *p++); } if(!*p) disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); @@ -1247,20 +1225,22 @@ const char* parse_simpleexpr(const char *p) p = script->skip_space(p); } while( *p && *p == '"' ); - script_string_buf_addb(sbuf, 0); + VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_str, '\0'); - if (!(script->syntax.translation_db && (st = strdb_get(script->syntax.translation_db, sbuf->ptr)) != NULL)) { + if (script->syntax.translation_db == NULL + || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(script->parse_simpleexpr_str))) == NULL) { script->addc(C_STR); - if( script->pos+sbuf->pos >= script->size ) { + if (script->pos+VECTOR_LENGTH(script->parse_simpleexpr_str) >= script->size) { do { script->size += SCRIPT_BLOCK_SIZE; - } while( script->pos+sbuf->pos >= script->size ); + } while (script->pos+VECTOR_LENGTH(script->parse_simpleexpr_str) >= script->size); RECREATE(script->buf,unsigned char,script->size); } - memcpy(script->buf+script->pos, sbuf->ptr, sbuf->pos); - script->pos += sbuf->pos; + memcpy(script->buf+script->pos, VECTOR_DATA(script->parse_simpleexpr_str), VECTOR_LENGTH(script->parse_simpleexpr_str)); + script->pos += VECTOR_LENGTH(script->parse_simpleexpr_str); } else { int expand = sizeof(int) + sizeof(uint8); @@ -1292,13 +1272,14 @@ const char* parse_simpleexpr(const char *p) } /* When exporting we don't know what is a translation and what isn't */ - if( script->lang_export_fp && sbuf->pos > 1 ) {//sbuf->pos will always be at least 1 because of the '\0' + if (script->lang_export_fp && VECTOR_LENGTH(script->parse_simpleexpr_str) > 1) { + // The length of script->parse_simpleexpr_str will always be at least 1 because of the '\0' if( !script->syntax.strings ) { script->syntax.strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); } - if( !strdb_exists(script->syntax.strings,sbuf->ptr) ) { - strdb_put(script->syntax.strings, sbuf->ptr, NULL); + if (!strdb_exists(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str))) { + strdb_put(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str), NULL); duplicate = false; } } @@ -1309,9 +1290,7 @@ const char* parse_simpleexpr(const char *p) ) || script->syntax.lang_macro_active ) ) { const char *line_start = start_point; const char *line_end = start_point; - struct script_string_buf *lbuf = &script->lang_export_line_buf; - struct script_string_buf *ubuf = &script->lang_export_unescaped_buf; - size_t line_length, cursor; + int line_length, cursor; while( line_start > script->parser_current_src ) { if( *line_start != '\n' ) @@ -1323,23 +1302,25 @@ const char* parse_simpleexpr(const char *p) while( *line_end != '\n' && *line_end != '\0' ) line_end++; - line_length = (size_t)(line_end - line_start); + line_length = (int)(line_end - line_start); if( line_length > 0 ) { - script_string_buf_ensure(lbuf,line_length + 1); + VECTOR_ENSURE(script->lang_export_line_buf, line_length + 1, 512); + VECTOR_PUSHARRAY(script->lang_export_line_buf, line_start, line_length); + VECTOR_PUSH(script->lang_export_line_buf, '\0'); - memcpy(lbuf->ptr, line_start, line_length); - lbuf->pos = line_length; - script_string_buf_addb(lbuf, 0); - - normalize_name(lbuf->ptr, "\r\n\t "); + normalize_name(VECTOR_DATA(script->lang_export_line_buf), "\r\n\t "); // [!] Note: VECTOR_LENGTH() will lie. } - for(cursor = 0; cursor < sbuf->pos; cursor++) { - if( sbuf->ptr[cursor] == '"' ) - script_string_buf_addb(ubuf, '\\'); - script_string_buf_addb(ubuf, sbuf->ptr[cursor]); + for (cursor = 0; cursor < VECTOR_LENGTH(script->parse_simpleexpr_str); cursor++) { + if (VECTOR_INDEX(script->parse_simpleexpr_str, cursor) == '"') { + VECTOR_ENSURE(script->lang_export_unescaped_buf, 1, 512); + VECTOR_PUSH(script->lang_export_unescaped_buf, '\\'); + } + VECTOR_ENSURE(script->lang_export_unescaped_buf, 1, 512); + VECTOR_PUSH(script->lang_export_unescaped_buf, VECTOR_INDEX(script->parse_simpleexpr_str, cursor)); } - script_string_buf_addb(ubuf, 0); + VECTOR_ENSURE(script->lang_export_unescaped_buf, 1, 512); + VECTOR_PUSH(script->lang_export_unescaped_buf, '\0'); fprintf(script->lang_export_fp, "#: %s\n" "# %s\n" @@ -1347,14 +1328,14 @@ const char* parse_simpleexpr(const char *p) "msgid \"%s\"\n" "msgstr \"\"\n", script->parser_current_file ? script->parser_current_file : "Unknown File", - lbuf->ptr, + VECTOR_DATA(script->lang_export_line_buf), script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", - ubuf->ptr + VECTOR_DATA(script->lang_export_unescaped_buf) ); - lbuf->pos = 0; - ubuf->pos = 0; + VECTOR_TRUNCATE(script->lang_export_line_buf); + VECTOR_TRUNCATE(script->lang_export_unescaped_buf); } - sbuf->pos = 0; + VECTOR_TRUNCATE(script->parse_simpleexpr_str); } else { int l; const char* pv; @@ -4989,7 +4970,9 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { struct DBMap *string_db; size_t i; FILE *fp; - struct script_string_buf msgid = { 0 }, msgstr = { 0 }; + struct script_string_buf msgid, msgstr; + VECTOR_INIT(msgid); + VECTOR_INIT(msgstr); if( !(fp = fopen(file,"rb")) ) { ShowError("load_translation: failed to open '%s' for reading\n",file); @@ -5023,39 +5006,45 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { } msgctxt[cursor] = '\0'; } else if ( strncasecmp(line, "msgid \"", 7) == 0 ) { - msgid.pos = 0; + VECTOR_TRUNCATE(msgid); for(i = 7; i < len - 2; i++) { + VECTOR_ENSURE(msgid, 1, 512); if( line[i] == '\\' && line[i+1] == '"' ) { - script_string_buf_addb(&msgid, '"'); + VECTOR_PUSH(msgid, '"'); i++; - } else - script_string_buf_addb(&msgid, line[i]); + } else { + VECTOR_PUSH(msgid, line[i]); + } } - script_string_buf_addb(&msgid,0); + VECTOR_ENSURE(msgid, 1, 512); + VECTOR_PUSH(msgid, '\0'); } else if ( len > 9 && line[9] != '"' && strncasecmp(line, "msgstr \"",8) == 0 ) { - msgstr.pos = 0; + VECTOR_TRUNCATE(msgstr); for(i = 8; i < len - 2; i++) { + VECTOR_ENSURE(msgstr, 1, 512); if( line[i] == '\\' && line[i+1] == '"' ) { - script_string_buf_addb(&msgstr, '"'); + VECTOR_PUSH(msgstr, '"'); i++; - } else - script_string_buf_addb(&msgstr, line[i]); + } else { + VECTOR_PUSH(msgstr, line[i]); + } } - script_string_buf_addb(&msgstr,0); + VECTOR_ENSURE(msgstr, 1, 512); + VECTOR_PUSH(msgstr, '\0'); } - if( msgctxt[0] && msgid.pos > 1 && msgstr.pos > 1 ) { - size_t msgstr_len = msgstr.pos; + if( msgctxt[0] && VECTOR_LENGTH(msgid) > 1 && VECTOR_LENGTH(msgstr) > 1 ) { + int msgstr_len = VECTOR_LENGTH(msgstr); unsigned int inner_len = 1 + (uint32)msgstr_len + 1; //uint8 lang_id + msgstr_len + '\0' if( strcasecmp(msgctxt, "messages.conf") == 0 ) { int k; for(k = 0; k < MAX_MSG; k++) { - if( atcommand->msg_table[0][k] && strcmpi(atcommand->msg_table[0][k],msgid.ptr) == 0 ) { + if( atcommand->msg_table[0][k] && strcmpi(atcommand->msg_table[0][k], VECTOR_DATA(msgid)) == 0 ) { if( atcommand->msg_table[lang_id][k] ) aFree(atcommand->msg_table[lang_id][k]); - atcommand->msg_table[lang_id][k] = aStrdup(msgstr.ptr); + atcommand->msg_table[lang_id][k] = aStrdup(VECTOR_DATA(msgstr)); break; } } @@ -5067,21 +5056,22 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { strdb_put(script->translation_db, msgctxt, string_db); } - if( !(st = strdb_get(string_db, msgid.ptr) ) ) { + if( !(st = strdb_get(string_db, VECTOR_DATA(msgid)) ) ) { CREATE(st, struct string_translation, 1); - st->string_id = script->string_dup(msgid.ptr); - strdb_put(string_db, msgid.ptr, st); + st->string_id = script->string_dup(VECTOR_DATA(msgid)); + strdb_put(string_db, VECTOR_DATA(msgid), st); } RECREATE(st->buf, char, st->len + inner_len); WBUFB(st->buf, st->len) = lang_id; - safestrncpy(WBUFP(st->buf, st->len + 1), msgstr.ptr, msgstr_len + 1); + safestrncpy(WBUFP(st->buf, st->len + 1), VECTOR_DATA(msgstr), msgstr_len + 1); st->translations++; st->len += inner_len; } msgctxt[0] = '\0'; - msgid.pos = msgstr.pos = 0; + VECTOR_TRUNCATE(msgid); + VECTOR_TRUNCATE(msgstr); translations++; } } @@ -5090,8 +5080,8 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { fclose(fp); - script_string_buf_destroy(&msgid); - script_string_buf_destroy(&msgstr); + VECTOR_CLEAR(msgid); + VECTOR_CLEAR(msgstr); ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", translations, file); } @@ -5176,9 +5166,9 @@ void script_parser_clean_leftovers(void) { script->syntax.strings = NULL; } - script_string_buf_destroy(&script->parse_simpleexpr_str); - script_string_buf_destroy(&script->lang_export_line_buf); - script_string_buf_destroy(&script->lang_export_unescaped_buf); + VECTOR_CLEAR(script->parse_simpleexpr_str); + VECTOR_CLEAR(script->lang_export_line_buf); + VECTOR_CLEAR(script->lang_export_unescaped_buf); } /** @@ -5197,6 +5187,9 @@ int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) { *------------------------------------------*/ void do_init_script(bool minimal) { script->parse_cleanup_timer_id = INVALID_TIMER; + VECTOR_INIT(script->lang_export_line_buf); + VECTOR_INIT(script->lang_export_unescaped_buf); + VECTOR_INIT(script->parse_simpleexpr_str); script->st_db = idb_alloc(DB_OPT_BASE); script->userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0); -- cgit v1.2.3-70-g09d2 From a16cfeda0e57207cc655fb94415ee78b0c8520e6 Mon Sep 17 00:00:00 2001 From: Haru Date: Fri, 1 Jan 2016 02:42:44 +0100 Subject: Replaced script->buf with a VECTOR - Fixes various signed/unsigned comparisons. Signed-off-by: Haru --- src/map/script.c | 240 +++++++++++++++++++++++++++---------------------------- src/map/script.h | 13 ++- 2 files changed, 128 insertions(+), 125 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index 27df57236..f62cf2744 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -583,21 +583,26 @@ int script_add_str(const char* p) return script->str_num++; } -/// Appends 1 byte to the script buffer. +/** + * Appends 1 byte to the script buffer. + * + * @param a The byte to append. + */ void add_scriptb(int a) { - if( script->pos+1 >= script->size ) - { - script->size += SCRIPT_BLOCK_SIZE; - RECREATE(script->buf,unsigned char,script->size); - } - script->buf[script->pos++] = (uint8)(a); + VECTOR_ENSURE(script->buf, 1, SCRIPT_BLOCK_SIZE); + VECTOR_PUSH(script->buf, (uint8)a); } -/// Appends a c_op value to the script buffer. -/// The value is variable-length encoded into 8-bit blocks. -/// The encoding scheme is ( 01?????? )* 00??????, LSB first. -/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). +/** + * Appends a c_op value to the script buffer. + * + * The value is variable-length encoded into 8-bit blocks. + * The encoding scheme is ( 01?????? )* 00??????, LSB first. + * All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). + * + * @param a The value to append. + */ void add_scriptc(int a) { while( a >= 0x40 ) @@ -609,10 +614,15 @@ void add_scriptc(int a) script->addb(a); } -/// Appends an integer value to the script buffer. -/// The value is variable-length encoded into 8-bit blocks. -/// The encoding scheme is ( 11?????? )* 10??????, LSB first. -/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). +/** + * Appends an integer value to the script buffer. + * + * The value is variable-length encoded into 8-bit blocks. + * The encoding scheme is ( 11?????? )* 10??????, LSB first. + * All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). + * + * @param a The value to append. + */ void add_scripti(int a) { while( a >= 0x40 ) @@ -623,11 +633,11 @@ void add_scripti(int a) script->addb(a|0x80); } -/// Appends a script->str_data object (label/function/variable/integer) to the script buffer. - -/// -/// @param l The id of the script->str_data entry -// Maximum up to 16M +/** + * Appends a script->str_data object (label/function/variable/integer) to the script buffer. + * + * @param l The id of the script->str_data entry (Maximum up to 16M) + */ void add_scriptl(int l) { int backpatch = script->str_data[l].backpatch; @@ -644,7 +654,7 @@ void add_scriptl(int l) case C_USERFUNC: // Embedded data backpatch there is a possibility of label script->addc(C_NAME); - script->str_data[l].backpatch = script->pos; + script->str_data[l].backpatch = VECTOR_LENGTH(script->buf); script->addb(backpatch); script->addb(backpatch>>8); script->addb(backpatch>>16); @@ -682,9 +692,9 @@ void set_label(int l,int pos, const char* script_pos) script->str_data[l].type=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); script->str_data[l].label=pos; for (i = script->str_data[l].backpatch; i >= 0 && i != 0x00ffffff; ) { - int next = GETVALUE(script->buf,i); - script->buf[i-1]=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); - SETVALUE(script->buf,i,pos); + int next = GETVALUE(VECTOR_DATA(script->buf), i); + VECTOR_INDEX(script->buf, i-1) = (script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); + SETVALUE(VECTOR_DATA(script->buf), i, pos); i = next; } } @@ -919,7 +929,7 @@ void parse_nextline(bool first, const char* p) if( !first ) { script->addc(C_EOL); // mark end of line for stack cleanup - script->set_label(LABEL_NEXTLINE, script->pos, p); // fix up '-' labels + script->set_label(LABEL_NEXTLINE, VECTOR_LENGTH(script->buf), p); // fix up '-' labels } // initialize data for new '-' label fix up scheduling @@ -1136,13 +1146,19 @@ bool is_number(const char *p) { } /** + * Duplicates a script string into the script string list. * - **/ -int script_string_dup(char *str) { - size_t len = strlen(str); + * Grows the script string list as needed. + * + * @param str The string to insert. + * @return the string position in the script string list. + */ +int script_string_dup(char *str) +{ + int len = (int)strlen(str); int pos = script->string_list_pos; - while( pos+len+1 >= script->string_list_size ) { + while (pos+len+1 >= script->string_list_size) { script->string_list_size += (1024*1024)/2; RECREATE(script->string_list,char,script->string_list_size); } @@ -1232,42 +1248,30 @@ const char* parse_simpleexpr(const char *p) || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(script->parse_simpleexpr_str))) == NULL) { script->addc(C_STR); - if (script->pos+VECTOR_LENGTH(script->parse_simpleexpr_str) >= script->size) { - do { - script->size += SCRIPT_BLOCK_SIZE; - } while (script->pos+VECTOR_LENGTH(script->parse_simpleexpr_str) >= script->size); - RECREATE(script->buf,unsigned char,script->size); - } - - memcpy(script->buf+script->pos, VECTOR_DATA(script->parse_simpleexpr_str), VECTOR_LENGTH(script->parse_simpleexpr_str)); - script->pos += VECTOR_LENGTH(script->parse_simpleexpr_str); + VECTOR_ENSURE(script->buf, VECTOR_LENGTH(script->parse_simpleexpr_str), SCRIPT_BLOCK_SIZE); + VECTOR_PUSHARRAY(script->buf, VECTOR_DATA(script->parse_simpleexpr_str), VECTOR_LENGTH(script->parse_simpleexpr_str)); } else { - int expand = sizeof(int) + sizeof(uint8); - unsigned char j; - unsigned int st_cursor = 0; + unsigned char u; + int st_cursor = 0; script->addc(C_LSTR); - expand += (sizeof(char*) + sizeof(uint8)) * st->translations; - - while( script->pos+expand >= script->size ) { - script->size += SCRIPT_BLOCK_SIZE; - RECREATE(script->buf,unsigned char,script->size); - } - - *((int *)(&script->buf[script->pos])) = st->string_id; - *((uint8 *)(&script->buf[script->pos + sizeof(int)])) = st->translations; - - script->pos += sizeof(int) + sizeof(uint8); - - for(j = 0; j < st->translations; j++) { - *((uint8 *)(&script->buf[script->pos])) = RBUFB(st->buf, st_cursor); - *((char **)(&script->buf[script->pos+sizeof(uint8)])) = &st->buf[st_cursor + sizeof(uint8)]; - script->pos += sizeof(char*) + sizeof(uint8); - st_cursor += sizeof(uint8); - while(st->buf[st_cursor++]); - st_cursor += sizeof(uint8); + VECTOR_ENSURE(script->buf, (int)(sizeof(st->string_id) + sizeof(st->translations)), SCRIPT_BLOCK_SIZE); + VECTOR_PUSHARRAY(script->buf, (void *)&st->string_id, sizeof(st->string_id)); + VECTOR_PUSHARRAY(script->buf, (void *)&st->translations, sizeof(st->translations)); + + for (u = 0; u != st->translations; u++) { + struct string_translation_entry *entry = (void *)(st->buf+st_cursor); + char *stringptr = &entry->string[0]; + st_cursor += sizeof(*entry); + VECTOR_ENSURE(script->buf, (int)(sizeof(entry->lang_id) + sizeof(char *)), SCRIPT_BLOCK_SIZE); + VECTOR_PUSHARRAY(script->buf, (void *)&entry->lang_id, sizeof(entry->lang_id)); + VECTOR_PUSHARRAY(script->buf, (void *)&stringptr, sizeof(stringptr)); + st_cursor += sizeof(uint8); // FIXME: What are we skipping here? + while (st->buf[st_cursor++] != 0) + (void)0; // Skip string + st_cursor += sizeof(uint8); // FIXME: What are we skipping here? } } @@ -1563,7 +1567,7 @@ const char* parse_curly_close(const char* p) // You are here labeled sprintf(label,"__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); if(script->syntax.curly[pos].flag) { //Exists default @@ -1576,7 +1580,7 @@ const char* parse_curly_close(const char* p) // Label end sprintf(label,"__SW%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); linkdb_final(&script->syntax.curly[pos].case_label); // free the list of case label script->syntax.curly_count--; //Closing decision if, for , while @@ -1655,7 +1659,7 @@ const char* parse_syntax(const char* p) // You are here labeled sprintf(label,"__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); } //Decision statement switch p = script->skip_space(p2); @@ -1695,7 +1699,7 @@ const char* parse_syntax(const char* p) // Label after the completion of FALLTHRU sprintf(label, "__SW%x_%xJ", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); } // check duplication of case label [Rayce] if(linkdb_search(&script->syntax.curly[pos].case_label, (void*)h64BPTRSIZE(v)) != NULL) @@ -1762,7 +1766,7 @@ const char* parse_syntax(const char* p) } sprintf(label, "__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); // Skip to the next link w/o condition sprintf(label, "goto __SW%x_%x;", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count + 1); @@ -1773,7 +1777,7 @@ const char* parse_syntax(const char* p) // The default label sprintf(label, "__SW%x_DEF", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly[script->syntax.curly_count - 1].flag = 1; script->syntax.curly[pos].count++; @@ -1791,7 +1795,7 @@ const char* parse_syntax(const char* p) // Label of the (do) form here sprintf(label, "__DO%x_BGN", (unsigned int)script->syntax.curly[script->syntax.curly_count].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count++; return p; } @@ -1822,7 +1826,7 @@ const char* parse_syntax(const char* p) // Form the start of label decision sprintf(label, "__FR%x_J", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); p=script->skip_space(p); if(*p == ';') { @@ -1851,7 +1855,7 @@ const char* parse_syntax(const char* p) // Labels to form the next loop sprintf(label, "__FR%x_NXT", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); // Process the next time you enter the loop // A ')' last for; flag to be treated as' @@ -1870,7 +1874,7 @@ const char* parse_syntax(const char* p) // Loop start labeling sprintf(label, "__FR%x_BGN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); return p; } else if( p2 - p == 8 && strncmp(p, "function", 8) == 0 ) { // internal script function @@ -1920,9 +1924,9 @@ const char* parse_syntax(const char* p) if( script->str_data[l].type == C_NOP || script->str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else { script->str_data[l].type = C_USERFUNC; - script->set_label(l, script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); if( script->parse_options&SCRIPT_USE_LABEL_DB ) - script->label_add(l,script->pos); + script->label_add(l, VECTOR_LENGTH(script->buf)); } else disp_error_message("parse_syntax:function: function name is invalid", func_name); @@ -2002,7 +2006,7 @@ const char* parse_syntax(const char* p) // Form the start of label decision sprintf(label, "__WL%x_NXT", (unsigned int)script->syntax.curly[script->syntax.curly_count].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); // Skip to the end point if the condition is false sprintf(label, "__WL%x_FIN", (unsigned int)script->syntax.curly[script->syntax.curly_count].index); @@ -2059,7 +2063,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Put the label of the location sprintf(label, "__IF%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly[pos].count++; p = script->skip_space(p); @@ -2097,7 +2101,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Put the label of the final location sprintf(label, "__IF%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); if(script->syntax.curly[pos].flag == 1) { // Because the position of the pointer is the same if not else for this return bp; @@ -2110,7 +2114,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // (Come here continue) to form the label here sprintf(label, "__DO%x_NXT", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); } // Skip to the end point if the condition is false @@ -2145,7 +2149,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Form label of the end point conditions sprintf(label, "__DO%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); p = script->skip_space(p); if(*p != ';') { disp_error_message("parse_syntax: need ';'",p); @@ -2167,7 +2171,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // End for labeling sprintf(label, "__FR%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count--; return p; } else if(script->syntax.curly[pos].type == TYPE_WHILE) { @@ -2183,7 +2187,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // End while labeling sprintf(label, "__WL%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count--; return p; } else if(script->syntax.curly[pos].type == TYPE_USERFUNC) { @@ -2196,7 +2200,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Put the label of the location sprintf(label, "__FN%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count--; return p; } else { @@ -2537,11 +2541,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->syntax.translation_db = strdb_get(script->translation_db, script->parser_current_npc_name); } - if( !script->buf ) { - script->buf = (unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char)); - script->size = SCRIPT_BLOCK_SIZE; - } - script->pos=0; + VECTOR_TRUNCATE(script->buf); script->parse_nextline(true, NULL); // who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here @@ -2555,7 +2555,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o if( script->error_report ) script->error(src,file,line,script->error_msg,script->error_pos); aFree( script->error_msg ); - script->pos = 0; + VECTOR_TRUNCATE(script->buf); for(i=LABEL_START;istr_num;i++) if(script->str_data[i].type == C_NOP) script->str_data[i].type = C_NAME; for(i=0; iskip_space(p); if( options&SCRIPT_IGNORE_EXTERNAL_BRACKETS ) {// does not require brackets around the script - if( *p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) - {// empty script and can return NULL - script->pos = 0; + if (*p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT)) { + // empty script and can return NULL + VECTOR_TRUNCATE(script->buf); #ifdef ENABLE_CASE_CHECK script->local_casecheck.clear(); script->parser_current_src = NULL; @@ -2595,9 +2595,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o if (retval) *retval = EXIT_FAILURE; } p = script->skip_space(p+1); - if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) - {// empty script and can return NULL - script->pos = 0; + if (*p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT)) { + // empty script and can return NULL + VECTOR_TRUNCATE(script->buf); #ifdef ENABLE_CASE_CHECK script->local_casecheck.clear(); script->parser_current_src = NULL; @@ -2629,9 +2629,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o tmpp=script->skip_space(script->skip_word(p)); if(*tmpp==':' && !(strncmp(p,"default:",8) == 0 && p + 7 == tmpp)) { i=script->add_word(p); - script->set_label(i,script->pos,p); + script->set_label(i, VECTOR_LENGTH(script->buf), p); if( script->parse_options&SCRIPT_USE_LABEL_DB ) - script->label_add(i,script->pos); + script->label_add(i, VECTOR_LENGTH(script->buf)); p=tmpp+1; p=script->skip_space(p); continue; @@ -2653,8 +2653,8 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->str_data[i].type=C_NAME; script->str_data[i].label=i; for (j = script->str_data[i].backpatch; j >= 0 && j != 0x00ffffff; ) { - int next = GETVALUE(script->buf,j); - SETVALUE(script->buf,j,i); + int next = GETVALUE(VECTOR_DATA(script->buf), j); + SETVALUE(VECTOR_DATA(script->buf), j, i); j = next; } } else if(script->str_data[i].type == C_USERFUNC) { @@ -2671,37 +2671,39 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o } #ifdef SCRIPT_DEBUG_DISP - for(i=0;ipos;i++) { - if((i&15)==0) ShowMessage("%04x : ",i); - ShowMessage("%02x ",script->buf[i]); - if((i&15)==15) ShowMessage("\n"); + for (i = 0; i < VECTOR_LENGTH(script->buf); i++) { + if ((i&15) == 0) + ShowMessage("%04x : ",i); + ShowMessage("%02x ", VECTOR_INDEX(script->buf, i)); + if ((i&15) == 15) + ShowMessage("\n"); } ShowMessage("\n"); #endif #ifdef SCRIPT_DEBUG_DISASM i = 0; - while (i < script->pos) { - c_op op = script->get_com(script->buf, &i); + while (i < VECTOR_LENGTH(script->buf)) { + c_op op = script->get_com(VECTOR_DATA(script->buf), &i); int j = i; // Note: i is modified in the line above. ShowMessage("%06x %s", i, script->op2name(op)); switch (op) { case C_INT: - ShowMessage(" %d", script->get_num(script->buf,&i)); + ShowMessage(" %d", script->get_num(VECTOR_DATA(script->buf), &i)); break; case C_POS: - ShowMessage(" 0x%06x", *(int*)(script->buf+i)&0xffffff); + ShowMessage(" 0x%06x", *(int*)(&VECTOR_INDEX(script->buf, i))&0xffffff); i += 3; break; case C_NAME: - j = (*(int*)(script->buf+i)&0xffffff); + j = (*(int*)(&VECTOR_INDEX(script->buf, i))&0xffffff); ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : script->get_str(j)); i += 3; break; case C_STR: - j = (int)strlen((char*)script->buf + i); - ShowMessage(" %s", script->buf + i); + j = (int)strlen((char*)&VECTOR_INDEX(script->buf, i)); + ShowMessage(" %s", &VECTOR_INDEX(script->buf, i)); i += j+1; break; } @@ -2710,9 +2712,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o #endif CREATE(code,struct script_code,1); - code->script_buf = (unsigned char *)aMalloc(script->pos*sizeof(unsigned char)); - memcpy(code->script_buf, script->buf, script->pos); - code->script_size = script->pos; + code->script_buf = (unsigned char *)aMalloc(VECTOR_LENGTH(script->buf)*sizeof(unsigned char)); + memcpy(code->script_buf, VECTOR_DATA(script->buf), VECTOR_LENGTH(script->buf)); + code->script_size = VECTOR_LENGTH(script->buf); code->local.vars = NULL; code->local.arrays = NULL; #ifdef ENABLE_CASE_CHECK @@ -4914,7 +4916,7 @@ void script_load_translations(void) { for (string_db = dbi_first(main_iter); dbi_exists(main_iter); string_db = dbi_next(main_iter)) { struct DBIterator *sub_iter = db_iterator(string_db); for (st = dbi_first(sub_iter); dbi_exists(sub_iter); st = dbi_next(sub_iter)) { - script->translation_buf[j++] = st->buf; + script->translation_buf[j++] = st->buf; // FIXME: change translation_buf to uint8 } dbi_destroy(sub_iter); } @@ -5056,12 +5058,12 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { strdb_put(script->translation_db, msgctxt, string_db); } - if( !(st = strdb_get(string_db, VECTOR_DATA(msgid)) ) ) { + if ((st = strdb_get(string_db, VECTOR_DATA(msgid))) == NULL) { CREATE(st, struct string_translation, 1); st->string_id = script->string_dup(VECTOR_DATA(msgid)); strdb_put(string_db, VECTOR_DATA(msgid), st); } - RECREATE(st->buf, char, st->len + inner_len); + RECREATE(st->buf, uint8, st->len + inner_len); WBUFB(st->buf, st->len) = lang_id; safestrncpy(WBUFP(st->buf, st->len + 1), VECTOR_DATA(msgstr), msgstr_len + 1); @@ -5149,12 +5151,9 @@ int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_lis /** * **/ -void script_parser_clean_leftovers(void) { - if( script->buf ) - aFree(script->buf); - - script->buf = NULL; - script->size = 0; +void script_parser_clean_leftovers(void) +{ + VECTOR_CLEAR(script->buf); if( script->translation_db ) { script->translation_db->destroy(script->translation_db,script->translation_db_destroyer); @@ -21047,8 +21046,7 @@ void script_defaults(void) { script->label_count = 0; script->labels_size = 0; - script->buf = NULL; - script->pos = 0, script->size = 0; + VECTOR_INIT(script->buf); script->parse_options = 0; script->buildin_set_ref = 0; diff --git a/src/map/script.h b/src/map/script.h index 8650cab9c..77d734e52 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -517,16 +517,22 @@ struct script_array { unsigned int *members;/* member list */ }; + /** * A script string buffer, used to hold strings used by the script engine. */ VECTOR_STRUCT_DECL(script_string_buf, char); +struct string_translation_entry { + uint8 lang_id; + char string[]; +}; + struct string_translation { int string_id; uint8 translations; - unsigned int len; - char *buf; + int len; + uint8 *buf; // Array of struct string_translation_entry }; /** @@ -576,8 +582,7 @@ struct script_interface { /* */ /// temporary buffer for passing around compiled bytecode /// @see add_scriptb, set_label, parse_script - unsigned char* buf; - int pos, size; + VECTOR_DECL(unsigned char) buf; /* */ struct script_syntax_data syntax; /* */ -- cgit v1.2.3-70-g09d2 From 3dcdb2bbc6e9c06ebdec1e5ad2d18e93c1394a86 Mon Sep 17 00:00:00 2001 From: Haru Date: Fri, 1 Jan 2016 03:07:16 +0100 Subject: Replaced script_code::script_buf with a VECTOR - Fixes various signed/unsigned comparisons. Signed-off-by: Haru --- src/map/npc.c | 2 +- src/map/script.c | 79 ++++++++++++++++++++++++++++++-------------------------- src/map/script.h | 25 ++++++++++-------- 3 files changed, 58 insertions(+), 48 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/npc.c b/src/map/npc.c index 6b55bf5ae..b49e56d20 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -3759,7 +3759,7 @@ const char *npc_parse_function(const char *w1, const char *w2, const char *w3, c struct script_code *oldscript = (struct script_code*)DB->data2ptr(&old_data); ShowWarning("npc_parse_function: Overwriting user function [%s] in file '%s', line '%d'.\n", w3, filepath, strline(buffer,start-buffer)); script->free_vars(oldscript->local.vars); - aFree(oldscript->script_buf); + VECTOR_CLEAR(oldscript->script_buf); aFree(oldscript); } diff --git a/src/map/script.c b/src/map/script.c index f62cf2744..b8e458e33 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -83,13 +83,18 @@ struct script_interface script_s; struct script_interface *script; -static inline int GETVALUE(const unsigned char* buf, int i) { - return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0)); +static inline int GETVALUE(const struct script_buf *buf, int i) +{ + Assert_ret(VECTOR_LENGTH(*buf) > i + 2); + return (int)MakeDWord(MakeWord(VECTOR_INDEX(*buf, i), VECTOR_INDEX(*buf, i+1)), + MakeWord(VECTOR_INDEX(*buf, i+2), 0)); } -static inline void SETVALUE(unsigned char* buf, int i, int n) { - buf[i] = GetByte(n, 0); - buf[i+1] = GetByte(n, 1); - buf[i+2] = GetByte(n, 2); +static inline void SETVALUE(struct script_buf *buf, int i, int n) +{ + Assert_retv(VECTOR_LENGTH(*buf) > i + 2); + VECTOR_INDEX(*buf, i) = GetByte(n, 0); + VECTOR_INDEX(*buf, i+1) = GetByte(n, 1); + VECTOR_INDEX(*buf, i+2) = GetByte(n, 2); } const char* script_op2name(int op) { @@ -692,9 +697,9 @@ void set_label(int l,int pos, const char* script_pos) script->str_data[l].type=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); script->str_data[l].label=pos; for (i = script->str_data[l].backpatch; i >= 0 && i != 0x00ffffff; ) { - int next = GETVALUE(VECTOR_DATA(script->buf), i); + int next = GETVALUE(&script->buf, i); VECTOR_INDEX(script->buf, i-1) = (script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); - SETVALUE(VECTOR_DATA(script->buf), i, pos); + SETVALUE(&script->buf, i, pos); i = next; } } @@ -2653,8 +2658,8 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->str_data[i].type=C_NAME; script->str_data[i].label=i; for (j = script->str_data[i].backpatch; j >= 0 && j != 0x00ffffff; ) { - int next = GETVALUE(VECTOR_DATA(script->buf), j); - SETVALUE(VECTOR_DATA(script->buf), j, i); + int next = GETVALUE(&script->buf, j); + SETVALUE(&script->buf, j, i); j = next; } } else if(script->str_data[i].type == C_USERFUNC) { @@ -2683,14 +2688,14 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o #ifdef SCRIPT_DEBUG_DISASM i = 0; while (i < VECTOR_LENGTH(script->buf)) { - c_op op = script->get_com(VECTOR_DATA(script->buf), &i); + c_op op = script->get_com(&script->buf, &i); int j = i; // Note: i is modified in the line above. ShowMessage("%06x %s", i, script->op2name(op)); switch (op) { case C_INT: - ShowMessage(" %d", script->get_num(VECTOR_DATA(script->buf), &i)); + ShowMessage(" %d", script->get_num(&script->buf, &i)); break; case C_POS: ShowMessage(" 0x%06x", *(int*)(&VECTOR_INDEX(script->buf, i))&0xffffff); @@ -2712,9 +2717,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o #endif CREATE(code,struct script_code,1); - code->script_buf = (unsigned char *)aMalloc(VECTOR_LENGTH(script->buf)*sizeof(unsigned char)); - memcpy(code->script_buf, VECTOR_DATA(script->buf), VECTOR_LENGTH(script->buf)); - code->script_size = VECTOR_LENGTH(script->buf); + VECTOR_INIT(code->script_buf); + VECTOR_ENSURE(code->script_buf, VECTOR_LENGTH(script->buf), 1); + VECTOR_PUSHARRAY(code->script_buf, VECTOR_DATA(script->buf), VECTOR_LENGTH(script->buf)); code->local.vars = NULL; code->local.arrays = NULL; #ifdef ENABLE_CASE_CHECK @@ -3607,7 +3612,7 @@ void script_free_code(struct script_code* code) script->free_vars(code->local.vars); if (code->local.arrays) code->local.arrays->destroy(code->local.arrays,script->array_free_db); - aFree(code->script_buf); + VECTOR_CLEAR(code->script_buf); aFree(code); } @@ -3732,32 +3737,32 @@ void script_add_pending_ref(struct script_state *st, struct reg_db *ref) { /*========================================== * Read command *------------------------------------------*/ -c_op get_com(unsigned char *scriptbuf,int *pos) +c_op get_com(const struct script_buf *scriptbuf, int *pos) { int i = 0, j = 0; - if(scriptbuf[*pos]>=0x80) { + if (VECTOR_INDEX(*scriptbuf, *pos) >= 0x80) { return C_INT; } - while(scriptbuf[*pos]>=0x40) { - i=scriptbuf[(*pos)++]<= 0x40) { + i = VECTOR_INDEX(*scriptbuf, (*pos)++) << j; j+=6; } - return (c_op)(i+(scriptbuf[(*pos)++]<=0xc0) { - i+=(scriptbuf[(*pos)++]&0x7f)<= 0xc0) { + i+= (VECTOR_INDEX(*scriptbuf, (*pos)++)&0x7f)<state = RUN; while( st->state == RUN ) { - enum c_op c = script->get_com(st->script->script_buf,&st->pos); + enum c_op c = script->get_com(&st->script->script_buf, &st->pos); switch(c) { case C_EOL: if( stack->defsp > stack->sp ) @@ -4386,27 +4391,29 @@ void run_script_main(struct script_state *st) { script->pop_stack(st, stack->defsp, stack->sp);// pop unused stack data. (unused return value) break; case C_INT: - script->push_val(stack,C_INT,script->get_num(st->script->script_buf,&st->pos),NULL); + script->push_val(stack,C_INT,script->get_num(&st->script->script_buf, &st->pos), NULL); break; case C_POS: case C_NAME: - script->push_val(stack,c,GETVALUE(st->script->script_buf,st->pos),NULL); + script->push_val(stack,c,GETVALUE(&st->script->script_buf, st->pos), NULL); st->pos+=3; break; case C_ARG: script->push_val(stack,c,0,NULL); break; case C_STR: - script->push_conststr(stack, (const char *)(st->script->script_buf+st->pos)); - while(st->script->script_buf[st->pos++]); + script->push_conststr(stack, (const char *)&VECTOR_INDEX(st->script->script_buf, st->pos)); + while (VECTOR_INDEX(st->script->script_buf, st->pos++) != 0) + (void)0; // Skip string break; case C_LSTR: { - int string_id = *((int *)(&st->script->script_buf[st->pos])); - uint8 translations = *((uint8 *)(&st->script->script_buf[st->pos+sizeof(int)])); struct map_session_data *lsd = NULL; - - st->pos += sizeof(int) + sizeof(uint8); + uint8 translations = 0; + int string_id = *((int *)(&VECTOR_INDEX(st->script->script_buf, st->pos))); + st->pos += sizeof(string_id); + translations = *((uint8 *)(&VECTOR_INDEX(st->script->script_buf, st->pos))); + st->pos += sizeof(translations); if( (!st->rid || !(lsd = map->id2sd(st->rid)) || !lsd->lang_id) && !map->default_lang_id ) script->push_conststr(stack, script->string_list+string_id); @@ -4415,7 +4422,7 @@ void run_script_main(struct script_state *st) { int offset = st->pos; for(k = 0; k < translations; k++) { - uint8 lang_id = *(uint8 *)(&st->script->script_buf[offset]); + uint8 lang_id = *(uint8 *)(&VECTOR_INDEX(st->script->script_buf, offset)); offset += sizeof(uint8); if( lang_id == wlang_id ) break; @@ -4424,7 +4431,7 @@ void run_script_main(struct script_state *st) { if (k == translations) script->push_conststr(stack, script->string_list+string_id); else - script->push_conststr(stack, *(const char**)(&st->script->script_buf[offset]) ); + script->push_conststr(stack, *(const char**)(&VECTOR_INDEX(st->script->script_buf, offset))); } st->pos += ( ( sizeof(char*) + sizeof(uint8) ) * translations ); } diff --git a/src/map/script.h b/src/map/script.h index 77d734e52..dabebe89e 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -394,11 +394,20 @@ struct script_data { struct reg_db *ref; ///< Reference to the scope's variables }; +/** + * A script string buffer, used to hold strings used by the script engine. + */ +VECTOR_STRUCT_DECL(script_string_buf, char); + +/** + * Script buffer, used to hold parsed script data. + */ +VECTOR_STRUCT_DECL(script_buf, unsigned char); + // Moved defsp from script_state to script_stack since // it must be saved when script state is RERUNLINE. [Eoe / jA 1094] struct script_code { - int script_size; - unsigned char *script_buf; + struct script_buf script_buf; struct reg_db local; ///< Local (npc) vars unsigned short instances; }; @@ -517,12 +526,6 @@ struct script_array { unsigned int *members;/* member list */ }; - -/** - * A script string buffer, used to hold strings used by the script engine. - */ -VECTOR_STRUCT_DECL(script_string_buf, char); - struct string_translation_entry { uint8 lang_id; char string[]; @@ -582,7 +585,7 @@ struct script_interface { /* */ /// temporary buffer for passing around compiled bytecode /// @see add_scriptb, set_label, parse_script - VECTOR_DECL(unsigned char) buf; + struct script_buf buf; /* */ struct script_syntax_data syntax; /* */ @@ -711,8 +714,8 @@ struct script_interface { const char * (*parse_syntax_close) (const char *p); const char * (*parse_syntax_close_sub) (const char *p, int *flag); const char * (*parse_syntax) (const char *p); - c_op (*get_com) (unsigned char *scriptbuf, int *pos); - int (*get_num) (unsigned char *scriptbuf, int *pos); + c_op (*get_com) (const struct script_buf *scriptbuf, int *pos); + int (*get_num) (const struct script_buf *scriptbuf, int *pos); const char* (*op2name) (int op); void (*reportsrc) (struct script_state *st); void (*reportdata) (struct script_data *data); -- cgit v1.2.3-70-g09d2 From 2a661267b59ebdaad1fceb00339b11eaa06d5bef Mon Sep 17 00:00:00 2001 From: Haru Date: Fri, 1 Jan 2016 04:40:06 +0100 Subject: Changed script->translation_buf to a VECTOR Signed-off-by: Haru --- src/map/script.c | 49 ++++++++++++++++++++++++------------------------- src/map/script.h | 5 ++--- 2 files changed, 26 insertions(+), 28 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index b8e458e33..fa33c5d76 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -4869,7 +4869,7 @@ void script_load_translations(void) { const char *config_filename = "db/translations.conf"; // FIXME hardcoded name struct config_setting_t *translations = NULL; int i, size; - uint32 total = 0; + int total = 0; uint8 lang_id = 0, k; if (map->minimal) // No translations in minimal mode @@ -4906,24 +4906,22 @@ void script_load_translations(void) { for(i = 0; i < size; i++) { const char *translation_file = libconfig->setting_get_string_elem(translations, i); - script->load_translation(translation_file, ++lang_id, &total); + total += script->load_translation(translation_file, ++lang_id); } libconfig->destroy(&translations_conf); - if( total ) { + if (total != 0) { struct DBIterator *main_iter; struct DBMap *string_db; struct string_translation *st = NULL; - uint32 j = 0; - CREATE(script->translation_buf, char *, total); - script->translation_buf_size = total; + VECTOR_ENSURE(script->translation_buf, total, 1); main_iter = db_iterator(script->translation_db); for (string_db = dbi_first(main_iter); dbi_exists(main_iter); string_db = dbi_next(main_iter)) { struct DBIterator *sub_iter = db_iterator(string_db); for (st = dbi_first(sub_iter); dbi_exists(sub_iter); st = dbi_next(sub_iter)) { - script->translation_buf[j++] = st->buf; // FIXME: change translation_buf to uint8 + VECTOR_PUSH(script->translation_buf, st->buf); } dbi_destroy(sub_iter); } @@ -4970,24 +4968,30 @@ const char *script_get_translation_file_name(const char *file) } /** - * Parses a individual translation file - **/ -void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { - uint32 translations = 0; + * Parses an individual translation file. + * + * @param file The filename to parse. + * @param lang_id The language identifier. + * @return The amount of strings loaded. + */ +int script_load_translation(const char *file, uint8 lang_id) +{ + int translations = 0; char line[1024]; char msgctxt[NAME_LENGTH*2+1] = { 0 }; struct DBMap *string_db; size_t i; FILE *fp; struct script_string_buf msgid, msgstr; - VECTOR_INIT(msgid); - VECTOR_INIT(msgstr); if( !(fp = fopen(file,"rb")) ) { ShowError("load_translation: failed to open '%s' for reading\n",file); - return; + return 0; } + VECTOR_INIT(msgid); + VECTOR_INIT(msgstr); + script->add_language(script->get_translation_file_name(file)); if( lang_id >= atcommand->max_message_table ) atcommand->expand_message_table(); @@ -5085,14 +5089,13 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { } } - *total += translations; - fclose(fp); VECTOR_CLEAR(msgid); VECTOR_CLEAR(msgstr); - ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", translations, file); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", translations, file); + return translations; } /** @@ -5108,15 +5111,10 @@ void script_clear_translations(bool reload) { script->string_list_pos = 0; script->string_list_size = 0; - if( script->translation_buf ) { - for(i = 0; i < script->translation_buf_size; i++) { - aFree(script->translation_buf[i]); - } - aFree(script->translation_buf); + while (VECTOR_LENGTH(script->translation_buf) > 0) { + aFree(VECTOR_POP(script->translation_buf)); } - - script->translation_buf = NULL; - script->translation_buf_size = 0; + VECTOR_CLEAR(script->translation_buf); if( script->languages ) { for(i = 0; i < script->max_lang_id; i++) @@ -21054,6 +21052,7 @@ void script_defaults(void) { script->labels_size = 0; VECTOR_INIT(script->buf); + VECTOR_INIT(script->translation_buf); script->parse_options = 0; script->buildin_set_ref = 0; diff --git a/src/map/script.h b/src/map/script.h index dabebe89e..845d52280 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -630,8 +630,7 @@ struct script_interface { int buildin_lang_macro_offset; /* */ struct DBMap *translation_db;/* npc_name => DBMap (strings) */ - char **translation_buf;/* */ - uint32 translation_buf_size; + VECTOR_DECL(uint8 *) translation_buf; /* */ char **languages; uint8 max_lang_id; @@ -815,7 +814,7 @@ struct script_interface { unsigned short (*mapindexname2id) (struct script_state *st, const char* name); int (*string_dup) (char *str); void (*load_translations) (void); - void (*load_translation) (const char *file, uint8 lang_id, uint32 *total); + int (*load_translation) (const char *file, uint8 lang_id); int (*translation_db_destroyer) (union DBKey key, struct DBData *data, va_list ap); void (*clear_translations) (bool reload); int (*parse_cleanup_timer) (int tid, int64 tick, int id, intptr_t data); -- cgit v1.2.3-70-g09d2 From ba035696cf0927624b02db5573c617566cdd645f Mon Sep 17 00:00:00 2001 From: Haru Date: Mon, 16 May 2016 04:58:16 +0200 Subject: Re-implemented BUILDIN(sprintf) - The function now checks its arguments, rather than passing them to the system implementation (safer against arbitrary memory access or wrong variable type) - Implemented positional ('%1$d') specifiers (POSIX style) - See script_commands.txt for details about the supported format specifiers. Signed-off-by: Haru --- doc/script_commands.txt | 73 ++++++++++++- npc/dev/test.txt | 18 ++++ src/map/script.c | 281 ++++++++++++++++++++++++++++++++---------------- 3 files changed, 275 insertions(+), 97 deletions(-) (limited to 'src/map/script.c') diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 05d075ac1..f9a628953 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -8067,10 +8067,75 @@ Example: *sprintf({,param{,param{,...}}}) -C style sprintf. The resulting string is returned same as in PHP. All C -format specifiers are supported except %n. For more info check sprintf -function at www.cplusplus.com -Number of params is only limited by Hercules' script engine. +C style sprintf. The resulting string is returned. + +The format string can contain placeholders (format specifiers) using the +following structure: + + %[parameter][flags][width]type + +The following format specifier types are supported: + +%%: Prints a literal '%' (special case, doesn't support parameter, flag, width) +%d, %i: Formats the specified value as a decimal signed number +%u: Formats the specified value as a decimal unsigned number +%x: Formats the specified value as a hexadecimal (lowercase) unsigned number +%X: Formats the specified value as a hexadecimal (uppercase) unsigned number +%o: Formats the specified value as an octal unsigned number +%s: Formats the specified value as a string +%c: Formats the specified value as a character (only uses the first character + of strings) + +The following format specifier types are not supported: + +%n (not implemented due to safety concerns) +%f, %F, %e, %E, %g, %G (the script engine doesn't use floating point values) +%p (the script engine doesn't use pointers) +%a, %A (not supported, use 0x%x and 0x%X respectively instead) + +An ordinal parameter can be specified in the form 'x$' (where x is a number), +to reorder the output (this may be useful in translated strings, where the +sentence order may be different from the original order). Example: + + // Name, level, job name + mes(sprintf("Hello, I'm %s, a level %d %s", strcharinfo(PC_NAME), BaseLevel, jobname(Class))); + +When translating the sentence to other languages (for example Italian), +swapping some arguments may be appropriate, and it may be desirable to keep the +actual arguments in the same order (i.e. when translating through the HULD): + + // Job name is printed before the level, although they're specified in the opposite order. + // Name, job name, level + mes(sprintf("Ciao, io sono %1$s, un %3$s di livello %2$d", strcharinfo(PC_NAME), BaseLevel, jobname(Class))); + +The supported format specifier flags are: + +- (minus): Left-align the output of this format specifier. (the default is to + right-align the output). ++ (plus): Prepends a plus for positive signed-numeric types. positive = '+', + negative = '-'. +(space): Prepends a space for positive signed-numeric types. positive = ' ', + negative = '-'. This flag is ignored if the '+' flag exists. +0 (zero): When a field width option is specified, prepends zeros for numeric + types. (the default prepends spaces). +A field width can be specified. + + mes(sprintf("The temperature is %+d degrees Celsius", .@temperature)); // Keeps the '+' sign in front of positive values + .@map_name$ = sprintf("quiz_%02d", .@i); // Keeps the leading 0 in "quiz_00", etc + +A field width may be specified, to ensure that 'at least' that many characters +are printed. If a star ('*') is specified as width, then the width is read as +argument to the sprintf() function. This also supports positional arguments. + + sprintf("%04d", 10) // Returns "0010" + sprintf("%0*d", 5, 10) // Returns "00010" + sprintf("%5d", 10) // Returns " 10" + sprintf("%-5d", 10) // Returns "10 " + sprintf("%10s", "Hello") // Returns " Hello"; + sprintf("%-10s", "Hello") // Returns "Hello "; + +Precision ('.X') and length ('hh', 'h', 'l', 'll', 'L', 'z', 'j', 't') +specifiers are not implemented (not necessary for the script engine purposes) Example: .@format$ = "The %s contains %d monkeys"; diff --git a/npc/dev/test.txt b/npc/dev/test.txt index 72cf86616..ee2bda259 100644 --- a/npc/dev/test.txt +++ b/npc/dev/test.txt @@ -711,6 +711,24 @@ function script HerculesSelfTestHelper { callsub(OnCheck, "Callfunc (return NPC variables from another NPC)", callfunc("F_TestVarOfAnotherNPC", "TestVarOfAnotherNPC"), 1); callsub(OnCheck, "Callfunc (return NPC variables from another NPC - local variable overwrite check)", .x, 2); + callsub(OnCheckStr, "sprintf (%%)", sprintf("'%%'"), "'%'"); + callsub(OnCheckStr, "sprintf (%d)", sprintf("'%d'", 5), "'5'"); + callsub(OnCheckStr, "sprintf (neg. %d)", sprintf("'%d'", -5), "'-5'"); + callsub(OnCheckStr, "sprintf (%u)", sprintf("'%u'", 5), "'5'"); + callsub(OnCheckStr, "sprintf (%x)", sprintf("'%x'", 10), "'a'"); + callsub(OnCheckStr, "sprintf (%X)", sprintf("'%X'", 31), "'1F'"); + callsub(OnCheckStr, "sprintf (%s)", sprintf("'%s'", "Hello World!"), "'Hello World!'"); + callsub(OnCheckStr, "sprintf (%c)", sprintf("'%c'", "Hello World!"), "'H'"); + callsub(OnCheckStr, "sprintf (%+d)", sprintf("'%+d'", 5), "'+5'"); + callsub(OnCheckStr, "sprintf (%{n}d)", sprintf("'%5d'", 5), "' 5'"); + callsub(OnCheckStr, "sprintf (%-{n}d)", sprintf("'%-5d'", 5), "'5 '"); + callsub(OnCheckStr, "sprintf (%-+{n}d)", sprintf("'%-+5d'", 5), "'+5 '"); + callsub(OnCheckStr, "sprintf (%+0{n}d)", sprintf("'%+05d'", 5), "'+0005'"); + callsub(OnCheckStr, "sprintf (%0*d)", sprintf("'%0*d'", 5, 10), "'00010'"); + callsub(OnCheckStr, "sprintf (Two args)", sprintf("'%+05d' '%x'", 5, 0x7f), "'+0005' '7f'"); + callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$+05d'", 5, 6), "'+0006'"); + callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$s' '%1$c'", "First", "Second"), "'Second' 'F'"); + if (.errors) { debugmes "Script engine self-test [ \033[0;31mFAILED\033[0m ]"; debugmes "**** The test was completed with " + .errors + " errors. ****"; diff --git a/src/map/script.c b/src/map/script.c index fa33c5d76..d97dacb89 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -15239,129 +15239,224 @@ BUILDIN(implode) // Implements C sprintf, except format %n. The resulting string is // returned, instead of being saved in variable by reference. //------------------------------------------------------- -BUILDIN(sprintf) { - unsigned int argc = 0, arg = 0; - const char* format; - char* p; - char* q; - char* buf = NULL; - char* buf2 = NULL; - struct script_data* data; - size_t len, buf2_len = 0; +BUILDIN(sprintf) +{ + const char *format = script_getstr(st, 2); + const char *p = NULL, *np = NULL; StringBuf final_buf; + char *buf = NULL; + int buf_len = 0; + int lastarg = 2; + int argc = script_lastdata(st) + 1; - // Fetch init data - format = script_getstr(st, 2); - argc = script_lastdata(st)-2; - len = strlen(format); - - // Skip parsing, where no parsing is required. - if(len==0) { - script_pushconststr(st,""); - return true; - } - - // Pessimistic alloc - CREATE(buf, char, len+1); - - // Need not be parsed, just solve stuff like %%. - if(argc==0) { - memcpy(buf,format,len+1); - script_pushstrcopy(st, buf); - aFree(buf); - return true; - } + StrBuf->Init(&final_buf); - safestrncpy(buf, format, len+1); + p = format; - // Issue sprintf for each parameter - StrBuf->Init(&final_buf); - q = buf; - while((p = strchr(q, '%'))!=NULL) { - if(p!=q) { - len = p-q+1; - if(buf2_lenAppendStr(&final_buf, buf2); - q = p; + safestrncpy(buf, p, len); + StrBuf->AppendStr(&final_buf, buf); } - p = q+1; - if(*p=='%') { // %% + + p = np; + np++; + + // placeholder = "%%" ; (special case) + if (*np == '%') { StrBuf->AppendStr(&final_buf, "%"); - q+=2; + p = np + 1; continue; } - if(*p=='n') { // %n + // placeholder = "%n" ; (ignored) + if (*np == 'n') { ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n"); script->reportsrc(st); - q+=2; + lastarg = nextarg; + p = np + 1; continue; } - if(arg>=argc) { + + // std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type + + // pos-parameter = number "$" + if (ISDIGIT(*np) && *np != '0') { + const char *pp = np; + while (ISDIGIT(*pp)) + pp++; + if (*pp == '$') { + thisarg = atoi(np) + 2; + positional_arg = true; + np = pp + 1; + } + } + + if (thisarg >= argc) { ShowError("buildin_sprintf: Not enough arguments passed!\n"); - aFree(buf); - if(buf2) aFree(buf2); + if (buf != NULL) + aFree(buf); StrBuf->Destroy(&final_buf); script_pushconststr(st,""); return false; } - if((p = strchr(q+1, '%'))==NULL) { - p = strchr(q, 0); // EOS - } - len = p-q+1; - if(buf2_lenPrintf(&final_buf, buf2, script_getstr(st, arg+3)); - } else if(data_isint(data)) { // Number - StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); - } else if(data_isreference(data)) { // Variable - char* name = reference_getname(data); - if(name[strlen(name)-1]=='$') { // var Str - StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3)); - } else { // var Int - StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); + // width = number / ("*" [pos-parameter]) + if (ISDIGIT(*np)) { + width = atoi(np); + while (ISDIGIT(*np)) + np++; + } else if (*np == '*') { + bool positional_widtharg = false; + int width_arg; + np++; + // pos-parameter = number "$" + if (ISDIGIT(*np) && *np != '0') { + const char *pp = np; + while (ISDIGIT(*pp)) + pp++; + if (*pp == '$') { + width_arg = atoi(np) + 2; + positional_widtharg = true; + np = pp + 1; + } } - } else { // Unsupported type - ShowError("buildin_sprintf: Unknown argument type!\n"); - aFree(buf); - if(buf2) aFree(buf2); + if (!positional_widtharg) { + width_arg = nextarg; + nextarg++; + if (!positional_arg) + thisarg++; + } + + if (width_arg >= argc || thisarg >= argc) { + ShowError("buildin_sprintf: Not enough arguments passed!\n"); + if (buf != NULL) + aFree(buf); + StrBuf->Destroy(&final_buf); + script_pushconststr(st,""); + return false; + } + width = script_getnum(st, width_arg); + } + + // precision = "." (number / ("*" [pos-parameter])) ; (not needed/implemented) + + // length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" ; (not needed/implemented) + + // type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A" + if (buf_len < 16) { + RECREATE(buf, char, 16); + buf_len = 16; + } + { + int i = 0; + memset(buf, '\0', buf_len); + buf[i++] = '%'; + if (flag_minus) + buf[i++] = '-'; + if (flag_plus) + buf[i++] = '+'; + else if (flag_space) // ignored if '+' is specified + buf[i++] = ' '; + if (flag_zero) + buf[i++] = '0'; + if (width > 0) + safesnprintf(buf + i, buf_len - i - 1, "%d", width); + } + buf[(int)strlen(buf)] = *np; + switch (*np) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + // Piggyback printf + StrBuf->Printf(&final_buf, buf, script_getnum(st, thisarg)); + break; + case 's': + // Piggyback printf + StrBuf->Printf(&final_buf, buf, script_getstr(st, thisarg)); + break; + case 'c': + { + const char *str = script_getstr(st, thisarg); + // Piggyback printf + StrBuf->Printf(&final_buf, buf, str[0]); + } + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'p': + case 'a': + case 'A': + ShowWarning("buildin_sprintf: Format %%%c not supported! Skipping...\n", *np); + script->reportsrc(st); + lastarg = nextarg; + p = np + 1; + continue; + default: + ShowError("buildin_sprintf: Invalid format string.\n"); + if (buf != NULL) + aFree(buf); StrBuf->Destroy(&final_buf); script_pushconststr(st,""); return false; } - arg++; - } - - // Append anything left - if(*q) { - StrBuf->AppendStr(&final_buf, q); + lastarg = nextarg; + p = np + 1; } - // Passed more, than needed - if(argreportsrc(st); - } + // Append the remaining part + if (p != NULL) + StrBuf->AppendStr(&final_buf, p); script_pushstrcopy(st, StrBuf->Value(&final_buf)); - aFree(buf); - if(buf2) aFree(buf2); + if (buf != NULL) + aFree(buf); StrBuf->Destroy(&final_buf); return true; -- cgit v1.2.3-70-g09d2 From d7db381921c0d6c6b1cdaa4b2083aa1d877046f5 Mon Sep 17 00:00:00 2001 From: Haru Date: Thu, 31 Dec 2015 21:12:31 +0100 Subject: Improved handling of nested function calls by the HULD Signed-off-by: Haru --- src/map/script.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index d97dacb89..46116f75a 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -803,18 +803,13 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) char *arg = NULL; char null_arg = '\0'; int func; - bool nested_call = false, macro = false; + bool macro = false; // is need add check for arg null pointer below? func = script->add_word(p); - if( script->str_data[func].type == C_FUNC ) { - /** only when unset (-1), valid values are >= 0 **/ - if( script->syntax.last_func == -1 ) - script->syntax.last_func = script->str_data[func].val; - else { //Nested function call - script->syntax.nested_call++; - nested_call = true; - + if (script->str_data[func].type == C_FUNC) { + script->syntax.nested_call++; + if (script->syntax.last_func != -1) { if( script->str_data[func].val == script->buildin_lang_macro_offset ) { script->syntax.lang_macro_active = true; macro = true; @@ -823,6 +818,7 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) if( !macro ) { // buildin function + script->syntax.last_func = script->str_data[func].val; script->addl(func); script->addc(C_ARG); } @@ -915,14 +911,11 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) script->syntax.lang_macro_active = false; } - if( nested_call ) - script->syntax.nested_call--; - - if( !script->syntax.nested_call ) - script->syntax.last_func = -1; - - if( !macro ) + if (!macro) { + if (0 == --script->syntax.nested_call) + script->syntax.last_func = -1; script->addc(C_FUNC); + } return p; } @@ -1058,6 +1051,8 @@ const char* parse_variable(const char* p) } // push the set function onto the stack + script->syntax.nested_call++; + script->syntax.last_func = script->str_data[script->buildin_set_ref].val; script->addl(script->buildin_set_ref); script->addc(C_ARG); @@ -1109,6 +1104,8 @@ const char* parse_variable(const char* p) // close the script by appending the function operator script->addc(C_FUNC); + if (--script->syntax.nested_call == 0) + script->syntax.last_func = -1; // push the buffer from the method return p; @@ -1295,7 +1292,7 @@ const char* parse_simpleexpr(const char *p) if( script->lang_export_fp && !duplicate && ( ( ( script->syntax.last_func == script->buildin_mes_offset || - script->syntax.last_func == script->buildin_select_offset ) && !script->syntax.nested_call + script->syntax.last_func == script->buildin_select_offset ) ) || script->syntax.lang_macro_active ) ) { const char *line_start = start_point; const char *line_end = start_point; -- cgit v1.2.3-70-g09d2 From d9fade08f4faf1f70671bdf02f124af7c5b236bc Mon Sep 17 00:00:00 2001 From: Haru Date: Fri, 1 Jan 2016 05:52:36 +0100 Subject: Correctly escaped special characters in the generated_translations.pot Signed-off-by: Haru --- src/common/strlib.c | 1 + src/map/script.c | 26 +++++++++++--------------- src/map/script.h | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) (limited to 'src/map/script.c') diff --git a/src/common/strlib.c b/src/common/strlib.c index 9690151b4..b67adb63c 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -772,6 +772,7 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca case '\v': out_dest[j++] = 'v'; break; case '\f': out_dest[j++] = 'f'; break; case '\?': out_dest[j++] = '?'; break; + case '\"': out_dest[j++] = '"'; break; default:// to octal out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); diff --git a/src/map/script.c b/src/map/script.c index 46116f75a..753306f91 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1296,7 +1296,7 @@ const char* parse_simpleexpr(const char *p) ) || script->syntax.lang_macro_active ) ) { const char *line_start = start_point; const char *line_end = start_point; - int line_length, cursor; + int line_length; while( line_start > script->parser_current_src ) { if( *line_start != '\n' ) @@ -1317,16 +1317,12 @@ const char* parse_simpleexpr(const char *p) normalize_name(VECTOR_DATA(script->lang_export_line_buf), "\r\n\t "); // [!] Note: VECTOR_LENGTH() will lie. } - for (cursor = 0; cursor < VECTOR_LENGTH(script->parse_simpleexpr_str); cursor++) { - if (VECTOR_INDEX(script->parse_simpleexpr_str, cursor) == '"') { - VECTOR_ENSURE(script->lang_export_unescaped_buf, 1, 512); - VECTOR_PUSH(script->lang_export_unescaped_buf, '\\'); - } - VECTOR_ENSURE(script->lang_export_unescaped_buf, 1, 512); - VECTOR_PUSH(script->lang_export_unescaped_buf, VECTOR_INDEX(script->parse_simpleexpr_str, cursor)); - } - VECTOR_ENSURE(script->lang_export_unescaped_buf, 1, 512); - VECTOR_PUSH(script->lang_export_unescaped_buf, '\0'); + VECTOR_ENSURE(script->lang_export_escaped_buf, 4*VECTOR_LENGTH(script->parse_simpleexpr_str)+1, 1); + VECTOR_LENGTH(script->lang_export_escaped_buf) = (int)sv->escape_c(VECTOR_DATA(script->lang_export_escaped_buf), + VECTOR_DATA(script->parse_simpleexpr_str), + VECTOR_LENGTH(script->parse_simpleexpr_str)-1, /* exclude null terminator */ + "\""); + VECTOR_PUSH(script->lang_export_escaped_buf, '\0'); fprintf(script->lang_export_fp, "#: %s\n" "# %s\n" @@ -1336,10 +1332,10 @@ const char* parse_simpleexpr(const char *p) script->parser_current_file ? script->parser_current_file : "Unknown File", VECTOR_DATA(script->lang_export_line_buf), script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", - VECTOR_DATA(script->lang_export_unescaped_buf) + VECTOR_DATA(script->lang_export_escaped_buf) ); VECTOR_TRUNCATE(script->lang_export_line_buf); - VECTOR_TRUNCATE(script->lang_export_unescaped_buf); + VECTOR_TRUNCATE(script->lang_export_escaped_buf); } VECTOR_TRUNCATE(script->parse_simpleexpr_str); } else { @@ -5169,7 +5165,7 @@ void script_parser_clean_leftovers(void) VECTOR_CLEAR(script->parse_simpleexpr_str); VECTOR_CLEAR(script->lang_export_line_buf); - VECTOR_CLEAR(script->lang_export_unescaped_buf); + VECTOR_CLEAR(script->lang_export_escaped_buf); } /** @@ -5189,7 +5185,7 @@ int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) { void do_init_script(bool minimal) { script->parse_cleanup_timer_id = INVALID_TIMER; VECTOR_INIT(script->lang_export_line_buf); - VECTOR_INIT(script->lang_export_unescaped_buf); + VECTOR_INIT(script->lang_export_escaped_buf); VECTOR_INIT(script->parse_simpleexpr_str); script->st_db = idb_alloc(DB_OPT_BASE); diff --git a/src/map/script.h b/src/map/script.h index 845d52280..35a6a1bbf 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -637,7 +637,7 @@ struct script_interface { /* */ struct script_string_buf parse_simpleexpr_str; struct script_string_buf lang_export_line_buf; - struct script_string_buf lang_export_unescaped_buf; + struct script_string_buf lang_export_escaped_buf; /* */ int parse_cleanup_timer_id; /* */ -- cgit v1.2.3-70-g09d2 From 95d5ff6fde56fbd407ac5fe07ceae22f67fea1da Mon Sep 17 00:00:00 2001 From: Haru Date: Tue, 17 May 2016 00:06:14 +0200 Subject: Split parse_simpleexpr() in specialized sub-functions (HPM compatibility) - parse_simpleexpr_paren() - parse_simpleexpr_number() - parse_simplexpr_string() - parse_simpleexpr_name() Signed-off-by: Haru --- src/map/script.c | 390 ++++++++++++++++++++++++++++++------------------------- src/map/script.h | 12 +- 2 files changed, 220 insertions(+), 182 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index 753306f91..7067c44b4 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1174,216 +1174,246 @@ int script_string_dup(char *str) /*========================================== * Analysis section *------------------------------------------*/ -const char* parse_simpleexpr(const char *p) +const char *parse_simpleexpr(const char *p) { p=script->skip_space(p); - if(*p==';' || *p==',') + if (*p == ';' || *p == ',') disp_error_message("parse_simpleexpr: unexpected end of expression",p); - if(*p=='(') { - int i = script->syntax.curly_count-1; - if (i >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST) - ++script->syntax.curly[i].count; - p=script->parse_subexpr(p+1,-1); - p=script->skip_space(p); - if( (i=script->syntax.curly_count-1) >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST - && script->syntax.curly[i].flag == ARGLIST_UNDEFINED && --script->syntax.curly[i].count == 0 - ) { - if( *p == ',' ) { - script->syntax.curly[i].flag = ARGLIST_PAREN; - return p; - } else { - script->syntax.curly[i].flag = ARGLIST_NO_PAREN; - } + if (*p == '(') { + return script->parse_simpleexpr_paren(p); + } else if (is_number(p)) { + return script->parse_simpleexpr_number(p); + } else if(*p == '"') { + return script->parse_simpleexpr_string(p); + } else { + return script->parse_simpleexpr_name(p); + } +} + +const char *parse_simpleexpr_paren(const char *p) +{ + int i = script->syntax.curly_count - 1; + if (i >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST) + ++script->syntax.curly[i].count; + + p = script->parse_subexpr(p + 1, -1); + p = script->skip_space(p); + if ((i = script->syntax.curly_count - 1) >= 0 + && script->syntax.curly[i].type == TYPE_ARGLIST + && script->syntax.curly[i].flag == ARGLIST_UNDEFINED + && --script->syntax.curly[i].count == 0 + ) { + if (*p == ',') { + script->syntax.curly[i].flag = ARGLIST_PAREN; + return p; + } else { + script->syntax.curly[i].flag = ARGLIST_NO_PAREN; } - if( *p != ')' ) - disp_error_message("parse_simpleexpr: unmatched ')'",p); - ++p; - } else if(is_number(p)) { - char *np; - long long lli; - while(*p == '0' && ISDIGIT(p[1])) p++; // Skip leading zeros, we don't support octal literals - lli=strtoll(p,&np,0); - if( lli < INT_MIN ) { - lli = INT_MIN; - script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN",p); - } else if( lli > INT_MAX ) { - lli = INT_MAX; - script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX",p); - } - script->addi((int)lli); // Cast is safe, as it's already been checked for overflows - p=np; - } else if(*p=='"') { - struct string_translation *st = NULL; - const char *start_point = p; - bool duplicate = true; + } + if (*p != ')') + disp_error_message("parse_simpleexpr: unmatched ')'", p); - do { - p++; - while( *p && *p != '"' ) { - if( (unsigned char)p[-1] <= 0x7e && *p == '\\' ) { - char buf[8]; - size_t len = sv->skip_escaped_c(p) - p; - size_t n = sv->unescape_c(buf, p, len); - if( n != 1 ) - ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); - p += len; - VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); - VECTOR_PUSH(script->parse_simpleexpr_str, buf[0]); - continue; - } else if( *p == '\n' ) { - disp_error_message("parse_simpleexpr: unexpected newline @ string",p); - } - VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); - VECTOR_PUSH(script->parse_simpleexpr_str, *p++); - } - if(!*p) - disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); - p++; //'"' - p = script->skip_space(p); - } while( *p && *p == '"' ); + return p + 1; +} - VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); - VECTOR_PUSH(script->parse_simpleexpr_str, '\0'); +const char *parse_simpleexpr_number(const char *p) +{ + char *np = NULL; + long long lli; - if (script->syntax.translation_db == NULL - || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(script->parse_simpleexpr_str))) == NULL) { - script->addc(C_STR); + while (*p == '0' && ISDIGIT(p[1])) + p++; // Skip leading zeros, we don't support octal literals - VECTOR_ENSURE(script->buf, VECTOR_LENGTH(script->parse_simpleexpr_str), SCRIPT_BLOCK_SIZE); + lli = strtoll(p, &np, 0); + if (lli < INT_MIN) { + lli = INT_MIN; + script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN", p); + } else if (lli > INT_MAX) { + lli = INT_MAX; + script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX", p); + } + script->addi((int)lli); // Cast is safe, as it's already been checked for overflows - VECTOR_PUSHARRAY(script->buf, VECTOR_DATA(script->parse_simpleexpr_str), VECTOR_LENGTH(script->parse_simpleexpr_str)); - } else { - unsigned char u; - int st_cursor = 0; - - script->addc(C_LSTR); - - VECTOR_ENSURE(script->buf, (int)(sizeof(st->string_id) + sizeof(st->translations)), SCRIPT_BLOCK_SIZE); - VECTOR_PUSHARRAY(script->buf, (void *)&st->string_id, sizeof(st->string_id)); - VECTOR_PUSHARRAY(script->buf, (void *)&st->translations, sizeof(st->translations)); - - for (u = 0; u != st->translations; u++) { - struct string_translation_entry *entry = (void *)(st->buf+st_cursor); - char *stringptr = &entry->string[0]; - st_cursor += sizeof(*entry); - VECTOR_ENSURE(script->buf, (int)(sizeof(entry->lang_id) + sizeof(char *)), SCRIPT_BLOCK_SIZE); - VECTOR_PUSHARRAY(script->buf, (void *)&entry->lang_id, sizeof(entry->lang_id)); - VECTOR_PUSHARRAY(script->buf, (void *)&stringptr, sizeof(stringptr)); - st_cursor += sizeof(uint8); // FIXME: What are we skipping here? - while (st->buf[st_cursor++] != 0) - (void)0; // Skip string - st_cursor += sizeof(uint8); // FIXME: What are we skipping here? - } - } + return np; +} - /* When exporting we don't know what is a translation and what isn't */ - if (script->lang_export_fp && VECTOR_LENGTH(script->parse_simpleexpr_str) > 1) { - // The length of script->parse_simpleexpr_str will always be at least 1 because of the '\0' - if( !script->syntax.strings ) { - script->syntax.strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); - } +const char *parse_simpleexpr_string(const char *p) +{ + struct string_translation *st = NULL; + const char *start_point = p; + bool duplicate = true; - if (!strdb_exists(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str))) { - strdb_put(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str), NULL); - duplicate = false; + do { + p++; + while (*p != '\0' && *p != '"') { + if ((unsigned char)p[-1] <= 0x7e && *p == '\\') { + char buf[8]; + size_t len = sv->skip_escaped_c(p) - p; + size_t n = sv->unescape_c(buf, p, len); + if (n != 1) + ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); + p += len; + VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_str, buf[0]); + continue; } + if (*p == '\n') { + disp_error_message("parse_simpleexpr: unexpected newline @ string", p); + } + VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_str, *p++); } + if (*p == '\0') + disp_error_message("parse_simpleexpr: unexpected end of file @ string", p); + p++; //'"' + p = script->skip_space(p); + } while (*p != '\0' && *p == '"'); - if( script->lang_export_fp && !duplicate && - ( ( ( script->syntax.last_func == script->buildin_mes_offset || - script->syntax.last_func == script->buildin_select_offset ) - ) || script->syntax.lang_macro_active ) ) { - const char *line_start = start_point; - const char *line_end = start_point; - int line_length; + VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_str, '\0'); - while( line_start > script->parser_current_src ) { - if( *line_start != '\n' ) - line_start--; - else - break; - } + if (script->syntax.translation_db == NULL + || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(script->parse_simpleexpr_str))) == NULL) { + script->addc(C_STR); - while( *line_end != '\n' && *line_end != '\0' ) - line_end++; + VECTOR_ENSURE(script->buf, VECTOR_LENGTH(script->parse_simpleexpr_str), SCRIPT_BLOCK_SIZE); - line_length = (int)(line_end - line_start); - if( line_length > 0 ) { - VECTOR_ENSURE(script->lang_export_line_buf, line_length + 1, 512); - VECTOR_PUSHARRAY(script->lang_export_line_buf, line_start, line_length); - VECTOR_PUSH(script->lang_export_line_buf, '\0'); + VECTOR_PUSHARRAY(script->buf, VECTOR_DATA(script->parse_simpleexpr_str), VECTOR_LENGTH(script->parse_simpleexpr_str)); + } else { + unsigned char u; + int st_cursor = 0; - normalize_name(VECTOR_DATA(script->lang_export_line_buf), "\r\n\t "); // [!] Note: VECTOR_LENGTH() will lie. - } + script->addc(C_LSTR); - VECTOR_ENSURE(script->lang_export_escaped_buf, 4*VECTOR_LENGTH(script->parse_simpleexpr_str)+1, 1); - VECTOR_LENGTH(script->lang_export_escaped_buf) = (int)sv->escape_c(VECTOR_DATA(script->lang_export_escaped_buf), - VECTOR_DATA(script->parse_simpleexpr_str), - VECTOR_LENGTH(script->parse_simpleexpr_str)-1, /* exclude null terminator */ - "\""); - VECTOR_PUSH(script->lang_export_escaped_buf, '\0'); - - fprintf(script->lang_export_fp, "#: %s\n" - "# %s\n" - "msgctxt \"%s\"\n" - "msgid \"%s\"\n" - "msgstr \"\"\n", - script->parser_current_file ? script->parser_current_file : "Unknown File", - VECTOR_DATA(script->lang_export_line_buf), - script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", - VECTOR_DATA(script->lang_export_escaped_buf) - ); - VECTOR_TRUNCATE(script->lang_export_line_buf); - VECTOR_TRUNCATE(script->lang_export_escaped_buf); + VECTOR_ENSURE(script->buf, (int)(sizeof(st->string_id) + sizeof(st->translations)), SCRIPT_BLOCK_SIZE); + VECTOR_PUSHARRAY(script->buf, (void *)&st->string_id, sizeof(st->string_id)); + VECTOR_PUSHARRAY(script->buf, (void *)&st->translations, sizeof(st->translations)); + + for (u = 0; u != st->translations; u++) { + struct string_translation_entry *entry = (void *)(st->buf+st_cursor); + char *stringptr = &entry->string[0]; + st_cursor += sizeof(*entry); + VECTOR_ENSURE(script->buf, (int)(sizeof(entry->lang_id) + sizeof(char *)), SCRIPT_BLOCK_SIZE); + VECTOR_PUSHARRAY(script->buf, (void *)&entry->lang_id, sizeof(entry->lang_id)); + VECTOR_PUSHARRAY(script->buf, (void *)&stringptr, sizeof(stringptr)); + st_cursor += sizeof(uint8); // FIXME: What are we skipping here? + while (st->buf[st_cursor++] != 0) + (void)0; // Skip string + st_cursor += sizeof(uint8); // FIXME: What are we skipping here? } - VECTOR_TRUNCATE(script->parse_simpleexpr_str); - } else { - int l; - const char* pv; + } - // label , register , function etc - if(script->skip_word(p)==p) - disp_error_message("parse_simpleexpr: unexpected character",p); + /* When exporting we don't know what is a translation and what isn't */ + if (script->lang_export_fp != NULL && VECTOR_LENGTH(script->parse_simpleexpr_str) > 1) { + // The length of script->parse_simpleexpr_str will always be at least 1 because of the '\0' + if (script->syntax.strings == NULL) { + script->syntax.strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); + } - l=script->add_word(p); - if( script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) { - return script->parse_callfunc(p,1,0); -#ifdef SCRIPT_CALLFUNC_CHECK - } else { - const char* name = script->get_str(l); - if( strdb_get(script->userfunc_db,name) != NULL ) { - return script->parse_callfunc(p,1,1); - } -#endif + if (!strdb_exists(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str))) { + strdb_put(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str), NULL); + duplicate = false; } + } + + if (script->lang_export_fp != NULL && !duplicate && + ( ( ( script->syntax.last_func == script->buildin_mes_offset || + script->syntax.last_func == script->buildin_select_offset ) + ) || script->syntax.lang_macro_active ) ) { + const char *line_start = start_point; + const char *line_end = start_point; + int line_length; - if( (pv = script->parse_variable(p)) ) { - // successfully processed a variable assignment - return pv; + while( line_start > script->parser_current_src ) { + if( *line_start != '\n' ) + line_start--; + else + break; } - if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) { - disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p); + while( *line_end != '\n' && *line_end != '\0' ) + line_end++; + + line_length = (int)(line_end - line_start); + if( line_length > 0 ) { + VECTOR_ENSURE(script->lang_export_line_buf, line_length + 1, 512); + VECTOR_PUSHARRAY(script->lang_export_line_buf, line_start, line_length); + VECTOR_PUSH(script->lang_export_line_buf, '\0'); + + normalize_name(VECTOR_DATA(script->lang_export_line_buf), "\r\n\t "); // [!] Note: VECTOR_LENGTH() will lie. } - p=script->skip_word(p); - if( *p == '[' ) { - // array(name[i] => getelementofarray(name,i) ) - script->addl(script->buildin_getelementofarray_ref); - script->addc(C_ARG); - script->addl(l); + VECTOR_ENSURE(script->lang_export_escaped_buf, 4*VECTOR_LENGTH(script->parse_simpleexpr_str)+1, 1); + VECTOR_LENGTH(script->lang_export_escaped_buf) = (int)sv->escape_c(VECTOR_DATA(script->lang_export_escaped_buf), + VECTOR_DATA(script->parse_simpleexpr_str), + VECTOR_LENGTH(script->parse_simpleexpr_str)-1, /* exclude null terminator */ + "\""); + VECTOR_PUSH(script->lang_export_escaped_buf, '\0'); - p=script->parse_subexpr(p+1,-1); - p=script->skip_space(p); - if( *p != ']' ) - disp_error_message("parse_simpleexpr: unmatched ']'",p); - ++p; - script->addc(C_FUNC); - } else { - script->addl(l); + fprintf(script->lang_export_fp, "#: %s\n" + "# %s\n" + "msgctxt \"%s\"\n" + "msgid \"%s\"\n" + "msgstr \"\"\n", + script->parser_current_file ? script->parser_current_file : "Unknown File", + VECTOR_DATA(script->lang_export_line_buf), + script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", + VECTOR_DATA(script->lang_export_escaped_buf) + ); + VECTOR_TRUNCATE(script->lang_export_line_buf); + VECTOR_TRUNCATE(script->lang_export_escaped_buf); + } + VECTOR_TRUNCATE(script->parse_simpleexpr_str); + + return p; +} + +const char *parse_simpleexpr_name(const char *p) +{ + int l; + const char *pv = NULL; + + // label , register , function etc + if (script->skip_word(p) == p) + disp_error_message("parse_simpleexpr: unexpected character", p); + + l = script->add_word(p); + if (script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) { + return script->parse_callfunc(p,1,0); +#ifdef SCRIPT_CALLFUNC_CHECK + } else { + const char *name = script->get_str(l); + if (strdb_get(script->userfunc_db,name) != NULL) { + return script->parse_callfunc(p, 1, 1); } +#endif + } + + if ((pv = script->parse_variable(p)) != NULL) { + // successfully processed a variable assignment + return pv; + } + if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) { + disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p); + } + + p = script->skip_word(p); + if (*p == '[') { + // array(name[i] => getelementofarray(name,i) ) + script->addl(script->buildin_getelementofarray_ref); + script->addc(C_ARG); + script->addl(l); + + p = script->parse_subexpr(p + 1, -1); + p = script->skip_space(p); + if (*p != ']') + disp_error_message("parse_simpleexpr: unmatched ']'", p); + ++p; + script->addc(C_FUNC); + } else { + script->addl(l); } return p; @@ -21266,6 +21296,10 @@ void script_defaults(void) { script->parse_nextline = parse_nextline; script->parse_variable = parse_variable; script->parse_simpleexpr = parse_simpleexpr; + script->parse_simpleexpr_paren = parse_simpleexpr_paren; + script->parse_simpleexpr_number = parse_simpleexpr_number; + script->parse_simpleexpr_string = parse_simpleexpr_string; + script->parse_simpleexpr_name = parse_simpleexpr_name; script->parse_expr = parse_expr; script->parse_line = parse_line; script->read_constdb = read_constdb; diff --git a/src/map/script.h b/src/map/script.h index 35a6a1bbf..a9a719099 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -731,10 +731,14 @@ struct script_interface { int (*add_word) (const char *p); const char* (*parse_callfunc) (const char *p, int require_paren, int is_custom); void (*parse_nextline) (bool first, const char *p); - const char* (*parse_variable) (const char *p); - const char* (*parse_simpleexpr) (const char *p); - const char* (*parse_expr) (const char *p); - const char* (*parse_line) (const char *p); + const char *(*parse_variable) (const char *p); + const char *(*parse_simpleexpr) (const char *p); + const char *(*parse_simpleexpr_paren) (const char *p); + const char *(*parse_simpleexpr_number) (const char *p); + const char *(*parse_simpleexpr_string) (const char *p); + const char *(*parse_simpleexpr_name) (const char *p); + const char *(*parse_expr) (const char *p); + const char *(*parse_line) (const char *p); void (*read_constdb) (void); void (*constdb_comment) (const char *comment); void (*load_parameters) (void); -- cgit v1.2.3-70-g09d2 From 70a1facc30c2670d57744b67ec2e7842b8e0a840 Mon Sep 17 00:00:00 2001 From: Haru Date: Tue, 17 May 2016 00:44:14 +0200 Subject: Split translation handling out of parse_simpleexpr_string() Signed-off-by: Haru --- src/map/script.c | 154 +++++++++++++++++++++++++++++-------------------------- src/map/script.h | 3 +- 2 files changed, 83 insertions(+), 74 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index 7067c44b4..5b179dea1 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1240,9 +1240,7 @@ const char *parse_simpleexpr_number(const char *p) const char *parse_simpleexpr_string(const char *p) { - struct string_translation *st = NULL; const char *start_point = p; - bool duplicate = true; do { p++; @@ -1254,15 +1252,15 @@ const char *parse_simpleexpr_string(const char *p) if (n != 1) ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); p += len; - VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); - VECTOR_PUSH(script->parse_simpleexpr_str, buf[0]); + VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_strbuf, buf[0]); continue; } if (*p == '\n') { disp_error_message("parse_simpleexpr: unexpected newline @ string", p); } - VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); - VECTOR_PUSH(script->parse_simpleexpr_str, *p++); + VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_strbuf, *p++); } if (*p == '\0') disp_error_message("parse_simpleexpr: unexpected end of file @ string", p); @@ -1270,16 +1268,78 @@ const char *parse_simpleexpr_string(const char *p) p = script->skip_space(p); } while (*p != '\0' && *p == '"'); - VECTOR_ENSURE(script->parse_simpleexpr_str, 1, 512); - VECTOR_PUSH(script->parse_simpleexpr_str, '\0'); + VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_strbuf, '\0'); + + script->add_translatable_string(&script->parse_simpleexpr_strbuf, start_point); + + VECTOR_TRUNCATE(script->parse_simpleexpr_strbuf); + + return p; +} + +const char *parse_simpleexpr_name(const char *p) +{ + int l; + const char *pv = NULL; + + // label , register , function etc + if (script->skip_word(p) == p) + disp_error_message("parse_simpleexpr: unexpected character", p); + + l = script->add_word(p); + if (script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) { + return script->parse_callfunc(p,1,0); +#ifdef SCRIPT_CALLFUNC_CHECK + } else { + const char *name = script->get_str(l); + if (strdb_get(script->userfunc_db,name) != NULL) { + return script->parse_callfunc(p, 1, 1); + } +#endif + } + + if ((pv = script->parse_variable(p)) != NULL) { + // successfully processed a variable assignment + return pv; + } + + if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) { + disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p); + } + + p = script->skip_word(p); + if (*p == '[') { + // array(name[i] => getelementofarray(name,i) ) + script->addl(script->buildin_getelementofarray_ref); + script->addc(C_ARG); + script->addl(l); + + p = script->parse_subexpr(p + 1, -1); + p = script->skip_space(p); + if (*p != ']') + disp_error_message("parse_simpleexpr: unmatched ']'", p); + ++p; + script->addc(C_FUNC); + } else { + script->addl(l); + } + + return p; +} + +void script_add_translatable_string(const struct script_string_buf *string, const char *start_point) +{ + struct string_translation *st = NULL; + bool duplicate = true; if (script->syntax.translation_db == NULL - || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(script->parse_simpleexpr_str))) == NULL) { + || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(*string))) == NULL) { script->addc(C_STR); - VECTOR_ENSURE(script->buf, VECTOR_LENGTH(script->parse_simpleexpr_str), SCRIPT_BLOCK_SIZE); + VECTOR_ENSURE(script->buf, VECTOR_LENGTH(*string), SCRIPT_BLOCK_SIZE); - VECTOR_PUSHARRAY(script->buf, VECTOR_DATA(script->parse_simpleexpr_str), VECTOR_LENGTH(script->parse_simpleexpr_str)); + VECTOR_PUSHARRAY(script->buf, VECTOR_DATA(*string), VECTOR_LENGTH(*string)); } else { unsigned char u; int st_cursor = 0; @@ -1305,14 +1365,14 @@ const char *parse_simpleexpr_string(const char *p) } /* When exporting we don't know what is a translation and what isn't */ - if (script->lang_export_fp != NULL && VECTOR_LENGTH(script->parse_simpleexpr_str) > 1) { - // The length of script->parse_simpleexpr_str will always be at least 1 because of the '\0' + if (script->lang_export_fp != NULL && VECTOR_LENGTH(*string) > 1) { + // The length of script->parse_simpleexpr_strbuf will always be at least 1 because of the '\0' if (script->syntax.strings == NULL) { script->syntax.strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); } - if (!strdb_exists(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str))) { - strdb_put(script->syntax.strings, VECTOR_DATA(script->parse_simpleexpr_str), NULL); + if (!strdb_exists(script->syntax.strings, VECTOR_DATA(*string))) { + strdb_put(script->syntax.strings, VECTOR_DATA(*string), NULL); duplicate = false; } } @@ -1344,10 +1404,10 @@ const char *parse_simpleexpr_string(const char *p) normalize_name(VECTOR_DATA(script->lang_export_line_buf), "\r\n\t "); // [!] Note: VECTOR_LENGTH() will lie. } - VECTOR_ENSURE(script->lang_export_escaped_buf, 4*VECTOR_LENGTH(script->parse_simpleexpr_str)+1, 1); + VECTOR_ENSURE(script->lang_export_escaped_buf, 4*VECTOR_LENGTH(*string)+1, 1); VECTOR_LENGTH(script->lang_export_escaped_buf) = (int)sv->escape_c(VECTOR_DATA(script->lang_export_escaped_buf), - VECTOR_DATA(script->parse_simpleexpr_str), - VECTOR_LENGTH(script->parse_simpleexpr_str)-1, /* exclude null terminator */ + VECTOR_DATA(*string), + VECTOR_LENGTH(*string)-1, /* exclude null terminator */ "\""); VECTOR_PUSH(script->lang_export_escaped_buf, '\0'); @@ -1364,59 +1424,6 @@ const char *parse_simpleexpr_string(const char *p) VECTOR_TRUNCATE(script->lang_export_line_buf); VECTOR_TRUNCATE(script->lang_export_escaped_buf); } - VECTOR_TRUNCATE(script->parse_simpleexpr_str); - - return p; -} - -const char *parse_simpleexpr_name(const char *p) -{ - int l; - const char *pv = NULL; - - // label , register , function etc - if (script->skip_word(p) == p) - disp_error_message("parse_simpleexpr: unexpected character", p); - - l = script->add_word(p); - if (script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) { - return script->parse_callfunc(p,1,0); -#ifdef SCRIPT_CALLFUNC_CHECK - } else { - const char *name = script->get_str(l); - if (strdb_get(script->userfunc_db,name) != NULL) { - return script->parse_callfunc(p, 1, 1); - } -#endif - } - - if ((pv = script->parse_variable(p)) != NULL) { - // successfully processed a variable assignment - return pv; - } - - if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) { - disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p); - } - - p = script->skip_word(p); - if (*p == '[') { - // array(name[i] => getelementofarray(name,i) ) - script->addl(script->buildin_getelementofarray_ref); - script->addc(C_ARG); - script->addl(l); - - p = script->parse_subexpr(p + 1, -1); - p = script->skip_space(p); - if (*p != ']') - disp_error_message("parse_simpleexpr: unmatched ']'", p); - ++p; - script->addc(C_FUNC); - } else { - script->addl(l); - } - - return p; } /*========================================== @@ -5193,7 +5200,7 @@ void script_parser_clean_leftovers(void) script->syntax.strings = NULL; } - VECTOR_CLEAR(script->parse_simpleexpr_str); + VECTOR_CLEAR(script->parse_simpleexpr_strbuf); VECTOR_CLEAR(script->lang_export_line_buf); VECTOR_CLEAR(script->lang_export_escaped_buf); } @@ -5216,7 +5223,7 @@ void do_init_script(bool minimal) { script->parse_cleanup_timer_id = INVALID_TIMER; VECTOR_INIT(script->lang_export_line_buf); VECTOR_INIT(script->lang_export_escaped_buf); - VECTOR_INIT(script->parse_simpleexpr_str); + VECTOR_INIT(script->parse_simpleexpr_strbuf); script->st_db = idb_alloc(DB_OPT_BASE); script->userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0); @@ -21300,6 +21307,7 @@ void script_defaults(void) { script->parse_simpleexpr_number = parse_simpleexpr_number; script->parse_simpleexpr_string = parse_simpleexpr_string; script->parse_simpleexpr_name = parse_simpleexpr_name; + script->add_translatable_string = script_add_translatable_string; script->parse_expr = parse_expr; script->parse_line = parse_line; script->read_constdb = read_constdb; diff --git a/src/map/script.h b/src/map/script.h index a9a719099..30737e950 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -635,7 +635,7 @@ struct script_interface { char **languages; uint8 max_lang_id; /* */ - struct script_string_buf parse_simpleexpr_str; + struct script_string_buf parse_simpleexpr_strbuf; struct script_string_buf lang_export_line_buf; struct script_string_buf lang_export_escaped_buf; /* */ @@ -737,6 +737,7 @@ struct script_interface { const char *(*parse_simpleexpr_number) (const char *p); const char *(*parse_simpleexpr_string) (const char *p); const char *(*parse_simpleexpr_name) (const char *p); + void (*add_translatable_string) (const struct script_string_buf *string, const char *start_point); const char *(*parse_expr) (const char *p); const char *(*parse_line) (const char *p); void (*read_constdb) (void); -- cgit v1.2.3-70-g09d2 From d442d4c5beca900865c5f323486818ae9ef42d89 Mon Sep 17 00:00:00 2001 From: Haru Date: Wed, 30 Dec 2015 17:47:24 +0100 Subject: Improved the format of the exported .pot translation template Signed-off-by: Haru --- src/map/map.c | 25 ++++++++++++++++++++++++- src/map/script.c | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/map.c b/src/map/map.c index 3a7d752c3..22486b8f4 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -6010,8 +6010,31 @@ static CMDLINEARG(loadscript) static CMDLINEARG(generatetranslations) { script->lang_export_file = aStrdup("./generated_translations.pot"); - if( !(script->lang_export_fp = fopen(script->lang_export_file,"wb")) ) { + if (!(script->lang_export_fp = fopen(script->lang_export_file,"wb"))) { ShowError("export-dialog: failed to open '%s' for writing\n",script->lang_export_file); + } else { + time_t t = time(NULL); + struct tm *lt = localtime(&t); + int year = lt->tm_year+1900; + fprintf(script->lang_export_fp, + "# This file is part of Hercules.\n" + "# http://herc.ws - http://github.com/HerculesWS/Hercules\n" + "#\n" + "# Copyright (C) 2013-%d Hercules Dev Team\n" + "#\n" + "# Hercules is free software: you can redistribute it and/or modify\n" + "# it under the terms of the GNU General Public License as published by\n" + "# the Free Software Foundation, either version 3 of the License, or\n" + "# (at your option) any later version.\n" + "#\n" + "# This program is distributed in the hope that it will be useful,\n" + "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "# GNU General Public License for more details.\n" + "#\n" + "# You should have received a copy of the GNU General Public License\n" + "# along with this program. If not, see .\n", + year); } core->runflag = CORE_ST_STOP; return true; diff --git a/src/map/script.c b/src/map/script.c index 5b179dea1..1f2f51d13 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1411,7 +1411,7 @@ void script_add_translatable_string(const struct script_string_buf *string, cons "\""); VECTOR_PUSH(script->lang_export_escaped_buf, '\0'); - fprintf(script->lang_export_fp, "#: %s\n" + fprintf(script->lang_export_fp, "\n#: %s\n" "# %s\n" "msgctxt \"%s\"\n" "msgid \"%s\"\n" -- cgit v1.2.3-70-g09d2 From 6ff6b99d6665a387d83018f39dbf88f150338711 Mon Sep 17 00:00:00 2001 From: Haru Date: Tue, 17 May 2016 01:19:35 +0200 Subject: Moved translations template generator to a plugin Signed-off-by: Haru --- src/map/atcommand.c | 16 --- src/map/map.c | 40 ------- src/map/npc.c | 6 - src/map/script.c | 77 ------------ src/map/script.h | 8 +- src/plugins/generate-translations.c | 231 ++++++++++++++++++++++++++++++++++++ 6 files changed, 232 insertions(+), 146 deletions(-) create mode 100644 src/plugins/generate-translations.c (limited to 'src/map/script.c') diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 841cf855d..094e64e2a 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -132,7 +132,6 @@ bool msg_config_read(const char *cfg_name, bool allow_override) { int msg_number; char line[1024], w1[1024], w2[1024]; FILE *fp; - static int called = 1; nullpo_retr(false, cfg_name); if ((fp = fopen(cfg_name, "r")) == NULL) { @@ -170,21 +169,6 @@ bool msg_config_read(const char *cfg_name, bool allow_override) { } fclose(fp); - if( ++called == 1 ) { //Original - if( script->lang_export_fp ) { - int i; - for(i = 0; i < MAX_MSG;i++) { - if( atcommand->msg_table[0][i] != NULL ) { - fprintf(script->lang_export_fp, "msgctxt \"messages.conf\"\n" - "msgid \"%s\"\n" - "msgstr \"\"\n", - atcommand->msg_table[0][i] - ); - } - } - } - } - return true; } diff --git a/src/map/map.c b/src/map/map.c index 22486b8f4..779f8d601 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -6001,45 +6001,6 @@ static CMDLINEARG(loadscript) return true; } -/** - * --generate-translations - * - * Creates "./generated_translations.pot" - * @see cmdline->exec - **/ -static CMDLINEARG(generatetranslations) { - script->lang_export_file = aStrdup("./generated_translations.pot"); - - if (!(script->lang_export_fp = fopen(script->lang_export_file,"wb"))) { - ShowError("export-dialog: failed to open '%s' for writing\n",script->lang_export_file); - } else { - time_t t = time(NULL); - struct tm *lt = localtime(&t); - int year = lt->tm_year+1900; - fprintf(script->lang_export_fp, - "# This file is part of Hercules.\n" - "# http://herc.ws - http://github.com/HerculesWS/Hercules\n" - "#\n" - "# Copyright (C) 2013-%d Hercules Dev Team\n" - "#\n" - "# Hercules is free software: you can redistribute it and/or modify\n" - "# it under the terms of the GNU General Public License as published by\n" - "# the Free Software Foundation, either version 3 of the License, or\n" - "# (at your option) any later version.\n" - "#\n" - "# This program is distributed in the hope that it will be useful,\n" - "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "# GNU General Public License for more details.\n" - "#\n" - "# You should have received a copy of the GNU General Public License\n" - "# along with this program. If not, see .\n", - year); - } - core->runflag = CORE_ST_STOP; - return true; -} - /** * Defines the local command line arguments */ @@ -6056,7 +6017,6 @@ void cmdline_args_init_local(void) CMDLINEARG_DEF2(log-config, logconfig, "Alternative logging configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); CMDLINEARG_DEF2(script-check, scriptcheck, "Doesn't run the server, only tests the scripts passed through --load-script.", CMDLINE_OPT_SILENT); CMDLINEARG_DEF2(load-script, loadscript, "Loads an additional script (can be repeated).", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); - CMDLINEARG_DEF2(generate-translations, generatetranslations, "Creates './generated_translations.pot' file with all translateable strings from scripts, server terminates afterwards.", CMDLINE_OPT_NORMAL); } int do_init(int argc, char *argv[]) diff --git a/src/map/npc.c b/src/map/npc.c index b49e56d20..945a84957 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -5002,12 +5002,6 @@ int do_init_npc(bool minimal) { timer->add_func_list(npc->timerevent,"npc_timerevent"); } - if( script->lang_export_fp ) { - ShowInfo("Lang exported to '%s'\n",script->lang_export_file); - fclose(script->lang_export_fp); - script->lang_export_fp = NULL; - } - // Init dummy NPC CREATE(npc->fake_nd, struct npc_data, 1); npc->fake_nd->bl.m = -1; diff --git a/src/map/script.c b/src/map/script.c index 1f2f51d13..e4c973045 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1331,7 +1331,6 @@ const char *parse_simpleexpr_name(const char *p) void script_add_translatable_string(const struct script_string_buf *string, const char *start_point) { struct string_translation *st = NULL; - bool duplicate = true; if (script->syntax.translation_db == NULL || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(*string))) == NULL) { @@ -1363,67 +1362,6 @@ void script_add_translatable_string(const struct script_string_buf *string, cons st_cursor += sizeof(uint8); // FIXME: What are we skipping here? } } - - /* When exporting we don't know what is a translation and what isn't */ - if (script->lang_export_fp != NULL && VECTOR_LENGTH(*string) > 1) { - // The length of script->parse_simpleexpr_strbuf will always be at least 1 because of the '\0' - if (script->syntax.strings == NULL) { - script->syntax.strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); - } - - if (!strdb_exists(script->syntax.strings, VECTOR_DATA(*string))) { - strdb_put(script->syntax.strings, VECTOR_DATA(*string), NULL); - duplicate = false; - } - } - - if (script->lang_export_fp != NULL && !duplicate && - ( ( ( script->syntax.last_func == script->buildin_mes_offset || - script->syntax.last_func == script->buildin_select_offset ) - ) || script->syntax.lang_macro_active ) ) { - const char *line_start = start_point; - const char *line_end = start_point; - int line_length; - - while( line_start > script->parser_current_src ) { - if( *line_start != '\n' ) - line_start--; - else - break; - } - - while( *line_end != '\n' && *line_end != '\0' ) - line_end++; - - line_length = (int)(line_end - line_start); - if( line_length > 0 ) { - VECTOR_ENSURE(script->lang_export_line_buf, line_length + 1, 512); - VECTOR_PUSHARRAY(script->lang_export_line_buf, line_start, line_length); - VECTOR_PUSH(script->lang_export_line_buf, '\0'); - - normalize_name(VECTOR_DATA(script->lang_export_line_buf), "\r\n\t "); // [!] Note: VECTOR_LENGTH() will lie. - } - - VECTOR_ENSURE(script->lang_export_escaped_buf, 4*VECTOR_LENGTH(*string)+1, 1); - VECTOR_LENGTH(script->lang_export_escaped_buf) = (int)sv->escape_c(VECTOR_DATA(script->lang_export_escaped_buf), - VECTOR_DATA(*string), - VECTOR_LENGTH(*string)-1, /* exclude null terminator */ - "\""); - VECTOR_PUSH(script->lang_export_escaped_buf, '\0'); - - fprintf(script->lang_export_fp, "\n#: %s\n" - "# %s\n" - "msgctxt \"%s\"\n" - "msgid \"%s\"\n" - "msgstr \"\"\n", - script->parser_current_file ? script->parser_current_file : "Unknown File", - VECTOR_DATA(script->lang_export_line_buf), - script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", - VECTOR_DATA(script->lang_export_escaped_buf) - ); - VECTOR_TRUNCATE(script->lang_export_line_buf); - VECTOR_TRUNCATE(script->lang_export_escaped_buf); - } } /*========================================== @@ -2564,9 +2502,6 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->parse_cleanup_timer_id = timer->add(timer->gettick() + 10, script->parse_cleanup_timer, 0, 0); } - if( script->syntax.strings ) /* used only when generating translation file */ - db_destroy(script->syntax.strings); - memset(&script->syntax,0,sizeof(script->syntax)); script->syntax.last_func = -1;/* as valid values are >= 0 */ if( script->parser_current_npc_name ) { @@ -4875,9 +4810,6 @@ void do_final_script(void) script->clear_translations(false); script->parser_clean_leftovers(); - - if( script->lang_export_file ) - aFree(script->lang_export_file); } /** @@ -5195,14 +5127,7 @@ void script_parser_clean_leftovers(void) script->translation_db = NULL; } - if( script->syntax.strings ) { /* used only when generating translation file */ - db_destroy(script->syntax.strings); - script->syntax.strings = NULL; - } - VECTOR_CLEAR(script->parse_simpleexpr_strbuf); - VECTOR_CLEAR(script->lang_export_line_buf); - VECTOR_CLEAR(script->lang_export_escaped_buf); } /** @@ -5221,8 +5146,6 @@ int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) { *------------------------------------------*/ void do_init_script(bool minimal) { script->parse_cleanup_timer_id = INVALID_TIMER; - VECTOR_INIT(script->lang_export_line_buf); - VECTOR_INIT(script->lang_export_escaped_buf); VECTOR_INIT(script->parse_simpleexpr_strbuf); script->st_db = idb_alloc(DB_OPT_BASE); diff --git a/src/map/script.h b/src/map/script.h index 30737e950..133c205a7 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -502,8 +502,7 @@ struct script_syntax_data { int index; // Number of the syntax used in the script int last_func; // buildin index of the last parsed function unsigned int nested_call; //Dont really know what to call this - bool lang_macro_active; - struct DBMap *strings; // string map parsed (used when exporting strings only) + bool lang_macro_active; // Used to generate translation strings struct DBMap *translation_db; //non-null if this npc has any translated strings to be linked }; @@ -619,9 +618,6 @@ struct script_interface { /* */ unsigned int *generic_ui_array; unsigned int generic_ui_array_size; - /* Set during startup when attempting to export the lang, unset after server initialization is over */ - FILE *lang_export_fp; - char *lang_export_file;/* for lang_export_fp */ /* set and unset on npc_parse_script */ const char *parser_current_npc_name; /* */ @@ -636,8 +632,6 @@ struct script_interface { uint8 max_lang_id; /* */ struct script_string_buf parse_simpleexpr_strbuf; - struct script_string_buf lang_export_line_buf; - struct script_string_buf lang_export_escaped_buf; /* */ int parse_cleanup_timer_id; /* */ diff --git a/src/plugins/generate-translations.c b/src/plugins/generate-translations.c new file mode 100644 index 000000000..daa3349fa --- /dev/null +++ b/src/plugins/generate-translations.c @@ -0,0 +1,231 @@ +/** + * This file is part of Hercules. + * http://herc.ws - http://github.com/HerculesWS/Hercules + * + * Copyright (C) 2016 Hercules Dev Team + * + * Hercules is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "config/core.h" + +#include "common/hercules.h" +#include "common/cbasetypes.h" +#include "common/memmgr.h" +#include "common/showmsg.h" +#include "common/strlib.h" +#include "map/atcommand.h" +#include "map/map.h" +#include "map/script.h" + +#include "plugins/HPMHooking.h" +#include "common/HPMDataCheck.h" + +#include +#include + +HPExport struct hplugin_info pinfo = { + "generate-translations", // Plugin name + SERVER_TYPE_MAP, // Which server types this plugin works with? + "0.1", // Plugin version + HPM_VERSION, // HPM Version (don't change, macro is automatically updated) +}; + +struct DBMap *translatable_strings; // string map parsed (used when exporting strings only) +/* Set during startup when attempting to export the lang, unset after server initialization is over */ +FILE *lang_export_fp; +char *lang_export_file;/* for lang_export_fp */ +struct script_string_buf lang_export_line_buf; +struct script_string_buf lang_export_escaped_buf; + +/// Whether the translations template generator will automatically run. +bool generating_translations = false; + +/** + * --generate-translations + * + * Creates "./generated_translations.pot" + * @see cmdline->exec + */ +CMDLINEARG(generatetranslations) +{ + lang_export_file = aStrdup("./generated_translations.pot"); + + if (!(lang_export_fp = fopen(lang_export_file, "wb"))) { + ShowError("export-dialog: failed to open '%s' for writing\n", lang_export_file); + } else { + time_t t = time(NULL); + struct tm *lt = localtime(&t); + int year = lt->tm_year+1900; + fprintf(lang_export_fp, + "# This file is part of Hercules.\n" + "# http://herc.ws - http://github.com/HerculesWS/Hercules\n" + "#\n" + "# Copyright (C) 2013-%d Hercules Dev Team\n" + "#\n" + "# Hercules is free software: you can redistribute it and/or modify\n" + "# it under the terms of the GNU General Public License as published by\n" + "# the Free Software Foundation, either version 3 of the License, or\n" + "# (at your option) any later version.\n" + "#\n" + "# This program is distributed in the hope that it will be useful,\n" + "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "# GNU General Public License for more details.\n" + "#\n" + "# You should have received a copy of the GNU General Public License\n" + "# along with this program. If not, see .\n", + year); + } + generating_translations = true; + return true; +} + +void script_add_translatable_string_posthook(const struct script_string_buf *string, const char *start_point) +{ + bool duplicate = true; + + /* When exporting we don't know what is a translation and what isn't */ + if (lang_export_fp != NULL && VECTOR_LENGTH(*string) > 1) { + // The length of *string will always be at least 1 because of the '\0' + if (translatable_strings == NULL) { + translatable_strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); + } + + if (!strdb_exists(translatable_strings, VECTOR_DATA(*string))) { + strdb_put(translatable_strings, VECTOR_DATA(*string), NULL); + duplicate = false; + } + } + + if (lang_export_fp != NULL && !duplicate && + ( ( ( script->syntax.last_func == script->buildin_mes_offset || + script->syntax.last_func == script->buildin_select_offset ) + ) || script->syntax.lang_macro_active ) ) { + const char *line_start = start_point; + const char *line_end = start_point; + int line_length; + + while( line_start > script->parser_current_src ) { + if( *line_start != '\n' ) + line_start--; + else + break; + } + + while( *line_end != '\n' && *line_end != '\0' ) + line_end++; + + line_length = (int)(line_end - line_start); + if( line_length > 0 ) { + VECTOR_ENSURE(lang_export_line_buf, line_length + 1, 512); + VECTOR_PUSHARRAY(lang_export_line_buf, line_start, line_length); + VECTOR_PUSH(lang_export_line_buf, '\0'); + + normalize_name(VECTOR_DATA(lang_export_line_buf), "\r\n\t "); // [!] Note: VECTOR_LENGTH() will lie. + } + + VECTOR_ENSURE(lang_export_escaped_buf, 4*VECTOR_LENGTH(*string)+1, 1); + VECTOR_LENGTH(lang_export_escaped_buf) = (int)sv->escape_c(VECTOR_DATA(lang_export_escaped_buf), + VECTOR_DATA(*string), + VECTOR_LENGTH(*string)-1, /* exclude null terminator */ + "\""); + VECTOR_PUSH(lang_export_escaped_buf, '\0'); + + fprintf(lang_export_fp, "\n#: %s\n" + "# %s\n" + "msgctxt \"%s\"\n" + "msgid \"%s\"\n" + "msgstr \"\"\n", + script->parser_current_file ? script->parser_current_file : "Unknown File", + VECTOR_DATA(lang_export_line_buf), + script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", + VECTOR_DATA(lang_export_escaped_buf) + ); + VECTOR_TRUNCATE(lang_export_line_buf); + VECTOR_TRUNCATE(lang_export_escaped_buf); + } +} + +struct script_code *parse_script_prehook(const char **src, const char **file, int *line, int *options, int **retval) +{ + if (translatable_strings != NULL) /* used only when generating translation file */ + db_destroy(translatable_strings); + translatable_strings = NULL; + return NULL; +} + +void script_parser_clean_leftovers_posthook(void) +{ + if (translatable_strings != NULL) { /* used only when generating translation file */ + db_destroy(translatable_strings); + translatable_strings = NULL; + } + + VECTOR_CLEAR(lang_export_line_buf); + VECTOR_CLEAR(lang_export_escaped_buf); +} + +bool msg_config_read_posthook(bool retVal, const char *cfg_name, bool allow_override) +{ + static int called = 1; + + if (retVal && ++called == 1) { //Original + if (lang_export_fp != NULL) { + int i; + for (i = 0; i < MAX_MSG; i++) { + if (atcommand->msg_table[0][i] != NULL) { + fprintf(lang_export_fp, "msgctxt \"messages.conf\"\n" + "msgid \"%s\"\n" + "msgstr \"\"\n", + atcommand->msg_table[0][i] + ); + } + } + } + } + + return retVal; +} + +HPExport void server_preinit(void) +{ + addArg("--generate-translations", false, generatetranslations, + "Creates './generated_translations.pot' file with all translateable strings from scripts, server terminates afterwards."); + VECTOR_INIT(lang_export_line_buf); + VECTOR_INIT(lang_export_escaped_buf); + addHookPost(script, add_translatable_string, script_add_translatable_string_posthook); + addHookPre(script, parse, parse_script_prehook); + addHookPost(script, parser_clean_leftovers, script_parser_clean_leftovers_posthook); + addHookPost(atcommand, msg_read, msg_config_read_posthook); +} + +HPExport void plugin_init(void) +{ +} + +HPExport void server_online(void) +{ + if (lang_export_fp != NULL) { + ShowInfo("Lang exported to '%s'\n", lang_export_file); + fclose(lang_export_fp); + lang_export_fp = NULL; + } + core->runflag = CORE_ST_STOP; +} + +HPExport void plugin_final(void) +{ + if (lang_export_file != NULL) + aFree(lang_export_file); +} -- cgit v1.2.3-70-g09d2 From be570dd88f744efcf837a69901ad60bb1c78fffe Mon Sep 17 00:00:00 2001 From: Haru Date: Sat, 18 Jun 2016 00:45:47 +0200 Subject: Removed the uncommon (and useless) multi-argument variant of mes() Signed-off-by: Haru --- doc/script_commands.txt | 10 +--------- src/map/script.c | 15 +++------------ 2 files changed, 4 insertions(+), 21 deletions(-) (limited to 'src/map/script.c') diff --git a/doc/script_commands.txt b/doc/script_commands.txt index f9a628953..fea7b3c3b 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -1188,7 +1188,7 @@ From here on, we will have the commands sorted as followed: //===================================== --------------------------------------- -*mes ""{,""...""}; +*mes ""; This command will displays a box on the screen for the invoking character, if no such box is displayed already, and will print the string specified @@ -1220,14 +1220,6 @@ non-English characters, the color codes might get screwed if they stick to letters with no intervening space. Separating them with spaces from the letters on either side solves the problem. -To display multiple lines of message while only using a single mes; -command, use the script command in the following format: - - mes "Line 1", "Line 2", "Line 3"; - -This will display 3 different lines while only consuming a single line in -the relevant script file. - If you're using a client from 2011-10-10aRagexe.exe onwards, you can also use automatic navigation and open URLs in browser by using some HTML-like labels. For example: diff --git a/src/map/script.c b/src/map/script.c index e4c973045..d9487de3b 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -5248,19 +5248,10 @@ const char *script_getfuncname(struct script_state *st) { BUILDIN(mes) { struct map_session_data *sd = script->rid2sd(st); - if( sd == NULL ) + if (sd == NULL) return true; - if( !script_hasdata(st, 3) ) {// only a single line detected in the script - clif->scriptmes(sd, st->oid, script_getstr(st, 2)); - } else {// parse multiple lines as they exist - int i; - - for( i = 2; script_hasdata(st, i); i++ ) { - // send the message to the client - clif->scriptmes(sd, st->oid, script_getstr(st, i)); - } - } + clif->scriptmes(sd, st->oid, script_getstr(st, 2)); return true; } @@ -20354,7 +20345,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(__setr,"rv?"), // NPC interaction - BUILDIN_DEF(mes,"s*"), + BUILDIN_DEF(mes,"s"), BUILDIN_DEF(next,""), BUILDIN_DEF(close,""), BUILDIN_DEF(close2,""), -- cgit v1.2.3-70-g09d2 From d77c30e5b348a0a9f960a0c16826432c5d85548f Mon Sep 17 00:00:00 2001 From: Haru Date: Fri, 17 Jun 2016 21:52:27 +0200 Subject: Split sprintf logic out of buildin_sprintf (to be used by other commands as well) --- src/map/script.c | 448 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 234 insertions(+), 214 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index d9487de3b..40dafd2a5 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -5233,6 +5233,232 @@ const char *script_getfuncname(struct script_state *st) { return NULL; } +/** + * Writes a string to a StringBuf by combining a format string and a set of + * arguments taken from the current script state (caller script function + * arguments). + * + * @param[in] st Script state (must have at least a string at index + * 'start'). + * @param[in] start Index of the format string argument. + * @param[out] out Output string buffer (managed by the caller, must be + * already initialized) + * @retval false if an error occurs. + */ +bool script_sprintf(struct script_state *st, int start, struct StringBuf *out) +{ + const char *format = NULL; + const char *p = NULL, *np = NULL; + char *buf = NULL; + int buf_len = 0; + int lastarg = start; + int argc = script_lastdata(st) + 1; + + Assert_retr(-1, start >= 2 && start <= argc); + Assert_retr(-1, script_hasdata(st, start)); + + p = format = script_getstr(st, start); + + /* + * format-string = "" / *(text / placeholder) + * placeholder = "%%" / "%n" / std-placeholder + * std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type + * pos-parameter = number "$" + * flags = *("-" / "+" / "0" / SP) + * width = number / ("*" [pos-parameter]) + * precision = "." (number / ("*" [pos-parameter])) + * length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" + * type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A" + * number = digit-nonzero *DIGIT + * digit-nonzero = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" + */ + + while ((np = strchr(p, '%')) != NULL) { + bool flag_plus = false, flag_minus = false, flag_zero = false, flag_space = false; + bool positional_arg = false; + int width = 0, nextarg = lastarg + 1, thisarg = nextarg; + + if (p != np) { + int len = (int)(np - p + 1); + if (buf_len < len) { + RECREATE(buf, char, len); + buf_len = len; + } + safestrncpy(buf, p, len); + StrBuf->AppendStr(out, buf); + } + + p = np; + np++; + + // placeholder = "%%" ; (special case) + if (*np == '%') { + StrBuf->AppendStr(out, "%"); + p = np + 1; + continue; + } + // placeholder = "%n" ; (ignored) + if (*np == 'n') { + ShowWarning("script_sprintf: Format %%n not supported! Skipping...\n"); + script->reportsrc(st); + lastarg = nextarg; + p = np + 1; + continue; + } + + // std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type + + // pos-parameter = number "$" + if (ISDIGIT(*np) && *np != '0') { + const char *pp = np; + while (ISDIGIT(*pp)) + pp++; + if (*pp == '$') { + thisarg = atoi(np) + start; + positional_arg = true; + np = pp + 1; + } + } + + if (thisarg >= argc) { + ShowError("buildin_sprintf: Not enough arguments passed!\n"); + if (buf != NULL) + aFree(buf); + return false; + } + + // flags = *("-" / "+" / "0" / SP) + while (true) { + if (*np == '-') { + flag_minus = true; + } else if (*np == '+') { + flag_plus = true; + } else if (*np == ' ') { + flag_space = true; + } else if (*np == '0') { + flag_zero = true; + } else { + break; + } + np++; + } + + // width = number / ("*" [pos-parameter]) + if (ISDIGIT(*np)) { + width = atoi(np); + while (ISDIGIT(*np)) + np++; + } else if (*np == '*') { + bool positional_widtharg = false; + int width_arg; + np++; + // pos-parameter = number "$" + if (ISDIGIT(*np) && *np != '0') { + const char *pp = np; + while (ISDIGIT(*pp)) + pp++; + if (*pp == '$') { + width_arg = atoi(np) + start; + positional_widtharg = true; + np = pp + 1; + } + } + if (!positional_widtharg) { + width_arg = nextarg; + nextarg++; + if (!positional_arg) + thisarg++; + } + + if (width_arg >= argc || thisarg >= argc) { + ShowError("buildin_sprintf: Not enough arguments passed!\n"); + if (buf != NULL) + aFree(buf); + return false; + } + width = script_getnum(st, width_arg); + } + + // precision = "." (number / ("*" [pos-parameter])) ; (not needed/implemented) + + // length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" ; (not needed/implemented) + + // type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A" + if (buf_len < 16) { + RECREATE(buf, char, 16); + buf_len = 16; + } + { + int i = 0; + memset(buf, '\0', buf_len); + buf[i++] = '%'; + if (flag_minus) + buf[i++] = '-'; + if (flag_plus) + buf[i++] = '+'; + else if (flag_space) // ignored if '+' is specified + buf[i++] = ' '; + if (flag_zero) + buf[i++] = '0'; + if (width > 0) + safesnprintf(buf + i, buf_len - i - 1, "%d", width); + } + buf[(int)strlen(buf)] = *np; + switch (*np) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + // Piggyback printf + StrBuf->Printf(out, buf, script_getnum(st, thisarg)); + break; + case 's': + // Piggyback printf + StrBuf->Printf(out, buf, script_getstr(st, thisarg)); + break; + case 'c': + { + const char *str = script_getstr(st, thisarg); + // Piggyback printf + StrBuf->Printf(out, buf, str[0]); + } + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'p': + case 'a': + case 'A': + ShowWarning("buildin_sprintf: Format %%%c not supported! Skipping...\n", *np); + script->reportsrc(st); + lastarg = nextarg; + p = np + 1; + continue; + default: + ShowError("buildin_sprintf: Invalid format string.\n"); + if (buf != NULL) + aFree(buf); + return false; + } + lastarg = nextarg; + p = np + 1; + } + + // Append the remaining part + if (p != NULL) + StrBuf->AppendStr(out, p); + + if (buf != NULL) + aFree(buf); + + return true; +} + //----------------------------------------------------------------------------- // buildin functions // @@ -15185,223 +15411,17 @@ BUILDIN(implode) //------------------------------------------------------- BUILDIN(sprintf) { - const char *format = script_getstr(st, 2); - const char *p = NULL, *np = NULL; - StringBuf final_buf; - char *buf = NULL; - int buf_len = 0; - int lastarg = 2; - int argc = script_lastdata(st) + 1; - - StrBuf->Init(&final_buf); - - p = format; - - /* - * format-string = "" / *(text / placeholder) - * placeholder = "%%" / "%n" / std-placeholder - * std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type - * pos-parameter = number "$" - * flags = *("-" / "+" / "0" / SP) - * width = number / ("*" [pos-parameter]) - * precision = "." (number / ("*" [pos-parameter])) - * length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" - * type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A" - * number = digit-nonzero *DIGIT - * digit-nonzero = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" - */ - - while ((np = strchr(p, '%')) != NULL) { - bool flag_plus = false, flag_minus = false, flag_zero = false, flag_space = false; - bool positional_arg = false; - int width = 0, nextarg = lastarg + 1, thisarg = nextarg; - - if (p != np) { - int len = (int)(np - p + 1); - if (buf_len < len) { - RECREATE(buf, char, len); - buf_len = len; - } - safestrncpy(buf, p, len); - StrBuf->AppendStr(&final_buf, buf); - } - - p = np; - np++; - - // placeholder = "%%" ; (special case) - if (*np == '%') { - StrBuf->AppendStr(&final_buf, "%"); - p = np + 1; - continue; - } - // placeholder = "%n" ; (ignored) - if (*np == 'n') { - ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n"); - script->reportsrc(st); - lastarg = nextarg; - p = np + 1; - continue; - } - - // std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type - - // pos-parameter = number "$" - if (ISDIGIT(*np) && *np != '0') { - const char *pp = np; - while (ISDIGIT(*pp)) - pp++; - if (*pp == '$') { - thisarg = atoi(np) + 2; - positional_arg = true; - np = pp + 1; - } - } - - if (thisarg >= argc) { - ShowError("buildin_sprintf: Not enough arguments passed!\n"); - if (buf != NULL) - aFree(buf); - StrBuf->Destroy(&final_buf); - script_pushconststr(st,""); - return false; - } - - // flags = *("-" / "+" / "0" / SP) - while (true) { - if (*np == '-') { - flag_minus = true; - } else if (*np == '+') { - flag_plus = true; - } else if (*np == ' ') { - flag_space = true; - } else if (*np == '0') { - flag_zero = true; - } else { - break; - } - np++; - } - - // width = number / ("*" [pos-parameter]) - if (ISDIGIT(*np)) { - width = atoi(np); - while (ISDIGIT(*np)) - np++; - } else if (*np == '*') { - bool positional_widtharg = false; - int width_arg; - np++; - // pos-parameter = number "$" - if (ISDIGIT(*np) && *np != '0') { - const char *pp = np; - while (ISDIGIT(*pp)) - pp++; - if (*pp == '$') { - width_arg = atoi(np) + 2; - positional_widtharg = true; - np = pp + 1; - } - } - if (!positional_widtharg) { - width_arg = nextarg; - nextarg++; - if (!positional_arg) - thisarg++; - } - - if (width_arg >= argc || thisarg >= argc) { - ShowError("buildin_sprintf: Not enough arguments passed!\n"); - if (buf != NULL) - aFree(buf); - StrBuf->Destroy(&final_buf); - script_pushconststr(st,""); - return false; - } - width = script_getnum(st, width_arg); - } - - // precision = "." (number / ("*" [pos-parameter])) ; (not needed/implemented) - - // length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" ; (not needed/implemented) + struct StringBuf buf; + StrBuf->Init(&buf); - // type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A" - if (buf_len < 16) { - RECREATE(buf, char, 16); - buf_len = 16; - } - { - int i = 0; - memset(buf, '\0', buf_len); - buf[i++] = '%'; - if (flag_minus) - buf[i++] = '-'; - if (flag_plus) - buf[i++] = '+'; - else if (flag_space) // ignored if '+' is specified - buf[i++] = ' '; - if (flag_zero) - buf[i++] = '0'; - if (width > 0) - safesnprintf(buf + i, buf_len - i - 1, "%d", width); - } - buf[(int)strlen(buf)] = *np; - switch (*np) { - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'o': - // Piggyback printf - StrBuf->Printf(&final_buf, buf, script_getnum(st, thisarg)); - break; - case 's': - // Piggyback printf - StrBuf->Printf(&final_buf, buf, script_getstr(st, thisarg)); - break; - case 'c': - { - const char *str = script_getstr(st, thisarg); - // Piggyback printf - StrBuf->Printf(&final_buf, buf, str[0]); - } - break; - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'p': - case 'a': - case 'A': - ShowWarning("buildin_sprintf: Format %%%c not supported! Skipping...\n", *np); - script->reportsrc(st); - lastarg = nextarg; - p = np + 1; - continue; - default: - ShowError("buildin_sprintf: Invalid format string.\n"); - if (buf != NULL) - aFree(buf); - StrBuf->Destroy(&final_buf); - script_pushconststr(st,""); - return false; - } - lastarg = nextarg; - p = np + 1; + if (!script_sprintf(st, 2, &buf)) { + StrBuf->Destroy(&buf); + script_pushconststr(st, ""); + return false; } - // Append the remaining part - if (p != NULL) - StrBuf->AppendStr(&final_buf, p); - - script_pushstrcopy(st, StrBuf->Value(&final_buf)); - - if (buf != NULL) - aFree(buf); - StrBuf->Destroy(&final_buf); + script_pushstrcopy(st, StrBuf->Value(&buf)); + StrBuf->Destroy(&buf); return true; } -- cgit v1.2.3-70-g09d2 From 17f4709adeb4d9159359d901b1743de56348e7e4 Mon Sep 17 00:00:00 2001 From: Haru Date: Tue, 17 May 2016 15:11:00 +0200 Subject: Added _$() macro to the script engine to mark a translatable string as format string - Strings passed to sprintf should use the _$() macro instead of _(), to generate the .pot translation template with a directive to correctly handle the % sign. - Strings passed through _() are instead explicitly marked as regular (non format) strings if they contain '%'. Signed-off-by: Haru --- src/map/script.c | 11 +++++++++-- src/map/script.h | 2 ++ src/plugins/generate-translations.c | 25 +++++++++++++++++++++---- 3 files changed, 32 insertions(+), 6 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index 40dafd2a5..926f19bf0 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -810,9 +810,12 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) if (script->str_data[func].type == C_FUNC) { script->syntax.nested_call++; if (script->syntax.last_func != -1) { - if( script->str_data[func].val == script->buildin_lang_macro_offset ) { + if (script->str_data[func].val == script->buildin_lang_macro_offset) { script->syntax.lang_macro_active = true; macro = true; + } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) { + script->syntax.lang_macro_fmtstring_active = true; + macro = true; } } @@ -907,8 +910,10 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) disp_error_message("parse_callfunc: expected ')' to close argument list",p); ++p; - if( script->str_data[func].val == script->buildin_lang_macro_offset ) + if (script->str_data[func].val == script->buildin_lang_macro_offset) script->syntax.lang_macro_active = false; + else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) + script->syntax.lang_macro_fmtstring_active = false; } if (!macro) { @@ -20272,6 +20277,7 @@ bool script_add_builtin(const struct script_function *buildin, bool override) { else if( strcmp(buildin->name, "mes") == 0 ) script->buildin_mes_offset = script->buildin_count; else if( strcmp(buildin->name, "select") == 0 ) script->buildin_select_offset = script->buildin_count; else if( strcmp(buildin->name, "_") == 0 ) script->buildin_lang_macro_offset = script->buildin_count; + else if( strcmp(buildin->name, "_$") == 0 ) script->buildin_lang_macro_fmtstring_offset = script->buildin_count; offset = script->buildin_count; @@ -20877,6 +20883,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(showscript, "s?"), BUILDIN_DEF(mergeitem,""), BUILDIN_DEF(_,"s"), + BUILDIN_DEF2(_, "_$", "s"), }; int i, len = ARRAYLENGTH(BUILDIN); RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up diff --git a/src/map/script.h b/src/map/script.h index 133c205a7..7811cd64e 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -503,6 +503,7 @@ struct script_syntax_data { int last_func; // buildin index of the last parsed function unsigned int nested_call; //Dont really know what to call this bool lang_macro_active; // Used to generate translation strings + bool lang_macro_fmtstring_active; // Used to generate translation strings struct DBMap *translation_db; //non-null if this npc has any translated strings to be linked }; @@ -624,6 +625,7 @@ struct script_interface { int buildin_mes_offset; int buildin_select_offset; int buildin_lang_macro_offset; + int buildin_lang_macro_fmtstring_offset; /* */ struct DBMap *translation_db;/* npc_name => DBMap (strings) */ VECTOR_DECL(uint8 *) translation_buf; diff --git a/src/plugins/generate-translations.c b/src/plugins/generate-translations.c index daa3349fa..7928fec9c 100644 --- a/src/plugins/generate-translations.c +++ b/src/plugins/generate-translations.c @@ -94,6 +94,8 @@ CMDLINEARG(generatetranslations) void script_add_translatable_string_posthook(const struct script_string_buf *string, const char *start_point) { bool duplicate = true; + bool is_translatable_string = false; + bool is_translatable_fmtstring = false; /* When exporting we don't know what is a translation and what isn't */ if (lang_export_fp != NULL && VECTOR_LENGTH(*string) > 1) { @@ -108,13 +110,26 @@ void script_add_translatable_string_posthook(const struct script_string_buf *str } } - if (lang_export_fp != NULL && !duplicate && - ( ( ( script->syntax.last_func == script->buildin_mes_offset || - script->syntax.last_func == script->buildin_select_offset ) - ) || script->syntax.lang_macro_active ) ) { + if (!duplicate) { + if (script->syntax.last_func == script->buildin_mes_offset + || script->syntax.last_func == script->buildin_select_offset + || script->syntax.lang_macro_active + ) { + is_translatable_string = true; + } else if (script->syntax.lang_macro_fmtstring_active) { + is_translatable_fmtstring = true; + } + } + + if (lang_export_fp != NULL && (is_translatable_string || is_translatable_fmtstring)) { const char *line_start = start_point; const char *line_end = start_point; int line_length; + bool has_percent_sign = false; + + if (!is_translatable_fmtstring && strchr(VECTOR_DATA(*string), '%') != NULL) { + has_percent_sign = true; + } while( line_start > script->parser_current_src ) { if( *line_start != '\n' ) @@ -145,11 +160,13 @@ void script_add_translatable_string_posthook(const struct script_string_buf *str fprintf(lang_export_fp, "\n#: %s\n" "# %s\n" "msgctxt \"%s\"\n" + "%s" "msgid \"%s\"\n" "msgstr \"\"\n", script->parser_current_file ? script->parser_current_file : "Unknown File", VECTOR_DATA(lang_export_line_buf), script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", + is_translatable_fmtstring ? "#, c-format\n" : (has_percent_sign ? "#, no-c-format\n" : ""), VECTOR_DATA(lang_export_escaped_buf) ); VECTOR_TRUNCATE(lang_export_line_buf); -- cgit v1.2.3-70-g09d2 From 9164ea7ec938958245e1ceb75035f90500c8a7c8 Mon Sep 17 00:00:00 2001 From: Haru Date: Sat, 18 Jun 2016 00:19:39 +0200 Subject: Added mesf() command (combination of mes() and sprintf()) Signed-off-by: Haru --- doc/script_commands.txt | 17 +++++++++++++++++ src/map/script.c | 33 +++++++++++++++++++++++++++++++++ src/map/script.h | 1 + src/plugins/generate-translations.c | 4 +++- 4 files changed, 54 insertions(+), 1 deletion(-) (limited to 'src/map/script.c') diff --git a/doc/script_commands.txt b/doc/script_commands.txt index fea7b3c3b..f0758de71 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -1235,6 +1235,23 @@ Clicking Google will open the browser and point to Google website. --------------------------------------- +*mesf(""{,{, {, ...}}}) + +This command will display a box on the screen for the invoking character, +if no such box is displayed already, and will print the string specified +into that box, after applying the same format-string replacements as sprintf(). + +Example: + + mesf("Hello, I'm %s, a level %d %s", strcharinfo(PC_NAME), BaseLevel, jobname(Class)); + // is equivalent to: + mes(sprintf("Hello, I'm %s, a level %d %s", strcharinfo(PC_NAME), BaseLevel, jobname(Class))); + +This command is a combination of mes() and sprintf(). See their documentation +for more details. + +--------------------------------------- + *next; This command will display a 'next' button in the message window for the diff --git a/src/map/script.c b/src/map/script.c index 926f19bf0..a6a9a9cf9 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -5487,6 +5487,37 @@ BUILDIN(mes) return true; } +/** + * Appends a message to the npc dialog, applying format string conversions (see + * sprintf). + * + * If a dialog doesn't exist yet, one is created. + * + * @code + * mes ""; + * @endcode + */ +BUILDIN(mesf) +{ + struct map_session_data *sd = script->rid2sd(st); + struct StringBuf buf; + + if (sd == NULL) + return true; + + StrBuf->Init(&buf); + + if (!script_sprintf(st, 2, &buf)) { + StrBuf->Destroy(&buf); + return false; + } + + clif->scriptmes(sd, st->oid, StrBuf->Value(&buf)); + StrBuf->Destroy(&buf); + + return true; +} + /// Displays the button 'next' in the npc dialog. /// The dialog text is cleared and the script continues when the button is pressed. /// @@ -20275,6 +20306,7 @@ bool script_add_builtin(const struct script_function *buildin, bool override) { else if( strcmp(buildin->name, "callfunc") == 0 ) script->buildin_callfunc_ref = n; else if( strcmp(buildin->name, "getelementofarray") == 0 ) script->buildin_getelementofarray_ref = n; else if( strcmp(buildin->name, "mes") == 0 ) script->buildin_mes_offset = script->buildin_count; + else if( strcmp(buildin->name, "mesf") == 0 ) script->buildin_mesf_offset = script->buildin_count; else if( strcmp(buildin->name, "select") == 0 ) script->buildin_select_offset = script->buildin_count; else if( strcmp(buildin->name, "_") == 0 ) script->buildin_lang_macro_offset = script->buildin_count; else if( strcmp(buildin->name, "_$") == 0 ) script->buildin_lang_macro_fmtstring_offset = script->buildin_count; @@ -20372,6 +20404,7 @@ void script_parse_builtin(void) { // NPC interaction BUILDIN_DEF(mes,"s"), + BUILDIN_DEF(mesf,"s*"), BUILDIN_DEF(next,""), BUILDIN_DEF(close,""), BUILDIN_DEF(close2,""), diff --git a/src/map/script.h b/src/map/script.h index 7811cd64e..61c6a4583 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -623,6 +623,7 @@ struct script_interface { const char *parser_current_npc_name; /* */ int buildin_mes_offset; + int buildin_mesf_offset; int buildin_select_offset; int buildin_lang_macro_offset; int buildin_lang_macro_fmtstring_offset; diff --git a/src/plugins/generate-translations.c b/src/plugins/generate-translations.c index 7928fec9c..0f69c69a1 100644 --- a/src/plugins/generate-translations.c +++ b/src/plugins/generate-translations.c @@ -116,7 +116,9 @@ void script_add_translatable_string_posthook(const struct script_string_buf *str || script->syntax.lang_macro_active ) { is_translatable_string = true; - } else if (script->syntax.lang_macro_fmtstring_active) { + } else if (script->syntax.last_func == script->buildin_mesf_offset + || script->syntax.lang_macro_fmtstring_active + ) { is_translatable_fmtstring = true; } } -- cgit v1.2.3-70-g09d2 From a8590a0b235ce48320d428a184181c1e93267cd6 Mon Sep 17 00:00:00 2001 From: Haru Date: Sat, 25 Jun 2016 17:28:21 +0200 Subject: Corrected an issue that prevented changing default languages The script->get_translation_file_name() is more robust (and actually works) now. Signed-off-by: Haru --- src/map/script.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index a6a9a9cf9..64966f987 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -4910,28 +4910,42 @@ void script_load_translations(void) { } /** + * Generates a language name from a translation filename. * - **/ + * @param file The filename. + * @return The corresponding translation name. + */ const char *script_get_translation_file_name(const char *file) { - int i, len = (int)strlen(file), last_bar = -1, last_dot = -1; + const char *basename = NULL, *last_dot = NULL; + + nullpo_retr("Unknown", file); - for(i = 0; i < len; i++) { - if( file[i] == '/' || file[i] == '\\' ) - last_bar = i; - else if ( file[i] == '.' ) - last_dot = i; + basename = strrchr(file, '/');; +#ifdef WIN32 + { + const char *basename_windows = strrchr(file, '\\'); + if (basename_windows > basename) + basename = basename_windows; } +#endif // WIN32 + if (basename == NULL) + basename = file; + else + basename++; // Skip slash + Assert_retr("Unknown", *basename != '\0'); - if( last_bar != -1 || last_dot != -1 ) { + last_dot = strrchr(basename, '.'); + if (last_dot != NULL) { static char file_name[200]; - if( last_bar != -1 && last_dot < last_bar ) - last_dot = -1; - safestrncpy(file_name, file+(last_bar >= 0 ? last_bar+1 : 0), ( last_dot >= 0 ? ( last_bar >= 0 ? last_dot - last_bar : last_dot ) : sizeof(file_name) )); + if (last_dot == basename) + return basename + 1; + + safestrncpy(file_name, basename, last_dot - basename + 1); return file_name; } - return file; + return basename; } /** -- cgit v1.2.3-70-g09d2