Create Xref-Html Frames                    Remove All Frames
file:/home/jivera/wd/pcsx/Misc.c        (Tue Nov 25 22:46:14 2003 )


   1: /*  Pcsx - Pc Psx Emulator
   2:  *  Copyright (C) 1999-2003  Pcsx Team
   3:  *
   4:  *  This program is free software; you can redistribute it and/or modify
   5:  *  it under the terms of the GNU General Public License as published by
   6:  *  the Free Software Foundation; either version 2 of the License, or
   7:  *  (at your option) any later version.
   8:  *
   9:  *  This program is distributed in the hope that it will be useful,
  10:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12:  *  GNU General Public License for more details.
  13:  *
  14:  *  You should have received a copy of the GNU General Public License
  15:  *  along with this program; if not, write to the Free Software
  16:  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17:  */
  18: 
  19: #include <stdio.h>
  20: #include <string.h>
  21: #include <stdlib.h>
  22: #include <stdarg.h>
  23: #include <ctype.h>
  24: 
  25: #include "Coff.h"
  26: #include "PsxCommon.h"
  27: #include "plugins.h"
  28: 
  29: int Log = 0;
  30: 
  31: char *LabelAuthors = { N_(
  32:         "PCSX a psx emulator\n\n"
  33:         "written by:\n"
  34:         "main coder: linuzappz\n"
  35:         "co-coders: shadow\n"
  36:         "ex-coders: Nocomp, Pete Bernett, nik3d\n"
  37:         "Webmaster: AkumaX")
  38: };
  39: 
  40: char *LabelGreets = { N_(
  41:         "Greets to: Duddie, Tratax, Kazzuya, JNS, Bobbi, Psychojak, Shunt,\n"
  42:         "           Keith, DarkWatcher, Xeven, Liquid, Dixon, Prafull\n"
  43:         "Special thanks to:\n"
  44:         "Twin (we Love you twin0r), Roor (love for you too),\n"
  45:         "calb (Thanks for help :) ), now3d (for great help to my psxdev stuff :) )")
  46: };
  47: 
  48: 
  49: // LOAD STUFF
  50: 
  51: #ifdef __MACOSX__
  52: 
  53: #define SWAP(b) b = (((unsigned char*)&b)[0]&0xff) | ((((unsigned char*)&b)[1]&0xff)<<8) | ((((unsigned char*)&b)[2]&0xff)<<16) | (((unsigned char*)&b)[3]<<24);
  54: 
  55: void swapEXE_HEADER(EXE_HEADER* exe) {
  56:         SWAP(exe->text);
  57:         SWAP(exe->data);                    
  58:         SWAP(exe->pc0);
  59:         SWAP(exe->gp0);                     
  60:         SWAP(exe->t_addr);
  61:         SWAP(exe->t_size);
  62:         SWAP(exe->d_addr);                  
  63:         SWAP(exe->d_size);                  
  64:         SWAP(exe->b_addr);                  
  65:         SWAP(exe->b_size);                  
  66:         SWAP(exe->s_addr);
  67:         SWAP(exe->s_size);
  68:         SWAP(exe->SavedSP);
  69:         SWAP(exe->SavedFP);
  70:         SWAP(exe->SavedGP);
  71:         SWAP(exe->SavedRA);
  72:         SWAP(exe->SavedS0);
  73: }
  74: 
  75: #endif
  76: 
  77: #define ISODCL(from, to) (to - from + 1)
  78: 
  79: struct iso_directory_record {
  80:         char length                     [ISODCL (1, 1)]; /* 711 */
  81:         char ext_attr_length            [ISODCL (2, 2)]; /* 711 */
  82:         char extent                     [ISODCL (3, 10)]; /* 733 */
  83:         char size                       [ISODCL (11, 18)]; /* 733 */
  84:         char date                       [ISODCL (19, 25)]; /* 7 by 711 */
  85:         char flags                      [ISODCL (26, 26)];
  86:         char file_unit_size             [ISODCL (27, 27)]; /* 711 */
  87:         char interleave                 [ISODCL (28, 28)]; /* 711 */
  88:         char volume_sequence_number     [ISODCL (29, 32)]; /* 723 */
  89:         unsigned char name_len          [ISODCL (33, 33)]; /* 711 */
  90:         char name                       [1];
  91: };
  92: 
  93: #define btoi(b)         ((b)/16*10 + (b)%16)            /* BCD to u_char */
  94: #define itob(i)         ((i)/10*16 + (i)%10)            /* u_char to BCD */
  95: 
  96: void mmssdd( char *b, char *p )
  97:  {
  98:         int m, s, d;
  99: #if defined(__DREAMCAST__) || defined(__MACOSX__)
 100:         int block = (b[0]&0xff) | ((b[1]&0xff)<<8) | ((b[2]&0xff)<<16) | (b[3]<<24);
 101: #else
 102:         int block = *((int*)b);
 103: #endif
 104:         
 105:         block += 150;
 106:         m = block / 4500;                       // minuten
 107:         block = block - m * 4500;       // minuten rest
 108:         s = block / 75;                         // sekunden
 109:         d = block - s * 75;                     // sekunden rest
 110:         
 111:         m = ( ( m / 10 ) << 4 ) | m % 10;
 112:         s = ( ( s / 10 ) << 4 ) | s % 10;
 113:         d = ( ( d / 10 ) << 4 ) | d % 10;       
 114:         
 115:         p[0] = m;
 116:         p[1] = s;
 117:         p[2] = d;
 118: }
 119: 
 120: #define incTime() \
 121:         time[0] = btoi(time[0]); time[1] = btoi(time[1]); time[2] = btoi(time[2]); \
 122:         time[2]++; \
 123:         if(time[2] == 75) { \
 124:                 time[2] = 0; \
 125:                 time[1]++; \
 126:                 if (time[1] == 60) { \
 127:                         time[1] = 0; \
 128:                         time[0]++; \
 129:                 } \
 130:         } \
 131:         time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]);
 132: 
 133: #define READTRACK() \
 134:         if (CDR_readTrack(time) == -1) return -1; \
 135:         buf = CDR_getBuffer(); if (buf == NULL) return -1;
 136: 
 137: #define READDIR(_dir) \
 138:         READTRACK(); \
 139:         memcpy(_dir, buf+12, 2048); \
 140:  \
 141:         incTime(); \
 142:         READTRACK(); \
 143:         memcpy(_dir+2048, buf+12, 2048);
 144: 
 145: int GetCdromFile(u8 *mdir, u8 *time, s8 *filename) {
 146:         struct iso_directory_record *dir;
 147:         char ddir[4096];
 148:         u8 *buf;
 149:         int i;
 150: 
 151:         i = 0;
 152:         while (i < 4096) {
 153:                 dir = (struct iso_directory_record*) &mdir[i];
 154:                 if (dir->length[0] == 0) {
 155:                         return -1;
 156:                 }
 157:                 i += dir->length[0];
 158: 
 159:                 if (dir->flags[0] & 0x2) { // it's a dir
 160:                         if (!strnicmp((char*)&dir->name[0], filename, dir->name_len[0])) {
 161:                                 if (filename[dir->name_len[0]] != '\\') continue;
 162:                                 
 163:                                 filename+= dir->name_len[0] + 1;
 164: 
 165:                                 mmssdd(dir->extent, (char*)time);
 166:                                 READDIR(ddir);
 167:                                 i = 0;
 168:                         }
 169:                 } else {
 170:                         if (!strnicmp((char*)&dir->name[0], filename, strlen(filename))) {
 171:                                 mmssdd(dir->extent, (char*)time);
 172:                                 break;
 173:                         }
 174:                 }
 175:         }
 176:         return 0;
 177: }
 178: 
 179: int LoadCdrom() {
 180:         EXE_HEADER tmpHead;
 181:         struct iso_directory_record *dir;
 182:         u8 time[4],*buf;
 183:         u8 mdir[4096];
 184:         s8 exename[256];
 185:         int i;
 186: 
 187:         if (!Config.HLE) {
 188:                 psxRegs.pc = psxRegs.GPR.n.ra;
 189:                 return 0;
 190:         }
 191: 
 192:         time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
 193: 
 194:         READTRACK();
 195: 
 196:         // skip head and sub, and go to the root directory record
 197:         dir = (struct iso_directory_record*) &buf[12+156]; 
 198: 
 199:         mmssdd(dir->extent, (char*)time);
 200: 
 201:         READDIR(mdir);
 202: 
 203:         if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) {
 204:                 if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1;
 205: 
 206:                 READTRACK();
 207:         }
 208:         else {
 209:                 READTRACK();
 210: 
 211:                 sscanf((char*)buf+12, "BOOT = cdrom:\\%s", exename);
 212:                 if (GetCdromFile(mdir, time, exename) == -1) {
 213:                         sscanf((char*)buf+12, "BOOT = cdrom:%s", exename);
 214:                         if (GetCdromFile(mdir, time, exename) == -1) {
 215:                                 char *ptr = strstr(buf+12, "cdrom:");
 216:                                 for (i=0; i<32; i++) {
 217:                                         if (ptr[i] == ' ') continue;
 218:                                         if (ptr[i] == '\\') continue;
 219:                                 }
 220:                                 strcpy(exename, ptr);
 221:                                 if (GetCdromFile(mdir, time, exename) == -1)
 222:                                         return -1;
 223:                         }
 224:                 }
 225: 
 226:                 READTRACK();
 227:         }
 228: 
 229:         memcpy(&tmpHead, buf+12, sizeof(EXE_HEADER));
 230: 
 231: #ifdef __MACOSX__
 232:         swapEXE_HEADER(&tmpHead);
 233: #endif
 234: 
 235:         psxRegs.pc = tmpHead.pc0;
 236:         psxRegs.GPR.n.gp = tmpHead.gp0;
 237:         psxRegs.GPR.n.sp = tmpHead.s_addr; 
 238:         if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
 239: 
 240:         while (tmpHead.t_size) {
 241:                 void *ptr = (void *)PSXM(tmpHead.t_addr);
 242: 
 243:                 incTime();
 244:                 READTRACK();
 245: 
 246:                 if (ptr != NULL) memcpy(ptr, buf+12, 2048);
 247: 
 248:                 tmpHead.t_size -= 2048;
 249:                 tmpHead.t_addr += 2048;
 250:         }
 251: 
 252:         return 0;
 253: }
 254: 
 255: int LoadCdromFile(char *filename, EXE_HEADER *head) {
 256:         struct iso_directory_record *dir;
 257:         u8 time[4],*buf;
 258:         u8 mdir[4096], exename[256];
 259:         u32 size, addr;
 260: 
 261:         sscanf(filename, "cdrom:\\%s", exename);
 262: 
 263:         time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
 264: 
 265:         READTRACK();
 266: 
 267:         // skip head and sub, and go to the root directory record
 268:         dir = (struct iso_directory_record*) &buf[12+156]; 
 269: 
 270:         mmssdd(dir->extent, (char*)time);
 271: 
 272:         READDIR(mdir);
 273: 
 274:         if (GetCdromFile(mdir, time, exename) == -1) return -1;
 275: 
 276:         READTRACK();
 277: 
 278:         memcpy(head, buf+12, sizeof(EXE_HEADER));
 279:         size = head->t_size;
 280:         addr = head->t_addr;
 281: 
 282:         while (size) {
 283:                 incTime();
 284:                 READTRACK();
 285: 
 286:                 memcpy((void *)PSXM(addr), buf+12, 2048);
 287: 
 288:                 size -= 2048;
 289:                 addr += 2048;
 290:         }
 291: 
 292:         return 0;
 293: }
 294: 
 295: int CheckCdrom() {
 296:         struct iso_directory_record *dir;
 297:         unsigned char time[4],*buf;
 298:         unsigned char mdir[4096];
 299:         char exename[256];
 300:         int i, c;
 301: 
 302:         time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
 303: 
 304:         READTRACK();
 305: 
 306:         strncpy(CdromLabel, buf+52, 11);
 307: 
 308:         // skip head and sub, and go to the root directory record
 309:         dir = (struct iso_directory_record*) &buf[12+156]; 
 310: 
 311:         mmssdd(dir->extent, (char*)time);
 312: 
 313:         READDIR(mdir);
 314: 
 315:         if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
 316:                 READTRACK();
 317: 
 318:                 sscanf((char*)buf+12, "BOOT = cdrom:\\%s", exename);
 319:                 if (GetCdromFile(mdir, time, exename) == -1) {
 320:                         sscanf((char*)buf+12, "BOOT = cdrom:%s", exename);
 321:                         if (GetCdromFile(mdir, time, exename) == -1) {
 322:                                 char *ptr = strstr(buf+12, "cdrom:");
 323:                                 for (i=0; i<32; i++) {
 324:                                         if (ptr[i] == ' ') continue;
 325:                                         if (ptr[i] == '\\') continue;
 326:                                 }
 327:                                 strcpy(exename, ptr);
 328:                                 if (GetCdromFile(mdir, time, exename) == -1)
 329:                                         return 0;
 330:                         }
 331:                 }
 332:         }
 333: 
 334:         i = strlen(exename);
 335:         if (i >= 2) {
 336:                 if (exename[i - 2] == ';') i-= 2;
 337:                 c = 8; i--;
 338:                 while (i >= 0 && c >= 0) {
 339:                         if (isalnum(exename[i])) CdromId[c--] = exename[i];
 340:                         i--;
 341:                 }
 342:         }
 343: 
 344:         if (Config.PsxAuto) { // autodetect system (pal or ntsc)
 345:                 if (strstr(exename, "ES") != NULL)
 346:                         Config.PsxType = 1; // pal
 347:                 else Config.PsxType = 0; // ntsc
 348:         }
 349:         psxUpdateVSyncRate();
 350:         if (CdromLabel[0] == ' ') {
 351:                 strcpy(CdromLabel, CdromId);
 352:         }
 353:         SysPrintf("*PCSX*: CdromLabel: %s\n", CdromLabel);
 354:         SysPrintf("*PCSX*: CdromId: %s\n", CdromId);
 355: 
 356:         return 0;
 357: }
 358: 
 359: #define PSX_EXE     1
 360: #define CPE_EXE     2
 361: #define COFF_EXE    3
 362: #define INVALID_EXE 4
 363: 
 364: static int PSXGetFileType(FILE *f) {
 365:     unsigned long current;
 366:     unsigned long mybuf[2048];
 367:     EXE_HEADER *exe_hdr;
 368:     FILHDR *coff_hdr;
 369: 
 370:     current = ftell(f);
 371:     fseek(f,0L,SEEK_SET);
 372:     fread(mybuf,2048,1,f);
 373:     fseek(f,current,SEEK_SET);
 374: 
 375:     exe_hdr = (EXE_HEADER *)mybuf;
 376:     if (memcmp(exe_hdr->id,"PS-X EXE",8)==0)
 377:         return PSX_EXE;
 378: 
 379:     if (mybuf[0]=='C' && mybuf[1]=='P' && mybuf[2]=='E')
 380:         return CPE_EXE;
 381: 
 382:     coff_hdr = (FILHDR *)mybuf;
 383:     if (coff_hdr->f_magic == 0x0162)
 384:         return COFF_EXE;
 385: 
 386:     return INVALID_EXE;
 387: }
 388: 
 389: int Load(char *ExePath) {
 390:         FILE *tmpFile;
 391:         EXE_HEADER tmpHead;
 392:         int type;
 393: 
 394:         strncpy(CdromId, "SLUS99999", 9);
 395:         strncpy(CdromLabel, "SLUS_999.99", 11);
 396: 
 397:     tmpFile = fopen(ExePath,"rb");
 398:         if (tmpFile == NULL) { SysMessage(_("Error opening file: %s"), ExePath); return 0; }
 399: 
 400:     type = PSXGetFileType(tmpFile);
 401:     switch (type) {
 402:         case PSX_EXE:
 403:                 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
 404:                     fseek(tmpFile, 0x800, SEEK_SET);            
 405:                         fread((void *)PSXM(tmpHead.t_addr), tmpHead.t_size,1,tmpFile);
 406:                         fclose(tmpFile);
 407:                         psxRegs.pc = tmpHead.pc0;
 408:                         psxRegs.GPR.n.gp = tmpHead.gp0;
 409:                         psxRegs.GPR.n.sp = tmpHead.s_addr; 
 410:                         if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
 411:                 break;
 412:         case CPE_EXE:
 413:                 SysMessage(_("Pcsx found that you wanna use a CPE file. CPE files not supported"));
 414:                         break;
 415:         case COFF_EXE:
 416:                 SysMessage(_("Pcsx found that you wanna use a COFF file. COFF files not supported"));
 417:                         break;
 418:         case INVALID_EXE:
 419:                 SysMessage(_("This file is not a psx file"));
 420:                         break;
 421:         }
 422:         return 1;
 423: }
 424: 
 425: // STATES
 426: 
 427: const char PcsxHeader[32] = "STv3 PCSX v" PCSX_VERSION;
 428: 
 429: int SaveState(char *file) {
 430:         gzFile f;
 431:         GPUFreeze_t *gpufP;
 432:         SPUFreeze_t *spufP;
 433:         int Size;
 434:         unsigned char *pMem;
 435: 
 436:         f = gzopen(file, "wb");
 437:         if (f == NULL) return -1;
 438: 
 439:         gzwrite(f, (void*)PcsxHeader, 32);
 440: 
 441:         pMem = (unsigned char *) malloc(128*96*3);
 442:         if (pMem == NULL) return -1;
 443:         GPU_getScreenPic(pMem);
 444:         gzwrite(f, pMem, 128*96*3);
 445:         free(pMem);
 446: 
 447:         gzwrite(f, psxM, 0x00200000);
 448:         gzwrite(f, psxR, 0x00080000);
 449:         gzwrite(f, psxH, 0x00010000);
 450:         gzwrite(f, (void*)&psxRegs, sizeof(psxRegs));
 451: 
 452:         // gpu
 453:         gpufP = (GPUFreeze_t *) malloc(sizeof(GPUFreeze_t));
 454:         gpufP->ulFreezeVersion = 1;
 455:         GPU_freeze(1, gpufP);
 456:         gzwrite(f, gpufP, sizeof(GPUFreeze_t));
 457:         free(gpufP);
 458: 
 459:         // spu
 460:         spufP = (SPUFreeze_t *) malloc(16);
 461:         SPU_freeze(2, spufP);
 462:         Size = spufP->Size; gzwrite(f, &Size, 4);
 463:         free(spufP);
 464:         spufP = (SPUFreeze_t *) malloc(Size);
 465:         SPU_freeze(1, spufP);
 466:         gzwrite(f, spufP, Size);
 467:         free(spufP);
 468: 
 469:         sioFreeze(f, 1);
 470:         cdrFreeze(f, 1);
 471:         psxHwFreeze(f, 1);
 472:         psxRcntFreeze(f, 1);
 473:         mdecFreeze(f, 1);
 474: 
 475:         gzclose(f);
 476: 
 477:         return 0;
 478: }
 479: 
 480: int LoadState(char *file) {
 481:         gzFile f;
 482:         GPUFreeze_t *gpufP;
 483:         SPUFreeze_t *spufP;
 484:         int Size;
 485:         char header[32];
 486: 
 487:         f = gzopen(file, "rb");
 488:         if (f == NULL) return -1;
 489: 
 490:         psxCpu->Reset();
 491: 
 492:         gzread(f, header, 32);
 493: 
 494:         if (strncmp("STv3 PCSX", header, 9)) { gzclose(f); return -1; }
 495: 
 496:         gzseek(f, 128*96*3, SEEK_CUR);
 497: 
 498:         gzread(f, psxM, 0x00200000);
 499:         gzread(f, psxR, 0x00080000);
 500:         gzread(f, psxH, 0x00010000);
 501:         gzread(f, (void*)&psxRegs, sizeof(psxRegs));
 502: 
 503:         // gpu
 504:         gpufP = (GPUFreeze_t *) malloc (sizeof(GPUFreeze_t));
 505:         gzread(f, gpufP, sizeof(GPUFreeze_t));
 506:         GPU_freeze(0, gpufP);
 507:         free(gpufP);
 508: 
 509:         // spu
 510:         gzread(f, &Size, 4);
 511:         spufP = (SPUFreeze_t *) malloc (Size);
 512:         gzread(f, spufP, Size);
 513:         SPU_freeze(0, spufP);
 514:         free(spufP);
 515: 
 516:         sioFreeze(f, 0);
 517:         cdrFreeze(f, 0);
 518:         psxHwFreeze(f, 0);
 519:         psxRcntFreeze(f, 0);
 520:         mdecFreeze(f, 0);
 521: 
 522:         gzclose(f);
 523: 
 524:         return 0;
 525: }
 526: 
 527: int CheckState(char *file) {
 528:         gzFile f;
 529:         char header[32];
 530: 
 531:         f = gzopen(file, "rb");
 532:         if (f == NULL) return -1;
 533: 
 534:         psxCpu->Reset();
 535: 
 536:         gzread(f, header, 32);
 537: 
 538:         gzclose(f);
 539: 
 540:         if (strncmp("STv3 PCSX", header, 9)) return -1;
 541: 
 542:         return 0;
 543: }
 544: 
 545: // NET Function Helpers
 546: 
 547: int SendPcsxInfo() {
 548:         if (NET_recvData == NULL || NET_sendData == NULL)
 549:                 return 0;
 550: 
 551: //      SysPrintf("SendPcsxInfo\n");
 552: 
 553:         NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
 554:         NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
 555:         NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
 556:         NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
 557:         NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
 558:         NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
 559: 
 560: //      SysPrintf("Send OK\n");
 561: 
 562:         return 0;
 563: }
 564: 
 565: int RecvPcsxInfo() {
 566:         int tmp;
 567: 
 568:         if (NET_recvData == NULL || NET_sendData == NULL)
 569:                 return 0;
 570: 
 571: //      SysPrintf("RecvPcsxInfo\n");
 572: 
 573:         NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
 574:         NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
 575:         NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
 576:         NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
 577:         NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
 578:         psxUpdateVSyncRate();
 579: 
 580:         SysUpdate();
 581: 
 582:         tmp = Config.Cpu;
 583:         NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
 584:         if (tmp != Config.Cpu) {
 585:                 psxCpu->Shutdown();
 586: #ifdef PSXREC
 587:                 if (Config.Cpu) 
 588:                          psxCpu = &psxInt;
 589:                 else psxCpu = &psxRec;
 590: #else
 591:                 psxCpu = &psxInt;
 592: #endif
 593:                 if (psxCpu->Init() == -1) {
 594:                         SysClose(); return -1;
 595:                 }
 596:                 psxCpu->Reset();
 597:         }
 598: 
 599: //      SysPrintf("Recv OK\n");
 600: 
 601:         return 0;
 602: }
 603: 
 604: 
 605: void __Log(char *fmt, ...) {
 606:         va_list list;
 607: #ifdef LOG_STDOUT
 608:         char tmp[1024];
 609: #endif
 610: 
 611:         va_start(list, fmt);
 612: #ifndef LOG_STDOUT
 613:         vfprintf(emuLog, fmt, list);
 614: #else
 615:         vsprintf(tmp, fmt, list);
 616:         SysPrintf(tmp);
 617: #endif
 618:         va_end(list);
 619: }
 620: 
 621: typedef struct {
 622:         char id[8];
 623:         char name[64];
 624: } LangDef;
 625: 
 626: LangDef sLangs[] = {
 627:         { "ar", N_("Arabic") },
 628:         { "ca", N_("Catalan") },
 629:         { "de", N_("German") },
 630:         { "el", N_("Greek") },
 631:         { "en", N_("English") },
 632:         { "es", N_("Spanish") },
 633:         { "fr_FR", N_("French") },
 634:         { "it_IT", N_("Italian") },
 635:         { "pt", N_("Portuguese") },
 636:         { "ro", N_("Romanian") },
 637:         { "ru", N_("Russian") },
 638:         { "", "" },
 639: };
 640: 
 641: 
 642: char *ParseLang(char *id) {
 643:         int i=0;
 644: 
 645:         while (sLangs[i].id[0] != 0) {
 646:                 if (!strcmp(id, sLangs[i].id))
 647:                         return _(sLangs[i].name);
 648:                 i++;
 649:         }
 650: 
 651:         return id;
 652: }
 653: 
 654: /* arch-tag: Matthew Dempsky Wed Oct 15 10:34:43 CST 2003 (Misc.c)
 655:  */
 656: 








































Html form generated by Xrefactory version 1.6.4 on Fri Dec 12 20:52:56 2003
Trial version.