00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00116 #include "StdAfx.h"
00117 #include "Configurator.h"
00118 #include "System.h"
00119 #include "AlphaCPU.h"
00120 #include "Serial.h"
00121 #include "Flash.h"
00122 #include "DPR.h"
00123 #include "AliM1543C.h"
00124 #include "Keyboard.h"
00125 #include "DMA.h"
00126 #include "AliM1543C_ide.h"
00127 #include "AliM1543C_usb.h"
00128 #include "DiskFile.h"
00129 #include "DiskDevice.h"
00130 #include "DiskRam.h"
00131 #include "Port80.h"
00132 #include "S3Trio64.h"
00133 #include "Cirrus.h"
00134 #if defined(HAVE_RADEON)
00135 #include "Radeon.h"
00136 #endif
00137 #include "gui/plugin.h"
00138 #if defined(HAVE_PCAP)
00139 #include "DEC21143.h"
00140 #endif
00141 #include "Sym53C895.h"
00142 #include "Sym53C810.h"
00143
00157 CConfigurator::CConfigurator(class CConfigurator* parent, char* name,
00158 char* value, char* text, size_t textlen)
00159 {
00160 if(parent == 0)
00161 {
00162
00163
00164
00165
00166
00167
00168 char* dst = (char*) malloc(textlen + 1);
00169 char* p = dst;
00170 char* q = text;
00171
00172 int cbrace = 0;
00173 enum
00174 {
00175 STATE_NONE,
00176 STATE_C_COMMENT,
00177 STATE_CC_COMMENT,
00178 STATE_STRING
00179 }
00180
00181 state = STATE_NONE;
00182
00183 int state_start = 0;
00184 int line = 1;
00185 int col = 1;
00186 for(int i = 0; i < textlen; i++, q++, col++)
00187 {
00188 if(*q == 0x0a)
00189 {
00190 line++;
00191 col = 1;
00192 }
00193
00194 switch(state)
00195 {
00196 case STATE_NONE:
00197 switch(*q)
00198 {
00199 case '"':
00200 state = STATE_STRING;
00201 state_start = line;
00202 *p++ = *q;
00203 break;
00204
00205 case '/':
00206 if(i == textlen - 1)
00207 FAILURE_2(Configuration,
00208 "Configuration file ends in mid-token at line %d, col %d",
00209 line, col);
00210
00211 if(*(q + 1) == '/')
00212 {
00213 state = STATE_CC_COMMENT;
00214 state_start = line;
00215 }
00216 else if(*(q + 1) == '*')
00217 {
00218 state = STATE_C_COMMENT;
00219 state_start = line;
00220 }
00221 break;
00222
00223 case '{':
00224 cbrace++;
00225 *p++ = *q;
00226 break;
00227
00228 case '}':
00229 if(cbrace == 0)
00230 FAILURE_2(Configuration,
00231 "Too many closed braces at line %d, col %d", line, col);
00232 cbrace--;
00233 *p++ = *q;
00234 break;
00235
00236 default:
00237 if(!isspace(*q))
00238 {
00239 if(isalnum(*q) || *q == '_' || *q == '.' || *q == '=' || *q == ';')
00240 {
00241 *p++ = *q;
00242 }
00243 else
00244 FAILURE_3(Configuration,
00245 "Illegal character %c at line %d, col %d", *q, line, col);
00246 }
00247 }
00248 break;
00249
00250 case STATE_CC_COMMENT:
00251 if(*q == 0x0d || *q == 0x0a)
00252 {
00253 state = STATE_NONE;
00254 state_start = line;
00255 }
00256 break;
00257
00258 case STATE_C_COMMENT:
00259 if(*q == '*')
00260 {
00261 if(i == textlen - 1)
00262 FAILURE_2(Configuration,
00263 "Configuration file ends in mid-comment at line %d, col %d",
00264 line, col);
00265 if(*(q + 1) == '/')
00266 {
00267 state = STATE_NONE;
00268 state_start = line;
00269 }
00270 }
00271 break;
00272
00273 case STATE_STRING:
00274 if(*q == '"')
00275 {
00276 if(i == textlen - 1)
00277 FAILURE_2(Configuration,
00278 "Configuration file ends in mid-string at line %d, col %d",
00279 line, col);
00280 if(*(q + 1) != '"')
00281 {
00282 state_start = line;
00283 state = STATE_NONE;
00284 }
00285 else
00286 {
00287 *p++ = *q;
00288 i++;
00289 q++;
00290 }
00291 }
00292 else if(*q == 0x0a || *q == 0x0d)
00293 FAILURE_2(Configuration,
00294 "Multi-line strings are forbidden at line %d, col %d", line,
00295 col);
00296 *p++ = *q;
00297 break;
00298 }
00299 }
00300
00301 *p++ = 0;
00302
00303 if(state != 0 && state != 1)
00304 {
00305 printf("%%SYS-E-PARSE: unclosed %s. Started on line %d.\n",
00306 state == STATE_C_COMMENT ? "comment" : "string", state_start);
00307 }
00308
00309 if(cbrace != 0)
00310 {
00311 printf("%%SYS-E-PARSE: unclosed brace in file.\n");
00312 }
00313
00314 textlen = strlen(dst);
00315 memcpy(text, dst, textlen + 1);
00316 free(dst);
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 enum
00328 {
00329 STATE_NONE,
00330 STATE_NAME,
00331 STATE_IS,
00332 STATE_VALUE,
00333 STATE_QUOTE,
00334 STATE_CHILD
00335 }
00336
00337 state = STATE_NONE;
00338
00339 char* cur_name;
00340 char* cur_value;
00341
00342 int child_depth = 0;
00343
00344 size_t name_start = 0;
00345 size_t name_len = 0;
00346
00347 size_t value_start = 0;
00348 size_t value_len = 0;
00349
00350 size_t child_start = 0;
00351 size_t child_len = 0;
00352
00353 pParent = parent;
00354 iNumChildren = 0;
00355 iNumValues = 0;
00356 myName = name;
00357 myValue = value;
00358
00359 for(size_t curtext = 0; curtext < textlen; curtext++)
00360 {
00361 switch(state)
00362 {
00363 case STATE_NONE:
00364 if(isalnum((unsigned char) text[curtext]) || text[curtext] == '.'
00365 || text[curtext] == '_')
00366 {
00367 name_start = curtext;
00368 state = STATE_NAME;
00369 }
00370 break;
00371
00372 case STATE_NAME:
00373 if(text[curtext] == '=')
00374 {
00375 state = STATE_IS;
00376 name_len = curtext - name_start;
00377 }
00378 break;
00379
00380 case STATE_IS:
00381 if(isalnum((unsigned char) text[curtext]) || text[curtext] == '.'
00382 || text[curtext] == '_')
00383 {
00384 value_start = curtext;
00385 value_len = 1;
00386 state = STATE_VALUE;
00387 }
00388
00389 if(text[curtext] == '\"')
00390 {
00391 value_start = curtext;
00392 state = STATE_QUOTE;
00393
00394
00395 }
00396 break;
00397
00398 case STATE_VALUE:
00399 if(text[curtext] == ';')
00400 {
00401 value_len = curtext - value_start;
00402 cur_name = (char*) malloc(name_len + 1);
00403 memcpy(cur_name, &text[name_start], name_len);
00404 cur_name[name_len] = '\0';
00405 cur_value = (char*) malloc(value_len + 1);
00406 memcpy(cur_value, &text[value_start], value_len);
00407 cur_value[value_len] = '\0';
00408
00409
00410 strip_string(cur_value);
00411 add_value(cur_name, cur_value);
00412
00413 state = STATE_NONE;
00414 }
00415 else if(text[curtext] == '{')
00416 {
00417 value_len = curtext - value_start;
00418 state = STATE_CHILD;
00419 child_start = curtext + 1;
00420 child_depth = 1;
00421 }
00422 break;
00423
00424 case STATE_QUOTE:
00425 if((text[curtext] == '\"') && (text[curtext + 1] == '\"'))
00426 {
00427 curtext++;
00428 }
00429 else if(text[curtext] == '\"')
00430 {
00431 state = STATE_VALUE;
00432 }
00433 break;
00434
00435 case STATE_CHILD:
00436 if(text[curtext] == '{')
00437 child_depth++;
00438 else if(text[curtext] == '}')
00439 {
00440 child_depth--;
00441 if(!child_depth)
00442 {
00443 cur_name = (char*) malloc(name_len + 1);
00444 memcpy(cur_name, &text[name_start], name_len);
00445 cur_name[name_len] = '\0';
00446 cur_value = (char*) malloc(value_len + 1);
00447 memcpy(cur_value, &text[value_start], value_len);
00448 cur_value[value_len] = '\0';
00449 child_len = curtext - child_start;
00450 state = STATE_NONE;
00451
00452 strip_string(cur_value);
00453
00454 pChildren[iNumChildren++] = new CConfigurator(this, cur_name,
00455 cur_value,
00456 &text[child_start],
00457 child_len);
00458 }
00459 }
00460 }
00461 }
00462
00463 int i;
00464 if(parent == 0)
00465 {
00466 myFlags = 0;
00467 for(i = 0; i < iNumChildren; i++)
00468 {
00469 pChildren[i]->initialize();
00470 }
00471 }
00472 }
00473
00484 CConfigurator::~CConfigurator(void)
00485 { }
00486
00497 char* CConfigurator::strip_string(char* c)
00498 {
00499 char* pos = c;
00500 char* org = c + 1;
00501 bool end_it = false;
00502
00503 if(c[0] == '\"')
00504 {
00505 while(!end_it)
00506 {
00507 if(*org == '\"')
00508 {
00509 org++;
00510 if(*org == '\"')
00511 *pos++ = *org++;
00512 else
00513 end_it = true;
00514 }
00515 else
00516 *pos++ = *org++;
00517 }
00518
00519 *pos = '\0';
00520 }
00521
00522 return c;
00523 }
00524
00528 void CConfigurator::add_value(char* n, char* v)
00529 {
00530 pValues[iNumValues].name = n;
00531 pValues[iNumValues].value = v;
00532 iNumValues++;
00533 }
00534
00539 char* CConfigurator::get_text_value(const char* n, const char* def)
00540 {
00541 int i;
00542 for(i = 0; i < iNumValues; i++)
00543 {
00544 if(!strcmp(pValues[i].name, n))
00545 return pValues[i].value;
00546 }
00547
00548 return (char *)def;
00549 }
00550
00564 bool CConfigurator::get_bool_value(const char* n, bool def)
00565 {
00566 int i;
00567 for(i = 0; i < iNumValues; i++)
00568 {
00569 if(!strcmp(pValues[i].name, n))
00570 {
00571 switch(pValues[i].value[0])
00572 {
00573 case 't':
00574 case 'T':
00575 case 'y':
00576 case 'Y':
00577 case '1':
00578 return true;
00579
00580 case 'f':
00581 case 'F':
00582 case 'n':
00583 case 'N':
00584 case '0':
00585 return false;
00586
00587 default:
00588 FAILURE_2(Configuration, "Illegal boolean value (%s) for %s",
00589 pValues[i].value, n);
00590 }
00591 }
00592 }
00593
00594 return def;
00595 }
00596
00601 u64 CConfigurator::get_num_value(const char* n, bool decimal, u64 def)
00602 {
00603 int i;
00604 u64 multiplier = decimal ? 1000 : 1024;
00605 for(i = 0; i < iNumValues; i++)
00606 {
00607 if(!strcmp(pValues[i].name, n))
00608 {
00609 u64 retval = 0;
00610 u64 partval = 0;
00611 char* val = pValues[i].value;
00612 int j = 0;
00613 for(;;)
00614 {
00615 while(val[j] && strchr("0123456789", val[j]))
00616 {
00617 partval *= 10;
00618 partval += val[j] - '0';
00619 j++;
00620 }
00621
00622 switch(val[j])
00623 {
00624 case 'T':
00625 partval *= multiplier;
00626
00627 case 'G':
00628 partval *= multiplier;
00629
00630 case 'M':
00631 partval *= multiplier;
00632
00633 case 'K':
00634 retval += partval * multiplier;
00635 partval = 0;
00636 j++;
00637 break;
00638
00639 case '\0':
00640 retval += partval;
00641 return retval;
00642
00643 default:
00644 FAILURE_2(Configuration, "Illegal numeric value (%s) for %s",
00645 pValues[i].value, n);
00646 }
00647 }
00648 }
00649 }
00650
00651 return def;
00652 }
00653
00654
00655 #define NO_FLAGS 0
00656
00657 #define IS_CS 1
00658 #define ON_CS 2
00659
00660 #define HAS_PCI 4
00661 #define IS_PCI 8
00662
00663 #define HAS_ISA 16
00664 #define IS_ISA 32
00665
00666 #define HAS_DISK 64
00667 #define IS_DISK 128
00668
00669 #define IS_GUI 256
00670 #define ON_GUI 512
00671
00672 #define IS_NIC 1024
00673
00674 #define N_P 2048 // no parent
00675 typedef struct
00676 {
00677 const char* name;
00678 classid id;
00679 int flags;
00680 } classinfo;
00681
00682 classinfo classes[] = {
00683 {"tsunami", c_tsunami, N_P | IS_CS | HAS_PCI},
00684 {"ev68cb", c_ev68cb, ON_CS},
00685 {"ali", c_ali, IS_PCI | HAS_ISA},
00686 {"ali_ide", c_ali_ide, IS_PCI | HAS_DISK},
00687 {"ali_usb", c_ali_usb, IS_PCI},
00688 {"serial", c_serial, ON_CS},
00689 {"s3", c_s3, IS_PCI | ON_GUI},
00690 {"cirrus", c_cirrus, IS_PCI | ON_GUI},
00691 {"radeon", c_radeon, IS_PCI | ON_GUI},
00692 {"dec21143", c_dec21143, IS_PCI | IS_NIC},
00693 {"sym53c895", c_sym53c895, IS_PCI | HAS_DISK},
00694 {"sym53c810", c_sym53c810, IS_PCI | HAS_DISK},
00695 {"file", c_file, IS_DISK},
00696 {"device", c_device, IS_DISK},
00697 {"ramdisk", c_ramdisk, IS_DISK},
00698 {"sdl", c_sdl, N_P | IS_GUI},
00699 {"win32", c_win32, N_P | IS_GUI},
00700 {"X11", c_x11, N_P | IS_GUI},
00701 {0, c_none, 0}
00702 };
00703
00708 void CConfigurator::initialize()
00709 {
00710 myClassId = c_none;
00711
00712 int i = 0;
00713 int pcibus = 0;
00714 int pcidev = 0;
00715 int idedev = 0;
00716 int idebus = 0;
00717 int number;
00718 char* pt;
00719
00720 for(i = 0; classes[i].id != c_none; i++)
00721 {
00722 if(!strcmp(myValue, classes[i].name))
00723 {
00724 myClassId = classes[i].id;
00725 myFlags = classes[i].flags;
00726 break;
00727 }
00728 }
00729
00730 if(myClassId == c_none)
00731 FAILURE_2(Configuration, "Class %s for %s not known", myValue, myName);
00732
00733 if(myFlags & N_P)
00734 {
00735 if(pParent->get_flags())
00736 FAILURE_2(Configuration, "Class %s for %s needs a parent", myValue, myName);
00737 }
00738
00739 if(myFlags & ON_CS)
00740 {
00741 if(!(pParent->get_flags() & IS_CS))
00742 FAILURE_2(Configuration, "Class %s for %s needs a chipset parent",
00743 myValue, myName);
00744 }
00745
00746 if(myFlags & ON_GUI)
00747 {
00748 if(!bx_gui)
00749 FAILURE_2(Configuration, "Class %s for %s needs a GUI", myValue, myName);
00750 }
00751
00752 if(myFlags & IS_GUI)
00753 {
00754 if(bx_gui)
00755 FAILURE_2(Configuration, "Class %s for %s already found a gui", myValue,
00756 myName);
00757 }
00758
00759 #if !defined(HAVE_PCAP)
00760 if(myFlags & IS_NIC)
00761 FAILURE_2(Configuration,
00762 "Class %s for %s needs compilation with libpcap support", myValue,
00763 myName);
00764 #endif
00765 if(myFlags & IS_PCI)
00766 {
00767 if(strncmp(myName, "pci", 3))
00768 FAILURE_2(Configuration,
00769 "Name %s for class %s should be pci<bus>.<device>", myName,
00770 myValue);
00771 if(!(pParent->get_flags() & HAS_PCI))
00772 {
00773 FAILURE_2(Configuration,
00774 "Class %s for %s should have a pci-bus capable parent device", myValue,
00775 myName);
00776 }
00777
00778 pt = &myName[3];
00779 pcibus = atoi(pt);
00780 pt = strchr(pt, '.');
00781 if(!pt)
00782 FAILURE_2(Configuration,
00783 "Name %s for class %s should be pci<bus>.<device>", myName,
00784 myValue);
00785 pt++;
00786 pcidev = atoi(pt);
00787 }
00788
00789 if(myFlags & IS_DISK)
00790 {
00791 if(strncmp(myName, "disk", 4))
00792 FAILURE_2(Configuration,
00793 "Name %s for class %s should be disk<bus>.<device>", myName,
00794 myValue);
00795 if(!(pParent->get_flags() & HAS_DISK))
00796 {
00797 FAILURE_2(Configuration,
00798 "Class %s for %s should have a disk-controller parent device", myValue,
00799 myName);
00800 }
00801
00802 pt = &myName[4];
00803 idebus = atoi(pt);
00804 pt = strchr(pt, '.');
00805 if(!pt)
00806 FAILURE_2(Configuration,
00807 "Name %s for class %s should be disk<bus>.<device>", myName,
00808 myValue);
00809 pt++;
00810 idedev = atoi(pt);
00811 }
00812
00813 switch(myClassId)
00814 {
00815 case c_tsunami:
00816 myDevice = new CSystem(this);
00817 new CDPR(this, (CSystem*) myDevice);
00818 new CFlash(this, (CSystem*) myDevice);
00819 break;
00820
00821 case c_ev68cb:
00822 myDevice = new CAlphaCPU(this, (CSystem*) pParent->get_device());
00823 break;
00824
00825 case c_ali:
00826 myDevice = new CAliM1543C(this, (CSystem*) pParent->get_device(), pcibus,
00827 pcidev);
00828 new CPort80(this, (CSystem*) pParent->get_device());
00829 new CKeyboard(this, (CSystem*) pParent->get_device());
00830 new CDMA(this, (CSystem*) pParent->get_device());
00831 break;
00832
00833 case c_ali_ide:
00834 myDevice = new CAliM1543C_ide(this, (CSystem*) pParent->get_device(),
00835 pcibus, pcidev);
00836 break;
00837
00838 case c_ali_usb:
00839 myDevice = new CAliM1543C_usb(this, (CSystem*) pParent->get_device(),
00840 pcibus, pcidev);
00841 break;
00842
00843 case c_s3:
00844 myDevice = new CS3Trio64(this, (CSystem*) pParent->get_device(), pcibus,
00845 pcidev);
00846 break;
00847
00848 case c_cirrus:
00849 myDevice = new CCirrus(this, (CSystem*) pParent->get_device(), pcibus,
00850 pcidev);
00851 break;
00852
00853 case c_radeon:
00854 #if defined(HAVE_RADEON)
00855 myDevice = new CRadeon(this, (CSystem*) pParent->get_device(), pcibus,
00856 pcidev);
00857 #else
00858 FAILURE_2(Configuration,
00859 "Class %s for %s needs compilation with Radeon support", myValue,
00860 myName);
00861 #endif
00862 break;
00863
00864 #if defined(HAVE_PCAP)
00865
00866 case c_dec21143:
00867 myDevice = new CDEC21143(this, (CSystem*) pParent->get_device(), pcibus,
00868 pcidev);
00869 break;
00870 #endif
00871
00872 case c_sym53c895:
00873 myDevice = new CSym53C895(this, (CSystem*) pParent->get_device(), pcibus,
00874 pcidev);
00875 break;
00876
00877 case c_sym53c810:
00878 myDevice = new CSym53C810(this, (CSystem*) pParent->get_device(), pcibus,
00879 pcidev);
00880 break;
00881
00882 case c_file:
00883 myDevice = new CDiskFile(this, theSystem,
00884 (CDiskController*) pParent->get_device(), idebus,
00885 idedev);
00886 break;
00887
00888 case c_device:
00889 myDevice = new CDiskDevice(this, theSystem,
00890 (CDiskController*) pParent->get_device(),
00891 idebus, idedev);
00892 break;
00893
00894 case c_ramdisk:
00895 myDevice = new CDiskRam(this, theSystem,
00896 (CDiskController*) pParent->get_device(), idebus,
00897 idedev);
00898 break;
00899
00900 case c_serial:
00901 number = 0;
00902 if(!strncmp(myName, "serial", 6))
00903 {
00904 pt = &myName[6];
00905 number = atoi(pt);
00906 }
00907
00908 myDevice = new CSerial(this, (CSystem*) pParent->get_device(), number);
00909 break;
00910
00911 case c_sdl:
00912 #if defined(HAVE_SDL)
00913 PLUG_load_plugin(this, sdl);
00914 #else
00915 FAILURE_2(Configuration,
00916 "Class %s for %s needs compilation with SDL support", myValue,
00917 myName);
00918 #endif
00919 break;
00920
00921 case c_win32:
00922 #if defined(_WIN32)
00923 PLUG_load_plugin(this, win32);
00924 #else
00925 FAILURE_2(Configuration, "Class %s for %s needs a Win32 platform", myValue,
00926 myName);
00927 #endif
00928 break;
00929
00930 case c_x11:
00931 #if defined(HAVE_X11)
00932 PLUG_load_plugin(this, x11);
00933 #else
00934 FAILURE_2(Configuration, "Class %s for %s needs an X11 platform", myValue,
00935 myName);
00936 #endif
00937 break;
00938
00939 case c_none:
00940 break;
00941 }
00942
00943 for(i = 0; i < iNumChildren; i++)
00944 pChildren[i]->initialize();
00945
00946 if(myFlags & IS_CS)
00947 ((CSystem*) myDevice)->init();
00948 }