From f352daf00dae26da977e1a0f6b13d259c9b2f275 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 19:23:15 +0200 Subject: [PATCH 01/70] Allow moving mouse while spectating and typing (fixes #798) --- src/game/client/components/controls.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/game/client/components/controls.cpp b/src/game/client/components/controls.cpp index 334157d52..43239fa8e 100644 --- a/src/game/client/components/controls.cpp +++ b/src/game/client/components/controls.cpp @@ -486,8 +486,7 @@ void CControls::OnRender() bool CControls::OnMouseMove(float x, float y) { - if((m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED) || - (m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_pChat->IsActive())) + if((m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED)) return false; #if defined(__ANDROID__) // No relative mouse on Android From 35befec54ce78ddbb570a9d08e967b64e739bbb1 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 19:32:32 +0200 Subject: [PATCH 02/70] Clean up key binding a bit --- src/game/client/components/binds.cpp | 157 ++++++++------------------- src/game/client/components/binds.h | 2 +- 2 files changed, 49 insertions(+), 110 deletions(-) diff --git a/src/game/client/components/binds.cpp b/src/game/client/components/binds.cpp index 94e0f038f..e9592f9d9 100644 --- a/src/game/client/components/binds.cpp +++ b/src/game/client/components/binds.cpp @@ -33,11 +33,14 @@ CBinds::~CBinds() mem_free(m_apKeyBindings[i]); } -void CBinds::Bind(int KeyID, const char *pStr) +void CBinds::Bind(int KeyID, const char *pStr, bool FreeOnly) { if(KeyID < 0 || KeyID >= KEY_LAST) return; + if(FreeOnly && Get(KeyID)[0]) + return; + if(m_apKeyBindings[KeyID]) { mem_free(m_apKeyBindings[KeyID]); @@ -121,8 +124,8 @@ void CBinds::SetDefaults() Bind(KEY_BACKQUOTE, "+statboard"); Bind(KEY_F10, "screenshot"); - Bind('a', "+left"); - Bind('d', "+right"); + Bind(KEY_A, "+left"); + Bind(KEY_D, "+right"); Bind(KEY_SPACE, "+jump"); Bind(KEY_MOUSE_1, "+fire"); @@ -147,27 +150,27 @@ void CBinds::SetDefaults() #endif - Bind('1', "+weapon1"); - Bind('2', "+weapon2"); - Bind('3', "+weapon3"); - Bind('4', "+weapon4"); - Bind('5', "+weapon5"); + Bind(KEY_1, "+weapon1"); + Bind(KEY_2, "+weapon2"); + Bind(KEY_3, "+weapon3"); + Bind(KEY_4, "+weapon4"); + Bind(KEY_5, "+weapon5"); Bind(KEY_MOUSE_WHEEL_UP, "+prevweapon"); Bind(KEY_MOUSE_WHEEL_DOWN, "+nextweapon"); - Bind('t', "+show_chat; chat all"); - Bind('y', "+show_chat; chat team"); - Bind('z', "+show_chat; chat team"); // For German keyboards - Bind('u', "+show_chat"); - Bind('i', "+show_chat; chat all /c "); + Bind(KEY_T, "+show_chat; chat all"); + Bind(KEY_Y, "+show_chat; chat team"); + Bind(KEY_Z, "+show_chat; chat team"); // For German keyboards + Bind(KEY_U, "+show_chat"); + Bind(KEY_I, "+show_chat; chat all /c "); Bind(KEY_F3, "vote yes"); Bind(KEY_F4, "vote no"); - Bind('k', "kill"); - Bind('q', "say /pause"); - Bind('p', "say /pause"); + Bind(KEY_K, "kill"); + Bind(KEY_Q, "say /pause"); + Bind(KEY_P, "say /pause"); // DDRace @@ -314,101 +317,37 @@ void CBinds::ConfigSaveCallback(IConfig *pConfig, void *pUserData) void CBinds::SetDDRaceBinds(bool FreeOnly) { - if(!FreeOnly) - { - Bind(KEY_KP_PLUS, "zoom+"); - Bind(KEY_KP_MINUS, "zoom-"); - Bind(KEY_KP_MULTIPLY, "zoom"); - Bind(KEY_HOME, "kill"); - Bind(KEY_PAUSE, "say /pause"); - Bind(KEY_UP, "+jump"); - Bind(KEY_LEFT, "+left"); - Bind(KEY_RIGHT, "+right"); - Bind('[', "+prevweapon"); - Bind(']', "+nextweapon"); - Bind('c', "say /rank"); - Bind('v', "say /info"); - Bind('b', "say /top5"); - Bind('x', "emote 14"); - Bind('h', "emote 2"); - Bind('m', "emote 5"); - Bind('s', "+showhookcoll"); - Bind('x', "toggle cl_dummy 0 1"); + Bind(KEY_KP_PLUS, "zoom+", FreeOnly); + Bind(KEY_KP_MINUS, "zoom-", FreeOnly); + Bind(KEY_KP_MULTIPLY, "zoom", FreeOnly); + Bind(KEY_HOME, "kill", FreeOnly); + Bind(KEY_PAUSE, "say /pause", FreeOnly); + Bind(KEY_UP, "+jump", FreeOnly); + Bind(KEY_LEFT, "+left", FreeOnly); + Bind(KEY_RIGHT, "+right", FreeOnly); + Bind(KEY_LEFTBRACKET, "+prevweapon", FreeOnly); + Bind(KEY_RIGHTBRACKET, "+nextweapon", FreeOnly); + Bind(KEY_C, "say /rank", FreeOnly); + Bind(KEY_V, "say /info", FreeOnly); + Bind(KEY_B, "say /top5", FreeOnly); + Bind(KEY_X, "emote 14", FreeOnly); + Bind(KEY_H, "emote 2", FreeOnly); + Bind(KEY_M, "emote 5", FreeOnly); + Bind(KEY_S, "+showhookcoll", FreeOnly); + Bind(KEY_X, "toggle cl_dummy 0 1", FreeOnly); #if !defined(__ANDROID__) - Bind(KEY_PAGEDOWN, "toggle cl_show_quads 0 1"); - Bind(KEY_PAGEUP, "toggle cl_overlay_entities 0 100"); + Bind(KEY_PAGEDOWN, "toggle cl_show_quads 0 1", FreeOnly); + Bind(KEY_PAGEUP, "toggle cl_overlay_entities 0 100", FreeOnly); #endif - Bind(KEY_KP_0, "say /emote normal 999999"); - Bind(KEY_KP_1, "say /emote happy 999999"); - Bind(KEY_KP_2, "say /emote angry 999999"); - Bind(KEY_KP_3, "say /emote pain 999999"); - Bind(KEY_KP_4, "say /emote surprise 999999"); - Bind(KEY_KP_5, "say /emote blink 999999"); - Bind(KEY_MOUSE_3, "+spectate"); - Bind(KEY_MINUS, "spectate_previous"); - Bind(KEY_EQUALS, "spectate_next"); - } - else - { - if(!Get(KEY_KP_PLUS)[0]) - Bind(KEY_KP_PLUS, "zoom+"); - if(!Get(KEY_KP_MINUS)[0]) - Bind(KEY_KP_MINUS, "zoom-"); - if(!Get(KEY_KP_MULTIPLY)[0]) - Bind(KEY_KP_MULTIPLY, "zoom"); - if(!Get(KEY_HOME)[0]) - Bind(KEY_HOME, "kill"); - if(!Get(KEY_PAUSE)[0]) - Bind(KEY_PAUSE, "say /pause"); - if(!Get(KEY_UP)[0]) - Bind(KEY_UP, "+jump"); - if(!Get(KEY_LEFT)[0]) - Bind(KEY_LEFT, "+left"); - if(!Get(KEY_RIGHT)[0]) - Bind(KEY_RIGHT, "+right"); - if(!Get('[')[0]) - Bind('[', "+prevweapon"); - if(!Get(']')[0]) - Bind(']', "+nextweapon"); - if(!Get('c')[0]) - Bind('c', "say /rank"); - if(!Get('v')[0]) - Bind('v', "say /info"); - if(!Get('b')[0]) - Bind('b', "say /top5"); - if(!Get('x')[0]) - Bind('x', "emote 14"); - if(!Get(KEY_KP_PLUS)[0]) - Bind('h', "emote 2"); - if(!Get('m')[0]) - Bind('m', "emote 5"); - if(!Get('s')[0]) - Bind('s', "+showhookcoll"); - if(!Get('x')[0]) - Bind('x', "toggle cl_dummy 0 1"); - if(!Get(KEY_PAGEDOWN)[0]) - Bind(KEY_PAGEDOWN, "toggle cl_show_quads 0 1"); - if(!Get(KEY_PAGEUP)[0]) - Bind(KEY_PAGEUP, "toggle cl_overlay_entities 0 100"); - if(!Get(KEY_KP_0)[0]) - Bind(KEY_KP_0, "say /emote normal 999999"); - if(!Get(KEY_KP_1)[0]) - Bind(KEY_KP_1, "say /emote happy 999999"); - if(!Get(KEY_KP_2)[0]) - Bind(KEY_KP_2, "say /emote angry 999999"); - if(!Get(KEY_KP_3)[0]) - Bind(KEY_KP_3, "say /emote pain 999999"); - if(!Get(KEY_KP_4)[0]) - Bind(KEY_KP_4, "say /emote surprise 999999"); - if(!Get(KEY_KP_5)[0]) - Bind(KEY_KP_5, "say /emote blink 999999"); - if(!Get(KEY_MOUSE_3)[0]) - Bind(KEY_MOUSE_3, "+spectate"); - if(!Get(KEY_MINUS)[0]) - Bind(KEY_MINUS, "spectate_previous"); - if(!Get(KEY_EQUALS)[0]) - Bind(KEY_EQUALS, "spectate_next"); - } + Bind(KEY_KP_0, "say /emote normal 999999", FreeOnly); + Bind(KEY_KP_1, "say /emote happy 999999", FreeOnly); + Bind(KEY_KP_2, "say /emote angry 999999", FreeOnly); + Bind(KEY_KP_3, "say /emote pain 999999", FreeOnly); + Bind(KEY_KP_4, "say /emote surprise 999999", FreeOnly); + Bind(KEY_KP_5, "say /emote blink 999999", FreeOnly); + Bind(KEY_MOUSE_3, "+spectate", FreeOnly); + Bind(KEY_MINUS, "spectate_previous", FreeOnly); + Bind(KEY_EQUALS, "spectate_next", FreeOnly); g_Config.m_ClDDRaceBindsSet = 1; } diff --git a/src/game/client/components/binds.h b/src/game/client/components/binds.h index 411721748..46c6a35eb 100644 --- a/src/game/client/components/binds.h +++ b/src/game/client/components/binds.h @@ -32,7 +32,7 @@ public: CBindsSpecial m_SpecialBinds; - void Bind(int KeyID, const char *pStr); + void Bind(int KeyID, const char *pStr, bool FreeOnly = false); void SetDefaults(); void UnbindAll(); const char *Get(int KeyID); From b57ffa429ea1ecff4926f90a4b2e8cbb153e8f51 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 19:53:49 +0200 Subject: [PATCH 03/70] Use scancodes instead of keycodes for input (fixes #796, please test) --- scripts/gen_keys.py | 8 +- src/engine/client/input.cpp | 14 +- src/engine/client/keynames.h | 462 ++++++++++++------------ src/engine/keys.h | 504 ++++++++++++++------------- src/game/client/components/binds.cpp | 3 +- 5 files changed, 499 insertions(+), 492 deletions(-) diff --git a/scripts/gen_keys.py b/scripts/gen_keys.py index 44a3b063f..0d8c7a84c 100644 --- a/scripts/gen_keys.py +++ b/scripts/gen_keys.py @@ -44,9 +44,11 @@ print >>f, "\tKEY_MOUSE_5 = %d,"%(highestid+5); keynames[highestid+5] = "mouse5" print >>f, "\tKEY_MOUSE_6 = %d,"%(highestid+6); keynames[highestid+6] = "mouse6" print >>f, "\tKEY_MOUSE_7 = %d,"%(highestid+7); keynames[highestid+7] = "mouse7" print >>f, "\tKEY_MOUSE_8 = %d,"%(highestid+8); keynames[highestid+8] = "mouse8" -print >>f, "\tKEY_MOUSE_WHEEL_UP = %d,"%(highestid+9); keynames[highestid+9] = "mousewheelup" -print >>f, "\tKEY_MOUSE_WHEEL_DOWN = %d,"%(highestid+10); keynames[highestid+10] = "mousewheeldown" -print >>f, "\tKEY_MOUSE_9 = %d,"%(highestid+11); keynames[highestid+11] = "mouse9" +print >>f, "\tKEY_MOUSE_9 = %d,"%(highestid+9); keynames[highestid+9] = "mouse9" +print >>f, "\tKEY_MOUSE_WHEEL_UP = %d,"%(highestid+10); keynames[highestid+10] = "mousewheelup" +print >>f, "\tKEY_MOUSE_WHEEL_DOWN = %d,"%(highestid+11); keynames[highestid+11] = "mousewheeldown" +print >>f, "\tKEY_MOUSE_WHEEL_LEFT = %d,"%(highestid+12); keynames[highestid+12] = "mousewheelleft" +print >>f, "\tKEY_MOUSE_WHEEL_RIGHT = %d,"%(highestid+13); keynames[highestid+13] = "mousewheelright" print >>f, "\tKEY_LAST = 512," print >>f, "};" diff --git a/src/engine/client/input.cpp b/src/engine/client/input.cpp index 885f77fc6..05e7bcb28 100644 --- a/src/engine/client/input.cpp +++ b/src/engine/client/input.cpp @@ -129,7 +129,9 @@ void CInput::Clear() bool CInput::KeyState(int Key) const { - return m_aInputState[Key>=KEY_MOUSE_1 ? Key : SDL_GetScancodeFromKey(KeyToKeycode(Key))]; + if(Key < 0 || Key >= KEY_LAST) + return false; + return m_aInputState[Key]; } void CInput::NextFrame() @@ -237,13 +239,13 @@ int CInput::Update() // Sum if you want to ignore multiple modifiers. if(!(Event.key.keysym.mod & g_Config.m_InpIgnoredModifiers)) { - Key = KeycodeToKey(Event.key.keysym.sym); + Key = Event.key.keysym.sym; Scancode = Event.key.keysym.scancode; } break; case SDL_KEYUP: Action = IInput::FLAG_RELEASE; - Key = KeycodeToKey(Event.key.keysym.sym); + Key = Event.key.keysym.sym; Scancode = Event.key.keysym.scancode; break; @@ -322,14 +324,14 @@ int CInput::Update() return 1; } - if(Key >= 0 && Key < g_MaxKeys && !IgnoreKeys && m_CountEditingText == 0) + if(Scancode >= 0 && Scancode < g_MaxKeys && !IgnoreKeys && m_CountEditingText == 0) { if(Action&IInput::FLAG_PRESS) { m_aInputState[Scancode] = 1; - m_aInputCount[Key] = m_InputCounter; + m_aInputCount[Scancode] = m_InputCounter; } - AddEvent(0, Key, Action); + AddEvent(0, Scancode, Action); } } diff --git a/src/engine/client/keynames.h b/src/engine/client/keynames.h index 56930626e..64bddd503 100644 --- a/src/engine/client/keynames.h +++ b/src/engine/client/keynames.h @@ -4,105 +4,14 @@ #error do not include this header! #endif +#include + const char g_aaKeyStrings[512][20] = { "unknown", "&1", "&2", "&3", - "&4", - "&5", - "&6", - "&7", - "backspace", - "tab", - "&10", - "&11", - "&12", - "return", - "&14", - "&15", - "&16", - "&17", - "&18", - "&19", - "&20", - "&21", - "&22", - "&23", - "&24", - "&25", - "&26", - "escape", - "&28", - "&29", - "&30", - "&31", - "space", - "exclaim", - "quotedbl", - "hash", - "dollar", - "percent", - "ampersand", - "quote", - "leftparen", - "rightparen", - "asterix", - "plus", - "comma", - "minus", - "period", - "slash", - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "colon", - "semicolon", - "less", - "equals", - "greater", - "question", - "at", - "&65", - "&66", - "&67", - "&68", - "&69", - "&70", - "&71", - "&72", - "&73", - "&74", - "&75", - "&76", - "&77", - "&78", - "&79", - "&80", - "&81", - "&82", - "&83", - "&84", - "&85", - "&86", - "&87", - "&88", - "&89", - "&90", - "leftbracket", - "backslash", - "rightbracket", - "caret", - "underscore", - "backquote", "a", "b", "c", @@ -129,68 +38,33 @@ const char g_aaKeyStrings[512][20] = "x", "y", "z", - "&123", - "&124", - "&125", - "&126", - "delete", - "&128", - "&129", - "&130", - "&131", - "&132", - "&133", - "&134", - "&135", - "&136", - "&137", - "&138", - "&139", - "&140", - "&141", - "&142", - "&143", - "&144", - "&145", - "&146", - "&147", - "&148", - "&149", - "&150", - "&151", - "&152", - "&153", - "&154", - "&155", - "&156", - "&157", - "&158", - "&159", - "&160", - "&161", - "&162", - "&163", - "&164", - "&165", - "&166", - "&167", - "&168", - "&169", - "&170", - "&171", - "&172", - "&173", - "&174", - "&175", - "&176", - "&177", - "&178", - "&179", - "&180", - "&181", - "&182", - "&183", - "&184", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + "return", + "escape", + "backspace", + "tab", + "space", + "minus", + "equals", + "leftbracket", + "rightbracket", + "backslash", + "nonushash", + "semicolon", + "apostrophe", + "grave", + "comma", + "period", + "slash", "capslock", "f1", "f2", @@ -210,7 +84,7 @@ const char g_aaKeyStrings[512][20] = "insert", "home", "pageup", - "&204", + "delete", "end", "pagedown", "right", @@ -234,7 +108,7 @@ const char g_aaKeyStrings[512][20] = "kp_9", "kp_0", "kp_period", - "&228", + "nonusbackslash", "application", "power", "kp_equals", @@ -264,29 +138,29 @@ const char g_aaKeyStrings[512][20] = "mute", "volumeup", "volumedown", - "&258", - "&259", - "&260", + "&130", + "&131", + "&132", "kp_comma", "kp_equalsas400", - "&263", - "&264", - "&265", - "&266", - "&267", - "&268", - "&269", - "&270", - "&271", - "&272", - "&273", - "&274", - "&275", - "&276", - "&277", - "&278", - "&279", - "&280", + "international1", + "international2", + "international3", + "international4", + "international5", + "international6", + "international7", + "international8", + "international9", + "lang1", + "lang2", + "lang3", + "lang4", + "lang5", + "lang6", + "lang7", + "lang8", + "lang9", "alterase", "sysreq", "cancel", @@ -299,17 +173,17 @@ const char g_aaKeyStrings[512][20] = "clearagain", "crsel", "exsel", - "&293", - "&294", - "&295", - "&296", - "&297", - "&298", - "&299", - "&300", - "&301", - "&302", - "&303", + "&165", + "&166", + "&167", + "&168", + "&169", + "&170", + "&171", + "&172", + "&173", + "&174", + "&175", "kp_00", "kp_000", "thousandsseparator", @@ -356,8 +230,8 @@ const char g_aaKeyStrings[512][20] = "kp_octal", "kp_decimal", "kp_hexadecimal", - "&350", - "&351", + "&222", + "&223", "lctrl", "lshift", "lalt", @@ -366,6 +240,134 @@ const char g_aaKeyStrings[512][20] = "rshift", "ralt", "rgui", + "&232", + "&233", + "&234", + "&235", + "&236", + "&237", + "&238", + "&239", + "&240", + "&241", + "&242", + "&243", + "&244", + "&245", + "&246", + "&247", + "&248", + "&249", + "&250", + "&251", + "&252", + "&253", + "&254", + "&255", + "&256", + "mode", + "audionext", + "audioprev", + "audiostop", + "audioplay", + "audiomute", + "mediaselect", + "www", + "mail", + "calculator", + "computer", + "ac_search", + "ac_home", + "ac_back", + "ac_forward", + "ac_stop", + "ac_refresh", + "ac_bookmarks", + "brightnessdown", + "brightnessup", + "displayswitch", + "kbdillumtoggle", + "kbdillumdown", + "kbdillumup", + "eject", + "sleep", + "app1", + "app2", + "mouse1", + "mouse2", + "mouse3", + "mouse4", + "mouse5", + "mouse6", + "mouse7", + "mouse8", + "mouse9", + "mousewheelup", + "mousewheeldown", + "mousewheelleft", + "mousewheelright", + "&298", + "&299", + "&300", + "&301", + "&302", + "&303", + "&304", + "&305", + "&306", + "&307", + "&308", + "&309", + "&310", + "&311", + "&312", + "&313", + "&314", + "&315", + "&316", + "&317", + "&318", + "&319", + "&320", + "&321", + "&322", + "&323", + "&324", + "&325", + "&326", + "&327", + "&328", + "&329", + "&330", + "&331", + "&332", + "&333", + "&334", + "&335", + "&336", + "&337", + "&338", + "&339", + "&340", + "&341", + "&342", + "&343", + "&344", + "&345", + "&346", + "&347", + "&348", + "&349", + "&350", + "&351", + "&352", + "&353", + "&354", + "&355", + "&356", + "&357", + "&358", + "&359", "&360", "&361", "&362", @@ -391,45 +393,45 @@ const char g_aaKeyStrings[512][20] = "&382", "&383", "&384", - "mode", - "audionext", - "audioprev", - "audiostop", - "audioplay", - "audiomute", - "mediaselect", - "www", - "mail", - "calculator", - "computer", - "ac_search", - "ac_home", - "ac_back", - "ac_forward", - "ac_stop", - "ac_refresh", - "ac_bookmarks", - "brightnessdown", - "brightnessup", - "displayswitch", - "kbdillumtoggle", - "kbdillumdown", - "kpdillumup", - "eject", - "sleep", - "mouse1", - "mouse2", - "mouse3", - "mouse4", - "mouse5", - "mouse6", - "mouse7", - "mouse8", - "mouse9", - "mousewheelup", - "mousewheeldown", - "mousewheelleft", - "mousewheelright", + "&385", + "&386", + "&387", + "&388", + "&389", + "&390", + "&391", + "&392", + "&393", + "&394", + "&395", + "&396", + "&397", + "&398", + "&399", + "&400", + "&401", + "&402", + "&403", + "&404", + "&405", + "&406", + "&407", + "&408", + "&409", + "&410", + "&411", + "&412", + "&413", + "&414", + "&415", + "&416", + "&417", + "&418", + "&419", + "&420", + "&421", + "&422", + "&423", "&424", "&425", "&426", diff --git a/src/engine/keys.h b/src/engine/keys.h index 37a873e46..4e68e74e3 100644 --- a/src/engine/keys.h +++ b/src/engine/keys.h @@ -8,258 +8,260 @@ enum { KEY_FIRST = 0, KEY_UNKNOWN = 0, - KEY_BACKSPACE = 8, - KEY_TAB = 9, - KEY_RETURN = 13, - KEY_ESCAPE = 27, - KEY_SPACE = 32, - KEY_EXCLAIM = 33, - KEY_QUOTEDBL = 34, - KEY_HASH = 35, - KEY_DOLLAR = 36, - KEY_PERCENT = 37, - KEY_AMPERSAND = 38, - KEY_QUOTE = 39, - KEY_LEFTPAREN = 40, - KEY_RIGHTPAREN = 41, - KEY_ASTERISK = 42, - KEY_PLUS = 43, - KEY_COMMA = 44, + KEY_A = 4, + KEY_B = 5, + KEY_C = 6, + KEY_D = 7, + KEY_E = 8, + KEY_F = 9, + KEY_G = 10, + KEY_H = 11, + KEY_I = 12, + KEY_J = 13, + KEY_K = 14, + KEY_L = 15, + KEY_M = 16, + KEY_N = 17, + KEY_O = 18, + KEY_P = 19, + KEY_Q = 20, + KEY_R = 21, + KEY_S = 22, + KEY_T = 23, + KEY_U = 24, + KEY_V = 25, + KEY_W = 26, + KEY_X = 27, + KEY_Y = 28, + KEY_Z = 29, + KEY_1 = 30, + KEY_2 = 31, + KEY_3 = 32, + KEY_4 = 33, + KEY_5 = 34, + KEY_6 = 35, + KEY_7 = 36, + KEY_8 = 37, + KEY_9 = 38, + KEY_0 = 39, + KEY_RETURN = 40, + KEY_ESCAPE = 41, + KEY_BACKSPACE = 42, + KEY_TAB = 43, + KEY_SPACE = 44, KEY_MINUS = 45, - KEY_PERIOD = 46, - KEY_SLASH = 47, - KEY_0 = 48, - KEY_1 = 49, - KEY_2 = 50, - KEY_3 = 51, - KEY_4 = 52, - KEY_5 = 53, - KEY_6 = 54, - KEY_7 = 55, - KEY_8 = 56, - KEY_9 = 57, - KEY_COLON = 58, - KEY_SEMICOLON = 59, - KEY_LESS = 60, - KEY_EQUALS = 61, - KEY_GREATER = 62, - KEY_QUESTION = 63, - KEY_AT = 64, - KEY_LEFTBRACKET = 91, - KEY_BACKSLASH = 92, - KEY_RIGHTBRACKET = 93, - KEY_CARET = 94, - KEY_UNDERSCORE = 95, - KEY_BACKQUOTE = 96, - KEY_A = 97, - KEY_B = 98, - KEY_C = 99, - KEY_D = 100, - KEY_E = 101, - KEY_F = 102, - KEY_G = 103, - KEY_H = 104, - KEY_I = 105, - KEY_J = 106, - KEY_K = 107, - KEY_L = 108, - KEY_M = 109, - KEY_N = 110, - KEY_O = 111, - KEY_P = 112, - KEY_Q = 113, - KEY_R = 114, - KEY_S = 115, - KEY_T = 116, - KEY_U = 117, - KEY_V = 118, - KEY_W = 119, - KEY_X = 120, - KEY_Y = 121, - KEY_Z = 122, - KEY_DELETE = 127, - KEY_CAPSLOCK = 185, - KEY_F1 = 186, - KEY_F2 = 187, - KEY_F3 = 188, - KEY_F4 = 189, - KEY_F5 = 190, - KEY_F6 = 191, - KEY_F7 = 192, - KEY_F8 = 193, - KEY_F9 = 194, - KEY_F10 = 195, - KEY_F11 = 196, - KEY_F12 = 197, - KEY_PRINTSCREEN = 198, - KEY_SCROLLLOCK = 199, - KEY_PAUSE = 200, - KEY_INSERT = 201, - KEY_HOME = 202, - KEY_PAGEUP = 203, - KEY_END = 205, - KEY_PAGEDOWN = 206, - KEY_RIGHT = 207, - KEY_LEFT = 208, - KEY_DOWN = 209, - KEY_UP = 210, - KEY_NUMLOCKCLEAR = 211, - KEY_KP_DIVIDE = 212, - KEY_KP_MULTIPLY = 213, - KEY_KP_MINUS = 214, - KEY_KP_PLUS = 215, - KEY_KP_ENTER = 216, - KEY_KP_1 = 217, - KEY_KP_2 = 218, - KEY_KP_3 = 219, - KEY_KP_4 = 220, - KEY_KP_5 = 221, - KEY_KP_6 = 222, - KEY_KP_7 = 223, - KEY_KP_8 = 224, - KEY_KP_9 = 225, - KEY_KP_0 = 226, - KEY_KP_PERIOD = 227, - KEY_APPLICATION = 229, - KEY_POWER = 230, - KEY_KP_EQUALS = 231, - KEY_F13 = 232, - KEY_F14 = 233, - KEY_F15 = 234, - KEY_F16 = 235, - KEY_F17 = 236, - KEY_F18 = 237, - KEY_F19 = 238, - KEY_F20 = 239, - KEY_F21 = 240, - KEY_F22 = 241, - KEY_F23 = 242, - KEY_F24 = 243, - KEY_EXECUTE = 244, - KEY_HELP = 245, - KEY_MENU = 246, - KEY_SELECT = 247, - KEY_STOP = 248, - KEY_AGAIN = 249, - KEY_UNDO = 250, - KEY_CUT = 251, - KEY_COPY = 252, - KEY_PASTE = 253, - KEY_FIND = 254, - KEY_MUTE = 255, - KEY_VOLUMEUP = 256, - KEY_VOLUMEDOWN = 257, - KEY_KP_COMMA = 261, - KEY_KP_EQUALSAS400 = 262, - KEY_ALTERASE = 281, - KEY_SYSREQ = 282, - KEY_CANCEL = 283, - KEY_CLEAR = 284, - KEY_PRIOR = 285, - KEY_RETURN2 = 286, - KEY_SEPARATOR = 287, - KEY_OUT = 288, - KEY_OPER = 289, - KEY_CLEARAGAIN = 290, - KEY_CRSEL = 291, - KEY_EXSEL = 292, - KEY_KP_00 = 304, - KEY_KP_000 = 305, - KEY_THOUSANDSSEPARATOR = 306, - KEY_DECIMALSEPARATOR = 307, - KEY_CURRENCYUNIT = 308, - KEY_CURRENCYSUBUNIT = 309, - KEY_KP_LEFTPAREN = 310, - KEY_KP_RIGHTPAREN = 311, - KEY_KP_LEFTBRACE = 312, - KEY_KP_RIGHTBRACE = 313, - KEY_KP_TAB = 314, - KEY_KP_BACKSPACE = 315, - KEY_KP_A = 316, - KEY_KP_B = 317, - KEY_KP_C = 318, - KEY_KP_D = 319, - KEY_KP_E = 320, - KEY_KP_F = 321, - KEY_KP_XOR = 322, - KEY_KP_POWER = 323, - KEY_KP_PERCENT = 324, - KEY_KP_LESS = 325, - KEY_KP_GREATER = 326, - KEY_KP_AMPERSAND = 327, - KEY_KP_DBLAMPERSAND = 328, - KEY_KP_VERTICALBAR = 329, - KEY_KP_DBLVERTICALBAR = 330, - KEY_KP_COLON = 331, - KEY_KP_HASH = 332, - KEY_KP_SPACE = 333, - KEY_KP_AT = 334, - KEY_KP_EXCLAM = 335, - KEY_KP_MEMSTORE = 336, - KEY_KP_MEMRECALL = 337, - KEY_KP_MEMCLEAR = 338, - KEY_KP_MEMADD = 339, - KEY_KP_MEMSUBTRACT = 340, - KEY_KP_MEMMULTIPLY = 341, - KEY_KP_MEMDIVIDE = 342, - KEY_KP_PLUSMINUS = 343, - KEY_KP_CLEAR = 344, - KEY_KP_CLEARENTRY = 345, - KEY_KP_BINARY = 346, - KEY_KP_OCTAL = 347, - KEY_KP_DECIMAL = 348, - KEY_KP_HEXADECIMAL = 349, - KEY_LCTRL = 352, - KEY_LSHIFT = 353, - KEY_LALT = 354, - KEY_LGUI = 355, - KEY_RCTRL = 356, - KEY_RSHIFT = 357, - KEY_RALT = 358, - KEY_RGUI = 359, - KEY_MODE = 385, - KEY_AUDIONEXT = 386, - KEY_AUDIOPREV = 387, - KEY_AUDIOSTOP = 388, - KEY_AUDIOPLAY = 389, - KEY_AUDIOMUTE = 390, - KEY_MEDIASELECT = 391, - KEY_WWW = 392, - KEY_MAIL = 393, - KEY_CALCULATOR = 394, - KEY_COMPUTER = 395, - KEY_AC_SEARCH = 396, - KEY_AC_HOME = 397, - KEY_AC_BACK = 398, - KEY_AC_FORWARD = 399, - KEY_AC_STOP = 400, - KEY_AC_REFRESH = 401, - KEY_AC_BOOKMARKS = 402, - KEY_BRIGHTNESSDOWN = 403, - KEY_BRIGHTNESSUP = 404, - KEY_DISPLAYSWITCH = 405, - KEY_KBDILLUMTOGGLE = 406, - KEY_KBDILLUMDOWN = 407, - KEY_KBDILLUMUP = 408, - KEY_EJECT = 409, - KEY_SLEEP = 410, - KEY_MOUSE_1 = 411, - KEY_MOUSE_2 = 412, - KEY_MOUSE_3 = 413, - KEY_MOUSE_4 = 414, - KEY_MOUSE_5 = 415, - KEY_MOUSE_6 = 416, - KEY_MOUSE_7 = 417, - KEY_MOUSE_8 = 418, - KEY_MOUSE_9 = 419, - KEY_MOUSE_WHEEL_UP = 420, - KEY_MOUSE_WHEEL_DOWN = 421, - KEY_MOUSE_WHEEL_LEFT = 422, - KEY_MOUSE_WHEEL_RIGHT = 423, - KEY_LAST, + KEY_EQUALS = 46, + KEY_LEFTBRACKET = 47, + KEY_RIGHTBRACKET = 48, + KEY_BACKSLASH = 49, + KEY_NONUSHASH = 50, + KEY_SEMICOLON = 51, + KEY_APOSTROPHE = 52, + KEY_GRAVE = 53, + KEY_COMMA = 54, + KEY_PERIOD = 55, + KEY_SLASH = 56, + KEY_CAPSLOCK = 57, + KEY_F1 = 58, + KEY_F2 = 59, + KEY_F3 = 60, + KEY_F4 = 61, + KEY_F5 = 62, + KEY_F6 = 63, + KEY_F7 = 64, + KEY_F8 = 65, + KEY_F9 = 66, + KEY_F10 = 67, + KEY_F11 = 68, + KEY_F12 = 69, + KEY_PRINTSCREEN = 70, + KEY_SCROLLLOCK = 71, + KEY_PAUSE = 72, + KEY_INSERT = 73, + KEY_HOME = 74, + KEY_PAGEUP = 75, + KEY_DELETE = 76, + KEY_END = 77, + KEY_PAGEDOWN = 78, + KEY_RIGHT = 79, + KEY_LEFT = 80, + KEY_DOWN = 81, + KEY_UP = 82, + KEY_NUMLOCKCLEAR = 83, + KEY_KP_DIVIDE = 84, + KEY_KP_MULTIPLY = 85, + KEY_KP_MINUS = 86, + KEY_KP_PLUS = 87, + KEY_KP_ENTER = 88, + KEY_KP_1 = 89, + KEY_KP_2 = 90, + KEY_KP_3 = 91, + KEY_KP_4 = 92, + KEY_KP_5 = 93, + KEY_KP_6 = 94, + KEY_KP_7 = 95, + KEY_KP_8 = 96, + KEY_KP_9 = 97, + KEY_KP_0 = 98, + KEY_KP_PERIOD = 99, + KEY_NONUSBACKSLASH = 100, + KEY_APPLICATION = 101, + KEY_POWER = 102, + KEY_KP_EQUALS = 103, + KEY_F13 = 104, + KEY_F14 = 105, + KEY_F15 = 106, + KEY_F16 = 107, + KEY_F17 = 108, + KEY_F18 = 109, + KEY_F19 = 110, + KEY_F20 = 111, + KEY_F21 = 112, + KEY_F22 = 113, + KEY_F23 = 114, + KEY_F24 = 115, + KEY_EXECUTE = 116, + KEY_HELP = 117, + KEY_MENU = 118, + KEY_SELECT = 119, + KEY_STOP = 120, + KEY_AGAIN = 121, + KEY_UNDO = 122, + KEY_CUT = 123, + KEY_COPY = 124, + KEY_PASTE = 125, + KEY_FIND = 126, + KEY_MUTE = 127, + KEY_VOLUMEUP = 128, + KEY_VOLUMEDOWN = 129, + KEY_KP_COMMA = 133, + KEY_KP_EQUALSAS400 = 134, + KEY_INTERNATIONAL1 = 135, + KEY_INTERNATIONAL2 = 136, + KEY_INTERNATIONAL3 = 137, + KEY_INTERNATIONAL4 = 138, + KEY_INTERNATIONAL5 = 139, + KEY_INTERNATIONAL6 = 140, + KEY_INTERNATIONAL7 = 141, + KEY_INTERNATIONAL8 = 142, + KEY_INTERNATIONAL9 = 143, + KEY_LANG1 = 144, + KEY_LANG2 = 145, + KEY_LANG3 = 146, + KEY_LANG4 = 147, + KEY_LANG5 = 148, + KEY_LANG6 = 149, + KEY_LANG7 = 150, + KEY_LANG8 = 151, + KEY_LANG9 = 152, + KEY_ALTERASE = 153, + KEY_SYSREQ = 154, + KEY_CANCEL = 155, + KEY_CLEAR = 156, + KEY_PRIOR = 157, + KEY_RETURN2 = 158, + KEY_SEPARATOR = 159, + KEY_OUT = 160, + KEY_OPER = 161, + KEY_CLEARAGAIN = 162, + KEY_CRSEL = 163, + KEY_EXSEL = 164, + KEY_KP_00 = 176, + KEY_KP_000 = 177, + KEY_THOUSANDSSEPARATOR = 178, + KEY_DECIMALSEPARATOR = 179, + KEY_CURRENCYUNIT = 180, + KEY_CURRENCYSUBUNIT = 181, + KEY_KP_LEFTPAREN = 182, + KEY_KP_RIGHTPAREN = 183, + KEY_KP_LEFTBRACE = 184, + KEY_KP_RIGHTBRACE = 185, + KEY_KP_TAB = 186, + KEY_KP_BACKSPACE = 187, + KEY_KP_A = 188, + KEY_KP_B = 189, + KEY_KP_C = 190, + KEY_KP_D = 191, + KEY_KP_E = 192, + KEY_KP_F = 193, + KEY_KP_XOR = 194, + KEY_KP_POWER = 195, + KEY_KP_PERCENT = 196, + KEY_KP_LESS = 197, + KEY_KP_GREATER = 198, + KEY_KP_AMPERSAND = 199, + KEY_KP_DBLAMPERSAND = 200, + KEY_KP_VERTICALBAR = 201, + KEY_KP_DBLVERTICALBAR = 202, + KEY_KP_COLON = 203, + KEY_KP_HASH = 204, + KEY_KP_SPACE = 205, + KEY_KP_AT = 206, + KEY_KP_EXCLAM = 207, + KEY_KP_MEMSTORE = 208, + KEY_KP_MEMRECALL = 209, + KEY_KP_MEMCLEAR = 210, + KEY_KP_MEMADD = 211, + KEY_KP_MEMSUBTRACT = 212, + KEY_KP_MEMMULTIPLY = 213, + KEY_KP_MEMDIVIDE = 214, + KEY_KP_PLUSMINUS = 215, + KEY_KP_CLEAR = 216, + KEY_KP_CLEARENTRY = 217, + KEY_KP_BINARY = 218, + KEY_KP_OCTAL = 219, + KEY_KP_DECIMAL = 220, + KEY_KP_HEXADECIMAL = 221, + KEY_LCTRL = 224, + KEY_LSHIFT = 225, + KEY_LALT = 226, + KEY_LGUI = 227, + KEY_RCTRL = 228, + KEY_RSHIFT = 229, + KEY_RALT = 230, + KEY_RGUI = 231, + KEY_MODE = 257, + KEY_AUDIONEXT = 258, + KEY_AUDIOPREV = 259, + KEY_AUDIOSTOP = 260, + KEY_AUDIOPLAY = 261, + KEY_AUDIOMUTE = 262, + KEY_MEDIASELECT = 263, + KEY_WWW = 264, + KEY_MAIL = 265, + KEY_CALCULATOR = 266, + KEY_COMPUTER = 267, + KEY_AC_SEARCH = 268, + KEY_AC_HOME = 269, + KEY_AC_BACK = 270, + KEY_AC_FORWARD = 271, + KEY_AC_STOP = 272, + KEY_AC_REFRESH = 273, + KEY_AC_BOOKMARKS = 274, + KEY_BRIGHTNESSDOWN = 275, + KEY_BRIGHTNESSUP = 276, + KEY_DISPLAYSWITCH = 277, + KEY_KBDILLUMTOGGLE = 278, + KEY_KBDILLUMDOWN = 279, + KEY_KBDILLUMUP = 280, + KEY_EJECT = 281, + KEY_SLEEP = 282, + KEY_APP1 = 283, + KEY_APP2 = 284, + KEY_MOUSE_1 = 285, + KEY_MOUSE_2 = 286, + KEY_MOUSE_3 = 287, + KEY_MOUSE_4 = 288, + KEY_MOUSE_5 = 289, + KEY_MOUSE_6 = 290, + KEY_MOUSE_7 = 291, + KEY_MOUSE_8 = 292, + KEY_MOUSE_9 = 293, + KEY_MOUSE_WHEEL_UP = 294, + KEY_MOUSE_WHEEL_DOWN = 295, + KEY_MOUSE_WHEEL_LEFT = 296, + KEY_MOUSE_WHEEL_RIGHT = 297, + KEY_LAST = 512, }; -inline int KeyToKeycode(int Key) { return (Key>=0x80) ? (Key-0x80)|(1<<30) : Key; }; -inline int KeycodeToKey(int Keycode) { return (Keycode&(1<<30)) ? Keycode-(1<<30)+0x80 : Keycode; }; - #endif diff --git a/src/game/client/components/binds.cpp b/src/game/client/components/binds.cpp index e9592f9d9..129131065 100644 --- a/src/game/client/components/binds.cpp +++ b/src/game/client/components/binds.cpp @@ -121,7 +121,7 @@ void CBinds::SetDefaults() Bind(KEY_F1, "toggle_local_console"); Bind(KEY_F2, "toggle_remote_console"); Bind(KEY_TAB, "+scoreboard"); - Bind(KEY_BACKQUOTE, "+statboard"); + Bind(KEY_EQUALS, "+statboard"); Bind(KEY_F10, "screenshot"); Bind(KEY_A, "+left"); @@ -161,7 +161,6 @@ void CBinds::SetDefaults() Bind(KEY_T, "+show_chat; chat all"); Bind(KEY_Y, "+show_chat; chat team"); - Bind(KEY_Z, "+show_chat; chat team"); // For German keyboards Bind(KEY_U, "+show_chat"); Bind(KEY_I, "+show_chat; chat all /c "); From 0b5942fc044beb627005a2e381cb45ac421f3b12 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 21:43:56 +0200 Subject: [PATCH 04/70] Add special handling for infClass class selection (fixes #794) --- src/engine/shared/storage.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/engine/shared/storage.cpp b/src/engine/shared/storage.cpp index 905e97aaa..2c41cadbf 100644 --- a/src/engine/shared/storage.cpp +++ b/src/engine/shared/storage.cpp @@ -284,7 +284,10 @@ public: { return io_open(pFilename, Flags); } - else if (pFilename[0] == '/' || pFilename[0] == '\\' || str_find(pFilename, "../") != NULL || str_find(pFilename, "..\\") != NULL + if(str_comp_num(pFilename, "mapres/../skins/", 16) == 0) { + pFilename = pFilename + 10; // just start from skins/ + } + if(pFilename[0] == '/' || pFilename[0] == '\\' || str_find(pFilename, "../") != NULL || str_find(pFilename, "..\\") != NULL #ifdef CONF_FAMILY_WINDOWS || (pFilename[0] && pFilename[1] == ':') #endif From 6a76bf9b736b02c48bb484ec1611fff1650c9c40 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 23:06:07 +0200 Subject: [PATCH 05/70] Add some debugging to cmake --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 35d6d734a..9b3733655 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,10 +19,10 @@ set(CLIENT_EXECUTABLE DDNet CACHE STRING "Name of the build client executable") # DEPENDENCIES ######################################################################## -if(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(TARGET_BITS 32) -elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(TARGET_BITS 64) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(TARGET_BITS "64") +else + set(TARGET_BITS "32") endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows") @@ -33,6 +33,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(TARGET_OS "mac") endif() +message(STATUS "Target OS: ${TARGET_OS} ${TARGET_BITS}bit") + function(set_extra_dirs VARIABLE NAME) if(TARGET_BITS AND TARGET_OS) set("EXTRA_${VARIABLE}_LIBDIR" "ddnet-libs/${NAME}/${TARGET_OS}/lib${TARGET_BITS}" PARENT_SCOPE) From a7439af1fff2bea41cab3e2aa33e913fd8d276ce Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 23:12:07 +0200 Subject: [PATCH 06/70] Syntax --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b3733655..86863577d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set(CLIENT_EXECUTABLE DDNet CACHE STRING "Name of the build client executable") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(TARGET_BITS "64") -else +else() set(TARGET_BITS "32") endif() From c53f39c43426d3bcbbf0425fbee95e6bcb36b8d4 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 23:43:01 +0200 Subject: [PATCH 07/70] Let's try the nicer dll names on windows --- bam.lua | 28 ++++++++++++++-------------- cmake/FindCurl.cmake | 2 +- cmake/FindFreetype.cmake | 2 +- cmake/FindOpusfile.cmake | 6 +++--- ddnet-libs | 2 +- other/freetype.lua | 6 +++--- other/mysql.lua | 2 ++ other/sdl.lua | 4 ++-- scripts/make_release.py | 10 +++++----- 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/bam.lua b/bam.lua index 4b7636faa..8239d7e35 100644 --- a/bam.lua +++ b/bam.lua @@ -142,25 +142,25 @@ server_sql_depends = {} if family == "windows" then if platform == "win32" then - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/freetype/lib32/libfreetype-6.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/sdl/lib32/SDL2.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/curl/windows/lib32/libcurl-4.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/freetype/windows/lib32/libfreetype.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/sdl/windows/lib32/SDL2.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/curl/windows/lib32/libcurl.dll")) table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libwinpthread-1.dll")) table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libgcc_s_sjlj-1.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libogg-0.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libopus-0.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libopusfile-0.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libogg.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libopus.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libopusfile.dll")) else - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/freetype/lib64/libfreetype-6.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/sdl/lib64/SDL2.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/curl/windows/lib64/libcurl-4.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/freetype/windows/lib64/libfreetype.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/sdl/windows/lib64/SDL2.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/curl/windows/lib64/libcurl.dll")) table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libwinpthread-1.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libogg-0.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libopus-0.dll")) - table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libopusfile-0.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libogg.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libopus.dll")) + table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libopusfile.dll")) end - table.insert(server_sql_depends, CopyToDirectory(".", "ddnet-libs/mysql/vc2005libs/mysqlcppconn.dll")) - table.insert(server_sql_depends, CopyToDirectory(".", "ddnet-libs/mysql/vc2005libs/libmysql.dll")) + table.insert(server_sql_depends, CopyToDirectory(".", "ddnet-libs/mysql/windows/mysqlcppconn.dll")) + table.insert(server_sql_depends, CopyToDirectory(".", "ddnet-libs/mysql/windows/libmysql.dll")) if config.compiler.driver == "cl" then client_link_other = {ResCompile("other/icons/DDNet_cl.rc")} diff --git a/cmake/FindCurl.cmake b/cmake/FindCurl.cmake index 4b120aaad..c6d72ef31 100644 --- a/cmake/FindCurl.cmake +++ b/cmake/FindCurl.cmake @@ -23,7 +23,7 @@ set(CURL_INCLUDE_DIRS ${CURL_INCLUDEDIR}) string(FIND "${CURL_LIBRARY}" "${PROJECT_SOURCE_DIR}" LOCAL_PATH_POS) if(LOCAL_PATH_POS EQUAL 0 AND TARGET_OS STREQUAL "windows") set(CURL_COPY_FILES - "${EXTRA_CURL_LIBDIR}/libcurl-4.dll" + "${EXTRA_CURL_LIBDIR}/libcurl.dll" ) else() set(CURL_COPY_FILES) diff --git a/cmake/FindFreetype.cmake b/cmake/FindFreetype.cmake index f779f13d4..6e6aa9e60 100644 --- a/cmake/FindFreetype.cmake +++ b/cmake/FindFreetype.cmake @@ -24,7 +24,7 @@ set(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDEDIR}) string(FIND "${FREETYPE_LIBRARY}" "${PROJECT_SOURCE_DIR}" LOCAL_PATH_POS) if(LOCAL_PATH_POS EQUAL 0 AND TARGET_OS STREQUAL "windows") - set(FREETYPE_COPY_FILES "${EXTRA_FREETYPE_LIBDIR}/libfreetype-6.dll") + set(FREETYPE_COPY_FILES "${EXTRA_FREETYPE_LIBDIR}/libfreetype.dll") else() set(FREETYPE_COPY_FILES) endif() diff --git a/cmake/FindOpusfile.cmake b/cmake/FindOpusfile.cmake index 44798c1a4..c9fb5f87a 100644 --- a/cmake/FindOpusfile.cmake +++ b/cmake/FindOpusfile.cmake @@ -24,9 +24,9 @@ set(OPUSFILE_INCLUDE_DIRS ${OPUSFILE_INCLUDEDIR}) string(FIND "${OPUSFILE_LIBRARY}" "${PROJECT_SOURCE_DIR}" LOCAL_PATH_POS) if(LOCAL_PATH_POS EQUAL 0 AND TARGET_OS STREQUAL "windows") set(OPUSFILE_COPY_FILES - "${EXTRA_OPUSFILE_LIBDIR}/libogg-0.dll" - "${EXTRA_OPUSFILE_LIBDIR}/libopus-0.dll" - "${EXTRA_OPUSFILE_LIBDIR}/libopusfile-0.dll" + "${EXTRA_OPUSFILE_LIBDIR}/libogg.dll" + "${EXTRA_OPUSFILE_LIBDIR}/libopus.dll" + "${EXTRA_OPUSFILE_LIBDIR}/libopusfile.dll" "${EXTRA_OPUSFILE_LIBDIR}/libwinpthread-1.dll" ) if (TARGET_BITS EQUAL 32) diff --git a/ddnet-libs b/ddnet-libs index e2e4953af..8135082b8 160000 --- a/ddnet-libs +++ b/ddnet-libs @@ -1 +1 @@ -Subproject commit e2e4953afd0d1f903693cd2a6977b8425b57b1e4 +Subproject commit 8135082b8ea3ad911abcda39ef21bed1da77c62c diff --git a/other/freetype.lua b/other/freetype.lua index 95fedbd75..5a5a8994f 100644 --- a/other/freetype.lua +++ b/other/freetype.lua @@ -30,11 +30,11 @@ FreeType = { elseif option.use_winlib > 0 then if option.use_winlib == 32 then - settings.link.libpath:Add("ddnet-libs/freetype/lib32") + settings.link.libpath:Add("ddnet-libs/freetype/windows/lib32") else - settings.link.libpath:Add("ddnet-libs/freetype/lib64") + settings.link.libpath:Add("ddnet-libs/freetype/windows/lib64") end - settings.link.libs:Add("freetype-6") + settings.link.libs:Add("freetype") end end diff --git a/other/mysql.lua b/other/mysql.lua index 426f1e36c..40bd79449 100644 --- a/other/mysql.lua +++ b/other/mysql.lua @@ -67,6 +67,8 @@ Mysql = { elseif platform == "linux" then settings.link.libpath:Add("ddnet-libs/mysql/linux/lib64") settings.link.libpath:Add("ddnet-libs/mysql/linux/lib32") + elseif platform == "windows" then + settings.link.libpath:Add("ddnet-libs/mysql/windows") end end end diff --git a/other/sdl.lua b/other/sdl.lua index a418542eb..86ce3065d 100644 --- a/other/sdl.lua +++ b/other/sdl.lua @@ -41,9 +41,9 @@ SDL = { if option.use_winlib > 0 then settings.cc.includes:Add("ddnet-libs/sdl/include") if option.use_winlib == 32 then - settings.link.libpath:Add("ddnet-libs/sdl/lib32") + settings.link.libpath:Add("ddnet-libs/sdl/windows/lib32") else - settings.link.libpath:Add("ddnet-libs/sdl/lib64") + settings.link.libpath:Add("ddnet-libs/sdl/windows/lib64") end settings.link.libs:Add("SDL2") settings.link.libs:Add("SDL2main") diff --git a/scripts/make_release.py b/scripts/make_release.py index 3ba487ff5..f81037c0e 100644 --- a/scripts/make_release.py +++ b/scripts/make_release.py @@ -69,14 +69,14 @@ if include_data and not use_bundle: if platform[:3] == "win": shutil.copy("other/config_directory.bat", package_dir) shutil.copy("SDL2.dll", package_dir) - shutil.copy("libfreetype-6.dll", package_dir) + shutil.copy("libfreetype.dll", package_dir) if platform == "win32": shutil.copy("libgcc_s_sjlj-1.dll", package_dir) shutil.copy("libwinpthread-1.dll", package_dir) - shutil.copy("libogg-0.dll", package_dir) - shutil.copy("libopus-0.dll", package_dir) - shutil.copy("libopusfile-0.dll", package_dir) - shutil.copy("libcurl-4.dll", package_dir) + shutil.copy("libogg.dll", package_dir) + shutil.copy("libopus.dll", package_dir) + shutil.copy("libopusfile.dll", package_dir) + shutil.copy("libcurl.dll", package_dir) if include_exe and not use_bundle: shutil.copy(name+exe_ext, package_dir) From 7d26c1fa38aadbdc9d7c0146de06de45f6c24a11 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 23:47:53 +0200 Subject: [PATCH 08/70] bam fix --- bam.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bam.lua b/bam.lua index 8239d7e35..5fcc72b55 100644 --- a/bam.lua +++ b/bam.lua @@ -324,8 +324,8 @@ function build(settings) client_settings.link.libs:Add("opengl32") client_settings.link.libs:Add("glu32") client_settings.link.libs:Add("winmm") - client_settings.link.libs:Add("libopusfile-0") - client_settings.link.libs:Add("curl-4") + client_settings.link.libs:Add("libopusfile") + client_settings.link.libs:Add("curl") if string.find(settings.config_name, "sql") then server_settings.link.libpath:Add("ddnet-libs/mysql/vc2005libs") server_settings.link.libs:Add("mysqlcppconn") From 0db98b218b32a56bde81e16fa216bf9f2bddb87d Mon Sep 17 00:00:00 2001 From: def Date: Fri, 21 Jul 2017 23:54:58 +0200 Subject: [PATCH 09/70] Fix icons --- CMakeLists.txt | 12 ++++++++++-- bam.lua | 4 ++-- other/icons/{DDNet_srv_cl.rc => DDNet-Server_cl.rc} | 0 .../icons/{DDNet_srv_gcc.rc => DDNet-Server_gcc.rc} | 0 4 files changed, 12 insertions(+), 4 deletions(-) rename other/icons/{DDNet_srv_cl.rc => DDNet-Server_cl.rc} (100%) rename other/icons/{DDNet_srv_gcc.rc => DDNet-Server_gcc.rc} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86863577d..fa53f3bf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -295,7 +295,11 @@ if(CLIENT) ) if(TARGET_OS STREQUAL "windows") - set(CLIENT_ICON "other/icons/DDNet.rc") + if(MSVC) + set(CLIENT_ICON "other/icons/DDNet_cl.rc") + else() + set(CLIENT_ICON "other/icons/DDNet_gcc.rc") + endif() else() set(CLIENT_ICON) endif() @@ -333,7 +337,11 @@ file(GLOB_RECURSE GAME_SERVER "src/game/server/*.cpp" "src/game/server/*.h") set(GAME_GENERATED_SERVER "src/game/generated/server_data.cpp" "src/game/generated/server_data.h") set(SERVER_SRC ${ENGINE_SERVER} ${GAME_SERVER} ${GAME_GENERATED_SERVER}) if(TARGET_OS STREQUAL "windows") - set(SERVER_ICON "other/icons/DDNet-Server.rc") + if(MSVC) + set(CLIENT_ICON "other/icons/DDNet-Server_cl.rc") + else() + set(CLIENT_ICON "other/icons/DDNet-Server_gcc.rc") + endif() else() set(SERVER_ICON) endif() diff --git a/bam.lua b/bam.lua index 5fcc72b55..01c55ca59 100644 --- a/bam.lua +++ b/bam.lua @@ -164,10 +164,10 @@ if family == "windows" then if config.compiler.driver == "cl" then client_link_other = {ResCompile("other/icons/DDNet_cl.rc")} - server_link_other = {ResCompile("other/icons/DDNet_srv_cl.rc")} + server_link_other = {ResCompile("other/icons/DDNet-Server_cl.rc")} elseif config.compiler.driver == "gcc" then client_link_other = {ResCompile("other/icons/DDNet_gcc.rc")} - server_link_other = {ResCompile("other/icons/DDNet_srv_gcc.rc")} + server_link_other = {ResCompile("other/icons/DDNet-Server_gcc.rc")} end end diff --git a/other/icons/DDNet_srv_cl.rc b/other/icons/DDNet-Server_cl.rc similarity index 100% rename from other/icons/DDNet_srv_cl.rc rename to other/icons/DDNet-Server_cl.rc diff --git a/other/icons/DDNet_srv_gcc.rc b/other/icons/DDNet-Server_gcc.rc similarity index 100% rename from other/icons/DDNet_srv_gcc.rc rename to other/icons/DDNet-Server_gcc.rc From 6b9386ce86d1f66086167d8157ddd27ce48b139d Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 00:02:00 +0200 Subject: [PATCH 10/70] Windows compiler fix --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa53f3bf1..6c5cbf1c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -446,6 +446,7 @@ foreach(target ${TARGETS}) target_compile_options(${target} PRIVATE /EHsc) # Only catch C++ exceptions with catch. target_compile_options(${target} PRIVATE /GS) # Protect the stack pointer. target_compile_options(${target} PRIVATE /wd4996) # Use of non-_s functions. + target_compile_options(${target} PRIVATE /SAFESEH:NO) # No Windows 8 store elseif(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU) if(ENABLE_STACK_PROTECTOR) target_compile_options(${target} PRIVATE -fstack-protector-all) # Protect the stack pointer. From 609adcfe8ce153e7e998fb513d1e4858e258640b Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 00:20:29 +0200 Subject: [PATCH 11/70] Windows linker fix --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c5cbf1c9..1940ad1e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -446,7 +446,7 @@ foreach(target ${TARGETS}) target_compile_options(${target} PRIVATE /EHsc) # Only catch C++ exceptions with catch. target_compile_options(${target} PRIVATE /GS) # Protect the stack pointer. target_compile_options(${target} PRIVATE /wd4996) # Use of non-_s functions. - target_compile_options(${target} PRIVATE /SAFESEH:NO) # No Windows 8 store + target_link_libraries(${target} INTERFACE "-SAFESEH:NO") # No Windows 8 store elseif(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU) if(ENABLE_STACK_PROTECTOR) target_compile_options(${target} PRIVATE -fstack-protector-all) # Protect the stack pointer. From 8082a461ceffd212b1933dc77e258916e6918bfa Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 00:27:52 +0200 Subject: [PATCH 12/70] Windows linker fix --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1940ad1e1..aa775593a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,6 +438,10 @@ source_group_tree(src) set(TARGETS ${TARGETS_OWN} ${TARGETS_DEP}) +if(MSVC) + target_link_libraries(${TARGET_CLIENT} PRIVATE "-SAFESEH:NO") # No Windows 8 store +endif() + foreach(target ${TARGETS}) if(MSVC) set(DBG $,$>) @@ -446,7 +450,6 @@ foreach(target ${TARGETS}) target_compile_options(${target} PRIVATE /EHsc) # Only catch C++ exceptions with catch. target_compile_options(${target} PRIVATE /GS) # Protect the stack pointer. target_compile_options(${target} PRIVATE /wd4996) # Use of non-_s functions. - target_link_libraries(${target} INTERFACE "-SAFESEH:NO") # No Windows 8 store elseif(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU) if(ENABLE_STACK_PROTECTOR) target_compile_options(${target} PRIVATE -fstack-protector-all) # Protect the stack pointer. From be8a149d12ffe839afba9a7a8cd2f155c34dab65 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 09:15:28 +0200 Subject: [PATCH 13/70] We want Y axis falloff on both speakers --- src/engine/client/sound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index b58d39d41..cd93a4abd 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -215,8 +215,8 @@ static void Mix(short *pFinalOut, unsigned Frames) } { - Lvol *= FalloffX; - Rvol *= FalloffX; + Lvol *= FalloffX * FalloffY; + Rvol *= FalloffX * FalloffY; } } else From 39b0c9282f94d9caa38072eb445fe6d63f23a653 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 09:59:27 +0200 Subject: [PATCH 14/70] SAFESEH:NO --- CMakeLists.txt | 2 +- ddnet-libs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa775593a..c4e815600 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -439,7 +439,7 @@ source_group_tree(src) set(TARGETS ${TARGETS_OWN} ${TARGETS_DEP}) if(MSVC) - target_link_libraries(${TARGET_CLIENT} PRIVATE "-SAFESEH:NO") # No Windows 8 store + target_link_libraries(${TARGET_CLIENT} -SAFESEH:NO) # No Windows 8 store endif() foreach(target ${TARGETS}) diff --git a/ddnet-libs b/ddnet-libs index 8135082b8..856f9c803 160000 --- a/ddnet-libs +++ b/ddnet-libs @@ -1 +1 @@ -Subproject commit 8135082b8ea3ad911abcda39ef21bed1da77c62c +Subproject commit 856f9c8039af923d54659c40ad45d148f62162df From 2fb58359802bac123d51ae9cae754caee1e93c9d Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 11:07:17 +0200 Subject: [PATCH 15/70] Update json-parser to 1.1.0, zlib to 1.2.11 --- ddnet-libs | 2 +- src/engine/client/serverbrowser.cpp | 2 +- src/engine/client/updater.cpp | 2 +- src/engine/external/json-parser/LICENSE | 26 + src/engine/external/json-parser/VERSION | 1 + src/engine/external/json-parser/json.c | 445 ++++++++---- src/engine/external/json-parser/json.h | 125 +++- src/engine/external/wavpack/VERSION | 2 +- src/engine/external/zlib/VERSION | 2 +- src/engine/external/zlib/adler32.c | 21 +- src/engine/external/zlib/compress.c | 42 +- src/engine/external/zlib/crc32.c | 41 +- src/engine/external/zlib/deflate.c | 860 +++++++++++++++--------- src/engine/external/zlib/deflate.h | 35 +- src/engine/external/zlib/gzguts.h | 23 +- src/engine/external/zlib/gzlib.c | 31 +- src/engine/external/zlib/gzread.c | 158 +++-- src/engine/external/zlib/gzwrite.c | 334 +++++---- src/engine/external/zlib/infback.c | 4 +- src/engine/external/zlib/inffast.c | 85 +-- src/engine/external/zlib/inflate.c | 123 +++- src/engine/external/zlib/inflate.h | 11 +- src/engine/external/zlib/inftrees.c | 26 +- src/engine/external/zlib/trees.c | 99 ++- src/engine/external/zlib/uncompr.c | 114 ++-- src/engine/external/zlib/zconf.h | 41 +- src/engine/external/zlib/zlib.h | 444 +++++++----- src/engine/external/zlib/zutil.c | 49 +- src/engine/external/zlib/zutil.h | 52 +- 29 files changed, 2053 insertions(+), 1147 deletions(-) create mode 100644 src/engine/external/json-parser/LICENSE create mode 100644 src/engine/external/json-parser/VERSION diff --git a/ddnet-libs b/ddnet-libs index 856f9c803..2fd77d026 160000 --- a/ddnet-libs +++ b/ddnet-libs @@ -1 +1 @@ -Subproject commit 856f9c8039af923d54659c40ad45d148f62162df +Subproject commit 2fd77d02664b32569ad5d388d3c0d2141b593a11 diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 003540ded..0d370981d 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -931,7 +931,7 @@ void CServerBrowser::LoadDDNet() io_close(File); // parse JSON - json_value *pCountries = json_parse(aBuf); + json_value *pCountries = json_parse(aBuf, sizeof(aBuf)); if (pCountries && pCountries->type == json_array) { diff --git a/src/engine/client/updater.cpp b/src/engine/client/updater.cpp index f8340ca5a..abaf55d9d 100644 --- a/src/engine/client/updater.cpp +++ b/src/engine/client/updater.cpp @@ -165,7 +165,7 @@ void CUpdater::ParseUpdate() io_read(File, aBuf, sizeof(aBuf)); io_close(File); - json_value *pVersions = json_parse(aBuf); + json_value *pVersions = json_parse(aBuf, sizeof(aBuf)); if(pVersions && pVersions->type == json_array) { diff --git a/src/engine/external/json-parser/LICENSE b/src/engine/external/json-parser/LICENSE new file mode 100644 index 000000000..1aee375e0 --- /dev/null +++ b/src/engine/external/json-parser/LICENSE @@ -0,0 +1,26 @@ + + Copyright (C) 2012, 2013 James McLaughlin et al. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + diff --git a/src/engine/external/json-parser/VERSION b/src/engine/external/json-parser/VERSION new file mode 100644 index 000000000..9084fa2f7 --- /dev/null +++ b/src/engine/external/json-parser/VERSION @@ -0,0 +1 @@ +1.1.0 diff --git a/src/engine/external/json-parser/json.c b/src/engine/external/json-parser/json.c index 6637c2da5..f60dadbca 100644 --- a/src/engine/external/json-parser/json.c +++ b/src/engine/external/json-parser/json.c @@ -1,7 +1,6 @@ - -/* vim: set et ts=3 sw=3 ft=c: +/* vim: set et ts=3 sw=3 sts=3 ft=c: * - * Copyright (C) 2012 James McLaughlin et al. All rights reserved. + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. * https://github.com/udp/json-parser * * Redistribution and use in source and binary forms, with or without @@ -36,50 +35,58 @@ #endif #endif -#ifdef __cplusplus - const struct _json_value json_value_none; /* zero-d by ctor */ -#else - const struct _json_value json_value_none = { 0 }; -#endif +const struct _json_value json_value_none; -#include #include #include #include #include -typedef unsigned short json_uchar; +typedef unsigned int json_uchar; static unsigned char hex_value (json_char c) { - if (c >= 'A' && c <= 'F') - return (c - 'A') + 10; - - if (c >= 'a' && c <= 'f') - return (c - 'a') + 10; - - if (c >= '0' && c <= '9') + if (isdigit(c)) return c - '0'; - return 0xFF; + switch (c) { + case 'a': case 'A': return 0x0A; + case 'b': case 'B': return 0x0B; + case 'c': case 'C': return 0x0C; + case 'd': case 'D': return 0x0D; + case 'e': case 'E': return 0x0E; + case 'f': case 'F': return 0x0F; + default: return 0xFF; + } } typedef struct { - json_settings settings; - int first_pass; - unsigned long used_memory; unsigned int uint_max; unsigned long ulong_max; + json_settings settings; + int first_pass; + + const json_char * ptr; + unsigned int cur_line, cur_col; + } json_state; +static void * default_alloc (size_t size, int zero, void * user_data) +{ + return zero ? calloc (1, size) : malloc (size); +} + +static void default_free (void * ptr, void * user_data) +{ + free (ptr); +} + static void * json_alloc (json_state * state, unsigned long size, int zero) { - void * mem; - if ((state->ulong_max - state->used_memory) < size) return 0; @@ -89,14 +96,12 @@ static void * json_alloc (json_state * state, unsigned long size, int zero) return 0; } - if (! (mem = zero ? calloc (size, 1) : malloc (size))) - return 0; - - return mem; + return state->settings.mem_alloc (size, zero, state->settings.user_data); } -static int new_value - (json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type) +static int new_value (json_state * state, + json_value ** top, json_value ** root, json_value ** alloc, + json_type type) { json_value * value; int values_size; @@ -155,10 +160,11 @@ static int new_value return 1; } - value = (json_value *) json_alloc (state, sizeof (json_value), 1); - - if (!value) + if (! (value = (json_value *) json_alloc + (state, sizeof (json_value) + state->settings.value_extra, 1))) + { return 0; + } if (!*root) *root = value; @@ -166,6 +172,11 @@ static int new_value value->type = type; value->parent = *top; + #ifdef JSON_TRACK_SOURCE + value->line = state->cur_line; + value->col = state->cur_col; + #endif + if (*alloc) (*alloc)->_reserved.next_alloc = value; @@ -174,38 +185,67 @@ static int new_value return 1; } -#define e_off \ - ((int) (i - cur_line_begin)) - #define whitespace \ - case '\n': ++ cur_line; cur_line_begin = i; \ + case '\n': ++ state.cur_line; state.cur_col = 0; \ case ' ': case '\t': case '\r' #define string_add(b) \ do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); -const static long - flag_next = 1, flag_reproc = 2, flag_need_comma = 4, flag_seek_value = 8, - flag_escaped = 16, flag_string = 32, flag_need_colon = 64, flag_done = 128, - flag_num_negative = 256, flag_num_zero = 512, flag_num_e = 1024, - flag_num_e_got_sign = 2048, flag_num_e_negative = 4096; +#define line_and_col \ + state.cur_line, state.cur_col -json_value * json_parse_ex (json_settings * settings, const json_char * json, char * error_buf) +static const long + flag_next = 1 << 0, + flag_reproc = 1 << 1, + flag_need_comma = 1 << 2, + flag_seek_value = 1 << 3, + flag_escaped = 1 << 4, + flag_string = 1 << 5, + flag_need_colon = 1 << 6, + flag_done = 1 << 7, + flag_num_negative = 1 << 8, + flag_num_zero = 1 << 9, + flag_num_e = 1 << 10, + flag_num_e_got_sign = 1 << 11, + flag_num_e_negative = 1 << 12, + flag_line_comment = 1 << 13, + flag_block_comment = 1 << 14; + +json_value * json_parse_ex (json_settings * settings, + const json_char * json, + size_t length, + char * error_buf) { - json_char error [128]; - unsigned int cur_line; - const json_char * cur_line_begin, * i; + json_char error [json_error_max]; + const json_char * end; json_value * top, * root, * alloc = 0; - json_state state; + json_state state = { 0 }; long flags; - long num_digits, num_fraction, num_e; + long num_digits = 0, num_e = 0; + json_int_t num_fraction = 0; + + /* Skip UTF-8 BOM + */ + if (length >= 3 && ((unsigned char) json [0]) == 0xEF + && ((unsigned char) json [1]) == 0xBB + && ((unsigned char) json [2]) == 0xBF) + { + json += 3; + length -= 3; + } error[0] = '\0'; - num_digits = num_fraction = num_e = 0; + end = (json + length); - memset (&state, 0, sizeof (json_state)); memcpy (&state.settings, settings, sizeof (json_settings)); + if (!state.settings.mem_alloc) + state.settings.mem_alloc = default_alloc; + + if (!state.settings.mem_free) + state.settings.mem_free = default_free; + memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); @@ -216,41 +256,22 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch { json_uchar uchar; unsigned char uc_b1, uc_b2, uc_b3, uc_b4; - json_char * string; - unsigned int string_length; + json_char * string = 0; + unsigned int string_length = 0; top = root = 0; flags = flag_seek_value; - string_length = 0; - string = 0; - cur_line = 1; - cur_line_begin = json; + state.cur_line = 1; - for (i = json ;; ++ i) + for (state.ptr = json ;; ++ state.ptr) { - json_char b = *i; - - if (flags & flag_done) - { - if (!b) - break; - - switch (b) - { - whitespace: - continue; - - default: - sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b); - goto e_failed; - }; - } - + json_char b = (state.ptr == end ? 0 : *state.ptr); + if (flags & flag_string) { if (!b) - { sprintf (error, "Unexpected EOF in string (at %d:%d)", cur_line, e_off); + { sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col); goto e_failed; } @@ -270,19 +291,41 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch case 't': string_add ('\t'); break; case 'u': - if ((uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF - || (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF) + if (end - state.ptr < 4 || + (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) { - sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off); + sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); goto e_failed; } - uc_b1 = uc_b1 * 16 + uc_b2; - uc_b2 = uc_b3 * 16 + uc_b4; + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar = (uc_b1 << 8) | uc_b2; - uchar = ((json_char) uc_b1) * 256 + uc_b2; + if ((uchar & 0xF800) == 0xD800) { + json_uchar uchar2; + + if (end - state.ptr < 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' || + (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) + { + sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); + goto e_failed; + } - if (sizeof (json_char) >= sizeof (json_uchar) || (uc_b1 == 0 && uc_b2 <= 0x7F)) + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar2 = (uc_b1 << 8) | uc_b2; + + uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); + } + + if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F)) { string_add ((json_char) uchar); break; @@ -293,19 +336,32 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch if (state.first_pass) string_length += 2; else - { string [string_length ++] = 0xC0 | ((uc_b2 & 0xC0) >> 6) | ((uc_b1 & 0x7) << 2); - string [string_length ++] = 0x80 | (uc_b2 & 0x3F); + { string [string_length ++] = 0xC0 | (uchar >> 6); + string [string_length ++] = 0x80 | (uchar & 0x3F); } break; } + if (uchar <= 0xFFFF) { + if (state.first_pass) + string_length += 3; + else + { string [string_length ++] = 0xE0 | (uchar >> 12); + string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); + string [string_length ++] = 0x80 | (uchar & 0x3F); + } + + break; + } + if (state.first_pass) - string_length += 3; + string_length += 4; else - { string [string_length ++] = 0xE0 | ((uc_b1 & 0xF0) >> 4); - string [string_length ++] = 0x80 | ((uc_b1 & 0xF) << 2) | ((uc_b2 & 0xC0) >> 6); - string [string_length ++] = 0x80 | (uc_b2 & 0x3F); + { string [string_length ++] = 0xF0 | (uchar >> 18); + string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F); + string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); + string [string_length ++] = 0x80 | (uchar & 0x3F); } break; @@ -345,10 +401,13 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch if (state.first_pass) (*(json_char **) &top->u.object.values) += string_length + 1; else - { + { top->u.object.values [top->u.object.length].name = (json_char *) top->_reserved.object_mem; + top->u.object.values [top->u.object.length].name_length + = string_length; + (*(json_char **) &top->_reserved.object_mem) += string_length + 1; } @@ -366,6 +425,85 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch } } + if (state.settings.settings & json_enable_comments) + { + if (flags & (flag_line_comment | flag_block_comment)) + { + if (flags & flag_line_comment) + { + if (b == '\r' || b == '\n' || !b) + { + flags &= ~ flag_line_comment; + -- state.ptr; /* so null can be reproc'd */ + } + + continue; + } + + if (flags & flag_block_comment) + { + if (!b) + { sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col); + goto e_failed; + } + + if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/') + { + flags &= ~ flag_block_comment; + ++ state.ptr; /* skip closing sequence */ + } + + continue; + } + } + else if (b == '/') + { + if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) + { sprintf (error, "%d:%d: Comment not allowed here", line_and_col); + goto e_failed; + } + + if (++ state.ptr == end) + { sprintf (error, "%d:%d: EOF unexpected", line_and_col); + goto e_failed; + } + + switch (b = *state.ptr) + { + case '/': + flags |= flag_line_comment; + continue; + + case '*': + flags |= flag_block_comment; + continue; + + default: + sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b); + goto e_failed; + }; + } + } + + if (flags & flag_done) + { + if (!b) + break; + + switch (b) + { + whitespace: + continue; + + default: + + sprintf (error, "%d:%d: Trailing garbage: `%c`", + state.cur_line, state.cur_col, b); + + goto e_failed; + }; + } + if (flags & flag_seek_value) { switch (b) @@ -375,10 +513,10 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch case ']': - if (top->type == json_array) + if (top && top->type == json_array) flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; - else if (!state.settings.settings & json_relaxed_commas) - { sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off); + else + { sprintf (error, "%d:%d: Unexpected ]", line_and_col); goto e_failed; } @@ -393,7 +531,10 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch continue; } else - { sprintf (error, "%d:%d: Expected , before %c", cur_line, e_off, b); + { + sprintf (error, "%d:%d: Expected , before %c", + state.cur_line, state.cur_col, b); + goto e_failed; } } @@ -405,7 +546,10 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch continue; } else - { sprintf (error, "%d:%d: Expected : before %c", cur_line, e_off, b); + { + sprintf (error, "%d:%d: Expected : before %c", + state.cur_line, state.cur_col, b); + goto e_failed; } } @@ -443,8 +587,11 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch case 't': - if (*(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e') + if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' || + *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e') + { goto e_unknown_value; + } if (!new_value (&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; @@ -456,8 +603,12 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch case 'f': - if (*(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e') + if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' || + *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' || + *(++ state.ptr) != 'e') + { goto e_unknown_value; + } if (!new_value (&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; @@ -467,8 +618,11 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch case 'n': - if (*(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l') + if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' || + *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l') + { goto e_unknown_value; + } if (!new_value (&state, &top, &root, &alloc, json_null)) goto e_alloc_failure; @@ -488,7 +642,13 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch while (isdigit (b) || b == '+' || b == '-' || b == 'e' || b == 'E' || b == '.') { - b = *++ i; + if ( (++ state.ptr) == end) + { + b = 0; + break; + } + + b = *state.ptr; } flags |= flag_next | flag_reproc; @@ -513,7 +673,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch continue; } else - { sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b); + { sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b); goto e_failed; } }; @@ -524,7 +684,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch switch (top->type) { case json_object: - + switch (b) { whitespace: @@ -532,9 +692,8 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch case '"': - if (flags & flag_need_comma && (!state.settings.settings & json_relaxed_commas)) - { - sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off); + if (flags & flag_need_comma) + { sprintf (error, "%d:%d: Expected , before \"", line_and_col); goto e_failed; } @@ -544,7 +703,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch string_length = 0; break; - + case '}': flags = (flags & ~ flag_need_comma) | flag_next; @@ -559,8 +718,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch } default: - - sprintf (error, "%d:%d: Unexpected `%c` in object", cur_line, e_off, b); + sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b); goto e_failed; }; @@ -578,7 +736,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch if (! (flags & flag_num_e)) { if (flags & flag_num_zero) - { sprintf (error, "%d:%d: Unexpected `0` before `%c`", cur_line, e_off, b); + { sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b); goto e_failed; } @@ -615,12 +773,12 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch else if (b == '.' && top->type == json_integer) { if (!num_digits) - { sprintf (error, "%d:%d: Expected digit before `.`", cur_line, e_off); + { sprintf (error, "%d:%d: Expected digit before `.`", line_and_col); goto e_failed; } top->type = json_double; - top->u.dbl = top->u.integer; + top->u.dbl = (double) top->u.integer; num_digits = 0; continue; @@ -631,11 +789,11 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch if (top->type == json_double) { if (!num_digits) - { sprintf (error, "%d:%d: Expected digit after `.`", cur_line, e_off); + { sprintf (error, "%d:%d: Expected digit after `.`", line_and_col); goto e_failed; } - top->u.dbl += ((double) num_fraction) / (pow (10.0, num_digits)); + top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits)); } if (b == 'e' || b == 'E') @@ -645,7 +803,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch if (top->type == json_integer) { top->type = json_double; - top->u.dbl = top->u.integer; + top->u.dbl = (double) top->u.integer; } num_digits = 0; @@ -657,11 +815,12 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch else { if (!num_digits) - { sprintf (error, "%d:%d: Expected digit after `e`", cur_line, e_off); + { sprintf (error, "%d:%d: Expected digit after `e`", line_and_col); goto e_failed; } - top->u.dbl *= pow (10.0, flags & flag_num_e_negative ? - num_e : num_e); + top->u.dbl *= pow (10.0, (double) + (flags & flag_num_e_negative ? - num_e : num_e)); } if (flags & flag_num_negative) @@ -683,7 +842,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch if (flags & flag_reproc) { flags &= ~ flag_reproc; - -- i; + -- state.ptr; } if (flags & flag_next) @@ -700,7 +859,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch if (top->parent->type == json_array) flags |= flag_seek_value; - + if (!state.first_pass) { json_value * parent = top->parent; @@ -742,7 +901,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch e_unknown_value: - sprintf (error, "%d:%d: Unknown value", cur_line, e_off); + sprintf (error, "%d:%d: Unknown value", line_and_col); goto e_failed; e_alloc_failure: @@ -752,7 +911,7 @@ e_alloc_failure: e_overflow: - sprintf (error, "%d:%d: Too long (caught overflow)", cur_line, e_off); + sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col); goto e_failed; e_failed: @@ -771,25 +930,23 @@ e_failed: while (alloc) { top = alloc->_reserved.next_alloc; - free (alloc); + state.settings.mem_free (alloc, state.settings.user_data); alloc = top; } if (!state.first_pass) - json_value_free (root); + json_value_free_ex (&state.settings, root); return 0; } -json_value * json_parse (const json_char * json) +json_value * json_parse (const json_char * json, size_t length) { - json_settings settings; - memset (&settings, 0, sizeof (json_settings)); - - return json_parse_ex (&settings, json, 0); + json_settings settings = { 0 }; + return json_parse_ex (&settings, json, length, 0); } -void json_value_free (json_value * value) +void json_value_free_ex (json_settings * settings, json_value * value) { json_value * cur_value; @@ -806,7 +963,7 @@ void json_value_free (json_value * value) if (!value->u.array.length) { - free (value->u.array.values); + settings->mem_free (value->u.array.values, settings->user_data); break; } @@ -817,7 +974,7 @@ void json_value_free (json_value * value) if (!value->u.object.length) { - free (value->u.object.values); + settings->mem_free (value->u.object.values, settings->user_data); break; } @@ -826,7 +983,7 @@ void json_value_free (json_value * value) case json_string: - free (value->u.string.ptr); + settings->mem_free (value->u.string.ptr, settings->user_data); break; default: @@ -835,9 +992,18 @@ void json_value_free (json_value * value) cur_value = value; value = value->parent; - free (cur_value); + settings->mem_free (cur_value, settings->user_data); } } + +void json_value_free (json_value * value) +{ + json_settings settings = { 0 }; + settings.mem_free = default_free; + json_value_free_ex (&settings, value); +} + +/* DDNet additions */ const struct _json_value *json_object_get (const json_value * object, const char * index) { unsigned int i; @@ -860,7 +1026,18 @@ const struct _json_value *json_array_get (const json_value * array, int index) return array->u.array.values[index]; } -int json_array_length (const json_value * array) { return array->u.array.length; } -const char * json_string_get (const json_value * string) { return string->u.string.ptr; } -int json_int_get (const json_value * integer) { return integer->u.integer; } -int json_boolean_get(const json_value * boolean) { return boolean->u.boolean != 0; } +int json_array_length (const json_value * array) { + return array->u.array.length; +} + +const char * json_string_get (const json_value * string) { + return string->u.string.ptr; +} + +int json_int_get (const json_value * integer) { + return integer->u.integer; +} + +int json_boolean_get(const json_value * boolean) { + return boolean->u.boolean != 0; +} diff --git a/src/engine/external/json-parser/json.h b/src/engine/external/json-parser/json.h index 1a862bde5..cb80c6436 100644 --- a/src/engine/external/json-parser/json.h +++ b/src/engine/external/json-parser/json.h @@ -1,7 +1,7 @@ -/* vim: set et ts=3 sw=3 ft=c: +/* vim: set et ts=3 sw=3 sts=3 ft=c: * - * Copyright (C) 2012 James McLaughlin et al. All rights reserved. + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. * https://github.com/udp/json-parser * * Redistribution and use in source and binary forms, with or without @@ -31,16 +31,21 @@ #ifndef _JSON_H #define _JSON_H -#ifdef _MSC_VER - #define inline __inline -#endif - -#include - #ifndef json_char #define json_char char #endif +#ifndef json_int_t + #ifndef _MSC_VER + #include + #define json_int_t int64_t + #else + #define json_int_t __int64 + #endif +#endif + +#include + #ifdef __cplusplus #include @@ -55,9 +60,19 @@ typedef struct unsigned long max_memory; int settings; + /* Custom allocator support (leave null to use malloc/free) + */ + + void * (* mem_alloc) (size_t, int zero, void * user_data); + void (* mem_free) (void *, void * user_data); + + void * user_data; /* will be passed to mem_alloc and mem_free */ + + size_t value_extra; /* how much extra space to allocate for values? */ + } json_settings; -#define json_relaxed_commas 1 +#define json_enable_comments 0x01 typedef enum { @@ -83,7 +98,7 @@ typedef struct _json_value union { int boolean; - long integer; + json_int_t integer; double dbl; struct @@ -100,10 +115,21 @@ typedef struct _json_value struct { json_char * name; + unsigned int name_length; + struct _json_value * value; } * values; + #if defined(__cplusplus) && __cplusplus >= 201103L + decltype(values) begin () const + { return values; + } + decltype(values) end () const + { return values + length; + } + #endif + } object; struct @@ -111,6 +137,15 @@ typedef struct _json_value unsigned int length; struct _json_value ** values; + #if defined(__cplusplus) && __cplusplus >= 201103L + decltype(values) begin () const + { return values; + } + decltype(values) end () const + { return values + length; + } + #endif + } array; } u; @@ -122,6 +157,14 @@ typedef struct _json_value } _reserved; + #ifdef JSON_TRACK_SOURCE + + /* Location of the value in the source JSON + */ + unsigned int line, col; + + #endif + /* Some C++ operator sugar */ @@ -145,7 +188,7 @@ typedef struct _json_value } inline const struct _json_value &operator [] (const char * index) const - { + { if (type != json_object) return json_value_none; @@ -157,7 +200,7 @@ typedef struct _json_value } inline operator const char * () const - { + { switch (type) { case json_string: @@ -168,30 +211,69 @@ typedef struct _json_value }; } - inline operator long () const - { return u.integer; + inline operator json_int_t () const + { + switch (type) + { + case json_integer: + return u.integer; + + case json_double: + return (json_int_t) u.dbl; + + default: + return 0; + }; } inline operator bool () const - { return u.boolean != 0; + { + if (type != json_boolean) + return false; + + return u.boolean != 0; + } + + inline operator double () const + { + switch (type) + { + case json_integer: + return (double) u.integer; + + case json_double: + return u.dbl; + + default: + return 0; + }; } #endif } json_value; -json_value * json_parse - (const json_char * json); +json_value * json_parse (const json_char * json, + size_t length); -json_value * json_parse_ex - (json_settings * settings, const json_char * json, char * error); +#define json_error_max 128 +json_value * json_parse_ex (json_settings * settings, + const json_char * json, + size_t length, + char * error); void json_value_free (json_value *); + +/* Not usually necessary, unless you used a custom mem_alloc and now want to + * use a custom mem_free. + */ +void json_value_free_ex (json_settings * settings, + json_value *); + +/* DDNet additions */ const struct _json_value *json_object_get (const json_value * object, const char * index); - const struct _json_value *json_array_get (const json_value * array, int index); - int json_array_length (const json_value * array); const char * json_string_get (const json_value * string); int json_int_get (const json_value * integer); @@ -203,3 +285,4 @@ int json_boolean_get(const json_value * boolean); #endif + diff --git a/src/engine/external/wavpack/VERSION b/src/engine/external/wavpack/VERSION index 4e21c89ec..df83b62e9 100644 --- a/src/engine/external/wavpack/VERSION +++ b/src/engine/external/wavpack/VERSION @@ -1 +1 @@ -4.40 \ No newline at end of file +Tiny Decoder 4.40 diff --git a/src/engine/external/zlib/VERSION b/src/engine/external/zlib/VERSION index db6fb4a91..c11470058 100644 --- a/src/engine/external/zlib/VERSION +++ b/src/engine/external/zlib/VERSION @@ -1 +1 @@ -1.2.8 +1.2.11 diff --git a/src/engine/external/zlib/adler32.c b/src/engine/external/zlib/adler32.c index a868f073d..d0be4380a 100644 --- a/src/engine/external/zlib/adler32.c +++ b/src/engine/external/zlib/adler32.c @@ -1,5 +1,5 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler + * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -7,11 +7,9 @@ #include "zutil.h" -#define local static - local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); -#define BASE 65521 /* largest prime smaller than 65536 */ +#define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ @@ -62,10 +60,10 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #endif /* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) +uLong ZEXPORT adler32_z(adler, buf, len) uLong adler; const Bytef *buf; - uInt len; + z_size_t len; { unsigned long sum2; unsigned n; @@ -132,6 +130,15 @@ uLong ZEXPORT adler32(adler, buf, len) return adler | (sum2 << 16); } +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + return adler32_z(adler, buf, len); +} + /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; @@ -156,7 +163,7 @@ local uLong adler32_combine_(adler1, adler2, len2) sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; - if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } diff --git a/src/engine/external/zlib/compress.c b/src/engine/external/zlib/compress.c index 6e9762676..e2db404ab 100644 --- a/src/engine/external/zlib/compress.c +++ b/src/engine/external/zlib/compress.c @@ -1,5 +1,5 @@ /* compress.c -- compress a memory buffer - * Copyright (C) 1995-2005 Jean-loup Gailly. + * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -28,16 +28,11 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) { z_stream stream; int err; + const uInt max = (uInt)-1; + uLong left; - stream.next_in = (z_const Bytef *)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + left = *destLen; + *destLen = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; @@ -46,15 +41,26 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) err = deflateInit(&stream, level); if (err != Z_OK) return err; - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; + stream.next_out = dest; + stream.avail_out = 0; + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; - err = deflateEnd(&stream); - return err; + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; + sourceLen -= stream.avail_in; + } + err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + } while (err == Z_OK); + + *destLen = stream.total_out; + deflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== diff --git a/src/engine/external/zlib/crc32.c b/src/engine/external/zlib/crc32.c index 979a7190a..9580440c0 100644 --- a/src/engine/external/zlib/crc32.c +++ b/src/engine/external/zlib/crc32.c @@ -1,5 +1,5 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler + * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster @@ -30,17 +30,15 @@ #include "zutil.h" /* for STDC and FAR definitions */ -#define local static - /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) && defined(Z_U4) # define BYFOUR #endif #ifdef BYFOUR local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); + const unsigned char FAR *, z_size_t)); local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); + const unsigned char FAR *, z_size_t)); # define TBLS 8 #else # define TBLS 1 @@ -201,10 +199,10 @@ const z_crc_t FAR * ZEXPORT get_crc_table() #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) +unsigned long ZEXPORT crc32_z(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; - uInt len; + z_size_t len; { if (buf == Z_NULL) return 0UL; @@ -235,8 +233,29 @@ unsigned long ZEXPORT crc32(crc, buf, len) return crc ^ 0xffffffffUL; } +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + return crc32_z(crc, buf, len); +} + #ifdef BYFOUR +/* + This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit + integer pointer type. This violates the strict aliasing rule, where a + compiler can assume, for optimization purposes, that two pointers to + fundamentally different types won't ever point to the same memory. This can + manifest as a problem only if one of the pointers is written to. This code + only reads from those pointers. So long as this code remains isolated in + this compilation unit, there won't be a problem. For this reason, this code + should not be copied and pasted into a compilation unit in which other code + writes to the buffer that is passed to these routines. + */ + /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ @@ -247,7 +266,7 @@ unsigned long ZEXPORT crc32(crc, buf, len) local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; - unsigned len; + z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; @@ -278,7 +297,7 @@ local unsigned long crc32_little(crc, buf, len) } /* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ +#define DOBIG4 c ^= *buf4++; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 @@ -287,7 +306,7 @@ local unsigned long crc32_little(crc, buf, len) local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; - unsigned len; + z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; @@ -300,7 +319,6 @@ local unsigned long crc32_big(crc, buf, len) } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - buf4--; while (len >= 32) { DOBIG32; len -= 32; @@ -309,7 +327,6 @@ local unsigned long crc32_big(crc, buf, len) DOBIG4; len -= 4; } - buf4++; buf = (const unsigned char FAR *)buf4; if (len) do { diff --git a/src/engine/external/zlib/deflate.c b/src/engine/external/zlib/deflate.c index 696957705..1ec761448 100644 --- a/src/engine/external/zlib/deflate.c +++ b/src/engine/external/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; + " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -73,6 +73,8 @@ typedef enum { typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ +local int deflateStateCheck OF((z_streamp strm)); +local void slide_hash OF((deflate_state *s)); local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); @@ -84,15 +86,16 @@ local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV +# pragma message("Assembler code may have bugs -- use at your own risk") void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif -#ifdef DEBUG +#ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif @@ -148,21 +151,14 @@ local const config configuration_table[10] = { * meaning. */ -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ -#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) @@ -173,9 +169,9 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ @@ -197,6 +193,37 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +local void slide_hash(s) + deflate_state *s; +{ + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} + /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; @@ -270,7 +297,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ @@ -278,14 +305,15 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ s->wrap = wrap; s->gzhead = Z_NULL; - s->w_bits = windowBits; + s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; - s->hash_bits = memLevel + 7; + s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); @@ -319,6 +347,31 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, return deflateReset(strm); } +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +local int deflateStateCheck (strm) + z_streamp strm; +{ + deflate_state *s; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) + return 1; + return 0; +} + /* ========================================================================= */ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; @@ -331,7 +384,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) unsigned avail; z_const unsigned char *next; - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + if (deflateStateCheck(strm) || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; @@ -388,14 +441,35 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) return Z_OK; } +/* ========================================================================= */ +int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) + z_streamp strm; + Bytef *dictionary; + uInt *dictLength; +{ + deflate_state *s; + uInt len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) + *dictLength = len; + return Z_OK; +} + /* ========================================================================= */ int ZEXPORT deflateResetKeep (strm) z_streamp strm; { deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + if (deflateStateCheck(strm)) { return Z_STREAM_ERROR; } @@ -410,7 +484,11 @@ int ZEXPORT deflateResetKeep (strm) if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : @@ -440,8 +518,8 @@ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head; { - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (strm->state->wrap != 2) return Z_STREAM_ERROR; + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } @@ -452,7 +530,7 @@ int ZEXPORT deflatePending (strm, pending, bits) int *bits; z_streamp strm; { - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) @@ -469,7 +547,7 @@ int ZEXPORT deflatePrime (strm, bits, value) deflate_state *s; int put; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; @@ -494,9 +572,8 @@ int ZEXPORT deflateParams(strm, level, strategy) { deflate_state *s; compress_func func; - int err = Z_OK; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST @@ -510,13 +587,22 @@ int ZEXPORT deflateParams(strm, level, strategy) func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && - strm->total_in != 0) { + s->high_water) { /* Flush the last buffer: */ - err = deflate(strm, Z_BLOCK); - if (err == Z_BUF_ERROR && s->pending == 0) - err = Z_OK; + int err = deflate(strm, Z_BLOCK); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_out == 0) + return Z_BUF_ERROR; } if (s->level != level) { + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) + slide_hash(s); + else + CLEAR_HASH(s); + s->matches = 0; + } s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; @@ -524,7 +610,7 @@ int ZEXPORT deflateParams(strm, level, strategy) s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; - return err; + return Z_OK; } /* ========================================================================= */ @@ -537,12 +623,12 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) { deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - s->good_match = good_length; - s->max_lazy_match = max_lazy; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; s->nice_match = nice_length; - s->max_chain_length = max_chain; + s->max_chain_length = (uInt)max_chain; return Z_OK; } @@ -569,14 +655,13 @@ uLong ZEXPORT deflateBound(strm, sourceLen) { deflate_state *s; uLong complen, wraplen; - Bytef *str; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ - if (strm == Z_NULL || strm->state == Z_NULL) + if (deflateStateCheck(strm)) return complen + 6; /* compute wrapper length */ @@ -588,9 +673,11 @@ uLong ZEXPORT deflateBound(strm, sourceLen) case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; +#ifdef GZIP case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; @@ -607,6 +694,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen += 2; } break; +#endif default: /* for compiler happiness */ wraplen = 6; } @@ -634,10 +722,10 @@ local void putShortMSB (s, b) } /* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; @@ -654,13 +742,23 @@ local void flush_pending(strm) strm->next_out += len; s->pending_out += len; strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; + strm->avail_out -= len; + s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ + } while (0) + /* ========================================================================= */ int ZEXPORT deflate (strm, flush) z_streamp strm; @@ -669,203 +767,21 @@ int ZEXPORT deflate (strm, flush) int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_BLOCK || flush < 0) { + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || + (strm->avail_in != 0 && strm->next_in == Z_NULL) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == Z_NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != Z_NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } -#ifdef GZIP - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - - while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) - break; - } - put_byte(s, s->gzhead->extra[s->gzindex]); - s->gzindex++; - } - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (s->gzindex == s->gzhead->extra_len) { - s->gzindex = 0; - s->status = NAME_STATE; - } - } - else - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) { - s->gzindex = 0; - s->status = COMMENT_STATE; - } - } - else - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) - s->status = HCRC_STATE; - } - else - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) - flush_pending(strm); - if (s->pending + 2 <= s->pending_buf_size) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - } - } - else - s->status = BUSY_STATE; - } -#endif - /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); @@ -894,15 +810,197 @@ int ZEXPORT deflate (strm, flush) ERR_RETURN(strm, Z_BUF_ERROR); } + /* Write the header */ + if (s->status == INIT_STATE) { + /* zlib header */ + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + while (s->pending + left > s->pending_buf_size) { + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + } + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#endif + /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; - bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : - (s->strategy == Z_RLE ? deflate_rle(s, flush) : - (*(configuration_table[s->level].func))(s, flush)); + bstate = s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; @@ -944,7 +1042,6 @@ int ZEXPORT deflate (strm, flush) } } } - Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; @@ -981,18 +1078,9 @@ int ZEXPORT deflateEnd (strm) { int status; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; status = strm->state->status; - if (status != INIT_STATE && - status != EXTRA_STATE && - status != NAME_STATE && - status != COMMENT_STATE && - status != HCRC_STATE && - status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); @@ -1023,7 +1111,7 @@ int ZEXPORT deflateCopy (dest, source) ushf *overlay; - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; } @@ -1073,7 +1161,7 @@ int ZEXPORT deflateCopy (dest, source) * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ -local int read_buf(strm, buf, size) +local unsigned read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; @@ -1097,7 +1185,7 @@ local int read_buf(strm, buf, size) strm->next_in += len; strm->total_in += len; - return (int)len; + return len; } /* =========================================================================== @@ -1151,9 +1239,9 @@ local uInt longest_match(s, cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ + register Bytef *match; /* matched string */ register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ + int best_len = (int)s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; @@ -1188,7 +1276,7 @@ local uInt longest_match(s, cur_match) /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); @@ -1349,7 +1437,11 @@ local uInt longest_match(s, cur_match) #endif /* FASTEST */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + /* =========================================================================== * Check that the match at match_start is indeed a match. */ @@ -1375,7 +1467,7 @@ local void check_match(s, start, match, length) } #else # define check_match(s, start, match, length) -#endif /* DEBUG */ +#endif /* ZLIB_DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. @@ -1390,8 +1482,7 @@ local void check_match(s, start, match, length) local void fill_window(s) deflate_state *s; { - register unsigned n, m; - register Posf *p; + unsigned n; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; @@ -1418,35 +1509,11 @@ local void fill_window(s) */ if (s->strstart >= wsize+MAX_DIST(s)) { - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif + slide_hash(s); more += wsize; } if (s->strm->avail_in == 0) break; @@ -1552,70 +1619,199 @@ local void fill_window(s) if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunites to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. */ - ulg max_block_size = 0xffff; - ulg max_start; + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s->strm); + +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; +#endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + } + s->block_start = s->strstart; + s->insert += MIN(used, s->w_size - s->insert); } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart - 1; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ } - if ((long)s->strstart > s->block_start) - FLUSH_BLOCK(s, 0); - return block_done; + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; } /* =========================================================================== @@ -1892,7 +2088,7 @@ local block_state deflate_rle(s, flush) prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); - s->match_length = MAX_MATCH - (int)(strend - scan); + s->match_length = MAX_MATCH - (uInt)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } diff --git a/src/engine/external/zlib/deflate.h b/src/engine/external/zlib/deflate.h index ce0299edd..23ecdd312 100644 --- a/src/engine/external/zlib/deflate.h +++ b/src/engine/external/zlib/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2012 Jean-loup Gailly + * Copyright (C) 1995-2016 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -51,13 +51,16 @@ #define Buf_size 16 /* size of bit buffer in bi_buf */ -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ /* Stream status */ @@ -83,7 +86,7 @@ typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; @@ -100,10 +103,10 @@ typedef struct internal_state { Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ + ulg pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ + ulg gzindex; /* where in extra, name, or comment */ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ @@ -249,7 +252,7 @@ typedef struct internal_state { uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif @@ -275,7 +278,7 @@ typedef struct internal_state { /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) @@ -309,7 +312,7 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, * used. */ -#ifndef DEBUG +#ifndef ZLIB_DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) @@ -328,8 +331,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ diff --git a/src/engine/external/zlib/gzguts.h b/src/engine/external/zlib/gzguts.h index d87659d03..990a4d251 100644 --- a/src/engine/external/zlib/gzguts.h +++ b/src/engine/external/zlib/gzguts.h @@ -1,5 +1,5 @@ /* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -25,6 +25,10 @@ # include # include #endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif #include #ifdef _WIN32 @@ -35,6 +39,10 @@ # include #endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define WIDECHAR +#endif + #ifdef WINAPI_FAMILY # define open _open # define read _read @@ -95,18 +103,19 @@ # endif #endif -/* unlike snprintf (which is required in C99, yet still not supported by - Microsoft more than a decade later!), _snprintf does not guarantee null - termination of the result -- however this is only used in gzlib.c where +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where the result is assured to fit in the space provided */ -#ifdef _MSC_VER +#if defined(_MSC_VER) && _MSC_VER < 1900 # define snprintf _snprintf #endif #ifndef local # define local static #endif -/* compile with -Dlocal if your debugger can't find static symbols */ +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC @@ -170,7 +179,7 @@ typedef struct { char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ - unsigned char *in; /* input buffer */ + unsigned char *in; /* input buffer (double-sized when writing) */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ diff --git a/src/engine/external/zlib/gzlib.c b/src/engine/external/zlib/gzlib.c index fae202ef8..4105e6aff 100644 --- a/src/engine/external/zlib/gzlib.c +++ b/src/engine/external/zlib/gzlib.c @@ -1,11 +1,11 @@ /* gzlib.c -- zlib functions common to reading and writing gzip files - * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" -#if defined(_WIN32) && !defined(__BORLANDC__) +#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 @@ -94,7 +94,7 @@ local gzFile gz_open(path, fd, mode) const char *mode; { gz_statep state; - size_t len; + z_size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; @@ -188,10 +188,10 @@ local gzFile gz_open(path, fd, mode) } /* save the path name for error messages */ -#ifdef _WIN32 +#ifdef WIDECHAR if (fd == -2) { len = wcstombs(NULL, path, 0); - if (len == (size_t)-1) + if (len == (z_size_t)-1) len = 0; } else @@ -202,7 +202,7 @@ local gzFile gz_open(path, fd, mode) free(state); return NULL; } -#ifdef _WIN32 +#ifdef WIDECHAR if (fd == -2) if (len) wcstombs(state->path, path, len + 1); @@ -211,7 +211,7 @@ local gzFile gz_open(path, fd, mode) else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) - snprintf(state->path, len + 1, "%s", (const char *)path); + (void)snprintf(state->path, len + 1, "%s", (const char *)path); #else strcpy(state->path, path); #endif @@ -239,7 +239,7 @@ local gzFile gz_open(path, fd, mode) /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( -#ifdef _WIN32 +#ifdef WIDECHAR fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); @@ -248,8 +248,10 @@ local gzFile gz_open(path, fd, mode) free(state); return NULL; } - if (state->mode == GZ_APPEND) + if (state->mode == GZ_APPEND) { + LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ state->mode = GZ_WRITE; /* simplify later checks */ + } /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { @@ -291,7 +293,7 @@ gzFile ZEXPORT gzdopen(fd, mode) if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) - snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); #else sprintf(path, "", fd); /* for debugging */ #endif @@ -301,7 +303,7 @@ gzFile ZEXPORT gzdopen(fd, mode) } /* -- see zlib.h -- */ -#ifdef _WIN32 +#ifdef WIDECHAR gzFile ZEXPORT gzopen_w(path, mode) const wchar_t *path; const char *mode; @@ -329,6 +331,8 @@ int ZEXPORT gzbuffer(file, size) return -1; /* check and set requested size */ + if ((size << 1) < size) + return -1; /* need to be able to double it */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; @@ -604,14 +608,13 @@ void ZLIB_INTERNAL gz_error(state, err, msg) return; } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) - snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, - "%s%s%s", state->path, ": ", msg); + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif - return; } #ifndef INT_MAX diff --git a/src/engine/external/zlib/gzread.c b/src/engine/external/zlib/gzread.c index bf4538eb2..956b91ea7 100644 --- a/src/engine/external/zlib/gzread.c +++ b/src/engine/external/zlib/gzread.c @@ -1,5 +1,5 @@ /* gzread.c -- zlib functions for reading gzip files - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -12,6 +12,7 @@ local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); +local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. @@ -24,13 +25,17 @@ local int gz_load(state, buf, len, have) unsigned *have; { int ret; + unsigned get, max = ((unsigned)-1 >> 2) + 1; *have = 0; do { - ret = read(state->fd, buf + *have, len - *have); + get = len - *have; + if (get > max) + get = max; + ret = read(state->fd, buf + *have, get); if (ret <= 0) break; - *have += ret; + *have += (unsigned)ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); @@ -94,10 +99,8 @@ local int gz_look(state) state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { - if (state->out != NULL) - free(state->out); - if (state->in != NULL) - free(state->in); + free(state->out); + free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } @@ -284,33 +287,17 @@ local int gz_skip(state, len) return 0; } -/* -- see zlib.h -- */ -int ZEXPORT gzread(file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - unsigned got, n; +/* Read len bytes into buf from file, or less than len up to the end of the + input. Return the number of bytes read. If zero is returned, either the + end of file was reached, or there was an error. state->err must be + consulted in that case to determine which. */ +local z_size_t gz_read(state, buf, len) gz_statep state; - z_streamp strm; - - /* get internal structure */ - if (file == NULL) - return -1; - state = (gz_statep)file; - strm = &(state->strm); - - /* check that we're reading and that there's no (serious) error */ - if (state->mode != GZ_READ || - (state->err != Z_OK && state->err != Z_BUF_ERROR)) - return -1; - - /* since an int is returned, make sure len fits in one, otherwise return - with an error (this avoids the flaw in the interface) */ - if ((int)len < 0) { - gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); - return -1; - } + voidp buf; + z_size_t len; +{ + z_size_t got; + unsigned n; /* if len is zero, avoid unnecessary operations */ if (len == 0) @@ -320,32 +307,38 @@ int ZEXPORT gzread(file, buf, len) if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) - return -1; + return 0; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { + /* set n to the maximum amount of len that fits in an unsigned int */ + n = -1; + if (n > len) + n = len; + /* first just try copying data from the output buffer */ if (state->x.have) { - n = state->x.have > len ? len : state->x.have; + if (state->x.have < n) + n = state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ - else if (state->eof && strm->avail_in == 0) { + else if (state->eof && state->strm.avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ - else if (state->how == LOOK || len < (state->size << 1)) { + else if (state->how == LOOK || n < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) - return -1; + return 0; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ @@ -353,16 +346,16 @@ int ZEXPORT gzread(file, buf, len) /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ - if (gz_load(state, (unsigned char *)buf, len, &n) == -1) - return -1; + if (gz_load(state, (unsigned char *)buf, n, &n) == -1) + return 0; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ - strm->avail_out = len; - strm->next_out = (unsigned char *)buf; + state->strm.avail_out = n; + state->strm.next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) - return -1; + return 0; n = state->x.have; state->x.have = 0; } @@ -374,8 +367,75 @@ int ZEXPORT gzread(file, buf, len) state->x.pos += n; } while (len); - /* return number of bytes read into user buffer (will fit in int) */ - return (int)got; + /* return number of bytes read into user buffer */ + return got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); + return -1; + } + + /* read len or fewer bytes to buf */ + len = gz_read(state, buf, len); + + /* check for an error */ + if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* return the number of bytes read (this is assured to fit in an int) */ + return (int)len; +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfread(buf, size, nitems, file) + voidp buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* read len or fewer bytes to buf, return the number of full items read */ + return len ? gz_read(state, buf, len) / size : 0; } /* -- see zlib.h -- */ @@ -408,8 +468,8 @@ int ZEXPORT gzgetc(file) return *(state->x.next)++; } - /* nothing there -- try gzread() */ - ret = gzread(file, buf, 1); + /* nothing there -- try gz_read() */ + ret = gz_read(state, buf, 1); return ret < 1 ? -1 : buf[0]; } @@ -451,7 +511,7 @@ int ZEXPORT gzungetc(c, file) if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; - state->x.next[0] = c; + state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; @@ -473,7 +533,7 @@ int ZEXPORT gzungetc(c, file) } state->x.have++; state->x.next--; - state->x.next[0] = c; + state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; diff --git a/src/engine/external/zlib/gzwrite.c b/src/engine/external/zlib/gzwrite.c index aa767fbf6..c7b5651d7 100644 --- a/src/engine/external/zlib/gzwrite.c +++ b/src/engine/external/zlib/gzwrite.c @@ -1,5 +1,5 @@ /* gzwrite.c -- zlib functions for writing gzip files - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,17 +9,19 @@ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); +local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); /* Initialize state for writing a gzip file. Mark initialization by setting - state->size to non-zero. Return -1 on failure or 0 on success. */ + state->size to non-zero. Return -1 on a memory allocation failure, or 0 on + success. */ local int gz_init(state) gz_statep state; { int ret; z_streamp strm = &(state->strm); - /* allocate input buffer */ - state->in = (unsigned char *)malloc(state->want); + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)malloc(state->want << 1); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; @@ -47,6 +49,7 @@ local int gz_init(state) gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } + strm->next_in = NULL; } /* mark state as initialized */ @@ -62,17 +65,17 @@ local int gz_init(state) } /* Compress whatever is at avail_in and next_in and write to the output file. - Return -1 if there is an error writing to the output file, otherwise 0. - flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, - then the deflate() state is reset to start a new gzip stream. If gz->direct - is true, then simply write to the output file without compressing, and - ignore flush. */ + Return -1 if there is an error writing to the output file or if gz_init() + fails to allocate memory, otherwise 0. flush is assumed to be a valid + deflate() flush value. If flush is Z_FINISH, then the deflate() state is + reset to start a new gzip stream. If gz->direct is true, then simply write + to the output file without compressing, and ignore flush. */ local int gz_comp(state, flush) gz_statep state; int flush; { - int ret, got; - unsigned have; + int ret, writ; + unsigned have, put, max = ((unsigned)-1 >> 2) + 1; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ @@ -81,12 +84,16 @@ local int gz_comp(state, flush) /* write directly if requested */ if (state->direct) { - got = write(state->fd, strm->next_in, strm->avail_in); - if (got < 0 || (unsigned)got != strm->avail_in) { - gz_error(state, Z_ERRNO, zstrerror()); - return -1; + while (strm->avail_in) { + put = strm->avail_in > max ? max : strm->avail_in; + writ = write(state->fd, strm->next_in, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in -= (unsigned)writ; + strm->next_in += writ; } - strm->avail_in = 0; return 0; } @@ -97,17 +104,21 @@ local int gz_comp(state, flush) doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { - have = (unsigned)(strm->next_out - state->x.next); - if (have && ((got = write(state->fd, state->x.next, have)) < 0 || - (unsigned)got != have)) { - gz_error(state, Z_ERRNO, zstrerror()); - return -1; + while (strm->next_out > state->x.next) { + put = strm->next_out - state->x.next > (int)max ? max : + (unsigned)(strm->next_out - state->x.next); + writ = write(state->fd, state->x.next, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + state->x.next += writ; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; + state->x.next = state->out; } - state->x.next = strm->next_out; } /* compress */ @@ -129,7 +140,8 @@ local int gz_comp(state, flush) return 0; } -/* Compress len zeros to output. Return -1 on error, 0 on success. */ +/* Compress len zeros to output. Return -1 on a write error or memory + allocation failure by gz_comp(), or 0 on success. */ local int gz_zero(state, len) gz_statep state; z_off64_t len; @@ -161,32 +173,14 @@ local int gz_zero(state, len) return 0; } -/* -- see zlib.h -- */ -int ZEXPORT gzwrite(file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - unsigned put = len; +/* Write len bytes from buf to file. Return the number of bytes written. If + the returned value is less than len, then there was an error. */ +local z_size_t gz_write(state, buf, len) gz_statep state; - z_streamp strm; - - /* get internal structure */ - if (file == NULL) - return 0; - state = (gz_statep)file; - strm = &(state->strm); - - /* check that we're writing and that there's no error */ - if (state->mode != GZ_WRITE || state->err != Z_OK) - return 0; - - /* since an int is returned, make sure len fits in one, otherwise return - with an error (this avoids the flaw in the interface) */ - if ((int)len < 0) { - gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); - return 0; - } + voidpc buf; + z_size_t len; +{ + z_size_t put = len; /* if len is zero, avoid unnecessary operations */ if (len == 0) @@ -209,14 +203,15 @@ int ZEXPORT gzwrite(file, buf, len) do { unsigned have, copy; - if (strm->avail_in == 0) - strm->next_in = state->in; - have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (state->strm.avail_in == 0) + state->strm.next_in = state->in; + have = (unsigned)((state->strm.next_in + state->strm.avail_in) - + state->in); copy = state->size - have; if (copy > len) copy = len; memcpy(state->in + have, buf, copy); - strm->avail_in += copy; + state->strm.avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; @@ -226,19 +221,83 @@ int ZEXPORT gzwrite(file, buf, len) } else { /* consume whatever's left in the input buffer */ - if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ - strm->avail_in = len; - strm->next_in = (z_const Bytef *)buf; - state->x.pos += len; - if (gz_comp(state, Z_NO_FLUSH) == -1) - return 0; + state->strm.next_in = (z_const Bytef *)buf; + do { + unsigned n = (unsigned)-1; + if (n > len) + n = len; + state->strm.avail_in = n; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + len -= n; + } while (len); } - /* input was all buffered or compressed (put will fit in int) */ - return (int)put; + /* input was all buffered or compressed */ + return put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* write len bytes from buf (the return value will fit in an int) */ + return (int)gz_write(state, buf, len); +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) + voidpc buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* write len bytes to buf, return the number of full items written */ + return len ? gz_write(state, buf, len) / size : 0; } /* -- see zlib.h -- */ @@ -275,7 +334,7 @@ int ZEXPORT gzputc(file, c) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); if (have < state->size) { - state->in[have] = c; + state->in[have] = (unsigned char)c; strm->avail_in++; state->x.pos++; return c & 0xff; @@ -283,8 +342,8 @@ int ZEXPORT gzputc(file, c) } /* no room in buffer or not initialized, use gz_write() */ - buf[0] = c; - if (gzwrite(file, buf, 1) != 1) + buf[0] = (unsigned char)c; + if (gz_write(state, buf, 1) != 1) return -1; return c & 0xff; } @@ -295,11 +354,21 @@ int ZEXPORT gzputs(file, str) const char *str; { int ret; - unsigned len; + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; /* write string */ - len = (unsigned)strlen(str); - ret = gzwrite(file, str, len); + len = strlen(str); + ret = gz_write(state, str, len); return ret == 0 && len != 0 ? -1 : ret; } @@ -309,63 +378,73 @@ int ZEXPORT gzputs(file, str) /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { - int size, len; + int len; + unsigned left; + char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) - return -1; + return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) - return 0; + return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) - return 0; + return state->err; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return 0; + return state->err; } - /* consume whatever's left in the input buffer */ - if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) - return 0; - - /* do the printf() into the input buffer, put length in len */ - size = (int)(state->size); - state->in[size - 1] = 0; + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); + next[state->size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void - (void)vsprintf((char *)(state->in), format, va); - for (len = 0; len < size; len++) - if (state->in[len] == 0) break; + (void)vsprintf(next, format, va); + for (len = 0; len < state->size; len++) + if (next[len] == 0) break; # else - len = vsprintf((char *)(state->in), format, va); + len = vsprintf(next, format, va); # endif #else # ifdef HAS_vsnprintf_void - (void)vsnprintf((char *)(state->in), size, format, va); - len = strlen((char *)(state->in)); + (void)vsnprintf(next, state->size, format, va); + len = strlen(next); # else - len = vsnprintf((char *)(state->in), size, format, va); + len = vsnprintf(next, state->size, format, va); # endif #endif /* check that printf() results fit in buffer */ - if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) return 0; - /* update buffer and position, defer compression until needed */ - strm->avail_in = (unsigned)len; - strm->next_in = state->in; + /* update buffer and position, compress first half if past that */ + strm->avail_in += (unsigned)len; state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memcpy(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } return len; } @@ -390,73 +469,82 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { - int size, len; + unsigned len, left; + char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) - return -1; + return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) - return 0; + return Z_STREAM_ERROR; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) - return 0; + return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) - return 0; + return state->error; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return 0; + return state->error; } - /* consume whatever's left in the input buffer */ - if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) - return 0; - - /* do the printf() into the input buffer, put length in len */ - size = (int)(state->size); - state->in[size - 1] = 0; + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(strm->next_in + strm->avail_in); + next[state->size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void - sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) - if (state->in[len] == 0) break; + if (next[len] == 0) + break; # else - len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void - snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen((char *)(state->in)); + snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(next); # else - len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, - a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, - a19, a20); + len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ - if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + if (len == 0 || len >= state->size || next[state->size - 1] != 0) return 0; - /* update buffer and position, defer compression until needed */ - strm->avail_in = (unsigned)len; - strm->next_in = state->in; + /* update buffer and position, compress first half if past that */ + strm->avail_in += len; state->x.pos += len; - return len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memcpy(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return (int)len; } #endif @@ -470,7 +558,7 @@ int ZEXPORT gzflush(file, flush) /* get internal structure */ if (file == NULL) - return -1; + return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing and that there's no error */ @@ -485,11 +573,11 @@ int ZEXPORT gzflush(file, flush) if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return -1; + return state->err; } /* compress remaining data with requested flush */ - gz_comp(state, flush); + (void)gz_comp(state, flush); return state->err; } @@ -520,13 +608,13 @@ int ZEXPORT gzsetparams(file, level, strategy) if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return -1; + return state->err; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ - if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) + if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) return state->err; deflateParams(strm, level, strategy); } diff --git a/src/engine/external/zlib/infback.c b/src/engine/external/zlib/infback.c index f3833c2e4..59679ecbf 100644 --- a/src/engine/external/zlib/infback.c +++ b/src/engine/external/zlib/infback.c @@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2011 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -61,7 +61,7 @@ int stream_size; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; - state->wbits = windowBits; + state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; diff --git a/src/engine/external/zlib/inffast.c b/src/engine/external/zlib/inffast.c index bda59ceb6..0dbd1dbc0 100644 --- a/src/engine/external/zlib/inffast.c +++ b/src/engine/external/zlib/inffast.c @@ -1,5 +1,5 @@ /* inffast.c -- fast decoding - * Copyright (C) 1995-2008, 2010, 2013 Mark Adler + * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -8,26 +8,9 @@ #include "inflate.h" #include "inffast.h" -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") #else -# define OFF 1 -# define PUP(a) *++(a) -#endif /* Decode literal, length, and distance codes and write out the resulting @@ -96,9 +79,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; + in = strm->next_in; last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; + out = strm->next_out; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT @@ -119,9 +102,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ input data or output space */ do { if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } here = lcode[hold & lmask]; @@ -134,14 +117,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); - PUP(out) = (unsigned char)(here.val); + *out++ = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); @@ -150,9 +133,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } here = dcode[hold & dmask]; @@ -165,10 +148,10 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } } @@ -196,30 +179,30 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { - PUP(out) = 0; + *out++ = 0; } while (--len); continue; } len -= op - whave; do { - PUP(out) = 0; + *out++ = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--len); continue; } #endif } - from = window - OFF; + from = window; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } @@ -230,14 +213,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ if (op < len) { /* some from end of window */ len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); - from = window - OFF; + from = window; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } @@ -248,35 +231,35 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ if (op < len) { /* some from window */ len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; len -= 3; } if (len) { - PUP(out) = PUP(from); + *out++ = *from++; if (len > 1) - PUP(out) = PUP(from); + *out++ = *from++; } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; len -= 3; } while (len > 2); if (len) { - PUP(out) = PUP(from); + *out++ = *from++; if (len > 1) - PUP(out) = PUP(from); + *out++ = *from++; } } } @@ -313,8 +296,8 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ hold &= (1U << bits) - 1; /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; + strm->next_in = in; + strm->next_out = out; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); diff --git a/src/engine/external/zlib/inflate.c b/src/engine/external/zlib/inflate.c index 870f89bb4..ac333e8c2 100644 --- a/src/engine/external/zlib/inflate.c +++ b/src/engine/external/zlib/inflate.c @@ -1,5 +1,5 @@ /* inflate.c -- zlib decompression - * Copyright (C) 1995-2012 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -92,6 +92,7 @@ #endif /* function prototypes */ +local int inflateStateCheck OF((z_streamp strm)); local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); @@ -101,12 +102,26 @@ local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); +local int inflateStateCheck(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; @@ -131,7 +146,7 @@ z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; @@ -147,7 +162,7 @@ int windowBits; struct inflate_state FAR *state; /* get the state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ @@ -156,7 +171,7 @@ int windowBits; windowBits = -windowBits; } else { - wrap = (windowBits >> 4) + 1; + wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; @@ -210,7 +225,9 @@ int stream_size; if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; + state->strm = strm; state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); @@ -234,17 +251,17 @@ int value; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } - if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; - state->hold += value << state->bits; - state->bits += bits; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; return Z_OK; } @@ -625,7 +642,7 @@ int flush; static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; @@ -645,6 +662,8 @@ int flush; NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); @@ -672,7 +691,7 @@ int flush; len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; - else if (len > state->wbits) { + if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; @@ -699,14 +718,16 @@ int flush; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); - if (state->flags & 0x0200) CRC2(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; - if (state->flags & 0x0200) CRC4(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: @@ -715,7 +736,8 @@ int flush; state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } - if (state->flags & 0x0200) CRC2(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: @@ -724,7 +746,8 @@ int flush; state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; - if (state->flags & 0x0200) CRC2(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) @@ -742,7 +765,7 @@ int flush; len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } - if (state->flags & 0x0200) + if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; @@ -761,9 +784,9 @@ int flush; if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) - state->head->name[state->length++] = len; + state->head->name[state->length++] = (Bytef)len; } while (len && copy < have); - if (state->flags & 0x0200) + if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; @@ -782,9 +805,9 @@ int flush; if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) - state->head->comment[state->length++] = len; + state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); - if (state->flags & 0x0200) + if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; @@ -796,7 +819,7 @@ int flush; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); - if (hold != (state->check & 0xffff)) { + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; @@ -1177,11 +1200,11 @@ int flush; out -= left; strm->total_out += out; state->total += out; - if (out) + if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; - if (( + if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif @@ -1240,10 +1263,10 @@ int flush; strm->total_in += in; strm->total_out += out; state->total += out; - if (state->wrap && out) + if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) @@ -1255,7 +1278,7 @@ int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); @@ -1273,7 +1296,7 @@ uInt *dictLength; struct inflate_state FAR *state; /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ @@ -1298,7 +1321,7 @@ uInt dictLength; int ret; /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; @@ -1330,7 +1353,7 @@ gz_headerp head; struct inflate_state FAR *state; /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; @@ -1383,7 +1406,7 @@ z_streamp strm; struct inflate_state FAR *state; /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; @@ -1430,7 +1453,7 @@ z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } @@ -1445,8 +1468,7 @@ z_streamp source; unsigned wsize; /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + if (inflateStateCheck(source) || dest == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; @@ -1467,6 +1489,7 @@ z_streamp source; /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); @@ -1488,25 +1511,51 @@ int subvert; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; - state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; return Z_OK; #else + (void)subvert; state->sane = 1; return Z_DATA_ERROR; #endif } +int ZEXPORT inflateValidate(strm, check) +z_streamp strm; +int check; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; + if (inflateStateCheck(strm)) + return -(1L << 16); state = (struct inflate_state FAR *)strm->state; - return ((long)(state->back) << 16) + + return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } + +unsigned long ZEXPORT inflateCodesUsed(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/src/engine/external/zlib/inflate.h b/src/engine/external/zlib/inflate.h index 95f4986d4..a46cce6b6 100644 --- a/src/engine/external/zlib/inflate.h +++ b/src/engine/external/zlib/inflate.h @@ -1,5 +1,5 @@ /* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2009 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -18,7 +18,7 @@ /* Possible inflate modes between inflate() calls */ typedef enum { - HEAD, /* i: waiting for magic header */ + HEAD = 16180, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ @@ -77,11 +77,14 @@ typedef enum { CHECK -> LENGTH -> DONE */ -/* state maintained between inflate() calls. Approximately 10K bytes. */ +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ diff --git a/src/engine/external/zlib/inftrees.c b/src/engine/external/zlib/inftrees.c index 44d89cf24..2ea08fc13 100644 --- a/src/engine/external/zlib/inftrees.c +++ b/src/engine/external/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2013 Mark Adler + * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; + " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -54,7 +54,7 @@ unsigned short FAR *work; code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ + unsigned match; /* use base and extra for symbol >= match */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, @@ -181,19 +181,17 @@ unsigned short FAR *work; switch (type) { case CODES: base = extra = work; /* dummy value--not used */ - end = 19; + match = 20; break; case LENS: base = lbase; - base -= 257; extra = lext; - extra -= 257; - end = 256; + match = 257; break; - default: /* DISTS */ + default: /* DISTS */ base = dbase; extra = dext; - end = -1; + match = 0; } /* initialize state for loop */ @@ -216,13 +214,13 @@ unsigned short FAR *work; for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { + if (work[sym] + 1U < match) { here.op = (unsigned char)0; here.val = work[sym]; } - else if ((int)(work[sym]) > end) { - here.op = (unsigned char)(extra[work[sym]]); - here.val = base[work[sym]]; + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ diff --git a/src/engine/external/zlib/trees.c b/src/engine/external/zlib/trees.c index 1fd7759ef..50cf4b457 100644 --- a/src/engine/external/zlib/trees.c +++ b/src/engine/external/zlib/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2012 Jean-loup Gailly + * Copyright (C) 1995-2017 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -36,7 +36,7 @@ #include "deflate.h" -#ifdef DEBUG +#ifdef ZLIB_DEBUG # include #endif @@ -122,13 +122,13 @@ struct static_tree_desc_s { int max_length; /* max bit length for the codes */ }; -local static_tree_desc static_l_desc = +local const static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -local static_tree_desc static_d_desc = +local const static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -local static_tree_desc static_bl_desc = +local const static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== @@ -152,18 +152,16 @@ local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif -#ifndef DEBUG +#ifndef ZLIB_DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ -#else /* DEBUG */ +#else /* !ZLIB_DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } @@ -182,7 +180,7 @@ local void gen_trees_header OF((void)); * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) @@ -208,12 +206,12 @@ local void send_bits(s, value, length) s->bi_valid += length; } } -#else /* !DEBUG */ +#else /* !ZLIB_DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ + int val = (int)value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ @@ -223,7 +221,7 @@ local void send_bits(s, value, length) s->bi_valid += len;\ }\ } -#endif /* DEBUG */ +#endif /* ZLIB_DEBUG */ /* the arguments must not have side effects */ @@ -317,7 +315,7 @@ local void tr_static_init() * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H -# ifndef DEBUG +# ifndef ZLIB_DEBUG # include # endif @@ -394,7 +392,7 @@ void ZLIB_INTERNAL _tr_init(s) s->bi_buf = 0; s->bi_valid = 0; -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif @@ -522,12 +520,12 @@ local void gen_bitlen(s, desc) xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } if (overflow == 0) return; - Trace((stderr,"\nbit length overflow\n")); + Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ @@ -554,9 +552,8 @@ local void gen_bitlen(s, desc) m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; tree[m].Len = (ush)bits; } n--; @@ -578,7 +575,7 @@ local void gen_codes (tree, max_code, bl_count) ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ + unsigned code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ @@ -586,7 +583,8 @@ local void gen_codes (tree, max_code, bl_count) * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. @@ -599,7 +597,7 @@ local void gen_codes (tree, max_code, bl_count) int len = tree[n].Len; if (len == 0) continue; /* Now reverse the bits */ - tree[n].Code = bi_reverse(next_code[len]++, len); + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); @@ -821,7 +819,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -869,11 +867,17 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ -#ifdef DEBUG + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len<<3; #endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== @@ -894,7 +898,7 @@ void ZLIB_INTERNAL _tr_align(s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); @@ -902,7 +906,7 @@ void ZLIB_INTERNAL _tr_align(s) /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. + * trees or store, and write out the encoded block. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; @@ -974,7 +978,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { @@ -983,7 +987,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex+1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 3 + s->opt_len; #endif } @@ -995,7 +999,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) if (last) { bi_windup(s); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } @@ -1090,7 +1094,7 @@ local void compress_block(s, ltree, dtree) send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { - dist -= base_dist[code]; + dist -= (unsigned)base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ @@ -1193,34 +1197,7 @@ local void bi_windup(s) } s->bi_buf = 0; s->bi_valid = 0; -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} diff --git a/src/engine/external/zlib/uncompr.c b/src/engine/external/zlib/uncompr.c index 242e9493d..f03a1a865 100644 --- a/src/engine/external/zlib/uncompr.c +++ b/src/engine/external/zlib/uncompr.c @@ -1,5 +1,5 @@ /* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,51 +9,85 @@ #include "zlib.h" /* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. + Decompresses the source buffer into the destination buffer. *sourceLen is + the byte length of the source buffer. Upon entry, *destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, + *destLen is the size of the decompressed data and *sourceLen is the number + of source bytes consumed. Upon return, source + *sourceLen points to the + first unused input byte. - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, or + Z_DATA_ERROR if the input data was corrupted, including if the input data is + an incomplete zlib stream. */ +int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong *sourceLen; +{ + z_stream stream; + int err; + const uInt max = (uInt)-1; + uLong len, left; + Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ + + len = *sourceLen; + if (*destLen) { + left = *destLen; + *destLen = 0; + } + else { + left = 1; + dest = buf; + } + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = len > (uLong)max ? max : (uInt)len; + len -= stream.avail_in; + } + err = inflate(&stream, Z_NO_FLUSH); + } while (err == Z_OK); + + *sourceLen -= len + stream.avail_in; + if (dest != buf) + *destLen = stream.total_out; + else if (stream.total_out && err == Z_BUF_ERROR) + left = 1; + + inflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : + err == Z_NEED_DICT ? Z_DATA_ERROR : + err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : + err; +} + int ZEXPORT uncompress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { - z_stream stream; - int err; - - stream.next_in = (z_const Bytef *)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; + return uncompress2(dest, destLen, source, &sourceLen); } diff --git a/src/engine/external/zlib/zconf.h b/src/engine/external/zlib/zconf.h index 9987a7755..5e1d68a00 100644 --- a/src/engine/external/zlib/zconf.h +++ b/src/engine/external/zlib/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2013 Jean-loup Gailly. + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -17,7 +17,7 @@ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET -/* all linked symbols */ +/* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align @@ -29,6 +29,7 @@ # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 @@ -37,10 +38,14 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams @@ -67,6 +72,8 @@ # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets @@ -78,7 +85,6 @@ # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf -# define gzvprintf z_gzvprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread @@ -89,32 +95,39 @@ # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary -# define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine -# define inflateResetKeep z_inflateResetKeep +# define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress +# define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO @@ -224,9 +237,19 @@ # define z_const #endif -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ @@ -256,7 +279,7 @@ Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ diff --git a/src/engine/external/zlib/zlib.h b/src/engine/external/zlib/zlib.h index 3e0c7672a..f09cdaf1e 100644 --- a/src/engine/external/zlib/zlib.h +++ b/src/engine/external/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.8, April 28th, 2013 + version 1.2.11, January 15th, 2017 - Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.8" -#define ZLIB_VERNUM 0x1280 +#define ZLIB_VERSION "1.2.11" +#define ZLIB_VERNUM 0x12b0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 8 +#define ZLIB_VER_REVISION 11 #define ZLIB_VER_SUBREVISION 0 /* @@ -65,7 +65,8 @@ extern "C" { with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - This library can optionally read and write gzip streams in memory as well. + This library can optionally read and write gzip and raw deflate streams in + memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- @@ -74,7 +75,7 @@ extern "C" { The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash - even in case of corrupted input. + even in the case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); @@ -87,7 +88,7 @@ typedef struct z_stream_s { uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ - Bytef *next_out; /* next output byte should be put there */ + Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ @@ -98,8 +99,9 @@ typedef struct z_stream_s { free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; @@ -142,7 +144,9 @@ typedef gz_header FAR *gz_headerp; zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if @@ -155,7 +159,7 @@ typedef gz_header FAR *gz_headerp; The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the - uncompressed data and may be saved for use in the decompressor (particularly + uncompressed data and may be saved for use by the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ @@ -200,7 +204,7 @@ typedef gz_header FAR *gz_headerp; #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ +/* Possible values of the data_type field for deflate() */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ @@ -258,11 +262,11 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - - Provide more output starting at next_out and update next_out and avail_out + - Generate more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). Some - output may be provided even if flush is not set. + should be set only when necessary. Some output may be provided even if + flush is zero. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more @@ -271,7 +275,9 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output - buffer because there might be more output pending. + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more ouput + in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to @@ -292,8 +298,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output - in order for the decompressor to finish the block before the empty fixed code - block. + in order for the decompressor to finish the block before the empty fixed + codes block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to @@ -319,34 +325,38 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was - enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the stream - are deflateReset or deflateEnd. + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least the - value returned by deflateBound (see below). Then deflate is guaranteed to - return Z_STREAM_END. If not enough output space is provided, deflate will - not return Z_STREAM_END, and it must be called again as described above. + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect the - compression algorithm in any manner. + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. */ @@ -369,23 +379,21 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the - exact value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit does not perform any decompression - apart from possibly reading the zlib header if present: actual decompression - will be done by inflate(). (So next_in and avail_in may be modified, but - next_out and avail_out are unused and unchanged.) The current implementation - of inflateInit() does not process any header information -- that is deferred - until inflate() is called. + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. */ @@ -401,17 +409,20 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing will - resume at this point for the next call of inflate(). + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). - - Provide more output starting at next_out and update next_out and avail_out + - Generate more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more - output, and updating the next_* and avail_* values accordingly. The + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be @@ -428,7 +439,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the + To assist in this, on return inflate() always sets strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or @@ -454,7 +465,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been - saved by the compressor for this purpose.) The use of Z_FINISH is not + saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the @@ -476,32 +487,33 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 + below. At the end of the stream, inflate() checks that its computed Adler-32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip - header is not retained, so applications that need that information should - instead use raw inflate, see inflateInit2() below, or inflateBack() and - perform their own processing of the gzip header and trailer. When processing + header is not retained unless inflateGetHeader() is used. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output - producted so far. The CRC-32 is checked against the gzip trailer. + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial - recovery of the data is desired. + recovery of the data is to be attempted. */ @@ -511,9 +523,8 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); This function discards any unprocessed input and does not flush any pending output. - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. */ @@ -544,16 +555,29 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. + with no zlib header or trailer, and will not compute a check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no - header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is @@ -614,12 +638,12 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. - Upon return of this function, strm->adler is set to the adler32 value + Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value + which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. + Adler-32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is @@ -628,6 +652,28 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, not perform any compression: this will be done by deflate(). */ +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* @@ -648,10 +694,10 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. The - stream will keep the same compression level and any other attributes that - may have been set by deflateInit2. + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). @@ -662,20 +708,36 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int strategy)); /* Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be + interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. - If the compression level is changed, the input available so far is - compressed with the old level (and may be flushed); the new level will take - effect only at the next call of deflate(). + If the compression approach (which is a function of the level) or the + strategy is changed, and if any input has been consumed in a previous + deflate() call, then the input available so far is compressed with the old + level and strategy using deflate(strm, Z_BLOCK). There are three approaches + for the compression levels 0, 1..3, and 4..9 respectively. The new level + and strategy will take effect at the next call of deflate(). - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to be - compressed and flushed. In particular, strm->avail_out must be non-zero. + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if - strm->avail_out was zero. + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, @@ -793,7 +855,7 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to + recommended that a check value such as an Adler-32 or a CRC-32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. @@ -802,7 +864,10 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a - crc32 instead of an adler32. + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will not automatically decode concatenated gzip streams. + inflate() will return Z_STREAM_END at the end of the gzip stream. The state + would need to be reset to continue decoding a subsequent gzip stream. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the @@ -823,7 +888,7 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. + can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the @@ -834,7 +899,7 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not + expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ @@ -892,7 +957,7 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. The + but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source @@ -904,7 +969,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted - the same as it is for inflateInit2. + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if @@ -956,7 +1023,7 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. - inflateMark returns the value noted above or -1 << 16 if the provided + inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ @@ -1048,9 +1115,9 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only - the raw deflate stream to decompress. This is different from the normal - behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those @@ -1059,12 +1126,12 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). @@ -1092,7 +1159,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is - assured to be defined if out() returns non-zero.) Note that inflateBack() + assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ @@ -1114,7 +1181,7 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); 7.6: size of z_off_t Compiler, assembler, and debug options: - 8: DEBUG + 8: ZLIB_DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) @@ -1164,7 +1231,8 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output @@ -1180,7 +1248,7 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. + compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, @@ -1203,7 +1271,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen - is the actual size of the uncompressed buffer. + is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output @@ -1212,6 +1280,14 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, buffer with the uncompressed data up to that point. */ +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + /* gzip file access functions */ /* @@ -1290,10 +1366,9 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or - write. Two buffers are allocated, either both of the specified size when - writing, or one of the specified size and the other twice that size when - reading. A larger buffer size of, for example, 64K or 128K bytes will - noticeably increase the speed of decompression (reading). + write. Three times that size in buffer space is allocated. A larger buffer + size of, for example, 64K or 128K bytes will noticeably increase the speed + of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). @@ -1304,10 +1379,12 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. + of deflateInit2 for the meaning of these parameters. Previously provided + data is flushed before the parameter change. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); @@ -1335,7 +1412,35 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); case. gzread returns the number of uncompressed bytes actually read, less than - len for end of file, or -1 for error. + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read up to nitems items of size size from file to buf, otherwise operating + as gzread() does. This duplicates the interface of stdio's fread(), with + size_t request and return types. If the library defines size_t, then + z_size_t is identical to size_t. If not, then z_size_t is an unsigned + integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevetheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, reseting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, @@ -1346,19 +1451,33 @@ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, error. */ +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + gzfwrite() writes nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written, or 0 in case of error. The number of - uncompressed bytes written is limited to 8191, or one less than the buffer - size given to gzbuffer(). The caller should assure that this limit is not - exceeded. If it is exceeded, then gzprintf() will return an error (0) with - nothing written. In this case, there may also be a buffer overflow with - unpredictable consequences, which is possible only if zlib was compiled with - the insecure functions sprintf() or vsprintf() because the secure snprintf() - or vsnprintf() functions were not available. This can be determined using - zlibCompileFlags(). + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); @@ -1418,7 +1537,7 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such - concatented gzip streams. + concatenated gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. @@ -1572,7 +1691,7 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. Usage example: @@ -1585,6 +1704,12 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); @@ -1614,6 +1739,12 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ +ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); @@ -1644,19 +1775,35 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ - (int)sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, (int)sizeof(z_stream)) +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif #ifndef Z_SOLO @@ -1676,10 +1823,10 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #else # define gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or @@ -1737,19 +1884,16 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #endif /* !Z_SOLO */ -/* hack for buggy compilers */ -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; -#endif - /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); -#if defined(_WIN32) && !defined(Z_SOLO) +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, const char *mode)); #endif diff --git a/src/engine/external/zlib/zutil.c b/src/engine/external/zlib/zutil.c index 23d2ebef0..a76c6b0c7 100644 --- a/src/engine/external/zlib/zutil.c +++ b/src/engine/external/zlib/zutil.c @@ -1,5 +1,5 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. + * Copyright (C) 1995-2017 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -10,21 +10,18 @@ # include "gzguts.h" #endif -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - z_const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; const char * ZEXPORT zlibVersion() @@ -61,7 +58,7 @@ uLong ZEXPORT zlibCompileFlags() case 8: flags += 2 << 6; break; default: flags += 3 << 6; } -#ifdef DEBUG +#ifdef ZLIB_DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) @@ -115,8 +112,8 @@ uLong ZEXPORT zlibCompileFlags() return flags; } -#ifdef DEBUG - +#ifdef ZLIB_DEBUG +#include # ifndef verbose # define verbose 0 # endif @@ -219,9 +216,11 @@ local ptr_table table[MAX_PTR]; voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { - voidpf buf = opaque; /* just to make some compilers happy */ + voidpf buf; ulg bsize = (ulg)items*size; + (void)opaque; + /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ @@ -244,6 +243,9 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; + + (void)opaque; + if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; @@ -259,7 +261,6 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) next_ptr--; return; } - ptr = opaque; /* just to make some compilers happy */ Assert(0, "zcfree: ptr not found"); } @@ -278,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { - if (opaque) opaque = 0; /* to make compiler happy */ + (void)opaque; return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { - if (opaque) opaque = 0; /* to make compiler happy */ + (void)opaque; _hfree(ptr); } @@ -306,7 +307,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) unsigned items; unsigned size; { - if (opaque) items += size - size; /* make compiler happy */ + (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } @@ -315,8 +316,8 @@ void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf opaque; voidpf ptr; { + (void)opaque; free(ptr); - if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ diff --git a/src/engine/external/zlib/zutil.h b/src/engine/external/zlib/zutil.h index 24ab06b1c..b079ea6a8 100644 --- a/src/engine/external/zlib/zutil.h +++ b/src/engine/external/zlib/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2013 Jean-loup Gailly. + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -36,7 +36,9 @@ #ifndef local # define local static #endif -/* compile with -Dlocal if your debugger can't find static symbols */ +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; @@ -98,28 +100,38 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #endif #ifdef AMIGA -# define OS_CODE 0x01 +# define OS_CODE 1 #endif #if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 +# define OS_CODE 2 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + #if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 +# define OS_CODE 5 #endif #ifdef OS2 -# define OS_CODE 0x06 +# define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 +# define OS_CODE 7 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fdopen */ @@ -131,18 +143,24 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif #endif -#ifdef TOPS20 -# define OS_CODE 0x0a +#ifdef __acorn +# define OS_CODE 13 #endif -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 #endif -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 #endif #if defined(_BEOS_) || defined(RISCOS) @@ -177,7 +195,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* common defaults */ #ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ +# define OS_CODE 3 /* assume Unix */ #endif #ifndef F_OPEN @@ -216,7 +234,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #endif /* Diagnostic functions */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); From 8e4a4d673f62f38fe6a0fe56fe827bb6b056888d Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 11:46:43 +0200 Subject: [PATCH 16/70] New Windows MSVC try --- CMakeLists.txt | 5 +---- ddnet-libs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c4e815600..b89821d93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,10 +438,6 @@ source_group_tree(src) set(TARGETS ${TARGETS_OWN} ${TARGETS_DEP}) -if(MSVC) - target_link_libraries(${TARGET_CLIENT} -SAFESEH:NO) # No Windows 8 store -endif() - foreach(target ${TARGETS}) if(MSVC) set(DBG $,$>) @@ -450,6 +446,7 @@ foreach(target ${TARGETS}) target_compile_options(${target} PRIVATE /EHsc) # Only catch C++ exceptions with catch. target_compile_options(${target} PRIVATE /GS) # Protect the stack pointer. target_compile_options(${target} PRIVATE /wd4996) # Use of non-_s functions. + set_property(TARGET ${target} APPEND PROPERTY LINK_FLAGS /SAFESEH:NO) # disable seh because the shipped libraries don't support it elseif(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU) if(ENABLE_STACK_PROTECTOR) target_compile_options(${target} PRIVATE -fstack-protector-all) # Protect the stack pointer. diff --git a/ddnet-libs b/ddnet-libs index 2fd77d026..0a24f70b0 160000 --- a/ddnet-libs +++ b/ddnet-libs @@ -1 +1 @@ -Subproject commit 2fd77d02664b32569ad5d388d3c0d2141b593a11 +Subproject commit 0a24f70b0d102826f70359f5b49df381f4d824c2 From 275adcba54f0cfbd24c4a3e844a7c5e79d138bbf Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 11:50:58 +0200 Subject: [PATCH 17/70] No manifest for MSVC --- other/icons/DDNet_cl.rc | 1 - 1 file changed, 1 deletion(-) diff --git a/other/icons/DDNet_cl.rc b/other/icons/DDNet_cl.rc index a99eeaf2a..178cb62fd 100644 --- a/other/icons/DDNet_cl.rc +++ b/other/icons/DDNet_cl.rc @@ -1,2 +1 @@ 50h ICON "DDNet.ico" -1 24 "DDNet.exe.manifest" From 7428dd06376186c4c7bc21c7f2c8bf551d203040 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 12:18:53 +0200 Subject: [PATCH 18/70] Editor: Don't show server settings when picker is active --- src/game/editor/editor.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 93b55a2c0..9f03228bb 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -5220,12 +5220,15 @@ void CEditor::Render() RenderMenubar(MenuBar); RenderModebar(CModeBar); - if(m_ShowEnvelopeEditor && !m_ShowPicker) - RenderEnvelopeEditor(ExtraEditor); - if(m_ShowUndo) - RenderUndoList(UndoList); - if(m_ShowServerSettingsEditor) - RenderServerSettingsEditor(ExtraEditor); + if(!m_ShowPicker) + { + if(m_ShowEnvelopeEditor) + RenderEnvelopeEditor(ExtraEditor); + if(m_ShowUndo) + RenderUndoList(UndoList); + if(m_ShowServerSettingsEditor) + RenderServerSettingsEditor(ExtraEditor); + } } if(m_Dialog == DIALOG_FILE) From 6e5375da717fb1612b8fb604c986e80da9bf855f Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 12:28:06 +0200 Subject: [PATCH 19/70] Moving mouse is not a key --- src/engine/client/input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/client/input.cpp b/src/engine/client/input.cpp index 05e7bcb28..ac6d0b2ce 100644 --- a/src/engine/client/input.cpp +++ b/src/engine/client/input.cpp @@ -324,7 +324,7 @@ int CInput::Update() return 1; } - if(Scancode >= 0 && Scancode < g_MaxKeys && !IgnoreKeys && m_CountEditingText == 0) + if(Scancode > KEY_FIRST && Scancode < g_MaxKeys && !IgnoreKeys && m_CountEditingText == 0) { if(Action&IInput::FLAG_PRESS) { From 2d68aed009824f9b8313e3fe99e558210ae1a5b4 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 13:41:18 +0200 Subject: [PATCH 20/70] More settings in controls menu. use listbox (fixes #802) --- src/game/client/components/menus_demo.cpp | 16 ++++- src/game/client/components/menus_settings.cpp | 65 +++++++++++++------ 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index f7132ed8e..25985a3fe 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -490,9 +490,21 @@ void CMenus::UiDoListboxStart(const void *pID, const CUIRect *pRect, float RowHe int NumViewable = (int)(gs_ListBoxOriginalView.h/Row.h) + 1; int Num = (NumItems+gs_ListBoxItemsPerRow-1)/gs_ListBoxItemsPerRow-NumViewable+1; - if(Num < 0) + if(Num <= 0) + { Num = 0; - if(Num > 0) + } + else if(Num == 1) + { + if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View)) + gs_ListBoxScrollValue -= 0.1f; + if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View)) + gs_ListBoxScrollValue += 0.1f; + + if(gs_ListBoxScrollValue < 0.0f) gs_ListBoxScrollValue = 0.0f; + if(gs_ListBoxScrollValue > 1.0f) gs_ListBoxScrollValue = 1.0f; + } + else { if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View)) gs_ListBoxScrollValue -= 3.0f/Num; diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 128eff9e3..c3f1faa06 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -646,13 +646,24 @@ typedef struct static CKeyInfo gs_aKeys[] = { - { "Move left", "+left", 0}, // Localize - these strings are localized within CLocConstString + { "Move left", "+left", 0}, // Localize - these strings are localized within CLocConstString { "Move right", "+right", 0 }, { "Jump", "+jump", 0 }, { "Fire", "+fire", 0 }, { "Hook", "+hook", 0 }, - { "Hook Collisions", "+showhookcoll", 0 }, - { "Toggle DynCam", "toggle cl_dyncam 0 1", 0 }, + { "Hook collisions", "+showhookcoll", 0 }, + { "Pause", "say /pause", 0 }, + { "Kill", "kill", 0 }, + { "Zoom in", "zoom+", 0 }, + { "Zoom out", "zoom-", 0 }, + { "Default zoom", "zoom", 0 }, + { "Show others", "say /showothers", 0 }, + { "Show all", "say /showall", 0 }, + { "Toggle dyncam", "toggle cl_dyncam 0 1", 0 }, + { "Toggle dummy", "toggle cl_dummy 0 1", 0 }, + { "Dummy copy", "toggle cl_dummy_copy_moves 0 1", 0 }, + { "Hammerfly dummy", "toggle cl_dummy_hammer 0 1", 0 }, + { "Hammer", "+weapon1", 0 }, { "Pistol", "+weapon2", 0 }, { "Shotgun", "+weapon3", 0 }, @@ -660,12 +671,15 @@ static CKeyInfo gs_aKeys[] = { "Rifle", "+weapon5", 0 }, { "Next weapon", "+nextweapon", 0 }, { "Prev. weapon", "+prevweapon", 0 }, + { "Vote yes", "vote yes", 0 }, { "Vote no", "vote no", 0 }, + { "Chat", "+show_chat; chat all", 0 }, { "Team chat", "+show_chat; chat team", 0 }, { "Converse", "+show_chat; chat all /c ", 0 }, { "Show chat", "+show_chat", 0 }, + { "Emoticon", "+emote", 0 }, { "Spectator mode", "+spectate", 0 }, { "Spectate next", "spectate_next", 0 }, @@ -675,10 +689,9 @@ static CKeyInfo gs_aKeys[] = { "Screenshot", "screenshot", 0 }, { "Scoreboard", "+scoreboard", 0 }, { "Statboard", "+statboard", 0 }, - { "Respawn", "kill", 0 }, - { "Toggle Dummy", "toggle cl_dummy 0 1", 0 }, - { "Dummy Copy", "toggle cl_dummy_copy_moves 0 1", 0 }, - { "Hammerfly Dummy", "toggle cl_dummy_hammer 0 1", 0 }, + { "Lock team", "say /lock", 0 }, + { "Show entities", "toggle cl_overlay_entities 0 100", 0 }, + { "Show HUD", "toggle cl_showhud 0 1", 0 }, }; /* This is for scripts/update_localization.py to work, don't remove! @@ -736,13 +749,22 @@ void CMenus::RenderSettingsControls(CUIRect MainView) } } + // controls in a scrollable listbox + static int s_ControlsList = 0; + static int s_SelectedControl = -1; + static float s_ScrollValue = 0; + int OldSelected = s_SelectedControl; + UiDoListboxStart(&s_ControlsList , &MainView, 475.0f, Localize("Controls"), "", 1, 1, s_SelectedControl, s_ScrollValue); + CUIRect MovementSettings, WeaponSettings, VotingSettings, ChatSettings, MiscSettings, ResetButton; - MainView.VSplitMid(&MovementSettings, &VotingSettings); + CListboxItem Item = UiDoListboxNextItem(&OldSelected, false, false); + Item.m_Rect.HSplitTop(10.0f, 0, &Item.m_Rect); + Item.m_Rect.VSplitMid(&MovementSettings, &VotingSettings); // movement settings { MovementSettings.VMargin(5.0f, &MovementSettings); - MovementSettings.HSplitTop(MainView.h/3+75.0f, &MovementSettings, &WeaponSettings); + MovementSettings.HSplitTop(450.0f, &MovementSettings, &WeaponSettings); RenderTools()->DrawUIRect(&MovementSettings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); MovementSettings.VMargin(10.0f, &MovementSettings); @@ -761,26 +783,27 @@ void CMenus::RenderSettingsControls(CUIRect MainView) MovementSettings.HSplitTop(20.0f, 0, &MovementSettings); } - UiDoGetButtons(0, 7, MovementSettings); + UiDoGetButtons(0, 17, MovementSettings); } // weapon settings { WeaponSettings.HSplitTop(10.0f, 0, &WeaponSettings); - WeaponSettings.HSplitTop(MainView.h/3+35.0f, &WeaponSettings, &ResetButton); + WeaponSettings.HSplitTop(190.0f, &WeaponSettings, &ResetButton); RenderTools()->DrawUIRect(&WeaponSettings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); WeaponSettings.VMargin(10.0f, &WeaponSettings); TextRender()->Text(0, WeaponSettings.x, WeaponSettings.y, 14.0f*UI()->Scale(), Localize("Weapon"), -1); WeaponSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &WeaponSettings); - UiDoGetButtons(7, 14, WeaponSettings); + UiDoGetButtons(17, 24, WeaponSettings); } // defaults { ResetButton.HSplitTop(10.0f, 0, &ResetButton); + ResetButton.HSplitTop(40.0f, &ResetButton, 0); RenderTools()->DrawUIRect(&ResetButton, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); ResetButton.HMargin(10.0f, &ResetButton); ResetButton.VMargin(30.0f, &ResetButton); @@ -793,41 +816,43 @@ void CMenus::RenderSettingsControls(CUIRect MainView) // voting settings { VotingSettings.VMargin(5.0f, &VotingSettings); - VotingSettings.HSplitTop(MainView.h/3-106.0f, &VotingSettings, &ChatSettings); + VotingSettings.HSplitTop(80.0f, &VotingSettings, &ChatSettings); RenderTools()->DrawUIRect(&VotingSettings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); VotingSettings.VMargin(10.0f, &VotingSettings); TextRender()->Text(0, VotingSettings.x, VotingSettings.y, 14.0f*UI()->Scale(), Localize("Voting"), -1); - VotingSettings.HSplitTop(14.0f+5.0f, 0, &VotingSettings); - UiDoGetButtons(14, 16, VotingSettings); + VotingSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &VotingSettings); + UiDoGetButtons(24, 26, VotingSettings); } // chat settings { ChatSettings.HSplitTop(10.0f, 0, &ChatSettings); - ChatSettings.HSplitTop(MainView.h/3-56.0f, &ChatSettings, &MiscSettings); + ChatSettings.HSplitTop(125.0f, &ChatSettings, &MiscSettings); RenderTools()->DrawUIRect(&ChatSettings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); ChatSettings.VMargin(10.0f, &ChatSettings); TextRender()->Text(0, ChatSettings.x, ChatSettings.y, 14.0f*UI()->Scale(), Localize("Chat"), -1); - ChatSettings.HSplitTop(14.0f+5.0f, 0, &ChatSettings); - UiDoGetButtons(16, 20, ChatSettings); + ChatSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &ChatSettings); + UiDoGetButtons(26, 30, ChatSettings); } // misc settings { MiscSettings.HSplitTop(10.0f, 0, &MiscSettings); + MiscSettings.HSplitTop(300.0f, &MiscSettings, 0); RenderTools()->DrawUIRect(&MiscSettings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); MiscSettings.VMargin(10.0f, &MiscSettings); TextRender()->Text(0, MiscSettings.x, MiscSettings.y, 14.0f*UI()->Scale(), Localize("Miscellaneous"), -1); - MiscSettings.HSplitTop(14.0f+5.0f, 0, &MiscSettings); - UiDoGetButtons(20, 33, MiscSettings); + MiscSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &MiscSettings); + UiDoGetButtons(30, 42, MiscSettings); } + UiDoListboxEnd(&s_ScrollValue, 0); } void CMenus::RenderSettingsGraphics(CUIRect MainView) From fd732e43bd57a37dcecd75916400fcf4ca2322cf Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 13:55:56 +0200 Subject: [PATCH 21/70] Version 10.6.8 --- src/game/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game/version.h b/src/game/version.h index 45a50e2f1..3160b216d 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -3,8 +3,8 @@ #ifndef GAME_VERSION_H #define GAME_VERSION_H #include "generated/nethash.cpp" -#define GAME_VERSION "0.6.3, 10.6.7" +#define GAME_VERSION "0.6.3, 10.6.8" #define GAME_NETVERSION "0.6 626fce9a778df4d4" -static const char GAME_RELEASE_VERSION[8] = "10.6.7"; -#define CLIENT_VERSIONNR 10067 +static const char GAME_RELEASE_VERSION[8] = "10.6.8"; +#define CLIENT_VERSIONNR 10068 #endif From dabd60d13fa47752b5cb32b3a6bd872b9776816e Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 14:24:45 +0200 Subject: [PATCH 22/70] Needs more build badges --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1722a848a..0a94302fa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -[![DDraceNetwork](https://ddnet.tw/ddnet-small.png)](https://ddnet.tw) [![Build Status](https://circleci.com/gh/ddnet/ddnet/tree/master.png)](https://circleci.com/gh/ddnet/ddnet) +[![DDraceNetwork](https://ddnet.tw/ddnet-small.png)](https://ddnet.tw) [![CircleCI Build Status](https://circleci.com/gh/ddnet/ddnet/tree/master.png)](https://circleci.com/gh/ddnet/ddnet) [![Travis CI Build Status](https://travis-ci.org/ddnet/ddnet.svg?branch=master)](https://travis-ci.org/ddnet/ddnet) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/foeer8wbynqaqqho?svg=true)](https://ci.appveyor.com/project/def-/ddnet) + ================================ Our own flavor of DDRace, a Teeworlds mod. See the [website](https://ddnet.tw) for more information. From 26b576ff7a9e1a5ffef59945927d57bfce19fc81 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 14:28:11 +0200 Subject: [PATCH 23/70] Header --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 0a94302fa..deea7c79f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ [![DDraceNetwork](https://ddnet.tw/ddnet-small.png)](https://ddnet.tw) [![CircleCI Build Status](https://circleci.com/gh/ddnet/ddnet/tree/master.png)](https://circleci.com/gh/ddnet/ddnet) [![Travis CI Build Status](https://travis-ci.org/ddnet/ddnet.svg?branch=master)](https://travis-ci.org/ddnet/ddnet) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/foeer8wbynqaqqho?svg=true)](https://ci.appveyor.com/project/def-/ddnet) -================================ - Our own flavor of DDRace, a Teeworlds mod. See the [website](https://ddnet.tw) for more information. Development discussions happen on #ddnet on Quakenet ([Webchat](http://webchat.quakenet.org/?channels=ddnet&uio=d4)). From 9b582cfa93e6fb8a4e14ebb42fd39407ebaee25c Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 14:30:43 +0200 Subject: [PATCH 24/70] discord link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index deea7c79f..cdcbf7b52 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Our own flavor of DDRace, a Teeworlds mod. See the [website](https://ddnet.tw) for more information. -Development discussions happen on #ddnet on Quakenet ([Webchat](http://webchat.quakenet.org/?channels=ddnet&uio=d4)). +Development discussions happen on #ddnet on Quakenet ([Webchat](http://webchat.quakenet.org/?channels=ddnet&uio=d4)) or on [Discord in the developer channel](https://discord.gg/xsEd9xu). You can get binary releases on the [DDNet website](https://ddnet.tw/downloads/). From d50b39c530ba8de8faff34bd990c2169bbfd7c25 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 17:35:30 +0200 Subject: [PATCH 25/70] Fix controls rectangle overlapping topbar and being clickable outside of scope --- ddnet-libs | 2 +- src/game/client/components/menus.cpp | 9 +++++---- src/game/client/components/menus.h | 2 +- src/game/client/components/menus_settings.cpp | 17 ++++++++++------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/ddnet-libs b/ddnet-libs index 0a24f70b0..f7ab5bfcf 160000 --- a/ddnet-libs +++ b/ddnet-libs @@ -1 +1 @@ -Subproject commit 0a24f70b0d102826f70359f5b49df381f4d824c2 +Subproject commit f7ab5bfcfb38adeaac9906df520e1305f0004fea diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 59ba142bc..74b05019c 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1009,16 +1009,13 @@ int CMenus::Render() if(m_Popup == POPUP_NONE) { - // do tab bar #if defined(__ANDROID__) Screen.HSplitTop(100.0f, &TabBar, &MainView); #else Screen.HSplitTop(24.0f, &TabBar, &MainView); #endif - TabBar.VMargin(20.0f, &TabBar); - RenderMenubar(TabBar); - // news is not implemented yet + // render news if(g_Config.m_UiPage < PAGE_NEWS || g_Config.m_UiPage > PAGE_SETTINGS || (Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiPage >= PAGE_GAME && g_Config.m_UiPage <= PAGE_CALLVOTE)) { ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); @@ -1060,6 +1057,10 @@ int CMenus::Render() RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_SETTINGS) RenderSettings(MainView); + + // do tab bar + TabBar.VMargin(20.0f, &TabBar); + RenderMenubar(TabBar); } else { diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index d0860abcc..75c66296e 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -73,7 +73,7 @@ class CMenus : public CComponent int DoKeyReader(void *pID, const CUIRect *pRect, int Key); //static int ui_do_key_reader(void *id, const CUIRect *rect, int key); - void UiDoGetButtons(int Start, int Stop, CUIRect View); + void UiDoGetButtons(int Start, int Stop, CUIRect View, CUIRect ScopeView); struct CListboxItem { diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index c3f1faa06..9f6c96fcd 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -703,15 +703,18 @@ static CKeyInfo gs_aKeys[] = const int g_KeyCount = sizeof(gs_aKeys) / sizeof(CKeyInfo); -void CMenus::UiDoGetButtons(int Start, int Stop, CUIRect View) +void CMenus::UiDoGetButtons(int Start, int Stop, CUIRect View, CUIRect ScopeView) { - for (int i = Start; i < Stop; i++) + for(int i = Start; i < Stop; i++) { CKeyInfo &Key = gs_aKeys[i]; CUIRect Button, Label; View.HSplitTop(20.0f, &Button, &View); Button.VSplitLeft(135.0f, &Label, &Button); + if(Button.y < ScopeView.y || Button.y + Button.h > ScopeView.y + ScopeView.h) + continue; + char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%s:", (const char *)Key.m_Name); @@ -783,7 +786,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) MovementSettings.HSplitTop(20.0f, 0, &MovementSettings); } - UiDoGetButtons(0, 17, MovementSettings); + UiDoGetButtons(0, 17, MovementSettings, MainView); } @@ -797,7 +800,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) TextRender()->Text(0, WeaponSettings.x, WeaponSettings.y, 14.0f*UI()->Scale(), Localize("Weapon"), -1); WeaponSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &WeaponSettings); - UiDoGetButtons(17, 24, WeaponSettings); + UiDoGetButtons(17, 24, WeaponSettings, MainView); } // defaults @@ -823,7 +826,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) TextRender()->Text(0, VotingSettings.x, VotingSettings.y, 14.0f*UI()->Scale(), Localize("Voting"), -1); VotingSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &VotingSettings); - UiDoGetButtons(24, 26, VotingSettings); + UiDoGetButtons(24, 26, VotingSettings, MainView); } // chat settings @@ -836,7 +839,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) TextRender()->Text(0, ChatSettings.x, ChatSettings.y, 14.0f*UI()->Scale(), Localize("Chat"), -1); ChatSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &ChatSettings); - UiDoGetButtons(26, 30, ChatSettings); + UiDoGetButtons(26, 30, ChatSettings, MainView); } // misc settings @@ -849,7 +852,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) TextRender()->Text(0, MiscSettings.x, MiscSettings.y, 14.0f*UI()->Scale(), Localize("Miscellaneous"), -1); MiscSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &MiscSettings); - UiDoGetButtons(30, 42, MiscSettings); + UiDoGetButtons(30, 42, MiscSettings, MainView); } UiDoListboxEnd(&s_ScrollValue, 0); From e37d895399f84bb216a13d8d926514ef009b30aa Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 17:35:45 +0200 Subject: [PATCH 26/70] Version 10.6.9 --- src/game/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game/version.h b/src/game/version.h index 3160b216d..4d49f8f16 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -3,8 +3,8 @@ #ifndef GAME_VERSION_H #define GAME_VERSION_H #include "generated/nethash.cpp" -#define GAME_VERSION "0.6.3, 10.6.8" +#define GAME_VERSION "0.6.3, 10.6.9" #define GAME_NETVERSION "0.6 626fce9a778df4d4" -static const char GAME_RELEASE_VERSION[8] = "10.6.8"; -#define CLIENT_VERSIONNR 10068 +static const char GAME_RELEASE_VERSION[8] = "10.6.9"; +#define CLIENT_VERSIONNR 10069 #endif From 2fc7f65c42cac2918f5346a265df3c86be83b504 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 18:13:41 +0200 Subject: [PATCH 27/70] Mention cmake in readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cdcbf7b52..a768d0c58 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,11 @@ To clone this repository with history since we moved the libraries to https://gi Building -------- -To compile DDNet yourself, you can follow the [instructions for compiling Teeworlds](https://www.teeworlds.com/?page=docs&wiki=compiling_everything). +To compile DDNet yourself, you can follow the [instructions for compiling Teeworlds](https://www.teeworlds.com/?page=docs&wiki=compiling_everything). Alternatively we also support CMake, so something like this works: + + make build + cmake .. + make DDNet requires additional libraries, that are bundled for the most common platforms (Windows, Mac, Linux, all x86 and x86_64). The bundled libraries are now in the ddnet-libs submodule. From 6048b76c17ffd6696eb3a86c6d377f9e85e08929 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 21:18:22 +0200 Subject: [PATCH 28/70] Fix websocket linking --- bam.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bam.lua b/bam.lua index 01c55ca59..d9e272ffd 100644 --- a/bam.lua +++ b/bam.lua @@ -373,7 +373,8 @@ function build(settings) tools = {} for i,v in ipairs(tools_src) do toolname = PathFilename(PathBase(v)) - tools[i] = Link(settings, toolname, Compile(settings, v), engine, zlib, pnglite, md5, game_shared) + tools[i] = Link(settings, toolname, Compile(settings, v), engine, + zlib, pnglite, md5, game_shared, libwebsockets) end -- build client, server, version server and master server From 34c8b047ea4822be5254bacf3af94d1643b83ba8 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 21:20:15 +0200 Subject: [PATCH 29/70] Oldschool C please --- src/base/system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/system.c b/src/base/system.c index fe2a81b09..ffba556b8 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -1160,11 +1160,11 @@ NETSOCKET net_udp_create(NETADDR bindaddr) if(bindaddr.type&NETTYPE_WEBSOCKET_IPV4) { int socket = -1; + char addr_str[NETADDR_MAXSTRSIZE]; /* bind, we should check for error */ tmpbindaddr.type = NETTYPE_WEBSOCKET_IPV4; - char addr_str[NETADDR_MAXSTRSIZE]; net_addr_str(&tmpbindaddr, addr_str, sizeof(addr_str), 0); socket = websocket_create(addr_str, tmpbindaddr.port); From 46f30a2fc1589c167202b8dcfc8719053c91779a Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 21:53:55 +0200 Subject: [PATCH 30/70] Fix mysql cmake build --- CMakeLists.txt | 2 +- cmake/FindMySQL.cmake | 71 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b89821d93..5e1b0231c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,7 @@ endfunction() show_dependency_status("Curl" ${CURL_FOUND} "${CURL_LIBRARY}") show_dependency_status("Freetype" ${FREETYPE_FOUND} "${FREETYPE_LIBRARY}") if(MYSQL) - show_dependency_status("MySQL" ${MYSQL_FOUND} "") + show_dependency_status("MySQL" ${MYSQL_FOUND} "${MYSQL_LIBRARY}") endif() show_dependency_status("Ogg" ${OGG_FOUND} "${OGG_INCLUDEDIR}") show_dependency_status("Opus" ${OPUS_FOUND} "${OPUS_INCLUDEDIR}") diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake index 95b79ab24..1507131fa 100644 --- a/cmake/FindMySQL.cmake +++ b/cmake/FindMySQL.cmake @@ -1,24 +1,69 @@ +find_program(MYSQL_CONFIG + NAMES mysql_config +) -find_path(MYSQL_INCLUDE_DIR +if(MYSQL_CONFIG) + exec_program(${MYSQL_CONFIG} + ARGS --include + OUTPUT_VARIABLE MY_TMP + ) + + string(REGEX REPLACE "-I([^ ]*)( .*)?" "\\1" MY_TMP "${MY_TMP}") + + set(MYSQL_CONFIG_INCLUDE_DIR ${MY_TMP} CACHE FILEPATH INTERNAL) + + exec_program(${MYSQL_CONFIG} + ARGS --libs_r + OUTPUT_VARIABLE MY_TMP + ) + + set(MYSQL_CONFIG_LIBRARIES "") + + string(REGEX MATCHALL "-l[^ ]*" MYSQL_LIB_LIST "${MY_TMP}") + foreach(LIB ${MYSQL_LIB_LIST}) + string(REGEX REPLACE "[ ]*-l([^ ]*)" "\\1" LIB "${LIB}") + list(APPEND MYSQL_CONFIG_LIBRARIES "${LIB}") + endforeach(LIB ${MYSQL_LIBS}) + + set(MYSQL_CONFIG_LIBRARY_PATH "") + + string(REGEX MATCHALL "-L[^ ]*" MYSQL_LIBDIR_LIST "${MY_TMP}") + foreach(LIB ${MYSQL_LIBDIR_LIST}) + string(REGEX REPLACE "[ ]*-L([^ ]*)" "\\1" LIB "${LIB}") + list(APPEND MYSQL_CONFIG_LIBRARY_PATH "${LIB}") + endforeach(LIB ${MYSQL_LIBS}) +endif(MYSQL_CONFIG) + +set_extra_dirs(MYSQL mysql) + +find_path(MYSQL_INCLUDEDIR NAMES "mysql.h" - PATHS - "/usr/include/mysql" - "/usr/local/include/mysql" + HINTS ${MYSQL_CONFIG_INCLUDE_DIR} + PATHS ${EXTRA_MYSQL_INCLUDEDIR} ) find_library(MYSQL_LIBRARY NAMES "mysqlclient" "mysqlclient_r" "mariadbclient" - PATHS - "/usr/lib/mysql" - "/usr/lib64/mysql" - "/usr/local/lib/mysql" - "/usr/local/lib64/mysql" + HINTS ${MYSQL_CONFIG_LIBRARY_PATH} + PATHS ${EXTRA_MYSQL_LIBDIR} +) + +find_path(MYSQL_CPPCONN_INCLUDEDIR + NAMES "mysql_connection.h" + HINTS ${MYSQL_CONFIG_INCLUDE_DIR} + PATHS ${EXTRA_MYSQL_INCLUDEDIR} +) + +find_library(MYSQL_CPPCONN_LIBRARY + NAMES "mysqlcppconn" "mysqlcppconn-static" + HINTS ${MYSQL_CONFIG_LIBRARY_PATH} + PATHS ${EXTRA_MYSQL_LIBDIR} ) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MySQL DEFAULT_MSG MYSQL_LIBRARY MYSQL_INCLUDE_DIR) +find_package_handle_standard_args(MySQL DEFAULT_MSG MYSQL_LIBRARY MYSQL_INCLUDEDIR) -set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIR}) -set(MYSQL_LIBRARIES ${MYSQL_LIBRARY}) +set(MYSQL_LIBRARIES ${MYSQL_LIBRARY} ${MYSQL_CPPCONN_LIBRARY}) +set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDEDIR} ${MYSQL_CPPCONN_INCLUDEDIR}) -mark_as_advanced(MYSQL_INCLUDE_DIR MYSQL_LIBRARY) +mark_as_advanced(MYSQL_INCLUDEDIR MYSQL_LIBRARY) From 60d7388d9fea2a9debc16e3bd9f99dad6e95d90c Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 22:03:05 +0200 Subject: [PATCH 31/70] Fix demo slicing --- src/engine/shared/demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index fedcc6934..b86d0c61c 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -958,7 +958,7 @@ void CDemoEditor::Slice(const char *pDemo, const char *pDst, int StartTick, int return; const CDemoPlayer::CMapInfo *pMapInfo = m_pDemoPlayer->GetMapInfo(); - if (m_pDemoRecorder->Start(m_pStorage, m_pConsole, pDst, m_pNetVersion, pMapInfo->m_aName, pMapInfo->m_Crc, "client", 0, 0, 0, pfnFilter, pUser) == -1) + if (m_pDemoRecorder->Start(m_pStorage, m_pConsole, pDst, m_pNetVersion, pMapInfo->m_aName, pMapInfo->m_Crc, "client", pMapInfo->m_Size, NULL, NULL, pfnFilter, pUser) == -1) return; From f09a0f640fad9c411b327c9c4c86cd21acd3aef6 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 22:31:14 +0200 Subject: [PATCH 32/70] Fix mouse sensitivity setting dialog and introduce new one for ui mouse sens (#fixes 804) --- src/game/client/components/menus_settings.cpp | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 9f6c96fcd..425f1bc37 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -734,6 +734,8 @@ void CMenus::UiDoGetButtons(int Start, int Stop, CUIRect View, CUIRect ScopeView void CMenus::RenderSettingsControls(CUIRect MainView) { + char aBuf[128]; + // this is kinda slow, but whatever for(int i = 0; i < g_KeyCount; i++) gs_aKeys[i].m_KeyId = 0; @@ -778,11 +780,26 @@ void CMenus::RenderSettingsControls(CUIRect MainView) { CUIRect Button, Label; MovementSettings.HSplitTop(20.0f, &Button, &MovementSettings); - Button.VSplitLeft(135.0f, &Label, &Button); - UI()->DoLabel(&Label, Localize("Mouse sens."), 14.0f*UI()->Scale(), -1); + Button.VSplitLeft(160.0f, &Label, &Button); + str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("Mouse sens."), g_Config.m_InpMousesens); + UI()->DoLabel(&Label, aBuf, 14.0f*UI()->Scale(), -1); Button.HMargin(2.0f, &Button); - g_Config.m_InpMousesens = (int)(DoScrollbarH(&g_Config.m_InpMousesens, &Button, (g_Config.m_InpMousesens-5)/500.0f)*500.0f)+5; - //*key.key = ui_do_key_reader(key.key, &Button, *key.key); + int NewValue = (int)(DoScrollbarH(&g_Config.m_InpMousesens, &Button, (min(g_Config.m_InpMousesens, 500)-5)/500.0f)*500.0f)+5; + if(g_Config.m_InpMousesens < 500 || NewValue < 500) + g_Config.m_InpMousesens = min(NewValue, 500); + MovementSettings.HSplitTop(20.0f, 0, &MovementSettings); + } + + { + CUIRect Button, Label; + MovementSettings.HSplitTop(20.0f, &Button, &MovementSettings); + Button.VSplitLeft(160.0f, &Label, &Button); + str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("UI mouse s."), g_Config.m_UiMousesens); + UI()->DoLabel(&Label, aBuf, 14.0f*UI()->Scale(), -1); + Button.HMargin(2.0f, &Button); + int NewValue = (int)(DoScrollbarH(&g_Config.m_UiMousesens, &Button, (min(g_Config.m_UiMousesens, 500)-5)/500.0f)*500.0f)+5; + if(g_Config.m_UiMousesens < 500 || NewValue < 500) + g_Config.m_UiMousesens = min(NewValue, 500); MovementSettings.HSplitTop(20.0f, 0, &MovementSettings); } From af5b903944d1f95bce2667c48d328d50338f05d7 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 22:32:35 +0200 Subject: [PATCH 33/70] Version 10.7 --- src/game/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game/version.h b/src/game/version.h index 4d49f8f16..1a96054e2 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -3,8 +3,8 @@ #ifndef GAME_VERSION_H #define GAME_VERSION_H #include "generated/nethash.cpp" -#define GAME_VERSION "0.6.3, 10.6.9" +#define GAME_VERSION "0.6.3, 10.7" #define GAME_NETVERSION "0.6 626fce9a778df4d4" -static const char GAME_RELEASE_VERSION[8] = "10.6.9"; -#define CLIENT_VERSIONNR 10069 +static const char GAME_RELEASE_VERSION[8] = "10.7"; +#define CLIENT_VERSIONNR 10070 #endif From ec885f3e25310732551a0628ad7d9a11c8181f51 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 22 Jul 2017 22:43:20 +0200 Subject: [PATCH 34/70] Fix layout --- src/game/client/components/menus_settings.cpp | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 425f1bc37..a3b6d7602 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -712,22 +712,23 @@ void CMenus::UiDoGetButtons(int Start, int Stop, CUIRect View, CUIRect ScopeView View.HSplitTop(20.0f, &Button, &View); Button.VSplitLeft(135.0f, &Label, &Button); - if(Button.y < ScopeView.y || Button.y + Button.h > ScopeView.y + ScopeView.h) - continue; - - char aBuf[64]; - str_format(aBuf, sizeof(aBuf), "%s:", (const char *)Key.m_Name); - - UI()->DoLabelScaled(&Label, aBuf, 13.0f, -1); - int OldId = Key.m_KeyId; - int NewId = DoKeyReader((void *)&gs_aKeys[i].m_Name, &Button, OldId); - if(NewId != OldId) + if(Button.y >= ScopeView.y && Button.y + Button.h <= ScopeView.y + ScopeView.h) { - if(OldId != 0 || NewId == 0) - m_pClient->m_pBinds->Bind(OldId, ""); - if(NewId != 0) - m_pClient->m_pBinds->Bind(NewId, gs_aKeys[i].m_pCommand); + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "%s:", (const char *)Key.m_Name); + + UI()->DoLabelScaled(&Label, aBuf, 13.0f, -1); + int OldId = Key.m_KeyId; + int NewId = DoKeyReader((void *)&gs_aKeys[i].m_Name, &Button, OldId); + if(NewId != OldId) + { + if(OldId != 0 || NewId == 0) + m_pClient->m_pBinds->Bind(OldId, ""); + if(NewId != 0) + m_pClient->m_pBinds->Bind(NewId, gs_aKeys[i].m_pCommand); + } } + View.HSplitTop(2.0f, 0, &View); } } @@ -769,7 +770,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) // movement settings { MovementSettings.VMargin(5.0f, &MovementSettings); - MovementSettings.HSplitTop(450.0f, &MovementSettings, &WeaponSettings); + MovementSettings.HSplitTop(490.0f, &MovementSettings, &WeaponSettings); RenderTools()->DrawUIRect(&MovementSettings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); MovementSettings.VMargin(10.0f, &MovementSettings); From 3de72f66e32bfc3f72522da4758825aa23043938 Mon Sep 17 00:00:00 2001 From: def Date: Sun, 23 Jul 2017 01:36:36 +0200 Subject: [PATCH 35/70] mysql needs CONF_SQL defined everywhere --- CMakeLists.txt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e1b0231c..d34e2989c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -361,12 +361,6 @@ add_executable(${TARGET_SERVER} target_link_libraries(${TARGET_SERVER} ${LIBS_SERVER}) list(APPEND TARGETS_OWN ${TARGET_SERVER}) -if(MYSQL) - target_compile_definitions(${TARGET_SERVER} PRIVATE -DCONF_SQL) - target_include_directories(${TARGET_SERVER} PRIVATE ${MYSQL_INCLUDE_DIRS}) -endif() - - ######################################################################## # VARIOUS TARGETS ######################################################################## @@ -476,6 +470,10 @@ foreach(target ${TARGETS_OWN}) if(WEBSOCKETS) target_compile_definitions(${target} PRIVATE CONF_WEBSOCKETS) endif() + if(MYSQL) + target_compile_definitions(${target} PRIVATE CONF_SQL) + target_include_directories(${target} PRIVATE ${MYSQL_INCLUDE_DIRS}) + endif() endforeach() foreach(target ${TARGETS_DEP}) From bf0e67a34ab8bfe866daf5c07ef6f72ff2be1fb0 Mon Sep 17 00:00:00 2001 From: def Date: Sun, 23 Jul 2017 21:20:12 +0200 Subject: [PATCH 36/70] We want the Timestamp of a team to stay min(Timestamp) to indicate the first time this team finished the map --- src/game/server/score/sql_score.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp index c14d124dc..6f36fa7b6 100644 --- a/src/game/server/score/sql_score.cpp +++ b/src/game/server/score/sql_score.cpp @@ -688,7 +688,7 @@ bool CSqlScore::SaveTeamScoreThread(CSqlServer* pSqlServer, const CSqlData *pGam if (aUpdateID[0]) { - str_format(aBuf, sizeof(aBuf), "UPDATE %s_teamrace SET Time='%.2f', Timestamp=CURRENT_TIMESTAMP() WHERE ID = '%s';", pSqlServer->GetPrefix(), pData->m_Time, aUpdateID); + str_format(aBuf, sizeof(aBuf), "UPDATE %s_teamrace SET Time='%.2f' WHERE ID = '%s';", pSqlServer->GetPrefix(), pData->m_Time, aUpdateID); dbg_msg("sql", "%s", aBuf); pSqlServer->executeSql(aBuf); } From 79d29b1e3133f104b7c6b0ff7b3f1f0a7272bec9 Mon Sep 17 00:00:00 2001 From: def Date: Sun, 23 Jul 2017 21:33:55 +0200 Subject: [PATCH 37/70] Fix: Finish score should always show the fastest time --- src/game/server/player.cpp | 2 ++ src/game/server/teams.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index f9c6b5a65..43bd297d5 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -119,6 +119,8 @@ void CPlayer::Reset() m_DND = false; m_LastPause = 0; + m_Score = -9999; + m_HasFinishScore = false // Variable initialized: m_Last_Team = 0; diff --git a/src/game/server/teams.cpp b/src/game/server/teams.cpp index 1d2473dee..3a37e7ad8 100644 --- a/src/game/server/teams.cpp +++ b/src/game/server/teams.cpp @@ -595,7 +595,10 @@ void CGameTeams::OnFinish(CPlayer* Player) int TTime = 0 - (int)Time; if (Player->m_Score < TTime || !Player->m_HasFinishScore) + { Player->m_Score = TTime; + Player->m_HasFinishScore = true; + } } void CGameTeams::OnCharacterSpawn(int ClientID) From 4c98c4bdd635a1a67f417fdb57df0226084ec4ea Mon Sep 17 00:00:00 2001 From: def Date: Sun, 23 Jul 2017 21:34:36 +0200 Subject: [PATCH 38/70] typo --- src/game/server/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 43bd297d5..d9a4fdfa6 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -120,7 +120,7 @@ void CPlayer::Reset() m_LastPause = 0; m_Score = -9999; - m_HasFinishScore = false + m_HasFinishScore = false; // Variable initialized: m_Last_Team = 0; From f2ac4a02ce00910630d610c00600414ff523f832 Mon Sep 17 00:00:00 2001 From: HMH Date: Mon, 24 Jul 2017 15:27:30 +0200 Subject: [PATCH 39/70] use str_append for appending strings this fixes corrupted stat csvs as str_format does not work with same source and destination --- src/game/client/components/statboard.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/game/client/components/statboard.cpp b/src/game/client/components/statboard.cpp index 56f4f5c28..e577cdf53 100644 --- a/src/game/client/components/statboard.cpp +++ b/src/game/client/components/statboard.cpp @@ -510,8 +510,8 @@ void CStatboard::FormatStats() { const CNetObj_PlayerInfo *pInfo = apPlayers[i]; const CGameClient::CClientStats *pStats = &m_pClient->m_aStats[pInfo->m_ClientID]; - - // Pre-formatting + + // Pre-formatting // Weapons frags/deaths char aWeaponFD[64 * NUM_WEAPONS]; @@ -534,8 +534,8 @@ void CStatboard::FormatStats() // Game with flags bool GameWithFlags = (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS); - char aBuf[1024]; - str_format(aBuf, sizeof(aBuf), "%d,%d,%s,%s,%d,%d,%d,%d,%.2f,%i,%.1f,%d,%d,%s,%d,%d,%d", + char aBuf[1024]; + str_format(aBuf, sizeof(aBuf), "%d,%d,%s,%s,%d,%d,%d,%d,%.2f,%i,%.1f,%d,%d,%s,%d,%d,%d\n", localPlayer?1:0, // Local player m_pClient->m_aClients[pInfo->m_ClientID].m_Team, // Team ReplaceCommata(m_pClient->m_aClients[pInfo->m_ClientID].m_aName), // Name @@ -554,7 +554,7 @@ void CStatboard::FormatStats() pStats->m_FlagGrabs, // Flag grabs pStats->m_FlagCaptures); // Flag captures - str_format(aPlayerStats, sizeof(aPlayerStats), "%s%s\n", aPlayerStats, aBuf); + str_append(aPlayerStats, aBuf, sizeof(aPlayerStats)); } char aStats[1024*(VANILLA_MAX_CLIENTS+1)]; From bcec0f1bb197a2a56496663a6663acddd310d0d5 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 24 Jul 2017 18:05:19 +0200 Subject: [PATCH 40/70] ctrl-f to search, ctrl-x to exclude, ctrl-r to reason --- src/game/client/components/menus_browser.cpp | 4 ++++ src/game/client/components/menus_ingame.cpp | 4 ++++ src/game/client/components/menus_settings.cpp | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index dec7d12a2..fae58a296 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -490,6 +490,8 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) QuickSearch.VSplitLeft(5.0f, 0, &QuickSearch); QuickSearch.VSplitLeft(QuickSearch.w-15.0f, &QuickSearch, &Button); static float Offset = 0.0f; + if(Input()->KeyPress(KEY_F) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))) + UI()->SetActiveItem(&g_Config.m_BrFilterString); if(DoEditBox(&g_Config.m_BrFilterString, &QuickSearch, g_Config.m_BrFilterString, sizeof(g_Config.m_BrFilterString), 12.0f, &Offset, false, CUI::CORNER_L, Localize("Search"))) Client()->ServerBrowserUpdate(); } @@ -516,6 +518,8 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) QuickExclude.VSplitLeft(5.0f, 0, &QuickExclude); QuickExclude.VSplitLeft(QuickExclude.w-15.0f, &QuickExclude, &Button); static float Offset = 0.0f; + if(Input()->KeyPress(KEY_X) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))) + UI()->SetActiveItem(&g_Config.m_BrExcludeString); if(DoEditBox(&g_Config.m_BrExcludeString, &QuickExclude, g_Config.m_BrExcludeString, sizeof(g_Config.m_BrExcludeString), 12.0f, &Offset, false, CUI::CORNER_L, Localize("Exclude"))) Client()->ServerBrowserUpdate(); } diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp index c7ca492f5..d8d61833e 100644 --- a/src/game/client/components/menus_ingame.cpp +++ b/src/game/client/components/menus_ingame.cpp @@ -622,6 +622,8 @@ void CMenus::RenderServerControl(CUIRect MainView) QuickSearch.VSplitLeft(QuickSearch.w-15.0f, &QuickSearch, &Button2); static float Offset = 0.0f; //static char aFilterString[25]; + if(Input()->KeyPress(KEY_F) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))) + UI()->SetActiveItem(&m_aFilterString); if(DoEditBox(&m_aFilterString, &QuickSearch, m_aFilterString, sizeof(m_aFilterString), 14.0f, &Offset, false, CUI::CORNER_L, Localize("Search"))) { // TODO: Implement here } @@ -681,6 +683,8 @@ void CMenus::RenderServerControl(CUIRect MainView) float w = TextRender()->TextWidth(0, 14.0f, pLabel, -1); Reason.VSplitLeft(w+10.0f, 0, &Reason); static float s_Offset = 0.0f; + if(Input()->KeyPress(KEY_R) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))) + UI()->SetActiveItem(&m_aCallvoteReason); DoEditBox(&m_aCallvoteReason, &Reason, m_aCallvoteReason, sizeof(m_aCallvoteReason), 14.0f, &s_Offset, false, CUI::CORNER_ALL); // extended features (only available when authed in rcon) diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index a3b6d7602..6b0da6afc 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -616,6 +616,8 @@ void CMenus::RenderSettingsTee(CUIRect MainView) QuickSearch.VSplitLeft(5.0f, 0, &QuickSearch); QuickSearch.VSplitLeft(QuickSearch.w-15.0f, &QuickSearch, &QuickSearchClearButton); static float Offset = 0.0f; + if(Input()->KeyPress(KEY_F) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))) + UI()->SetActiveItem(&g_Config.m_ClSkinFilterString); if(DoEditBox(&g_Config.m_ClSkinFilterString, &QuickSearch, g_Config.m_ClSkinFilterString, sizeof(g_Config.m_ClSkinFilterString), 14.0f, &Offset, false, CUI::CORNER_L, Localize("Search"))) s_InitSkinlist = true; From 147005ea428df22b435461906b080c48aaefbdbe Mon Sep 17 00:00:00 2001 From: def Date: Mon, 24 Jul 2017 18:33:11 +0200 Subject: [PATCH 41/70] ask before overwriting demo file when slicing (fixes #806) --- src/game/client/components/menus_demo.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 25985a3fe..64e9c38ac 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -122,19 +122,29 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) static int s_ButtonOk = 0; if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || m_EnterPressed) { - if (str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, m_aCurrentDemoFile) == 0) + if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, m_aCurrentDemoFile) == 0) str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name"), sizeof(m_aDemoPlayerPopupHint)); else { - m_DemoPlayerState = DEMOPLAYER_NONE; - int len = str_length(m_aCurrentDemoFile); if(len < 5 || str_comp_nocase(&m_aCurrentDemoFile[len-5], ".demo")) str_append(m_aCurrentDemoFile, ".demo", sizeof(m_aCurrentDemoFile)); char aPath[512]; str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); - Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat); + + IOHANDLE DemoFile = Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_SAVE); + const char* pStr = Localize("File already exists, do you want to overwrite it?"); + if(DemoFile && str_comp_num(m_aDemoPlayerPopupHint, pStr, sizeof(m_aDemoPlayerPopupHint)) != 0) + { + io_close(DemoFile); + str_copy(m_aDemoPlayerPopupHint, pStr, sizeof(m_aDemoPlayerPopupHint)); + } + else + { + m_DemoPlayerState = DEMOPLAYER_NONE; + Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat); + } } } @@ -160,7 +170,10 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("New name:"), 18.0f, -1); static float Offset = 0.0f; - DoEditBox(&Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &Offset); + if(DoEditBox(&Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &Offset)) + { + m_aDemoPlayerPopupHint[0] = '\0'; + } } // handle mousewheel independent of active menu From cf08239e58d85e80c04aa105fefa660466976155 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 24 Jul 2017 20:58:51 +0200 Subject: [PATCH 42/70] no plenk --- src/game/server/score/sql_score.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp index 6f36fa7b6..c1192a414 100644 --- a/src/game/server/score/sql_score.cpp +++ b/src/game/server/score/sql_score.cpp @@ -187,7 +187,7 @@ bool CSqlScore::CheckBirthdayThread(CSqlServer* pSqlServer, const CSqlData *pGam str_format(aBuf, sizeof(aBuf), "Happy DDNet birthday to %s for finishing their first map %d year%s ago!", pData->m_Name.Str(), yearsAgo, yearsAgo > 1 ? "s" : ""); pData->GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, pData->m_ClientID); - str_format(aBuf, sizeof(aBuf), "Happy DDNet birthday %s !\nYou have finished your first map %d year%s ago!", pData->m_Name.Str(), yearsAgo, yearsAgo > 1 ? "s" : ""); + str_format(aBuf, sizeof(aBuf), "Happy DDNet birthday %s!\nYou have finished your first map %d year%s ago!", pData->m_Name.Str(), yearsAgo, yearsAgo > 1 ? "s" : ""); pData->GameServer()->SendBroadcast(aBuf, pData->m_ClientID); } From 1ebb4f89a649484b6307e633ae98db82de84d0d8 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Mon, 24 Jul 2017 21:43:55 +0200 Subject: [PATCH 43/70] Reopen: Add a flag for rcon login via username (#800) This uses an extended protocol message to signal that rcon authentication might require a username, allowing the client to enable the username prompt. Add a forgotten logout on key update --- src/engine/client.h | 1 + src/engine/client/client.cpp | 5 +++++ src/engine/server/authmanager.cpp | 6 ++++++ src/engine/server/authmanager.h | 1 + src/engine/server/server.cpp | 24 ++++++++++++++++++++++++ src/engine/server/server.h | 1 + src/engine/shared/protocol_ex_msgs.h | 2 ++ src/game/client/components/console.cpp | 23 +++++++++++------------ src/game/client/components/console.h | 2 ++ src/game/client/gameclient.cpp | 5 +++++ src/game/client/gameclient.h | 1 + 11 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/engine/client.h b/src/engine/client.h index 271510f38..04c33e87e 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -204,6 +204,7 @@ protected: public: virtual void OnConsoleInit() = 0; + virtual void OnRconType(bool UsernameReq) = 0; virtual void OnRconLine(const char *pLine) = 0; virtual void OnInit() = 0; virtual void OnNewSnapshot() = 0; diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 8c0e2108a..5baeab32d 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1978,6 +1978,11 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) } } } + else if(Msg == NETMSG_RCONTYPE) + { + bool UsernameReq = Unpacker.GetInt() & 1; + GameClient()->OnRconType(UsernameReq); + } } else { diff --git a/src/engine/server/authmanager.cpp b/src/engine/server/authmanager.cpp index 8e4f7358e..a65263f2c 100644 --- a/src/engine/server/authmanager.cpp +++ b/src/engine/server/authmanager.cpp @@ -182,3 +182,9 @@ bool CAuthManager::IsGenerated() { return m_Generated; } + +int CAuthManager::NumNonDefaultKeys() +{ + int DefaultCount = (m_aDefault[0] >= 0) + (m_aDefault[1] >= 0) + (m_aDefault[2] >= 0); + return m_aKeys.size() - DefaultCount; +} diff --git a/src/engine/server/authmanager.h b/src/engine/server/authmanager.h index 7cae19b29..1267917b7 100644 --- a/src/engine/server/authmanager.h +++ b/src/engine/server/authmanager.h @@ -46,6 +46,7 @@ public: void ListKeys(FListCallback pfnListCallbac, void *pUser); void AddDefaultKey(int Level, const char *pPw); bool IsGenerated(); + int NumNonDefaultKeys(); }; #endif //ENGINE_SERVER_AUTH_MANAGER_H diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 2f9a2cbe4..ddd86fbad 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -864,6 +864,13 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) return 0; } +void CServer::SendRconType(int ClientID, bool UsernameReq) +{ + CMsgPacker Msg(NETMSG_RCONTYPE); + Msg.AddInt(UsernameReq); + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); +} + void CServer::SendMap(int ClientID) { CMsgPacker Msg(NETMSG_MAP_CHANGE); @@ -1052,6 +1059,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) } m_aClients[ClientID].m_State = CClient::STATE_CONNECTING; + SendRconType(ClientID, m_AuthManager.NumNonDefaultKeys() > 0); SendMap(ClientID); } } @@ -2094,10 +2102,15 @@ void CServer::ConAuthAdd(IConsole::IResult *pResult, void *pUser) return; } + bool NeedUpdate = !pManager->NumNonDefaultKeys(); if(pManager->AddKey(pIdent, pPw, Level) < 0) pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "ident already exists"); else + { + if(NeedUpdate) + pThis->SendRconType(-1, true); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key added"); + } } void CServer::ConAuthAddHashed(IConsole::IResult *pResult, void *pUser) @@ -2131,10 +2144,16 @@ void CServer::ConAuthAddHashed(IConsole::IResult *pResult, void *pUser) return; } + bool NeedUpdate = !pManager->NumNonDefaultKeys(); + if(pManager->AddKeyHash(pIdent, aHash, aSalt, Level) < 0) pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "ident already exists"); else + { + if(NeedUpdate) + pThis->SendRconType(-1, true); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key added"); + } } void CServer::ConAuthUpdate(IConsole::IResult *pResult, void *pUser) @@ -2161,6 +2180,7 @@ void CServer::ConAuthUpdate(IConsole::IResult *pResult, void *pUser) } pManager->UpdateKey(KeySlot, pPw, Level); + pThis->LogoutKey(KeySlot, "key update"); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key updated"); } @@ -2224,6 +2244,10 @@ void CServer::ConAuthRemove(IConsole::IResult *pResult, void *pUser) } pThis->AuthRemoveKey(KeySlot); + + if(!pManager->NumNonDefaultKeys()) + pThis->SendRconType(-1, false); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key removed, all users logged out"); } diff --git a/src/engine/server/server.h b/src/engine/server/server.h index aa572ec7c..9ab477dca 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -252,6 +252,7 @@ public: static int ClientRejoinCallback(int ClientID, void *pUser); + void SendRconType(int ClientID, bool UsernameReq); void SendMap(int ClientID); void SendMapData(int ClientID, int Chunk); void SendConnectionReady(int ClientID); diff --git a/src/engine/shared/protocol_ex_msgs.h b/src/engine/shared/protocol_ex_msgs.h index 1d98014ce..eb660da61 100644 --- a/src/engine/shared/protocol_ex_msgs.h +++ b/src/engine/shared/protocol_ex_msgs.h @@ -20,3 +20,5 @@ UUID(NETMSG_WHATIS, "what-is@ddnet.tw") UUID(NETMSG_ITIS, "it-is@ddnet.tw") UUID(NETMSG_IDONTKNOW, "i-dont-know@ddnet.tw") + +UUID(NETMSG_RCONTYPE, "rcon-type@ddnet.tw") diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index 6aa6ad1d4..07c76e2c3 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -51,6 +51,7 @@ CGameConsole::CInstance::CInstance(int Type) m_aUser[0] = '\0'; m_UserGot = false; + m_UsernameReq = false; m_IsCommand = false; } @@ -82,10 +83,7 @@ void CGameConsole::CInstance::ExecuteLine(const char *pLine) m_pGameConsole->Client()->Rcon(pLine); else { - CServerInfo pServerInfo; - m_pGameConsole->Client()->GetServerInfo(&pServerInfo); - - if(!m_UserGot && IsDDNet(&pServerInfo)) + if(!m_UserGot && m_UsernameReq) { m_UserGot = true; str_copy(m_aUser, pLine, sizeof m_aUser); @@ -149,9 +147,7 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event) { if(Event.m_Key == KEY_RETURN || Event.m_Key == KEY_KP_ENTER) { - CServerInfo pServerInfo; - m_pGameConsole->Client()->GetServerInfo(&pServerInfo); - if(m_Input.GetString()[0] || (IsDDNet(&pServerInfo) && !m_pGameConsole->Client()->RconAuthed() && !m_UserGot)) + if(m_Input.GetString()[0] || (m_UsernameReq && !m_pGameConsole->Client()->RconAuthed() && !m_UserGot)) { if(m_Type == CONSOLETYPE_LOCAL || m_pGameConsole->Client()->RconAuthed()) { @@ -488,9 +484,6 @@ void CGameConsole::OnRender() Info.m_pCurrentCmd = pConsole->m_aCompletionBuffer; TextRender()->SetCursor(&Info.m_Cursor, x+Info.m_Offset, y+RowHeight+2.0f, FontSize, TEXTFLAG_RENDER); - CServerInfo pServerInfo; - Client()->GetServerInfo(&pServerInfo); - // render prompt CTextCursor Cursor; TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER); @@ -503,7 +496,7 @@ void CGameConsole::OnRender() pPrompt = "rcon> "; else { - if(IsDDNet(&pServerInfo)) + if(pConsole->m_UsernameReq) { if(!pConsole->m_UserGot) pPrompt = "Enter Username> "; @@ -537,7 +530,7 @@ void CGameConsole::OnRender() //hide rcon password char aInputString[512]; str_copy(aInputString, pConsole->m_Input.GetString(Editing), sizeof(aInputString)); - if(m_ConsoleType == CONSOLETYPE_REMOTE && Client()->State() == IClient::STATE_ONLINE && !Client()->RconAuthed() && (pConsole->m_UserGot || !IsDDNet(&pServerInfo))) + if(m_ConsoleType == CONSOLETYPE_REMOTE && Client()->State() == IClient::STATE_ONLINE && !Client()->RconAuthed() && (pConsole->m_UserGot || !pConsole->m_UsernameReq)) { for(int i = 0; i < pConsole->m_Input.GetLength(Editing); ++i) aInputString[i] = '*'; @@ -788,6 +781,11 @@ void CGameConsole::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, } } +void CGameConsole::RequireUsername(bool UsernameReq) +{ + m_RemoteConsole.m_UsernameReq = UsernameReq; +} + void CGameConsole::PrintLine(int Type, const char *pLine) { if(Type == CONSOLETYPE_LOCAL) @@ -823,5 +821,6 @@ void CGameConsole::OnStateChange(int NewState, int OldState) { m_RemoteConsole.m_UserGot = false; m_RemoteConsole.m_Input.Clear(); + m_RemoteConsole.m_UsernameReq = false; } } diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h index 88e7a7ef4..ecdb71fc3 100644 --- a/src/game/client/components/console.h +++ b/src/game/client/components/console.h @@ -45,6 +45,7 @@ class CGameConsole : public CComponent char m_aUser[32]; bool m_UserGot; + bool m_UsernameReq; bool m_IsCommand; char m_aCommandName[IConsole::TEMPCMD_NAME_LENGTH]; @@ -103,6 +104,7 @@ public: CGameConsole(); void PrintLine(int Type, const char *pLine); + void RequireUsername(bool UsernameReq); virtual void OnStateChange(int NewState, int OldState); virtual void OnConsoleInit(); diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 1797348ef..5cb4968cd 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -884,6 +884,11 @@ void CGameClient::OnFlagGrab(int TeamID) m_aStats[m_Snap.m_pGameDataObj->m_FlagCarrierBlue].m_FlagGrabs++; } +void CGameClient::OnRconType(bool UsernameReq) +{ + m_pGameConsole->RequireUsername(UsernameReq); +} + void CGameClient::OnRconLine(const char *pLine) { m_pGameConsole->PrintLine(CGameConsole::CONSOLETYPE_REMOTE, pLine); diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index cecff7e7c..cc4deb85e 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -311,6 +311,7 @@ public: virtual int OnSnapInput(int *pData, bool Dummy, bool Force); virtual void OnShutdown(); virtual void OnEnterGame(); + virtual void OnRconType(bool UsernameReq); virtual void OnRconLine(const char *pLine); virtual void OnGameOver(); virtual void OnStartGame(); From a9498b15cba3e28535b1295030a2667d10fe09ac Mon Sep 17 00:00:00 2001 From: def Date: Mon, 24 Jul 2017 23:48:26 +0200 Subject: [PATCH 44/70] Fat skins --- src/game/client/components/menus_settings.cpp | 9 ++++++++- src/game/client/render.cpp | 3 ++- src/game/variables.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 6b0da6afc..a04d7f2c4 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -425,12 +425,19 @@ void CMenus::RenderSettingsTee(CUIRect MainView) Dummy.HSplitTop(20.0f, &DummyLabel, &Dummy); - if(DoButton_CheckBox(&g_Config.m_ClVanillaSkinsOnly, Localize("Vanilla Skins only"), g_Config.m_ClVanillaSkinsOnly, &DummyLabel)) + if(DoButton_CheckBox(&g_Config.m_ClVanillaSkinsOnly, Localize("Vanilla skins only"), g_Config.m_ClVanillaSkinsOnly, &DummyLabel)) { g_Config.m_ClVanillaSkinsOnly ^= 1; CheckSettings = true; } + Dummy.HSplitTop(20.0f, &DummyLabel, &Dummy); + + if(DoButton_CheckBox(&g_Config.m_ClFatSkins, Localize("Fat skins"), g_Config.m_ClFatSkins, &DummyLabel)) + { + g_Config.m_ClFatSkins ^= 1; + } + if(CheckSettings) { if(s_ClVanillaSkinsOnly == g_Config.m_ClVanillaSkinsOnly) diff --git a/src/game/client/render.cpp b/src/game/client/render.cpp index f1c8fc4c0..12e71deef 100644 --- a/src/game/client/render.cpp +++ b/src/game/client/render.cpp @@ -231,7 +231,8 @@ void CRenderTools::RenderTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, int Emote vec2 BodyPos = Position + vec2(pAnim->GetBody()->m_X, pAnim->GetBody()->m_Y)*AnimScale; SelectSprite(OutLine?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, 0); - IGraphics::CQuadItem QuadItem(BodyPos.x, BodyPos.y, BaseSize, BaseSize); + float BodySize = g_Config.m_ClFatSkins ? BaseSize * 1.3 : BaseSize; + IGraphics::CQuadItem QuadItem(BodyPos.x, BodyPos.y, BodySize, BodySize); Graphics()->QuadsDraw(&QuadItem, 1); // draw eyes diff --git a/src/game/variables.h b/src/game/variables.h index e671b2c3a..4652709b4 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -86,6 +86,7 @@ MACRO_CONFIG_INT(ClPlayerUseCustomColor, player_use_custom_color, 0, 0, 1, CFGFL MACRO_CONFIG_INT(ClPlayerColorBody, player_color_body, 65408, 0, 0xFFFFFF, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Player body color") MACRO_CONFIG_INT(ClPlayerColorFeet, player_color_feet, 65408, 0, 0xFFFFFF, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Player feet color") MACRO_CONFIG_STR(ClPlayerSkin, player_skin, 24, "default", CFGFLAG_CLIENT|CFGFLAG_SAVE, "Player skin") +MACRO_CONFIG_INT(ClFatSkins, cl_fat_skins, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Enable fat skins") MACRO_CONFIG_INT(UiPage, ui_page, 6, 0, 11, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface page") MACRO_CONFIG_INT(UiToolboxPage, ui_toolbox_page, 0, 0, 2, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Toolbox page") From 8d621dfc003315662a44a0d3a7156fc0f2876192 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 25 Jul 2017 00:11:25 +0200 Subject: [PATCH 45/70] Add kitty skins (by Ravie + fuzzy ninja by patwo.*) --- data/skins/kitty_bluestripe.png | Bin 0 -> 7793 bytes data/skins/kitty_brownbear.png | Bin 0 -> 10995 bytes data/skins/kitty_cammo.png | Bin 0 -> 7749 bytes data/skins/kitty_cammostripes.png | Bin 0 -> 7291 bytes data/skins/kitty_coala.png | Bin 0 -> 7102 bytes data/skins/kitty_default.png | Bin 0 -> 6837 bytes data/skins/kitty_pinky.png | Bin 0 -> 7115 bytes data/skins/kitty_redbopp.png | Bin 0 -> 7092 bytes data/skins/kitty_redstripe.png | Bin 0 -> 7350 bytes data/skins/kitty_saddo.png | Bin 0 -> 7766 bytes data/skins/kitty_toptri.png | Bin 0 -> 7146 bytes data/skins/kitty_twinbop.png | Bin 0 -> 7400 bytes data/skins/kitty_twintri.png | Bin 0 -> 7398 bytes data/skins/kitty_warpaint.png | Bin 0 -> 7435 bytes data/skins/kitty_x_ninja.png | Bin 0 -> 5979 bytes src/game/client/components/menus_settings.cpp | 7 +++++++ src/game/client/components/skins.cpp | 15 +++++++++++++++ src/game/variables.h | 1 + 18 files changed, 23 insertions(+) create mode 100644 data/skins/kitty_bluestripe.png create mode 100644 data/skins/kitty_brownbear.png create mode 100644 data/skins/kitty_cammo.png create mode 100644 data/skins/kitty_cammostripes.png create mode 100644 data/skins/kitty_coala.png create mode 100644 data/skins/kitty_default.png create mode 100644 data/skins/kitty_pinky.png create mode 100644 data/skins/kitty_redbopp.png create mode 100644 data/skins/kitty_redstripe.png create mode 100644 data/skins/kitty_saddo.png create mode 100644 data/skins/kitty_toptri.png create mode 100644 data/skins/kitty_twinbop.png create mode 100644 data/skins/kitty_twintri.png create mode 100644 data/skins/kitty_warpaint.png create mode 100644 data/skins/kitty_x_ninja.png diff --git a/data/skins/kitty_bluestripe.png b/data/skins/kitty_bluestripe.png new file mode 100644 index 0000000000000000000000000000000000000000..4ee79da693218c55e390a68a746ad84c03c7a74d GIT binary patch literal 7793 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 literal 0 HcmV?d00001 diff --git a/data/skins/kitty_cammostripes.png b/data/skins/kitty_cammostripes.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7549ad6799f9dca40e3b0a5a7cf071a4e3576f GIT binary patch literal 7291 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%0AbWbLC%ThW%0CFCiShoWA%K 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 X)`E8bIkBjb|DCESYbjMIScm)%&z8{x literal 0 HcmV?d00001 diff --git a/data/skins/kitty_default.png b/data/skins/kitty_default.png new file mode 100644 index 0000000000000000000000000000000000000000..28cef14b0279d146df268c938d3213109f46bdac GIT binary patch literal 6837 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 aWD?(hIEAYcCI0VQ5~ifCSSfEF@_zvIu7J$| literal 0 HcmV?d00001 diff --git a/data/skins/kitty_saddo.png b/data/skins/kitty_saddo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d16dc52216a1ba882e0ae8d24eee28b7622a2f6 GIT binary patch literal 7766 zcmb7}RZtvEkjEEy5AGg3EFrktB7xupSsVhv-5nMJfyE)Xy9JjlPVgmo0>KkBxGpRl z-#y>U^}|$GP50E))YSZYejWEtQ-uJR1{VMT5U7F_bpQaAXBQBLjrlz8w6;G_FwmyGX`oP2pxD(P+(nv;~1jZlsAaV0!jUTqnfoOqRsfp3~wm@DbK)Ws-n68U9TLl&zPv)7{h`4VHakemyg?rwZ%s+O9Xm1 z#sb{e>*2SUu3QR~7Jgsd;>rRG2?>ClSkTh+ExaD`Sq(SlJTzDVO~KI9U*^6yLHX&9 zk`fO4uGN8mDm1}Fz1IV&XamO_A(u!qdBRc)ctNgs8(-V?04vP@IPhnqdGwWCg4GT# zgA^Z{F@E`Kuoo(F=OA+2C>`m&8Jrsy_s6AM@?OojyfG|S6Nt?`z|s0cW%FwrX~y-S zfoaUsO$4cEM-|;AAeWUky*ax|uM}BYbww}+tBxE8f=B3$dB~Dnq07xUsuTlz?Teri zxuPvbDvNbiNjx*b7fk?}X8dM1oCBfH1A}YyRJV4<9Dqxy`~~&c_(A&^j>RRq^@pl`zTl1<3g7d7GU>jrNGUv?w=>0^3Cj%9}kpT2W9Ke zc)#vgxGq%37H@(UYgdf#*1p%2!4-li{A*D2a%Ls$0-PB>BAwqN4+OUc!I(+Np9u}s;j^-ycf;zOSJ_&pFS zn;DG>T+b+(y}FExgMXPxvaRrEh*N89EQxZoKlF2^8P@$F>WRhR;kRKp-0;NHu#}zN zjeHAJkb&XR`e^aH%82K51D@WHr>7n>ZD`g-Xv|s+>@o}gy@b{trN!OO{ag1nmHu?q z3hyV`0Jh4Dd&@({_LUKv=^OKuqC<+&nbwPaETe|&xTSgNUz(JOwR2B?hMQy_L zHTXgHj3)h3#s<$w>N^wo_$7lEw-v)QdzZ}(F0AjOlEAluPg723|Hb&g_C8_Nd^L<8 zR81`%ODH|vv~Zdujr#ovT!-7kAC$<7uB*4Xz=ug$$=Y@B(I|hY>!;mh{sQ6s0IVvQ zuKUJ+C1B6ZOEjt3Pddu4^Co#=?uFJitEq+_N^qno`gS-ws*Y4gbRCoSvR+aAuTFWS z^uA55M$gi=w9UVVoxt79;p&U4mk5jxiLgvZL^4++Cx*L4OrZHRagTm!f{ zvA~T4FGDI7$gF&WqaHA@G`Xl^ip2^B7lUum+x|5EljGcCKiW_y)nvEg1_)7)vLWNt zR#9Vrwi@S|9}W~y@u3F8@{5*ZT!NQ16i+uraU>eSn05J8*9!(HUd{RdR?DjglrxXs zfh|F5+$xgAgAmS*$6bd5PMIDNtGO-w2EcO6oHLPlleV}vj@SBq@laz!fd3UV0})S& zQnSk$n|Y5yk)*0Ms!&JU@y5p2=^F#dC~>Wc^WeTPs=bJ61*>~C>0YoTSiqjGB>!>C z8?taAI5ZKA9sj*FZ!lVx-$IdTSYGn{&#)t%%=M*mIKqFYoSn;np;qFj^Nl2hfF5AH zQI~e%>+DtafdJUVNQ#pge2o5lCJ1OTQKn}nss)w67^>u6_CD}&=9i7#eVzV^>cPc- z=|oc57Bv9*SK$V7$>X+Hlno5E`BKCJ?X=GuRsz9NluQdceSy>a$+@;;ra1T^ z;V9c@iDp&ukh=A=&jY^`E-4#GYxC)!v+$m?d_hIH>~pV!MYh)5a;3f?6Hh#wgpv;d zI#)j%OAxOCmpEw-mWOD2csvzM_3}Nd-Y=q~tvyiBK}Q>}^#Oz1lpOqhxx2kk1YRg% z&uJ38d0H>Ht-X#But(Jn3O$=17|$jgW3d}77OcX+nM_w0+0Xgd5i52Vht~*`167}{ z4HYac-BrAND5W86+1KD<(i&sQE@Iq315uoj@Y1B-C8ma%e!pD9GC;wXDdPrUP5o7p zkSrgM;EL;p@|M!^Ql;K7e>2cnh#se@0Jv94U{D1ce?}L@{@popU_Fxz<+a1tsP$vR z9ZfcqaT*NH3(LtUts#SYm%C7%Ps;FwO^@og6h3aHhcA4^NEvogvD2WwRAei+q_CP{ z^d^Sx+XFm2HO&fFCGh=3(+9&e8@NCrRPW*!$z@rDS-TDezyd~m>#|?7T$A7H(BYl& zuwjU}p>Drp(anDnVOUk7e0igVE}nZGC;KCSdwlz;w1LwpK5nP2M?>Y^T?dV0h^D_)+bM^w)h%`>}swEd2{R++@+ zlT&1r6h+=&+^`(4axdWm$1TtN2J!pCa@1zt;ToLxzT>RKU1YD4HWZLD6{bfSY)DoMAH&&0LT;7w;%keB!TjBqZ(*9m|mQnC94!1)Zlr2@y=ynsa1zZ z)S^uM4P~;vgy!LOEERO&e27^mw#n{d1_6ao@(cmY8?I=fC9Ob)6s6CRJp0VUGpvLd>z2xeb=D)s*(hVhcEnV4|lP-XF zNV5~oDZwlmDNGZy@PLqB% zb7V93a#hc{3^ZLi&}f4kK0uu%g37yLFP7tGzJ06{r|%$Qi$B2Nv7=%$>|X_Xd~8XO zqM8UTu^BD51n!l&QJ)R~_S?&QFU@{0$@SXbkM*@ivIQwb;Rkw0C9ILKT3>6WC9hbq zxoWSl9@zDL{fV>R<>vGWLyxfuOFXBe#O1zqh&~BZ_t3&jQ%i99%{_6$nuq}$pdr7z zCJE9XY;l)m$hkOqbIPC; zB>`pCZiFkR9jW)%Qxi}~q^4+fKITKxKZ5u`({F1}9WIX&OFm`)v^V1|%FyM$R`xVH z;%@N8<{T+l8i_|Tk((^4`%gXCg>n!VsBKk@{d#hwG-)JZkSORNgn8#Dvda@rHh;Ofd7YY= zpUcf0Xs*$97b*(&pqS*msqYl9ThMLbwG(=NQyQ4j7Ne83$V+-$+me!&TeZc9lK)4vU|G4*lhe4 z7%EBsGAh9^l?Rpz za@jetWQ2M01+bBr&lT@x`I5V;@Iiu_{+PHFFyi6-WYv>smHe^^0;E81rMc+xS{YXEzs$N`c>w! z#O>gLKmFDpaEvO)C^0Bxy5KwAOeU60AFeFp-IZS`Zbau}?}sbMWu^-;P{Gmv?qB~& zF{TDkF363}bYfMGQa&jcRZ-L*f0>y7a=#YOkNb7b$3TicuIJCEO*i#@yPAgM_TSLk zThL8KMQIJHMXt;OIepFO?C>;ks`xepHaMEv9DxRD4J77Tz)D1*@UUB>h6P;ERz6{Js=M z^5e=yYw}%E9-HmR*=b@t2(YEzGoJVn7OGkXVQ>wnM#>Y_Ek$b)Ok9=ezseoAn9SA# z?}namNt3J&-)JXZ=Mh!ZZA1qDWU@68`O0|CgXs!N(s-PKuI%9o#Hl(2VRD()6-Rx$ zinw4F^^&4#!1ZBttAkxCxrQ8%c?5$`2rUDb)QTL_k1Db>EGN5&INXdEajxr@L~x_}^bkhO--mo$WMgZvjHDpox z9Rz0=H<&hU)C98^qZDwX?^4QhBy#>}mn-0nP1&>=Xz@nEYbc-AHj@LA4++MrNZ@LWc6c|icEzk$jj3|#Pn60R; z0f+ODXd%&^PkWmp`w6a0M5Bg#d(mX;ZJWlJc`STzH6d(TOH9H|Qnqw{3&!#y>6AoO zpM*g;G0`3MHZivA1ism=(5SbDN`{7N%OI1Y)h{V+Y!#EVutPzdA?yd*6uHOGMc7dy z<>)T5z~#5|$}vMjrML{=#a1~nq=gx%pafmAXcH4WMS(->`L|KokdvTg+H7Cgn;bl#^dTdxSnlSP#p3CykYeh2@FJj2ab3cMYVj{ZSC z*TleiD)u;{;`d@~XlRHHJM~P8P30L|wOR`~2zF(*Bpk33$;=uBA(2r_nyj2hy3~fB zmMYnjh6pp-wz1TnrJ+o53No~$75tZbdY3=f{F8ni6UtAtt5i)Zi-IY!2#*^0IXIXz zO|0YnZ4r=EuLlYPBhXsrxU&{UB764mPO_4hieWjq(lLIR-^#v zuDn$r<=@#3TdUJU)0IxQiUhI{&Fq!>hCw$@1>R}qnTmPJvlNxW z52$ro)cjlNbcAYK(c$!bgJAPyUnp3#l-|wDi<+- zW8#Uq0_w+~sQS#sGi)^%N7@0~MYm7$!@m>fAnbS9i`Ix5xYrk9c>!Gv$yfG1+FAw7 zHszrfVF_ZVJ^!S%UF)?Ac);I^!R0)}-YxKa&P;Gdt?}=bPvYz#^Jf{b+Kt7!m%O}I zVg5MGCi56EnI)*e5ALaaoH()Qq$N~zm6`7fpBoT59u@a~(QZ=yryMSUffV^JM*i|;5;fqUP9dZZz zcaUphcfY5ySkRlJGb+gX;myC=#pI5#|A>@P2r)fVa6#Vwsd#z{!gTBEqT3i;rl7k5 z{0u{NpVdITn1bfhMTs^M<&PSSN`)4`mdyKrEq&(3{*E=;{xmr90Bnj9gd*m)5w@&^ zoIdwzcR7r>czmB2-B!TeqDHK8`&>1*d|M3OM@Rm$oJP_oK9b~6R7E)V@=wn#+&hRZ z3mDRS^FHCa?g;2k7X2Y^wQoK4(mQN!?qSR@VhPa5|!15=} zOqv5X_I#=Mlrq3 z&XIC;fkeCx*u`DA0CxvUtR$P$Hu}^{1J`XwHLs>uz$PME|1_SFB7M%eGfnI-RYt~z z@QO@dGf@M+iVH2P>-Cd|5~ZTRV|}F|U=Fi@z*q9Ha3}bqu%_<(zRHr)cBxJcBH*^^ z)ohM5)aLS9mZ*`YG1IWs0a;e*(PO+rd%gKQM-^=0xAvB%~{?rxwh1pTV>dMnKKY>aBrhJMZVCaxL+?A;^E=`9vqM>d9wJ`+a^gTVU zGbx5DL5ZM>tlxUl9-etn6@)-n4nDFH0jEy&brODEdweQE7JSJ#PwD&ID%d{_$Y;Tr zKa7h3=(EqVd~N^IWK=1yy5fM_6}a)DkP--FhT3>VNU%Cw60T4nSk54A9?W1fpAprIH%2M+={-RchILaY2t1e|qLKj69K(l{^_0ukC%D85q zMMv%tR8!~#K67|JM8yTJD^}QDZxqR>VhCEhXI~pPsf7-6evC`nLL}j+P|;}$$?vM{FP#9<_huYMxjudQP+G5KVH5E_ zqU-J?ai^~pOB8<(@)RxVj)HPJorPP-#`f|hh~S=`0n^66D+XmkET-$3_7pAX`%uw97Q$-)S++`H2lm!mdf9t*GCleJQ-D-J;U^}&~ zlB@39NL1Iu)}_2~d}I}?d$HhSfi`9M9_E5+dmie14L5Hfz4UDqj-2Bs_u_0w7YlVg zJh&1>W!Lg8=^|u7>=sD)N=%i-x52~s_AbG3;Z(Yx)g}K^j*+h)OOkx<9?D7Lm=|cJ z%~@&p_;>eg`CD2feOAotVMdvES@WfI#;EugwyA-%yzxZTC59I$AJ%H9gJ0+fzZfMh ze8x3(5-V0ky0{`d?H`AdL%Q&T9AK{|wC16N%v0`M_TfwmHc8K&s07SCgMoIRsh?^c zI)zR+3#Il6=0t~|6&xN0qL}tyc~^Rw0KvveH~JL}7~?M}xe1X(7xlEearYZ9ho+fZ zSB1`o1!MC{96MDrI;lP&F84h)2Qae5y{nNer$Hc3h7lK2$OhJnc8MFa2pM;Rb?Z0z zBTCrQEETElhfkW9Jr^7^T=A4{f5qD*Bd$)ePgIu4!tV|9&idt=hD-^VvF`)^?xT2 y7t9lNeyU&)8`sG^%AV_<8))%d;Qe2A9*P#5Ng6(+-2Y$OSXD_=v0mOH;(q`p9_J4L literal 0 HcmV?d00001 diff --git a/data/skins/kitty_toptri.png b/data/skins/kitty_toptri.png new file mode 100644 index 0000000000000000000000000000000000000000..7f530bcb15e243e453e0ab0ad233cf730c31d159 GIT binary patch literal 7146 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 literal 0 HcmV?d00001 diff --git a/data/skins/kitty_twinbop.png b/data/skins/kitty_twinbop.png new file mode 100644 index 0000000000000000000000000000000000000000..224893e4e3d27e4572413a82c14806cffab5472b GIT binary patch literal 7400 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 literal 0 HcmV?d00001 diff --git a/data/skins/kitty_warpaint.png b/data/skins/kitty_warpaint.png new file mode 100644 index 0000000000000000000000000000000000000000..9573da4306549c2c537962385d30fefadbc68c32 GIT binary patch literal 7435 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 DaxFg+ literal 0 HcmV?d00001 diff --git a/data/skins/kitty_x_ninja.png b/data/skins/kitty_x_ninja.png new file mode 100644 index 0000000000000000000000000000000000000000..336eb27a857e31af51720e9128b3402e66e072da GIT binary patch literal 5979 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 u{9QC*5jVk`JF-+5&EQcW^8W$7H-Hb Date: Tue, 25 Jul 2017 19:08:16 +0200 Subject: [PATCH 46/70] Add ui_close_window_after_changing_setting --- src/game/client/components/menus_ingame.cpp | 3 ++- src/game/variables.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp index d8d61833e..0299f529e 100644 --- a/src/game/client/components/menus_ingame.cpp +++ b/src/game/client/components/menus_ingame.cpp @@ -650,7 +650,8 @@ void CMenus::RenderServerControl(CUIRect MainView) if(s_ControlPage == 0) { m_pClient->m_pVoting->CallvoteOption(m_CallvoteSelectedOption, m_aCallvoteReason); - SetActive(false); + if(g_Config.m_UiCloseWindowAfterChangingSetting) + SetActive(false); } else if(s_ControlPage == 1) { diff --git a/src/game/variables.h b/src/game/variables.h index d1084f5b5..32b501f17 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -104,6 +104,7 @@ MACRO_CONFIG_INT(UiColorizePing, ui_colorize_ping, 1, 0, 1, CFGFLAG_CLIENT|CFGFL MACRO_CONFIG_INT(UiColorizeGametype, ui_colorize_gametype, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Highlight gametype") MACRO_CONFIG_STR(UiDemoSelected, ui_demo_selected, 256, "", CFGFLAG_CLIENT|CFGFLAG_SAVE, "Selected demo file") +MACRO_CONFIG_INT(UiCloseWindowAfterChangingSetting, ui_close_window_after_changing_setting, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Close window after changing setting") MACRO_CONFIG_INT(GfxNoclip, gfx_noclip, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Disable clipping") From 379f060126ade9f961d836aefd00e263aee023df Mon Sep 17 00:00:00 2001 From: def Date: Tue, 25 Jul 2017 19:09:05 +0200 Subject: [PATCH 47/70] Version 10.7.1 --- src/game/client/components/menus_settings.cpp | 4 ++-- src/game/version.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index f52e0337c..02045fa56 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -433,14 +433,14 @@ void CMenus::RenderSettingsTee(CUIRect MainView) Dummy.HSplitTop(20.0f, &DummyLabel, &Dummy); - if(DoButton_CheckBox(&g_Config.m_ClKittySkins, Localize("Kitty skins"), g_Config.m_ClKittySkins, &DummyLabel)) + if(DoButton_CheckBox(&g_Config.m_ClKittySkins, Localize("Kitty skins (DDCat)"), g_Config.m_ClKittySkins, &DummyLabel)) { g_Config.m_ClKittySkins ^= 1; } Dummy.HSplitTop(20.0f, &DummyLabel, &Dummy); - if(DoButton_CheckBox(&g_Config.m_ClFatSkins, Localize("Fat skins"), g_Config.m_ClFatSkins, &DummyLabel)) + if(DoButton_CheckBox(&g_Config.m_ClFatSkins, Localize("Fat skins (DDFat)"), g_Config.m_ClFatSkins, &DummyLabel)) { g_Config.m_ClFatSkins ^= 1; } diff --git a/src/game/version.h b/src/game/version.h index 1a96054e2..b8dd46e43 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -3,8 +3,8 @@ #ifndef GAME_VERSION_H #define GAME_VERSION_H #include "generated/nethash.cpp" -#define GAME_VERSION "0.6.3, 10.7" +#define GAME_VERSION "0.6.3, 10.7.1" #define GAME_NETVERSION "0.6 626fce9a778df4d4" -static const char GAME_RELEASE_VERSION[8] = "10.7"; -#define CLIENT_VERSIONNR 10070 +static const char GAME_RELEASE_VERSION[8] = "10.7.1"; +#define CLIENT_VERSIONNR 10071 #endif From 5a437b110f8efdb1c27e38f26b7681ff7d1c33cb Mon Sep 17 00:00:00 2001 From: def Date: Tue, 25 Jul 2017 19:23:10 +0200 Subject: [PATCH 48/70] Nicer formatting for task fetcher --- src/engine/client/fetcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/client/fetcher.cpp b/src/engine/client/fetcher.cpp index cb251be34..6e86063ce 100644 --- a/src/engine/client/fetcher.cpp +++ b/src/engine/client/fetcher.cpp @@ -86,7 +86,7 @@ void CFetcher::FetcherThread(void *pUser) lock_unlock(pFetcher->m_Lock); if(pTask) { - dbg_msg("fetcher", "task got %s:%s", pTask->m_aUrl, pTask->m_aDest); + dbg_msg("fetcher", "task got %s -> %s", pTask->m_aUrl, pTask->m_aDest); pFetcher->FetchFile(pTask); if(pTask->m_pfnCompCallback) pTask->m_pfnCompCallback(pTask, pTask->m_pUser); From 8ab1c66eccf516369bf5c846b13fa6f280946270 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 25 Jul 2017 23:50:50 +0200 Subject: [PATCH 49/70] Lazy developers --- .gitmodules | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 23aa58d9f..5e1392e40 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,3 @@ [submodule "ddnet-libs"] path = ddnet-libs url = https://github.com/ddnet/ddnet-libs - shallow = true From fd8bccb0f48f4ef6bb61827fe733dac9d5c17314 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Wed, 26 Jul 2017 04:30:56 +0200 Subject: [PATCH 50/70] Fix the CMake Mac build Fixes #805. --- CMakeLists.txt | 45 +++++++++++++++++++++++++---- cmake/FindSDL2.cmake | 4 ++- ddnet-libs | 2 +- src/game/client/components/chat.cpp | 2 +- src/osx/notification.h | 4 +-- src/osx/notification.m | 20 +------------ src/osx/notification.mm | 19 ++++++++++++ 7 files changed, 66 insertions(+), 30 deletions(-) mode change 100644 => 120000 src/osx/notification.m create mode 100644 src/osx/notification.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index d34e2989c..daee99aa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set(CLIENT_EXECUTABLE DDNet CACHE STRING "Name of the build client executable") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(TARGET_BITS "64") -else() +elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) set(TARGET_BITS "32") endif() @@ -33,8 +33,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(TARGET_OS "mac") endif() -message(STATUS "Target OS: ${TARGET_OS} ${TARGET_BITS}bit") - function(set_extra_dirs VARIABLE NAME) if(TARGET_BITS AND TARGET_OS) set("EXTRA_${VARIABLE}_LIBDIR" "ddnet-libs/${NAME}/${TARGET_OS}/lib${TARGET_BITS}" PARENT_SCOPE) @@ -61,8 +59,9 @@ find_package(Threads) find_package(ZLIB) message(STATUS "******** DDNet ********") -message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") +message(STATUS "Target OS: ${TARGET_OS} ${TARGET_BITS}bit") message(STATUS "Compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "Dependencies:") function(show_dependency_status NAME FOUND PATH) @@ -118,9 +117,23 @@ if(CLIENT AND NOT(SDL2_FOUND)) endif() if(TARGET_OS STREQUAL "windows") + set(PLATFORM_CLIENT) set(PLATFORM_CLIENT_LIBS opengl32 glu32 winmm) set(PLATFORM_LIBS ws2_32) # Windows sockets +elseif(TARGET_OS STREQUAL "mac") + find_library(CARBON Carbon) + find_library(COCOA Cocoa) + find_library(OPENGL OpenGL) + set(PLATFORM_CLIENT + src/osx/notification.h + src/osx/notification.mm + src/osxlaunch/client.h + src/osxlaunch/client.m + ) + set(PLATFORM_CLIENT_LIBS ${COCOA} ${OPENGL}) + set(PLATFORM_LIBS ${CARBON}) else() + set(PLATFORM_CLIENT) set(PLATFORM_CLIENT_LIBS GL GLU X11) if(TARGET_OS STREQUAL "linux") set(PLATFORM_LIBS rt) # clock_gettime for glibc < 2.17 @@ -143,6 +156,8 @@ endif() set(TARGETS_OWN) set(TARGETS_DEP) +set(TARGETS_LINK) # Targets with a linking stage. + ######################################################################## # DEPENDENCY COMPILATION ######################################################################## @@ -275,7 +290,7 @@ if(CLIENT) file(GLOB_RECURSE GAME_CLIENT "src/game/client/*.cpp" "src/game/client/*.h") file(GLOB_RECURSE GAME_EDITOR "src/game/editor/*.cpp" "src/game/editor/*.h") set(GAME_GENERATED_CLIENT "src/game/generated/client_data.cpp" "src/game/generated/client_data.h") - set(CLIENT_SRC ${ENGINE_CLIENT} ${GAME_CLIENT} ${GAME_EDITOR} ${GAME_GENERATED_CLIENT}) + set(CLIENT_SRC ${ENGINE_CLIENT} ${PLATFORM_CLIENT} ${GAME_CLIENT} ${GAME_EDITOR} ${GAME_GENERATED_CLIENT}) set(DEPS_CLIENT ${DEPS} ${DEP_JSON} ${DEP_PNG} ${DEP_WAV}) @@ -324,6 +339,7 @@ if(CLIENT) ${SDL2_INCLUDE_DIRS} ) list(APPEND TARGETS_OWN ${TARGET_CLIENT}) + list(APPEND TARGETS_LINK ${TARGET_CLIENT}) endif() @@ -360,6 +376,7 @@ add_executable(${TARGET_SERVER} ) target_link_libraries(${TARGET_SERVER} ${LIBS_SERVER}) list(APPEND TARGETS_OWN ${TARGET_SERVER}) +list(APPEND TARGETS_LINK ${TARGET_SERVER}) ######################################################################## # VARIOUS TARGETS @@ -385,6 +402,7 @@ target_link_libraries(${TARGET_VERSIONSRV} ${LIBS}) target_link_libraries(${TARGET_TWPING} ${LIBS}) list(APPEND TARGETS_OWN ${TARGET_MASTERSRV} ${TARGET_TWPING} ${TARGET_VERSIONSRV}) +list(APPEND TARGETS_LINK ${TARGET_MASTERSRV} ${TARGET_TWPING} ${TARGET_VERSIONSRV}) set(TARGETS_TOOLS) file(GLOB TOOLS RELATIVE "${PROJECT_SOURCE_DIR}/src/tools/" "src/tools/*.cpp") @@ -408,6 +426,7 @@ foreach(T ${TOOLS}) endforeach() list(APPEND TARGETS_OWN ${TARGETS_TOOLS}) +list(APPEND TARGETS_LINK ${TARGETS_TOOLS}) add_custom_target(tools DEPENDS ${TARGETS_TOOLS}) add_custom_target(everything DEPENDS ${TARGETS_OWN}) @@ -440,7 +459,6 @@ foreach(target ${TARGETS}) target_compile_options(${target} PRIVATE /EHsc) # Only catch C++ exceptions with catch. target_compile_options(${target} PRIVATE /GS) # Protect the stack pointer. target_compile_options(${target} PRIVATE /wd4996) # Use of non-_s functions. - set_property(TARGET ${target} APPEND PROPERTY LINK_FLAGS /SAFESEH:NO) # disable seh because the shipped libraries don't support it elseif(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU) if(ENABLE_STACK_PROTECTOR) target_compile_options(${target} PRIVATE -fstack-protector-all) # Protect the stack pointer. @@ -449,6 +467,21 @@ foreach(target ${TARGETS}) target_compile_definitions(${target} PRIVATE $<$>:_FORTIFY_SOURCE=2>) # Detect some buffer overflows. endif() endif() + if(TARGET_OS STREQUAL "mac") + target_compile_options(${target} PRIVATE -stdlib=libc++) + target_compile_options(${target} PRIVATE -mmacosx-version-min=10.7) + endif() +endforeach() + +if(TARGET_OS STREQUAL "windows") + set_property(TARGET ${TARGET_CLIENT} APPEND PROPERTY LINK_FLAGS /SAFESEH:NO) # Disable SafeSEH because the shipped libraries don't support it. +endif() + +foreach(target ${TARGETS_LINK}) + if(TARGET_OS STREQUAL "mac") + target_link_libraries(${target} -stdlib=libc++) + target_link_libraries(${target} -mmacosx-version-min=10.7) + endif() endforeach() foreach(target ${TARGETS_OWN}) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 12fc219b1..ec1998169 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -3,7 +3,9 @@ pkg_check_modules(PC_SDL2 sdl2) set_extra_dirs(SDL2 sdl) -find_path(SDL2_INCLUDEDIR SDL.h +# Looking for 'SDL.h' directly might accidently find a SDL instead of SDL 2 +# installation. Look for a header file only present in SDL 2 instead. +find_path(SDL2_INCLUDEDIR SDL_assert.h PATH_SUFFIXES SDL2 HINTS ${PC_SDL2_INCLUDEDIR} ${PC_SDL2_INCLUDE_DIRS} PATHS ${EXTRA_SDL2_INCLUDEDIR} diff --git a/ddnet-libs b/ddnet-libs index f7ab5bfcf..8c2489d7e 160000 --- a/ddnet-libs +++ b/ddnet-libs @@ -1 +1 @@ -Subproject commit f7ab5bfcfb38adeaac9906df520e1305f0004fea +Subproject commit 8c2489d7e184af1935ff6486033de94cabf11eec diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp index b2f5b00b7..f0a5de19c 100644 --- a/src/game/client/components/chat.cpp +++ b/src/game/client/components/chat.cpp @@ -577,7 +577,7 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine) #ifdef CONF_PLATFORM_MACOSX char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "%s%s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText); - CNotification::notify("DDNet-Chat", aBuf); + CNotification::Notify("DDNet-Chat", aBuf); #else Graphics()->NotifyWindow(); #endif diff --git a/src/osx/notification.h b/src/osx/notification.h index ce32f9bcc..ec2dbc6f7 100644 --- a/src/osx/notification.h +++ b/src/osx/notification.h @@ -3,8 +3,8 @@ class CNotification { - public: - static void notify(const char *pTitle, const char *pMsg); +public: + static void Notify(const char *pTitle, const char *pMsg); }; #endif // NOTIFICATION_H diff --git a/src/osx/notification.m b/src/osx/notification.m deleted file mode 100644 index e0aa39eaa..000000000 --- a/src/osx/notification.m +++ /dev/null @@ -1,19 +0,0 @@ -#import -#import -#import -#import "notification.h" - -void CNotification::notify(const char *pTitle, const char *pMsg) -{ - NSString* title = [NSString stringWithCString:pTitle encoding:NSUTF8StringEncoding]; - NSString* msg = [NSString stringWithCString:pMsg encoding:NSUTF8StringEncoding]; - - NSUserNotification *notification = [[NSUserNotification alloc] autorelease]; - notification.title = title; - notification.informativeText = msg; - notification.soundName = NSUserNotificationDefaultSoundName; - - [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; - - [NSApp requestUserAttention:NSInformationalRequest]; // use NSCriticalRequest to annoy the user (doesn't stop bouncing) -} diff --git a/src/osx/notification.m b/src/osx/notification.m new file mode 120000 index 000000000..047beaaa1 --- /dev/null +++ b/src/osx/notification.m @@ -0,0 +1 @@ +notification.mm \ No newline at end of file diff --git a/src/osx/notification.mm b/src/osx/notification.mm new file mode 100644 index 000000000..761a0564f --- /dev/null +++ b/src/osx/notification.mm @@ -0,0 +1,19 @@ +#import +#import +#import +#import "notification.h" + +void CNotification::Notify(const char *pTitle, const char *pMsg) +{ + NSString* pNsTitle = [NSString stringWithCString:pTitle encoding:NSUTF8StringEncoding]; + NSString* pNsMsg = [NSString stringWithCString:pMsg encoding:NSUTF8StringEncoding]; + + NSUserNotification *pNotification = [[NSUserNotification alloc] autorelease]; + pNotification.title = pNsTitle; + pNotification.informativeText = pNsMsg; + pNotification.soundName = NSUserNotificationDefaultSoundName; + + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:pNotification]; + + [NSApp requestUserAttention:NSInformationalRequest]; // use NSCriticalRequest to annoy the user (doesn't stop bouncing) +} From c76bb9d5cee468da305d01cecb65cc1875fabfa9 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Wed, 26 Jul 2017 04:57:14 +0200 Subject: [PATCH 51/70] Add macOS to Travis --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e4f3a0c9..3c004faab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,16 @@ language: c++ sudo: false dist: trusty +os: +- linux +- osx addons: apt: packages: - libfreetype6-dev - libsdl2-dev script: -- git submodule update --init +- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install sdl2; fi - mkdir build - cd build - cmake .. From ed0949cb2ef32562651a658ba34f067818d4c361 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Wed, 26 Jul 2017 11:38:26 +0200 Subject: [PATCH 52/70] Remove unused function `gui_messagebox` The Mac implementation was causing problems and it wasn't used anywhere. --- src/base/system.c | 42 ------------------------------------------ src/base/system.h | 10 ---------- 2 files changed, 52 deletions(-) diff --git a/src/base/system.c b/src/base/system.c index ffba556b8..fc0b02da2 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -2270,48 +2270,6 @@ void net_stats(NETSTATS *stats_inout) *stats_inout = network_stats; } -void gui_messagebox(const char *title, const char *message) -{ -#if defined(CONF_PLATFORM_MACOSX) - DialogRef theItem; - DialogItemIndex itemIndex; - - /* FIXME: really needed? can we rely on glfw? */ - /* HACK - get events without a bundle */ - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - TransformProcessType(&psn,kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); - /* END HACK */ - - CreateStandardAlert(kAlertStopAlert, - CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII), - CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII), - NULL, - &theItem); - - RunStandardAlert(theItem, NULL, &itemIndex); -#elif defined(CONF_FAMILY_UNIX) - static char cmd[1024]; - int err; - /* use xmessage which is available on nearly every X11 system */ - snprintf(cmd, sizeof(cmd), "xmessage -center -title '%s' '%s'", - title, - message); - - err = system(cmd); - dbg_msg("gui/msgbox", "result = %i", err); -#elif defined(CONF_FAMILY_WINDOWS) - MessageBox(NULL, - message, - title, - MB_ICONEXCLAMATION | MB_OK); -#else - /* this is not critical */ - #warning not implemented -#endif -} - int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; } char str_uppercase(char c) diff --git a/src/base/system.h b/src/base/system.h index b7da26d68..69790b5f9 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -1295,16 +1295,6 @@ int str_isspace(char c); char str_uppercase(char c); unsigned str_quickhash(const char *str); -/* - Function: gui_messagebox - Display plain OS-dependent message box - - Parameters: - title - title of the message box - message - text to display -*/ -void gui_messagebox(const char *title, const char *message); - /* Function: str_utf8_comp_confusable Compares two strings for visual appearance. From 98f229c48b0309076cfb6f80fbac3fc5f6221625 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Wed, 26 Jul 2017 11:53:21 +0200 Subject: [PATCH 53/70] Fix a `-Wunused-value` warning in `map_diff` --- src/tools/map_diff.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/map_diff.cpp b/src/tools/map_diff.cpp index 17fe9ddc8..89f073edb 100644 --- a/src/tools/map_diff.cpp +++ b/src/tools/map_diff.cpp @@ -47,7 +47,7 @@ bool Process(IStorage *pStorage, char **pMapNames) { pItem[i] = (CMapItemLayer *)Maps[i].GetItem(Start[i]+j, 0, 0); pTilemap[i] = (CMapItemLayerTilemap *)pItem[i]; - (CTile *)Maps[i].GetData(pTilemap[i]->m_Data); + (void)(CTile *)Maps[i].GetData(pTilemap[i]->m_Data); } } From adef38a5745d8139b118e7df8b6004ab3ca03d40 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 26 Jul 2017 18:12:41 +0200 Subject: [PATCH 54/70] Revert "We want the Timestamp of a team to stay min(Timestamp) to indicate the first time this team finished the map" This reverts commit bf0e67a34ab8bfe866daf5c07ef6f72ff2be1fb0. --- src/game/server/score/sql_score.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp index c1192a414..7151ef66f 100644 --- a/src/game/server/score/sql_score.cpp +++ b/src/game/server/score/sql_score.cpp @@ -688,7 +688,7 @@ bool CSqlScore::SaveTeamScoreThread(CSqlServer* pSqlServer, const CSqlData *pGam if (aUpdateID[0]) { - str_format(aBuf, sizeof(aBuf), "UPDATE %s_teamrace SET Time='%.2f' WHERE ID = '%s';", pSqlServer->GetPrefix(), pData->m_Time, aUpdateID); + str_format(aBuf, sizeof(aBuf), "UPDATE %s_teamrace SET Time='%.2f', Timestamp=CURRENT_TIMESTAMP() WHERE ID = '%s';", pSqlServer->GetPrefix(), pData->m_Time, aUpdateID); dbg_msg("sql", "%s", aBuf); pSqlServer->executeSql(aBuf); } From d513af6a42fb219880e95d18efb9612af39822f1 Mon Sep 17 00:00:00 2001 From: Marcel Herd Date: Wed, 26 Jul 2017 20:43:26 +0200 Subject: [PATCH 55/70] Removed default bind for home key (kill) Kill is already bound to K by default, binding it on home as well doesn't really have any purpose. (?) Furthermore, the home key is right next to page up which is bound to toggling entities. It is very easy to accidentally hit home instead of page up, which is highly frustrating.. therefore I suggest removing this duplicate binding. --- src/game/client/components/binds.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/game/client/components/binds.cpp b/src/game/client/components/binds.cpp index 129131065..09f537e68 100644 --- a/src/game/client/components/binds.cpp +++ b/src/game/client/components/binds.cpp @@ -319,7 +319,6 @@ void CBinds::SetDDRaceBinds(bool FreeOnly) Bind(KEY_KP_PLUS, "zoom+", FreeOnly); Bind(KEY_KP_MINUS, "zoom-", FreeOnly); Bind(KEY_KP_MULTIPLY, "zoom", FreeOnly); - Bind(KEY_HOME, "kill", FreeOnly); Bind(KEY_PAUSE, "say /pause", FreeOnly); Bind(KEY_UP, "+jump", FreeOnly); Bind(KEY_LEFT, "+left", FreeOnly); From 6247aa0c7f3ba6647db576667e190c1f87a2ea77 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Wed, 26 Jul 2017 03:58:00 +0200 Subject: [PATCH 56/70] Enable `-Wextra` and `-Wformat=2` Also annotate `dbg_msg`, `str_format` and `str_timestamp_ex` so that the compiler can determine whether the format strings are correct. Fix the compiler warnings generated by these extra warnings -- some of them were security issues. --- CMakeLists.txt | 6 ++-- src/base/system.c | 16 +++++---- src/base/system.h | 15 ++++++-- src/engine/client/input.cpp | 8 ++--- src/engine/client/input.h | 6 ++-- src/engine/shared/datafile.cpp | 6 ++-- src/engine/shared/kernel.cpp | 2 +- src/engine/shared/network_server.cpp | 2 +- src/game/client/components/menus.cpp | 12 +++---- src/game/client/gameclient.h | 4 +-- src/game/localization.h | 3 +- src/game/server/entities/character.cpp | 35 +++++++++---------- src/game/server/gamecontext.cpp | 47 +++++++++++++------------- src/game/server/gamecontext.h | 10 +++--- src/tools/map_extract.cpp | 12 +++---- 15 files changed, 99 insertions(+), 85 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d34e2989c..0c75bb4d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -461,8 +461,10 @@ foreach(target ${TARGETS_OWN}) if(CMAKE_VERSION VERSION_GREATER 3.3 OR CMAKE_VERSION VERSION_EQUAL 3.3) target_compile_options(${target} PRIVATE $<$:-Wdeclaration-after-statement>) endif() - #target_compile_options(${target} PRIVATE -Wextra) - #target_compile_options(${target} PRIVATE -Wformat=2) # Warn about format strings. + target_compile_options(${target} PRIVATE -Wextra) + target_compile_options(${target} PRIVATE -Wno-unused-parameter) + target_compile_options(${target} PRIVATE -Wno-missing-field-initializers) + target_compile_options(${target} PRIVATE -Wformat=2) # Warn about format strings. endif() target_include_directories(${target} PRIVATE src) target_compile_definitions(${target} PRIVATE $<$:CONF_DEBUG>) diff --git a/src/base/system.c b/src/base/system.c index ffba556b8..127768048 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -193,13 +193,10 @@ void dbg_msg(const char *sys, const char *fmt, ...) //str_format(str, sizeof(str), "[%08x][%s]: ", (int)time(0), sys); time_t rawtime; - struct tm* timeinfo; - char timestr [80]; + char timestr[80]; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); - - strftime (timestr,sizeof(timestr),"%y-%m-%d %H:%M:%S",timeinfo); + time(&rawtime); + str_timestamp_ex(rawtime, timestr, sizeof(timestr), "%Y-%m %H:%M:%S"); #if !defined(CONF_PLATFORM_MACOSX) if(dbg_msg_threaded) @@ -2228,7 +2225,14 @@ void str_timestamp_ex(time_t time_data, char *buffer, int buffer_size, const cha struct tm *time_info; time_info = localtime(&time_data); + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wformat-nonliteral" + #endif strftime(buffer, buffer_size, format, time_info); + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif buffer[buffer_size-1] = 0; /* assure null termination */ } diff --git a/src/base/system.h b/src/base/system.h index b7da26d68..0c8b5b75a 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -45,6 +45,12 @@ void dbg_assert_imp(const char *filename, int line, int test, const char *msg); #define dbg_assert(test,msg) assert(test) #endif +#ifdef __GNUC__ +#define GNUC_ATTRIBUTE(x) __attribute__(x) +#else +#define GNUC_ATTRIBUTE(x) +#endif + /* Function: dbg_break Breaks into the debugger. @@ -77,7 +83,8 @@ void dbg_break_imp(); See Also: */ -void dbg_msg(const char *sys, const char *fmt, ...); +void dbg_msg(const char *sys, const char *fmt, ...) +GNUC_ATTRIBUTE((format(printf, 2, 3))); /* Group: Memory */ @@ -795,7 +802,8 @@ int str_length(const char *str); - The strings are treated as zero-termineted strings. - Garantees that dst string will contain zero-termination. */ -int str_format(char *buffer, int buffer_size, const char *format, ...); +int str_format(char *buffer, int buffer_size, const char *format, ...) +GNUC_ATTRIBUTE((format(printf, 3, 4))); /* Function: str_trim_words @@ -1056,7 +1064,8 @@ int str_hex_decode(unsigned char *dst, int dst_size, const char *src); - Guarantees that buffer string will contain zero-termination. */ void str_timestamp(char *buffer, int buffer_size); -void str_timestamp_ex(time_t time, char *buffer, int buffer_size, const char *format); +void str_timestamp_ex(time_t time, char *buffer, int buffer_size, const char *format) +GNUC_ATTRIBUTE((format(strftime, 4, 0))); /* Function: str_escape diff --git a/src/engine/client/input.cpp b/src/engine/client/input.cpp index ac6d0b2ce..3d8b37db1 100644 --- a/src/engine/client/input.cpp +++ b/src/engine/client/input.cpp @@ -169,8 +169,8 @@ void CInput::SetIMEState(bool Activate) const char* CInput::GetIMECandidate() { - if (str_length(m_pEditingText)) - return m_pEditingText; + if (str_length(m_aEditingText)) + return m_aEditingText; else return ""; } @@ -211,10 +211,10 @@ int CInput::Update() { if(str_length(Event.edit.text)) { - str_format(m_pEditingText, sizeof(m_pEditingText), Event.edit.text); + str_copy(m_aEditingText, Event.edit.text, sizeof(m_aEditingText)); m_EditingCursor = 0; for (int i = 0; i < Event.edit.start; i++) - m_EditingCursor = str_utf8_forward(m_pEditingText, m_EditingCursor); + m_EditingCursor = str_utf8_forward(m_aEditingText, m_EditingCursor); } break; } diff --git a/src/engine/client/input.h b/src/engine/client/input.h index fda9b93a4..1351fd96d 100644 --- a/src/engine/client/input.h +++ b/src/engine/client/input.h @@ -20,14 +20,14 @@ class CInput : public IEngineInput void Clear(); bool IsEventValid(CEvent *pEvent) const { return pEvent->m_InputCount == m_InputCounter; }; - //quick access to input + // quick access to input unsigned short m_aInputCount[g_MaxKeys]; // tw-KEY unsigned char m_aInputState[g_MaxKeys]; // SDL_SCANCODE int m_InputCounter; - //ime support + // IME support int m_CountEditingText; - char m_pEditingText[32]; + char m_aEditingText[32]; int m_EditingCursor; bool KeyState(int Key) const; diff --git a/src/engine/shared/datafile.cpp b/src/engine/shared/datafile.cpp index 533077249..d48b3f1ad 100644 --- a/src/engine/shared/datafile.cpp +++ b/src/engine/shared/datafile.cpp @@ -299,7 +299,7 @@ void *CDataFileReader::GetDataImpl(int Index, int Swap) unsigned long UncompressedSize = m_pDataFile->m_Info.m_pDataSizes[Index]; unsigned long s; - dbg_msg("datafile", "loading data index=%d size=%d uncompressed=%d", Index, DataSize, UncompressedSize); + dbg_msg("datafile", "loading data index=%d size=%d uncompressed=%lu", Index, DataSize, UncompressedSize); m_pDataFile->m_ppDataPtrs[Index] = (char *)mem_alloc(UncompressedSize, 1); // read the compressed data @@ -589,7 +589,7 @@ int CDataFileWriter::Finish() for(int i = 0; i < m_NumItems; i++) { if(DEBUG) - dbg_msg("datafile", "item=%d size=%d (%d)", i, m_pItems[i].m_Size, m_pItems[i].m_Size+sizeof(CDatafileItem)); + dbg_msg("datafile", "item=%d size=%d (%d)", i, m_pItems[i].m_Size, m_pItems[i].m_Size + (int)sizeof(CDatafileItem)); ItemSize += m_pItems[i].m_Size + sizeof(CDatafileItem); } @@ -626,7 +626,7 @@ int CDataFileWriter::Finish() // write Header if(DEBUG) - dbg_msg("datafile", "HeaderSize=%d", sizeof(Header)); + dbg_msg("datafile", "HeaderSize=%d", (int)sizeof(Header)); #if defined(CONF_ARCH_ENDIAN_BIG) swap_endian(&Header, sizeof(int), sizeof(Header)/sizeof(int)); #endif diff --git a/src/engine/shared/kernel.cpp b/src/engine/shared/kernel.cpp index b422b591a..95ecddbd0 100644 --- a/src/engine/shared/kernel.cpp +++ b/src/engine/shared/kernel.cpp @@ -77,7 +77,7 @@ public: { if(FindInterfaceInfo(pName) == 0) { - dbg_msg("kernel", "ERROR: couldn't reregister interface '%s'. interface doesn't exist"); + dbg_msg("kernel", "ERROR: couldn't reregister interface '%s'. interface doesn't exist", pName); return false; } diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index d0ea38bcd..8cf0c50f9 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -503,7 +503,7 @@ void CNetServer::OnConnCtrlMsg(NETADDR &Addr, int ClientID, int ControlMsg, cons // correct token // try to accept client if (g_Config.m_Debug) - dbg_msg("security", "client %d reconnect"); + dbg_msg("security", "client %d reconnect", ClientID); // reset netconn and process rejoin m_aSlots[ClientID].m_Connection.Reset(true); diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 74b05019c..b79225a1f 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -368,7 +368,7 @@ int CMenus::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrS char aInputing[32] = {0}; if(UI()->HotItem() == pID && Input()->GetIMEState()) { - str_format(aInputing, sizeof(aInputing), pStr); + str_copy(aInputing, pStr, sizeof(aInputing)); const char *Text = Input()->GetIMECandidate(); if (str_length(Text)) { @@ -1098,7 +1098,7 @@ int CMenus::Render() pButtonText = Localize("Ok"); if(Client()->m_ReconnectTime > 0) { - str_format(aBuf, sizeof(aBuf), Localize("\n\nReconnect in %d sec"), ((Client()->m_ReconnectTime - time_get()) / time_freq() + g_Config.m_ClReconnectFull)); + str_format(aBuf, sizeof(aBuf), Localize("\n\nReconnect in %d sec"), (int)((Client()->m_ReconnectTime - time_get()) / time_freq() + g_Config.m_ClReconnectFull)); pTitle = Client()->ErrorString(); pExtraText = aBuf; pButtonText = Localize("Abort"); @@ -1344,18 +1344,18 @@ int CMenus::Render() UI()->DoLabel(&Part, aBuf, 20.f, 0, -1); // time left - const char *pTimeLeftString; int TimeLeft = max(1, m_DownloadSpeed > 0.0f ? static_cast((Client()->MapDownloadTotalsize()-Client()->MapDownloadAmount())/m_DownloadSpeed) : 1); if(TimeLeft >= 60) { TimeLeft /= 60; - pTimeLeftString = TimeLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"); + str_format(aBuf, sizeof(aBuf), TimeLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"), TimeLeft); } else - pTimeLeftString = TimeLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"); + { + str_format(aBuf, sizeof(aBuf), TimeLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"), TimeLeft); + } Box.HSplitTop(20.f, 0, &Box); Box.HSplitTop(24.f, &Part, &Box); - str_format(aBuf, sizeof(aBuf), pTimeLeftString, TimeLeft); UI()->DoLabel(&Part, aBuf, 20.f, 0, -1); // progress bar diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index cc4deb85e..47c0e3de2 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "render.h" @@ -442,7 +443,4 @@ inline vec3 RgbToHsl(vec3 RGB) vec3 CalculateNameColor(vec3 TextColorHSL); -extern const char *Localize(const char *Str); - - #endif diff --git a/src/game/localization.h b/src/game/localization.h index 49edd8602..06cd7fd99 100644 --- a/src/game/localization.h +++ b/src/game/localization.h @@ -56,5 +56,6 @@ public: }; -extern const char *Localize(const char *pStr); +extern const char *Localize(const char *pStr) +GNUC_ATTRIBUTE((format_arg(1))); #endif diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 19d82a2a4..c8aca2e82 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -1977,34 +1977,35 @@ void CCharacter::HandleTuneLayer() void CCharacter::SendZoneMsgs() { // send zone leave msg - if (m_TuneZoneOld >= 0 && GameServer()->m_ZoneLeaveMsg[m_TuneZoneOld]) // m_TuneZoneOld >= 0: avoid zone leave msgs on spawn + // (m_TuneZoneOld >= 0: avoid zone leave msgs on spawn) + if (m_TuneZoneOld >= 0 && GameServer()->m_aaZoneLeaveMsg[m_TuneZoneOld]) { - const char* cur = GameServer()->m_ZoneLeaveMsg[m_TuneZoneOld]; - const char* pos; - while ((pos = str_find(cur, "\\n"))) + const char *pCur = GameServer()->m_aaZoneLeaveMsg[m_TuneZoneOld]; + const char *pPos; + while ((pPos = str_find(pCur, "\\n"))) { char aBuf[256]; - str_copy(aBuf, cur, pos - cur + 1); - aBuf[pos - cur + 1] = '\0'; - cur = pos + 2; + str_copy(aBuf, pCur, pPos - pCur + 1); + aBuf[pPos - pCur + 1] = '\0'; + pCur = pPos + 2; GameServer()->SendChatTarget(m_pPlayer->GetCID(), aBuf); } - GameServer()->SendChatTarget(m_pPlayer->GetCID(), cur); + GameServer()->SendChatTarget(m_pPlayer->GetCID(), pCur); } // send zone enter msg - if (GameServer()->m_ZoneEnterMsg[m_TuneZone]) + if (GameServer()->m_aaZoneEnterMsg[m_TuneZone]) { - const char* cur = GameServer()->m_ZoneEnterMsg[m_TuneZone]; - const char* pos; - while ((pos = str_find(cur, "\\n"))) + const char* pCur = GameServer()->m_aaZoneEnterMsg[m_TuneZone]; + const char* pPos; + while ((pPos = str_find(pCur, "\\n"))) { char aBuf[256]; - str_copy(aBuf, cur, pos - cur + 1); - aBuf[pos - cur + 1] = '\0'; - cur = pos + 2; + str_copy(aBuf, pCur, pPos - pCur + 1); + aBuf[pPos - pCur + 1] = '\0'; + pCur = pPos + 2; GameServer()->SendChatTarget(m_pPlayer->GetCID(), aBuf); } - GameServer()->SendChatTarget(m_pPlayer->GetCID(), cur); + GameServer()->SendChatTarget(m_pPlayer->GetCID(), pCur); } } @@ -2240,7 +2241,7 @@ void CCharacter::Rescue() if (m_LastRescue + g_Config.m_SvRescueDelay * Server()->TickSpeed() > Server()->Tick()) { char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "You have to wait %d seconds until you can rescue yourself", (m_LastRescue + g_Config.m_SvRescueDelay * Server()->TickSpeed() - Server()->Tick()) / Server()->TickSpeed()); + str_format(aBuf, sizeof(aBuf), "You have to wait %d seconds until you can rescue yourself", (int)((m_LastRescue + g_Config.m_SvRescueDelay * Server()->TickSpeed() - Server()->Tick()) / Server()->TickSpeed())); GameServer()->SendChatTarget(GetPlayer()->GetCID(), aBuf); return; } diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 978d876a6..2ac91cdb4 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -516,7 +516,7 @@ void CGameContext::SendTuningParams(int ClientID, int Zone) if (Zone == 0) pParams = (int *)&m_Tuning; else - pParams = (int *)&(m_TuningList[Zone]); + pParams = (int *)&(m_aTuningList[Zone]); unsigned int last = sizeof(m_Tuning)/sizeof(int); if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion < VERSION_DDNET_EXTRATUNES) @@ -1237,7 +1237,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) if(Now < pPlayer->m_FirstVoteTick) { char aBuf[64]; - str_format(aBuf, sizeof(aBuf), "You must wait %d seconds before making your first vote", ((pPlayer->m_FirstVoteTick - Now) / TickSpeed) + 1); + str_format(aBuf, sizeof(aBuf), "You must wait %d seconds before making your first vote", (int)((pPlayer->m_FirstVoteTick - Now) / TickSpeed) + 1); SendChatTarget(ClientID, aBuf); return; } @@ -1246,7 +1246,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) if(pPlayer->m_LastVoteCall && TimeLeft > 0) { char aChatmsg[64]; - str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (TimeLeft/TickSpeed)+1); + str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (int)(TimeLeft / TickSpeed) + 1); SendChatTarget(ClientID, aChatmsg); return; } @@ -1281,9 +1281,8 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) } if(!m_apPlayers[ClientID]->m_Authed && (str_comp_num(pOption->m_aCommand, "sv_map ", 7) == 0 || str_comp_num(pOption->m_aCommand, "change_map ", 11) == 0 || str_comp_num(pOption->m_aCommand, "random_map", 10) == 0 || str_comp_num(pOption->m_aCommand, "random_unfinished_map", 21) == 0) && time_get() < m_LastMapVote + (time_freq() * g_Config.m_SvVoteMapTimeDelay)) { - char chatmsg[512] = {0}; - str_format(chatmsg, sizeof(chatmsg), "There's a %d second delay between map-votes, please wait %d seconds.", g_Config.m_SvVoteMapTimeDelay,((m_LastMapVote+(g_Config.m_SvVoteMapTimeDelay * time_freq()))/time_freq())-(time_get()/time_freq())); - SendChatTarget(ClientID, chatmsg); + str_format(aChatmsg, sizeof(aChatmsg), "There's a %d second delay between map-votes, please wait %d seconds.", g_Config.m_SvVoteMapTimeDelay, (int)(((m_LastMapVote+(g_Config.m_SvVoteMapTimeDelay * time_freq()))/time_freq())-(time_get()/time_freq()))); + SendChatTarget(ClientID, aChatmsg); return; } @@ -1334,12 +1333,11 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) return; else if(!m_apPlayers[ClientID]->m_Authed && time_get() < m_apPlayers[ClientID]->m_Last_KickVote + (time_freq() * g_Config.m_SvVoteKickDelay)) { - char chatmsg[512] = {0}; - str_format(chatmsg, sizeof(chatmsg), "There's a %d second wait time between kick votes for each player please wait %d second(s)", + str_format(aChatmsg, sizeof(aChatmsg), "There's a %d second wait time between kick votes for each player please wait %d second(s)", g_Config.m_SvVoteKickDelay, - ((m_apPlayers[ClientID]->m_Last_KickVote + (m_apPlayers[ClientID]->m_Last_KickVote*time_freq()))/time_freq())-(time_get()/time_freq()) + (int)(((m_apPlayers[ClientID]->m_Last_KickVote + (m_apPlayers[ClientID]->m_Last_KickVote*time_freq()))/time_freq())-(time_get()/time_freq())) ); - SendChatTarget(ClientID, chatmsg); + SendChatTarget(ClientID, aChatmsg); m_apPlayers[ClientID]->m_Last_KickVote = time_get(); return; } @@ -1846,7 +1844,7 @@ void CGameContext::ConTuneZone(IConsole::IResult *pResult, void *pUserData) const char *pParamName = pResult->GetString(1); float NewValue = pResult->GetFloat(2); - if (List >= 0 && List < NUM_TUNINGZONES) + if (List >= 0 && List < NUM_TUNEZONES) { if(pSelf->TuningList()[List].Set(pParamName, NewValue)) { @@ -1865,7 +1863,7 @@ void CGameContext::ConTuneDumpZone(IConsole::IResult *pResult, void *pUserData) CGameContext *pSelf = (CGameContext *)pUserData; int List = pResult->GetInteger(0); char aBuf[256]; - if (List >= 0 && List < NUM_TUNINGZONES) + if (List >= 0 && List < NUM_TUNEZONES) { for(int i = 0; i < pSelf->TuningList()[List].Num(); i++) { @@ -1884,7 +1882,7 @@ void CGameContext::ConTuneResetZone(IConsole::IResult *pResult, void *pUserData) if (pResult->NumArguments()) { int List = pResult->GetInteger(0); - if (List >= 0 && List < NUM_TUNINGZONES) + if (List >= 0 && List < NUM_TUNEZONES) { pSelf->TuningList()[List] = TuningParams; char aBuf[256]; @@ -1895,7 +1893,7 @@ void CGameContext::ConTuneResetZone(IConsole::IResult *pResult, void *pUserData) } else { - for (int i = 0; i < NUM_TUNINGZONES; i++) + for (int i = 0; i < NUM_TUNEZONES; i++) { *(pSelf->TuningList()+i) = TuningParams; pSelf->SendTuningParams(-1, i); @@ -1910,9 +1908,9 @@ void CGameContext::ConTuneSetZoneMsgEnter(IConsole::IResult *pResult, void *pUse if (pResult->NumArguments()) { int List = pResult->GetInteger(0); - if (List >= 0 && List < NUM_TUNINGZONES) + if (List >= 0 && List < NUM_TUNEZONES) { - str_format(pSelf->m_ZoneEnterMsg[List], sizeof(pSelf->m_ZoneEnterMsg[List]), pResult->GetString(1)); + str_copy(pSelf->m_aaZoneEnterMsg[List], pResult->GetString(1), sizeof(pSelf->m_aaZoneEnterMsg[List])); } } } @@ -1923,9 +1921,9 @@ void CGameContext::ConTuneSetZoneMsgLeave(IConsole::IResult *pResult, void *pUse if (pResult->NumArguments()) { int List = pResult->GetInteger(0); - if (List >= 0 && List < NUM_TUNINGZONES) + if (List >= 0 && List < NUM_TUNEZONES) { - str_format(pSelf->m_ZoneLeaveMsg[List], sizeof(pSelf->m_ZoneLeaveMsg[List]), pResult->GetString(1)); + str_copy(pSelf->m_aaZoneLeaveMsg[List], pResult->GetString(1), sizeof(pSelf->m_aaZoneLeaveMsg[List])); } } } @@ -2443,7 +2441,7 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/) // Reset Tunezones CTuningParams TuningParams; - for (int i = 0; i < NUM_TUNINGZONES; i++) + for (int i = 0; i < NUM_TUNEZONES; i++) { TuningList()[i] = TuningParams; TuningList()[i].Set("gun_curvature", 0); @@ -2453,10 +2451,11 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/) TuningList()[i].Set("shotgun_speeddiff", 0); } - for (int i = 0; i < NUM_TUNINGZONES; i++) // decided to send no text on changing Tunezones for now + for (int i = 0; i < NUM_TUNEZONES; i++) { - str_format(m_ZoneEnterMsg[i], sizeof(m_ZoneEnterMsg[i]), "", i); - str_format(m_ZoneLeaveMsg[i], sizeof(m_ZoneLeaveMsg[i]), "", i); + // Send no text by default when changing tune zones. + m_aaZoneEnterMsg[i][0] = 0; + m_aaZoneLeaveMsg[i][0] = 0; } // Reset Tuning if(g_Config.m_SvTuneReset) @@ -2503,7 +2502,7 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/) Tuning()->Set("player_collision", 0); Tuning()->Set("player_hooking", 0); - for (int i = 0; i < NUM_TUNINGZONES; i++) + for (int i = 0; i < NUM_TUNEZONES; i++) { TuningList()[i].Set("player_collision", 0); TuningList()[i].Set("player_hooking", 0); @@ -3209,7 +3208,7 @@ void CGameContext::List(int ClientID, const char *pFilter) if (pFilter[0]) str_format(aBuf, sizeof(aBuf), "Listing players with \"%s\" in name:", pFilter); else - str_format(aBuf, sizeof(aBuf), "Listing all players:", pFilter); + str_format(aBuf, sizeof(aBuf), "Listing all players:"); SendChatTarget(ClientID, aBuf); for(int i = 0; i < MAX_CLIENTS; i++) { diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index ccf081e81..24aa018ac 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -48,7 +48,7 @@ typedef unsigned __int64 uint64_t; enum { - NUM_TUNINGZONES = 256 + NUM_TUNEZONES = 256 }; class CGameContext : public IGameServer @@ -59,7 +59,7 @@ class CGameContext : public IGameServer CCollision m_Collision; CNetObjHandler m_NetObjHandler; CTuningParams m_Tuning; - CTuningParams m_TuningList[NUM_TUNINGZONES]; + CTuningParams m_aTuningList[NUM_TUNEZONES]; static void ConTuneParam(IConsole::IResult *pResult, void *pUserData); static void ConTuneReset(IConsole::IResult *pResult, void *pUserData); @@ -100,7 +100,7 @@ public: class IConsole *Console() { return m_pConsole; } CCollision *Collision() { return &m_Collision; } CTuningParams *Tuning() { return &m_Tuning; } - CTuningParams *TuningList() { return &m_TuningList[0]; } + CTuningParams *TuningList() { return &m_aTuningList[0]; } CGameContext(); ~CGameContext(); @@ -134,8 +134,8 @@ public: char m_aVoteReason[VOTE_REASON_LENGTH]; int m_NumVoteOptions; int m_VoteEnforce; - char m_ZoneEnterMsg[NUM_TUNINGZONES][256]; // 0 is used for switching from or to area without tunings - char m_ZoneLeaveMsg[NUM_TUNINGZONES][256]; + char m_aaZoneEnterMsg[NUM_TUNEZONES][256]; // 0 is used for switching from or to area without tunings + char m_aaZoneLeaveMsg[NUM_TUNEZONES][256]; char m_aDeleteTempfile[128]; void DeleteTempfile(); diff --git a/src/tools/map_extract.cpp b/src/tools/map_extract.cpp index 0b1c800c2..e9fe815ef 100644 --- a/src/tools/map_extract.cpp +++ b/src/tools/map_extract.cpp @@ -25,10 +25,10 @@ bool Process(IStorage *pStorage, const char *pMapName, const char *pPathSave) CMapItemInfo *pInfo = (CMapItemInfo *)Map.FindItem(MAPITEMTYPE_INFO, 0); - dbg_msg("map_extract", "author: %s", Map.GetData(pInfo->m_Author)); - dbg_msg("map_extract", "version: %s", Map.GetData(pInfo->m_MapVersion)); - dbg_msg("map_extract", "credits: %s", Map.GetData(pInfo->m_Credits)); - dbg_msg("map_extract", "license: %s", Map.GetData(pInfo->m_License)); + dbg_msg("map_extract", "author: %s", (char *)Map.GetData(pInfo->m_Author)); + dbg_msg("map_extract", "version: %s", (char *)Map.GetData(pInfo->m_MapVersion)); + dbg_msg("map_extract", "credits: %s", (char *)Map.GetData(pInfo->m_Credits)); + dbg_msg("map_extract", "license: %s", (char *)Map.GetData(pInfo->m_License)); int Start, Num; @@ -77,7 +77,7 @@ bool Process(IStorage *pStorage, const char *pMapName, const char *pPathSave) return Map.Close(); } -int main(int argc, char* argv[]) +int main(int argc, char *argv[]) { dbg_logger_stdout(); @@ -104,7 +104,7 @@ int main(int argc, char* argv[]) if (!fs_is_dir(aDir)) { - dbg_msg("usage" "directory '%s' does not exist", aDir); + dbg_msg("usage", "directory '%s' does not exist", aDir); return -1; } From 50a397e32c50801811076666500eecfbad01ffb5 Mon Sep 17 00:00:00 2001 From: HMH Date: Sat, 29 Jul 2017 13:50:37 +0200 Subject: [PATCH 57/70] removed unused and outdated docs folder, closes #826 --- docs/conf/Data/ClassHierarchy.nd | Bin 424 -> 0 bytes docs/conf/Data/ConfigFileInfo.nd | Bin 26 -> 0 bytes docs/conf/Data/FileInfo.nd | 254 -- docs/conf/Data/ImageFileInfo.nd | Bin 8 -> 0 bytes docs/conf/Data/ImageReferenceTable.nd | Bin 8 -> 0 bytes docs/conf/Data/IndexInfo.nd | Bin 226 -> 0 bytes docs/conf/Data/PreviousMenuState.nd | Bin 868 -> 0 bytes docs/conf/Data/PreviousSettings.nd | Bin 103 -> 0 bytes docs/conf/Data/SymbolTable.nd | Bin 9634 -> 0 bytes docs/conf/Languages.txt | 113 - docs/conf/Menu.txt | 92 - docs/conf/Topics.txt | 81 - docs/tool/Config/Languages.txt | 286 -- docs/tool/Config/Topics.txt | 382 -- docs/tool/Help/customizinglanguages.html | 52 - docs/tool/Help/customizingtopics.html | 74 - docs/tool/Help/documenting.html | 58 - docs/tool/Help/documenting/reference.html | 146 - docs/tool/Help/documenting/walkthrough.html | 180 - docs/tool/Help/example/Default.css | 528 --- docs/tool/Help/example/NaturalDocs.js | 204 - docs/tool/Help/examples.css | 90 - docs/tool/Help/images/header/background.png | Bin 171 -> 0 bytes docs/tool/Help/images/header/leftside.png | Bin 1087 -> 0 bytes docs/tool/Help/images/header/logo.png | Bin 10663 -> 0 bytes docs/tool/Help/images/header/overbody.png | Bin 221 -> 0 bytes docs/tool/Help/images/header/overbodybg.png | Bin 88 -> 0 bytes .../Help/images/header/overleftmargin.png | Bin 105 -> 0 bytes docs/tool/Help/images/header/overmenu.png | Bin 190 -> 0 bytes docs/tool/Help/images/header/overmenubg.png | Bin 88 -> 0 bytes docs/tool/Help/images/header/rightside.png | Bin 1042 -> 0 bytes docs/tool/Help/images/logo.gif | Bin 8221 -> 0 bytes docs/tool/Help/images/menu/about.png | Bin 339 -> 0 bytes docs/tool/Help/images/menu/background.png | Bin 133 -> 0 bytes docs/tool/Help/images/menu/bottomleft.png | Bin 175 -> 0 bytes docs/tool/Help/images/menu/bottomright.png | Bin 180 -> 0 bytes docs/tool/Help/images/menu/community.png | Bin 451 -> 0 bytes docs/tool/Help/images/menu/customizing.png | Bin 514 -> 0 bytes docs/tool/Help/images/menu/using.png | Bin 332 -> 0 bytes docs/tool/Help/index.html | 9 - docs/tool/Help/javascript/BrowserStyles.js | 77 - docs/tool/Help/javascript/PNGHandling.js | 72 - docs/tool/Help/keywords.html | 38 - docs/tool/Help/languages.html | 32 - docs/tool/Help/menu.html | 79 - docs/tool/Help/output.html | 84 - docs/tool/Help/running.html | 40 - docs/tool/Help/styles.css | 290 -- docs/tool/Help/styles.html | 52 - docs/tool/Help/troubleshooting.html | 18 - docs/tool/Info/CSSGuide.txt | 947 ----- docs/tool/Info/File Parsing.txt | 83 - docs/tool/Info/HTMLTestCases.pm | 269 -- docs/tool/Info/Languages.txt | 107 - docs/tool/Info/NDMarkup.txt | 91 - docs/tool/Info/Symbol Management.txt | 59 - docs/tool/Info/images/Logo.png | Bin 11591 -> 0 bytes docs/tool/JavaScript/NaturalDocs.js | 836 ---- docs/tool/License-GPL.txt | 341 -- docs/tool/Modules/NaturalDocs/BinaryFile.pm | 294 -- docs/tool/Modules/NaturalDocs/Builder.pm | 280 -- docs/tool/Modules/NaturalDocs/Builder/Base.pm | 348 -- .../Modules/NaturalDocs/Builder/FramedHTML.pm | 345 -- docs/tool/Modules/NaturalDocs/Builder/HTML.pm | 398 -- .../Modules/NaturalDocs/Builder/HTMLBase.pm | 3693 ----------------- .../Modules/NaturalDocs/ClassHierarchy.pm | 860 ---- .../NaturalDocs/ClassHierarchy/Class.pm | 412 -- .../NaturalDocs/ClassHierarchy/File.pm | 157 - docs/tool/Modules/NaturalDocs/ConfigFile.pm | 497 --- docs/tool/Modules/NaturalDocs/Constants.pm | 165 - .../tool/Modules/NaturalDocs/DefineMembers.pm | 100 - docs/tool/Modules/NaturalDocs/Error.pm | 305 -- docs/tool/Modules/NaturalDocs/File.pm | 540 --- .../NaturalDocs/ImageReferenceTable.pm | 383 -- .../ImageReferenceTable/Reference.pm | 44 - .../NaturalDocs/ImageReferenceTable/String.pm | 110 - docs/tool/Modules/NaturalDocs/Languages.pm | 1475 ------- .../NaturalDocs/Languages/ActionScript.pm | 1473 ------- .../tool/Modules/NaturalDocs/Languages/Ada.pm | 38 - .../Modules/NaturalDocs/Languages/Advanced.pm | 828 ---- .../NaturalDocs/Languages/Advanced/Scope.pm | 95 - .../Languages/Advanced/ScopeChange.pm | 70 - .../Modules/NaturalDocs/Languages/Base.pm | 832 ---- .../Modules/NaturalDocs/Languages/CSharp.pm | 1484 ------- .../Modules/NaturalDocs/Languages/PLSQL.pm | 319 -- .../Modules/NaturalDocs/Languages/Pascal.pm | 143 - .../Modules/NaturalDocs/Languages/Perl.pm | 1370 ------ .../NaturalDocs/Languages/Prototype.pm | 92 - .../Languages/Prototype/Parameter.pm | 87 - .../Modules/NaturalDocs/Languages/Simple.pm | 503 --- .../tool/Modules/NaturalDocs/Languages/Tcl.pm | 219 - docs/tool/Modules/NaturalDocs/Menu.pm | 3406 --------------- docs/tool/Modules/NaturalDocs/Menu/Entry.pm | 201 - docs/tool/Modules/NaturalDocs/NDMarkup.pm | 76 - docs/tool/Modules/NaturalDocs/Parser.pm | 1331 ------ .../Modules/NaturalDocs/Parser/JavaDoc.pm | 464 --- .../tool/Modules/NaturalDocs/Parser/Native.pm | 1060 ----- .../Modules/NaturalDocs/Parser/ParsedTopic.pm | 253 -- docs/tool/Modules/NaturalDocs/Project.pm | 1402 ------- .../Modules/NaturalDocs/Project/ImageFile.pm | 160 - .../Modules/NaturalDocs/Project/SourceFile.pm | 113 - .../Modules/NaturalDocs/ReferenceString.pm | 334 -- docs/tool/Modules/NaturalDocs/Settings.pm | 1418 ------- .../NaturalDocs/Settings/BuildTarget.pm | 66 - docs/tool/Modules/NaturalDocs/SourceDB.pm | 678 --- .../Modules/NaturalDocs/SourceDB/Extension.pm | 84 - .../tool/Modules/NaturalDocs/SourceDB/File.pm | 129 - .../tool/Modules/NaturalDocs/SourceDB/Item.pm | 201 - .../NaturalDocs/SourceDB/ItemDefinition.pm | 45 - .../SourceDB/WatchedFileDefinitions.pm | 159 - .../tool/Modules/NaturalDocs/StatusMessage.pm | 102 - docs/tool/Modules/NaturalDocs/SymbolString.pm | 212 - docs/tool/Modules/NaturalDocs/SymbolTable.pm | 1984 --------- .../Modules/NaturalDocs/SymbolTable/File.pm | 186 - .../NaturalDocs/SymbolTable/IndexElement.pm | 522 --- .../NaturalDocs/SymbolTable/Reference.pm | 273 -- .../SymbolTable/ReferenceTarget.pm | 97 - .../Modules/NaturalDocs/SymbolTable/Symbol.pm | 428 -- .../SymbolTable/SymbolDefinition.pm | 96 - docs/tool/Modules/NaturalDocs/Topics.pm | 1319 ------ docs/tool/Modules/NaturalDocs/Topics/Type.pm | 151 - docs/tool/Modules/NaturalDocs/Version.pm | 384 -- docs/tool/NaturalDocs | 400 -- docs/tool/NaturalDocs.bat | 17 - docs/tool/Styles/Default.css | 767 ---- docs/tool/Styles/Roman.css | 765 ---- docs/tool/Styles/Small.css | 763 ---- 127 files changed, 44069 deletions(-) delete mode 100644 docs/conf/Data/ClassHierarchy.nd delete mode 100644 docs/conf/Data/ConfigFileInfo.nd delete mode 100644 docs/conf/Data/FileInfo.nd delete mode 100644 docs/conf/Data/ImageFileInfo.nd delete mode 100644 docs/conf/Data/ImageReferenceTable.nd delete mode 100644 docs/conf/Data/IndexInfo.nd delete mode 100644 docs/conf/Data/PreviousMenuState.nd delete mode 100644 docs/conf/Data/PreviousSettings.nd delete mode 100644 docs/conf/Data/SymbolTable.nd delete mode 100644 docs/conf/Languages.txt delete mode 100644 docs/conf/Menu.txt delete mode 100644 docs/conf/Topics.txt delete mode 100644 docs/tool/Config/Languages.txt delete mode 100644 docs/tool/Config/Topics.txt delete mode 100644 docs/tool/Help/customizinglanguages.html delete mode 100644 docs/tool/Help/customizingtopics.html delete mode 100644 docs/tool/Help/documenting.html delete mode 100644 docs/tool/Help/documenting/reference.html delete mode 100644 docs/tool/Help/documenting/walkthrough.html delete mode 100644 docs/tool/Help/example/Default.css delete mode 100644 docs/tool/Help/example/NaturalDocs.js delete mode 100644 docs/tool/Help/examples.css delete mode 100644 docs/tool/Help/images/header/background.png delete mode 100644 docs/tool/Help/images/header/leftside.png delete mode 100644 docs/tool/Help/images/header/logo.png delete mode 100644 docs/tool/Help/images/header/overbody.png delete mode 100644 docs/tool/Help/images/header/overbodybg.png delete mode 100644 docs/tool/Help/images/header/overleftmargin.png delete mode 100644 docs/tool/Help/images/header/overmenu.png delete mode 100644 docs/tool/Help/images/header/overmenubg.png delete mode 100644 docs/tool/Help/images/header/rightside.png delete mode 100644 docs/tool/Help/images/logo.gif delete mode 100644 docs/tool/Help/images/menu/about.png delete mode 100644 docs/tool/Help/images/menu/background.png delete mode 100644 docs/tool/Help/images/menu/bottomleft.png delete mode 100644 docs/tool/Help/images/menu/bottomright.png delete mode 100644 docs/tool/Help/images/menu/community.png delete mode 100644 docs/tool/Help/images/menu/customizing.png delete mode 100644 docs/tool/Help/images/menu/using.png delete mode 100644 docs/tool/Help/index.html delete mode 100644 docs/tool/Help/javascript/BrowserStyles.js delete mode 100644 docs/tool/Help/javascript/PNGHandling.js delete mode 100644 docs/tool/Help/keywords.html delete mode 100644 docs/tool/Help/languages.html delete mode 100644 docs/tool/Help/menu.html delete mode 100644 docs/tool/Help/output.html delete mode 100644 docs/tool/Help/running.html delete mode 100644 docs/tool/Help/styles.css delete mode 100644 docs/tool/Help/styles.html delete mode 100644 docs/tool/Help/troubleshooting.html delete mode 100644 docs/tool/Info/CSSGuide.txt delete mode 100644 docs/tool/Info/File Parsing.txt delete mode 100644 docs/tool/Info/HTMLTestCases.pm delete mode 100644 docs/tool/Info/Languages.txt delete mode 100644 docs/tool/Info/NDMarkup.txt delete mode 100644 docs/tool/Info/Symbol Management.txt delete mode 100644 docs/tool/Info/images/Logo.png delete mode 100644 docs/tool/JavaScript/NaturalDocs.js delete mode 100644 docs/tool/License-GPL.txt delete mode 100644 docs/tool/Modules/NaturalDocs/BinaryFile.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Builder.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Builder/Base.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Builder/FramedHTML.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Builder/HTML.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Builder/HTMLBase.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ClassHierarchy.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ClassHierarchy/Class.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ClassHierarchy/File.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ConfigFile.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Constants.pm delete mode 100644 docs/tool/Modules/NaturalDocs/DefineMembers.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Error.pm delete mode 100644 docs/tool/Modules/NaturalDocs/File.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ImageReferenceTable.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ImageReferenceTable/Reference.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ImageReferenceTable/String.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/ActionScript.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Ada.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Advanced.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Advanced/Scope.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Base.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/CSharp.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/PLSQL.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Pascal.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Perl.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Prototype.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Prototype/Parameter.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Simple.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Languages/Tcl.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Menu.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Menu/Entry.pm delete mode 100644 docs/tool/Modules/NaturalDocs/NDMarkup.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Parser.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Parser/JavaDoc.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Parser/Native.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Parser/ParsedTopic.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Project.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Project/ImageFile.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Project/SourceFile.pm delete mode 100644 docs/tool/Modules/NaturalDocs/ReferenceString.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Settings.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Settings/BuildTarget.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SourceDB.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SourceDB/Extension.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SourceDB/File.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SourceDB/Item.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SourceDB/ItemDefinition.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm delete mode 100644 docs/tool/Modules/NaturalDocs/StatusMessage.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolString.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolTable.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolTable/File.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolTable/IndexElement.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolTable/Reference.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolTable/Symbol.pm delete mode 100644 docs/tool/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Topics.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Topics/Type.pm delete mode 100644 docs/tool/Modules/NaturalDocs/Version.pm delete mode 100644 docs/tool/NaturalDocs delete mode 100644 docs/tool/NaturalDocs.bat delete mode 100644 docs/tool/Styles/Default.css delete mode 100644 docs/tool/Styles/Roman.css delete mode 100644 docs/tool/Styles/Small.css diff --git a/docs/conf/Data/ClassHierarchy.nd b/docs/conf/Data/ClassHierarchy.nd deleted file mode 100644 index 5dbf4213249cf8908ed49910b9ed383e9280e23e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 424 zcmb7=u?oU46h+geLmm7DMUc8Q9}$W;I0-t(Qt^&{h^cA`7S@0Z6TJNa6SY3d4mQHO zfZkd_nyuz!6KmrrPgzX_U6a=?nD8cgzf4EP*c_FU>{t8m_ZDP+^Jq1(hvnHMJ)|-% Z7vgF(__NnQ@NN!|AKjpQwnp_4V;}2vgkAsu diff --git a/docs/conf/Data/ConfigFileInfo.nd b/docs/conf/Data/ConfigFileInfo.nd deleted file mode 100644 index 74be4db23e87ad3946dd8da960034b5d305b0d42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26 ScmZQ$)L>v>2^8g0-`hLgRy0B2s*}n2 z&YYc2=VAx|E$AeLMCDo#OxI}E5;vCsw;ytep;n<27;-Owmw1V(WO14r#xb^r$Eb3t zFithMajlv=0wcF|WYT*x1aK#{g6Gq4xmPx9ccxfrg?1L6PNVim*pP!6y#h@*EzvMP z`<#K-&vjWD&_cTJn4v+%k>1cx>h(-irs3{r66-x8LBw?pgfqt++7nE@FwgXpI<%iM zJTqls^oHhnu$LQF3dwCG;QlE0E24Y@D;RA%7ON~tW8C?`;AUcg!HhizHAL=c>v?wQEDFbMaWz}hA^nq`v>U;$zV1||kE{oK@)%tZZ^l%mAsRQ=+jWc~ES+*AfeLk0;ACC;K(qj!BrdQ$Jw2ySpYFl!*1qR?EpO{W#DP#@Ji;F@+7l6k zyd4CJ`=XsHzb)cX7>jlw{j{CNJW0ngOAoS7nRjO-V!Y_X%$=idr{6v5-tg{qehLF2 zKgd9MyZz&z-**p>24~%ixj1*7Cp`RX%y}Q1Q(~QR%jPIW-aV6p` zW!YG;Onl0wO0c1l6UO5iQzGS)B*F%6c=tP}@lbZ65MTG6^n|(+ioI3xI>o;|sWP+8 z{iQD8dwAv2yixN5zTfW{+q4S)eEJzXFmTI{c$#{($|h}Jtk5$qpQMS-_H z4C7z`$HOcXDXc%Aw?4wx+s4N>{r{TYBsYiC*v~>4BV2DzU?*kH5c4CMB5aazmdF&w zWsJB5h#TS<>!40ph-WMc)9e6<=(%Ht6RRO270wI1diONW5KbPgY^DHK(8rO7)(#s= z#m4fQ$zdkQVP79KcH)OuBEHINs@=ogH`jr)Te0cm8G7`Ap5Uhth4MyorMw-tA*T z{LI@)l>8J<@ZW*rK{%!8Kl}d~pdmh^*j?E@BlyodGR}BtfX$NeEDe1gu{8Wwe)jgg zmUlDY8OJ(}!c<=5H|J7=lJ-KR6i)a^FtUanRY+(H?r0*T{WRyD@|oQ486N9_SYc$7 zjO>Eku0nCWnVHH4SK5^!L!Ba@OEX({(lJ*eXpg7E;e^LTsHHT!cN(XOrJPj*Q*g|G z{*2=Bk!4(sME1kpL|lmdMPn%$5DzDQGK%mD*~_QumJkk@g8^U@d@$i$T93K4Icr2hMl zr|V_(lWIo)bBZDY2V0f$wNkyZRnhaF_8~MrA_h@ZR4f!DN-9lgAm_VI7kI5P0?{a0 zZw|vq7%sjC`4EJrF15Uu^ORCnI7$B9dK~{vK`>v{2b!`4u(7XKAd^2^02lk2g^C7< z5`_;09wiWOcvUY`ySlEY*`U)wig1(%h2X5I8UA2214Z4Mg;H^5Eny?k!eQt`M1cB0 zb7k#vlagiq}<|DI-ILZlV5OTl;$IO>|idpe-#m%#2G%pu);Fvo~fB07DHRoi5iD0mRU z6=%Qpu)0R&L%WXC#Do~=0fE!Rp2(yt+w>OoGsLyqM%lAo258YStf<-W#+?fz#~K8G z8C$>kt3Ypqw1=mf_L!s=hD5JMyHNr%5sJK|WD(pSgCvG%gT|obU0W#!f$-%7RD$MX zAuTMcujN+atE1eAme-f4!b08f?$|{PAur&ZWyW(_E_9!xj>cNg9V^)VhcDt{<(vQ@n1PR2O=w+Qm6YRb$O+WgL}Y^ghHs3PD6jc|9w1dw8bq+>+JCZZb4+$rwHqMo`_Gx9eMT+Qr9dm?Yw|Ba>sOd> zt+IY;YVfKOWPhp@pk?P}8LF(E8s&J~?T5%5d_b&c3JF$zHP5Bx=E8h$km1#OckvzV z@+BoE3OoJ_;uL{-rrQDcyehjNpVDLu%Er%fwZ5d>*ExOBc=@T34ieP-E=4I9p+S`vMhQm*mf--ZDLf8Ea))@z5~(kC;Ut{&IZL z!=bIm>#sGh8@Q4>!*F88l8Dc69s~-gI1DZvLd?hxbaKCAMH$U%*O&VJLz5?Y`-7~w z5;iS#a}>P9yv^u88u*f;Op<73sxq)O^-ceDiBYibNk{|lnnA(Q@rN$O=j~zVZ*cPI zQdC<7RUOxV-Op2kmZg}G4CA2Di7c3Et30P{S_z8bPc;#~utlYiH48*(lN4Z7UQnIN za;hv7z&7O@j<5RmHsU=L5AE_K;v>qyW-Je3{{qqh5__q@6kGqzd)_(!J5c0ZR5FtPV=aghmU#NNGFX@@0b{| zuAclf6Aw$-y@>HGfKE`QSO-DhE{vkKXhb6Q_^dVG?QN0DVJG@VWyKp5%vDeI z-ROz#e^c*Pr`>t+g6_zhs2aRpne5hFStZWU-gaYDE^CHXx)o}9Ul^yR6Fs0#YsOad z>Y??@HGDN=D|)ttTSzl(ui076smFSQVT>Pdgt*lfdY>CvG$F$^N3gjqg9(jK0(b+*=;qS /* */ - Function Prototype Enders: { < - - -Language: R - - Extension: r - Line Comment: # - Function Prototype Enders: { ; - Variable Prototype Enders: <- = ; \n - - -Language: Fortran - - Extensions: f90 f95 f03 - Line Comment: ! - Function Prototype Ender: \n - Variable Prototype Enders: \n = => - Line Extender: & diff --git a/docs/tool/Config/Topics.txt b/docs/tool/Config/Topics.txt deleted file mode 100644 index 75724d858..000000000 --- a/docs/tool/Config/Topics.txt +++ /dev/null @@ -1,382 +0,0 @@ -Format: 1.4 - -# This is the main Natural Docs topics file. If you change anything here, it -# will apply to EVERY PROJECT you use Natural Docs on. If you'd like to -# change something for just one project, edit the Topics.txt in its project -# directory instead. - - -#------------------------------------------------------------------------------- -# SYNTAX: -# -# Topic Type: [name] -# Creates a new topic type. Each type gets its own index and behavior -# settings. Its name can have letters, numbers, spaces, and these -# charaters: - / . ' -# -# The Enumeration type is special. It's indexed with Types but its members -# are indexed with Constants according to the rules in Languages.txt. -# -# Plural: [name] -# Sets the plural name of the topic type, if different. -# -# Keywords: -# [keyword] -# [keyword], [plural keyword] -# ... -# Defines a list of keywords for the topic type. They may only contain -# letters, numbers, and spaces and are not case sensitive. Plural keywords -# are used for list topics. -# -# Index: [yes|no] -# Whether the topics get their own index. Defaults to yes. Everything is -# included in the general index regardless of this setting. -# -# Scope: [normal|start|end|always global] -# How the topics affects scope. Defaults to normal. -# normal - Topics stay within the current scope. -# start - Topics start a new scope for all the topics beneath it, -# like class topics. -# end - Topics reset the scope back to global for all the topics -# beneath it. -# always global - Topics are defined as global, but do not change the scope -# for any other topics. -# -# Class Hierarchy: [yes|no] -# Whether the topics are part of the class hierarchy. Defaults to no. -# -# Page Title If First: [yes|no] -# Whether the topic's title becomes the page title if it's the first one in -# a file. Defaults to no. -# -# Break Lists: [yes|no] -# Whether list topics should be broken into individual topics in the output. -# Defaults to no. -# -# Can Group With: [type], [type], ... -# Defines a list of topic types that this one can possibly be grouped with. -# Defaults to none. -#------------------------------------------------------------------------------- - -# The following topics MUST be defined in this file: -# -# Generic, Class, Interface, Section, File, Group, Function, Variable, -# Property, Type, Constant, Enumeration, Event, Delegate - -# If you add something that you think would be useful to other developers -# and should be included in Natural Docs by default, please e-mail it to -# topics [at] naturaldocs [dot] org. - - -Topic Type: Generic - - Index: No - Keywords: - topic, topics - about, list - - -Topic Type: Class - - Plural: Classes - Scope: Start - Class Hierarchy: Yes - Page Title If First: Yes - Can Group With: Interfaces - - Keywords: - class, classes - structure, structures - struct, structs - package, packages - namespace, namespaces - - -Topic Type: Interface - - Plural: Interfaces - Scope: Start - Class Hierarchy: Yes - Page Title If First: Yes - Can Group With: Classes - - Keywords: - interface, interfaces - - -Topic Type: Section - - Plural: Sections - Index: No - Scope: End - Page Title If First: Yes - - Keywords: - section - title - - -Topic Type: File - - Plural: Files - Scope: Always global - Page Title If First: Yes - - Keywords: - file, files - program, programs - script, scripts - document, documents - doc, docs - header, headers - - -Topic Type: Group - - Plural: Groups - Index: No - - Keywords: - group - - -Topic Type: Function - - Plural: Functions - Break Lists: Yes - Can Group With: Properties - - Keywords: - function, functions - func, funcs - procedure, procedures - proc, procs - routine, routines - subroutine, subroutines - sub, subs - method, methods - callback, callbacks - constructor, constructors - destructor, destructors - operator, operators - - -Topic Type: Variable - - Plural: Variables - Can Group With: Types, Constants, Macros, Enumerations - - Keywords: - variable, variables - var, vars - integer, integers - int, ints - uint, uints - long, longs - ulong, ulongs - short, shorts - ushort, ushorts - byte, bytes - ubyte, ubytes - sbyte, sbytes - float, floats - double, doubles - real, reals - decimal, decimals - scalar, scalars - array, arrays - arrayref, arrayrefs - hash, hashes - hashref, hashrefs - bool, bools - boolean, booleans - flag, flags - bit, bits - bitfield, bitfields - field, fields - pointer, pointers - ptr, ptrs - reference, references - ref, refs - object, objects - obj, objs - character, characters - wcharacter, wcharacters - char, chars - wchar, wchars - string, strings - wstring, wstrings - str, strs - wstr, wstrs - handle, handles - - -Topic Type: Property - - Plural: Properties - Can Group With: Functions - - Keywords: - property, properties - prop, props - - -Topic Type: Type - - Plural: Types - Can Group With: Variables, Constants, Macros, Enumerations - - Keywords: - type, types - typedef, typedefs - - -Topic Type: Constant - - Plural: Constants - Can Group With: Variables, Types, Macros, Enumerations - - Keywords: - constant, constants - const, consts - - -Topic Type: Enumeration - - Plural: Enumerations - Index: No - Can Group With: Variables, Types, Macros, Constants - - Keywords: - enum, enums - enumeration, enumerations - - -Topic Type: Event - - Plural: Events - Keywords: - event, events - - -Topic Type: Delegate - - Plural: Delegates - Keywords: - delegate, delegates - - -Topic Type: Macro - - Plural: Macros - Can Group With: Variables, Types, Constants - - Keywords: - define, defines - def, defs - macro, macros - - -Topic Type: Database - - Plural: Databases - Page Title If First: Yes - - Keywords: - database, databases - db, dbs - - -Topic Type: Database Table - - Plural: Database Tables - Scope: Start - Page Title If First: Yes - - Keywords: - table, tables - database table, database tables - databasetable, databasetables - db table, db tables - dbtable, dbtables - - -Topic Type: Database View - - Plural: Database Views - Scope: Start - Page Title If First: Yes - - Keywords: - view, views - database view, database views - databaseview, databaseviews - db view, db views - dbview, dbviews - - -Topic Type: Database Index - - Plural: Database Indexes - Keywords: - index, indexes - index, indices - database index, database indexes - database index, database indices - databaseindex, databaseindexes - databaseindex, databaseindices - db index, db indexes - db index, db indices - dbindex, dbindexes - dbindex, dbindices - key, keys - database key, database keys - databasekey, databasekeys - db key, db keys - dbkey, dbkeys - primary key, primary keys - primarykey, primarykeys - database primary key, database primary keys - databaseprimarykey, databaseprimarykeys - db primary key, db primary keys - dbprimarykey, dbprimarykeys - - -Topic Type: Database Cursor - - Plural: Database Cursors - Keywords: - cursor, cursors - database cursor, database cursors - databasecursor, databasecursors - db cursor, db cursors - dbcursor, dbcursors - - -Topic Type: Database Trigger - - Plural: Database Triggers - Keywords: - trigger, triggers - database trigger, database triggers - databasetrigger, databasetriggers - db trigger, db triggers - dbtrigger, dbtriggers - - -Topic Type: Cookie - - Plural: Cookies - Scope: Always global - - Keywords: - cookie, cookies - - -Topic Type: Build Target - - Plural: Build Targets - Keywords: - target, targets - build target, build targets - buildtarget, buildtargets diff --git a/docs/tool/Help/customizinglanguages.html b/docs/tool/Help/customizinglanguages.html deleted file mode 100644 index 6c6509443..000000000 --- a/docs/tool/Help/customizinglanguages.html +++ /dev/null @@ -1,52 +0,0 @@ - - -Customizing Natural Docs Languages - - - -
Natural Docs
Customizing
Organizing the MenuCSS StylesTopics and KeywordsLanguages, Indexes,
and Prototypes
Customizing Languages
Languages.txt

Natural Docs has two files called Languages.txt: one in its Config directory, and one in your project directory.  These control the language, index prefix, and prototype features of Natural Docs.

You should edit the one in your project directory whenever possible.  It keeps your changes separate and easier to manage, plus you don’t have to reapply them whenever you upgrade.  Editing the one in Natural Docs’ Config directory would be better only if you’re using Natural Docs with a lot of projects and would like the changes to apply everywhere.

Note that unlike other Natural Docs configuration files, comments can only appear on their own lines.  They cannot appear after something else on a line because settings may need to use the # symbol.  Also, all lists are space-separated instead of comma-separated, again because some settings may need to use the comma symbol.

File Extensions

If Natural Docs doesn’t recognize a file extension you use for your code, it’s not a problem.  You can alter the language definition from your project file to add them.

Alter Language: [your language]
-   Add Extensions: cxx hxx

On the other hand, if it’s scanning some files you don’t want it to scan, you can exclude extensions as well.  Just add this to the top of your file:

Ignore Extensions: c cpp

In this example, Natural Docs will ignore C++ source files, thus only scanning the headers.

Adding Languages

You can add basic language support for any programming language just by editing these configuration files.  Here are the most important settings:

Language: Fictional
-
-   Extensions: fsrc fhdr
-   Shebang Strings: fictional
-   Line Comment: //
-   Block Comment: /* */
-   Package Separator: ::

This tells Natural Docs that any files with the .fsrc or .fhdr extensions are part of our fictional programming language.  Also, any .cgi or extensionless files that have “fictional” in the shebang (#!) line are part of it as well.  Line comments start with // and block comments appear between /* and */.  The default package separator is ::.  Not too hard, huh?

You can also add settings to ignore prefixes in the index and detect prototypes, but those are dealt with in their own sections on this page.

Prototypes

So you’ve added a new language and want to detect prototypes.  Or perhaps you added a custom topic type and want to detect prototypes for that as well.  Here’s an example of the properties you need:

Function Prototype Enders: ; {
-Variable Prototype Enders: ; =

The algorithm for finding prototypes is very simple, yet it works really well in practice.  All the code following the comment is grabbed until it reaches an ender symbol or another comment.  Ender symbols appearing inside parenthesis, brackets, braces, or angle brackets don’t count.  If it reaches an ender symbol and somewhere in that code is the topic title, the code is accepted as the prototype.

So in the example above, variables end at semicolons (the end of the declaration) or equal signs (the default value expression, which we don’t want to include.)  Since the Natural Docs comment for the variable should have appeared right before the definition, that leaves us with the name and type.  Functions are handled similarly: they end at a semicolon (the end of a predeclaration) or an opening brace (the beginning of the body) leaving us with the name, parameters, and return type.

You can do this with any topic type, including custom ones.  Any prototypes that look like they have parameters will be formatted as such automatically.

Line Breaks

For some languages, line breaks are significant.  To have them end a prototype, use \n.  If it has an extender symbol that allows the code to continue on the next line, you can specify that as well.

Function Prototype Ender: \n
-Variable Prototype Ender: \n =
-Line Extender: _
Colors

If you’re collecting prototypes for a custom topic type, they will not automatically get their own background color like the other types have.  You have to define it via CSS.

Index Prefixes

Natural Docs has the ability to ignore prefixes in the indexes.  This is necessary because in certain languages, variables are prefixed with $ or other symbols and we don’t want them to get all grouped together under the symbols heading.  Instead, they appear in the sidebar and are sorted as if they’re not there.

A
 AddProperty, SomeClass
$amount
 Average

However, we can take advantage of this simply to get around coding conventions.  Suppose you prefix all your class names with C.  They’d all form one gigantic group under C in the index.  If you want, you can have it ignored so CCat, CDog, and CMouse get filed under C, D, and M instead.  Just add this to your languages file:

Alter Language: [your language]
-   Add Ignored Class Prefix in Index: C

Now C is ignored in your indexes:

A
CAccount
CAccountHolder
 AddProperty, SomeClass
$amount
 Average

You can include any number of prefixes and can do this for any topic type.  So if you have a bunch of functions that start with COM_ and DB_, you can ignore them too:

Alter Language: [your language]
-   Add Ignored Class Prefix in Index: C
-   Add Ignored Function Prefixes in Index: COM_ DB_
Special Languages

There are two languages with special properties: Shebang Script and Text File.

Shebang Script allows you to define the file extensions where the language is really determined by the shebang (#!) line within it.  For example, .cgi files.  If Natural Docs finds a .cgi file, it sees that it’s a Shebang Script so it opens it up to parse it’s shebang line.  It then searches it for substrings defined by other languages’ Shebang String settings to find out what language it really is.  Files with no extension are always treated this way.

With Text File, the entire file is treated like a comment.  There are no comment symbols required, you can just put Natural Docs content there in plain text.  The most important setting is Extensions.

However, since it is possible to document classes, functions, etc. in text files, they also have their own Package Separator and Ignored [type] Prefixes in Index settings.  To make things easier on you, by default it copies these settings from whichever language has the most source files in your project.  You can override this by manually setting them, but you shouldn’t need to.

Syntax Reference

Unlike other Natural Docs configuration files, comments can only appear on their own lines.  They cannot appear after something else on a line because settings may need to use the # symbol.  Likewise, lists are separated with spaces instead of commas because commas themselves may need to appear on the list.

Singular and plural forms are generally both supported, so you can write Extension or Extensions.  It doesn’t matter if they match how many items are set.  Also, you can use either Ignore or Ignored.

Ignore Extensions: [extension] [extension] ...

Causes the listed file extensions to be ignored, even if they were previously defined to be part of a language.  The list is space-separated.  ex. “Ignore Extensions: cvs txt

Language: [name]
-Alter Language: [name]

Creates a new language or alters an existing one.  Names can use any characters.  Note the special behavior for languages named Shebang Script and Text File.

If you’re altering an existing language and a property has an [Add/Replace] form, you have to specify whether you’re adding to or replacing the list if that property has already been defined.

General Language Properties
Extensions: [extension] [extension] ...
-[Add/Replace] Extensions: [extension] [extension] ...

Defines file extensions for the language’s source files.  The list is space-separated.  ex. “Extensions: c cpp”.  You can use extensions that were previously used by another language to redefine them.  You can use * to specify all undefined extensions.

Shebang Strings: [string] [string] ...
-[Add/Replace] Shebang Strings: [string] [string] ...

Defines a list of strings that can appear in the shebang (#!) line to designate that it’s part of this language.  They can appear anywhere in the line, so php will work for “#!/user/bin/php4”.  You can use strings that were previously used by another language to redefine them.

Ignore Prefixes in Index: [prefix] [prefix] ...
-Ignore [type] Prefixes in Index: [prefix] [prefix] ...
-
-[Add/Replace] Ignored Prefixes in Index: [prefix] [prefix] ...
-[Add/Replace] Ignored [type] Prefixes in Index: [prefix] [prefix] ...

Specifies prefixes that should be ignored when sorting symbols for an index.  Can be specified in general or for a specific topic type.  The prefixes will still appear, the symbols will just be sorted as if they’re not there.  For example, specifying ADO_ for functions will mean that ADO_DoSomething will appear under D instead of A.

Basic Language Support Properties

These attributes are only available for languages with basic language support.

Line Comments: [symbol] [symbol] ...

Defines a space-separated list of symbols that are used for line comments, if any.  ex. “Line Comment: //”.

Block Comments: [opening symbol] [closing symbol] [o.s.] [c.s.] ...

Defines a space-separated list of symbol pairs that are used for block comments, if any.  ex. “Block Comment: /* */”.

Enum Values: [global|under type|under parent]

Defines the behavior of enum values.  The default is global.

GlobalEnum values are always global and will be referenced as “Value”.
Under TypeEnum values appear under the type and will be referenced as “Package.Enum.Value”.
Under ParentEnum values appear under the parent and will be referenced as “Package.Value”
[type] Prototype Enders: [symbol] [symbol] ...

When defined, Natural Docs will attempt to collect prototypes from the code following the specified topic type.  It grabs code until the first ender symbol or the next Natural Docs comment, and if it contains the topic name, it serves as its prototype.  Use \n to specify a line break.  ex. “Function Prototype Enders: { ;”, “Variable Prototype Enders: = ;”.

Line Extender: [symbol]

Defines the symbol that allows a prototype to span multiple lines if normally a line break would end it.

Perl Package: [perl package]

Specifies the Perl package used to fine-tune the language behavior in ways too complex to do in this file.

Full Language Support Properties

These attributes are only available for languages with full language support.

Full Language Support: [perl package]

Specifies the Perl package that has the parsing routines necessary for full language support.

Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/customizingtopics.html b/docs/tool/Help/customizingtopics.html deleted file mode 100644 index 49f4c50b8..000000000 --- a/docs/tool/Help/customizingtopics.html +++ /dev/null @@ -1,74 +0,0 @@ - - -Customizing Natural Docs Topics - - - -
Natural Docs
Customizing Topics
Topics.txt

Natural Docs has two files called Topics.txt: one in its Config directory, and one in your project directory.  These control the topic behavior and keywords Natural Docs uses.

You should edit the one in your project directory whenever possible.  It keeps your changes separate and easier to manage, plus you don’t have to reapply them whenever you upgrade.  Editing the one in Natural Docs’ Config directory would be better only if you’re using Natural Docs with a lot of projects and would like the changes to apply everywhere.

Topic Types vs. Keywords

It’s important to understand the difference between topic types and keywords.  Topic types have their own indexes and behavior settings.  You’ll reference them by name when dealing with indexes in the menu file or prototype detection in the language file, but not when documenting your code unless you make their names keywords as well.

You use keywords when documenting your code.  There can be many keywords per topic type, and they are completely interchangable.

Suppose you document a class with the Class keyword and a struct with Struct.  They are both keywords for the Class topic type by default, so they will appear in the same index.  If you wanted structs to have their own index, you would add a topic type for structs and change the Struct keyword to point to it.

Adding Topic Types

If you want to be able to document something in Natural Docs doesn’t handle by default, you want to create your own topic type for it.  Let’s say you’re working on a video game and you want to document all the sound effects because you want to keep track of what each one is for and have an index of them.  You’d add this to your topics file:

Topic Type: Sound Effect
-   Plural: Sound Effects
-   Keywords:
-      sound
-      sound effect
-

Sound effects can now be documented with the sound or sound effect keywords, and they’ll get their own index.  The Plural line just specifies the plural name of the topic type.  It isn’t required, but Natural Docs will use it in some places where the plural would sound more natural, like when grouping topics or naming indexes on the menu.

Here are a couple of other things you may want to add:

Topic Type: Sound Effect
-   Plural: Sound Effects
-   Scope: Always Global
-   Keywords:
-      sound, sounds
-      sound effect, sound effects
-

You can set the scope behavior of the topic type.  Your options are:

NormalTopics stay within the current scope.
StartTopics start a new scope for all the topics beneath it, like class topics.
EndTopics reset the scope back to global for all the topics beneath it.
Always GlobalTopics are defined as global, but do not change the scope for any other topics.

Here we set it to Always Global so that if we document one as part of a class, it will still be global yet will not break the class’ scope.  In other words, we can always link to it with just its name instead of needing something like <Class.Sound>.

The other thing we did was add plural keywords, which you do by using a comma after an existing keyword.  These keywords are used for list topics so we don’t have to document each one individually with the full syntax.

There are more options, these are just the most important ones.  See the full syntax reference for the rest.

Prototypes

If you’d like to collect prototypes for your new topic type, you have to do that by editing Languages.txt.

Changing Keywords
Adding and Changing

If you’re defining your own topic type or editing the main topics file, you simply add to the keywords list:

Topic Type: Sound Effect
-   Keywords:
-      sound, sounds
-      sound effect, sound effects
-

It doesn’t matter if the keyword was previously defined for a different topic type.  Just define it again and the definition will change.

If you want to add keywords to one of the main topic types from the project file, use Alter Topic Type instead:

Alter Topic Type: General
-   Keywords:
-      note
-      notes
-

Natural Docs will keep a list of the main file’s topic types in your project file so that you can do this easily.

Ignoring

Sometimes a keyword just gets in the way.  It’s too common in your comments and Natural Docs keeps accidentally picking them up as topics when that isn’t what you wanted.  You can get rid of keywords completely by either deleting them from the main file or putting this in your project file:

Ignore Keywords:
-   about
-   title
-

If you only have a few, you can use this syntax as well:

Ignore Keywords: note, notes, title
-
Altering Behavior

You can change the behavior of any topic type defined in the main file via your project file.  Just use Alter Topic Type and redefine any property.

Alter Topic Type: Constant
-   Scope: Always Global
-

Natural Docs will keep a list of the main file’s topic types in your project file so you can do this easily.  See the syntax reference below for a full list of your options.

Syntax Reference
Ignore Keywords: [keyword], [keyword] ...
-   [keyword]
-   [keyword], [keyword]
-   ...
-

Ignores the keywords so that they’re not recognized as Natural Docs topics anymore.  Can be specified as a list on the same line and/or following like a normal Keywords section.

Topic Type: [name]
-Alter Topic Type: [name]
-

Creates a new topic type or alters an existing one.  The name can only contain letters, numbers, spaces, and these characters: . - ‘ /.  It isn’t case sensitive, although the original case is remembered for presentation.

There are a number of default types that must be defined in the main file, but they will be listed there since it may change between versions.  The default types can have their keywords or behaviors changed, though, either by editing the default file or by overriding them in the user file.

Properties
Plural: [name]
-

Specifies the plural name of the topic type.  Defaults to the singular name.  Has the same restrictions as the topic type name.

Index: [yes|no]
-

Whether the topic type gets an index.  Defaults to yes.

Scope: [normal|start|end|always global]
-

How the topic affects scope.  Defaults to normal.

NormalTopics stay within the current scope.
StartTopics start a new scope for all the topics beneath it, like class topics.
EndTopics reset the scope back to global for all the topics beneath it.
Always GlobalTopics are defined as global, but do not change the scope for any other topics.
Class Hierarchy: [yes|no]
-

Whether the topic is part of the class hierarchy.  Defaults to no.

Page Title if First: [yes|no]
-

Whether the title of this topic becomes the page title if it is the first topic in a file.  Defaults to no.

Break Lists: [yes|no]
-

Whether list topics should be broken into individual topics in the output.  Defaults to no.

Can Group With: [topic type], [topic type], ...
-

Lists the topic types that can be grouped with this one in the output.  If two or more topic types often appear together, like Functions and Properties, this will allow them to be grouped together under one heading if it would cause too many groups otherwise.

Keywords:
-   [keyword]
-   [keyword], [plural keyword]
-   ...
-

A list of the topic type’s keywords.  Each line after the heading is the keyword and optionally its plural form.  This continues until the next line in “keyword: value” format.

  • Keywords can only have letters, numbers, and spaces.  No punctuation or symbols are allowed.
  • Keywords are not case sensitive.
  • Subsequent keyword sections add to the list.  They don’t replace it.
  • Keywords can be redefined by appearing in later keyword sections.
Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/documenting.html b/docs/tool/Help/documenting.html deleted file mode 100644 index 4d1343ba3..000000000 --- a/docs/tool/Help/documenting.html +++ /dev/null @@ -1,58 +0,0 @@ - - -Documenting Your Code - Natural Docs - - - -
Natural Docs
Using
Documenting
Your Code
KeywordsRunningTroubleshooting
Documenting Your Code

Here’s a quick example of how to document your code for Natural Docs.  If you’re a new user, we have a walkthrough to get you started.  Otherwise, visit the reference for the full details.

/*
-   Function: Multiply
-
-   Multiplies two integers.
-
-   Parameters:
-
-      x - The first integer.
-      y - The second integer.
-
-   Returns:
-
-      The two integers multiplied together.
-
-   See Also:
-
-      <Divide>
-*/
-int Multiply (int x, int y)
-   {  return x * y;  };
Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/documenting/reference.html b/docs/tool/Help/documenting/reference.html deleted file mode 100644 index 57dc97f48..000000000 --- a/docs/tool/Help/documenting/reference.html +++ /dev/null @@ -1,146 +0,0 @@ - - -Documenting Your Code: Reference - Natural Docs - - - -
Natural Docs
Documenting Your Code
int Add (int x,
int y)
Adds two integers.
int Subtract (int x,
int y)
Subtracts two integers.
int Multiply (int x,
int y)
Multiplies two integers.
int Divide (int x,
int y)
Divides two integers.
bool IsEqual (int x,
int y)
Returns whether two integers are equal.
Comments

There is no special comment style for Natural Docs.  You just embed Natural Docs topics into regular comments, and it’s pretty tolerant as far as style goes.  You can use block comments or string together line comments.  The only requirement is that the comments are not on the same line as code.

/* Function: Multiply
-   Multiplies two integers and returns the result. */
-
-// Function: Multiply
-// Multiplies two integers and returns the result.
-

Note that when stringing line comments together, blank lines that you want to include in the documentation must start with the comment symbol as well.  If a line is completely blank, it’s considered the end of the comment and thus the end of the Natural Docs topic.

Boxes and Horizontal Lines

Natural Docs can also handle comment boxes and horizontal lines.  It doesn’t matter what symbols they use.  The boxes don’t need to be closed on the right side, and they can have different symbols for the edges and corners.

/*
- * Function: Multiply
- * Multiplies two integers and returns the result.
- */
-
-/* +-------------------------------------------------+
-   | Function: Multiply                              |
-   | Multiplies two integers and returns the result. |
-   +-------------------------------------------------+ */
-
-//////////////////////////////////////////////////////////////
-//
-//  Function: Multiply
-//  ------------------
-//
-//  Multiplies two integers together and returns the result.
-//
-//////////////////////////////////////////////////////////////
-
Javadoc Style

If you have full language support, you can also use Javadoc-style comments to write Natural Docs documentation.  To do this you repeat the last symbol on the first line of the comment once.  The comment must appear directly above what it’s documenting, and you can omit the topic line if you want (the “Function: Multiply” part.)

/**
- * Multiplies two integers and returns the result.
- */
-
-///
-// Multiplies two integers together and returns the result.
-

If you omit the topic line and include any Javadoc tags in the comment, like @param, the entire comment will be treated as Javadoc and can only use Javadoc formatting.  Otherwise it’s treated as a Natural Docs comment and you can use all the formatting options described on this page.  You can have both styles in the same source file, but not in the same comment.

Perl POD

Perl users can also use POD to do block comments.

=begin nd
-
-Function: Multiply
-Multiplies two integers and returns the result.
-
-=cut
-

You can also use NaturalDocs or Natural Docs in place of ND.  None of them are case sensitive.  If for some reason you want to go back to POD documentation instead of using =cut, you can write =end nd.

There’s a second form of just =nd which is offered as a convenience.  However, it is not valid POD.  Perl will skip over it and execute fine, but POD parsers will give errors and possibly include the unformatted text in the output.  Use the longer, valid form unless you know for certain that no one will ever try to run POD on your code.

=nd
-
-Function: Multiply
-Multiplies two integers and returns the result.
-
-=cut
-
Text Files

Documentation can also be included in text files.  Any file with a .txt extension appearing in the source tree and starting with a topic line will included in the documentation.  It will be treated the same as a source file, meaning it will appear in the menu, its topics will be in the indexes, and its topics can be linked to from anywhere in the documentation.  The only difference is you don’t need comment symbols.

Remember that the topic line is required to be the first line of content.  If the first non-blank line is not in the “Function: Multiply” format the file will be ignored.  An easy way to do this is to use the Title keyword, although all of the other ones will work as well.

Title: License
-
-This project is licensed under the GPL.
-

This method is convenient for documenting file formats, configuration settings, the general program architecture, or anything else that isn’t directly tied to a source file.

Keywords, Topics, and Scope

A topic in Natural Docs starts with a topic line in the format “keyword: name”.  You can have multiple topics per comment as long as you separate them with a blank line.  The keywords aren’t case sensitive.

The list of keywords is pretty predictable: Function, Class, Variable, etc.  Just use what you’re documenting.  There are many synonyms as well, so you can use keywords like Func, Procedure, Proc, Method and Constructor.  Look at the full list of keywords to see everything that’s available.

The list of keywords is separated into topic types.  Each type gets its own index, and which specific keyword you use doesn’t matter.  Some also have scoping rules or other behavior as noted.

Scope

Like the code it’s documenting, Natural Docs topics have scope.  This mostly has to do with linking: if you’re in a class you can link to its members by their name alone, but if you’re not, you have to use a notation like class.member or class::member.

If you have full language support and are documenting something that appears in the code, the scope will be handled automatically.  If you’re using text files, have basic language support, or are including a topic that doesn’t correspond to something in the code, scoping follows these rules:

List Topics

If you looked at the list, you saw that most of the keywords have plural forms.  That’s for list topics, which let you document many small things without using the full syntax.  Anything that appears in definition lists within that topic will be treated as if it had its own topic.  It will appear in the indexes and be linkable, just like normal topics.

Function list topics will automatically break apart in the output as well, so it will look the same as if you documented each one individually.

Linking

Linking is the one place where Natural Docs has some negative effect on the readability of the comments.  The alternative would be to automatically guess where links should be, but systems that do that can sometimes pepper your sentences with unintentional links to functions called “is” or “on”.  However, the Natural Docs syntax is still as minimal as possible.  Simply surround any topic you want to link to with angle brackets.  Natural Docs will keep track off all the topics and where they are defined, so you don’t need to use HTML-like syntax or remember what file anything is in.  Also, if the link can’t be resolved to anything, Natural Docs leaves the angle brackets in the output so if something wasn’t intended to be a link (such as #include <somefile.h>) it won’t be mangled.

Let's link to function <Multiply>.
-

Let’s link to function Multiply.

Links and topic names are case sensitive, regardless of whether the language is or not.

When linking to functions, it doesn’t matter if you include empty parenthesis or not.  Both <Function> and <Function()> will work.  However, if you documented the function with parameters as part of the name, you will need to include those parameters whenever linking to it.  It is recommended that you only include parameters in the topic name if you need to distinguish between two functions with the same name.

If the topic has a summary sentence, hovering over the link will give it to you as a tooltip.  If the topic has a prototype, that will be included as well.  You can try it above.

Scope

If a topic is considered part of a class, they can be linked to using any of the three most common class/member notations:  class.member, class::member, and class->member.  Natural Docs will not be confused by <class->member>.  Like in the language itself, if the topic you’re writing is in that class’ scope you can link to it simply as <member>.

If you have multi-level classes and packages, links can be relative as well.  So if you’re in Project::UI::Window::Base and you want to link to Project::UI::Button::Base, just using <Button::Base> will work.

Plurals and Possessives

To make the documentation easier to write and easier to read in the source file, you can include plurals and possessives inside the angle brackets.  In other words, you don’t have to use awkward syntax like <Object>s, although that’s supported as well.  You can simply write <Objects> and it will link to the symbol Object just fine.  It can handle any plural and/or possessive form you can throw at it.  I’m not kidding: Foxes, Fox’s, Foxes’, Children, Mice, Alumni, Indices, Amoebae, Teeth, just try to trip it up.

URLs and E-Mail

You can also link to URLs and e-mail addresses.  It will detect them automatically, but you can also put them in angle brackets if you like.

Visit <http://www.website.com> or send messages to
-email@address.com.
-

E-mail addresses are protected in a way that should avoid spam crawlers.  Although the link above looks and acts like a regular link (try it) the HTML code actually looks like this:

<a href="#"
- onClick="location.href='mai' + 'lto:' + 'em' + 'ail' + '@'
-          + 'addre' + 'ss.com'; return false;">
-    em<span style="display: none">.nosp@m.</span>ail
-    <span>@</span>
-    addre<span style="display: none">.nosp@m.</span>ss.com
-</a>
-
Formatting and Layout

You can apply additional formatting and layout to your Natural Docs content, all in ways that will appear very natural in the source code.

Paragraphs

You can break paragraphs by leaving blank lines between them.  So we have this in our content:

The first paragraph blah blah blah blah blah blah blah blah
-blah blah blah blah blah blah blah blah blah blah blah blah
-blah blah blah blah.
-
-The second paragraph blah blah blah blah blah blah blah
-blah blah blah blah blah blah blah blah blah blah blah blah
-blah blah blah blah.
-

and we get this in our output:

The first paragraph blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah.

The second paragraph blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah.

Bold and Underline

You can apply bold to a stretch of text by surrounding it with asterisks.  You can apply underlining by surrounding it with underscores instead.  With underlining, it doesn’t matter if you use an underscore for every space between words or not; they’ll be converted to spaces if you do.

Some *bold text* and some _underlined text_
-and yet _more_underlined_text_.
-

Some bold text and some underlined text and yet more underlined text.

Headings

You can add headings to your output just by ending a line with a colon and having a blank line above it.

Some text before the heading.
-
-Heading:
-Some text under the heading.
-

Some text before the heading.

Heading

Some text under the heading.

You must have a blank line above the heading or it will not work.  You can skip the blank after it but not before.

Bullet Lists

You can add bullet lists by starting a line with a dash, an asterisk, an o, or a plus.  Bullets can have blank lines between them if you want, and subsequent lines don’t have to be indented.  You end a list by skipping a line and doing something else.

- Bullet one.
-- Bullet two.
-  Bullet two continued.
-- Bullet three.
-
-Some text after the bullet list.
-
-o Spaced bullet one.
-
-o Spaced bullet two.
-Spaced bullet two continued.
-
-o Spaced bullet three.
-
-Some text after the spaced bullet list.
-
  • Bullet one.
  • Bullet two.  Bullet two continued.
  • Bullet three.

Some text after the bullet list.

  • Spaced bullet one.
  • Spaced bullet two.  Spaced bullet two continued.
  • Spaced bullet three.

Some text after the spaced bullet list.

Definition Lists

You can add a definition list by using the format below, specifically “text space dash space text”.  Like bullet lists, you can have blank lines between them if you want, subsequent lines don’t have to be indented, and you end the list by skipping a line and doing something else.

First  - This is the first item.
-Second - This is the second item.
-         This is more of the second item.
-Third  - This is the third item.
-This is more of the third item.
-
-Some text after the definition list.
-
FirstThis is the first item.
SecondThis is the second item.  This is more of the second item.
ThirdThis is the third item.  This is more of the third item.

Some text after the definition list.

Remember that with definition lists, if you’re using the plural form of the keywords each entry can be linked to as if it had its own topic.

Code and Text Diagrams

You can add example code or text diagrams by starting each line with >, |, or :.  If you have a vertical line or text box with the comment, you must separate these symbols from it with a space.

: a = b + c;
-
->   +-----+     +-----+
->   |  A  | --> |  B  |
->   +-----+     +-----+
->                  |
->               +-----+
->               |  C  |
->               +-----+
-
a = b + c;
+-----+     +-----+
| A | --> | B |
+-----+ +-----+
|
+-----+
| C |
+-----+

For long stretches, this may be too tedious.  You can start a code section by placing (start code) or just (code) alone on a line.  You end it with either (end code) or just (end).  You can’t put any other content on these lines.

(start code)
-
-if (x == 0) {
-   DoSomething();
-}
-
-return x;
-
-(end)
-
if (x == 0) {
DoSomething();
}

return x;

You can also use example, diagram, or table instead of code.  Just use whatever’s appropriate.  Always flexible, it will accept begin for start and it will accept finish or done for end so you don’t have to remember the exact word.

Images

You can include images in your documentation by writing “(see filename)”.  If you put it alone on a line it will be embedded in place.

This is the first paragraph.
-
-(see logo.gif)
-
-This is the second paragraph.
-

This is the first paragraph.

This is the second paragraph.

If it’s not alone on a line the image will appear after the end of the paragraph, the text will become a link to it, and the file name will be used as a caption.

This is the first paragraph (see logo.gif)  This is
-more of the first paragraph.
-

This is the first paragraph (see logo)  This is more of the first paragraph.

logo

The image file names are relative to the source file the comment appears in or any directories specified with the -img command line option.  You can use relative paths like (see images/logo.gif) and (see ../images/logo.gif), but you cannot use absolute paths, URLs, or specify a file that’s not in a folder included by -i or -img.

Natural Docs supports gif, jpg, jpeg, png, and bmp files.

Page Titles

Natural Docs automatically determines the page title as follows:

  • If there’s only one topic in the file, that topic’s title becomes the page title.
  • Otherwise, if the first topic in the file is a class, section, or file, that topic’s title becomes the page title.
  • Otherwise, the file name becomes the page title.

This should be enough for most people.  However, if you don’t like the page title Natural Docs has chosen for you, add a “Title: [name]” comment to the top of the file to override it.  Title is a synonym of Section, so that will satisfy the second rule and make it the page title.

Summaries

Summaries are automatically generated for every file, class, and section.  You don’t have to do anything special to get them.

There are two things you may want to keep in mind when documenting your code so that the summaries are nicer.  The first is that they use the first sentence in the topic as the description, so long as it’s plain text and not something like a bullet list.  It will also appear in the tooltip whenever that topic is linked to.

The second is that you may want to manually add group topics to divide long lists and make the summaries easier to navigate.  Natural Docs will automatically group them by type if you do not, but sometimes you want to be more specific.  You don’t need to provide a description, just adding a “Group: [name]” comment is sufficient.  Note that once you manually add a group automatic grouping is completely turned off for that class.

Here’s an example summary.  Note that as before, when you hover over a link, you’ll get the prototype and summary line as a tooltip.

Summary
A example class that does arithmetic with functions for people scared of operators.
Adds two integers.
Subtracts two integers.
Multiplies two integers.
Divides two integers.
Returns whether two integers are equal.
Javadoc Compatibility

If you have full language support Natural Docs will also extract documentation from actual Javadoc comments, not just Natural Docs comments written with the Javadoc comment symbols.  This provides you with a good method of migrating to Natural Docs as you don’t have to convert all of your existing documentation.

/**
- * Multiplies two integers.
- *
- * @param x The first integer.
- * @param y The second integer.
- * @return The two integers multiplied together.
- * @see Divide
- */
-

Multiply

int Multiply (int x,
int y)

Multiplies two integers.

Parameters

xThe first integer.
yThe second integer.

Returns

The two integers multiplied together.

See Also

Divide

While most Javadoc tags and simple HTML formatting are supported, Natural Docs is not a full Javadoc parser and may not support some advanced tags and HTML.  See this page for a list of what’s supported and what isn’t.

A source file can contain both Natural Docs and Javadoc comments.  However, you cannot mix the two within a single comment.  For example, you can’t use asterisks for bold in a @param line.  If a comment is written with the Javadoc comment symbols (repeat the last symbol of the first line once) doesn’t have a topic line (like “Function: Multiply”) and uses Javadoc tags (like @param) the comment is treated as Javadoc.  If any of those conditions aren’t true it’s treated as a Natural Docs comment.

Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/documenting/walkthrough.html b/docs/tool/Help/documenting/walkthrough.html deleted file mode 100644 index 130fcc7bd..000000000 --- a/docs/tool/Help/documenting/walkthrough.html +++ /dev/null @@ -1,180 +0,0 @@ - - -Documenting Your Code - Walkthrough - Natural Docs - - - -
Natural Docs
Documenting Your Code
Our First Function

So you downloaded Natural Docs, you figured out the command line, and now it’s time to start documenting your code.  Natural Docs tries to make this very straightforward and painless, so let’s just dive right in:

/*
-   Function: Multiply
-   Multiplies two integers and returns the result.
-*/
-int Multiply (int x, int y)
-   {  return x * y;  };
-

That’s all you need.  Run Natural Docs and here’s what appears in your output:

Multiply

int Multiply (int x,
int y)

Multiplies two integers and returns the result.

Okay, so that’s all you need, but probably not all you want.  After all, you’ve got some real functions to document, not little one-liners.  Here’s something more elaborate:

/*
-   Function: Multiply
-
-   Multiplies two integers.
-
-   Parameters:
-
-      x - The first integer.
-      y - The second integer.
-
-   Returns:
-
-      The two integers multiplied together.
-
-   See Also:
-
-      <Divide>
-*/
-int Multiply (int x, int y)
-   {  return x * y;  };
-

Multiply

int Multiply (int x,
int y)

Multiplies two integers.

Parameters

xThe first integer.
yThe second integer.

Returns

The two integers multiplied together.

See Also

Divide

int Add (int x,
int y)
Adds two integers.
int Subtract (int x,
int y)
Subtracts two integers.
int Multiply (int x,
int y)
Multiplies two integers.
int Divide (int x,
int y)
Divides two integers.
bool IsEqual (int x,
int y)
Returns whether two integers are equal.

Still not too scary, huh?  Notice the comments are just as readable as the output.  No tags littered about, and the structure is very natural.  You probably get it just by looking at it, but let’s go through the details anyway.

Function: Multiply
-

Every one of these comments you write (called topics) are going to start with a topic line in the format “keyword: title”.  There are a lot of keywords, but they’re exactly what you’d expect: Function, Class, Variable, etc.  There are also a lot of synonyms so instead of Function you could use Func, Procedure, Proc, Method, Constructor, etc.  It’s designed so you can just use whatever it is you’re describing without memorizing anything.  You can glance over the keyword list but you shouldn’t have to consult it very often.

The other part of the topic line is the title.  It should match whatever it is you’re documenting, in this case the function name Multiply.  Natural Docs is case sensitive even if your programming language isn’t, so make sure you match it closely or you might not get the prototype in your output, which is the little gray box.  You don’t need to include the parameters in the title.  In fact, it’s better if you don’t.

Parameters:
-
-Returns:
-
-See Also:
-

You can also define headings by skipping a line and ending the text with a colon.  If you’re used to other documentation systems you may think there’s only a handful of headings to choose from, but any text formatted this way will become one.  If you want a heading called Dependencies you can go right ahead and add it.

x - The first integer.
-y - The second integer.
-

This is what’s called a definition list.  You can use more than one line to finish the definition, as it won’t stop until you skip a line.

x - The first integer.
-y - The second integer with a long description.
-    This is still part of the description.
-
-This is a new paragraph because we skipped a line.
-

Indentation doesn’t matter either, so even if the second description line wasn’t indented to match the first, it would still be considered part of it.

<Divide>
-

This is how we link in Natural Docs, with angle brackets.  There will be a lot more to say about this later, but for now I’ll just show you something cool.  Hover over it in the output below:

You get that everywhere in your generated documentation.

Classes and Scope

So that’s good for our one function of questionable usefulness, but what if we have a whole class of questionable usefulness?  We can document the class and it’s members the same way we documented the individual function, with a Natural Docs comment right above each element.  We’ll go back to short descriptions to keep the example manageable.

/*
-   Class: Counter
-   A class that manages an incrementing counter.
-*/
-class Counter
-   {
-   public:
-
-      /*
-         Constructor: Counter
-         Initializes the object.
-      */
-      Counter()
-         {  value = 0;  };
-
-      /*
-         Function: Value
-         Returns the value of the counter.
-      */
-      int Value()
-         {  return value;  };
-
-      /*
-         Function: Increment
-         Adds one to the counter.
-      */
-      void Increment()
-         {  value++;  };
-
-   protected:
-
-      /*
-         Variable: value
-         The counter's value.
-      */
-      int value;
-   };
-

Everything’s the same, we just substituted Class and Variable for the Function keyword when it was appropriate.  We also used Constructor, but we could have just as easily used Function there too.  They’re both keywords for the same thing so it doesn’t matter.

Scope

Like the source code itself, Natural Docs topics have scope.  Value and Increment are seen as part of class Counter, just like they are in the code.  Why is this important?  Linking.  Linking from one topic to another has similar rules to how one function can call another.  Since Value is in the same class as Increment, it’s topic can link to it with just <Increment>.  However, linking to Increment from a different class would require <Counter.Increment> instead.  You can actually use any of the three most common class/member notations: <Counter.Increment>, <Counter::Increment>, and <Counter->Increment>.

If your programming language has full language support, the scope is determined by the code and applied automatically.  However, if you only have basic language support it follows these rules:

  • Any topic that appears under a Class topic (or anything that says Starts Scope) is part of that class.
  • Any topic that appears under a Section topic (or anything that says Ends Scope) is global again.
  • Any File topic (or anything that says Always Global) is global no matter what and doesn’t affect any other topics.

Chances are you would have written the same thing even if you didn’t know this and it would have just worked.  You usually won’t need to think about them at all.  However, it’s still good to be aware of them in case something doesn’t behave the way you expected it to.

You actually know enough to go start documenting now.  I know Mr. ScrollBar says there’s more on this page you can learn, but if you want to skip out early, you can.  Really.  I don’t mind.

More Formatting

Okay then.  On we go.

Paragraphs, Bold, and Underline

The syntax for these three is exactly what you would expect it to be.

*Bold text*
-
-_Underlined text_
-
-Paragraphs are broken by skipping lines.  So the two
-lines above each have their own paragraph, but these
-three lines are all part of the same one.
-

Bold text

Underlined text

Paragraphs are broken by skipping lines.  So the two lines above each have their own paragraph, but these three lines are all part of the same one.

When underlining multiple words, you can use an underscore for each space or only put them at the edges like we did above.  Both ways will work.

Bullet Lists

You can add bullet lists by starting a line with a dash, an asterisk, an o, or a plus.  Like definition lists, bullets can span multiple lines and indentation doesn’t matter.  To end a bullet you have to skip a line before doing something else.

- Bullet one.
-- Bullet two.
-  Bullet two continued.
-- Bullet three.
-
-Some text after the bullet list.
-
  • Bullet one.
  • Bullet two.  Bullet two continued.
  • Bullet three.

Some text after the bullet list.

Code and Text Diagrams

You can add example code or text diagrams by starting each line with >, |, or :.

> a = b + c;
-> b++;
-
a = b + c;
b++;

If you have a long stretch, you can use (start code) and (end) instead.

(start code)
-
-if (x == 0) {
-   DoSomething();
-}
-
-return x;
-
-(end)
-
if (x == 0) {
DoSomething();
}

return x;

You can also use example, diagram, or table instead of code.  Just use whatever’s appropriate.

As I mentioned before, we don’t want you to worry about memorizing minor details, so in that spirit it will also accept begin for start and finish or done for end.  You can also write (end code) instead of just (end).

Images

You can include images in your documentation by writing “(see filename)”.  If you put it alone on a line it will be embedded in place, or if you put it in a paragraph it will appear after it using the file name as a caption.

This is the first paragraph.
-
-(see logo.gif)
-
-This is the second paragraph (see logo.gif)  This
-is more of the second paragraph.
-

This is the first paragraph.

This is the second paragraph (see logo)  This is more of the second paragraph.

logo

The image file names are relative to the source file the comment appears in, so if your file is C:\Project\SourceFile.cpp and your image is C:\Project\Images\Logo.gif, you would write (see Images/Logo.gif).  However, you can also specify image directories in the command line with -img, so if all your source files are in C:\Project\Source and all your images are in C:\Project\Images, you can put “-img C:\Project\Images” on the command line and just use (see logo.gif) again.

More on Linking

Yes, there’s still more to linking.  You can link to URLs and e-mail addresses, but in this case the angle brackets are optional.

Visit <http://www.website.com> or send messages to
-email@address.com.
-

E-mail addresses are protected from spam crawlers.  They look and act like regular links (try it above) but you can see the actual HTML that’s generated for them here.

As for regular links, to help them fit into sentences easily you can actually include plurals and possessives inside the angle brackets.  In other words, you don’t have to use awkward syntax like <Object>s, although that’s supported as well.  You can simply write <Objects> and it will link to the symbol Object just fine.  It can handle any plural and/or possessive form you can throw at it.  I’m not kidding: Foxes, Fox’s, Foxes’, Children, Mice, Alumni, Indices, Amoebae, Teeth, just try to trip it up.

Extra Documentation

Sometimes you want to include documentation that doesn’t correspond directly to a code element.  Maybe you want to include license information or architecture notes.  There are two ways to do this.

Freestanding Topics

Just because most of the things you write will directly correspond to an element of your source code doesn’t mean they have to.  You can pick any of the available keywords and create a freestanding comment with it.  For example:

/*
-   Class: Counter
-   A class that manages an incrementing counter.
-*/
-class Counter
-   {
-   public:
-
-      /*
-         About: License
-         This file is licensed under the GPL.
-      */
-
-      /*
-         Constructor: Counter
-         Initializes the object.
-      */
-      Counter()
-         {  value = 0;  };
-   ...
-

The extra license topic will be added to the output just like the functions.

License

This file is licensed under the GPL.

Remember that because of scope, the License topic will actually be considered part of Counter the way it’s listed above.  You’d link to it from outside Counter with <Counter.License>.  That idea may take some getting used to, but if an extra topic only applies to one class that’s actually the most appropriate way to do it.  In this case it’s a license, so if it applies to the entire project instead you could put the comment above the class to make it global, just like moving a function there would.

Text Files

You can also add additional documentation with text files.  If you put a file with a .txt extension in your source tree and start it with a topic line, it’s contents will be treated the same as if it were in a comment in your source code.  That means you can define multiple topics within it, you can link between them and topics in your source code, and you can use all available formatting options.

Title: License
-
-This file is licensed under the GPL.
-
-I can link to <Counter> and <Counter.Increment>, and
-the documentation in that class can even link back
-with <License>.
-
-
-About: Second Topic
-
-I can create a *second* topic in here too, complete
-with formatting.
-

The thing some people forget though is that you must start it with a topic line, like “Title: License” above.  This is how Natural Docs tells it apart from regular text files.

Abbreviated Syntax

Here’s another useful thing you may want to know about.  Suppose you have a lot of little things to document, like constants.  Writing a separate topic for each one can be very tedious, no matter how much you compress it:

// Constant: COUNTER_NORMAL
-// Causes the counter to increment normally.
-#define COUNTER_NORMAL 0
-
-// Constant: COUNTER_ODD
-// Causes the counter to only increment in odd numbers.
-#define COUNTER_ODD 1
-
-// Constant: COUNTER_EVEN
-// Causes the counter to only increment in even numbers.
-#define COUNTER_EVEN 2
-

One thing you may have noticed in the keyword list is that they almost all have plural forms.  These are used to create what are called list topics.  You define a topic using a plural keyword, and then anything appearing in a definition list within it creates a linkable symbol as if they each had their own topic.  For example:

/*
-   Constants: Counter Modes
-
-   COUNTER_NORMAL - Causes the counter to increment normally.
-   COUNTER_ODD    - Causes the counter to only increment in odd numbers.
-   COUNTER_EVEN   - Causes the counter to only increment in even numbers.
-*/
-#define COUNTER_NORMAL 0
-#define COUNTER_ODD 1
-#define COUNTER_EVEN 2
-

I would now be able to write <COUNTER_ODD> and have it work the same as it would with the first example.

Using the enum or enumeration keyword is special because it automatically behaves in a similar manner.  This allows both the enum and its values to be documented in the same place.

/*
-   Enum: CounterMode
-
-   NORMAL - Causes the counter to increment normally.
-   ODD    - Causes the counter to only increment in odd numbers.
-   EVEN   - Causes the counter to only increment in even numbers.
-*/
-enum CounterMode { NORMAL, ODD, EVEN };
-

That’s it, you’re done with this walkthrough.  You should know enough now to make very good use of Natural Docs.  If you still want to know more, you can look in the reference for some of the smaller details we may have skipped over.  Also, look at the Customizing pages on this web site for even more you can do.

Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/example/Default.css b/docs/tool/Help/example/Default.css deleted file mode 100644 index 7318fdcd9..000000000 --- a/docs/tool/Help/example/Default.css +++ /dev/null @@ -1,528 +0,0 @@ -/* - IMPORTANT: If you're editing this file in the output directory of one of - your projects, your changes will be overwritten the next time you run - Natural Docs. Instead, copy this file to your project directory, make your - changes, and you can use it with -s. Even better would be to make a CSS - file in your project directory with only your changes, which you can then - use with -s [original style] [your changes]. - - On the other hand, if you're editing this file in the Natural Docs styles - directory, the changes will automatically be applied to all your projects - that use this style the next time Natural Docs is run on them. - - This file is part of Natural Docs, which is Copyright © 2003-2004 Greg Valure - Natural Docs is licensed under the GPL -*/ - -body { - font-family: Verdana, Arial, sans-serif; - color: #000000; - margin: 0px; padding: 0px } - -body.UnframedPage { - background-color: #E8E8E8 } - - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -td { - vertical-align: top } - -/* - Comment out this line to use web-style paragraphs (blank line between - paragraphs, no indent) instead of print-style paragraphs (no blank line, - indented.) -*/ -p { - text-indent: 5ex; margin: 0 } - - -/* Can't use something like display: none or it won't break. */ -.HB { - font-size: 1px } - - - - -body.FramedMenuPage, -.MenuSection { - font-size: 9pt; - background-color: #E8E8E8; - padding: 10px 0 0 0 } - -.MenuSection { - width: 27ex } - - - .MTitle { - font-size: 16pt; font-weight: bold; font-variant: small-caps; - text-align: center; - padding: 5px 10px 15px 10px; - border-bottom: 1px dotted #000000; - margin-bottom: 15px } - - .MSubTitle { - font-size: 9pt; font-weight: normal; font-variant: normal; - margin-top: 1ex; margin-bottom: 5px } - - - .MEntry a:link, - .MEntry a:hover, - .MEntry a:visited { color: #606060; margin-right: 0 } - .MEntry a:active { color: #A00000; margin-right: 0 } - - - .MGroup { - font-variant: small-caps; font-weight: bold; - margin: 1em 0 1em 10px } - - /* Konqueror just can't do margins. */ - .KHTML .MGroup { - margin-bottom: 0; padding-bottom: 1em } - - .MGroupContent { - font-variant: normal; font-weight: normal } - - .MGroup a:link, - .MGroup a:hover, - .MGroup a:visited { color: #545454; margin-right: 10px } - .MGroup a:active { color: #A00000; margin-right: 10px } - - - .MFile, - .MText, - .MLink, - .MIndex { - padding: 1px 17px 2px 10px; - margin: .25em 0 .25em 0 } - - .MText { - font-size: 8pt; font-style: italic } - - .MLink { - font-style: italic } - - #MSelected { - color: #000000; background-color: #FFFFFF; - /* Replace padding with border. */ - padding: 0 10px 0 10px; - border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000; - margin-right: 5px } - - /* Close off the left side when its in a group. */ - .MGroup #MSelected { - padding-left: 9px; border-left-width: 1px } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko #MSelected { - -moz-border-radius-topright: 10px; - -moz-border-radius-bottomright: 10px } - .Gecko .MGroup #MSelected { - -moz-border-radius-topleft: 10px; - -moz-border-radius-bottomleft: 10px } - - - - -body.FramedContentPage, -.ContentSection { - background-color: #FFFFFF; - padding-bottom: 15px } - -.ContentSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - - .CTopic { - font-size: 10pt; - /* This should be a margin but Konq 3.1.1 sucks. */ - padding-bottom: 3em } - - - .CTitle { - font-size: 12pt; font-weight: bold; - border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0; - margin: 0 15px .5em 15px } - - .CGroup .CTitle { - font-size: 16pt; font-variant: small-caps; - padding-left: 15px; padding-right: 15px; - border-width: 0 0 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CClass .CTitle, - .CInterface .CTitle, - .CDatabase .CTitle, - .CDatabaseTable .CTitle, - .CSection .CTitle { - font-size: 18pt; - color: #FFFFFF; background-color: #A0A0A0; - padding: 10px 15px 10px 15px; - border-width: 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - #MainTopic .CTitle { - font-size: 20pt; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CBody { - margin-left: 15px; margin-right: 15px } - - - .CToolTip { - position: absolute; visibility: hidden; - left: 0; top: 0; max-width: 50%; - background-color: #FFFFE0; - padding: 5px; - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000; - font-size: 8pt } - - /* Opera 6 gives it a huge height otherwise. */ - .Opera6 .CTooltip, .Opera5 .CTooltip { - max-width: 100% } - - .CHeading { - font-weight: bold; font-size: 10pt; - margin-top: 1.5em; margin-bottom: .5em } - - .CCode { - font: 10pt "Courier New", Courier, monospace; - overflow: auto; - } - - .CBulletList { - /* I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever. - Reapply it here as padding. */ - padding-left: 15px; padding-right: 15px; - margin: .5em 5ex .5em 5ex; - } - - .CDescriptionList { - margin: .5em 5ex 0 5ex } - - /* IE 4 and Konqueror always makes it too long. */ - .IE4 .CDescriptionList, - .KHTML .CDescriptionList { - width: 85% } - - .CDLEntry { - font: 10pt "Courier New", Courier, monospace; color: #808080; - padding-bottom: .25em; - white-space: nowrap } - - .CDLDescription { - font-size: 10pt; /* For browsers that don't inherit correctly, like Opera 5. */ - padding-bottom: .5em; padding-left: 5ex } - - .CTopic img { - text-align: center; - display: block; - margin: 1em auto; - } - .CImageCaption { - font-variant: small-caps; - font-size: 8pt; - color: #808080; - text-align: center; - position: relative; - top: 1em; - } - - .CImageLink { - color: #808080; - font-style: italic; - } - a.CImageLink:link, - a.CImageLink:visited, - a.CImageLink:hover { color: #808080 } - - - -.Prototype { - font: 10pt "Courier New", Courier, monospace; - padding: 5px 3ex; - border-width: 1px; border-style: solid; - margin: 0 5ex 1.5em 5ex; - } - - .Prototype td { - font-size: 10pt; - } - - .PDefaultValue, - .PTypePrefix { - color: #8F8F8F; - } - .PTypePrefix { - text-align: right; - } - - .IE .Prototype table { - padding: 0; - } - - .CFunction .Prototype { - background-color: #F4F4F4; border-color: #D0D0D0 } - .CProperty .Prototype { - background-color: #F4F4FF; border-color: #C0C0E8 } - .CVariable .Prototype { - background-color: #FFFFF0; border-color: #E0E0A0 } - - .CDatabaseIndex .Prototype, - .CConstant .Prototype { - background-color: #D0D0D0; border-color: #000000 } - .CType .Prototype { - background-color: #FFF8F8; border-color: #E8C8C8 } - .CDatabaseTrigger .Prototype, - .CEvent .Prototype, - .CDelegate .Prototype { - background-color: #F0FCF0; border-color: #B8E4B8 } - - .CToolTip .Prototype { - margin: 0 0 .5em 0; - white-space: nowrap; - } - - - - - -.Summary { - margin: 1.5em 5ex 0 5ex } - - .STitle { - font-size: 12pt; font-weight: bold; - margin-bottom: .5em } - - - .SBorder { - background-color: #FFFFF0; - padding: 15px; - border: 1px solid #C0C060 } - - /* Let's observe the evolution of IE's brokeness, shall we? - IE 4 always makes them too long, there's no way around it. */ - .IE4 .SBorder { - width: 85% } - /* IE 5 will make them too long unless you set the width to 100%. Isn't this implied for a div? */ - .IE5 .SBorder { - width: 100% } - /* IE 6 behaves like 5 when it's in a frame, but without frames it will be correct without a width or slightly too long - (but not enough to scroll) with a width. This arbitrary weirdness simply astounds me. */ - body.FramedContentPage .IE6 .SBorder { - width: 100% } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko .SBorder { - -moz-border-radius: 20px } - - - .STable { - font-size: 9pt; width: 100% } - - .SEntrySize { - width: 30% } - .SDescriptionSize { - width: 70% } - - - .SMarked { - background-color: #F8F8D8 } - - - .SEntry .SIndent1 { - margin-left: 1.5ex } - .SEntry .SIndent2 { - margin-left: 3ex } - .SEntry .SIndent3 { - margin-left: 4.5ex } - .SEntry .SIndent4 { - margin-left: 6ex } - .SEntry .SIndent5 { - margin-left: 7.5ex } - - .SDescription { - padding-left: 3ex } - - .SDescription a { color: #800000} - .SDescription a:active { color: #A00000 } - - - .SGroup { - margin-top: .5em; margin-bottom: .25em } - - .SGroup .SEntry { - font-weight: bold; font-variant: small-caps } - - .SGroup .SEntry a { color: #800000 } - .SGroup .SEntry a:active { color: #F00000 } - - - .SMain .SEntry, - .SClass .SEntry, - .SDatabase .SEntry, - .SDatabaseTable .SEntry, - .SSection .SEntry { - font-weight: bold; font-size: 10pt; - margin-bottom: .25em } - - .SClass, - .SDatabase, - .SDatabaseTable, - .SSection { - margin-top: 1em } - - .SMain .SEntry a, - .SClass .SEntry a, - .SDatabase .SEntry a, - .SDatabaseTable .SEntry a, - .SSection .SEntry a { color: #000000 } - - .SMain .SEntry a:active, - .SClass .SEntry a:active, - .SDatabase .SEntry a:active, - .SDatabaseTable .SEntry a:active, - .SSection .SEntry a:active { color: #A00000 } - - - - - -.ClassHierarchy { - margin: 0 15px 1em 15px } - - .CHEntry { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - margin-bottom: 3px; - padding: 2px 2ex; - font-size: 10pt; - background-color: #F4F4F4; color: #606060; - } - - .Gecko .CHEntry { - -moz-border-radius: 4px; - } - - .CHCurrent .CHEntry { - font-weight: bold; - border-color: #000000; - color: #000000; - } - - .CHChildNote .CHEntry { - font-style: italic; - font-size: 8pt; - } - - .CHIndent { - margin-left: 3ex; - } - - .CHEntry a:link, - .CHEntry a:visited, - .CHEntry a:hover { - color: #606060; - } - .CHEntry a:active { - color: #800000; - } - - - - - -body.FramedIndexPage, -.IndexSection { - background-color: #FFFFFF; - font-size: 10pt; - padding: 15px } - -.IndexSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - .IPageTitle { - font-size: 20pt; font-weight: bold; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; border-style: solid; - margin: -15px -15px 0 -15px } - - .INavigationBar { - text-align: center; - background-color: #FFFFF0; - padding: 5px; - border-bottom: solid 1px black; - margin: 0 -15px 15px -15px } - - .INavigationBar a { - font-weight: bold } - - .IHeading { - font-size: 16pt; font-weight: bold; - padding: 2.5em 0 .5em 0; - text-align: center; - width: 3.5ex; - } - #IFirstHeading { - padding-top: 0; - } - - .IEntry { - padding-left: 1ex; } - - .ISubIndex { - padding-left: 3ex; padding-bottom: .5em } - - /* While it may cause some entries to look like links when they aren't, I found it's much easier to read the - index if everything's the same color. */ - .ISymbol { - font-weight: bold; color: #900000 } - - .ISymbolPrefix { - text-align: right; - color: #C47C7C; - background-color: #F8F8F8; - border-right: 3px solid #E0E0E0; - border-left: 1px solid #E0E0E0; - padding: 0 1px 0 2px; - } - #IFirstSymbolPrefix { - border-top: 1px solid #E0E0E0; - } - #ILastSymbolPrefix { - border-bottom: 1px solid #E0E0E0; - } - #IOnlySymbolPrefix { - border-top: 1px solid #E0E0E0; - border-bottom: 1px solid #E0E0E0; - } - - a.IParent, - a.IFile { - display: block; - } - - - - -.Footer { - font-size: 8pt; color: #909090 } - -body.UnframedPage .Footer { - text-align: right; - margin: 2px } - -body.FramedMenuPage .Footer { - text-align: center; - margin: 5em 10px 0 10px} - - .Footer a:link, - .Footer a:hover, - .Footer a:visited { color: #909090 } - .Footer a:active { color: #A00000 } diff --git a/docs/tool/Help/example/NaturalDocs.js b/docs/tool/Help/example/NaturalDocs.js deleted file mode 100644 index 2af84cf54..000000000 --- a/docs/tool/Help/example/NaturalDocs.js +++ /dev/null @@ -1,204 +0,0 @@ - -// -// Browser Styles -// ____________________________________________________________________________ - -var agt=navigator.userAgent.toLowerCase(); -var browserType; -var browserVer; - -if (agt.indexOf("opera") != -1) - { - browserType = "Opera"; - - if (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1) - { browserVer = "Opera5"; } - else if (agt.indexOf("opera 6") != -1 || agt.indexOf("opera/6") != -1) - { browserVer = "Opera6"; } - else if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { browserVer = "Opera7"; } - } - -else if (agt.indexOf("khtml") != -1 || agt.indexOf("konq") != -1 || agt.indexOf("safari") != -1) - { - browserType = "KHTML"; - } - -else if (agt.indexOf("msie") != -1) - { - browserType = "IE"; - - if (agt.indexOf("msie 4") != -1) - { browserVer = "IE4"; } - else if (agt.indexOf("msie 5") != -1) - { browserVer = "IE5"; } - else if (agt.indexOf("msie 6") != -1) - { browserVer = "IE6"; } - } - -else if (agt.indexOf("gecko") != -1) - { - browserType = "Gecko"; - } - -// Opera already taken care of. -else if (agt.indexOf("mozilla") != -1 && agt.indexOf("compatible") == -1 && agt.indexOf("spoofer") == -1 && - agt.indexOf("webtv") == -1 && agt.indexOf("hotjava") == -1) - { - browserType = "Netscape"; - - if (agt.indexOf("mozilla/4") != -1) - { browserVer = "Netscape4"; } - } - - -// -// Menu -// ____________________________________________________________________________ - - -function ToggleMenu(id) - { - if (!window.document.getElementById) - { return; }; - - var display = window.document.getElementById(id).style.display; - - if (display == "none") - { display = "block"; } - else - { display = "none"; } - - window.document.getElementById(id).style.display = display; - } - - -// -// Tooltips -// ____________________________________________________________________________ - - -var tooltipTimer = 0; - -function ShowTip(event, tooltipID, linkID) - { - if (tooltipTimer) - { clearTimeout(tooltipTimer); }; - - var docX = event.clientX + window.pageXOffset; - var docY = event.clientY + window.pageYOffset; - - var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")"; - - // KHTML cant handle showing on a timer right now. - - if (browserType != "KHTML") - { tooltipTimer = setTimeout(showCommand, 1000); } - else - { eval(showCommand); }; - } - -function ReallyShowTip(tooltipID, linkID, docX, docY) - { - tooltipTimer = 0; - - var tooltip; - var link; - - if (document.getElementById) - { - tooltip = document.getElementById(tooltipID); - link = document.getElementById(linkID); - } - else if (document.all) - { - tooltip = eval("document.all['" + tooltipID + "']"); - link = eval("document.all['" + linkID + "']"); - } - - if (tooltip) - { - var left = 0; - var top = 0; - - // Not everything supports offsetTop/Left/Width, and some, like Konqueror and Opera 5, think they do but do it badly. - - if (link && link.offsetWidth != null && browserType != "KHTML" && browserVer != "Opera5") - { - var item = link; - while (item != document.body) - { - left += item.offsetLeft; - item = item.offsetParent; - } - - item = link; - while (item != document.body) - { - top += item.offsetTop; - item = item.offsetParent; - } - top += link.offsetHeight; - } - - // The fallback method is to use the mouse X and Y relative to the document. We use a separate if and test if its a number - // in case some browser snuck through the above if statement but didn't support everything. - - if (!isFinite(top) || top == 0) - { - left = docX; - top = docY; - } - - // Some spacing to get it out from under the cursor. - - top += 10; - - // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the - // page. We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right. - - if (tooltip.offsetWidth != null) - { - var width = tooltip.offsetWidth; - var docWidth = document.body.clientWidth; - - if (left + width > docWidth) - { left = docWidth - width - 1; } - } - - // Opera 5 chokes on the px extension, so it can use the Microsoft one instead. - - if (tooltip.style.left != null && browserVer != "Opera5") - { - tooltip.style.left = left + "px"; - tooltip.style.top = top + "px"; - } - else if (tooltip.style.pixelLeft != null) - { - tooltip.style.pixelLeft = left; - tooltip.style.pixelTop = top; - } - - tooltip.style.visibility = "visible"; - } - } - -function HideTip(tooltipID) - { - if (tooltipTimer) - { - clearTimeout(tooltipTimer); - tooltipTimer = 0; - } - - var tooltip; - - if (document.getElementById) - { tooltip = document.getElementById(tooltipID); } - else if (document.all) - { tooltip = eval("document.all['" + tooltipID + "']"); } - - if (tooltip) - { tooltip.style.visibility = "hidden"; } - } - diff --git a/docs/tool/Help/examples.css b/docs/tool/Help/examples.css deleted file mode 100644 index 97a3fc03d..000000000 --- a/docs/tool/Help/examples.css +++ /dev/null @@ -1,90 +0,0 @@ -@import URL(example/Default.css); - - -.NDContent { - color: #000000; background-color: #FFFFFF; - padding: 15px 0; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #c0c0c0 #808080 #808080 #c0c0c0; - margin: 1em 5ex; - -moz-border-radius: 12px; - } - - .NDContent p, - .NDContent li, - .NDContent td, - .NDMenu td, - .NDSummary td, - .NDIndex td { - font-size: 10pt; - line-height: normal; - } - .NDContent .CTopic { - padding-bottom: 0; - } - .Prototype td { - font: 10pt Courier New, monospace; - } - .NDIndex .IHeading { - font-size: 16pt; - } - - -.NDMenu { - font: 9pt Verdana, Arial, sans-serif; - color: #000000; background-color: #E8E8E8; - width: 27ex; - padding: 10px 0; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #808080 #606060 #606060 #808080; - margin: 1em 0 1em 5ex; - -moz-border-radius: 12px; - } - - -.NDFooter { - font: 8pt Verdana, Arial, sans-serif; - color: #909090; background-color: #E8E8E8; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #808080 #606060 #606060 #808080; - margin: 1em 0 1em 5ex; - -moz-border-radius: 12px; - } -.NDFooter td { - font-size: 8pt; - padding: 0 2ex; - } - - .NDFooter a:link, - .NDFooter a:hover, - .NDFooter a:visited { color: #909090 } - .NDFooter a:active { color: #A00000 } - - -.NDSummary { - padding: 15px; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #c0c0c0 #808080 #808080 #c0c0c0; - margin: 1em 5ex; - -moz-border-radius: 12px; - } - - .NDSummary .Summary { - margin-top: 0; - } - - -.NDIndex { - color: #000000; background-color: #FFFFFF; - padding: 15px; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #c0c0c0 #808080 #808080 #c0c0c0; - margin: 1em 5ex; - -moz-border-radius: 12px; - } - diff --git a/docs/tool/Help/images/header/background.png b/docs/tool/Help/images/header/background.png deleted file mode 100644 index 895fcd6165ff1d11150ba3e5f6701b2a08e11cfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^0zmA|!2~3~-IxHPiacE$Ln;`PX4*biU9k7lwuK5^ zi8JbM)IWB=&!bav)0R>7fZ_Lc3k74o84(A(oV+hF1Wyy;cDP%ja^O*k+&PXLQ~X{u zZhN_}eV@ubxpkZ>`CjGsF1;OXk;vd$@?2>`fuLYDvl diff --git a/docs/tool/Help/images/header/leftside.png b/docs/tool/Help/images/header/leftside.png deleted file mode 100644 index dd15ae6b254f8357d4f0c7f2c04db45254cb0ba0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1087 zcmV-F1i<@=P)=I35LyOIf{ zlnL#UlNt=dYRx-64F&_z?TYIFwmxw@4l`NjVBhcdw9?o*P}dF9=}|W8hhZWC${-qO zAw(2KmCAT+-ErONM;fNaq{t0|@aLcVrBZ~~0La|*$dG*lf*Z2Kgu3s(-Gn|wh8o6N@-nup1*a#95v_Xp0 zaqFD5wW06hm1J3sQ=>`6(NX{4z><=;Y|=)W;_-N#&5k3n2q2Ad3>v3mFc>x(NhxkT z5ww*&dNRmvy*}{$JIJybZt6N)N{NGkHk!=1M7eI$Xfu8akK=q4U%6wVg0%_C+uN z5QTyp3yCNQ{ksrNmw7rU(UdNfGKps~B^7~WLdF#Gq^ZS@n+D(su|!W@am;uDqEHv; z%1d-UKJdnu+uYB33 zTn6G#;xKrnQb|qf`1s!CrI+I4l%^8~O`j}aGs!rj^ZA17zPPyfq)svTGM zdwZw__xp0WCdKQ^%S317=pOkj%bK5`zw55M9)9@Y(WG#tT5YS_8{B=@E6VQ$_?d}S z(&t-vNWuLc_aHP=DwS|-Jnydi@BhHIm!(w7;Zjp@+qPF$RvvojAykiwNE9}p-TrWK z;l=yzf7b$A|0BTU>gwv{p5Ow>WODAja8vLifE)UtWG@ap8ga`QInN$tj8}k^vW#ON#m_T_gYi002ovPDHLk FV1npXAcX(` diff --git a/docs/tool/Help/images/header/logo.png b/docs/tool/Help/images/header/logo.png deleted file mode 100644 index 88ca6745ab07b8a95870df61e45d8ef2a9063aa7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10663 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 N002ovPDHLkV1k{dk0001_NklblNa zD}+En7>2&@d(TAMw%sggn%*pRU8A`rpioNT6KYWWZUNEhbi#xPu8-WMY094BH|mSsgzlx0~Ec)b0~TadRzsJO2Y!P1cUt6-vKS#Sxipp(6C{eL(E Xfg1|#nhx(500000NkvXXu0mjfUqV@s diff --git a/docs/tool/Help/images/header/overbodybg.png b/docs/tool/Help/images/header/overbodybg.png deleted file mode 100644 index 562a47ca2a94b1a30467a5038f4210b2a490459b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~h!2~2-HA~9_%a9 s&N)$TW`%`soc4G|9$tv z4~IbzE*1+!j7I~aE>y<_7*p)dGiRgMULVZo-ZHw4hXUZ0EV|*w4S4gdvFG`*bUXRs zgwncs6F&NQ37I6_5CrOr zFQ%^R>R4DHVjG2fu3ok8+&PSeZy8=};DlO$`uXQMiO|}(19UD)6a<-T*Cw9lQR2Fd34yX@gq7&hjT<3lLZgC+t4s(i5nUP%aW>>6pIu8zbJ=NiGq54RIT<(rBW`J zqpaD42roHd698OUUoSTr4MI~U`>qqS=0qNsb;$KAmD?K|FA}<3E>j@nT4ycd*gbrK zDEe`Gdu@ArTf3$<5;`VpDGmOY+T1;}y&dfB?P)Z%kbJp3kpY_RsD1laGKHht* z-|zQ&y`7z%TCGN7M`(Qq4+JGX8H%F$VDNddI3?l}`=T_+^3ng2{3mG|0Y-y|-v!}? zjg3a9^Eg4Ddg>`kgBnOPr}y`XPnmQ%`2Juzz2tf4%H>>Vw@EfB2SO8fcXzj1t?DS) zXXCOqTCRI92u6Nz-*vBKG9meDwYE1mH>qPpB+&xom$-WSv441f2WoJ)1C`sot^fc4 M07*qoM6N<$f(6|0(*OVf diff --git a/docs/tool/Help/images/logo.gif b/docs/tool/Help/images/logo.gif deleted file mode 100644 index 2fa571ee7e456258331a97d51e5cce15c2df9cf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8221 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 E2cp-dH2?qr diff --git a/docs/tool/Help/images/menu/about.png b/docs/tool/Help/images/menu/about.png deleted file mode 100644 index f0e7f7a9a48b444fa26f7646414fd64c68b1f839..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmV-Z0j&OsP)TaBy(Iz`)SZ(2$UjKtMnsARyr2;1CcHP*6~SfPer10PyheJ}(!O0002q zNklA_T^o9mjjLRO~afRe#h_uGVjs%il5#sRMz z6dmeu$TqONiKE6y1=c;^;QQPf;HJ;%TzN{gD6IqG#nY)Wpg*9ieb8I(tpzjJ>|Ou>002ovPDHLkV1i7kl{NqX diff --git a/docs/tool/Help/images/menu/background.png b/docs/tool/Help/images/menu/background.png deleted file mode 100644 index 2aee532ea4ef5ed9000bd19b0c23bb1a4266f6bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0ze$k!3-p?DQ|xTq$C1-LR{axdGq@9>lZIxynXxj z-Me?MUcGw%{{73BFV`qVTm`Dp@N{tusbEY_NpfIy_GqYe;oQKd%y?{}_5p(wmKp8q h7)~1qB}jWRF?2j&Ji_#`Octnz!PC{xWt~$(69D7;GGzb& diff --git a/docs/tool/Help/images/menu/bottomleft.png b/docs/tool/Help/images/menu/bottomleft.png deleted file mode 100644 index 7dc39a23591aa3aa6630bbccaa16ec237be309c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 175 zcmV;g08sylP) dz9ngN-5;B15ECy%&OiVF002ovPDHLkV1jceS1bSk diff --git a/docs/tool/Help/images/menu/bottomright.png b/docs/tool/Help/images/menu/bottomright.png deleted file mode 100644 index 7fd9d24ef1cd5d45058b4759c466ce771b9ee077..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 180 zcmV;l089UgP)w1CXThC_@s&YuI5(D@kg4GbK48Me2%2h-~1?0Lg)+c$PlT z24=#g!AJ{2soCDDlp62LL|RIG*~b9x(w7><`M>03fGaaiXch7yHbsr$`*i3H(!Kr? z?}(&A6jl86!?Sb+;2E+{C2IR7Wo>}29l;;%JRf_*_A#tj=2?auh=4_sVf&NBF)l;1 z1Ei?}moc#QvG2XeC+1f0C_lN`@eEU8Q00KDa``G!$hd54 zFmzpJkN2@Z`b5@r2y;l95Sq|~q+p6?$vlN^0V@GrjiC-OwYe0PkCs@{d54rGt$-@| tHg5MQVVHD++a(yF@;3|k=!rvb zf3rYW<7NF#i9(Z)CaInGv#YcomR`mt`WsLs2lh}#QapNzSE`gCOAnMTDL?i*z`^5{ z2(lWb?(VEbT2uvO8TXH@3Qa-Dkb1eoR0f~Vse6ETv!uZf<}1^gW0M|pk_uSJ0LFxM zf;JQoatiEKxk7)pyY}vD14J_aE%40%9Za_e@6>x#4z=TDEp{*RZ#&Gjx#F{_vKR3y zi!}{C?lJKRv@sgM)c$f9i(*r|-SS2~cT zO;O^u8GC7ND0M@qK%UUorYfDp0P1M?Qsb$hd28JJw{)II-bRuZq_O;#*MK5v1#luM z13OErfh5K8(=Z)7T2q#kmQ?r9OB{Km3giNKJu^A{12CaI5$6!YkN^Mx07*qoM6N<$ Ef`@_Q+W-In diff --git a/docs/tool/Help/images/menu/using.png b/docs/tool/Help/images/menu/using.png deleted file mode 100644 index 2c3f510d2b5c842cf0a2ad9c0daa3921db784b68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 332 zcmV-S0ki&zP)2&|qL-kdTmofPer10Pyhe>!A$-0002j zNkl9KpD-SRidKT=Q&U&Xgx<9Kx`GWlnXlba0y|ujWWoMu#8Kq`}vtzR|9jVmQo#%T0 zO>2cxbA16B9sTj<<-tr2Zx)VRlu@!d>cq-&muY5L4I_W{%VOuHIBSx&!0O3#C0R+s eyl~7Ub>S!6dK{|#>4MY%0000Natural Docs - - - -
Natural Docs
Version 1.4

This is the Natural Docs help file, a subset of the documentation available at the web site.  Everything you need is on the menu to the left.

Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/javascript/BrowserStyles.js b/docs/tool/Help/javascript/BrowserStyles.js deleted file mode 100644 index 71666418d..000000000 --- a/docs/tool/Help/javascript/BrowserStyles.js +++ /dev/null @@ -1,77 +0,0 @@ - -// -// Browser Styles -// ____________________________________________________________________________ - -var agt=navigator.userAgent.toLowerCase(); -var browserType; -var browserVer; - -if (agt.indexOf("opera") != -1) - { - browserType = "Opera"; - - if (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1) - { browserVer = "Opera5"; } - else if (agt.indexOf("opera 6") != -1 || agt.indexOf("opera/6") != -1) - { browserVer = "Opera6"; } - else if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { browserVer = "Opera7"; } - } - -else if (agt.indexOf("khtml") != -1 || agt.indexOf("konq") != -1 || agt.indexOf("safari") != -1) - { - browserType = "KHTML"; - } - -else if (agt.indexOf("msie") != -1) - { - browserType = "IE"; - - if (agt.indexOf("msie 4") != -1) - { browserVer = "IE4"; } - else if (agt.indexOf("msie 5") != -1) - { browserVer = "IE5"; } - else if (agt.indexOf("msie 6") != -1) - { browserVer = "IE6"; } - else if (agt.indexOf("msie 7") != -1) - { browserVer = "IE7"; } - } - -else if (agt.indexOf("gecko") != -1) - { - browserType = "Gecko"; - } - -// Opera already taken care of. -else if (agt.indexOf("mozilla") != -1 && agt.indexOf("compatible") == -1 && agt.indexOf("spoofer") == -1 && - agt.indexOf("webtv") == -1 && agt.indexOf("hotjava") == -1) - { - browserType = "Netscape"; - - if (agt.indexOf("mozilla/4") != -1) - { browserVer = "Netscape4"; } - } - - -function OpeningBrowserTags() - { - if (browserType) - { - document.write('
'); - - if (browserVer) - { document.write('
'); } - } - }; - -function ClosingBrowserTags() - { - if (browserType) - { - document.write('
'); - - if (browserVer) - { document.write('
'); } - } - }; diff --git a/docs/tool/Help/javascript/PNGHandling.js b/docs/tool/Help/javascript/PNGHandling.js deleted file mode 100644 index c45006ecf..000000000 --- a/docs/tool/Help/javascript/PNGHandling.js +++ /dev/null @@ -1,72 +0,0 @@ -// Parts derived from: -// Opacity Displayer, Version 1.0 -// Copyright Michael Lovitt, 6/2002. -// Distribute freely, but please leave this notice intact. -// http://www.alistapart.com/articles/pngopacity/ - -// Parts derived from: -// Natural Docs -// Copyright (C) 2003-2004 Greg Valure -// http://www.naturaldocs.org/ - - -var pngTransform; -var pngNormal; - -var agt=navigator.userAgent.toLowerCase(); - -if (agt.indexOf("opera") != -1) - { - if ( (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1) && - agt.indexOf("mac") != -1) - { - pngNormal = 1; - } - else if (agt.indexOf("opera 6") != -1 || agt.indexOf("opera/6") != -1 || - agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { - pngNormal = 1; - } - } - -else if (agt.indexOf("msie") != -1) - { - if (agt.indexOf("msie 5.5") != -1 || agt.indexOf("msie 6") != -1) - { - if (agt.indexOf("mac") != -1) - { pngNormal = 1; } - else if (agt.indexOf("win") != -1) - { pngTransform = 1; }; - } - - else if (agt.indexOf("msie 5") != -1) - { - if (agt.indexOf("mac") != -1) - { pngNormal = 1; }; - } - - else if (agt.indexOf("msie 7") != -1) - { pngNormal = 1; } - } - -else if (agt.indexOf("gecko") != -1) - { - pngNormal = 1; - } - - -function PNGGIF(strPath, intWidth, intHeight, strAlt, strID) - { - if (pngTransform) - { - document.write('
'); - } - else if (pngNormal) - { - document.write(''+strAlt+''); - } - else - { - document.write(''+strAlt+''); - } - }; diff --git a/docs/tool/Help/keywords.html b/docs/tool/Help/keywords.html deleted file mode 100644 index 6a932b72d..000000000 --- a/docs/tool/Help/keywords.html +++ /dev/null @@ -1,38 +0,0 @@ - - -Natural Docs Topics and Keywords - - - -
Natural Docs
Topics and Keywords

Keywords are not case sensitive and are interchangable within their topic type.  The plural forms denote list topics where every item in its definition lists are treated like they have their own topic.

General Topics
Generic
topictopics
aboutlist
Section
Ends Scope
section
title
Group
group
File
Always Global
filefiles
programprograms
scriptscripts
documentdocuments
docdocs
headerheaders
Code Topics
Class
Starts Scope
classclasses
structurestructures
structstructs
packagepackages
namespacenamespaces
Interface
Starts Scope
interfaceinterfaces
Type
typetypes
typedeftypedefs
Constant
constantconstants
constconsts
Enumeration
Topic indexed under Types
Members indexed under Constants
enumerationenumerations
enumenums
Function
List topics break apart
functionfunctions
funcfuncs
procedureprocedures
procprocs
routineroutines
subroutinesubroutines
subsubs
methodmethods
callbackcallbacks
constructorconstructors
destructordestructors
operatoroperators
Property
propertyproperties
propprops
Event
eventevents
Delegate
delegatedelegates
Macro
macromacros
definedefines
defdefs
Variable
variablevariables
varvars
integerintegers
intints
uintuints
longlongs
ulongulongs
shortshorts
ushortushorts
bytebytes
ubyteubytes
sbytesbytes
floatfloats
doubledoubles
realreals
decimaldecimals
scalarscalars
arrayarrays
arrayrefarrayrefs
hashhashes
hashrefhashrefs
boolbools
booleanbooleans
flagflags
bitbits
bitfieldbitfields
fieldfields
pointerpointers
ptrptrs
referencereferences
refrefs
objectobjects
objobjs
charactercharacters
wcharacterwcharacters
charchars
wcharwchars
stringstrings
wstringwstrings
strstrs
wstrwstrs
handlehandles
Database Topics
Database
databasedatabases
dbdbs
Database Table
Starts Scope
tabletables
database tabledatabase tables
db tabledb tables
Database View
Starts Scope
viewviews
database viewdatabase views
db viewdb views
Database Cursor
cursorcursors
database cursordatabase cursors
db cursordb cursors
Database Index
indexindexes
indices
database indexdatabase indexes
database indices
db indexdb indexes
db indices
keykeys
database keydatabase keys
db keydb keys
primary keyprimary keys
database primary keydatabase primary keys
db primary keydb primary keys
Database Trigger
triggertriggers
database triggerdatabase triggers
db triggerdb triggers
Miscellaneous Topics
Cookie
Always global
cookiecookies
Build Target
targettargets
build targetbuild targets
Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/languages.html b/docs/tool/Help/languages.html deleted file mode 100644 index 37f4a6646..000000000 --- a/docs/tool/Help/languages.html +++ /dev/null @@ -1,32 +0,0 @@ - - -Natural Docs Language Support - - - -
Natural Docs
About
Language SupportOutput Formats
Language Support
Full Language Support

The following languages have full language support, which means you get:

Full code documentation.  All functions, variables, and classes will appear in the output regardless of whether you wrote anything for them.  This can be turned off with the -do command line option.

Inheritance diagrams.  They will appear in the output wherever appropriate.

Javadoc compatibility.  Natural Docs can read most Javadoc comments and include them in the output.  You can also write Natural Docs documentation without topic lines by using the Javadoc comment symbols.

Auto-scoping.  The class a topic is part of is determined by the source code rather than class and section topics.

  • C# (1.1, some 2.0)
  • Perl
  • ActionScript (2 and 3)
Basic Language Support

The following languages have basic language support, which means you have:

Explicit documentation only.  Only things you write Natural Docs documentation for will appear in the output.

No inheritance diagrams.

Natural Docs comments only.  They also need to include a topic line.

Topic scoping.  The class a topic is part of is determined by the topic scoping rules.

  • C/C++
  • Java
  • PHP
  • Python
  • PL/SQL
  • Visual Basic
  • Pascal/Delphi
  • Ada
  • JavaScript
  • Ruby
  • Tcl
  • ColdFusion
  • Assembly
  • Fortran (free-format only)
  • R
  • Makefiles
  • Plain Text
  • Custom Languages
Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/menu.html b/docs/tool/Help/menu.html deleted file mode 100644 index 91b04453a..000000000 --- a/docs/tool/Help/menu.html +++ /dev/null @@ -1,79 +0,0 @@ - - -Organizing the Menu - Natural Docs - - - -
Natural Docs
Organizing the Menu

Natural Docs creates a file called Menu.txt in your project directory that you can edit to organize the menu.  It normally takes care of this on its own, but you have the option of improving it manually if you want to.

Order and Titles

If you’ve never looked in it before, the menu file will have some comments explaining its syntax and a list like you see below.

File: ClassA  (ClassA.h)
-File: ClassB  (ClassB.h)
-File: Globals  (Globals.h)
-

The list gets turned into a menu that looks like this:

The lines are in the format “File: [title] ([filename])”.  When Natural Docs made the menu, it decided on its own what the title of each file should be and then put them in alphabetical order.  However, suppose we don’t want this.  We want Globals above the classes and we want spaces in the menu titles.  So we edit the file.

File: Globals  (Globals.h)
-File: Class A  (ClassA.h)
-File: Class B  (ClassB.h)
-

Run Natural Docs again and the menu is updated.

However, open the menu file again and you’ll see something interesting.

File: Globals  (Globals.h)
-File: Class A  (no auto-title, ClassA.h)
-File: Class B  (no auto-title, ClassB.h)
-

Natural Docs noticed that you changed a couple of the titles and added a no auto-title attribute to each one.  This tells it to never change them on it’s own in the future, so your changes won’t be lost.  You don’t have to worry about adding this, Natural Docs will always do it automatically.  However, to go back to automatic titles you’d have to manually remove it.

Grouping

This menu is good for our example, but in the real world they get much, much longer.  We can add groups to organize it further.  Natural Docs will create them automatically based on the each file’s directory, but once again you can improve it manually if that’s not good enough.

You can add groups as shown below.

File: Globals  (Globals.h)
-Group: Classes {
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h) }
-

You can also nest them inside each other.

File: Globals  (Globals.h)
-Group: Classes {
-   File: Class A  (no auto-title, ClassA.h)
-   Group: Nested Group {
-      File: Class B  (no auto-title, ClassB.h)  }
-   }
-

We’ll get rid of the nested group because it doesn’t make sense for our example.  Run Natural Docs, open up the menu file again and take a look.

File: Globals  (Globals.h)
-
-Group: Classes  {
-
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-   }  # Group: Classes
-

Natural Docs reformatted it.  When you’re organizing the menu, you don’t have to worry about the indentation or otherwise keeping it neat.  The file is reformatted every time it changes, so you can make quick and dirty edits and Natural Docs will keep it readable.

Besides breaking up long lists, groups also serve another purpose.  Clicking on them will make it expand and collapse.  Go ahead and try it in the examples above.  When the menu gets too long its groups will start being collapsed by default, allowing easier navigation on large projects where it would just be impractical to show everything at once.

Indexes and Search

Natural Docs will automatically determine what indexes your project needs and add them to the menu.  Anything indexed will also be used for the search feature.  The entries will look like this:

Group: Index {
-
-   Index: Everything
-   Class Index: Classes
-   Function Index: Functions
-   }  # Group: Index
-

Like the file entries we saw before, you can rename them by editing the title and reorder them by cutting and pasting.  However, if you decide you don’t want a particular index to be generated, just delete its entry and it will go away.  Just like before, Natural Docs will detect this and add something new:

Don't Index: Functions
-

As with no auto-title, Natural Docs adds this automatically to make sure it doesn’t later undo your changes.

Automatic Changes

Natural Docs tries to manage the menu on its own as much as possible so you don’t have to worry about it.  This is just a peek into some of the things it does so you know what to expect.

You already saw that by default Natural Docs tries to guess what title should be for each file.  If you leave it this way, Natural Docs will always update the menu for you if the file’s content changes significantly enough to change its guess, such as if you rename the first class defined in it.  If you’d like to take advantage of this to define the menu title in each source file instead of in the menu itself, add a “Title: [title]” comment to the top of the file.

When you add and delete source files, Natural Docs will automatically add and remove them from the menu file.  When adding one it will look for the best group to put it in by directory.  If your grouping mirrors the source tree somewhat, this will be a lot more accurate.  Also, if the group it’s putting it in is alphabetized, Natural Docs will put it in the correct place to maintain that alphabetization.  In fact, even if an existing file’s automatic title changes, it will change it’s position to make sure a previously alphabetized group stays that way.

There are exceptions in alphabetization for the indexes.  If a group only contains indexes, it can be the last item on the menu or in its parent group without making it count as unsorted.  Also, within groups that only contain indexes, the general index can be first, also without making the group count as unsorted.

Finally, if Natural Docs adds some files to a group that causes it to become too long, it will attempt to sub-group it based on directory.  However, it will only do this when its adding files on its own, so you don’t have to worry about it constantly messing up your groups.  Since new files aren’t added to a project that often, if you change the menu manually it should stay that way for quite some time.

Extras

There’s more you can do with the menu than just renaming and reorganizing its entries.  Natural Docs has a few extras you can add to it as well.

Title and Subtitle

You can add a title and subtitle to your menu.

Title: My Project
-SubTitle: Something That Does Something
-
-File: Globals  (Globals.h)
-Group: Classes
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-
My Project
Something That Does Something

In addition to adding the title to the menu, the Title tag will also change the HTML page titles from “Class A” to “Class A - My Project”, making bookmarks clearer.

Text and Web Links

You can also add arbitrary text and web links to your menu.

File: Globals  (Globals.h)
-Group: Classes  {
-   Text: I couldn't think of good names for these classes.
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-   }
-Link: Built with Natural Docs  (http://www.naturaldocs.org)
-
Classes

Even though comments use the # character, adding an anchor to a link (such as “http://www.website.com/page.html#anchor”) will still work.

Footers

Finally, you can add a footer to all your pages, such as a copyright notice.  Natural Docs will change any (c)’s it finds into real copyright symbols.

Footer: Copyright (C) 2008 Me
-
Copyright © 2008 Me  ·  Generated by Natural Docs

You can also add a timestamp in any format you want.  The tokens you can use in building it are:

mOne or two digit month.January is “1”
mmAlways two digit month.January is “01”
monShort month word.January is “Jan”
monthLong month word.January is “January”
dOne or two digit day.1 is “1”
ddAlways two digit day.1 is “01”
dayDay with letter extension.1 is “1st”
yyTwo digit year.2008 is “08”
yyyyFour digit year.2008 is “2008”
yearFour digit year.2008 is “2008”

Everything else appears literally, so we can add:

Timestamp: Updated month day, year
-

and get:

Copyright © 2008 Me  ·  Updated January 1st, 2008  ·  Generated by Natural Docs
Errors

If there’s ever an error in the menu file, Natural Docs will tell you when it’s run.  It also adds a comment for each one in the menu file itself so that you can search for them in a text editor.

# There is an error in this file.  Search for ERROR to find it.
-
-File: Globals  (Globals.h)
-Group: Classes  {
-# ERROR: Txet is not a valid keyword.
-   Txet: I couldn't think of good names for these classes.
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-   }
-

Remember that Natural Docs reformats the menu file whenever it’s run, so you only need to correct the error.  Natural Docs will remove the error comments on its own.

Portability and Versioning Systems

If you only use one input directory, all the files in the menu will have relative paths.  However, if you have more Natural Docs will use the absolute path instead.

This is not a problem.  The menu file can still be shared between machines even if they don’t keep the source tree in the exact same location.  As long as you have the same layout within the source tree and point to the same base directories in the command line, Natural Docs will be able to convert the paths automatically for the new machine.

However, if you’re putting the menu file in a versioning system like Subversion or SourceSafe, it might be very desirable to only have relative paths so anybody can check it in and only the real changes show.  In that case, instead of using multiple input directories, see if it’s possible to only have one input directory and use the -xi command line option to exclude the subdirectories you don’t want scanned.

That’s It!

And we’re done.  The syntax to do all of this is included in the menu file itself, so you don’t need to memorize everything.  You shouldn’t need to organize the menu very often, just after a lot of new files have been added and if you don’t like the default.

Note that if you’re using the non-framed HTML output format, changing the menu does require every output file to be updated.  However, Natural Docs has a special process just for this so it won’t take nearly as long as if it were rebuilding them all from scratch.  Still, if you’re working on a large project, it may be worth considering the framed HTML output format.

Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/output.html b/docs/tool/Help/output.html deleted file mode 100644 index 5576c3a7d..000000000 --- a/docs/tool/Help/output.html +++ /dev/null @@ -1,84 +0,0 @@ - - -Output Formats - Natural Docs - - - -
Natural Docs
About
Language SupportOutput Formats
Output Formats

These are the output formats that are currently implemented in Natural Docs.

HTMLHTML output.  Each page is self-contained.  Linking to specific pages is easy, but every file has to be updated whenever the menu changes.
FramedHTMLHTML output based on frames.  The menu is updated quickly, but linking to individual pages is difficult and some people just plain hate frames.
HTML Compatibility

These are the browsers Natural Docs’ HTML output has been tested with.  All browsers will be able to view and navigate it, some of the older ones just may not be able to use advanced features like search correctly.

FireFoxTested with 1.0, 1.5, and 2.0.
Internet ExplorerTested with 6 and 7.
SafariTested with 2 and 3.  Search doesn’t work with unframed HTML in 2.
OperaTested with 7.0, 7.5, 8.0, 8.5, and 9.0.  Search doesn’t work with 7.0, and sometimes tooltips.
KonquerorTested with 3.5.5.  Search doesn’t work.
Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/running.html b/docs/tool/Help/running.html deleted file mode 100644 index 1a4930f29..000000000 --- a/docs/tool/Help/running.html +++ /dev/null @@ -1,40 +0,0 @@ - - -Running Natural Docs - - - -
Natural Docs
Running Natural Docs
 
How and When

Probably the best way to run Natural Docs is as part of the build process.  This way every time you compile your code, your documentation is updated as well and you always have a current reference.  Natural Docs has a differential build process so it will not rebuild the entire set of documentation every time it’s run.

If you’d like to run it manually instead, you should determine the command line you need and save it as a shortcut, batch file, or script since you should be running it often and will rarely need to fiddle with the parameters.

Command Line
NaturalDocs -i [input (source) directory]
-            -o [output format] [output directory]
-            -p [project directory]
-            [options]
Required Parameters:
-i [dir]
--input [dir]
--source [dir]

The input (source) directory.  Natural Docs will build the documentation from the files in this directory and all its subdirectories.  You can specify it multiple times to include multiple directories.  See the list of supported programming languages.

-o [fmt] [dir]
--output [fmt] [dir]

The output format and directory.  This can also be specified multiple times, so you can build the documentation in multiple formats in a single run.  See the list of supported output formats.

-p [dir]
--project [dir]

The project directory.  Natural Docs needs a place to store configuration and data files for each project it’s run on, so this is where it will put them.  No two projects should share the same directory.

Optional Parameters:
-xi [dir]
--exclude-input [dir]
--exclude-source [dir]

Excludes a subdirectory from being scanned.  The output and project directories are automatically excluded.

-img [dir]
--images [dir]

Adds a directory to search for image files when using (see [file]).

-s [style] ([style] ...)
--style [style] ([style] ...)

Selects the CSS style for HTML output.  See the default list of styles.

You can use any CSS file in your project directory or Natural Docs’ Styles directory just by using its name without the .css extension.  If you include more than one, they will all be included in the HTML that order.

-r
--rebuild

Rebuilds everything from scratch.  All source files will be rescanned and all output files will be rebuilt

-ro
--rebuild-output

Rebuilds all output files from scratch.

-t [len]
--tab-length [len]

Sets the number of spaces tabs should be expanded to.  This only needs to be set if you use tabs in example code or text diagrams.  The default is 4.

-do
--documented-only

Tells Natural Docs to only include what you explicitly document in the output, and not to find undocumented classes, functions, and variables.  This option is only relevant if you have full language support.

-oft
--only-file-titles

Tells Natural Docs to only use the file name for its menu and page titles.  It won’t try to determine one from the contents of the file.

-nag
--no-auto-group

Tells Natural Docs to not automatically create group topics if you don’t add them yourself.

-cs [charset]
--charset [charset]
--character-set [charset]

Sets the character set property of the generated HTML, such as UTF-8 or Shift_JIS.  The default leaves it unspecified.

-q
--quiet

Suppresses all non-error output.

-?
-h
--help

Prints the syntax reference.

No Longer Supported:
These parameters were part of previous Natural Docs releases, but are no longer supported.
-ho
--headers-only

This used to check only the headers and not the source files in C and C++.  Edit Languages.txt instead and add the line “Ignore Extensions: c cpp cxx”.

-s Custom
--style Custom

This used to tell Natural Docs not to alter the CSS file in the output directory.  Copy your custom CSS file to your project directory and use it with -s instead.

-ag [level]
--auto-group [level]

This used to set the level of auto-grouping between Full, Basic, and None.  The algorithm was improved so there’s no need for separate levels anymore.  You can use -nag if you want to turn it off completely.

Examples
NaturalDocs -i C:\My Project\Source
-            -o FramedHTML C:\My Project\Docs
-            -p C:\My Project\Natural Docs
-
-NaturalDocs -i /project/src1
-            -i /project/src2
-            -o HTML /project/doc
-            -p /project/nd
-            -s Small -t 3
Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/styles.css b/docs/tool/Help/styles.css deleted file mode 100644 index 838202ec3..000000000 --- a/docs/tool/Help/styles.css +++ /dev/null @@ -1,290 +0,0 @@ - -body { - background: #FFFFFF; - margin: 18px 15px 25px 15px !important; - } - -body, -td, -li { - font: 9pt Verdana, sans-serif; - } -p, -td, -li { - line-height: 150%; - } - -p { - text-indent: 4ex; - margin: 0; - } - -td { - vertical-align: top; - } - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -.Opera wbr:after { - content: "\00200B"; - } - -.NoIndent p - { text-indent: 0; } - -img { - border: none; - } - -.First { - margin-top: 0 !important; - padding-top: 0 !important; - } -.Last { - margin-bottom: 0 !important; - padding-bottom: 0 !important; - } - -.Header { - background-image: URL("images/header/background.png"); - background-color: #7070C0; - } -.SideMenuTop { - background: URL("images/header/overmenubg.png"); - } -.SideMenuBottom { - vertical-align: bottom; - } -.BodyTop { - background: URL("images/header/overbodybg.png"); - text-align: right; - } -.BodyBottom { - vertical-align: bottom; - text-align: right; - font: italic 8pt Georgia, serif; - color: #C0C0C0; - padding-right: 10px; - } - -.Body { - padding: 15px 20px 0 25px; - } - -#SourceForgeLogo { - border: 1px solid #D8D8D8; - margin-top: 2em; - } - - - -pre, code, .Example { - font: 10pt Courier New, Courier, monospace; - color: #606060; - } -a code { - color: #C06060; - } -.Example { - overflow: auto; - } - -.PageTitle { - font: bold italic 21pt Trebuchet MS, sans-serif; letter-spacing: .5ex; text-transform: uppercase; - margin-bottom: .5em } -.IE .PageTitle { - letter-spacing: 1.25ex; - } - - -.Topic { - margin-bottom: 2em } - - -.TopicTitle { - font: 18pt Georgia, serif; - border-width: 0 0 1px 0; border-style: solid; border-color: #C0C0C0; - margin-bottom: .5em - } -#SubscribeTopicTitle { - margin-bottom: 0; - } -.Subscribe { - font-size: 8pt; - margin-bottom: 2em; - color: #909090; - } - -.Subscribe a:link, -.Subscribe a:hover, -.Subscribe a:visited { - color: #909090 } - - -.SubTopic { - font-weight: bold; font-size: 10pt; - padding-top: 1.5em; padding-bottom: .5em; - } - -.MiniTopic { - font-weight: bold; - padding-top: 1em; padding-bottom: 0em; - } - - -.TOC { - text-align: center; - font: 8pt Verdana, sans-serif; - text-transform: uppercase; - background-color: #F8F8F8; - border-width: 1px; border-style: solid; border-color: #C0C0C0; - margin-bottom: 1.5em; - padding: 2px 0; - -moz-border-radius: 14px; - } - - .TOC a { - margin: 0 0.75ex; } - - .TOC a:link, - .TOC a:hover, - .TOC a:visited { - color: #404040 } - - -.Example { - background-color: #FDFDFD; - padding: 15px; - border: 1px solid #C0C0C0; - border-width: 1px 1px 1px 6px; - border-style: dashed dashed dashed solid; - color: #707070; - margin: 15px 5ex; - } - - -.LastUpdated { - font: italic 10pt Georgia, serif; - color: #A0A0A0; - margin: 1em 0; - } - - - -.FAQSummary { - margin-bottom: 3em; - } -.FAQSummaryGroup { - font: bold 12pt Georgia, serif; - margin: 1em 0 .25em 0; - } -.FAQGroup { - font: 18pt Georgia, serif; - border-bottom: 1px solid #C0C0C0; - margin-bottom: .5em; - margin-top: 1.5em; - } -.FAQSummaryEntry:link, -.FAQSummaryEntry:visited, -.FAQSummaryEntry:hover, -.FAQSummaryEntry:active { - } - -.FAQEntry { - margin-bottom: 3em; - } -.FAQEntryTitle { - font: bold 12pt Georgia, serif; - margin-bottom: .5em; - } -.FAQEntry .SubTopic { - font: italic 9pt Verdana, sans-serif; - } - - - -.SideMenu { - width: 175px; /* 195 minus padding */ - text-align: center; - padding-top: 15px; - background-color: #F0F0F0; - } -.SideMenuBottom { - background-color: #F0F0F0; - } -.SideMenuBottomRight { - text-align: right; - } - -.SideMenuSection { - margin-bottom: 3em; - } - -.SideMenuTitle { - padding-bottom: 3px; - border-bottom: 1px solid #D0D0D0; - } - -.SideMenuBody { - padding-top: 1em; - background: URL("images/menu/background.png") repeat-x; - } - -.SideMenuEntry { - font: 8pt Verdana, sans-serif; - margin: 0 10px 1em 10px; - display: block; - } - -a.SideMenuEntry:link, -a.SideMenuEntry:visited { - color: #000000; - padding: 1px 10px 2px 9px; - } -a.SideMenuEntry:hover, -a.SideMenuEntry:active, -#SelectedSideMenuEntry { - border-style: solid; - border-width: 1px 2px 2px 1px; - padding: 0 8px; - text-decoration: none; - -moz-border-radius: 10px; - } -a.SideMenuEntry:hover, -a.SideMenuEntry:active { - color: #000000; - border-color: #C8C8C8; - background-color: #F8F8F8; - } -#SelectedSideMenuEntry { - color: #000000; - border-color: #606060; - background-color: #FFFFFF; - } - -.SideMenuSourceForge { - padding-top: 5px; - } - - - -/* Needed by the release notes for 1.3 */ - -.ExPrototype { - font: 10pt Courier New, Courier, monospace; - padding: 5px 3ex; - background-color: #F4F4F4; - border: 1px solid #D0D0D0; - margin: 1em 0; - } -.ExPrototype td { - font: 10pt Courier New, Courier, monospace; - } -.ExPrototype .Fade { - color: #8F8F8F; - } - diff --git a/docs/tool/Help/styles.html b/docs/tool/Help/styles.html deleted file mode 100644 index e9123d1ea..000000000 --- a/docs/tool/Help/styles.html +++ /dev/null @@ -1,52 +0,0 @@ - - -CSS Styles - Natural Docs - - - -
Natural Docs
CSS Styles
Default Styles

These are the styles that come with Natural Docs.  They all follow the same color scheme and general layout; the choices are more so that you can choose the style of text you want.

You choose which style you want for your project by adding “-s [style name]” to the command line.

DefaultThis is the default style that Natural Docs uses.  Most of the text is 10pt Verdana.
SmallSmaller fonts than Default with most of the text using 8pt Verdana.  Some people like the small fonts because you can fit more on the screen at once.  However, some people hate them and find them hard to read.
RomanSerif fonts with most of the text using 12pt Roman.  Some people prefer Roman fonts, usually those that have decent anti-aliasing displays like Mac OS X or Windows XP with ClearType.
Customizing

There are two ways to customize the CSS files.  One is to build your own file from scratch, and the other is to make a touch-up file that gets applied after one of the default styles.  Either way you want to create your own CSS file in your project directory (the one you use with -p) or if you plan on sharing it between many projects, in Natural Docs’ Styles directory.

To use a custom file, no matter where you put it, you just use it with -s without the CSS extension.  So if you made Red.css, you use “-s Red”.  If you made a touch-up file instead, you use it after one of the default styles, such as with “-s Default Red”.  If you’re so inclined, you can string as many touch-up files together as you want or use one of your own as a base.

The CSS Guide documents the page structure and CSS styles of Natural Docs’ output.  Always remember to check its revisions section every time you upgrade Natural Docs because it may change between releases.

Common Customizations
Web-Style Paragraphs

Natural Docs defaults to print-style paragraphs like the one you are reading.  Each one is indented and there are no blank lines between them.  To switch to web-style paragraphs, which have blank lines and no indents, add this to your custom CSS file:

p {
-   text-indent: 0;
-   margin-bottom: 1em;
-   }
-
Prototype Colors

If you’ve added a custom topic type and have it finding prototypes for you, you may want to have them appear in a different color than the default black and white.  Add this to your custom CSS file:

.C[type] .Prototype {
-   background-color: [color];
-   border-color: [color];
-   }
-

Replace [type] with the name of your topic type, minus any symbols and spaces.  So if you added a type “Sound Effect”, you would apply the style to “.CSoundEffect .Prototype”.

Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Help/troubleshooting.html b/docs/tool/Help/troubleshooting.html deleted file mode 100644 index 5b268447a..000000000 --- a/docs/tool/Help/troubleshooting.html +++ /dev/null @@ -1,18 +0,0 @@ - - -Troubleshooting - Natural Docs - - - -
Natural Docs
Troubleshooting
Natural Docs Issues
I don’t get any documentation
Is it recognizing your source files?

If Natural Docs has never said “Parsing n files...” when you run it, or n was way too low a number, it is not finding your source files.

If it has, try this test.  Run Natural Docs once.  Edit one of your source files and save it.  Run Natural Docs again.  If it doesn’t say “Parsing 1 file...” it is not recognizing your file.

No, it’s not recognizing them

The most likely scenario is that Natural Docs doesn’t associate the file extension you’re using with your programming language.  Open Languages.txt in Natural Docs’ Config directory and find your language.  Underneath it you should see a line that says something like “Extensions: c cpp cxx h hpp hxx”.  Add the file extensions you use and try again.

If you use extensionless or .cgi files, do the same thing but instead look for a line that says something like “Shebang Strings: tclsh wish expect”.  If it is not there, you may need to add it yourself.  Edit it to include whatever appears in your shebang (#!) line that would say this file belongs to your language.

Otherwise just make sure you included the directory or one of its parents with -i on the command line.

Yes, it’s recognizing them

First note that unless you have full language support, Natural Docs will only include what you write for it.  It will not be able to scan your code and pick out all the classes and functions on its own.

If the problem is with text files, the most likely scenario is that you’re not including topic lines.  Like in comments, only things that appear under “keyword: name” lines count as Natural Docs content.

If this is happening in code, remember that comments must appear alone on a line.  You cannot put Natural Docs comments on the same line as code.  This includes having anything appear after a closing block comment symbol.

Some of my topics don’t show up
  • Check the list of keywords to see if the one you’re using is there and you spelled it correctly.  Note that the web page only has the default set of keywords.  You may need to check Topics.txt in Natural Docs’ Config directory and your project directory if you’ve edited them
  • If the topics appear in code, make sure that the comments are alone on a line.  You cannot put Natural Docs content on the same line as code.  This includes having anything appear after a closing block comment symbol.
  • Make sure that if you have more than one topic in a comment, there is a blank line above the topic line.
  • If you have text boxes or lines, make sure they are completely unbroken.  You can also try removing them completely.
  • If the topics appear in a text file, make sure you included topic lines.  Like in comments, only things that appear after “keyword: name” lines count as Natural Docs content.  You could just add a Title: line to the top of the file to fix this.
Some of my topics aren’t formatting correctly
  • Headings must have a blank line above them.
  • Lines directly after bullet or definition lines are part of the previous bullet or definition, even if it’s not indented.  Skip a line first to do something else
  • If you’re getting symbols scattered throughout your text, make sure any text boxes or lines are completely unbroken.  You can also try removing them altogether.
  • If your example source code is getting mangled, remember to use the example code syntax.
  • If a line’s becoming a heading but shouldn’t, either get rid of the colon at the end or break it into two lines so the colon appears on the second line
  • If a line’s becoming a definition but shouldn’t, either get rid of the space-dash-space (use two dashes or remove one of the spaces) or break it into two lines so that the space-dash-space is on the second line.

I realize the last two aren’t great.  If you have any ideas as to how to reliably detect these kinds of false positives, e-mail me.

I’m not getting prototypes
  • The topic must appear directly above the thing it’s documenting.
  • Topics documented in lists will not get prototypes, even if the list break apart in the output.
  • The topic name must be present in the prototype somewhere.  Make sure the topic title has the same case as in the prototype and that it’s not misspelled.  This applies even if your language isn’t case sensitive.
  • If you’re documenting something with a new topic type you added to Topics.txt, you must also edit Languages.txt to tell it how to detect prototypes for that type.
My links aren’t working

If your links appear in the output as “<text>” instead of being converted to links, do the following:

  • Make sure the target appears in the output.  The easiest way is to see if it appears in the Everything index.
  • Make sure the link is spelled correctly and has the same case as what you’re linking to.  This applies even if your language isn’t case sensitive.
  • If the topic your link appears in and the link target are not in the same class (or are not both global) make sure you include the class in the link with class.target, class::target, or class->target.  You can check which classes topics appear in with the Everything index.  If your topics are appearing in the wrong classes, fix the documentation remembering the topic scoping rules.
Windows Issues
I get the message “Bad command or file name” or “perl is not recognized”

What’s happening is that NaturalDocs.bat can’t find Perl.  You need Perl installed to run Natural Docs, so if you haven’t done so already, you can download and install ActiveState’s ActivePerl for free.

If you already have Perl, it’s bin directory is either not in your path or the path isn’t being used by whatever you’re running it from, which happens on some IDEs.  Edit NaturalDocs.bat and on the line that says “perl NaturalDocs %NaturalDocsParams%”, change perl to be the full path to perl.exe, such as “C:\perl\bin\perl.exe”.  You need to include the quotes if there are spaces in the path.

I get the message “Can’t open perl script NaturalDocs”

What’s happening is that Perl can’t find the Natural Docs script file.  This happens when the working directory or “start in” folder isn’t the directory Natural Docs was installed to.  If changing that doesn’t work, or if you don’t have the option to set that, edit NaturalDocs.bat and find the line that says “perl NaturalDocs %NaturalDocsParams%”.  Change NaturalDocs to include the full path Natural Docs was installed to, such as “C:\Program Files\Natural Docs\NaturalDocs”.  You need to include the quotes if there are spaces in the path.

Copyright © 2003-2008 Greg Valure
\ No newline at end of file diff --git a/docs/tool/Info/CSSGuide.txt b/docs/tool/Info/CSSGuide.txt deleted file mode 100644 index dfa3aa4c1..000000000 --- a/docs/tool/Info/CSSGuide.txt +++ /dev/null @@ -1,947 +0,0 @@ - - Architecture: CSS Structure -_______________________________________________________________________________ - -It's important to understand the internal HTML file structure and styles in order to design your own CSS style for Natural Docs. If -you're content with the default styles, there's no need to read this document. - -Topic: Diagram Conventions - - The diagrams are designed for clarity. In the actual HTML, you'd obviously see "
" - instead of "
". - - - A tag with just a style, for example "CTitle", means an unspecified element with that class. Style with .CTitle. - - A tag that includes a #, for example "#Menu", means an unspecified element with that ID. Style with #Menu. - - A tag that includes a HTML element as well, for example "table CDescriptionList", means it will always be that element. You - can style with either .CDescriptionList or table.CDescriptionList. - - A tag that has multiple classes or has an "and" in it, for example "CType and CTopic", means that both styles will apply to the - same element. You can style it with .CType.CTopic, noting that the space between them must be omitted. - - A tag that has an "or" in it, for example "#Content or #Index", is just shorthand for either of those elements. The diagram - applies to both of them but only one will actually appear at a time in the output. - - A tag or style with a question mark means that tag or style will only be there in certain situations. - - -Topic: Page Structure -_______________________________________________________________________________ - - The body tag is used to distinguish between the types of pages. - - Unframed Content/Index Page: - - (start diagram) - - - [browser styles] - - <#Content or #Index> - Content or Index - - - <#Menu> - Menu - - - <#Footer> - Footer - - - [/browser styles] - - - (end diagram) - - - Unframed Search Results Popup Page: - - (start diagram) - - - [browser styles] - - <#Index> - Index - - - [browser styles] - - - (end diagram) - - - Framed Menu Page: - - (start diagram) - - - [browser styles] - - <#Menu> - Menu - - - <#Footer> - Footer - - - [browser styles] - - - (end diagram) - - - Framed Content/Index/SearchResults Page: - - (start diagram) - - - [browser styles] - - <#Content or #Index> - Content or Index - - - [browser styles] - - - (end diagram) - - -Styles: Page Styles - - ContentPage - An unframed content page. - IndexPage - An unframed index page. - PopupSearchResultsPage - A search results page for use in a popup iframe. - - FramedContentPage - A framed content page. - FramedIndexPage - A framed index page. - FramedSearchResultsPage - A framed search results page. - - #Footer - The page footer. Will be in a framed menu page or on its own in a non-framed page. - - See Also: - - - <#Content> - - <#Menu> - - <#Index> - - <#Footer> - - - - -Styles: Browser Styles -_______________________________________________________________________________ - - - Natural Docs pages include JavaScript to detect which browser the user is running and apply styles so that you can work - around browser quirks right in the CSS file. - - The browser type and version styles will be applied immediately after the body tag. However, neither are guaranteed to be - there; the user may have JavaScript turned off or be using a browser that isn't detected. These styles should only be used to - correct minor flaws and should not be heavily relied on. - - > - > ? - > ? - > - > Page Content - > - > ? - > ? - > - - For example, if a 's style is giving you problems in Internet Explorer 6, override it with .IE6 .CTopic. If a 's - style gives you a problem in Opera 7 but only in frames, override it with .Framed.Opera7 .MTitle. - - Browser Types: - - If the browser is not one of the types below, neither this nor the browser version will be present. There's the possibility that - some obscure browser will appear as one of the others by spoofing, but the most prominent of these, Opera, Konqueror, and - Safari, are taken care of. - - IE - Internet Explorer - Firefox - Firefox and anything else based on the Gecko rendering engine. - Opera - Opera - Safari - Safari - Konqueror - Konqueror and anything else based on the KHTML rendering engine except Safari. - - Browser Versions: - - If the browser is not one of the versions below, this style will not be present. The browser type still may be. - - IE6 - Internet Explorer 6.x. - IE7 - Internet Explorer 7.x. - - Firefox1 - Firefox 1.0.x and anything else based on Gecko 1.7.x. - Firefox15 - Firefox 1.5.x and anything else based on Gecko 1.8.0.x. - Firefox2 - Firefox 2.0.x and anything else based on Gecko 1.8.1.x. - - Opera7 - Opera 7.x. - Opera8 - Opera 8.x. - Opera9 - Opera 9.x. - - Safari2 - Safari 2.x. - Safari3 - Safari 3.x. - - Notes: - - Why not apply them to the body tag itself? The JavaScript is easy enough and everything supports multiple classes, right? - Because IE 6 doesn't support multiple selectors so I wouldn't be able to combine browser and page styles. - .Opera.ContentPage will apply to all ContentPages in IE because it treats it as if only the last class is there. - - - - -Topic: Content Structure -_______________________________________________________________________________ - - - All the topics of a given file is contained in a <#Content>. All other content styles are prefixed with a C. - - Surrounding each piece of content is a and its type; for example, CFunction for a function. Inside that are the - and if necessary, . Inside are analogues to all the top-level tags:

,

, etc. - - In addition to the top-level tags, you also have prototypes, class hierarchies, and summaries which are - described in their own sections. - - (start diagram) - - <#Content> - - - - - - Topic title - - - - - [Class Hierarchy] - - [Prototype] - - - Heading - - -

- Paragraph -

- -
-                        Code or text diagram
-                    
- -
    -
  • - Bullet item -
  • -
- - ? - Caption - ? - - - - text - - - - - - - -
- Entry - - Description -
- - [Summary] - - - - - - - - - (end diagram) - - Take advantange of the CSS inheritance model. For example, you can style all titles via .CTitle, and you can style - specific titles with .CType .CTitle. - - -Styles: Content Styles - - #Content - Parent element containing all topics. - - CTopic - An individual topic. - - CTitle - The title of a topic. - CBody - The body of a topic. May not exist. - CHeading - Surrounds a heading. - CImageCaption - Surrounds an image caption. - CImageLink - Surrounds a link to an image. - - CDescriptionList - A description list, which is the type of list you're reading right now. Is implemented with a table. - CDLEntry - A description list entry, which is the left side. - CDLDescription - A description list description, which is the right side. - - #MainTopic - The ID given to the main topic, which is the first in the file. It is applied to the . - - CType - A placeholder for all type-specific styles. The actual styles will be C followed by the alphanumeric-only topic type name. - So the CType of a "PL/SQL Function" topic will actually be CPLSQLFunction. - - - - -Topic: Menu Structure -_______________________________________________________________________________ - - - Everything is enclosed in a <#Menu>. All other menu styles are prefixed with an M. - - The title is an and will always be at the beginning of the menu if it exists. If a subtitle exists as well, it will appear - as an inside . Subtitles aren't allowed without titles. Most other entries in the menu are contained in - . Here's the diagram: - - (start diagram) - - <#Menu> - - - Menu title - - - Menu sub title - - - - - - - File - - - - - - File - - - - - - Text - - - - - - Link - - - - - - Group - - - (MEntries) - - - - - - <#MSearchPanel and MSearchPanelActive/Inactive> - - - - - - - (if in unframed HTML) - <#MSearchResultsWindow> - - - - - - - - (end) - - The or entry that's currently selected will have the <#MSelected> ID, so you can reference it in CSS via - .MFile#MSelected. - - The search panel is has its own ID, <#MSearchPanel>, but also has one of the classes or - depending on whether any of the controls are selected or the results window is open. - <#MSearchResultsWindow> is separate because it may be floating. - - -Styles: Menu Styles - - #Menu - Parent element containing the entire menu. - - MTitle - The title of the menu. - MSubTitle - The subtitle of the menu. Will appear within . - - MFile - A file entry. - MGroup - A group entry. - MGroupContent - A container for a content. - MText - A plain text entry. - MLink - An external link entry. - MIndex - An index entry. - - #MSelected - The ID of the currently selected or . - - MType - , , , , or . - - #MSearchPanel - Contains all the search controls. - MSearchPanelActive - Applied to <#MSearchPanel> when any of the controls are selected or the results window is open. - MSearchPanelInactive - Applied to <#MSearchPanel> when not in use. - - #MSearchField - The text input field of the search panel. - #MSearchType - The drop down type selector of the search panel. - #MSearchEverything - The <#MSearchType> option for the Everything index. - - #MSearchResultsWindow - Contains all the search results elements. - #MSearchResults - Contains the iframe that will hold the results. - #MSearchRseultsWindowClose - The link to manually close the search results window. - - - - -Topic: Class Hierarchy Structure -_______________________________________________________________________________ - - - Everything is contained in a single . Each entry is surrounded by its type, such as , and the - generic . Depending on the context, entries may be surrounded by one or more . - - (start diagram) - - - - ? - - - - - ? - Entry - - - - - - ? - - - - (end diagram) - - -Styles: Class Hierarchy Styles - - ClassHierarchy - The topmost style containing everything. - - CHEntry - A generic class entry. - - CHParent - The style for a parent class. - CHCurrent - The style for the current class, which is the one the hierarchy is generated for. - CHChild - The style for a child class. - CHChildNote - The style for when a child is added that just shows how many other children were omitted. - - CHIndent - A style used to indent a level. - - CHType - , , , or . - - - - -Topic: Summary Structure -_______________________________________________________________________________ - - - Everything is enclosed in a single . All the other summary styles are prefixed with an S. - - holds the actual word "Summary" and and hold the content. exists because different - browsers apply table padding attributes in different ways. exists as a class to separate the main table from any other - tables that may be necessary. Here's a diagram: - - > - > - > - > Title - > - > - > - > - > ... - >
- >
- > - >
- - On to the table content. - - > - > - > - > Entry - > - > - > - > - > Description - > - > - > - - exist to allow indenting. They're necessary because implementing it as nested tables, while structurally cleaner, - won't allow the desciptions to line up on the right throughout the entire summary. will be applied on almost every - other row to allow for tinting to improve readability. - - Use the power of CSS's inheritance rules to specify styles. For example, to set the style of a group entry, apply it to - .SGroup .SEntry. However, you could also apply a style to both the group's entry and description by applying the - style to .SGroup td. Or, you could apply a style to all the entries by applying it to .SEntry. And so on. - - -Styles: Summary Styles - - Summary - The topmost style containing the entire summary. - - STitle - Contains the summary title, which is the part that actually says "Summary". - - SBorder - Surrounds , since some browsers can't do table padding right. A hack, I know. - STable - The actual summary table. This class separates it from other layout tables that may appear. - - SMarked - A class applied to rows that should have a slightly different color than the rest of the rows to make them easier to - read. - - SEntry - The entry (left) side of the table. - SDescription - The description (right) side of the table. - - SIndent# - Surrounding entries and descriptions that are part of a group and need to be indented. Actual styles will be - SIndent1, SIndent2, etc. - - SType - A placeholder for all topic-specific styles. The actual styles will be S followed by the alphanumeric-only topic type name. - So the SType of a "PL/SQL Function" topic will actually be SPLSQLFunction. - - - - -Topic: Prototype Structure -_______________________________________________________________________________ - - - Everything is enclosed in a . All other styles are prefixed with a P. - - Parameter Type First Style: - - For prototypes such as - > void Function (unsigned int* a, int b = 0) - where the types come first. - - (start diagram) - - - - - - - - - - - - - - - - - - (repeated as necessary) - - - -
- "void Function (" - - "unsigned" - - "int" - - "*" - - "a", "b" - - "=" - - "0" - - ")" -
- - (end diagram) - - - Parameter Name First Style: - - For prototypes such as - > function Function (a, b: int; c: int := 0) - where the parameters come first. - - (start diagram) - - - - - - - - - - - - - - (repeated as necessary) - - - -
- "function Function (" - - "a,", "b:", "c:" - - "int" - - ":=" - - "0" - - ")" -
- - (end diagram) - - - Note that any section may not exist. For example, there will be no cells generated if none of the parameters - have it. - - -Styles: Prototype Styles - - Prototype - The style encompassing the entire prototype. - - PBeforeParameters - The part of the prototype that comes before the parameters. - PAfterParameters - The part of the prototype that comes after the parameters. - - PType - The parameter type. - PTypePrefix - The prefix of a parameter type. - PParameter - The parameter name. - PParameterPrefix - The prefix of a parameter name. - PDefaultValue - The default value expression for a parameter. - PDefaultValuePrefix - The prefix of the default value expression. - - - - -Topic: Link Structure -_______________________________________________________________________________ - - - All links to symbols have a type style prefixed with L. The only exceptions are summary entries; summary descriptions use - them as well. - - > - > Link - > - - You can use this to make links to different symbols appear in different styles. For example, making .LClass bold will make all - links to classes bold, except when appearing in summary entries. You can combine this with other styles to be even more - specific. For example, you can apply a style to function links appearing in summary descriptions with .SDescription .LFunction. - -Styles: Link Styles - - LType - A placeholder for all topic-specific styles. The actual styles will be L followed by the alphanumeric-only topic type name. - So the LType of a "PL/SQL Function" topic will actually be LPLSQLFunction. - - - -Topic: Index Structure -_______________________________________________________________________________ - - - Everything is enclosed in an <#Index>. Combine with and to distinguish between output formats. All - other index styles are prefixed with an I. - - (start diagram) - - <#Index> - - - Page Title - - - - A - B - C ... - - - - - - Heading (A, B, etc.) - - - - - - - ... - -
- Prefix, if any - - Entry -
- - - - (end diagram) - - Every index entry, including headings, are rows in a table. The first column of a non-heading are so that - the non-prefix portions align correctly. The other column are , of which there are multiple formats, described below. - - (start diagram) - - - Symbol - , - - Class - - - - Symbol - - - - Class - - ... - - - - Symbol - - - - Class - - - - File - - ... - - ... - - - (end diagram) - - Each part of the entry is surrounded by its type, which may or may not be a link. If an entry has more than one defining class - or file, they're broken out into . - - It's called instead of because class entries are . are only used when the symbol - has a class. If the symbol _is_ a class, the symbol is global. - - -Styles: Index Styles - - #Index - Parent element for the entire index. - - IPageTitle - The page title. - INavigationBar - The navigation bar. - - IHeading - An index heading, such as the letter for the group. - - IEntry - An entry in the index. - ISymbolPrefix - The stripped prefix of the entry. - ISymbol - The entry symbol. - IParent - The entry parent class. If the entry _is_ a class, this isn't defined because classes are global and don't have parent - classes. This is why it's called IParent instead of IClass; hopefully it's less confusing. - IFile - The file the entry is defined in. - - ISubIndex - The surrounding block if an entry needs to be broken out into a sub-index. - - #IFirstHeading - The ID of the first to appear in the file. - - #IFirstSymbolPrefix - The ID for the first to appear under an . - #ILastSymbolPrefix - The ID for the last to appear under an . - #IOnlySymbolPrefix - The ID if there is only one for an . - - - -Topic: Search Results Structure -_______________________________________________________________________________ - - - The search results use virtually the same structure and styles as the indexes, except that <#SearchResults> replaces - <#Index>, there's a new style, and there are a few additional blocks. - - Visibility: - - Visibility is *very* important to making the search work correctly. JavaScript will handle most of it, but your CSS needs to - abide by these rules. - - - sections are visible by default. - - sections are *not* visible by default. They must use display: none. - - should be display: none when under <#SearchResults>. - - -Styles: Search Results Styles - - #SearchResults - Parent element for the entire page. - SRStatus - Status message. Must be visible by default. - SRResult - A result. All you need to do for this class is set it to display: none. Nothing else should be set on it. - - - - -Topic: Tool Tip Structure -_______________________________________________________________________________ - - - Tool tips may appear anywhere in the page, mainly because it's assumed that they will use position: absolute and - visibility: hidden. - - The entire tool tip is found in a style, with a CType style inside it. CTypes are normally outside their elements, but - that would cause it to be partially visible in this case. We need to be the outermost style so its visibility and - position can be manipulated in JavaScript. - - Inside there's a and/or the description text. The description text has no special surrounding tags. - - > - > - > - > Prototype - > - > - > Summary text - > - > - -Styles: Tool Tip Styles - - CToolTip - Surrounds the entire tool tip. This *must* have position: absolute and visibility: hidden for the tool tip mechanism - to work. - - See also . - - -Styles: Miscellaneous Styles - - blockquote - This HTML element should surround anything that needs to be scrolled if it's too wide, like prototypes and text - diagrams. It's not a style because this makes it much easier to do the JavaScript necessary to get this working - in IE. - - -Group: History - -Topic: Revisions -_______________________________________________________________________________ - - - How the page structure has changed throughout the various releases. - - 1.4: - - - Replaced UnframedPage with and . - - Added <#Menu>, <#Content>, <#Footer>, and <#Index>. They were previously shown in the diagrams as classes but did - not actually appear in the generated output. - - Removed MenuSection, ContentSection, and IndexSection. Use things like ".ContentPage #Menu" instead. - - Removed tables from the unframed . Use CSS to position the elements instead. - - <#MainTopic> is applied to instead of . - - IE4, IE5, Opera5, Opera6, Netscape, and Netscape4 browser styles have been removed. , , - and have been added. Gecko has been replaced by , , , and . - KHTML has been replaced by , , , and . - - Removed redundant CParagraph, CCode, and CBulletList classes. Use with p, pre, and ul instead. - - Added and . - - Added <#MSearchPanel>, <#MSearchResultsWindow>, and all related styles. - - Added , , and . - - Removed SEntrySize. Apply the width to and instead. - - , , and were moved from the td and divs into the tr. - - Removed HB style. Now using wbr tag. - - 1.33: - - - Added . - - 1.32: - - - now surround elements that should scroll if they're too wide for the page. - - 1.3: - - - Removed CPrototype. See the replacement and . - - Removed SInGroup, SInClass, and SInSection in favor of more general . - - , , and are now completely determined by configuration files. - - , , and no longer have separate list types. A CFunctionList is now just a CFunction. - - Indexes are now done with tables. - - ISection was removed. - - are only used for the entry cell, not for each entry in an . - - Added , related IDs, and <#IFirstHeading>. - - Merged and into the same element. Must now be styled with .CType.CTopic (no space) while all - sub-elements will still be .CType .CElement (with space.) - - 1.21: - - - Added and TOPIC_PROPERTY_LIST styles, so they get corresponding , , and - . - - 1.2: - - - Added since 1.2 added class hierarchies. - - 1.16: - - - Changed the first topic from having a CMain type to having a normal type with a <#MainTopic> ID. - - 1.1: - - - Added . - - Renamed HiddenBreak to . - - Added , TOPIC_CONSTANT_LIST, , and TOPIC_TYPE_LIST types, so they get - corresponding , , and . - - 1.0: - - - The tags now appear arround the tags instead of vice versa. - - Added a tag to surround non- elements. - - now appears in tr's instead of td's, where it belonged in the first place. - - 0.95: - - - Added . - - Redid , replacing generic styles like Menu with page type styles like UnframedPage/MenuSection and - FramedMenuPage. - - 0.91: - - - Added and link styles, since 0.91 added URL and e-mail links. - - Added style, which is better than floating on its own. - - 0.9: - - - Added , since 0.9 added indexes. - diff --git a/docs/tool/Info/File Parsing.txt b/docs/tool/Info/File Parsing.txt deleted file mode 100644 index 4833777bd..000000000 --- a/docs/tool/Info/File Parsing.txt +++ /dev/null @@ -1,83 +0,0 @@ - - Architecture: File Parsing - -#################################################################################### - - This is the architecture and code path for general file parsing. We pick it up at Parse()> because we're not interested in how the files are gathered and their languages determined for the purposes of this document. We are just interested in the process each individual file goes through when it's decided that it should be parsed. - - - - Stage: Preparation and Differentiation - _______________________________________________________________________________________________________ - - Parse()> can be called from one of two places, ParseForInformation()> and ParseForBuild()>, which correspond to the parsing and building phases of Natural Docs. There is no noteworthy work done in either of them before they call Parse(). - - - Stage: Basic File Processing - _______________________________________________________________________________________________________ - - The nitty-gritty file handling is no longer done in itself due to the introduction of full language support in 1.3, as it required two completely different code paths for full and basic language support. Instead it's handled in NaturalDocs::Languages::Base->ParseFile(), which is really a virtual function that leads to ParseFile()> for basic language support or a version appearing in a package derived from for full language support. - - The mechinations of how these functions work is for another document, but their responsibility is to feed all comments Natural Docs should be interested in back to the parser via OnComment()>. - - - Stage: Comment Processing - _______________________________________________________________________________________________________ - - OnComment()> receives the comment sans comment symbols, since that's language specific. All comment symbols are replaced by spaces in the text instead of removed so any indentation is properly preserved. Also passed is whether it's a JavaDoc styled comment, as that varies by language as well. - - OnComment() runs what it receives through CleanComment()> which normalizes the text by removing comment boxes and horizontal lines, expanding tabs, etc. - - - Stage: Comment Type Determination - _______________________________________________________________________________________________________ - - OnComment() sends the comment to IsMine()> to test if it's definitely Natural Docs content, such as by starting with a recognized header line. If so, it sends it to ParseComment()>. - - If not, OnComment() sends the comment to IsMine()> to test if it's definitely JavaDoc content, such as by having JavaDoc tags. If so, it sends it to ParseComment()>. - - If not, the content is ambiguous. If it's a JavaDoc-styled comment it goes to ParseComment()> to be treated as a headerless Natural Docs comment. It is ignored otherwise, which lets normal comments slip through. Note that it's only ambiguous if neither parser claims it; there's no test to see if they both do. Instead Natural Docs always wins. - - We will not go into the JavaDoc code path for the purposes of this document. It simply converts the JavaDoc comment into as best it can, which will never be perfectly, and adds a to the list for that file. Each of those ParsedTopics will be headerless as indicated by having an undefined Title()>. - - - Stage: Native Comment Parsing - _______________________________________________________________________________________________________ - - At this point, parsing is handed off to ParseComment()>. It searches for header lines within the comment and divides the content into individual topics. It also detects (start code) and (end) sections so that anything that would normally be interpreted as a header line can appear there without breaking the topic. - - The content between the header lines is sent to FormatBody()> which handles all the block level formatting such as paragraphs, bullet lists, and code sections. That function in turn calls RichFormatTextBlock()> on certain snippets of the text to handle all inline formatting, such as bold, underline, and links, both explicit and automatic. - - ParseComment()> then has the body in so it makes a to add to the list. It keeps track of the scoping via topic scoping, regardless of whether we're using full or basic language support. Headerless topics are given normal scope regardless of whether they might be classes or other scoped types. - - - Group: Post Processing - _______________________________________________________________________________________________________ - - After all the comments have been parsed into ParsedTopics and execution has been returned to Parse()>, it's time for some after the fact cleanup. Some things are done like breaking topic lists, determining the menu title, and adding automatic group headings that we won't get into here. There are two processes that are very relevant though. - - - Stage: Repairing Packages - _______________________________________________________________________________________________________ - - If the file we parsed had full language support, the parser would have done more than just generate various OnComment() calls. It would also return a scope record, as represented by objects, and a second set of ParsedTopics it extracted purely from the code, which we'll refer to as autotopics. The scope record shows, purely from the source, what scope each line of code appears in. This is then combined with the topic scoping to update ParsedTopics that come from the comments in the function RepairPackages()>. - - If a comment topic changes the scope, that's honored until the next autotopic or scope change from the code. This allows someone to document a class that doesn't appear in the code purely with topic scoping without throwing off anything else. Any other comment topics have their scope changed to the current scope no matter how it's arrived at. This allows someone to manually document a function without manually documenting the class and still have it appear under that class. The scope record will change the scope to part of that class even if topic scoping did not. Essentially the previous topic scoping is thrown out, which I guess is something that can be improved. - - None of this affects the autotopics, as they are known to have the correct scoping since they are gleaned from the code with a dedicated parser. Wouldn't there be duplication of manually documented code elements, which would appear both in the autotopics and in the comment topics? Yes. That brings us to our next stage, which is... - - - Stage: Merging Auto Topics - _______________________________________________________________________________________________________ - - As mentioned above, ParseFile() also returns a set of ParsedTopics gleaned from the code called autotopics. The function MergeAutoTopics()> merges this list with the comment topics. - - The list is basically merged by line number. Since named topics should appear directly above the thing that they're documenting, topics are tested that way and combined into one if they match. The description and title of the comment topic is merged with the prototype of the autotopic. JavaDoc styled comments are also merged in this function, as they should appear directly above the code element they're documenting. Any headerless topics that don't, either by appearing past the last autotopic or above another comment topic, are discarded. - - - Stage: Conclusion - _______________________________________________________________________________________________________ - - Thus ends all processing by Parse()>. The file is now a single list of with all the body content in . If we were using ParseForBuild()>, that's pretty much it and it's ready to be converted into the output format. If we were using ParseForInformation()> though, the resulting file is scanned for all relevant information to feed into other packages such as . - - Note that no prototype processing was done in this process, only the possible tranferring of prototypes from one ParsedTopic to another when merging autotopics with comment topics. Obtaining prototypes and formatting them is handled by and derived packages. diff --git a/docs/tool/Info/HTMLTestCases.pm b/docs/tool/Info/HTMLTestCases.pm deleted file mode 100644 index 343b45a8f..000000000 --- a/docs/tool/Info/HTMLTestCases.pm +++ /dev/null @@ -1,269 +0,0 @@ -############################################################################### -# -# File: Browser Testing -# -############################################################################### -# -# This file tests Natural Docs' generated output. Particularly useful when testing various browsers. -# -############################################################################### - -# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -# Natural Docs is licensed under the GPL - -use strict; -use integer; - - -# -# About: Browsers -# -# The specific browser versions tested are below. Everything is tested on Windows Vista unless otherwise noted. -# -# Firefox 2.0.0.10 - 2.0 released October 2006. -# Firefox 1.5.0.8 - 1.5 released Novemer 2005. -# Firefox 1.0.8 - 1.0 released November 2004. Not critical to support. -# -# IE 7.0 - 7.0 released October 2006. -# IE 6.0 - 6.0 released August 2001. Tested on Windows XP SP2 via Virtual PC. -# -# Safari 3.0.4 - 3.0 released June 2007. Tested Windows version. -# Safari 2.0.4 - 2.0 released April 2005. Tested on Mac OS X 10.4 Tiger. -# -# Opera 9.02 - 9.0 released June 2006. -# Opera 8.54 - 8.5 released September 2005. -# Opera 8.02 - 8.0 released April 2005. -# Opera 7.51 - 7.5 released around August 2004 I think. Not critical to support. -# Opera 7.02 - 7.0 released January 2003. Not critical to support. -# -# Konqueror 3.5.5 - Tested on openSUSE 10.2 via VMware Player. -# - - -############################################################################### -# Group: Search - -# -# Topic: Unframed HTML Search -# -# Tests: -# -# - Make sure the search box appears and disappears correctly on hover. -# - Type to bring up results. Type further to narrow them. Narrow until there's no results. -# - Backspace to bring the results back. Backspacing to empty closes the results. -# - Type to bring up results with a different first letter. (Tests iframe content switch.) -# - Type *Z* to bring up empty page when there's nothing with that first letter. (Tests generic no results page.) -# - Type *Name* in Everything search to test expanding and collapsing, especially between two that differ only by case. -# - Change filter to *Functions* to test changing filter while results are open. Change to *Types* to switch to one with -# no results. -# - Test Close button on results. Should deactivate panel as well. -# - Clicking away should deactivate panel if the box is empty, not have an effect if there are results open. -# - Text should always change back to "Search" when deactivating. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - Functionally OK. Search panel doesn't activate on hover. Works fine when clicked. -# -# Safari 3.0 - OK -# Safari 2.0 - *Broken.* Results panel doesn't show up. Border around deactivated search box. -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - Functionally OK. Search panel has sunken border when deactivated, minor pixel shifting. -# Opera 7.0 - *Broken.* Completely. -# -# Konqueror 3.5 - *Broken.* Results panel doesn't show up. Seems to fail on "resultsFrame = window.frames.MSearchResults;" -# - -# -# Topic: Framed HTML Search -# -# Tests: -# -# - Make sure the search box appears and disappears correctly on hover. -# - Type to bring up results on right. Type further to narrow them. Narrow until there's no results. -# - Backspace to bring the results back. -# - Type to bring up results with a different first letter. (Tests frame content switch.) -# - Type *Z* to bring up empty page when there's nothing with that first letter. (Tests generic no results page.) -# - Type *Name* in Everything search to see that there's no collapsing in this mode. -# - Change filter to *Functions* to test changing filter while results are open. Change to *Types* to switch to one with -# no results. -# - Clicking away should deactivate panel. -# - Clicking a result should deactivate panel and show up in correct frame. -# - Text should always change back to "Search" when deactivating. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - Functionally OK. Search panel doesn't activate on hover, is a little wide. Works fine when clicked. -# -# Safari 3.0 - OK -# Safari 2.0 - Functionally OK. Has a sunken border around the deactivated seach field. -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - Functionally OK. Search panel has sunken border when deactivated, minor pixel shifting. -# Opera 7.0 - *Broken.* -# -# Konqueror 3.5 - Functionally OK. Panel doesn't reset and deactivate when clicking a result link. -# - - -############################################################################### -# Group: Other - -# -# Topic: Images -# -# Tests: -# -# - Here is an embedded image on its own line. -# -# (see images/logo.png) -# -# - Here is a reference in the middle of a sentence, in the middle of a bullet list: (see images/logo.png) It should have been -# converted to a link with the image appearing below the bullet list and the file name used as a caption. Make sure the -# caption positions correctly. -# - Here's a link to a non-existent image, which should appear literally: (see images/doesntexist.jpg) -# - Here is an embedded image that doesn't exist on it's own line. -# -# (see images/doesntexist.png) -# -# - Here is a link using the "(see)" syntax which shouldn't be interpreted as an image link because it doesn't end with an -# acceptable extension. Also, links should still resolve because of that. (see ) -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - OK -# Opera 7.0 - OK -# -# Konqueror 3.5 - OK - - -# -# Topic: Prototypes and Tooltips -# -# Hover over ParseComment()> and IsMine()> -# -# Tests: -# -# - A tooltip should appear about a second after you hover over the link above. -# - It should go away when you move the cursor away. -# - It shoud be positioned directly underneath with a slight gap. -# - The prototype should be formatted cleanly with each parameter on its own line and aligned in columns. -# - The asterisk should be in a separate column. -# - Test it with the link too close to the edge of the window so the pop-up has to shift left to fit. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 8.5 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 8.0 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 7.5 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 7.0 - *Broken.* Usually works, if the window is too narrow may collapse completely. -# -# Konqueror 3.5 - OK -# - - -# -# Topic: Long code block scrolling -# -# Go to . -# -# Tests: -# -# - Shrink the browser window so that a line extends past the end of it. Only the line should have a scrollbar, not the -# entire page. -# - Expand the browser window. The scrollbar should disappear. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - OK -# Opera 7.0 - OK -# -# Konqueror 3.5 - OK -# - - -# -# Topic: Menu and Class Hierarchies -# -# Go to . -# -# Tests: -# -# - Class hierarchy should look okay. -# - Make sure the menu hierarchy opens up on its own when the page is loaded. -# - You should be able to click on groups to open and close them. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - OK -# Opera 7.0 - OK -# -# Konqueror 3.5 - OK -# - - -1; diff --git a/docs/tool/Info/Languages.txt b/docs/tool/Info/Languages.txt deleted file mode 100644 index e123127db..000000000 --- a/docs/tool/Info/Languages.txt +++ /dev/null @@ -1,107 +0,0 @@ - - Title: Language Notes -_______________________________________________________________________________ - - This is more for my personal reference than anything else. - - - ___________________________________________________________________________ - - Topic: Prototype Parameter Styles - ___________________________________________________________________________ - - Parameters via Commas, Typed via Spaces: - - > FunctionName ( type indentifier, type identifier = value, modifier type identifier ) - > FunctionName ( indentifier, identifier = value ) - - The general idea is that parameters are separated by commas. Identifiers cannot contain spaces. Types and modifiers, - if available, are separated from the identifiers with spaces. There may be an equals sign to set the default value. - - So parsing means splitting by commas, stripping everything past an equals sign for the default value, stripping everything - after the last space for the identifier, and the rest is the type. If there are no internal spaces after the default value is - stripped, it's all identifier. - - Note that internal parenthesis, brackets, braces, and angle brackets should be parsed out. They may be present in default - values or types and any commas and equal signs in them should not be included. - - Applies to C++, Java, C#, JavaScript, Python, PHP, Ruby. - - Applies to Perl as well, even though it doesn't have any real parameter declaration structure. Just adding it with comments - is fine. - - Parameters via Semicolons and Commas, Typed via Colons: - - > FunctionName ( identifier: type; identifier, identifier: type; identifier: type := value ) - - Parameters via semicolons, types via colons. However, there can be more than one parameter per type via commas. - Default values via colon-equals. - - Applies to Pascal, Ada. - - - SQL: - - > FunctionName ( identifier type, identifier modifier type, identifier type := value ) - - Parameters separated by commas. Identifiers come before the types and are separated by a space. Default values are - specified with colon-equals. - - > FunctionName @identifier type, @dentifier modifier type, @identifier type = value - - Microsoft's SQL uses equals instead of colon-equals, doesn't need parenthesis, and starts its parameter names with an @ - symbol. - - - Visual Basic: - - > FunctionName ( modifiers identifier as type, identifier = value ) - - Parameters separated by commas. Default values via equals. However, any number of modifiers may appear before the - identifier. Those modifiers are ByVal, ByRef, Optional, and ParamArray. - - - Tcl: - - > FunctionName { identifier identifier { whatever } } { code } - - Identifiers are specified in the first set of braces and have no commas. However, they can be broken out into sub-braces. - - - ___________________________________________________________________________ - - Topic: Syntax References - ___________________________________________________________________________ - - C++ - http://www.csci.csusb.edu/dick/c++std/syntax.html - - C# - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/CSharpSpecStart.asp. Open in IE. - - Java - http://cui.unige.ch/db-research/Enseignement/analyseinfo/ - Ada - http://cui.unige.ch/db-research/Enseignement/analyseinfo/ - - SQL - http://cui.unige.ch/db-research/Enseignement/analyseinfo/, - , or - (open in IE). - - JavaScript - http://academ.hvcc.edu/~kantopet/javascript/index.php - - Python - http://www.python.org/doc/2.3.4/ref/ref.html - - PHP - http://www.php.net/manual/en/langref.php - - Visual Basic - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbls7/html/vbspecstart.asp. Open in IE. - - Pascal - . Open in IE. - - Ruby - http://www.rubycentral.com/book/ - - ActionScript 2 - - ActionScript 3 - - E2X - http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf - - R - Somewhere on http://www.r-project.org. - - ColdFusion - - - Eiffel - http://www.gobosoft.com/eiffel/syntax/ diff --git a/docs/tool/Info/NDMarkup.txt b/docs/tool/Info/NDMarkup.txt deleted file mode 100644 index 0d10e0f9a..000000000 --- a/docs/tool/Info/NDMarkup.txt +++ /dev/null @@ -1,91 +0,0 @@ - - Architecture: NDMarkup -_______________________________________________________________________________ - -A markup format used by the parser, both internally and in objects. Text formatted in -NDMarkup will only have the tags documented below. - - -About: Top-Level Tags - - All content will be surrounded by one of the top-level tags. These tags will not appear within each other. - -

- Surrounds a paragraph. Paragraph breaks will replace double line breaks, and single line breaks will - be removed completely. - - - Surrounds code or text diagrams that should appear literally in the output. - - - Surrounds a heading. - -
    - Surrounds a bulleted (unordered) list. -
    - Surrounds a description list, which is what you are reading. - - - An inline image. Target contains the image target, and original contains the - original text in case it doesn't resolve. - - -About: List Item Tags - - These tags will only appear within their respective lists. - -
  • - Surrounds a bulleted list item. - - Surrounds a description list entry, which is the left side. It will always be followed by a description list - description. - - Surrounds a description list symbol. This is the same as a description list entry, except that the content - is also a referenceable symbol. This occurs when inside a list topic. This tag will always - be followed by a description list description. -
    - Surrounds a description list description, which is the right side. It will always be preceded by a description - list entry or symbol. - -About: Text Tags - - These tags will only appear in paragraphs, headings, or description list descriptions. - - - Bold - - Italics - - Underline - - - Surrounds a potential link to a symbol; potential because the target is not guaranteed to - exist. This tag merely designates an attempted link. Target is what is attempting to be - linked to, name is the text that should appear for a successful link, and original is the - original text in case the link doesn't resolve. - - - An external link. There's no need for an original attribute because it will always be - turned into an actual link. - - A link to an e-mail address. - - - An image link. Target contains the image target, and original contains the original - text in case it doesn't resolve. - - -About: Amp Chars - - These are the only amp chars supported, and will appear everywhere. Every other character will appear as is. - - & - The ampersand &. - " - The double quote ". - < - The less than sign <. - > - The greater than sign >. - -About: Tabs - - NDMarkup will not contain tab characters, only spaces. Any tab characters appearing in the source files will be - expanded/replaced as necessary. - - -About: General Tag Properties - - Since the tags are generated, they will always have the following properties, which will make pattern matching much - easier. - - - Tags and amp chars will always be in all lowercase. - - Properties will appear exactly as documented here. They will be in all lowercase, in the documented order, and will have no - extraneous whitespace. Anything appearing in the properties will have amp chars. - - All code is valid, meaning tags will always be closed,
  • s will only appear within
      s, etc. - - So, for example, you can match description list entries with /(.+?)<\/de>/ and $1 will be the text. No surprises or - gotchas. No need for sophisticated parsing routines. - - Remember that for symbol definitions, the text should appear as is, but internally (such as for the anchor) they need to - be passed through Defines()> so that the output file is just as tolerant as - . diff --git a/docs/tool/Info/Symbol Management.txt b/docs/tool/Info/Symbol Management.txt deleted file mode 100644 index 93ba6a438..000000000 --- a/docs/tool/Info/Symbol Management.txt +++ /dev/null @@ -1,59 +0,0 @@ - - Architecture: Symbol Management - -#################################################################################### - - This is the architecture and code path for symbol management. This is almost exclusively managed by , but it's complicated enough that I want a plain-English walk through of the code paths anyway. - - An important thing to remember is that each section below is simplified initially and then expanded upon in later sections as more facets of the code are introduced. You will not get the whole story of what a function does by reading just one section. - - - - Topic: Symbol Storage - _______________________________________________________________________________________________________ - - Symbols are indexed primarily by their , which is the normalized, pre-parsed series of identifiers that make it up. A symbol can have any number of definitions, including none, but can only have one definition per file. If a symbol is defined more than once in a file, only the first definition is counted. Stored for each definition is the , summary, and prototype. - - Each symbol that has a definition has one designated as the global definition. This is the one linked to by other files, unless that file happens to have its own definition which then takes precedence. Which definition is chosen is rather arbitrary at this point; probably the first one that got defined. Similarly, if the global definition is deleted, which one is chosen to replace it is completely arbitrary. - - Each symbol also stores a list of references to it. Note that references can be interpreted as multiple symbols, and each of those symbols will store a link back to the reference. In other words, every reference a symbol stores is one that _can_ be interpreted as that symbol, but that is not necessarily the interpretation the reference actually uses. A reference could have a better interpretation it uses instead. - - For example, suppose there are two functions, MyFunction() and MyClass.MyFunction(). The reference text "MyFunction()" appearing in MyClass can be interpreted as either MyClass.MyFunction(), or if that doesn't exist, the global MyFunction(). Both the symbols for MyFunction() and MyClass.MyFunction() will store that it's referenced by the link, even though the class scoped one serves as the actual definition. - - This is also the reason a symbol can exist that has no definitions: it has references. We want symbols to be created in the table for each reference interpretation, even if it doesn't exist. These are called potential symbols. The reason is so we know whether a new symbol definition fulfills an existing reference, since it may be a better interpretation for the reference than what is currently used. - - - - Topic: Reference Storage - _______________________________________________________________________________________________________ - - References are indexed primarily by their , which is actually an elaborate data structure packed into a string. It includes a of the text that appears in the link and a bunch of other data that determines the rules by which the link can be resolved. For example, it includes the scope it appears in and any "using" statements in effect, which are alternate possible scopes. It includes the type of link it is (text links, the ones you explicitly put in comments, aren't the only kind) and resolving flags which encode the language-specific rules of non-text links. But the bottom line is the encodes everything that influences how it may be resolved, so if two links come up with the same rules, they're considered two definitions of the same reference. This is the understanding of the word "reference" that will used in this document. - - Like symbols, each reference stores a list of definitions. However, it only stores the name as all the other relevant information is encoded in the itself. Unlike a symbol, which can be linked to the same no matter what kind of definitions it has, references that are in any way different might be interpreted differently and so need their own distinct entries in the symbol table. - - References also store a list of interpretations. Every possible interpretation of the reference is stored and given a numeric score. The higher the score, the better it suits the reference. In the MyFunction() example from before, MyClass.MyFunction() would have a higher score than just MyFunction() because the local scope should win. Each interpretation has a unique score, there are no duplicates. - - So the symbol and reference data structures are complimentary. Each symbol has a list of every reference that might be interpreted as it, and every reference has a list of each symbol that it could be interpreted as. Again, objects are created for potential symbols (those with references but no definitions) so that this structure always remains intact. - - The interpretation with the highest score which actually exists is deemed the current interpretation of the reference. Unlike symbols where the next global definition is arbitrary, the succession of reference interpretations is very controlled and predictable. - - - Topic: Change Detection - _______________________________________________________________________________________________________ - - Change management is handled a couple of ways. First, there is a secondary file index in that stores which symbols and references are stored in each file. It doesn't have any information other than a list of and since they can be used in the main structures to look up the details. If a file is deleted, the symbol table can then prune any definitions that should no longer be in the table. - - Another way deals with how the information parsing stage works. Files parsed for information just have their symbols and references added to the table regardless of whether this was the first time it was ever parsed or if it had been parsed before. If it had been parsed before, all the information from the previous parse should be in the symbol table and file indexes already. If a new symbol or reference is defined, that's fine, it's added to the table normally. However, if a symbol is redefined it's ignored because only the first definition matters. Also, this won't detect things that disappear. - - Enter watched files. tells to designate a file as watched before it starts parsing it, and then says to analyze the changes when it's done. The watched file is a second index of all the symbols and references that were defined since the watch started, including the specific details on the symbol definitions. When the analysis is done, it compares the list of symbols and references to the one in the main file index. Any that appear in the main file index but not the watched one are deleted because they didn't show up the second time around. Any symbol definitions that are different in the watched file than the main file are changed to the former, since the first definition that appeared the second time around was different than the original. - - - Topic: Change Management - _______________________________________________________________________________________________________ - - When a symbol's global definition changes, either because it switches to another file or because the details of the current file's definition changed (prototype, summary, etc.) it goes through all the references that can be interpreted as that symbol, finds the ones that use it as their current definition, and marks all the files that define them for rebuilding. The links in their output files have to be changed to the new definition or at least have their tooltips updated. - - When a symbol's last definition is deleted, it goes through all the references that can be interpreted as that symbol, finds the ones that use it as their current definition, and has them reinterpreted to the definition with the next highest score. The files that define them are also marked for rebuilding. - - When a potential symbol's first definition is found, it goes through all the references that can be interpreted as it and sees if it can serve as a higher scored interpretation than the current one. If so, the interpretations are changed and all the files that define them are marked for rebuilding. - diff --git a/docs/tool/Info/images/Logo.png b/docs/tool/Info/images/Logo.png deleted file mode 100644 index 1d537c8f780eb9051d1087d0522062c627088033..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11591 zcmV-NEx6K&P)@>AJyoLI@wmw2X|5wAPhct$g)2 z-+XZN@yD(CB><>_0>fH-@eRElc0BFSASfIlgq3L|n5ig?j7GOwuh-bBr(Eth=gKP% zKIWyD?x+$t`T-2N`Q}GVS!t!6uk-!vD*YrF7#WRSXkWDD*HIMt`+KD^*A$z{vMc})WX#c$O#qS7CJP}Oa%-qD!by|0tf5}7efZK#x36{S zrTc!K1`Rt677H%8=A;D|T>EM%o&RaAnY1X=ju?$@;o|0nP7uHa5F7I_`5MDPqX``3 z;g%2#6bZKNpgpt;j^l&t`XHq{NR+h zb4sNdyS13Q8d!{kjFKuKj2AvSY=ACQDcVXd#kCD;*GA0mKn4rQ}7OQ~;VH zx>*H71`rG`u2SfK!$|)pf{Wpn`oB2{4aY`!cv%EUKu{6F8njtPt9AYBuissK_+d-z zi)k6HQh-6ZyVK6+uC&-<8{I2}uts>R)W}o|4b?#mgAn+*9#$bz^*@DyC2g>**cQbY z2-0@&Ym&YuB|!i!85+af7R9b7kgGyHL`RL)kZNdgY^pkZKM$Ulr5r#EQg@M}7y zq?a)eq)nx~luiN#%6Tq;7F_t+Ul-UwYuyq8TAOWDqqa(Ko-c64K!D)cLtkN~ zKt>4g05E|AwHK*i;GyMsmg5BEOlC3yBL+tox&t9nCQJDP1VIt9*-3QHQUsE-? z5Br!27@kSml8AvJ(S=Eq|F&kNRNH0bgsU=4>%bu3V;%%jR7y2~p~CG&%3x0h1cp~E&Yb3Z#eZt04IqqCp5i?1Z`he2SGmndS_*|0eOd~aD+Y`nMQ$hl zAZ;quc4P?~a@ncixjBMHx!eI!J%rAVAE2lEH^}Fw#_(YHrp$nJTW|J?nGmz#x8J_~ z0RU=ta&^6V=UaU)4cdxS)S?yX*At1inD{su{IIPCizdHIQ{>;ppX=3Zzl+~IGw}Y_ zh#*m`RiIk!f^zvcutXJ>TkanS2npM6yB1u3{c~{N{qH94A;@6#7!0$u84MD>o)K*= z5{Oc+XDg-MKVqU?a~kp%OS8Za3J8uLp^EKFh!Fqf*RP-(E098AI$e`yI~PJUJ?+*4 z3$8QIQ%_#{5$0VC4A=JxGgYLAZ=&LDK8c+IOpumQ)d;vm&a0gDg;4+&VS!)s1S&)9tsv4NpAz9qlpOwx0$Ke&-&# z2FD${6g1Omr@sQ7ogrw5Z=S*L;W6W!pK6?s(Jjp|nLSj|WrBl>;`65g&|C$4|9uU1 z*zrOr6(yW>(vAp-0AkS=q3zNZr?4bwK0j^jmJ|vA2OYRH^jDvK_A|Wv@>fu)M)3Ue z-%(Y=l?{VqB2^sO+!VSN*h2Kqk0J%Xb$m-LOTI9TwqpBHVFn2>EUqvlE=C)vH27~& ziR#o_U2y($_)q`(J9%FL7FV*gT@Y*_K$HaH?(Vh;*?a%Et-JemcX#)@Zjp7jxVznr zySqbVaG3u+Z%#dQ&-M;8gnYJ@r!vD#pE`Z2tExylwzb@J6KP2>SS)Y6v0m1$Jw@LQxoxP!cm&Hh zk!#XovRoo_j{yGrUt&F2SqmSntOZxq6fF$A~JjSc3HIOuoRYf z{SMID(FN$U0?Cm5x^;3ePDeRr0H$S2&J=h7QDDQE_~GdWPbAdBpr3*PjAwP33#!ZP z5HBWz1|!{Xzr9k14{s-p8`l#P9(Z7Y{Oxbcuu=r+MkHu0JzUMth%+_*-nAQVG#wU>lBeRe&ZsqI^AZ;+(ws=5qPg zx2_X~ix&&z2S0dL4jsxzCMAUxoNB#v?a~y=B}=+@Z%M_aFltmM89KDJJoC(ISRWU- zqB0BPt&N|l*hY$EWagm6`v@0oJUhqn0)nE&B}K688gZPX2~v8xfddan&>4*nJ*=X% zGd6~+=}uqMo9H@`9UaTc%7oJBC%^mMVz!gyG)_cZtF#QiHNm4t3|=baxBK>;#JBWm z`MFv+Qe#F_h!d^UufVI5nLrl_ej+Ct%aOs(|0b~ZENDTLQ50nkqVmuWQl`;@P!rxJ zO1gS2c}tA5Ya(bdRM2Wr>?~L9%lA(F?+mc|skMB2Lz58<2Jb0A32H$&6hu|y&vEq2u`M8{D|kI=0Haz= zNRqNanl4#`GG+!Kkdndi70M~y8D;}K{vSJbQGWE}Y4Yf!V`Tie!J=^2T?6F6!H?kT zUH~Z##(t)P;M}~HnpPLe_%yRpsi}3D?LwRiF3SVhSc9KP zT6_e!1j)b(U=mkAT&sKhYeZRaA0F{nw~@&hcd5F{a@GYW6odIUUNP4&zdI9(94V zij>w~Q6eln$k*flo{8Fo6d5t1w?;nko_$Bv_`&Ptqyf@6l;ZTR8mEuW_}R^ zt*L3HGInei4F<8kzZUuj3xoYqItqGEfMYY1-9NmKrY+mpbmO@CCa0vs(m0K0FXzev zD+1q{)>ioy@Iusr;C1ftjm5&S zSWuWpImtv&H2xx7`rtX#Yn+4iT#Us#n{g{kS@6zI3nOIvo;9p6K%1y`0)Q(=5+d2Z z_{B8&!yg`%oScTD@P)^&kw5)u0Ve4sk!0>OQ0Dlwtp4hjTzw9|iy?CxF<*6cQc&ib zd3+rV^_LM7pmy%owT|3yLoWzn9iyNrC`l!$QVL;)RilbcuO;ez^d7n|LWKggB#yR; zY8jBG3ZU-8(6#`jN0$RlAQO{7Iv{E2>Rb(8DBp>8orLn8-w82>z!C57 z$3R@5-zjYcjejI2#PhubglC&`meQDXUp7ib89Pyo%vVVV&E*wBD)P6 zrcYmwU4@6(rhosIa{cu^kcFy?x`_)|an~RxUqIp1`&EM%KHo!%uJN@nwp6vsMqG91 z^4X9=<*v;@AjlNG34;fBlowxIL&a~p#3~k9_#yYWjT-JTM&B4DkhNyZq!QufY7xVlYYj*S>u{MCk`h82DS1gBT=F`B7jo z!LxAxZjQDW(Y6q6xfer)35sNtgad?t>9YIpA0{J5b}}+g8Pcy`LyvzHa6AiyxMj?| zfbei~D9?3*+p+^x-p6KP7~>h|I>^Op}cY2K;M5o?drdH%#6R^5m1tQG;@klg(GADkoYU zOXdIY!?}!eeel6Xlncy(>0iV)_uV&C#*E?OLJx3Jt7Ple zV-Ub+QByEgOaNU91p1~XCxm9V+;PV<=-1m}3PWoq%B&;a?!9+9p69Rf@yB}&#ak+) zN4G}-Q(gJ`*Plfyakp{L0^Jf_ZC;?i%5&v&1Pk)Y&~0HZs66I^!C+)*0kapmxlO4oFfLd?Kg8<= zbwOn1%02k(eXUX9d{9}6jd zjAKeI5f2f-3Y~_%2-Bu5Lbc{LG2yn`p#8Jrr4Uiw5-^FImO|w~KCBr$Q)Gb^1_CBw z15r4B{45!b0GS^sOX79Ab{!T4SO*+9r0hsX`>18lwvLVC=Ln`LGVLgSfzeLT_3o*F zz!JA2Yu_0cAckb|l1*X&290f55Jmo3LBevbpq1(9hVuE(_dsfKhU`WK=B!!k^eZUg z_25|n;u@F0i-y(W1$e3bAd>IllUlA+MqC@uKs8Fa^n2uwRU!((^6a2rY68>Z3Q%Z;3M5fPIRSt_dNq}Z5e0;IYyvI{-)uxd+r%1 z04m<)D|V6|1G7LsFbm$F6NTo@Gf4;ifqY+tJK9tLs53bVx`li;Jdf88zHZ)fl*%69 zj|nh(J~KcM0PP~k1?el2etJeW`-(BA#ZdrD#BE^+14~yAwV(&Drdfa~$D`G-d4@sI zGz4OP{p*+EqMQ~JzWk+;2-2`n3gzKNEJ3z{o<<-P-vO!hAt*`OgqoeHU8ZCMz+@H; znG8V;fva*ku4Ryx|Kgdd)#_9Gn7BkASxkmk79tVjY;(@vjWmeORF9)aNeZf7h??3 z&XyfwwdF%TZNph8S{fnc51&IPm4Y69hpI%w2bk=4-__rUQ>^o30`yXZ{3WK4->P`jQh=qA%!+M>TD-m_80Knr8N8+|!M z_d&-kO8)qBEm5slXB)^lWT-Kp*>~>~?4YM1%;7oV8UkzZE5YaJs=8g+B8PMrzvw9IHzVOxJ`!RC90sr_7@RCS zc3crJtbWyOmP8`NMl9N~%9v?U8L94aWTa}ttw_;T9&v_pC|PDesOa?+G4PUwd5}$* z==pTn+P7~e0Aw-h%Z3dnL04$4_<$JFE_=@Y&tIZ35`?)AkHlL~nrwjli^EVP`Kk-V7)Bv~v`POE<7AF-pJq_gCpQ(_C#ua6%^75UZebqe%=yPf%#T?88@OT*p`1BcedhPMTE4f{gY}n zpH>YS)p};iETj+P=hQPjQwV0;Ldni+{(bzReu`lo)o z%}Tfb3GK{$dLU5d*B-os2!9KlV4Nii-~H|lNLxNh0kKyq6x*d{R?Wd(h#trLR>w}%yyg*`GKLSe-*))HHhWt`8i$|A?eznQEJ zte~d~#?{Bj_oQp0?gR^>%F9#ar$2oj#YsU?$jNB{hTYE7qKpkmM6K@3$cTfo7^@S6 zntRTijh6XtZK1E47ZKbB=d-X)bUb#M<7(==@Kaqr3&9^+ZT0IXqn_aQE98ak8q}2R zh*-R`AToayS?;b?v#>_Hhyn2ZH~Kz*g0A}3R{HexK;(PaO4D*>9PSj9RTEzxwPr|V zQ^!;>yzHAU3*%5Y?vTOjx8GiiBCtQ>T#&~R*E?le8>qc$$F#Q|#2mx?Q@%xcohz*x z(v%p}m414%=2NS@xt$7irr2P-F~x<`gSgx7@ZpOnG@333K2*@5QAsLdK3#Eu?Xy z{e27=9tn@oR?7}h*T5g7O^2mXAC+$VVMf0pEo3h8FA{KapqA8#t&f`CjVPeRvC*At(47SVGKclIEZ5 zQAn8`jx=iDe$51(-?qXp8k8#Mc*tGpS>ZHK zG$2*8sP~MNjR;wh}{(di<@j6Tt-hFoo+^$WO9o_J!sp-PPas+voivqGm ze$7dV`K-phygG}fYNa7dw*vPKsXK={jvc0Kpag#?<$AM^zZp_{*Q)li^0V8Qj3_x$U!=uj_=|(wMLO#LwWd&LmFO|URBhWf zhk|gqGB60d1iXkHrwujtZmrtny)`EK{u4Wkt>-q7yv3`vw_;>&AMi51dc086*G~Uf z_lg01-s-iVu*m#AddNQdNWMuSvOfjEbMWVDAyzd8N_TLjvUq0+eiGq5R1arDcGBqH z!hO)goalzV_Uck?4*vH=JJh83m96S7z@_uYxB$C=2Z>J9*I!!(8mT}QzY%B5m}|t? z>O&cfL;vzn5t`5b`r{3}Aek8e6$5dsjGDLK{BHAuGmjotD^;{3P$*3k6>(`T#Mg2eo;sP|ou)@-;gvsZ) zC#x#B*C7${3~W>b%>edIJZl9(X(aQXCeLdjU%l5Dz=ra@?_Dn$nepBayl`X9xba=& zZ-0M~W$30knVbRzGqOEmAUQNCX}*O>6Q*ar)%LEtN03&ngktPV7%V9P7L=(=#Uh@{ z)6s_@AlFF>AV5I$MdZHw2g`T9Gg*H4!>7WJcBhHV?b3YDzlo)m^+YRxp8@f`%|{Ng z%?liy+(^C~120D8wu4L4m}5mV+qPJEFODD0Z<@zd$W8@OpNWNIz$~OG0fs_uAzixW zkXONiJm5LG6eLRb9`$6@=r;1JUr&-h{_%FK(yfKS4PI~IS)eRZ>tQ@H>2k&CA;3Il zFp-~~Jy(otU)8t+enMfWcgPI)h3Nhcyys`AfdCKMQdxZKTTkKI67GSze6SBIMCJ9@ zm&4stS4Y_XcfY?ydh~37KA+_?#KjlM=rQf(@Bg@s^%{>qK3|j{4fLo1?pMi$#ncD= zE#UJPVfXUnDSZ+AzelvXcjl}OdMFUxi)iO1=A*hAcooOkPzN|&68?x0uw|Dn6YlQU z@2>B=f5=sH{jt_#Xo`~u&A=2aM8tPEwoiBSE8=#8Ve>HY<5@Oqn#eY7_5WFl3jxpL zp&tVWwnCclVL#3K99Gdwj4t-Xnt&f+juAV#bUFn1LflTYdC6;PZL zX|+`o;DRhA-_D#V^!Na*LvtRhzjbI4x1m#x@+nJ$2DODXa3dAuh7J3X(%gUphEI}* z4H~3SS&SOh9rAS)<=SuIoRV{-j}$1~5h!oE6TzTY02Tx3nU_#`TEQP^PDzRFywZY#v%oyc6*4iJX8p9%3Ty_Q`s=M* z-+vKr4;Tt#{M~)~-bsZKwbF>{_a~Se$F|%_EOhxaz~sQ>+(qVD!sbvu7#uz@1{=QO z5GbJuNIOjjBlGF6Vsg=H!S@_Q2m}UwFwQpUtc5z*NVHTw`e;3r)kSVC9y6v71oln= z(3L^K7*>lsUnqDU1(hC-G(+UN0_PHp!r=B5g=e3g1A*N@0o7_g^nv}%%oMB^!%&ue zjVM6)AT-;!DnS{s4+|ImS;7GEnr$f3Sw~^$)TusA??|wD^HKTz?-%KQ0bf}cC@&z$ z&A^MHJQguZUO+)EKy>~z0)9CV^4sLo09&##@!s`?mx{m2h2-wLd&BDLD6s<-CEWm3 zuox!>3NZ#mOb8=(L3!1C`${9|Ei8CtY7%2K0t%}s4$!gEvfQTwmkvByXWav@#=%5I zpv71U717Y49qB%3!C|GG%*Nv2orZpf$^u9lmrL}i#OT_N9orAr_fiF_*)41X*oAqr zo(n9L7E8+^Z<;cW^1$emoI_AFP&f@DC<{G6Xc`p82e!iK+i<7)XJKT?4TRyE+J~k9HU(1vj>8VgnK%Gb7G`D_7>}7r-~IJfO>gP+ zmgjIsQmfS@X=eJ@EoLdth2*slV2?-{bunaUE>~Oj-^j)l17%H)?1O`v#1@Z>{WVpA6dM7Ugg#Xe_qqI6&6usRc3ZivVVBj~jw1W5s7;pV70)gNMcT z%-JM2|K*tpiHZcBirblgN)Y+{ix1xa;fGJ32aJWKO=0(N#(GGrY1ffmF7E9N8g>>& zlIy@T2=Ol{R?!H7S6vmrcQAM{2B?DYKld2oE~e;_()K;gLF& z>&WmRE=QKY>(_XuGc)kqhbMTXuCnaO0!#=Dd$DZ6n&s>cSqKnBIXuuG+YUj6p-KPB zOC3(5Es1z2zB+Gp8SDD-tFzC`E8y*ct0d!@jHOJ4bEK#4mzz`iTTYQ5ygTOJ5t!*~ zX-E zoWLLOi~>HHL{nnZPHq#iLE;Oa7hb;n`$dJ-OG0^Cf<*aw5I7=CL2Z}I$t7I-)L3(ji+PF=c8QZMKoTE0H-$|<~R z_ac)=2h`DCdcI=YJ|E-bmVNCXdQ<3AJU9=R*r3u37?0bLYS-GsvD^ zq>1-+(85?rH`mxTTg`ein8RT92w&LBUxA$`C+W~ z-Pa>S7zKUX>99J(;gi;;j(i;d;cZA-an{IH2d%bN`WQN?K{*(xOKCY?ZA4n~>ZPBk zgWA3xFL20UA-@I;^!}*nJ>bFS!c=@*=}kQUx=m~#M$7{SYwLTLF8%uF{{Gu<)K1El zq|98^I7cfD1$DSYq{Cko**tBT8Tsw2kiNWvhW)Be>l1IX^NG)H?Df}K8M#>2ljDZv}}J8KdE(m5YLv6?b5AV|B4yQ zz0M>w0SNpzvEf;JXR+PP5k%q4&&CTL|GrC?X8(w%yC!eY4*26)B;W)2DwWh# z$Zm%u3$0zV`3=8GW#-L>mH}QPvqT*9<)+fL<;*g%EDG$Zs>K`V5ji))NPu8(Z&}U7 zi*LV$x{Xb|r(E#S4E`AK(JYpZD%3RcRWcSLUmzU~|)VrPr=~@Z6qiad6_*1^1`^E-r+;i?n!vcmX{j zN{^T}3le>&;t5t78$T; zwv}xf>%net6r2FZ!6C2{Yys;wZ{EKNg)*%A@~CvW&0(6o@$J{BGDy436DkoTGF$@O4AdMmnk|6u% z2O1b{&^R`NZD0%8K*Lx?bIDJsRH`h<&@f^kL;@fRlKj8 0 && number == ids[0]) - { ids.shift(); } - else - { - document.getElementById("MGroupContent" + number).style.display = "none"; - }; - - number++; - }; - }; - } - - -// -// Tooltips -// ____________________________________________________________________________ - - -var tooltipTimer = 0; - -function ShowTip(event, tooltipID, linkID) - { - if (tooltipTimer) - { clearTimeout(tooltipTimer); }; - - var docX = event.clientX + window.pageXOffset; - var docY = event.clientY + window.pageYOffset; - - var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")"; - - tooltipTimer = setTimeout(showCommand, 1000); - } - -function ReallyShowTip(tooltipID, linkID, docX, docY) - { - tooltipTimer = 0; - - var tooltip; - var link; - - if (document.getElementById) - { - tooltip = document.getElementById(tooltipID); - link = document.getElementById(linkID); - } -/* else if (document.all) - { - tooltip = eval("document.all['" + tooltipID + "']"); - link = eval("document.all['" + linkID + "']"); - } -*/ - if (tooltip) - { - var left = GetXPosition(link); - var top = GetYPosition(link); - top += link.offsetHeight; - - - // The fallback method is to use the mouse X and Y relative to the document. We use a separate if and test if its a number - // in case some browser snuck through the above if statement but didn't support everything. - - if (!isFinite(top) || top == 0) - { - left = docX; - top = docY; - } - - // Some spacing to get it out from under the cursor. - - top += 10; - - // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the - // page. We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right. - - if (tooltip.offsetWidth != null) - { - var width = tooltip.offsetWidth; - var docWidth = document.body.clientWidth; - - if (left + width > docWidth) - { left = docWidth - width - 1; } - - // If there's a horizontal scroll bar we could go past zero because it's using the page width, not the window width. - if (left < 0) - { left = 0; }; - } - - MoveToPosition(tooltip, left, top); - tooltip.style.visibility = "visible"; - } - } - -function HideTip(tooltipID) - { - if (tooltipTimer) - { - clearTimeout(tooltipTimer); - tooltipTimer = 0; - } - - var tooltip; - - if (document.getElementById) - { tooltip = document.getElementById(tooltipID); } - else if (document.all) - { tooltip = eval("document.all['" + tooltipID + "']"); } - - if (tooltip) - { tooltip.style.visibility = "hidden"; } - } - - -// -// Blockquote fix for IE -// ____________________________________________________________________________ - - -function NDOnLoad() - { - if (browserVer == "IE6") - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - if (scrollboxes.item(0)) - { - NDDoResize(); - window.onresize=NDOnResize; - }; - }; - }; - - -var resizeTimer = 0; - -function NDOnResize() - { - if (resizeTimer != 0) - { clearTimeout(resizeTimer); }; - - resizeTimer = setTimeout(NDDoResize, 250); - }; - - -function NDDoResize() - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - var i; - var item; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = 100; - i++; - }; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = item.parentNode.offsetWidth; - i++; - }; - - clearTimeout(resizeTimer); - resizeTimer = 0; - } - - - -/* ________________________________________________________________________________________________________ - - Class: SearchPanel - ________________________________________________________________________________________________________ - - A class handling everything associated with the search panel. - - Parameters: - - name - The name of the global variable that will be storing this instance. Is needed to be able to set timeouts. - mode - The mode the search is going to work in. Pass CommandLineOption()>, so the - value will be something like "HTML" or "FramedHTML". - - ________________________________________________________________________________________________________ -*/ - - -function SearchPanel(name, mode, resultsPath) - { - if (!name || !mode || !resultsPath) - { alert("Incorrect parameters to SearchPanel."); }; - - - // Group: Variables - // ________________________________________________________________________ - - /* - var: name - The name of the global variable that will be storing this instance of the class. - */ - this.name = name; - - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: resultsPath - The relative path from the current HTML page to the results page directory. - */ - this.resultsPath = resultsPath; - - /* - var: keyTimeout - The timeout used between a keystroke and when a search is performed. - */ - this.keyTimeout = 0; - - /* - var: keyTimeoutLength - The length of in thousandths of a second. - */ - this.keyTimeoutLength = 500; - - /* - var: lastSearchValue - The last search string executed, or an empty string if none. - */ - this.lastSearchValue = ""; - - /* - var: lastResultsPage - The last results page. The value is only relevant if is set. - */ - this.lastResultsPage = ""; - - /* - var: deactivateTimeout - - The timeout used between when a control is deactivated and when the entire panel is deactivated. Is necessary - because a control may be deactivated in favor of another control in the same panel, in which case it should stay - active. - */ - this.deactivateTimout = 0; - - /* - var: deactivateTimeoutLength - The length of in thousandths of a second. - */ - this.deactivateTimeoutLength = 200; - - - - - // Group: DOM Elements - // ________________________________________________________________________ - - - // Function: DOMSearchField - this.DOMSearchField = function() - { return document.getElementById("MSearchField"); }; - - // Function: DOMSearchType - this.DOMSearchType = function() - { return document.getElementById("MSearchType"); }; - - // Function: DOMPopupSearchResults - this.DOMPopupSearchResults = function() - { return document.getElementById("MSearchResults"); }; - - // Function: DOMPopupSearchResultsWindow - this.DOMPopupSearchResultsWindow = function() - { return document.getElementById("MSearchResultsWindow"); }; - - // Function: DOMSearchPanel - this.DOMSearchPanel = function() - { return document.getElementById("MSearchPanel"); }; - - - - - // Group: Event Handlers - // ________________________________________________________________________ - - - /* - Function: OnSearchFieldFocus - Called when focus is added or removed from the search field. - */ - this.OnSearchFieldFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchFieldChange - Called when the content of the search field is changed. - */ - this.OnSearchFieldChange = function() - { - if (this.keyTimeout) - { - clearTimeout(this.keyTimeout); - this.keyTimeout = 0; - }; - - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != this.lastSearchValue) - { - if (searchValue != "") - { - this.keyTimeout = setTimeout(this.name + ".Search()", this.keyTimeoutLength); - } - else - { - if (this.mode == "HTML") - { this.DOMPopupSearchResultsWindow().style.display = "none"; }; - this.lastSearchValue = ""; - }; - }; - }; - - - /* - Function: OnSearchTypeFocus - Called when focus is added or removed from the search type. - */ - this.OnSearchTypeFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchTypeChange - Called when the search type is changed. - */ - this.OnSearchTypeChange = function() - { - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != "") - { - this.Search(); - }; - }; - - - - // Group: Action Functions - // ________________________________________________________________________ - - - /* - Function: CloseResultsWindow - Closes the results window. - */ - this.CloseResultsWindow = function() - { - this.DOMPopupSearchResultsWindow().style.display = "none"; - this.Activate(false, true); - }; - - - /* - Function: Search - Performs a search. - */ - this.Search = function() - { - this.keyTimeout = 0; - - var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); - var searchTopic = this.DOMSearchType().value; - - var pageExtension = searchValue.substr(0,1); - - if (pageExtension.match(/^[a-z]/i)) - { pageExtension = pageExtension.toUpperCase(); } - else if (pageExtension.match(/^[0-9]/)) - { pageExtension = 'Numbers'; } - else - { pageExtension = "Symbols"; }; - - var resultsPage; - var resultsPageWithSearch; - var hasResultsPage; - - // indexSectionsWithContent is defined in searchdata.js - if (indexSectionsWithContent[searchTopic][pageExtension] == true) - { - resultsPage = this.resultsPath + '/' + searchTopic + pageExtension + '.html'; - resultsPageWithSearch = resultsPage+'?'+escape(searchValue); - hasResultsPage = true; - } - else - { - resultsPage = this.resultsPath + '/NoResults.html'; - resultsPageWithSearch = resultsPage; - hasResultsPage = false; - }; - - var resultsFrame; - if (this.mode == "HTML") - { resultsFrame = window.frames.MSearchResults; } - else if (this.mode == "FramedHTML") - { resultsFrame = window.top.frames['Content']; }; - - - if (resultsPage != this.lastResultsPage || - - // Bug in IE. If everything becomes hidden in a run, none of them will be able to be reshown in the next for some - // reason. It counts the right number of results, and you can even read the display as "block" after setting it, but it - // just doesn't work in IE 6 or IE 7. So if we're on the right page but the previous search had no results, reload the - // page anyway to get around the bug. - (browserType == "IE" && hasResultsPage && - (!resultsFrame.searchResults || resultsFrame.searchResults.lastMatchCount == 0)) ) - - { - resultsFrame.location.href = resultsPageWithSearch; - } - - // So if the results page is right and there's no IE bug, reperform the search on the existing page. We have to check if there - // are results because NoResults.html doesn't have any JavaScript, and it would be useless to do anything on that page even - // if it did. - else if (hasResultsPage) - { - // We need to check if this exists in case the frame is present but didn't finish loading. - if (resultsFrame.searchResults) - { resultsFrame.searchResults.Search(searchValue); } - - // Otherwise just reload instead of waiting. - else - { resultsFrame.location.href = resultsPageWithSearch; }; - }; - - - var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); - - if (this.mode == "HTML" && domPopupSearchResultsWindow.style.display != "block") - { - var domSearchType = this.DOMSearchType(); - - var left = GetXPosition(domSearchType); - var top = GetYPosition(domSearchType) + domSearchType.offsetHeight; - - MoveToPosition(domPopupSearchResultsWindow, left, top); - domPopupSearchResultsWindow.style.display = 'block'; - }; - - - this.lastSearchValue = searchValue; - this.lastResultsPage = resultsPage; - }; - - - - // Group: Activation Functions - // Functions that handle whether the entire panel is active or not. - // ________________________________________________________________________ - - - /* - Function: Activate - - Activates or deactivates the search panel, resetting things to their default values if necessary. You can call this on every - control's OnBlur() and it will handle not deactivating the entire panel when focus is just switching between them transparently. - - Parameters: - - isActive - Whether you're activating or deactivating the panel. - ignoreDeactivateDelay - Set if you're positive the action will deactivate the panel and thus want to skip the delay. - */ - this.Activate = function(isActive, ignoreDeactivateDelay) - { - // We want to ignore isActive being false while the results window is open. - if (isActive || (this.mode == "HTML" && this.DOMPopupSearchResultsWindow().style.display == "block")) - { - if (this.inactivateTimeout) - { - clearTimeout(this.inactivateTimeout); - this.inactivateTimeout = 0; - }; - - this.DOMSearchPanel().className = 'MSearchPanelActive'; - - var searchField = this.DOMSearchField(); - - if (searchField.value == 'Search') - { searchField.value = ""; } - } - else if (!ignoreDeactivateDelay) - { - this.inactivateTimeout = setTimeout(this.name + ".InactivateAfterTimeout()", this.inactivateTimeoutLength); - } - else - { - this.InactivateAfterTimeout(); - }; - }; - - - /* - Function: InactivateAfterTimeout - - Called by , which is set by . Inactivation occurs on a timeout because a control may - receive OnBlur() when focus is really transferring to another control in the search panel. In this case we don't want to - actually deactivate the panel because not only would that cause a visible flicker but it could also reset the search value. - So by doing it on a timeout instead, there's a short period where the second control's OnFocus() can cancel the deactivation. - */ - this.InactivateAfterTimeout = function() - { - this.inactivateTimeout = 0; - - this.DOMSearchPanel().className = 'MSearchPanelInactive'; - this.DOMSearchField().value = "Search"; - - this.lastSearchValue = ""; - this.lastResultsPage = ""; - }; - }; - - - - -/* ________________________________________________________________________________________________________ - - Class: SearchResults - _________________________________________________________________________________________________________ - - The class that handles everything on the search results page. - _________________________________________________________________________________________________________ -*/ - - -function SearchResults(name, mode) - { - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: lastMatchCount - The number of matches from the last run of . - */ - this.lastMatchCount = 0; - - - /* - Function: Toggle - Toggles the visibility of the passed element ID. - */ - this.Toggle = function(id) - { - if (this.mode == "FramedHTML") - { return; }; - - var parentElement = document.getElementById(id); - - var element = parentElement.firstChild; - - while (element && element != parentElement) - { - if (element.nodeName == 'DIV' && element.className == 'ISubIndex') - { - if (element.style.display == 'block') - { element.style.display = "none"; } - else - { element.style.display = 'block'; } - }; - - if (element.nodeName == 'DIV' && element.hasChildNodes()) - { element = element.firstChild; } - else if (element.nextSibling) - { element = element.nextSibling; } - else - { - do - { - element = element.parentNode; - } - while (element && element != parentElement && !element.nextSibling); - - if (element && element != parentElement) - { element = element.nextSibling; }; - }; - }; - }; - - - /* - Function: Search - - Searches for the passed string. If there is no parameter, it takes it from the URL query. - - Always returns true, since other documents may try to call it and that may or may not be possible. - */ - this.Search = function(search) - { - if (!search) - { - search = window.location.search; - search = search.substring(1); // Remove the leading ? - search = unescape(search); - }; - - search = search.replace(/^ +/, ""); - search = search.replace(/ +$/, ""); - search = search.toLowerCase(); - - if (search.match(/[^a-z0-9]/)) // Just a little speedup so it doesn't have to go through the below unnecessarily. - { - search = search.replace(/\_/g, "_und"); - search = search.replace(/\ +/gi, "_spc"); - search = search.replace(/\~/g, "_til"); - search = search.replace(/\!/g, "_exc"); - search = search.replace(/\@/g, "_att"); - search = search.replace(/\#/g, "_num"); - search = search.replace(/\$/g, "_dol"); - search = search.replace(/\%/g, "_pct"); - search = search.replace(/\^/g, "_car"); - search = search.replace(/\&/g, "_amp"); - search = search.replace(/\*/g, "_ast"); - search = search.replace(/\(/g, "_lpa"); - search = search.replace(/\)/g, "_rpa"); - search = search.replace(/\-/g, "_min"); - search = search.replace(/\+/g, "_plu"); - search = search.replace(/\=/g, "_equ"); - search = search.replace(/\{/g, "_lbc"); - search = search.replace(/\}/g, "_rbc"); - search = search.replace(/\[/g, "_lbk"); - search = search.replace(/\]/g, "_rbk"); - search = search.replace(/\:/g, "_col"); - search = search.replace(/\;/g, "_sco"); - search = search.replace(/\"/g, "_quo"); - search = search.replace(/\'/g, "_apo"); - search = search.replace(/\/g, "_ran"); - search = search.replace(/\,/g, "_com"); - search = search.replace(/\./g, "_per"); - search = search.replace(/\?/g, "_que"); - search = search.replace(/\//g, "_sla"); - search = search.replace(/[^a-z0-9\_]i/gi, "_zzz"); - }; - - var resultRows = document.getElementsByTagName("div"); - var matches = 0; - - var i = 0; - while (i < resultRows.length) - { - var row = resultRows.item(i); - - if (row.className == "SRResult") - { - var rowMatchName = row.id.toLowerCase(); - rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); - - if (search.length <= rowMatchName.length && rowMatchName.substr(0, search.length) == search) - { - row.style.display = "block"; - matches++; - } - else - { row.style.display = "none"; }; - }; - - i++; - }; - - document.getElementById("Searching").style.display="none"; - - if (matches == 0) - { document.getElementById("NoMatches").style.display="block"; } - else - { document.getElementById("NoMatches").style.display="none"; } - - this.lastMatchCount = matches; - - return true; - }; - }; - diff --git a/docs/tool/License-GPL.txt b/docs/tool/License-GPL.txt deleted file mode 100644 index e539652a0..000000000 --- a/docs/tool/License-GPL.txt +++ /dev/null @@ -1,341 +0,0 @@ -File: GNU General Public Licence - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - - -Topic: Preamble - -The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - -When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - -To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - -We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - -Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - -Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and -modification follow. - - -Topic: Terms and Conditions for Copying, Distribution, and Modification - -0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - -a) You must cause the modified files to carry prominent notices -stating that you changed the files and the date of any change. - -b) You must cause any work that you distribute or publish, that in -whole or in part contains or is derived from the Program or any -part thereof, to be licensed as a whole at no charge to all third -parties under the terms of this License. - -c) If the modified program normally reads commands interactively -when run, you must cause it, when started running for such -interactive use in the most ordinary way, to print or display an -announcement including an appropriate copyright notice and a -notice that there is no warranty (or else, saying that you provide -a warranty) and that users may redistribute the program under -these conditions, and telling the user how to view a copy of this -License. (Exception: if the Program itself is interactive but -does not normally print such an announcement, your work based on -the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - -3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - -a) Accompany it with the complete corresponding machine-readable -source code, which must be distributed under the terms of Sections -1 and 2 above on a medium customarily used for software interchange; or, - -b) Accompany it with a written offer, valid for at least three -years, to give any third party, for a charge no more than your -cost of physically performing source distribution, a complete -machine-readable copy of the corresponding source code, to be -distributed under the terms of Sections 1 and 2 above on a medium -customarily used for software interchange; or, - -c) Accompany it with the information you received as to the offer -to distribute corresponding source code. (This alternative is -allowed only for noncommercial distribution and only if you -received the program in object code or executable form with such -an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - -5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - -10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - -NO WARRANTY: - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - -Topic: How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - -Copyright (C) - -This program 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 2 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, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - -Gnomovision version 69, Copyright (C) year name of author -Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -This is free software, and you are welcome to redistribute it -under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in the program -`Gnomovision' (which makes passes at compilers) written by James Hacker. - -, 1 April 1989 -Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/docs/tool/Modules/NaturalDocs/BinaryFile.pm b/docs/tool/Modules/NaturalDocs/BinaryFile.pm deleted file mode 100644 index 5c1adb8d3..000000000 --- a/docs/tool/Modules/NaturalDocs/BinaryFile.pm +++ /dev/null @@ -1,294 +0,0 @@ -############################################################################### -# -# Package: NaturalDocs::BinaryFile -# -############################################################################### -# -# A package to manage Natural Docs' binary data files. -# -# Usage: -# -# - Only one data file can be managed with this package at a time. You must close the file before opening another -# one. -# -############################################################################### - -# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -# Natural Docs is licensed under the GPL - -use strict; -use integer; - -package NaturalDocs::BinaryFile; - -use vars qw(@EXPORT @ISA); -require Exporter; -@ISA = qw(Exporter); - -@EXPORT = ('BINARY_FORMAT'); - - -############################################################################### -# Group: Format - -# -# Topic: Standard Header -# -# > [UInt8: BINARY_FORMAT] -# > [VersionInt: app version] -# -# The first byte is , which distinguishes binary configuration files from text ones, since Natural Docs -# used to use text data files with the same name. -# -# The next section is the version of Natural Docs that wrote the file, as defined by AppVersion> -# and written by ToBinaryFile()>. -# - -# -# Topic: Data Types -# -# All the integer data types are written most significant byte first, aka big endian. -# -# An AString16 is a UInt16 followed by that many 8-bit ASCII characters. It doesn't include a null character at the end. Undef -# strings are represented by a zero for the UInt16 and nothing following it. -# - -# -# Constant: BINARY_FORMAT -# -# An 8-bit constant that's used as the first byte of binary data files. This is used so that you can easily distinguish between -# binary and old-style text data files. It's not a character that would appear in plain text files. -# -use constant BINARY_FORMAT => pack('C', 0x06); -# Which is ACK or acknowledge in ASCII. Is the cool spade character in DOS displays. - - -############################################################################### -# Group: Variables - -# -# handle: FH_BINARYDATAFILE -# -# The file handle used for the data file. -# - - -# -# string: currentFile -# -# The for the current configuration file being parsed. -# -my $currentFile; - - - -############################################################################### -# Group: File Functions - - -# -# Function: OpenForReading -# -# Opens a binary file for reading. -# -# Parameters: -# -# minimumVersion - The minimum version of the file format that is acceptible. May be undef. -# -# Returns: -# -# The format or undef if it failed. It could fail for any of the following reasons. -# -# - The file doesn't exist. -# - The file couldn't be opened. -# - The file didn't have the proper header. -# - Either the application or the file was from a development release, and they're not the exact same development release. -# - The file's format was less than the minimum version, if one was defined. -# - The file was from a later application version than the current. -# -sub OpenForReading #(FileName file, optional VersionInt minimumVersion) => VersionInt - { - my ($self, $file, $minimumVersion) = @_; - - if (defined $currentFile) - { die "Tried to open binary file " . $file . " for reading when " . $currentFile . " was already open."; }; - - $currentFile = $file; - - if (open(FH_BINARYDATAFILE, '<' . $currentFile)) - { - # See if it's binary. - binmode(FH_BINARYDATAFILE); - - my $firstChar; - read(FH_BINARYDATAFILE, $firstChar, 1); - - if ($firstChar == ::BINARY_FORMAT()) - { - my $version = NaturalDocs::Version->FromBinaryFile(\*FH_BINARYDATAFILE); - - if (NaturalDocs::Version->CheckFileFormat($version, $minimumVersion)) - { return $version; }; - }; - - close(FH_BINARYDATAFILE); - }; - - $currentFile = undef; - return undef; - }; - - -# -# Function: OpenForWriting -# -# Opens a binary file for writing and writes the standard header. Dies if the file cannot be opened. -# -sub OpenForWriting #(FileName file) - { - my ($self, $file) = @_; - - if (defined $currentFile) - { die "Tried to open binary file " . $file . " for writing when " . $currentFile . " was already open."; }; - - $currentFile = $file; - - open (FH_BINARYDATAFILE, '>' . $currentFile) - or die "Couldn't save " . $file . ".\n"; - - binmode(FH_BINARYDATAFILE); - - print FH_BINARYDATAFILE '' . ::BINARY_FORMAT(); - NaturalDocs::Version->ToBinaryFile(\*FH_BINARYDATAFILE, NaturalDocs::Settings->AppVersion()); - }; - - -# -# Function: Close -# -# Closes the current configuration file. -# -sub Close - { - my $self = shift; - - if (!$currentFile) - { die "Tried to close a binary file when one wasn't open."; }; - - close(FH_BINARYDATAFILE); - $currentFile = undef; - }; - - - -############################################################################### -# Group: Reading Functions - - -# -# Function: GetUInt8 -# Reads and returns a UInt8 from the open file. -# -sub GetUInt8 # => UInt8 - { - my $raw; - read(FH_BINARYDATAFILE, $raw, 1); - - return unpack('C', $raw); - }; - -# -# Function: GetUInt16 -# Reads and returns a UInt16 from the open file. -# -sub GetUInt16 # => UInt16 - { - my $raw; - read(FH_BINARYDATAFILE, $raw, 2); - - return unpack('n', $raw); - }; - -# -# Function: GetUInt32 -# Reads and returns a UInt32 from the open file. -# -sub GetUInt32 # => UInt32 - { - my $raw; - read(FH_BINARYDATAFILE, $raw, 4); - - return unpack('N', $raw); - }; - -# -# Function: GetAString16 -# Reads and returns an AString16 from the open file. Supports undef strings. -# -sub GetAString16 # => string - { - my $rawLength; - read(FH_BINARYDATAFILE, $rawLength, 2); - my $length = unpack('n', $rawLength); - - if (!$length) - { return undef; }; - - my $string; - read(FH_BINARYDATAFILE, $string, $length); - - return $string; - }; - - - -############################################################################### -# Group: Writing Functions - - -# -# Function: WriteUInt8 -# Writes a UInt8 to the open file. -# -sub WriteUInt8 #(UInt8 value) - { - my ($self, $value) = @_; - print FH_BINARYDATAFILE pack('C', $value); - }; - -# -# Function: WriteUInt16 -# Writes a UInt32 to the open file. -# -sub WriteUInt16 #(UInt16 value) - { - my ($self, $value) = @_; - print FH_BINARYDATAFILE pack('n', $value); - }; - -# -# Function: WriteUInt32 -# Writes a UInt32 to the open file. -# -sub WriteUInt32 #(UInt32 value) - { - my ($self, $value) = @_; - print FH_BINARYDATAFILE pack('N', $value); - }; - -# -# Function: WriteAString16 -# Writes an AString16 to the open file. Supports undef strings. -# -sub WriteAString16 #(string value) - { - my ($self, $string) = @_; - - if (length($string)) - { print FH_BINARYDATAFILE pack('nA*', length($string), $string); } - else - { print FH_BINARYDATAFILE pack('n', 0); }; - }; - - -1; diff --git a/docs/tool/Modules/NaturalDocs/Builder.pm b/docs/tool/Modules/NaturalDocs/Builder.pm deleted file mode 100644 index cdcdff72d..000000000 --- a/docs/tool/Modules/NaturalDocs/Builder.pm +++ /dev/null @@ -1,280 +0,0 @@ -############################################################################### -# -# Package: NaturalDocs::Builder -# -############################################################################### -# -# A package that takes parsed source file and builds the output for it. -# -# Usage and Dependencies: -# -# - can be called immediately. -# - and can be called once all sub-packages have been registered via . -# Since this is normally done in their INIT functions, they should be available to all normal functions immediately. -# -# - Prior to calling , , , , and -# must be initialized. GenerateDirectoryNames()> must be called. -# and must be initialized and fully resolved. -# -############################################################################### - -# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -# Natural Docs is licensed under the GPL - - -use strict; -use integer; - -use NaturalDocs::Builder::Base; -use NaturalDocs::Builder::HTML; -use NaturalDocs::Builder::FramedHTML; - -package NaturalDocs::Builder; - - -############################################################################### -# Group: Variables - -# -# Array: outputPackages -# -# An array of the output packages available for use. -# -my @outputPackages; - - -############################################################################### -# Group: Functions - - -# -# Function: OutputPackages -# -# Returns an arrayref of the output packages available for use. The arrayref is not a copy of the data, so don't change it. -# -# Add output packages to this list with the function. -# -sub OutputPackages - { return \@outputPackages; }; - - -# -# Function: OutputPackageOf -# -# Returns the output package corresponding to the passed command line option, or undef if none. -# -sub OutputPackageOf #(commandLineOption) - { - my ($self, $commandLineOption) = @_; - - $commandLineOption = lc($commandLineOption); - - foreach my $package (@outputPackages) - { - if (lc($package->CommandLineOption()) eq $commandLineOption) - { return $package; }; - }; - - return undef; - }; - - - -# -# Function: Add -# -# Adds an output package to those available for use. All output packages must call this function in order to be recognized. -# -# Parameters: -# -# package - The package name. -# -sub Add #(package) - { - my ($self, $package) = @_; - - # Output packages shouldn't register themselves more than once, so we don't need to check for it. - push @outputPackages, $package; - }; - - -# -# Function: Run -# -# Runs the build process. This must be called *every time* Natural Docs is run, regardless of whether any source files changed -# or not. Some output packages have dependencies on files outside of the source tree that need to be checked. -# -# Since there are multiple stages to the build process, this function will handle its own status messages. There's no need to print -# "Building files..." or something similar beforehand. -# -sub Run - { - my ($self) = @_; - - - # Determine what we're doing. - - my $buildTargets = NaturalDocs::Settings->BuildTargets(); - - my $filesToBuild = NaturalDocs::Project->FilesToBuild(); - my $numberOfFilesToBuild = (scalar keys %$filesToBuild) * (scalar @$buildTargets); - - my $filesToPurge = NaturalDocs::Project->FilesToPurge(); - my $numberOfFilesToPurge = (scalar keys %$filesToPurge) * (scalar @$buildTargets); - - my $imagesToUpdate = NaturalDocs::Project->ImageFilesToUpdate(); - my $numberOfImagesToUpdate = (scalar keys %$imagesToUpdate) * (scalar @$buildTargets); - - my $imagesToPurge = NaturalDocs::Project->ImageFilesToPurge(); - my $numberOfImagesToPurge = (scalar keys %$imagesToPurge) * (scalar @$buildTargets); - - my %indexesToBuild; - my %indexesToPurge; - - my $currentIndexes = NaturalDocs::Menu->Indexes(); - my $previousIndexes = NaturalDocs::Menu->PreviousIndexes(); - - foreach my $index (keys %$currentIndexes) - { - if (NaturalDocs::SymbolTable->IndexChanged($index) || !exists $previousIndexes->{$index}) - { - $indexesToBuild{$index} = 1; - }; - }; - - # All indexes that still exist should have been deleted. - foreach my $index (keys %$previousIndexes) - { - if (!exists $currentIndexes->{$index}) - { - $indexesToPurge{$index} = 1; - }; - }; - - my $numberOfIndexesToBuild = (scalar keys %indexesToBuild) * (scalar @$buildTargets); - my $numberOfIndexesToPurge = (scalar keys %indexesToPurge) * (scalar @$buildTargets); - - - # Start the build process - - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->BeginBuild( $numberOfFilesToBuild || $numberOfFilesToPurge || - $numberOfImagesToUpdate || $numberOfImagesToPurge || - $numberOfIndexesToBuild || $numberOfIndexesToPurge || - NaturalDocs::Menu->HasChanged() ); - }; - - if ($numberOfFilesToPurge) - { - NaturalDocs::StatusMessage->Start('Purging ' . $numberOfFilesToPurge - . ' file' . ($numberOfFilesToPurge > 1 ? 's' : '') . '...', - scalar @$buildTargets); - - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->PurgeFiles($filesToPurge); - NaturalDocs::StatusMessage->CompletedItem(); - }; - }; - - if ($numberOfIndexesToPurge) - { - NaturalDocs::StatusMessage->Start('Purging ' . $numberOfIndexesToPurge - . ' index' . ($numberOfIndexesToPurge > 1 ? 'es' : '') . '...', - scalar @$buildTargets); - - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->PurgeIndexes(\%indexesToPurge); - NaturalDocs::StatusMessage->CompletedItem(); - }; - }; - - if ($numberOfImagesToPurge) - { - NaturalDocs::StatusMessage->Start('Purging ' . $numberOfImagesToPurge - . ' image' . ($numberOfImagesToPurge > 1 ? 's' : '') . '...', - scalar @$buildTargets); - - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->PurgeImages($imagesToPurge); - NaturalDocs::StatusMessage->CompletedItem(); - }; - }; - - if ($numberOfFilesToBuild) - { - NaturalDocs::StatusMessage->Start('Building ' . $numberOfFilesToBuild - . ' file' . ($numberOfFilesToBuild > 1 ? 's' : '') . '...', - $numberOfFilesToBuild); - - foreach my $file (keys %$filesToBuild) - { - my $parsedFile = NaturalDocs::Parser->ParseForBuild($file); - - NaturalDocs::Error->OnStartBuilding($file); - - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->BuildFile($file, $parsedFile); - NaturalDocs::StatusMessage->CompletedItem(); - }; - - NaturalDocs::Error->OnEndBuilding($file); - }; - }; - - if ($numberOfIndexesToBuild) - { - NaturalDocs::StatusMessage->Start('Building ' . $numberOfIndexesToBuild - . ' index' . ($numberOfIndexesToBuild > 1 ? 'es' : '') . '...', - $numberOfIndexesToBuild); - - foreach my $index (keys %indexesToBuild) - { - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->BuildIndex($index); - NaturalDocs::StatusMessage->CompletedItem(); - }; - }; - }; - - if ($numberOfImagesToUpdate) - { - NaturalDocs::StatusMessage->Start('Updating ' . $numberOfImagesToUpdate - . ' image' . ($numberOfImagesToUpdate > 1 ? 's' : '') . '...', - $numberOfImagesToUpdate); - - foreach my $image (keys %$imagesToUpdate) - { - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->UpdateImage($image); - NaturalDocs::StatusMessage->CompletedItem(); - }; - }; - }; - - if (NaturalDocs::Menu->HasChanged()) - { - if (!NaturalDocs::Settings->IsQuiet()) - { print "Updating menu...\n"; }; - - foreach my $buildTarget (@$buildTargets) - { $buildTarget->Builder()->UpdateMenu(); }; - }; - - foreach my $buildTarget (@$buildTargets) - { - $buildTarget->Builder()->EndBuild($numberOfFilesToBuild || $numberOfFilesToPurge || - $numberOfIndexesToBuild || $numberOfIndexesToPurge || - $numberOfImagesToUpdate || $numberOfImagesToPurge || - NaturalDocs::Menu->HasChanged()); - }; - }; - - -1; diff --git a/docs/tool/Modules/NaturalDocs/Builder/Base.pm b/docs/tool/Modules/NaturalDocs/Builder/Base.pm deleted file mode 100644 index 0298264d9..000000000 --- a/docs/tool/Modules/NaturalDocs/Builder/Base.pm +++ /dev/null @@ -1,348 +0,0 @@ -############################################################################### -# -# Class: NaturalDocs::Builder::Base -# -############################################################################### -# -# A base class for all Builder output formats. -# -############################################################################### - -# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -# Natural Docs is licensed under the GPL - -use strict; -use integer; - -package NaturalDocs::Builder::Base; - - -############################################################################### -# Group: Notes - - -# -# Topic: Implementation -# -# Builder packages are implemented as blessed arrayrefs, not hashrefs. This is done for all objects in Natural Docs for -# efficiency reasons. You create members by defining constants via and using them as -# indexes into the array. -# - -# -# Topic: Function Order -# -# The functions in the build process will always be called in the following order. -# -# - will always be called. -# - will be called next only if there's files that need to be purged. -# - will be called next only if there's indexes that need to be purged. -# - will e called next only if there's images that need to be purged. -# - will be called once for each file that needs to be built, if any. -# - will be called once for each index that changed and is part of the menu, if any. -# - will be called once for each image that needs to be updated, if any. -# - will be called next only if the menu changed. -# - will always be called. -# - -# -# Topic: How to Approach -# -# Here's an idea of how to approach making packages for different output types. -# -# -# Multiple Output Files, Embedded Menu: -# -# This example is for when you want to build one output file per source file, each with its own copy of the menu within it. -# This is how works. -# -# Make sure you create a function that generates just the menu for a particular source file. We'll need to generate menus for -# both building a file from scratch and for updating the menu on an existing output file, so it's better to give it its own function. -# You may want to surround it with something that can be easily detected in the output file to make replacing easier. -# -# isn't important. You don't need to implement it. -# -# Implement to delete the output files associated with the purged files. -# -# Implement to delete the output files associated with the purged indexes. -# -# Implement to create an output file for the parsed source file. Use the menu function described earlier. -# -# Implement to create an output file for each index. Use the menu function described earlier for each page. -# -# Implement to go through the list of unbuilt files and update their menus. You can get the list from -# UnbuiltFilesWithContent()>. You need to open their output files, replace the menu, and save it back -# to disk. Yes, it would be simpler from a programmer's point of view to just rebuild the file completely, but that would be -# _very_ inefficient since there could potentially be a _lot_ of files in this group. -# -# Also make sure goes through the unchanged indexes and updates them as well. -# -# isn't important. You don't need to implement it. -# -# -# Multiple Output Files, Menu in File: -# -# This example is for when you want to build one output file per source file, but keep the menu in its own separate file. This -# is how works. -# -# isn't important. You don't need to implement it. -# -# Implement to delete the output files associated with the purged files. -# -# Implement to delete the output files associated with the purged indexes. -# -# Implement to generate an output file from the parsed source file. -# -# Implement to generate an output file for each index. -# -# Implement to rebuild the menu file. -# -# isn't important. You don't need to implement it. -# -# -# Single Output File using Intermediate Files: -# -# This example is for when you want to build one output file, such as a PDF file, but use intermediate files to handle differential -# building. This would be much like how a compiler compiles each source file into a object file, and then a linker stitches them -# all together into the final executable file. -# -# isn't important. You don't need to implement it. -# -# Implement to delete the intermediate files associated with the purged files. -# -# Implement to delete the intermediate files associated with the purged indexes. -# -# Implement to generate an intermediate file from the parsed source file. -# -# Implement to generate an intermediate file for the specified index. -# -# Implement to generate the intermediate file for the menu. -# -# Implement so that if the project changed, it stitches the intermediate files together into the final -# output file. Make sure you check the parameter because the function will be called when nothing changes too. -# -# -# Single Output File using Direct Changes: -# -# This example is for when you want to build one output file, such as a PDF file, but engineering it in such a way that you don't -# need to use intermediate files. In other words, you're able to add, delete, and modify entries directly in the output file. -# -# Implement so that if the project changed, it opens the output file and does anything it needs to do -# to get ready for editing. -# -# Implement to remove the entries associated with the purged files. -# -# Implement to remove the entries associated with the purged indexes. -# -# Implement to add or replace a section of the output file with a new one generated from the parsed file. -# -# Implement to add or replace an index in the output file with a new one generated from the specified index. -# -# Implement so that if the project changed, it saves the output file to disk. -# -# How you handle the menu depends on how the output file references other sections of itself. If it can do so by name, then -# you can implement to update the menu section of the file and you're done. If it has to reference itself -# by address or offset, it gets trickier. You should skip and instead rebuild the menu in if -# the parameter is true. This lets you do it whenever anything changes in a file, rather than just when the menu -# visibly changes. How you keep track of the locations and how they change is your problem. -# - - -############################################################################### -# -# Group: Required Interface Functions -# -# All Builder classes *must* define these functions. -# - - -# -# Function: INIT -# -# Define this function to call Add()> so that knows about this package. -# Packages are defined this way so that new ones can be added without messing around in other code. -# - - -# -# Function: CommandLineOption -# -# Define this function to return the text that should be put in the command line after -o to use this package. It cannot have -# spaces and is not case sensitive. -# -# For example, returns 'html' so someone could use -o html [directory] to use that package. -# -sub CommandLineOption - { - NaturalDocs::Error->SoftDeath($_[0] . " didn't define CommandLineOption()."); - }; - - -# -# Function: BuildFile -# -# Define this function to convert a parsed file to this package's output format. This function will be called once for every source -# file that needs to be rebuilt. However, if a file hasn't changed since the last time Natural Docs was run, it will not be sent to -# this function. All packages must support differential build. -# -# Parameters: -# -# sourceFile - The name of the source file. -# parsedFile - The parsed source file, as an arrayref of objects. -# -sub BuildFile #(sourceFile, parsedFile) - { - NaturalDocs::Error->SoftDeath($_[0] . " didn't define BuildFile()."); - }; - - -############################################################################### -# -# Group: Optional Interface Functions -# -# These functions can be implemented but packages are not required to do so. -# - - -# -# Function: New -# -# Creates and returns a new object. -# -# Note that this is the only function where the first parameter will be the package name, not the object itself. -# -sub New - { - my $package = shift; - - my $object = [ ]; - bless $object, $package; - - return $object; - }; - - -# -# Function: BeginBuild -# -# Define this function if the package needs to do anything at the beginning of the build process. This function will be called -# every time Natural Docs is run, even if the project hasn't changed. This allows you to manage dependencies specific -# to the output format that may change independently from the source tree and menu. For example, -# needs to keep the CSS files in sync regardless of whether the source tree changed or not. -# -# Parameters: -# -# hasChanged - Whether the project has changed, such as source files or the menu file. If false, nothing else is going to be -# called except . -# -sub BeginBuild #(hasChanged) - { - }; - - -# -# Function: EndBuild -# -# Define this function if the package needs to do anything at the end of the build process. This function will be called every time -# Natural Docs is run, even if the project hasn't changed. This allows you to manage dependencies specific to the output -# format that may change independently from the source tree. For example, needs to keep the -# CSS files in sync regardless of whether the source tree changed or not. -# -# Parameters: -# -# hasChanged - Whether the project has changed, such as source files or the menu file. If false, the only other function that -# was called was . -# -sub EndBuild #(hasChanged) - { - }; - - -# -# Function: BuildIndex -# -# Define this function to create an index for the passed topic. You can get the index from -# Index()>. -# -# The reason it's not passed directly to this function is because indexes may be time-consuming to create. As such, they're -# generated on demand because some output packages may choose not to implement them. -# -# Parameters: -# -# topic - The to limit the index by. -# -sub BuildIndex #(topic) - { - }; - - -# -# Function: UpdateImage -# -# Define this function to add or update the passed image in the output. -# -# Parameters: -# -# file - The image -# -sub UpdateImage #(file) - { - }; - - -# -# Function: PurgeFiles -# -# Define this function to make the package remove all output related to the passed files. These files no longer have Natural Docs -# content. -# -# Parameters: -# -# files - An existence hashref of the files to purge. -# -sub PurgeFiles #(files) - { - }; - - -# -# Function: PurgeIndexes -# -# Define this function to make the package remove all output related to the passed indexes. These indexes are no longer part -# of the menu. -# -# Parameters: -# -# indexes - An existence hashref of the of the indexes to purge. -# -sub PurgeIndexes #(indexes) - { - }; - - -# -# Function: PurgeImages -# -# Define this function to make the package remove all output related to the passed image files. These files are no longer used -# by the documentation. -# -# Parameters: -# -# files - An existence hashref of the image to purge. -# -sub PurgeImages #(files) - { - }; - - -# -# Function: UpdateMenu -# -# Define this function to make the package update the menu. It will only be called if the menu changed. -# -sub UpdateMenu - { - }; - - -1; diff --git a/docs/tool/Modules/NaturalDocs/Builder/FramedHTML.pm b/docs/tool/Modules/NaturalDocs/Builder/FramedHTML.pm deleted file mode 100644 index ab020aa6d..000000000 --- a/docs/tool/Modules/NaturalDocs/Builder/FramedHTML.pm +++ /dev/null @@ -1,345 +0,0 @@ -############################################################################### -# -# Package: NaturalDocs::Builder::FramedHTML -# -############################################################################### -# -# A package that generates output in HTML with frames. -# -# All functions are called with Package->Function() notation. -# -############################################################################### - -# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -# Natural Docs is licensed under the GPL - - -use strict; -use integer; - -package NaturalDocs::Builder::FramedHTML; - -use base 'NaturalDocs::Builder::HTMLBase'; - - -############################################################################### -# Group: Implemented Interface Functions - - -# -# Function: INIT -# -# Registers the package with . -# -sub INIT - { - NaturalDocs::Builder->Add(__PACKAGE__); - }; - - -# -# Function: CommandLineOption -# -# Returns the option to follow -o to use this package. In this case, "html". -# -sub CommandLineOption - { - return 'FramedHTML'; - }; - - -# -# Function: BuildFile -# -# Builds the output file from the parsed source file. -# -# Parameters: -# -# sourcefile - The of the source file. -# parsedFile - An arrayref of the source file as objects. -# -sub BuildFile #(sourceFile, parsedFile) - { - my ($self, $sourceFile, $parsedFile) = @_; - - my $outputFile = $self->OutputFileOf($sourceFile); - - - # 99.99% of the time the output directory will already exist, so this will actually be more efficient. It only won't exist - # if a new file was added in a new subdirectory and this is the first time that file was ever parsed. - if (!open(OUTPUTFILEHANDLE, '>' . $outputFile)) - { - NaturalDocs::File->CreatePath( NaturalDocs::File->NoFileName($outputFile) ); - - open(OUTPUTFILEHANDLE, '>' . $outputFile) - or die "Couldn't create output file " . $outputFile . "\n"; - }; - - print OUTPUTFILEHANDLE - - - - # IE 6 doesn't like any doctype here at all. Add one (strict or transitional doesn't matter) and it makes the page slightly too - # wide for the frame. Mozilla and Opera handle it like champs either way because they Don't Suck(tm). - - # '' . "\n\n" - - '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . '' - . $self->BuildTitle($sourceFile) - . '' - - . '' - - . '' - - . '' - . $self->OpeningBrowserStyles() - - . $self->StandardComments() - - . "\n\n\n" - . $self->BuildContent($sourceFile, $parsedFile) - . "\n\n\n" - - . $self->BuildToolTips() - - . $self->ClosingBrowserStyles() - . ''; - - - close(OUTPUTFILEHANDLE); - }; - - -# -# Function: BuildIndex -# -# Builds an index for the passed type. -# -# Parameters: -# -# type - The to limit the index to, or undef if none. -# -sub BuildIndex #(type) - { - my ($self, $type) = @_; - - my $indexTitle = $self->IndexTitleOf($type); - my $indexFile = $self->IndexFileOf($type); - - my $startIndexPage = - - '' . "\n\n" - - . '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . ''; - - if (defined NaturalDocs::Menu->Title()) - { $startIndexPage .= $self->StringToHTML(NaturalDocs::Menu->Title()) . ' - '; }; - - $startIndexPage .= - $indexTitle - . '' - - . '' - - . '' - - . '' - . $self->OpeningBrowserStyles() - - . "\n\n\n" - . $self->StandardComments() - . "\n\n\n" - . '
      ' - . '
      ' - . $indexTitle - . '
      '; - - - my $endIndexPage = - - '
      ' - . "\n\n\n" - - . $self->ClosingBrowserStyles() - - . ''; - - my $startSearchResultsPage = - - '' . "\n\n" - - . '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . '' - - . '' - . '' - - . '' - . $self->OpeningBrowserStyles() - - . "\n\n\n" - . $self->StandardComments() - . "\n\n\n" - - . '
      ' - . '
      ' - . 'Search Results' - . '
      '; - - my $endSearchResultsPage = - - '
      ' - . "\n\n\n" - - . $self->ClosingBrowserStyles() - - . ''; - - my $indexContent = NaturalDocs::SymbolTable->Index($type); - my $pageCount = $self->BuildIndexPages($type, $indexContent, $startIndexPage, $endIndexPage, - $startSearchResultsPage, $endSearchResultsPage); - $self->PurgeIndexFiles($type, $indexContent, $pageCount + 1); - }; - - -# -# Function: UpdateMenu -# -# Builds the menu file. Also generates index.html. -# -sub UpdateMenu - { - my $self = shift; - - my $outputDirectory = NaturalDocs::Settings->OutputDirectoryOf($self); - my $outputFile = NaturalDocs::File->JoinPaths($outputDirectory, 'menu.html'); - - - open(OUTPUTFILEHANDLE, '>' . $outputFile) - or die "Couldn't create output file " . $outputFile . "\n"; - - my $title = 'Menu'; - if (defined $title) - { $title .= ' - ' . NaturalDocs::Menu->Title(); }; - - $title = $self->StringToHTML($title); - - - print OUTPUTFILEHANDLE - - - '' . "\n\n" - - . '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . '' - . $title - . '' - - . '' - - . '' - - . '' - . '' - - . '' - . $self->OpeningBrowserStyles() - - . $self->StandardComments() - - . "\n\n\n" - . $self->BuildMenu(undef, undef) - . "\n\n\n" - . $self->BuildFooter(1) - . "\n\n\n" - - . $self->ClosingBrowserStyles() - . ''; - - - close(OUTPUTFILEHANDLE); - - - # Update index.html - - my $firstMenuEntry = $self->FindFirstFile(); - my $indexFile = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index.html' ); - - # We have to check because it's possible that there may be no files with Natural Docs content and thus no files on the menu. - if (defined $firstMenuEntry) - { - open(INDEXFILEHANDLE, '>' . $indexFile) - or die "Couldn't create output file " . $indexFile . ".\n"; - - print INDEXFILEHANDLE - - '' - - . '' - - . '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . '' - . $self->StringToHTML(NaturalDocs::Menu->Title()) - . '' - - . '' - - . $self->StandardComments() - - . '' - . '' - . '' - . '' - - . '' - . 'This documentation was designed for use with frames. However, you can still use it by ' - . '<a href="menu.html">starting from the menu page</a>.' - . "<script language=JavaScript><!--\n" - . 'location.href="menu.html";' - . "\n// --></script>" - . '' - - . ''; - - close INDEXFILEHANDLE; - } - - elsif (-e $indexFile) - { - unlink($indexFile); - }; - }; - - -1; diff --git a/docs/tool/Modules/NaturalDocs/Builder/HTML.pm b/docs/tool/Modules/NaturalDocs/Builder/HTML.pm deleted file mode 100644 index 95f31b5a2..000000000 --- a/docs/tool/Modules/NaturalDocs/Builder/HTML.pm +++ /dev/null @@ -1,398 +0,0 @@ -############################################################################### -# -# Package: NaturalDocs::Builder::HTML -# -############################################################################### -# -# A package that generates output in HTML. -# -# All functions are called with Package->Function() notation. -# -############################################################################### - -# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -# Natural Docs is licensed under the GPL - - -use strict; -use integer; - -package NaturalDocs::Builder::HTML; - -use base 'NaturalDocs::Builder::HTMLBase'; - - -############################################################################### -# Group: Implemented Interface Functions - - -# -# Function: INIT -# -# Registers the package with . -# -sub INIT - { - NaturalDocs::Builder->Add(__PACKAGE__); - }; - - -# -# Function: CommandLineOption -# -# Returns the option to follow -o to use this package. In this case, "html". -# -sub CommandLineOption - { - return 'HTML'; - }; - - -# -# Function: BuildFile -# -# Builds the output file from the parsed source file. -# -# Parameters: -# -# sourcefile - The of the source file. -# parsedFile - An arrayref of the source file as objects. -# -sub BuildFile #(sourceFile, parsedFile) - { - my ($self, $sourceFile, $parsedFile) = @_; - - my $outputFile = $self->OutputFileOf($sourceFile); - - - # 99.99% of the time the output directory will already exist, so this will actually be more efficient. It only won't exist - # if a new file was added in a new subdirectory and this is the first time that file was ever parsed. - if (!open(OUTPUTFILEHANDLE, '>' . $outputFile)) - { - NaturalDocs::File->CreatePath( NaturalDocs::File->NoFileName($outputFile) ); - - open(OUTPUTFILEHANDLE, '>' . $outputFile) - or die "Couldn't create output file " . $outputFile . "\n"; - }; - - print OUTPUTFILEHANDLE - - - '' . "\n\n" - - . '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . '' - . $self->BuildTitle($sourceFile) - . '' - - . '' - - . '' - . '' - - . '' - . $self->OpeningBrowserStyles() - - . $self->StandardComments() - - . "\n\n\n" - . $self->BuildContent($sourceFile, $parsedFile) - . "\n\n\n" - . $self->BuildFooter() - . "\n\n\n" - . $self->BuildMenu($sourceFile, undef) - . "\n\n\n" - . $self->BuildToolTips() - . "\n\n\n" - . '
      ' - . '' - . 'Close' - . '
      ' - . "\n\n\n" - - . $self->ClosingBrowserStyles() - . ''; - - - close(OUTPUTFILEHANDLE); - }; - - -# -# Function: BuildIndex -# -# Builds an index for the passed type. -# -# Parameters: -# -# type - The to limit the index to, or undef if none. -# -sub BuildIndex #(type) - { - my ($self, $type) = @_; - - my $indexTitle = $self->IndexTitleOf($type); - - my $startIndexPage = - - '' . "\n\n" - - . '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . '' - . $indexTitle; - - if (defined NaturalDocs::Menu->Title()) - { $startIndexPage .= ' - ' . $self->StringToHTML(NaturalDocs::Menu->Title()); }; - - $startIndexPage .= - '' - - . '' - - . '' - . '' - - . '' - . $self->OpeningBrowserStyles() - - . $self->StandardComments() - - . "\n\n\n" - - . '
      ' - . '
      ' - . $indexTitle - . '
      '; - - my $endIndexPage = - '
      ' - - . "\n\n\n" - . $self->BuildFooter() - . "\n\n\n" - . $self->BuildMenu(undef, $type) - . "\n\n\n" - . '
      ' - . '' - . 'Close' - . '
      ' - . "\n\n\n" - - . $self->ClosingBrowserStyles() - . ''; - - - my $startSearchResultsPage = - - '' . "\n\n" - - . '' - - . (NaturalDocs::Settings->CharSet() ? - '' : '') - - . '' - - . '' - - . '' - . $self->OpeningBrowserStyles() - - . $self->StandardComments() - - . "\n\n\n" - - . '
      '; - - - my $endSearchResultsPage = - '
      ' - . $self->ClosingBrowserStyles() - . ''; - - my $indexContent = NaturalDocs::SymbolTable->Index($type); - my $pageCount = $self->BuildIndexPages($type, $indexContent, $startIndexPage, $endIndexPage, - $startSearchResultsPage, $endSearchResultsPage); - $self->PurgeIndexFiles($type, $indexContent, $pageCount + 1); - }; - - -# -# Function: UpdateMenu -# -# Updates the menu in all the output files that weren't rebuilt. Also generates index.html. -# -sub UpdateMenu - { - my $self = shift; - - - # Update the menu on unbuilt files. - - my $filesToUpdate = NaturalDocs::Project->UnbuiltFilesWithContent(); - - foreach my $sourceFile (keys %$filesToUpdate) - { - $self->UpdateFile($sourceFile); - }; - - - # Update the menu on unchanged index files. - - my $indexes = NaturalDocs::Menu->Indexes(); - - foreach my $index (keys %$indexes) - { - if (!NaturalDocs::SymbolTable->IndexChanged($index)) - { - $self->UpdateIndex($index); - }; - }; - - - # Update index.html - - my $firstMenuEntry = $self->FindFirstFile(); - my $indexFile = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index.html' ); - - # We have to check because it's possible that there may be no files with Natural Docs content and thus no files on the menu. - if (defined $firstMenuEntry) - { - open(INDEXFILEHANDLE, '>' . $indexFile) - or die "Couldn't create output file " . $indexFile . ".\n"; - - print INDEXFILEHANDLE - '' - . '' - . ''; - - close INDEXFILEHANDLE; - } - - elsif (-e $indexFile) - { - unlink($indexFile); - }; - }; - - - -############################################################################### -# Group: Support Functions - - -# -# Function: UpdateFile -# -# Updates an output file. Replaces the menu, HTML title, and footer. It opens the output file, makes the changes, and saves it -# back to disk, which is much quicker than rebuilding the file from scratch if these were the only things that changed. -# -# Parameters: -# -# sourceFile - The source . -# -# Dependencies: -# -# - Requires to surround its content with the exact strings "". -# - Requires to surround its content with the exact strings "". -# -sub UpdateFile #(sourceFile) - { - my ($self, $sourceFile) = @_; - - my $outputFile = $self->OutputFileOf($sourceFile); - - if (open(OUTPUTFILEHANDLE, '<' . $outputFile)) - { - my $content; - - read(OUTPUTFILEHANDLE, $content, -s OUTPUTFILEHANDLE); - close(OUTPUTFILEHANDLE); - - - $content =~ s{[^<]*<\/title>}{'<title>' . $self->BuildTitle($sourceFile) . ''}e; - - $content =~ s/