home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d502 / cells.lha / CELLS / CELLSSource.lzh / cRead.c < prev    next >
C/C++ Source or Header  |  1991-04-20  |  21KB  |  780 lines

  1. /*
  2.  *  CELLS       An Implementation of the WireWorld cellular automata
  3.  *              as described in Scientific American, Jan 1990.
  4.  *
  5.  *              Copyright 1990 by Davide P. Cervone.
  6.  *  You may use this code, provided this copyright notice is kept intact.
  7.  *  See the CELLS.HELP file for complete information on distribution conditions.
  8.  */
  9.  
  10. /*
  11.  *  File:  cRead.c          Handles reading Ciruit and Library files.
  12.  */
  13.  
  14.  
  15. #include "cGadget.h"
  16. #include "cRequest.h"
  17. #include "cParts.h"
  18. #include <stdio.h>
  19.  
  20. char FileName[MAXFNAME];                /* current circuit's name */
  21.  
  22. static FILE *theFile;                   /* the file being read */
  23. static int noError,EndOfFile;           /* error flags */
  24. static char Line[256];                  /* input buffer */
  25. static char *NextWord,*Parameters;      /* pointers to parts of commands */
  26. static short LinePos;                   /* current character being read */
  27. static int TooWide;                     /* TRUE if circuit is too wide */
  28. static LIBRARY *LibList;                /* list of libraries to load */
  29.  
  30. #define MAXERROR        8
  31.  
  32. #define CELL_UNKNOWN    0xFF
  33.  
  34. #define COM_UNKNOWN     0
  35. #define COM_CIRCUIT     1
  36. #define COM_LIBRARY     2
  37. #define COM_PART        3
  38. #define COM_CELLSIZE    4
  39. #define COM_ORIGIN      5
  40. #define COM_VIEW        6
  41. #define COM_INCLUDE     7
  42. #define COM_BLANKLINE   8
  43. #define COM_CELLS       9
  44. #define COM_EOF         10
  45.  
  46. /*
  47.  *  Command character strings
  48.  */
  49.  
  50. static char *Command[] =
  51.    {"Circuit","Library","Part","CellSize","Origin","View","Include"};
  52.  
  53.  
  54. static char LoadMessage[] = "Continuing with Load...";
  55. #define LOADMESSAGE  LoadMessage
  56.  
  57.  
  58. /*
  59.  *  ReadError()
  60.  *
  61.  *  Put up the error message and increment the error count
  62.  *  If too many errors occurred, ask if the user wants to quit loading
  63.  *  If not, put up the info message again
  64.  */
  65.  
  66. void ReadError(s,x1,x2,x3)
  67. char *s,*x1,*x2,*x3;
  68. {
  69.    static int ErrorCount = 0;
  70.  
  71.    DoError(s,x1,x2,x3);
  72.    ErrorCount++;
  73.    if (ErrorCount == MAXERROR)
  74.    {
  75.       noError = DoQuestion("%d Errors:  Continue Loading?",ErrorCount);
  76.       ErrorCount = 0;
  77.    }
  78.    if (noError) DoInfoMessage(LOADMESSAGE);
  79. }
  80.  
  81.  
  82. /*
  83.  *  ReadNextLine()
  84.  *
  85.  *  If no errors have occurred
  86.  *    If we can read another line from the file
  87.  *      set the line position to the start of the line
  88.  *    otherwise
  89.  *      if we're at the end of the file, indicate that
  90.  *      otherwise put up an error message
  91.  *  Otherwise consider ourselves at the end of the file (don't read any more)
  92.  */
  93.  
  94. static void ReadNextLine()
  95. {
  96.    if (noError)
  97.    {
  98.       if (fgets(Line,256,theFile))
  99.       {
  100.          LinePos = 0;
  101.       } else {
  102.          if (feof(theFile))
  103.          {
  104.             EndOfFile = TRUE;
  105.          } else {
  106.             DosError("Read","Line");
  107.             noError = FALSE;
  108.          }
  109.       }
  110.    } else {
  111.       EndOfFile = TRUE;
  112.    }
  113. }
  114.  
  115.  
  116. /*
  117.  *  GetNextWord()
  118.  *
  119.  *  While still looking and not at the end of the file
  120.  *    if the the rest of the line is a comment, skip it
  121.  *    if the next character is a space or tab, go to the next character
  122.  *    otherwise we've found the first letter of the next word
  123.  *  Mark the start of the word
  124.  *  Find the end of the word and mark it as the beginning of the parameters
  125.  *  Find the trailing '\n' and convert it to a NULL
  126.  */
  127.  
  128. static void GetNextWord()
  129. {
  130.    int NotDone = TRUE;
  131.    char *s;
  132.  
  133.    while (NotDone && !EndOfFile)
  134.    {
  135.       if (Line[LinePos] == '*' || Line[LinePos] == '!') ReadNextLine();
  136.       else if (Line[LinePos] == ' ' || Line[LinePos] == '\t') LinePos++;
  137.       else NotDone = FALSE;
  138.    }
  139.    NextWord = &Line[LinePos];
  140.    while (Line[LinePos] != ' ' && Line[LinePos] != '\n' && Line[LinePos])
  141.       LinePos++;
  142.    s = Parameters = &Line[LinePos+1];
  143.    while (*s && *s != '\n') s++;
  144.    if (*s == '\n') *s = 0;
  145. }
  146.  
  147.  
  148. /*
  149.  *  GetNextCommand()
  150.  *
  151.  *  Get the next word and its parameters
  152.  *  If we're not at the end of the file
  153.  *    check if the first character of the command is a state symbol; if not
  154.  *      if we actually have some characters
  155.  *        temporarily mark the end of the word with a NULL
  156.  *        and look through the command list for a match
  157.  *        then put back the original separating character
  158.  *        (if no match is made, i will be decremented to COM_UNKNOWN)
  159.  */
  160.  
  161. static int GetNextCommand()
  162. {
  163.    short i = COM_EOF;
  164.    int NotDone = TRUE;
  165.    char c;
  166.  
  167.    GetNextWord();
  168.    if (!EndOfFile)
  169.    {
  170.       i--; c = *NextWord;
  171.       if (c != '[' && c != '=' && c != '#' && c != '.')
  172.       {
  173.          i--;
  174.          if (*NextWord && *NextWord != '\n')
  175.          {
  176.             c = Line[LinePos]; Line[LinePos] = 0;
  177.             while (i>0 && NotDone)
  178.                if (stricmp(NextWord,Command[i-1]) == 0)
  179.                    NotDone = FALSE; else i--;
  180.             Line[LinePos] = c;
  181.          }
  182.       }
  183.    }
  184.    return(i);
  185. }
  186.  
  187.  
  188. /*
  189.  *  AddLineToGrid()
  190.  *
  191.  *  Start at the beginning of the line
  192.  *  If the current Y position is past the bottom of the grid, give an error
  193.  *  otherwise
  194.  *    while there is more to do on the line
  195.  *      find the cell type of the next character on the line:
  196.  *        if we're at the end of the line, we're done
  197.  *        '[]' = WIRE  '##' = HEAD  '==' = TAIL  '. ' and '  ' = BLANK
  198.  *      If we're not at the end of the line
  199.  *        if the cell is not identified, give a message
  200.  *        otherwise, id the cell is within the array, set the cell state
  201.  *        move on the the next position in the array
  202.  *    If the circuit is too wide for the array, give a warning
  203.  *  return the new Y position
  204.  */
  205.  
  206. static short AddLineToGrid(Grid,Y,Ox,Oy,blank)
  207. UBYTE Grid[];
  208. short Ox,Oy;
  209. short Y;
  210. int blank;
  211. {
  212.    short X = Ox;
  213.    short i = X + (Y + Oy) * MAXGRIDW;
  214.    int NotDone = TRUE;
  215.    UBYTE CellType;
  216.  
  217.    LinePos = 0;
  218.    if (Y + Oy >= MAXGRIDH)
  219.    {
  220.       if (Y + Oy == MAXGRIDH)
  221.          ReadError("Circuit Exceeds Maximum Height of %d",MAXGRIDH);
  222.    } else {
  223.       while (NotDone)
  224.       {
  225.          CellType = CELL_UNKNOWN;
  226.          switch(Line[LinePos++])
  227.          {
  228.             case '\n':
  229.             case '\0':
  230.                NotDone = FALSE;
  231.                break;
  232.  
  233.             case '[':
  234.                if (Line[LinePos++] == ']') CellType = WIRE;
  235.                break;
  236.  
  237.             case '#':
  238.                if (Line[LinePos++] == '#') CellType = HEAD;
  239.                break;
  240.  
  241.             case '=':
  242.                if (Line[LinePos++] == '=') CellType = TAIL;
  243.                break;
  244.  
  245.             case ' ':
  246.                if (Line[LinePos++] == ' ') CellType = blank;
  247.                break;
  248.  
  249.             case '.':
  250.                if (Line[LinePos++] == ' ') CellType = BLANK;
  251.  
  252.             default:
  253.                LinePos++;
  254.                break;
  255.          }
  256.          if (NotDone)
  257.          {
  258.             if (CellType == CELL_UNKNOWN)
  259.                ReadError("Unknown Cell Symbol '%c%c'",
  260.                   Line[LinePos-2],Line[LinePos-1]);
  261.               else if (i < ARRAYSIZE)
  262.                Grid[i] = CellType;
  263.             i++; X++;
  264.          }
  265.       }
  266.       if (X >= MAXGRIDW && TooWide == FALSE)
  267.       {
  268.          ReadError("Circuit Exceeds Maximum Width of %d",MAXGRIDW);
  269.          TooWide = TRUE;
  270.       }
  271.    }
  272.    return((short)(Y+1));
  273. }
  274.  
  275.  
  276. /*
  277.  *  LoadLibrary()
  278.  *
  279.  *  If the library is being loaded as the Parts List
  280.  *    put up the proper message and use the proper library strucutre
  281.  *  Otherwise put up the standard load library message
  282.  *  Clear the flags
  283.  *  While there is more to the library
  284.  *    Read the next line from the file and the next command
  285.  *    If the command is other than another row of cells or a blank line
  286.  *      Finish any part in progress and clear the part flags
  287.  *    Do the correct command:
  288.  *
  289.  *      LIBRARY:
  290.  *        give an error
  291.  *
  292.  *      PART:
  293.  *        if the part has a name
  294.  *          clear the scratch grid and set the flags for starting a part
  295.  *          copy the name of the part into the part name string
  296.  *        otherwise warn the user that the part needs a name
  297.  *
  298.  *      CIRCUIT, CELLSIZE, ORIGIN, VIEW, INCLUDE:
  299.  *        these are legal only in Circuit files, so give an error
  300.  *
  301.  *      CELLS:
  302.  *        if a part is being made, add the line to the parts' grid
  303.  *        otherwise, if we haven't already warned the user, do so
  304.  *
  305.  *      BLANKLINE:
  306.  *        increment the position in the grid
  307.  *
  308.  *      UNKNOWN
  309.  *        warn the user about the bad command in the file
  310.  */
  311.  
  312. static void LoadLibraryParts(theLibrary)
  313. LIBRARY *theLibrary;
  314. {
  315.    int Command;
  316.    short Y = 0;
  317.    UBYTE *Grid = NULL;
  318.    char PartName[MAXPNAME];
  319.    int MakingPart;
  320.    int NoMessage = TRUE;
  321.  
  322.    if (theLibrary->Flags & PL_ASPARTS)
  323.    {
  324.       DoInfoMessage("Loading Library '%s' as Parts",theLibrary->Name);
  325.       theLibrary = &PartsList;
  326.    } else {
  327.       DoInfoMessage("Loading Library '%s'",theLibrary->Name);
  328.    }
  329.    MakingPart = FALSE; TooWide = FALSE;
  330.    while (!EndOfFile)
  331.    {
  332.       ReadNextLine(); Command = GetNextCommand();
  333.       if (Command != COM_CELLS && Command != COM_BLANKLINE)
  334.       {
  335.          if (MakingPart) FinishPart(PartName,theLibrary);
  336.          if (Grid && Y) Grid = NULL; Y = 0;
  337.          MakingPart = 0;
  338.       }
  339.       switch(Command)
  340.       {
  341.          case COM_LIBRARY:
  342.             ReadError("LIBRARY Command must be First in the File");
  343.             break;
  344.  
  345.          case COM_PART:
  346.             if (Parameters[0])
  347.             {
  348.                ZeroGrid(NewGen); Y = 0; Grid = NewGen;
  349.                NoMessage = TRUE; MakingPart = TRUE; TooWide = FALSE; 
  350.                strcpy(PartName,Parameters);
  351.             } else {
  352.                ReadError("Missing Name in PART command");
  353.             }
  354.             break;
  355.                
  356.          case COM_CIRCUIT:
  357.          case COM_CELLSIZE:
  358.          case COM_ORIGIN:
  359.          case COM_VIEW:
  360.          case COM_INCLUDE:
  361.             ReadError("Command '%s' Invalid in LIBRARY",NextWord);
  362.             break;
  363.  
  364.          case COM_CELLS:
  365.             if (Grid)
  366.             {
  367.                Y = AddLineToGrid(Grid,Y,0,0,0);
  368.             } else if (NoMessage) {
  369.                ReadError("Missing PART Command?");
  370.                NoMessage = FALSE;
  371.             }
  372.             break;
  373.  
  374.          case COM_BLANKLINE:
  375.             if (Y) Y++;
  376.             break;
  377.  
  378.          case COM_UNKNOWN:
  379.             *(Parameters-1) = 0;
  380.             ReadError("Unknown Command '%s'",NextWord);
  381.             break;
  382.       }
  383.    }
  384. }
  385.  
  386.  
  387. /*
  388.  *  IncludeLibrary()
  389.  *
  390.  *  Get a new Library structure, if possible, and link it into the
  391.  *  list of libraries to load
  392.  */
  393.  
  394. static void IncludeLibrary(Name)
  395. char *Name;
  396. {
  397.    LIBRARY *theLibrary;
  398.    extern LIBRARY *NewLibrary();
  399.    
  400.    theLibrary = NewLibrary(Name);
  401.    if (theLibrary)
  402.    {
  403.       theLibrary->Next = LibList;
  404.       LibList = theLibrary;
  405.    }
  406. }
  407.  
  408.  
  409. /*
  410.  *  LoadLibList()
  411.  *
  412.  *  For each library in the list
  413.  *    Find the location of the library (sorted) into the library list
  414.  *    If it does not already appear
  415.  *      if we can't open the specified library
  416.  *        inform the user of the problem
  417.  *        free the library structure
  418.  *      otherwise
  419.  *        clear the error flags and read the first line of the library
  420.  *        find the first command in the library
  421.  *        if the first command is a LIBRARY command
  422.  *          load the library's parts and close the file
  423.  *          warn the user if any errors occur
  424.  *        otherwise
  425.  *          close the file and warn the user it is not a library
  426.  *        If the library has parts in it
  427.  *          link the library into the list
  428.  *        otherwise
  429.  *          free the library structure
  430.  *    otherwise (already loaded) warn the user about it and free the duplicate
  431.  *  restore the error status
  432.  */
  433.  
  434. static void LoadLibList()
  435. {
  436.    LIBRARY *theLibrary;
  437.    LIBRARY *PrevLib;
  438.    LIBRARY **LibPtr;
  439.    int OldNoError = noError;
  440.    int Command;
  441.    char ErrorName[MAXFNAME];
  442.    
  443.    while (theLibrary = LibList)
  444.    {
  445.       LibList = LibList->Next;
  446.       FindListPos(theLibrary->Name,&(FirstLibrary),&PrevLib,&LibPtr);
  447.       if (LibPtr)
  448.       {
  449.          if ((theFile = fopen(theLibrary->Name,"r")) == NULL)
  450.          {
  451.             sprintf(ErrorName,"Library '%s'",theLibrary->Name);
  452.             DosError("Open",ErrorName);
  453.             DoInfoMessage(LOADMESSAGE);
  454.             FreeLibrary(theLibrary);
  455.          } else {
  456.             noError = TRUE; EndOfFile = FALSE; ReadNextLine();
  457.             while ((Command = GetNextCommand()) == COM_BLANKLINE)
  458.                ReadNextLine();
  459.             if (Command == COM_LIBRARY)
  460.             {
  461.                LoadLibraryParts(theLibrary);
  462.                fclose(theFile);
  463.                if (noError == FALSE)
  464.                  ReadError("Library '%s' Not Completely Read",theLibrary->Name);
  465.             } else {
  466.                fclose(theFile);
  467.                ReadError("File '%s' is not a Library",theLibrary->Name);
  468.             }
  469.             if (theLibrary->FirstPart)
  470.             {
  471.                theLibrary->Prev = PrevLib;
  472.                theLibrary->Next = *LibPtr;
  473.                if (theLibrary->Next) theLibrary->Next->Prev = theLibrary;
  474.                *LibPtr = theLibrary;
  475.                Changed = TRUE;
  476.             } else {
  477.                FreeLibrary(theLibrary);
  478.             }
  479.          }
  480.       } else {
  481.          ReadError("Library '%s' Already Loaded",theLibrary->Name);
  482.          FreeLibrary(theLibrary);
  483.       }
  484.    }
  485.    noError = OldNoError;
  486. }
  487.  
  488.  
  489. /*
  490.  *  LoadCircuit()
  491.  *
  492.  *  Clear the flags
  493.  *  While there is more data in the file
  494.  *    read the next line and get the command on that line
  495.  *    if the command is not more cells or blank lines
  496.  *      fininsh making a part, if one is being read
  497.  *      clear the part flags
  498.  *    Do the proper command:
  499.  *
  500.  *      LIBRARY, CIRCUIT:
  501.  *        warn the user about bad LIBRARY and CIRCUIT commands
  502.  *
  503.  *      PART:
  504.  *        if the part has a name
  505.  *          clear the scratch grid and set the flags for making a part
  506.  *          copy the part name into the name string
  507.  *        otherwise warn about the missing name
  508.  *
  509.  *      CELLSIZE:
  510.  *        get the specified cell size and check it for errors
  511.  *
  512.  *      ORIGIN:
  513.  *        get the position of the origin and check for errors
  514.  *
  515.  *      VIEW:
  516.  *        get the position of the visible grid area and check for errors
  517.  *
  518.  *      INCLUDE:
  519.  *        include the specified library in the libraries to be loaded
  520.  *
  521.  *      CELLS:
  522.  *        if there is a part in progress, add the line to it,
  523.  *        otherwise warn about the missing command
  524.  *
  525.  *      BLANK LINE:
  526.  *        move on to the next row in the grid
  527.  *
  528.  *      UNKNOWN:
  529.  *        warn the user about bad commands
  530.  *  close the circuit file
  531.  *  load any libraries that were indicated in the file
  532.  *  if there were errors in the circuit file, let the user know
  533.  *  clear the info message
  534.  */
  535.  
  536. static void LoadCircuit(Name)
  537. char *Name;
  538. {
  539.    int Command;
  540.    short Y = 0;
  541.    UBYTE *Grid = CurGen;
  542.    char PartName[MAXPNAME];
  543.    int tmp1,tmp2;
  544.    short Ox = 0, Oy = 0;
  545.    int blank = BLANK;
  546.    int NoMessage = TRUE;
  547.    int MakingPart;
  548.    
  549.    MakingPart = FALSE; TooWide = FALSE;
  550.    GridX = GridY = 0;
  551.    while (!EndOfFile)
  552.    {
  553.       ReadNextLine();
  554.       Command = GetNextCommand();
  555.       if (Command != COM_CELLS && Command != COM_BLANKLINE)
  556.       {
  557.          if (MakingPart) FinishPart(PartName,&PartsList);
  558.          if (Grid && Y) Grid = NULL; Y = 0;
  559.          MakingPart = 0;
  560.       }
  561.       switch(Command)
  562.       {
  563.          case COM_LIBRARY:
  564.             ReadError("Command 'LIBRARY' Invalid in CIRCUIT");
  565.             break;
  566.  
  567.          case COM_CIRCUIT:
  568.             ReadError("CIRCUIT Command must be First in the File");
  569.             break;
  570.  
  571.          case COM_PART:
  572.             if (Parameters[0])
  573.             {
  574.                ZeroGrid(NewGen);
  575.                Ox = 0; Oy = 0; blank = 0; NoMessage = TRUE;
  576.                Grid = NewGen; Y = 0; MakingPart = TRUE;
  577.                strcpy(PartName,Parameters);
  578.             } else {
  579.                ReadError("Missing Name in PART command");
  580.             }
  581.             break;
  582.                
  583.          case COM_CELLSIZE:
  584.             if (sscanf(Parameters,"%ld",&tmp1) != 1)
  585.                ReadError("Invalid CELLSIZE Value");
  586.             else if (tmp1 < MINCELLSIZE || tmp1 > MAXCELLSIZE)
  587.                ReadError("Invalid CELLSIZE:  %d",tmp1);
  588.             else CellSize = tmp1;
  589.             break;
  590.  
  591.          case COM_ORIGIN:
  592.             if (sscanf(Parameters,"%d %d",&tmp1,&tmp2) != 2)
  593.             {
  594.                ReadError("Invalid ORIGIN Values");
  595.             } else if (tmp1 < 0 || tmp1 >= MAXGRIDW ||
  596.                        tmp2 < 0 || tmp2 >= MAXGRIDH) {
  597.                ReadError("ORIGIN Value Out of Range: (%d,%d)",tmp1,tmp2);
  598.             } else {
  599.                Ox = tmp1; Oy = tmp2;
  600.             }
  601.             break;
  602.  
  603.          case COM_VIEW:
  604.             if (sscanf(Parameters,"%d %d",&tmp1,&tmp2) != 2)
  605.             {
  606.                ReadError("Invalid VIEW Values");
  607.             } else if (tmp1 < 0 || tmp2 >= MAXGRIDW ||
  608.                        tmp2 < 0 || tmp2 >= MAXGRIDH) {
  609.                ReadError("VIEW Value Out of Range: (%d,%d)",tmp1,tmp2);
  610.             } else {
  611.                GridX = tmp1; GridY = tmp2;
  612.             }
  613.             break;
  614.  
  615.          case COM_INCLUDE:
  616.             IncludeLibrary(Parameters);
  617.             break;
  618.  
  619.          case COM_CELLS:
  620.             if (Grid)
  621.             {
  622.                Y = AddLineToGrid(Grid,Y,Ox,Oy,blank);
  623.             } else if (NoMessage) {
  624.                ReadError("Missing PART Command?");
  625.                NoMessage = FALSE;
  626.             }
  627.             break;
  628.  
  629.          case COM_BLANKLINE:
  630.             if (Y) Y++;
  631.             break;
  632.  
  633.          case COM_UNKNOWN:
  634.             *(Parameters-1) = 0;
  635.             ReadError("Unknown Command '%s'",NextWord);
  636.             break;
  637.       }
  638.    }
  639.    fclose(theFile);
  640.    LoadLibList();
  641.    if (noError == FALSE) DoError("Circuit '%s' Not Completely Read",Name);
  642.    ClearInfoMessage();
  643. }
  644.  
  645.  
  646. /*
  647.  *  ReadCircuit()
  648.  *
  649.  *  If the previous circuit has been changed, ask if the user wants
  650.  *    to save the changes
  651.  *
  652.  *  If not (or no changes were made)
  653.  *   put up the message saying that a file is being read
  654.  *   clear the grid and the library lists
  655.  *   load the new circuit
  656.  *   copy the circuit's grid to the UNDO array and the RESET array
  657.  *   set the cell size to the new cell size and move to the specified 
  658.  *     viewing position
  659.  *   clear and refresh the screen and set the sliders
  660.  */
  661.  
  662. static void ReadCircuit(Name)
  663. char *Name;
  664. {
  665.    short tmp1,tmp2;
  666.  
  667.    if (Changed) noError = 
  668.       DoQuestion(" Changes have not been Saved. Discard Changes?      ");
  669.  
  670.    if (noError)
  671.    {
  672.       DoInfoMessage("Loading Circuit '%s'",Name);
  673.       ClearGrid(CurGen);
  674.       ClearLibs(); LibList = NULL;
  675.       LoadCircuit(Name);
  676.       CopyGrid(CurGen,UndoArray);
  677.       CopyGrid(CurGen,ResetArray);
  678.       tmp1 = GridX; tmp2 = GridY; GridW = GridH = 0;
  679.       SetBoardSize(CellSize);
  680.       GridX = tmp1; GridY = tmp2;
  681.       SetBoardSize(CellSize);
  682.       ClearScreen(FALSE);
  683.       RefreshScreen(CurGen);
  684.       UpdateSliders();
  685.    }
  686. }
  687.  
  688.  
  689. /*
  690.  *  ReadLibrary()
  691.  *
  692.  *  close the current file
  693.  *  if loading a library as parts and changes have been made,
  694.  *    ask if the user wants to save the changes
  695.  *  if not
  696.  *    if loading as parts clear the library list
  697.  *    set the list of libraries to read to the single specified library
  698.  *    if loading as parts, indicate this in the library
  699.  *    load the list
  700.  *    clear the info message
  701.  */
  702.  
  703. static void ReadLibrary(Name,Check)
  704. char *Name;
  705. int Check;
  706. {
  707.    int OKtoLoad = TRUE;
  708.  
  709.    fclose(theFile);
  710.    if (Check && Changed) OKtoLoad = 
  711.       DoQuestion(" Changes have not been Saved. Discard Changes?     ");
  712.    if (OKtoLoad)
  713.    {
  714.       if (Check) ClearLibs();
  715.       LibList = NULL;
  716.       IncludeLibrary(Name);
  717.       if (LibList && Check) LibList->Flags |= PL_ASPARTS;
  718.       LoadLibList();
  719.       ClearInfoMessage();
  720.    }
  721. }
  722.  
  723.  
  724. /*
  725.  *  ReadFile()
  726.  *
  727.  *  If we can open the specified file
  728.  *    clear the error flags and read the first line
  729.  *    get the first command in the file
  730.  *    if the command is CIRCUIT:
  731.  *      read the circuit
  732.  *      if it read in OK, set the circuit's name and mark it as unchanged
  733.  *    If the command is LIBRARY:
  734.  *      read the library
  735.  *      if no error and loading as parts, clear the circuit name
  736.  *    If any other command:
  737.  *      indicate that the file must have a CIRCUIT or LIBRARY command
  738.  *      close the file
  739.  *  otherwise indicate the problem with openning the file
  740.  *  clear the info message and put the LOAD button back to normal
  741.  */
  742.  
  743. void ReadFile(Name,Check)
  744. char *Name;
  745. int Check;
  746. {
  747.    int Command;
  748.  
  749.    if (theFile = fopen(Name,"r"))
  750.    {
  751.       noError = TRUE; EndOfFile = FALSE; ReadNextLine();
  752.       while ((Command = GetNextCommand()) == COM_BLANKLINE) ReadNextLine();
  753.       switch(Command)
  754.       {
  755.          case COM_CIRCUIT:
  756.             ReadCircuit(Name);
  757.             if (noError)
  758.             {
  759.                strcpy(FileName,Name);
  760.                Changed = FALSE;
  761.             }
  762.             break;
  763.  
  764.          case COM_LIBRARY:
  765.             ReadLibrary(Name,Check);
  766.             if (Check && noError) FileName[0] = 0;
  767.             break;
  768.  
  769.          default:
  770.             DoError("File must begin with a LIBRARY or CIRCUIT command");
  771.             fclose(theFile);
  772.             break;
  773.       }
  774.    } else {
  775.       DosError("Read","File");
  776.    }
  777.    ClearInfoMessage();
  778.    InvertGadget(&cGadget[ID_LOAD]);
  779. }
  780.