Configurator.cpp

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * WWW    : http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  * 
00021  * Although this is not required, the author would appreciate being notified of, 
00022  * and receiving any modifications you may make to the source code that might serve
00023  * the general public.
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     /* Phase 1:  Basic Syntax Check & Strip [first pass only]
00164      * - Make sure quotes and comments are closed.
00165      * - Make sure braces are balanced
00166      * - remove everything except configuration data.
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:  // c++ 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:   // 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:      // 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   /* Phase 2: Parse the file [every time]
00320    * The data is in a very compressed form at this point.  We also
00321    * know some important things about the data:
00322    * - There is no whitespace (except in strings)
00323    * - the braces are all closed
00324    * - comments have been removed.
00325    * - strings are valid.
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         //curtext--;
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         //        printf("Calling strip_string for  <%s>. \n",cur_value);
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 // THIS IS WHERE THINGS GET COMPLICATED...
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 }

SourceForge.net Logo
Project space on SourceForge.net