//////////////////////////////////////////////////////////////////////////////// // Convert a quantity in seconds to a more readable format. std::string formatBytes (size_t bytes) { char formatted[24]; if (bytes >= 995000000) sprintf (formatted, "%.1f GiB", (bytes / 1000000000.0)); else if (bytes >= 995000) sprintf (formatted, "%.1f MiB", (bytes / 1000000.0)); else if (bytes >= 995) sprintf (formatted, "%.1f KiB", (bytes / 1000.0)); else sprintf (formatted, "%d B", (int)bytes ); return commify (formatted); }
//////////////////////////////////////////////////////////////////////////////// // Convert a quantity in seconds to a more readable format. std::string formatBytes (size_t bytes) { char formatted[24]; if (bytes >= 995000000) sprintf (formatted, "%.1f %s", (bytes / 1000000000.0), STRING_UTIL_GIBIBYTES); else if (bytes >= 995000) sprintf (formatted, "%.1f %s", (bytes / 1000000.0), STRING_UTIL_MEBIBYTES); else if (bytes >= 995) sprintf (formatted, "%.1f %s", (bytes / 1000.0), STRING_UTIL_KIBIBYTES); else sprintf (formatted, "%d %s", (int)bytes, STRING_UTIL_BYTES); return commify (formatted); }
void draw_selected_module_cost () { Rect* b = &scr.select_message; char s[100]; char coststr[20]; char bldzstr[20]; selected_module_cost = get_type_cost (selected_module_type); commify(coststr,20,selected_module_cost); commify(bldzstr,20,main_groups[selected_module_group].bul_cost); if (selected_module_group == GROUP_BARE) snprintf (s, 100, _("Bulldoze - cost varies")); else snprintf (s, 100, _("%s %s Bulldoze %s"), _(main_groups[selected_module_group].name), coststr, bldzstr); Fgl_fillbox (b->x, b->y, 42 * 8, 8, TEXT_BG_COLOUR); Fgl_write (b->x, b->y, s); }
static int c_vlendecl(Generator* generator, Bytebuffer* codebuf, Symbol* tsym, int uid, size_t count, ...) { /* Build a bytebuffer to capture the vlen decl */ List* declstack = (List*)generator->state; Bytebuffer* decl = bbNew(); Bytebuffer* vlenbuf; va_list ap; vastart(ap,count); vlenbuf = va_arg(ap, Bytebuffer*); va_end(ap); bbprintf0(decl,"static const %s vlen_%u[] = {", ctypename(tsym->typ.basetype), uid); commify(vlenbuf); bbCatbuf(decl,vlenbuf); bbCat(decl,"} ;"); listpush(declstack,(void*)decl); /* Now generate the reference to buffer */ bbprintf(codebuf,"{%u,(void*)vlen_%u}",count,uid); return 1; }
/* * Return java type name for netCDF type, given type code. */ static void genjstd_defineattribute(Symbol* asym) { unsigned long len; Datalist* list; Bytebuffer* code = NULL; /* capture other decls*/ list = asym->data; if(list == NULL) len = 0; else len = asym->att.count; nprintf(stmt,sizeof(stmt),"/* attribute: %s */",asym->name); jlined(1,stmt); code = bbNew(); genjstd_attrdata(asym,code); /* Handle primitives separately */ if(asym->typ.basetype->typ.typecode != NC_CHAR) commify(code); genjstd_primattribute(asym, code, len); bbFree(code); }
// // M_LoadCVARs // void M_LoadCVARs(char *filename) { int bindcount = 0; int cvarcount = 0; int statcount = 0; // read the file in, overriding any set defaults FILE *file = fopen(filename, "r"); if (!file) { M_CheckCVARs(); M_SaveCVARs(); C_Output("Created <b>%s</b>.", filename); cvarsloaded = true; return; } for (int i = 0; i < MAXALIASES; i++) { aliases[i].name[0] = '\0'; aliases[i].string[0] = '\0'; } // Clear all default controls before reading them from config file if (!togglingvanilla && M_StringEndsWith(filename, PACKAGE_CONFIG)) { for (int i = 0; *actions[i].action; i++) { if (actions[i].keyboard1) *(int *)actions[i].keyboard1 = 0; if (actions[i].keyboard2) *(int *)actions[i].keyboard2 = 0; if (actions[i].mouse1) *(int *)actions[i].mouse1 = -1; if (actions[i].gamepad1) *(int *)actions[i].gamepad1 = 0; if (actions[i].gamepad2) *(int *)actions[i].gamepad2 = 0; } for (int i = 0; i < NUMKEYS; i++) keyactionlist[i][0] = '\0'; } while (!feof(file)) { char cvar[64] = ""; char value[256] = ""; if (fscanf(file, "%63s %255[^\n]\n", cvar, value) != 2) continue; if (cvar[0] == ';') continue; if (M_StringCompare(cvar, "bind")) { bind_cmd_func2("bind", value); bindcount++; continue; } else if (M_StringCompare(cvar, "alias")) { if (!togglingvanilla) alias_cmd_func2("alias", value); continue; } // Strip off trailing non-printable characters (\r characters from DOS text files) while (*value && !isprint((unsigned char)value[strlen(value) - 1])) value[strlen(value) - 1] = '\0'; if (togglingvanilla) { char *value_free = uncommify(value); C_ValidateInput(M_StringJoin(cvar, " ", value_free, NULL)); free(value_free); continue; } // Find the setting in the list for (int i = 0; i < arrlen(cvars); i++) { char *s; if (!M_StringCompare(cvar, cvars[i].name)) continue; // not this one if (M_StringStartsWith(cvar, "stat_")) statcount++; else cvarcount++; // parameter found switch (cvars[i].type) { case DEFAULT_STRING: s = M_StringDuplicate(value + 1); s[strlen(s) - 1] = '\0'; *(char **)cvars[i].location = s; break; case DEFAULT_INT: { char *value_free = uncommify(value); M_StringCopy(value, value_free, sizeof(value)); *(int *)cvars[i].location = ParseIntParameter(value, cvars[i].valuealiastype); free(value_free); break; } case DEFAULT_INT_UNSIGNED: { char *value_free = uncommify(value); M_StringCopy(value, value_free, sizeof(value)); sscanf(value, "%10u", (unsigned int *)cvars[i].location); free(value_free); break; } case DEFAULT_INT_PERCENT: { char *value_free = uncommify(value); M_StringCopy(value, value_free, sizeof(value)); s = M_StringDuplicate(value); if (*s && s[strlen(s) - 1] == '%') s[strlen(s) - 1] = '\0'; *(int *)cvars[i].location = ParseIntParameter(s, cvars[i].valuealiastype); free(value_free); break; } case DEFAULT_FLOAT: { char *value_free = uncommify(value); M_StringCopy(value, value_free, sizeof(value)); *(float *)cvars[i].location = ParseFloatParameter(value, cvars[i].valuealiastype); free(value_free); break; } case DEFAULT_FLOAT_PERCENT: { char *value_free = uncommify(value); M_StringCopy(value, value_free, sizeof(value)); s = M_StringDuplicate(value); if (*s && s[strlen(s) - 1] == '%') s[strlen(s) - 1] = '\0'; *(float *)cvars[i].location = ParseFloatParameter(s, cvars[i].valuealiastype); free(value_free); break; } case DEFAULT_OTHER: *(char **)cvars[i].location = M_StringDuplicate(value); break; } // finish break; } } fclose(file); if (!togglingvanilla) { char *cvarcount_str = commify(cvarcount); char *statcount_str = commify(statcount); char *bindcount_str = commify(bindcount); C_Output("Loaded %s CVARs and %s player stats from <b>%s</b>.", cvarcount_str, statcount_str, filename); C_Output("Bound %s actions to the keyboard, mouse and gamepad.", bindcount_str); M_CheckCVARs(); cvarsloaded = true; free(cvarcount_str); free(statcount_str); free(bindcount_str); } }
// // M_SaveCVARs // void M_SaveCVARs(void) { int numaliases = 0; int p; FILE *file; if (!cvarsloaded || vanilla || togglingvanilla) return; p = M_CheckParmWithArgs("-config", 1, 1); if (!(file = fopen((p ? myargv[p + 1] : packageconfig), "w"))) return; // can't write the file, but don't complain if (returntowidescreen) vid_widescreen = true; for (int i = 0; i < arrlen(cvars); i++) { if (!*cvars[i].name) { fputs("\n", file); continue; } if (cvars[i].name[0] == ';') { fputs(cvars[i].name, file); continue; } // Print the name fprintf(file, "%s ", cvars[i].name); // Print the value switch (cvars[i].type) { case DEFAULT_INT: { dboolean flag = false; int v = *(int *)cvars[i].location; for (int j = 0; *valuealiases[j].text; j++) if (v == valuealiases[j].value && cvars[i].valuealiastype == valuealiases[j].type) { fputs(valuealiases[j].text, file); flag = true; break; } if (!flag) { char *v_str = commify(v); fputs(v_str, file); free(v_str); } break; } case DEFAULT_INT_UNSIGNED: { char *cvars_location_free = commify(*(unsigned int *)cvars[i].location); fputs(cvars_location_free, file); free(cvars_location_free); } break; case DEFAULT_INT_PERCENT: { dboolean flag = false; int v = *(int *)cvars[i].location; for (int j = 0; *valuealiases[j].text; j++) if (v == valuealiases[j].value && cvars[i].valuealiastype == valuealiases[j].type) { fputs(valuealiases[j].text, file); flag = true; break; } if (!flag) { char *v_str = commify(v); fprintf(file, "%s%%", v_str); free(v_str); } break; } case DEFAULT_FLOAT: { dboolean flag = false; float v = *(float *)cvars[i].location; for (int j = 0; *valuealiases[j].text; j++) if (v == valuealiases[j].value && cvars[i].valuealiastype == valuealiases[j].type) { fputs(valuealiases[j].text, file); flag = true; break; } if (!flag) { static char buf[128]; int len; M_snprintf(buf, sizeof(buf), "%.2f", v); len = (int)strlen(buf); if (len >= 2 && buf[len - 1] == '0' && buf[len - 2] == '0') buf[len - 1] = '\0'; fputs(buf, file); } break; } case DEFAULT_FLOAT_PERCENT: { dboolean flag = false; float v = *(float *)cvars[i].location; for (int j = 0; *valuealiases[j].text; j++) if (v == valuealiases[j].value && cvars[i].valuealiastype == valuealiases[j].type) { fputs(valuealiases[j].text, file); flag = true; break; } if (!flag) { char *v_str = striptrailingzero(v, 1); fprintf(file, "%s%%", v_str); free(v_str); } break; } case DEFAULT_STRING: if (M_StringCompare(*(char **)cvars[i].location, EMPTYVALUE)) fputs(*(char **)cvars[i].location, file); else fprintf(file, "%s%s%s", (M_StringCompare(cvars[i].name, "version") ? "" : "\""), *(char **)cvars[i].location, (M_StringCompare(cvars[i].name, "version") ? "" : "\"")); break; case DEFAULT_OTHER: fputs(*(char **)cvars[i].location, file); break; } fputs("\n", file); } fputs("\n; bound controls\n", file); for (int i = 0; *actions[i].action; i++) { if (actions[i].keyboard1) SaveBindByValue(file, actions[i].action, *(int *)actions[i].keyboard1, keyboardcontrol); if (actions[i].keyboard2) SaveBindByValue(file, actions[i].action, *(int *)actions[i].keyboard2, keyboardcontrol); if (actions[i].mouse1) SaveBindByValue(file, actions[i].action, *(int *)actions[i].mouse1, mousecontrol); if (actions[i].gamepad1) SaveBindByValue(file, actions[i].action, *(int *)actions[i].gamepad1, gamepadcontrol); if (actions[i].gamepad2) SaveBindByValue(file, actions[i].action, *(int *)actions[i].gamepad2, gamepadcontrol); } for (int i = 0; controls[i].type; i++) if (controls[i].type == keyboardcontrol && keyactionlist[controls[i].value][0]) SaveBind(file, controls[i].control, keyactionlist[controls[i].value]); else if (controls[i].type == mousecontrol && mouseactionlist[controls[i].value][0]) SaveBind(file, controls[i].control, mouseactionlist[controls[i].value]); for (int i = 0; i < MAXALIASES; i++) if (*aliases[i].name) numaliases++; if (numaliases) { fputs("\n; aliases\n", file); for (int i = 0; i < MAXALIASES; i++) if (*aliases[i].name) fprintf(file, "alias %s \"%s\"\n", aliases[i].name, aliases[i].string); } fclose(file); if (returntowidescreen) vid_widescreen = false; }
static void genj_writeattr(Generator* generator, Symbol* asym, Bytebuffer* code, int rank, size_t* start, size_t* count) { Symbol* basetype = asym->typ.basetype; nc_type typecode = basetype->typ.typecode; /* default assumption */ size_t len = asym->data == NULL?0:asym->data->length; codeprintf("%s/* attribute: %s */\n",indented(1),asym->name); /* Handle NC_CHAR specially */ if(typecode == NC_CHAR) { /* revise the length count */ len = bbLength(code); if(len == 0) { bbAppend(code,'\0'); len++; bbClear(code); bbCat(code,"\"\""); len++; } else jquotestring(code,'"'); bbNull(code); } else { /* not NC_CHAR*/ char* code2; commify(code); /* Convert to constant */ code2 = bbDup(code); bbClear(code); bbprintf0(stmt,"new %s[]", jarraytype(typecode)); bbCatbuf(code,stmt); bbCat(code,"{"); bbCat(code,code2); bbCat(code,"}"); efree(code2); } switch (typecode) { case NC_BYTE: case NC_SHORT: case NC_INT: case NC_FLOAT: case NC_DOUBLE: codelined(1,"{"); bbprintf0(stmt,"%sArray data = Array.factory(%s.class, new int[]{%lu}, ", indented(1), jtype(basetype->typ.typecode), len); codedump(stmt); codedump(code); codeline(");"); if(asym->att.var == NULL) { bbprintf0(stmt,"%sncfile.addGlobalAttribute(\"%s\",data);\n", indented(1),jescapifyname(asym->name)); } else { bbprintf0(stmt,"%sncfile.addVariableAttribute(\"%s\",\"%s\",data);\n", indented(1), jescapifyname(asym->att.var->name), jescapifyname(asym->name)); } codedump(stmt); codelined(1,"}"); codeflush(); break; case NC_CHAR: if(asym->att.var == NULL) { bbprintf0(stmt,"%sncfile.addGlobalAttribute(\"%s\",%s);\n", indented(1), jescapifyname(asym->name), bbContents(code)); } else { bbprintf0(stmt,"%sncfile.addVariableAttribute(\"%s\",\"%s\",%s);\n", indented(1), jescapifyname(asym->att.var->name), jescapifyname(asym->name), bbContents(code)); } codedump(stmt); codeflush(); break; default: break; } codeflush(); }
static void genj_writevar(Generator* generator, Symbol* vsym, Bytebuffer* code, int rank, size_t* start, size_t* count) { Dimset* dimset = &vsym->typ.dimset; int typecode = vsym->typ.basetype->typ.typecode; int i; codeline(""); codelined(1,"{"); /* Enclose in {...} for scoping */ if(rank == 0) { bbprintf0(stmt,"%sArray%s.D0 data = new Array%s.D0();\n", indented(1),jtypecap(typecode), jtypecap(typecode)); codedump(stmt); if(typecode == NC_CHAR) { /* Construct the data Array */ jquotestring(code,'\''); bbprintf0(stmt,"%sdata.set((char)%s);\n", indented(1),bbContents(code)); } else { commify(code); bbprintf0(stmt,"%sdata.set((%s)%s);\n", indented(1),jtype(typecode),bbContents(code)); } codedump(stmt); /* do the actual write */ bbprintf0(stmt,"%sncfile.write(\"%s\",data);\n", indented(1),jescapifyname(vsym->name)); codedump(stmt); } else { /* array */ Bytebuffer* dimbuf = bbNew(); /* Construct the dimension set*/ bbCat(dimbuf,"new int[]{"); for(i=0;i<rank;i++) { Symbol* dsym = dimset->dimsyms[i]; char tmp[32]; nprintf(tmp,sizeof(tmp),"%lu",dsym->dim.declsize); if(i>0) {bbCat(dimbuf,", ");} bbCat(dimbuf,tmp); } bbCat(dimbuf,"}"); /* Construct the data array and capture its index */ if(typecode == NC_CHAR) { jquotestring(code,'"'); bbprintf0(stmt,"%sString contents = ", indented(1)); } else { bbprintf0(stmt,"%s%s[] contents = new %s[] {", indented(1),jtype(typecode),jtype(typecode)); commify(code); } codedump(stmt); codedump(code); if(typecode != NC_CHAR) codepartial("}"); codeline(";"); bbprintf0(stmt,"%sArray%s data = new Array%s(%s);\n", indented(1), jtypecap(typecode), jtypecap(typecode), bbContents(dimbuf)); codedump(stmt); codelined(1,"IndexIterator iter = data.getIndexIterator();"); codelined(1,"int count = 0;"); codelined(1,"while(iter.hasNext())"); if(typecode == NC_CHAR) bbprintf0(stmt, "%siter.setCharNext(contents.charAt(count++));\n",indented(2)); else bbprintf0(stmt,"%siter.set%sNext(contents[count++]);\n", indented(2),jtypecap(typecode)); codedump(stmt); bbFree(dimbuf); /* Construct the origin set from the start set */ bbprintf0(stmt,"%sint[] origin = new int[]{",indented(1)); for(i=0;i<rank;i++) { bbprintf(stmt,"%s%lu",(i>0?", ":""),start[i]); } bbCat(stmt,"};\n"); codedump(stmt); /* do the actual write */ bbprintf0(stmt,"%sncfile.write(\"%s\",origin,data);\n", indented(1),jescapifyname(vsym->name)); codedump(stmt); } codelined(1,"}"); /* Enclose in {...} for scoping */ codeflush(); }
static void genjstd_definevardata(Symbol* vsym) { Dimset* dimset = &vsym->typ.dimset; Symbol* basetype = vsym->typ.basetype; int rank = dimset->ndims; int isscalar = (dimset->ndims == 0); Bytebuffer* code; nc_type typecode = basetype->typ.typecode; if(vsym->data == NULL) return; code = bbNew(); jlined(1,"{"); /* Handle special cases first*/ if(isscalar) { /* Construct the data Array */ nprintf(stmt,sizeof(stmt),"Array%s.D0 data = new Array%s.D0();", jtypecap(typecode), jtypecap(typecode)); jlined(1,stmt); /* Fill it */ genjstd_scalardata(vsym,code); if(typecode == NC_CHAR) { nprintf(stmt,sizeof(stmt),"data.set(%s.charAt(0));", bbContents(code)); } else { nprintf(stmt,sizeof(stmt),"data.set((%s)%s);", jtype(typecode),bbContents(code)); } jlined(1,stmt); } else { /* Non-scalar*/ int i; Bytebuffer* dimbuf = bbNew(); /* Store the data */ genjstd_arraydata(vsym,NULL,code); /* Construct the dimension set*/ bbCat(dimbuf,"new int[]{"); for(i=0;i<rank;i++) { Symbol* dsym = dimset->dimsyms[i]; char tmp[32]; if(i==0 && dsym->dim.size == NC_UNLIMITED) nprintf(tmp,sizeof(tmp),"%lu",dsym->dim.unlimitedsize); else nprintf(tmp,sizeof(tmp),"%lu",dsym->dim.size); if(i>0) {bbCat(dimbuf,", ");} bbCat(dimbuf,tmp); } bbCat(dimbuf,"}"); /* Construct the data array and capture its index */ if(typecode == NC_CHAR) nprintf(stmt,sizeof(stmt),"%sString contents = ", indented(1)); else nprintf(stmt,sizeof(stmt),"%s%s[] contents = new %s[] {", indented(1),jtype(typecode),jtype(typecode)); jpartial(stmt); commify(code); jprint(code); if(typecode != NC_CHAR) jpartial("}"); jline(";"); nprintf(stmt,sizeof(stmt),"Array%s data = new Array%s(%s);", jtypecap(typecode), jtypecap(typecode), bbContents(dimbuf)); jlined(1,stmt); jlined(1,"IndexIterator iter = data.getIndexIterator();"); jlined(1,"int count = 0;"); jlined(1,"while(iter.hasNext())"); if(typecode == NC_CHAR) nprintf(stmt,sizeof(stmt), "iter.setCharNext(contents.charAt(count++));"); else nprintf(stmt,sizeof(stmt),"iter.set%sNext(contents[count++]);", jtypecap(typecode)); jlined(2,stmt); bbFree(dimbuf); } /* do the actual write */ nprintf(stmt,sizeof(stmt),"ncfile.write(\"%s\",data);", jescapifyname(vsym->name)); jlined(1,stmt); bbFree(code); jlined(1,"}"); jflush(); }
int main (int argc, char** argv) { UnitTest t (264); // void wrapText (std::vector <std::string>& lines, const std::string& text, const int width, bool hyphenate) std::string text = "This is a test of the line wrapping code."; std::vector <std::string> lines; wrapText (lines, text, 10, true); t.is (lines.size (), (size_t) 5, "wrapText 'This is a test of the line wrapping code.' -> total 5 lines"); t.is (lines[0], "This is a", "wrapText line 0 -> 'This is a'"); t.is (lines[1], "test of", "wrapText line 1 -> 'test of'"); t.is (lines[2], "the line", "wrapText line 2 -> 'the line'"); t.is (lines[3], "wrapping", "wrapText line 3 -> 'wrapping'"); t.is (lines[4], "code.", "wrapText line 4 -> 'code.'"); text = "This ☺ is a test of utf8 line extraction."; lines.clear (); wrapText (lines, text, 7, true); t.is (lines.size (), (size_t) 7, "wrapText 'This ☺ is a test of utf8 line extraction.' -> total 7 lines"); t.is (lines[0], "This ☺", "wrapText line 0 -> 'This ☺'"); t.is (lines[1], "is a", "wrapText line 1 -> 'is a'"); t.is (lines[2], "test of", "wrapText line 2 -> 'test of'"); t.is (lines[3], "utf8", "wrapText line 3 -> 'utf8'"); t.is (lines[4], "line", "wrapText line 4 -> 'line'"); t.is (lines[5], "extrac-", "wrapText line 5 -> 'extrac-'"); t.is (lines[6], "tion.", "wrapText line 6 -> 'tion.'"); text = "one two three\n four"; lines.clear (); wrapText (lines, text, 13, true); t.is (lines.size (), (size_t) 2, "wrapText 'one two three\\n four' -> 2 lines"); t.is (lines[0], "one two three", "wrapText line 0 -> 'one two three'"); t.is (lines[1], " four", "wrapText line 1 -> ' four'"); // void extractLine (std::string& text, std::string& line, int length, bool hyphenate, unsigned int& offset) text = "This ☺ is a test of utf8 line extraction."; unsigned int offset = 0; std::string line; extractLine (line, text, 7, true, offset); t.is (line, "This ☺", "extractLine 7 'This ☺ is a test of utf8 line extraction.' -> 'This ☺'"); // void extractLine (std::string& text, std::string& line, int length, bool hyphenate, unsigned int& offset) text = "line 1\nlengthy second line that exceeds width"; offset = 0; extractLine (line, text, 10, true, offset); t.is (line, "line 1", "extractLine 10 'line 1\\nlengthy second line that exceeds width' -> 'line 1'"); extractLine (line, text, 10, true, offset); t.is (line, "lengthy", "extractLine 10 'lengthy second line that exceeds width' -> 'lengthy'"); extractLine (line, text, 10, true, offset); t.is (line, "second", "extractLine 10 'second line that exceeds width' -> 'second'"); extractLine (line, text, 10, true, offset); t.is (line, "line that", "extractLine 10 'line that exceeds width' -> 'line that'"); extractLine (line, text, 10, true, offset); t.is (line, "exceeds", "extractLine 10 'exceeds width' -> 'exceeds'"); extractLine (line, text, 10, true, offset); t.is (line, "width", "extractLine 10 'width' -> 'width'"); t.notok (extractLine (line, text, 10, true, offset), "extractLine 10 '' -> ''"); // void split (std::vector<std::string>& results, const std::string& input, const char delimiter) std::vector <std::string> items; std::string unsplit = ""; split (items, unsplit, '-'); t.is (items.size (), (size_t) 0, "split '' '-' -> 0 items"); unsplit = "a"; split (items, unsplit, '-'); t.is (items.size (), (size_t) 1, "split 'a' '-' -> 1 item"); t.is (items[0], "a", "split 'a' '-' -> 'a'"); split (items, unsplit, '-'); t.is (items.size (), (size_t) 1, "split 'a' '-' -> 1 item"); t.is (items[0], "a", "split 'a' '-' -> 'a'"); unsplit = "-"; split (items, unsplit, '-'); t.is (items.size (), (size_t) 2, "split '-' '-' -> '' ''"); t.is (items[0], "", "split '-' '-' -> [0] ''"); t.is (items[1], "", "split '-' '-' -> [1] ''"); split_minimal (items, unsplit, '-'); t.is (items.size (), (size_t) 0, "split '-' '-' ->"); unsplit = "-a-bc-def"; split (items, unsplit, '-'); t.is (items.size (), (size_t) 4, "split '-a-bc-def' '-' -> '' 'a' 'bc' 'def'"); t.is (items[0], "", "split '-a-bc-def' '-' -> [0] ''"); t.is (items[1], "a", "split '-a-bc-def' '-' -> [1] 'a'"); t.is (items[2], "bc", "split '-a-bc-def' '-' -> [2] 'bc'"); t.is (items[3], "def", "split '-a-bc-def' '-' -> [3] 'def'"); split_minimal (items, unsplit, '-'); t.is (items.size (), (size_t) 3, "split '-a-bc-def' '-' -> 'a' 'bc' 'def'"); t.is (items[0], "a", "split '-a-bc-def' '-' -> [1] 'a'"); t.is (items[1], "bc", "split '-a-bc-def' '-' -> [2] 'bc'"); t.is (items[2], "def", "split '-a-bc-def' '-' -> [3] 'def'"); // void split (std::vector<std::string>& results, const std::string& input, const std::string& delimiter) unsplit = ""; split (items, unsplit, "--"); t.is (items.size (), (size_t) 0, "split '' '--' -> 0 items"); unsplit = "a"; split (items, unsplit, "--"); t.is (items.size (), (size_t) 1, "split 'a' '--' -> 1 item"); t.is (items[0], "a", "split 'a' '-' -> 'a'"); unsplit = "--"; split (items, unsplit, "--"); t.is (items.size (), (size_t) 2, "split '-' '--' -> '' ''"); t.is (items[0], "", "split '-' '-' -> [0] ''"); t.is (items[1], "", "split '-' '-' -> [1] ''"); unsplit = "--a--bc--def"; split (items, unsplit, "--"); t.is (items.size (), (size_t) 4, "split '-a-bc-def' '--' -> '' 'a' 'bc' 'def'"); t.is (items[0], "", "split '-a-bc-def' '--' -> [0] ''"); t.is (items[1], "a", "split '-a-bc-def' '--' -> [1] 'a'"); t.is (items[2], "bc", "split '-a-bc-def' '--' -> [2] 'bc'"); t.is (items[3], "def", "split '-a-bc-def' '--' -> [3] 'def'"); unsplit = "one\ntwo\nthree"; split (items, unsplit, "\n"); t.is (items.size (), (size_t) 3, "split 'one\\ntwo\\nthree' -> 'one', 'two', 'three'"); t.is (items[0], "one", "split 'one\\ntwo\\nthree' -> [0] 'one'"); t.is (items[1], "two", "split 'one\\ntwo\\nthree' -> [1] 'two'"); t.is (items[2], "three", "split 'one\\ntwo\\nthree' -> [2] 'three'"); // void splitq (std::vector<std::string>&, const std::string&, const char); unsplit = "one 'two' '' 'three four' \"five six seven\" eight'nine ten'"; splitq (items, unsplit, ' '); t.is (items.size () , (size_t) 6, "splitq 'one \\'two\\' \\'\\' \\'three four\\' \"five six seven\" eight'nine ten'"); t.is (items[0], "one", "splitq 'one \\'two\\' \\'\\' \\'three four\\' \"five six seven\" eight'nine ten' -> [0] 'one'"); t.is (items[1], "two", "splitq 'one \\'two\\' \\'\\' \\'three four\\' \"five six seven\" eight'nine ten' -> [1] 'two'"); t.is (items[2], "", "splitq 'one \\'two\\' \\'\\' \\'three four\\' \"five six seven\" eight'nine ten' -> [2] ''"); t.is (items[3], "three four", "splitq 'one \\'two\\' \\'\\' \\'three four\\' \"five six seven\" eight'nine ten' -> [3] 'three four'"); t.is (items[4], "five six seven", "splitq 'one \\'two\\' \\'\\' \\'three four\\' \"five six seven\" eight'nine ten' -> [4] 'five six seven'"); t.is (items[5], "eight'nine ten'", "splitq 'one \\'two\\' \\'\\' \\'three four\\' \"five six seven\" eight'nine ten' -> [4] 'eight\\'nine ten\\''"); // void join (std::string& result, const std::string& separator, const std::vector<std::string>& items) std::vector <std::string> unjoined; std::string joined; join (joined, "", unjoined); t.is (joined.length (), (size_t) 0, "join -> length 0"); t.is (joined, "", "join -> ''"); unjoined.push_back (""); unjoined.push_back ("a"); unjoined.push_back ("bc"); unjoined.push_back ("def"); join (joined, "", unjoined); t.is (joined.length (), (size_t) 6, "join '' 'a' 'bc' 'def' -> length 6"); t.is (joined, "abcdef", "join '' 'a' 'bc' 'def' -> 'abcdef'"); join (joined, "-", unjoined); t.is (joined.length (), (size_t) 9, "join '' - 'a' - 'bc' - 'def' -> length 9"); t.is (joined, "-a-bc-def", "join '' - 'a' - 'bc' - 'def' -> '-a-bc-def'"); // void join (std::string& result, const std::string& separator, const std::vector<int>& items) std::vector <int> unjoined2; join (joined, "", unjoined2); t.is (joined.length (), (size_t) 0, "join -> length 0"); t.is (joined, "", "join -> ''"); unjoined2.push_back (0); unjoined2.push_back (1); unjoined2.push_back (2); join (joined, "", unjoined2); t.is (joined.length (), (size_t) 3, "join 0 1 2 -> length 3"); t.is (joined, "012", "join 0 1 2 -> '012'"); join (joined, "-", unjoined2); t.is (joined.length (), (size_t) 5, "join 0 1 2 -> length 5"); t.is (joined, "0-1-2", "join 0 1 2 -> '0-1-2'"); // std::string trimLeft (const std::string& in, const std::string& t /*= " "*/) t.is (trimLeft (""), "", "trimLeft '' -> ''"); t.is (trimLeft (" "), "", "trimLeft ' ' -> ''"); t.is (trimLeft ("", " \t"), "", "trimLeft '' -> ''"); t.is (trimLeft ("xxx"), "xxx", "trimLeft 'xxx' -> 'xxx'"); t.is (trimLeft ("xxx", " \t"), "xxx", "trimLeft 'xxx' -> 'xxx'"); t.is (trimLeft (" \t xxx \t "), "\t xxx \t ", "trimLeft ' \\t xxx \\t ' -> '\\t xxx \\t '"); t.is (trimLeft (" \t xxx \t ", " \t"), "xxx \t ", "trimLeft ' \\t xxx \\t ' -> 'xxx \\t '"); // std::string trimRight (const std::string& in, const std::string& t /*= " "*/) t.is (trimRight (""), "", "trimRight '' -> ''"); t.is (trimRight (" "), "", "trimRight ' ' -> ''"); t.is (trimRight ("", " \t"), "", "trimRight '' -> ''"); t.is (trimRight ("xxx"), "xxx", "trimRight 'xxx' -> 'xxx'"); t.is (trimRight ("xxx", " \t"), "xxx", "trimRight 'xxx' -> 'xxx'"); t.is (trimRight (" \t xxx \t "), " \t xxx \t", "trimRight ' \\t xxx \\t ' -> ' \\t xxx \\t'"); t.is (trimRight (" \t xxx \t ", " \t"), " \t xxx", "trimRight ' \\t xxx \\t ' -> ' \\t xxx'"); // std::string trim (const std::string& in, const std::string& t /*= " "*/) t.is (trim (""), "", "trim '' -> ''"); t.is (trim (" "), "", "trim ' ' -> ''"); t.is (trim ("", " \t"), "", "trim '' -> ''"); t.is (trim ("xxx"), "xxx", "trim 'xxx' -> 'xxx'"); t.is (trim ("xxx", " \t"), "xxx", "trim 'xxx' -> 'xxx'"); t.is (trim (" \t xxx \t "), "\t xxx \t", "trim ' \\t xxx \\t ' -> '\\t xxx \\t'"); t.is (trim (" \t xxx \t ", " \t"), "xxx", "trim ' \\t xxx \\t ' -> 'xxx'"); // std::string unquoteText (const std::string& text) t.is (unquoteText (""), "", "unquoteText '' -> ''"); t.is (unquoteText ("x"), "x", "unquoteText 'x' -> 'x'"); t.is (unquoteText ("'x"), "'x", "unquoteText ''x' -> ''x'"); t.is (unquoteText ("x'"), "x'", "unquoteText 'x'' -> 'x''"); t.is (unquoteText ("\"x"), "\"x", "unquoteText '\"x' -> '\"x'"); t.is (unquoteText ("x\""), "x\"", "unquoteText 'x\"' -> 'x\"'"); t.is (unquoteText ("''"), "", "unquoteText '''' -> ''"); t.is (unquoteText ("'''"), "'", "unquoteText ''''' -> '''"); t.is (unquoteText ("\"\""), "", "unquoteText '\"\"' -> ''"); t.is (unquoteText ("\"\"\""), "\"", "unquoteText '\"\"\"' -> '\"'"); t.is (unquoteText ("''''"), "''", "unquoteText '''''' -> ''''"); t.is (unquoteText ("\"\"\"\""), "\"\"", "unquoteText '\"\"\"\"' -> '\"\"'"); t.is (unquoteText ("'\"\"'"), "\"\"", "unquoteText '''\"\"' -> '\"\"'"); t.is (unquoteText ("\"''\""), "''", "unquoteText '\"''\"' -> ''''"); t.is (unquoteText ("'x'"), "x", "unquoteText ''x'' -> 'x'"); t.is (unquoteText ("\"x\""), "x", "unquoteText '\"x\"' -> 'x'"); // int longestWord (const std::string&) t.is (longestWord (" "), 0, "longestWord ( ) --> 0"); t.is (longestWord ("this is a test"), 4, "longestWord (this is a test) --> 4"); t.is (longestWord ("this is a better test"), 6, "longestWord (this is a better test) --> 6"); t.is (longestWord ("house Çirçös clown"), 6, "longestWord (Çirçös) --> 6"); // int longestLine (const std::string&) t.is (longestLine ("one two three four"), 18, "longestLine (one two three four) --> 18"); t.is (longestLine ("one\ntwo three four"), 14, "longestLine (one\\ntwo three four) --> 14"); t.is (longestLine ("one\ntwo\nthree\nfour"), 5, "longestLine (one\\ntwo\\nthree\\nfour) --> 5"); // std::string commify (const std::string& data) t.is (commify (""), "", "commify '' -> ''"); t.is (commify ("1"), "1", "commify '1' -> '1'"); t.is (commify ("12"), "12", "commify '12' -> '12'"); t.is (commify ("123"), "123", "commify '123' -> '123'"); t.is (commify ("1234"), "1,234", "commify '1234' -> '1,234'"); t.is (commify ("12345"), "12,345", "commify '12345' -> '12,345'"); t.is (commify ("123456"), "123,456", "commify '123456' -> '123,456'"); t.is (commify ("1234567"), "1,234,567", "commify '1234567' -> '1,234,567'"); t.is (commify ("12345678"), "12,345,678", "commify '12345678' -> '12,345,678'"); t.is (commify ("123456789"), "123,456,789", "commify '123456789' -> '123,456,789'"); t.is (commify ("1234567890"), "1,234,567,890", "commify '1234567890' -> '1,234,567,890'"); t.is (commify ("pre"), "pre", "commify 'pre' -> 'pre'"); t.is (commify ("pre1234"), "pre1,234", "commify 'pre1234' -> 'pre1,234'"); t.is (commify ("1234post"), "1,234post", "commify '1234post' -> '1,234post'"); t.is (commify ("pre1234post"), "pre1,234post", "commify 'pre1234post' -> 'pre1,234post'"); // std::string lowerCase (const std::string& input) t.is (lowerCase (""), "", "lowerCase '' -> ''"); t.is (lowerCase ("pre01_:POST"), "pre01_:post", "lowerCase 'pre01_:POST' -> 'pre01_:post'"); // std::string upperCase (const std::string& input) t.is (upperCase (""), "", "upperCase '' -> ''"); t.is (upperCase ("pre01_:POST"), "PRE01_:POST", "upperCase 'pre01_:POST' -> 'PRE01_:POST'"); // bool nontrivial (const std::string&); t.notok (nontrivial (""), "nontrivial '' -> false"); t.notok (nontrivial (" "), "nontrivial ' ' -> false"); t.notok (nontrivial ("\t\t"), "nontrivial '\\t\\t' -> false"); t.notok (nontrivial (" \t \t"), "nontrivial ' \\t \\t' -> false"); t.ok (nontrivial ("a"), "nontrivial 'a' -> true"); t.ok (nontrivial (" a"), "nontrivial ' a' -> true"); t.ok (nontrivial ("a "), "nontrivial 'a ' -> true"); t.ok (nontrivial (" \t\ta"), "nontrivial ' \\t\\ta' -> true"); t.ok (nontrivial ("a\t\t "), "nontrivial 'a\\t\\t ' -> true"); // bool digitsOnly (const std::string&); t.ok (digitsOnly (""), "digitsOnly '' -> true"); t.ok (digitsOnly ("0"), "digitsOnly '0' -> true"); t.ok (digitsOnly ("123"), "digitsOnly '123' -> true"); t.notok (digitsOnly ("12fa"), "digitsOnly '12fa' -> false"); // bool noSpaces (const std::string&); t.ok (noSpaces (""), "noSpaces '' -> true"); t.ok (noSpaces ("a"), "noSpaces 'a' -> true"); t.ok (noSpaces ("abc"), "noSpaces 'abc' -> true"); t.notok (noSpaces (" "), "noSpaces ' ' -> false"); t.notok (noSpaces ("ab cd"), "noSpaces 'ab cd' -> false"); // bool noVerticalSpace (const std::string&); t.ok (noVerticalSpace (""), "noVerticalSpace '' -> true"); t.ok (noVerticalSpace ("a"), "noVerticalSpace 'a' -> true"); t.ok (noVerticalSpace ("abc"), "noVerticalSpace 'abc' -> true"); t.notok (noVerticalSpace ("a\nb"), "noVerticalSpace 'a\\nb' -> false"); t.notok (noVerticalSpace ("a\rb"), "noVerticalSpace 'a\\rb' -> false"); t.notok (noVerticalSpace ("a\fb"), "noVerticalSpace 'a\\fb' -> false"); text = "Hello, world."; // 0123456789012 // s e s e // bool isWordStart (const std::string&, std::string::size_type); t.notok (isWordStart ("", 0), "isWordStart (\"\", 0) -> false"); t.ok (isWordStart ("foo", 0), "isWordStart (\"foo\", 0) -> true"); t.ok (isWordStart (text, 0), "isWordStart (\"Hello, world.\", 0) -> true"); t.notok (isWordStart (text, 1), "isWordStart (\"Hello, world.\", 1) -> false"); t.notok (isWordStart (text, 2), "isWordStart (\"Hello, world.\", 2) -> false"); t.notok (isWordStart (text, 3), "isWordStart (\"Hello, world.\", 3) -> false"); t.notok (isWordStart (text, 4), "isWordStart (\"Hello, world.\", 4) -> false"); t.notok (isWordStart (text, 5), "isWordStart (\"Hello, world.\", 5) -> false"); t.notok (isWordStart (text, 6), "isWordStart (\"Hello, world.\", 6) -> false"); t.ok (isWordStart (text, 7), "isWordStart (\"Hello, world.\", 7) -> true"); t.notok (isWordStart (text, 8), "isWordStart (\"Hello, world.\", 8) -> false"); t.notok (isWordStart (text, 9), "isWordStart (\"Hello, world.\", 9) -> false"); t.notok (isWordStart (text, 10), "isWordStart (\"Hello, world.\", 10) -> false"); t.notok (isWordStart (text, 11), "isWordStart (\"Hello, world.\", 11) -> false"); t.notok (isWordStart (text, 12), "isWordStart (\"Hello, world.\", 12) -> false"); // bool isWordEnd (const std::string&, std::string::size_type); t.notok (isWordEnd ("", 0), "isWordEnd (\"\", 0) -> false"); t.ok (isWordEnd ("foo", 2), "isWordEnd (\"foo\", 2) -> true"); t.notok (isWordEnd (text, 0), "isWordEnd (\"Hello, world.\", 0) -> false"); t.notok (isWordEnd (text, 1), "isWordEnd (\"Hello, world.\", 1) -> false"); t.notok (isWordEnd (text, 2), "isWordEnd (\"Hello, world.\", 2) -> false"); t.notok (isWordEnd (text, 3), "isWordEnd (\"Hello, world.\", 3) -> false"); t.ok (isWordEnd (text, 4), "isWordEnd (\"Hello, world.\", 4) -> true"); t.notok (isWordEnd (text, 5), "isWordEnd (\"Hello, world.\", 5) -> false"); t.notok (isWordEnd (text, 6), "isWordEnd (\"Hello, world.\", 6) -> false"); t.notok (isWordEnd (text, 7), "isWordEnd (\"Hello, world.\", 7) -> false"); t.notok (isWordEnd (text, 8), "isWordEnd (\"Hello, world.\", 8) -> false"); t.notok (isWordEnd (text, 9), "isWordEnd (\"Hello, world.\", 9) -> false"); t.notok (isWordEnd (text, 10), "isWordEnd (\"Hello, world.\", 10) -> false"); t.ok (isWordEnd (text, 11), "isWordEnd (\"Hello, world.\", 11) -> true"); t.notok (isWordEnd (text, 12), "isWordEnd (\"Hello, world.\", 12) -> false"); // bool compare (const std::string&, const std::string&, bool caseless = false); // Make sure degenerate cases are handled. t.ok (compare ("", ""), "'' == ''"); t.notok (compare ("foo", ""), "foo != ''"); t.notok (compare ("", "foo"), "'' != foo"); // Make sure the default is case-sensitive. t.ok (compare ("foo", "foo"), "foo == foo"); t.notok (compare ("foo", "FOO"), "foo != foo"); // Test case-sensitive. t.notok (compare ("foo", "xx", true), "foo != xx"); t.ok (compare ("foo", "foo", true), "foo == foo"); t.notok (compare ("foo", "FOO", true), "foo != FOO"); t.notok (compare ("FOO", "foo", true), "FOO != foo"); t.ok (compare ("FOO", "FOO", true), "FOO == FOO"); // Test case-insensitive. t.notok (compare ("foo", "xx", false), "foo != foo (caseless)"); t.ok (compare ("foo", "foo", false), "foo == foo (caseless)"); t.ok (compare ("foo", "FOO", false), "foo == FOO (caseless)"); t.ok (compare ("FOO", "foo", false), "FOO == foo (caseless)"); t.ok (compare ("FOO", "FOO", false), "FOO == FOO (caseless)"); // std::string::size_type find (const std::string&, const std::string&, bool caseless = false); // Make sure degenerate cases are handled. t.is ((int) find ("foo", ""), (int) 0, "foo !contains ''"); t.is ((int) find ("", "foo"), (int) std::string::npos, "'' !contains foo"); // Make sure the default is case-sensitive. t.is ((int) find ("foo", "fo"), 0, "foo contains fo"); t.is ((int) find ("foo", "FO"), (int) std::string::npos, "foo !contains fo"); // Test case-sensitive. t.is ((int) find ("foo", "xx", true), (int) std::string::npos, "foo !contains xx"); t.is ((int) find ("foo", "oo", true), 1, "foo contains oo"); t.is ((int) find ("foo", "fo", true), 0, "foo contains fo"); t.is ((int) find ("foo", "FO", true), (int) std::string::npos, "foo !contains fo"); t.is ((int) find ("FOO", "fo", true), (int) std::string::npos, "foo !contains fo"); t.is ((int) find ("FOO", "FO", true), 0, "foo contains fo"); // Test case-insensitive. t.is ((int) find ("foo", "xx", false), (int) std::string::npos, "foo !contains xx (caseless)"); t.is ((int) find ("foo", "oo", false), 1, "foo contains oo (caseless)"); t.is ((int) find ("foo", "fo", false), 0, "foo contains fo (caseless)"); t.is ((int) find ("foo", "FO", false), 0, "foo contains FO (caseless)"); t.is ((int) find ("FOO", "fo", false), 0, "FOO contains fo (caseless)"); t.is ((int) find ("FOO", "FO", false), 0, "FOO contains FO (caseless)"); // Test start offset. t.is ((int) find ("one two three", "e", 3, true), (int) 11, "offset obeyed"); t.is ((int) find ("one two three", "e", 11, true), (int) 11, "offset obeyed"); // int strippedLength (const std::string&); t.is (strippedLength (std::string ("")), 0, "strippedLength -> 0"); t.is (strippedLength (std::string ("abc")), 3, "strippedLength abc -> 3"); t.is (strippedLength (std::string ("one\033[5;38;255mtwo\033[0mthree")), 11, "strippedLength one^[[5;38;255mtwo^[[0mthree -> 11"); t.is (strippedLength (std::string ("\033[0m")), 0, "strippedLength ^[[0m -> 0"); t.is (strippedLength (std::string ("\033[1m\033[0m")), 0, "strippedLength ^[[1m^[[0m -> 0"); // std::string format (char); t.is (format ('A'), "A", "format ('A') -> A"); // std::string format (int); t.is (format (0), "0", "format (0) -> 0"); t.is (format (-1), "-1", "format (-1) -> -1"); // std::string formatHex (int); t.is (formatHex (0), "0", "formatHex (0) -> 0"); t.is (formatHex (10), "a", "formatHex (10) -> a"); t.is (formatHex (123), "7b", "formatHex (123) -> 7b"); // std::string format (float, int, int); t.is (format (1.23456789, 8, 1), " 1", "format (1.23456789, 8, 1) -> _______1"); t.is (format (1.23456789, 8, 2), " 1.2", "format (1.23456789, 8, 2) -> _____1.2"); t.is (format (1.23456789, 8, 3), " 1.23", "format (1.23456789, 8, 3) -> ____1.23"); t.is (format (1.23456789, 8, 4), " 1.235", "format (1.23456789, 8, 4) -> ___1.235"); t.is (format (1.23456789, 8, 5), " 1.2346", "format (1.23456789, 8, 5) -> __1.2346"); t.is (format (1.23456789, 8, 6), " 1.23457", "format (1.23456789, 8, 6) -> 1.23457"); t.is (format (1.23456789, 8, 7), "1.234568", "format (1.23456789, 8, 7) -> 1.234568"); t.is (format (1.23456789, 8, 8), "1.2345679", "format (1.23456789, 8, 8) -> 1.2345679"); t.is (format (2444238.56789, 12, 11), "2444238.5679", "format (2444238.56789, 12, 11) -> 2444238.5679"); // std::string format (double, int, int); // std::string leftJustify (const std::string&, const int); t.is (leftJustify (123, 3), "123", "leftJustify 123,3 -> '123'"); t.is (leftJustify (123, 4), "123 ", "leftJustify 123,4 -> '123 '"); t.is (leftJustify (123, 5), "123 ", "leftJustify 123,5 -> '123 '"); // std::string leftJustify (const std::string&, const int); t.is (leftJustify ("foo", 3), "foo", "leftJustify foo,3 -> 'foo'"); t.is (leftJustify ("foo", 4), "foo ", "leftJustify foo,4 -> 'foo '"); t.is (leftJustify ("foo", 5), "foo ", "leftJustify foo,5 -> 'foo '"); t.is (leftJustify ("föo", 5), "föo ", "leftJustify föo,5 -> 'föo '"); // std::string rightJustify (const std::string&, const int); t.is (rightJustify (123, 3), "123", "rightJustify 123,3 -> '123'"); t.is (rightJustify (123, 4), " 123", "rightJustify 123,4 -> ' 123'"); t.is (rightJustify (123, 5), " 123", "rightJustify 123,5 -> ' 123'"); // std::string rightJustify (const std::string&, const int); t.is (rightJustify ("foo", 3), "foo", "rightJustify foo,3 -> 'foo'"); t.is (rightJustify ("foo", 4), " foo", "rightJustify foo,4 -> ' foo'"); t.is (rightJustify ("foo", 5), " foo", "rightJustify foo,5 -> ' foo'"); t.is (rightJustify ("föo", 5), " föo", "rightJustify föo,5 -> ' föo'"); // int utf8_length (const std::string&); t.is ((int) utf8_length ("Çirçös"), 6, "utf8_length (Çirçös) == 6"); t.is ((int) utf8_length ("ツネナラム"), 5, "utf8_length (ツネナラム) == 5"); t.is ((int) utf8_length ("Zwölf Boxkämpfer"), 16, "utf8_length (Zwölf Boxkämpfer) == 16"); return 0; }
// Perform the merge. // // The merge code creates a new lumpinfo list, adding entries from the // IWAD first followed by the PWAD. // // For the IWAD: // * Flats are added. If a flat with the same name is in the PWAD, // it is ignored (deleted). At the end of the section, all flats in the // PWAD are inserted. This is consistent with the behavior of // deutex/deusf. // * Sprites are added. The "replace list" is generated before the merge // from the list of sprites in the PWAD. Any sprites in the IWAD found // to match the replace list are removed. At the end of the section, // the sprites from the PWAD are inserted. // // For the PWAD: // * All Sprites and Flats are ignored, with the assumption they have // already been merged into the IWAD's sections. static void DoMerge(void) { section_t current_section; lumpinfo_t **newlumps; int num_newlumps; int lumpindex; // Can't ever have more lumps than we already have newlumps = calloc(numlumps, sizeof(lumpinfo_t *)); num_newlumps = 0; // Add IWAD lumps current_section = SECTION_NORMAL; for (int i = 0; i < iwad.numlumps; i++) { lumpinfo_t *lump = iwad.lumps[i]; switch (current_section) { case SECTION_NORMAL: if (!strncasecmp(lump->name, "F_START", 8)) current_section = SECTION_FLATS; else if (!strncasecmp(lump->name, "S_START", 8)) current_section = SECTION_SPRITES; newlumps[num_newlumps++] = lump; break; case SECTION_FLATS: // Have we reached the end of the section? if (!strncasecmp(lump->name, "F_END", 8)) { // Add all new flats from the PWAD to the end // of the section for (int n = 0; n < pwad_flats.numlumps; n++) newlumps[num_newlumps++] = pwad_flats.lumps[n]; newlumps[num_newlumps++] = lump; // back to normal reading current_section = SECTION_NORMAL; } else { // If there is a flat in the PWAD with the same name, // do not add it now. All PWAD flats are added to the // end of the section. Otherwise, if it is only in the // IWAD, add it now lumpindex = FindInList(&pwad_flats, lump->name); if (lumpindex < 0) newlumps[num_newlumps++] = lump; } break; case SECTION_SPRITES: // Have we reached the end of the section? if (!strncasecmp(lump->name, "S_END", 8)) { // add all the PWAD sprites for (int n = 0; n < pwad_sprites.numlumps; n++) if (SpriteLumpNeeded(pwad_sprites.lumps[n])) newlumps[num_newlumps++] = pwad_sprites.lumps[n]; // copy the ending newlumps[num_newlumps++] = lump; // back to normal reading current_section = SECTION_NORMAL; } else { // Is this lump holding a sprite to be replaced in the // PWAD? If so, wait until the end to add it. if (SpriteLumpNeeded(lump)) newlumps[num_newlumps++] = lump; } break; case SECTION_HIDEF: break; } } // Add PWAD lumps current_section = SECTION_NORMAL; for (int i = 0, histart; i < pwad.numlumps; i++) { lumpinfo_t *lump = pwad.lumps[i]; switch (current_section) { case SECTION_NORMAL: if (!strncasecmp(lump->name, "F_START", 8) || !strncasecmp(lump->name, "FF_START", 8)) current_section = SECTION_FLATS; else if (!strncasecmp(lump->name, "S_START", 8) || !strncasecmp(lump->name, "SS_START", 8)) current_section = SECTION_SPRITES; else if (!strncasecmp(lump->name, "HI_START", 8)) { current_section = SECTION_HIDEF; histart = i; } else // Don't include the headers of sections newlumps[num_newlumps++] = lump; break; case SECTION_FLATS: // PWAD flats are ignored (already merged) if (!strncasecmp(lump->name, "FF_END", 8) || !strncasecmp(lump->name, "F_END", 8)) // end of section current_section = SECTION_NORMAL; break; case SECTION_SPRITES: // PWAD sprites are ignored (already merged) if (!strncasecmp(lump->name, "SS_END", 8) || !strncasecmp(lump->name, "S_END", 8)) // end of section current_section = SECTION_NORMAL; break; case SECTION_HIDEF: if (!strncasecmp(lump->name, "HI_END", 8)) { int hiend = i - histart - 1; current_section = SECTION_NORMAL; if (hiend) { if (hiend == 1) C_Warning("The patch between the <b>HI_START</b> and <b>HI_END</b> markers will be ignored."); else C_Warning("The %s patches between the <b>HI_START</b> and <b>HI_END</b> markers will be ignored.", commify(hiend)); } } break; } } // Switch to the new lumpinfo, and free the old one free(lumpinfo); lumpinfo = newlumps; numlumps = num_newlumps; }
// // W_AddFile // All files are optional, but at least one file must be // found (PWAD, if all required lumps are present). // Files with a .wad extension are wadlink files // with multiple lumps. // Other files are single lumps with the base filename // for the lump name. wad_file_t *W_AddFile(char *filename, dboolean automatic) { wadinfo_t header; lumpindex_t i; int startlump; filelump_t *fileinfo; filelump_t *filerover; lumpinfo_t *filelumps; int numfilelumps; // open the file and add to directory wad_file_t *wad_file = W_OpenFile(filename); if (!wad_file) return NULL; M_StringCopy(wad_file->path, filename, sizeof(wad_file->path)); wad_file->freedoom = IsFreedoom(filename); if (!M_StringCompare(filename + strlen(filename) - 3, "wad")) { // single lump file // fraggle: Swap the filepos and size here. The WAD directory // parsing code expects a little-endian directory, so will swap // them back. Effectively we're constructing a "fake WAD directory" // here, as it would appear on disk. fileinfo = Z_Malloc(sizeof(filelump_t), PU_STATIC, NULL); fileinfo->filepos = LONG(0); fileinfo->size = LONG(wad_file->length); // Name the lump after the base of the filename (without the // extension). ExtractFileBase(filename, fileinfo->name); numfilelumps = 1; } else { int length; // WAD file W_Read(wad_file, 0, &header, sizeof(header)); // Homebrew levels? if (strncmp(header.identification, "IWAD", 4) && strncmp(header.identification, "PWAD", 4)) I_Error("Wad file %s doesn't have IWAD or PWAD id\n", filename); wad_file->type = (!strncmp(header.identification, "IWAD", 4) ? IWAD : PWAD); header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps * sizeof(filelump_t); fileinfo = Z_Malloc(length, PU_STATIC, NULL); W_Read(wad_file, header.infotableofs, fileinfo, length); numfilelumps = header.numlumps; } // Increase size of numlumps array to accommodate the new file. filelumps = calloc(numfilelumps, sizeof(lumpinfo_t)); if (!filelumps) I_Error("Failed to allocate array for lumps from new file."); startlump = numlumps; numlumps += numfilelumps; lumpinfo = Z_Realloc(lumpinfo, numlumps * sizeof(lumpinfo_t *)); if (!lumpinfo) I_Error("Failed to increase lumpinfo[] array size."); filerover = fileinfo; for (i = startlump; i < numlumps; ++i) { lumpinfo_t *lump_p = &filelumps[i - startlump]; lump_p->wad_file = wad_file; lump_p->position = LONG(filerover->filepos); lump_p->size = LONG(filerover->size); lump_p->cache = NULL; strncpy(lump_p->name, filerover->name, 8); lumpinfo[i] = lump_p; ++filerover; } Z_Free(fileinfo); if (lumphash) { Z_Free(lumphash); lumphash = NULL; } C_Output("%s %s lump%s from %.4s file %s.", (automatic ? "Automatically added" : "Added"), commify(numlumps - startlump), (numlumps - startlump == 1 ? "" : "s"), header.identification, uppercase(filename)); return wad_file; }