ДЕКОМПИЛЯЦИЯ ИЛИ ВОССТАНОВЛЕНИЕ ИСХОДНИКОВ

    Прежде, чем приступить к декомпиляции q2, нужно ознакомиться с правилами названия восстанавливаемых функций. Это можно сделать здесь.
    Разбор кода будет происходить последовательно-функция за функцией с разбором вложенных вызовов. Задача ясна: понять как работает q2 и, по возможности, получить его исходники на Си. Замечу, что ПОЛНОЕ восстановление НЕВОЗМОЖНО, лишь частичное. За синтаксис исходников не отвечаю:) Начали...

1. Точка входа и что там за код такой непонятный...
    Точка входа нам уже известна: 0043A7E0. По идее там и должна находиться функция WinMain. На самом деле это не так... Вот что находится по этому адресу:
:0043A7E0 55             push   ebp
          8BEC           mov    ebp,esp
          6AFF           push   FFFFFFFF
          68C89B4400     push   00449BC8
          68280B4400     push   00440B28
          64A100000000   mov    eax,fs:[00000000]
          50             push   eax
          64892500000000 mov    fs:[00000000],esp
          83C4A8         add    esp,FFFFFFA8
          53             push   ebx
          56             push   esi
          57             push   edi
          8965E8         mov    [ebp-18],esp
          FF153C914400   call   [0044913C]
          33D2           xor    edx,edx
          8AD4           mov    dl,ah
          891530C64700   mov    [0047C630],edx
          8BC8           mov    ecx,eax
          81E1FF000000   and    ecx,000000FF
          890D2CC64700   mov    [0047C62C],ecx
          C1E108         shl    ecx,08
          03CA           add    ecx,edx
          890D28C64700   mov    [0047C628],ecx
          C1E810         shr    eax,10
          A324C64700     mov    [0047C624],eax
          E894570000     call   QUAKE2.0043FFD0
          85C0           test   eax,eax
          750A           jne    QUAKE2.0043A84A (0043A84A)
          6A1C           push   0000001C
          E879010000     call   QUAKE2.0043A9C0
          83C404         add    esp,00000004
:0043A84A E8710E0000     call   QUAKE2.0043B6C0
          85C0           test   eax,eax
          750A           jne    QUAKE2.0043A85D (0043A85D)
                         ...
и это только часть всей, довольно большой функции (тут ~1/4 кусок). Сразу говорю, людям не владеющим Си, а тем более ассемблером i386-го, тут делать нечего. Тем кто знает асм по-минимому, кстати тоже... Для полного понимания всего что было и будет написано, нужно знать:

 -весь язык Си. Си с классами (т.е. Си++) не нужен.
 -устройство CPU i386 и все его инструкции (ассемблер). Также нужно знать разные фишки их использования, типа:
test eax, eax
je label1
 -как Си компилирует if, for, goto, основные соглашения по вызовам функций, как происходит передача параметров в этих соглашениях и как они компилируются в коде. Чем отличаются глобальные переменные от локальных и как хранятся в памяти те и другие. Как выглядит каркас функции в Си. В q2 в большинстве используется C/C++ Calling Convention-т.е. параметры передаются справа-налево, их уничтожение происходит после вызова, а возвращаемое значение помещается в eax(флаг cf не используется).
 -иметь опыт в дизассемблировании программ для Win32.

Короче, кодеры и кракеры все это должны знать, как и то, что за функция находится вначале всех программ, написанных на Си;) Сразу скажу, она называется WinMainCRTStartup. Эта функция предназначена для разного рода системной инициализации. Например в этой функции создаются массивы и структуры, используемые библиотечными функциями типа malloc. А где же тогда WinMain?!? Вызов WinMain также входит в задачу этой функции. Ведь кто-то должен подготовить все параметры для WinMain, например получить командную строку... Это и делает WinMainCRTStartup. Разбирать её нет необходимости, потому что это мартышкин труд. Нужно просто найти через эту функцию точку входа(адрес) WinMain. Делается это следующим образом: как известно у функции WinMain четыре параметра. Поэтому мы просто должны найти 4 push'а, а следующий за ними call будет вызовом WinMain. Вот что получилось:
                         ...
:0043A920 50             push   eax            ;nCmdShow
          56             push   esi            ;lpCmdLine
          6A00           push   00000000       ;hPrevInstance
          6A00           push   00000000 
          FF1548914400   call   [00449148]     ;это вызов GetModuleHandleA
          50             push   eax            ;hInstance
          E80EB3FFFF     call   QUAKE2.00435C40 ;а это WinMain
                         ...
значит адрес WinMain - 00435С40. Кстати откинув разбор функции WinMainCRTStartup, и всех её вложенных вызовов, мы избавились от лишних ~10% кода!!! Ещё одно замечание: особо волноваться за то, что откинув инициализацию, мы лишились чего-то интересного не стоит. Там такой НУДНЫЙ код, что уши вянут. Кто любит изучать такой тип кода, пусть разбирает, весело проведет пол-года... Единственное, что можно хорошее сказать про WinMainCRTStartup, так это то, что в ней заключена вся мелкомягкая гениальность программистов Microsoft: код написан классно и не глючит:)) Исходники можно найти в Visual C++ 6.0 в папке src в файле crt0.c, или выдрать из Visual C++ 5.0 в файле libc.lib с помощь lib.exe. Там находится объектный файл. А у Symantec C++ 6.1 есть такая замечательная утилита - obj2asm.exe.

2. WinMain...
:00435C40 8B442408       mov    eax,[esp+08]
          83EC1C         sub    esp,0000001C
          85C0           test   eax,eax
          53             push   ebx
          55             push   ebp
          56             push   esi
          57             push   edi
          740C           je     QUAKE2.00435C5B (00435C5B)
          5F             pop    edi
          5E             pop    esi
          5D             pop    ebp
          33C0           xor    eax,eax
          5B             pop    ebx
          83C41C         add    esp,0000001C
          C21000         ret    0010
:00435C5B 8B4C2438       mov    ecx,[esp+38]
          8B442430       mov    eax,[esp+30]
          51             push   ecx
          A394CC4700     mov    [0047CC94],eax ;HINSTANCE global_hInstance
          E852FFFFFF     call   QUAKE2.00435BC0 ;(1)
          83C404         add    esp,00000004
          E8FAF8FFFF     call   QUAKE2.00435570 ;(2)
          8B3DA0CC4700   mov    edi,[0047CCA0] ;! начало блока
          89442434       mov    [esp+34],eax
          85C0           test   eax,eax
          747B           je     QUAKE2.00435CFF (00435CFF)
          83FF7D         cmp    edi,0000007D
          7D76           jnl    QUAKE2.00435CFF (00435CFF)
          33DB           xor    ebx,ebx
          85FF           test   edi,edi
          7E46           jle    QUAKE2.00435CD5 (00435CD5)
          BDC0CC4700     mov    ebp,0047CCC0
:00435C94 8B4D00         mov    ecx,[ebp]
          BE74054500     mov    esi,00450574
:00435C9C 8A01           mov    al,[ecx]
          8AD0           mov    dl,al
          3A06           cmp    al,[esi]
          751C           jne    QUAKE2.00435CC0 (00435CC0)
          84D2           test   dl,dl
          7414           je     QUAKE2.00435CBC (00435CBC)
          8A4101         mov    al,[ecx+01]
          8AD0           mov    dl,al
          3A4601         cmp    al,[esi+01]
          750E           jne    QUAKE2.00435CC0 (00435CC0)
          83C102         add    ecx,00000002
          83C602         add    esi,00000002
          84D2           test   dl,dl
          75E0           jne    QUAKE2.00435C9C (00435C9C)
:00435CBC 33C9           xor    ecx,ecx
          EB05           jmp    QUAKE2.00435CC5 (00435CC5)
:00435CC0 1BC9           sbb    ecx,ecx
          83D9FF         sbb    ecx,FFFFFFFF
:00435CC5 85C9           test   ecx,ecx
          7408           je     QUAKE2.00435CD1 (00435CD1)
          43             inc    ebx
          83C504         add    ebp,00000004
          3BDF           cmp    ebx,edi
          7CC3           jl     QUAKE2.00435C94 (00435C94)
:00435CD1 8B442434       mov    eax,[esp+34]
:00435CD5 3BDF           cmp    ebx,edi
          7526           jne    QUAKE2.00435CFF (00435CFF)
          C704BDC0CC4700+mov    dword ptr [4*edi+0047CCC0],0044EA40
          47             inc    edi
          C704BDC0CC4700+mov    dword ptr [4*edi+0047CCC0],00450574
          47             inc    edi
          8904BDC0CC4700 mov    [4*edi+0047CCC0],eax
          47             inc    edi
          893DA0CC4700   mov    [0047CCA0],edi ;! конец блока
:00435CFF 68C0CC4700     push   0047CCC0
          57             push   edi
          E8663BFEFF     call   QUAKE2.00419870 ;(3)
          83C408         add    esp,00000008
          E8EE37FFFF     call   QUAKE2.00429500 ;(4)
          8B2DD0914400   mov    ebp,[004491D0]
          8BD8           mov    ebx,eax
:00435D1A A198CC4700     mov    eax,[0047CC98]
          85C0           test   eax,eax
          7519           jne    QUAKE2.00435D3C (00435D3C)
          A1B83D4F00     mov    eax,[004F3DB8]
          85C0           test   eax,eax
          7418           je     QUAKE2.00435D44 (00435D44)
          D94014         fld    dword ptr[eax+14]
          D81D449B4400   fcomp  dword ptr[00449B44]
          DFE0           fnstsw ax
          F6C440         test   ah,40
          7508           jne    QUAKE2.00435D44 (00435D44)
:00435D3C 6A01           push   00000001
          FF15E4904400   call   [004490E4] ;(5)-Sleep
:00435D44 6A00           push   00000000
          6A00           push   00000000
          6A00           push   00000000
          8D4C241C       lea    ecx,[esp+1C]
:00435D57 6A00           push   00000000
          51             push   ecx
          FFD5           call   ebp ;(6)-PeekMessageA
          85C0           test   eax,eax
          744C           je     QUAKE2.00435DA3 (00435DA3)
:00435D57 6A00           push   00000000
          6A00           push   00000000
          8D542418       lea    edx,[esp+18]
          6A00           push   00000000
          52             push   edx
          FF15D8914400   call   [004491D8] ;(7)-GetMessageA
          85C0           test   eax,eax
          7505           jne    QUAKE2.00435D71 (00435D71)
          E88F28FEFF     call   QUAKE2.00418600 ;(8)
:00435D71 8B442420       mov    eax,[esp+20]
          8D4C2410       lea    ecx,[esp+10]
          51             push   ecx
          A390CC4700     mov    [0047CC90],eax
          FF15D4914400   call   [004491D4] ;(9)-TranslateMessage
          8D542410       lea    edx,[esp+10]
          52             push   edx
          FF15DC914400   call   [004491DC] ;(10)-DispatchMessageA
          6A00           push   00000000
          6A00           push   00000000
          6A00           push   00000000
          8D44241C       lea    eax,[esp+1C]
          6A00           push   00000000
          50             push   eax
          FFD5           call   ebp ;(6.2)-PeekMessageA
          85C0           test   eax,eax
          75B4           jne    QUAKE2.00435D57 (00435D57)
:00435DA3 E85837FFFF     call   QUAKE2.00429500 ;(11)
          8BF8           mov    edi,eax
          8BF7           mov    esi,edi
          2BF3           sub    esi,ebx
          83FE01         cmp    esi,00000001
          7CF0           jl     QUAKE2.00435DA3 (00435DA3)
          6800000300     push   00030000
          6800000200     push   00020000
          E8CE480000     call   QUAKE2.0043A690 ;(12)
          83C408         add    esp,00000008
          56             push   esi
          E8153DFEFF     call   QUAKE2.00419AE0 ;(13)
          83C404         add    esp,00000004
          8BDF           mov    ebx,edi
          E945FFFFFF     jmp    QUAKE2.00435D1A
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
    Функция WinMain занимает всего-лишь 544 байта, чего не скажешь про размер листинга. Как видно, у WinMain 13 вложенных вызовов, из них шестой(PeekMessageA) вызывается дважды... На данный момент мое дерево разбора выглядит так: WinMain.3.20.2.4. Это где-то 1/6 часть от всего кода quake2.exe.
    В самом начале происходит своеобразная проверка на Win32: для него hPrevInstance всегда равен нулю(NULL). И если это не так (hPrevInstance!=NULL), то мы выходим из программы. Потом в глобальной переменной HINSTANCE global_hInstance сохраняется значение hInstance для общего (глобального) использования.
    После этого вызываются подряд (1) и (2). Они разбираются сразу на лету.. (1) частично есть в исходниках QW(QuakeWorld-см. раздел ИСХОДНИКИ ). Она входит в состав самой WinMain(см. файл sys_win.c). Вот её листинг:
:00435BC0 8B442404       mov    eax,[esp+04] ;параметр lpCmdLine
          BA01000000     mov    edx,00000001
          8915A0CC4700   mov    [0047CCA0],edx ;int argc'
          C705C0CC470048+mov    dword ptr [0047CCC0],00456348 ;char *argv[MAX_NUM_ARGVS]. argv[0]="exe"
          8A08           mov    cl,[eax]
          84C9           test   cl,cl
          745E           je     QUAKE.00435C3D (00435C3D)
:00435BDF 81FA80000000   cmp    edx,00000080
          7D56           jnl    QUAKE.00435C3D (00435C3D)
          84C9           test   cl,cl
          7412           je     QUAKE.00435BFD (00435BFD)
:00435BEB 80F920         cmp    cl,20
          7E05           jle    QUAKE.00435BF5 (00435BF5)
          80F97E         cmp    cl,7E
          7E08           jle    QUAKE.00435BFD (00435BFD)
:00435BF5 8A4801         mov    cl,[eax+01]
          40             inc    eax
          84C9           test   cl,cl
          75EE           jne    QUAKE.00435BEB (00435BEB)
:00435BFD 803800         cmp    byte ptr [eax],00
          7435           je     QUAKE.00435C37 (00435C37)
          890495C0CC4700 mov    [4*edx+0047CCC0],eax
          42             inc    edx
          8915A0CC4700   mov    [0047CCA0],edx
          8A08           mov    cl,[eax]
          84C9           test   cl,cl
          7412           je     QUAKE.00435C28 (00435C28)
:00435C16 80F920         cmp    cl,20
          7E0D           jle    QUAKE.00435C28 (00435C28)
          80F97E         cmp    cl,7E
          7F08           jg     QUAKE.00435C28 (00435C28)
          8A4801         mov    cl,[eax+01]
          40             inc    eax
          84C9           test   cl,cl
          75EE           jne    QUAKE.00435C16 (00435C16)
:00435C28 803800         cmp    byte ptr [eax],00
          740A           je     QUAKE.00435C37 (00435C37)
          C60000         mov    byte ptr [eax],00
          8B15A0CC4700   mov    edx,[0047CCA0]
          40             inc    eax
:00435C37 8A08           mov    cl,[eax]
          84C9           test   cl,cl
          75A2           jne    QUAKE.00435BDF (00435BDF)
:00435C3D C3             ret
          90             nop
          90             nop
    Кстати, эта функция расположена прямо перед функцией WinMain. То есть: Кармак увидел, что кусок WinMain из QW можно переделать в отдельную функцию и незамедлительно это сделал, приписав её в исходниках над WinMain...
    Эту функцию надо как-то назвать: пусть будет Create_Argv'. Эта функция нарезает слова из командной строки (аргументы), переданной ей в качестве параметра в массив argv. Количество аргументов заносится в argc'. Такой способ работы с командной строкой используется у функции main в DOS-приложениях. Замечания: количество аргументов не должно превышать MAX_NUM_ARGVS, которое полагается равным 128(см. quakedef.h). И ещё: самым первым аргументом argv полагается строка "exe". Это гарантирует ненулевой размер argc'.
    Далее я попытаюсь написать собранный исходник. Скорее всего эти две функции(WinMain и Create_Argv') как находились в sys_win.c у QW, так там и остались у q2. То же относится и к MAX_NUM_ARGVS.
//файл sys_win.c
HINSTANCE global_hInstance;
char *argv[MAX_NUM_ARGVS];
int argc;

void Create_Argv_(LPSTR lpCmdLine)
{
 argc=1;
 argv[0]="exe";
 while(*lpCmdLine && (argc < MAX_NUM_ARGVS))
 {
  while(*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine>126)))
   lpCmdLine++;
  if(*lpCmdLine)
  {
   argv[argc]=lpCmdLine;
   argc++;
   while(*lpCmdLine && ((*lpCmdLine >32) && (*lpCmdLine <=126)))
    lpCmdLine++;
   if(*lpCmdLine)
   {
    *lpCmdLine=0;
    lpCmdLine++;
   }
  }
 }
}

/*
==========
WinMain
==========
*/
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 if(hPrevInstance)
  return 0;
 global_hInstance=hInstance;
 Create_Argv_(lpCmdLine);
//...
}
//файл quakedef.h
#define MAX_NUM_ARGVS 128
    Законченным исходником написанное назвать нельзя. В нем нехватает пары include'ов, и к тому же правильность функций по нему не проверишь. Тут находится тестовая программка, которая проверяет правильность Create_Argv'. Рабочая версия компилилась на Visual C++ 5.0. Попробуйте запустить её из строки с такими параметрами: test.exe this is test
    Что же касается (2), то это новинка. По крайней мере в QW я её не нашел.У функции нет входных параметров, а на выходе указатель типа char, который сохраняется в локальной переменной. Листинг:
:00435570 A1BCBC4700     mov    eax,[0047BCBC] ;static cd_check_
          83EC44         sub    esp,00000044
          85C0           test   eax,eax
          56             push   esi
          740A           je     QUAKE.00435587 (00435587)
          B8C0BC4700     mov    eax,0047BCC0 ;char cddir_[MAX_QPATH]
          5E             pop    esi
          83C444         add    esp,00000044
          C3             ret
:00435587 6A01           push   00000001
          FF15C8904400   call   [004490C8] ;(1)-SetErrorMode
          8B35C4904400   mov    esi,[004490C4]
          C64424053A     mov    byte ptr [esp+05],3A
          C64424065C     mov    byte ptr [esp+06],5C
          C644240700     mov    byte ptr [esp+07],00
          C705BCBC470001+mov    dword ptr [0047BCBC],00000001
          C644240463     mov    byte ptr [esp+04],63
:004355B3 8D442404       lea    eax,[esp+04]
          50             push   eax
          68B0614500     push   004561B0
          68C0BC4700     push   0047BCC0
          E8E92D0000     call   QUAKE.004383B0 ;(2)-sprintf
          83C40C         add    esp,0000000C
          8D4C2404       lea    ecx,[esp+04]
          8D542408       lea    edx,[esp+08]
          51             push   ecx
          6894614500     push   00456194
          52             push   edx
          E8D22D0000     call   QUAKE.004383B0 ;(2.2)-sprintf
          83C40C         add    esp,0000000C
          8D442408       lea    eax,[esp+08]
          6890614500     push   00456190
          50             push   eax
          E8E02B0000     call   QUAKE.004381D0 ;(3)-fopen
          83C408         add    esp,00000008
          85C0           test   eax,eax
          7415           je     QUAKE.0043560C (0043560C)
          50             push   eax
          E8E3240000     call   QUAKE.00437AE0 ;(4)-fclose
          83C404         add    esp,00000004
          8D4C2404       lea    ecx,[esp+04]
          51             push   ecx
          FFD6           call   esi ;(5)-GetDriveType
          83F805         cmp    eax,00000005
          741C           je     QUAKE.00435628 (00435628)
:0043560C 8A442404       mov    al,[esp+04]
          FEC0           inc    al
          3C7A           cmp    al,7A
          88442404       mov    [esp+04],al
          7E99           jle    QUAKE.004355B3 (004355B3)
          C605C0BC470000 mov    byte ptr [0047BCC0],00
          33C0           xor    eax,eax
          5E             pop    esi
          83C444         add    esp,00000044
          C3             ret
:00435628 B8C0BC4700     mov    eax,0047BCC0
          5E             pop    esi
          83C444         add    esp,00000044
          C3             ret
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
          90             nop
    У функции 5 вложенных вызовов: 2 системных и 3 библиотечных. Что такое библиотечные функции??? Библиотечные функции - это функции Си, например printf, strcpy итд. Библиотечные функции прилинковываются в самый конец проекта в процессе компиляции. А вообще они хранятся в библиотеке libc.lib. О том, что это библиотечные функции можно узнать путем таких проверок: по входным параметрам и по коду этих функций(во-первых он там слишком замороченный для обычных программ, а во-вторых его можно найти, дизассемблировав W32DASM'ом какую-нибудь (лучше все) msvcrtXXX.dll и поискав совпадающие строчки кода). Потом, ещё можно смотреть по адресу: допустим у какой-то функции адрес заключен в пределах от 00437AE0 до 004381D0 - значит это 100% библиотечная функция, так как она находится между fclose и fopen. Короче поиск библиотечных функций я беру на себя...
    Что делает функция WinMain.2:
 -вначале нужно сказать, что эта функция защищена от повторного вызова статической переменной [0047BCBC]. То есть WinMain.2 вызывается в программе только один раз-в самом начале. Я назвал эту защелку cd_check'.
 -с помощью SetErrorMode мы убираем обработку критических ошибок. Такие ошибки могут возникнуть, например, если невозможно открыть файл (повреждена поверхность диска).
 -далее мы перебираем все диски с 'C' по 'Z' и ищем на них следующий файл: x:\install\data\quake2.exe. Как известно, такая директория находится на Quake2 CD, поэтому мы по существу определяем: вставлен ли диск с Quake2 в сидюк или нет. Проверка наличия этого файла на диске проверяется путем попытки его открытия с помощью fopen. А для того чтобы удостовериться, что это точно CD-ROM (а не винт), мы используем вызов GetDriveTypeA.
 -результат поиска - путь к Quake2 на CD-ROM, который заносится в глобальный массив cddir', размером MAX_QPATH(см. исходники gamex86.dll файл q_shared.h), поэтому WinMain.2 можно назвать get_cddir'. Её назначение-проверка наличия Quake2 CD-ROM и получение расположения данных на нем. Кстати, их расположение можно установить вручную, через командную строку: quake2.exe +set cddir d:\dir.
    Насчет исходника этой функции я не уверен, но попробовать можно:
//файл ???.c
char cddir_[MAX_QPATH];

char *get_cddir_(void)
{
 static int cd_check_;
 FILE *f;
 char cdpath[MAX_QPATH];

 if(cd_check_)
  return cddir_;
 SetErrorMode(SEM_FAILCRITICALERRORS);

 cdpath[1]=':';
 cdpath[2]='\\';
 cdpath[3]='\0';
 cd_check_=1;

//try to find quake2 CD
 for(cdpath[0]='c';cdpath[0]<='z';cdpath[0]++)
 {
  sprintf(cddir_, "%sinstall\\data", cdpath);
  sprintf(&cdpath[4], "%sinstall\\data\\quake2.exe", cdpath);
  f=fopen(&cdpath[4], "r");
  if(f)
  { 
   fclose(f);
   if(GetDriveTypeA(cdpath)==DRIVE_CDROM)
    return cddir_;
  }
 }

//quake2 CD not founded
 cddir_[0]='\0';
  return NULL;
}
//файл q_shared.h
#define MAX_QPATH 64
    Как обычно теперь будет, здесь лежит тестовая программка. Запустите её вначале со вставленным Quake2 CD-ROM, а потом без него и посмотрите на результат. Примечания: расположение функции get_cddir' в исходниках установить не удалось, поэтому она временно будет находиться в sys_win.c...
    Для полноты описания приведу внешние проявления get_cddir': при запуске q2 кратковременно заводится CD-ROM. Это происходит из-за get_cddir', когда она открывает на нем файл quake2.exe. Не знаю зачем нужна эта информация, но я становлюсь спокойным, когда контролирую поведение программы по полной;)

3. WinMain... Часть вторая.
    Здесь будет происходить разбор
части WinMain, заключенной в красные восклицательные знаки. Этот блок представляет собой сложную циклическую структуру, исходник которой получить очень сложно. Данный блок выполняется только в том случае, если в сидюке находится quake2 CD, иначе он просто пропускается.
    В общих чертах тут происходит вот что: если в командной строке есть определение пути к CD-данным(+set cddir d:\dir или просто cddir d:\dir), то мы выходим из блока, если же в командной строке определение cddir отсутствует, то в неё добавляются еще 3 аргумента: "+set", "cddir" и путь, полученный с помощью get_cddir'. Напомню - все это выполняется только в том случае, если вставлен диск с игрой. Таким образом блок обеспечивает наличие переменной cddir, даже если она не задана в командной строке.
    О том, что в исходниках присутсвует inline функция strcmp, я понял только тогда, когда она встретилась мне дальше в таком виде раз пять.
//файл sys_win.c
/*
==========
WinMain
==========
*/
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 char *cddir;
 int arg=0;

 if(hPrevInstance)
  return 0;
 global_hInstance=hInstance;
 Create_Argv_(lpCmdLine);
 cddir=get_cddir_();

 if(cddir && argc && (argc < MAX_NUM_ARGVS))
 {
  while(arg < argc)
   if(!strcmp(argv[arg++], "cddir")) break;
  if(arg == argc)
  {
   argv[argc++]="+set";
   argv[argc++]="cddir";
   argv[argc++]=cddir;
  }
 }
//...
}
    Эта программа выводит содержимое командной строки сразу после блока (т.е. она проверяет правильность восстановленного исходника). Чтобы протестить программу, запустите её вначале с диском, а потом без него; попробуйте ввести в обоих случаях в командной строке quake2.exe +set cddir d: или quake2.exe cddir e:\data или просто quake2.exe this is test.

    продолжение следует...


Organic /2001/
Hosted by uCoz