home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 418_02 / rasmol2 / command.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-02  |  85.8 KB  |  2,651 lines

  1. /* command.c
  2.  * RasMol2 Molecular Graphics
  3.  * Roger Sayle, February 1994
  4.  * Version 2.3
  5.  */
  6. #include "rasmol.h"
  7.  
  8. #ifdef IBMPC
  9. #include <windows.h>
  10. #include <malloc.h>
  11. #endif
  12.  
  13. #if !defined(IBMPC) && !defined(VMS)
  14. #include <pwd.h>
  15. #endif
  16.  
  17. #ifndef sun386
  18. #include <stdlib.h>
  19. #endif
  20.  
  21. #include <ctype.h>
  22. #include <stdio.h>
  23.  
  24. #define COMMAND
  25. #include "command.h"
  26. #include "tokens.h"
  27. #include "molecule.h"
  28. #include "abstree.h"
  29. #include "transfor.h"
  30. #include "render.h"
  31. #include "graphics.h"
  32. #include "pixutils.h"
  33. #include "outfile.h"
  34.  
  35.  
  36. /* Macros for commonly used loops */
  37. #define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
  38.                      for(group=chain->glist;group;group=group->gnext)    \
  39.                      for(ptr=group->alist;ptr;ptr=ptr->anext)
  40. #define ForEachBond  for(bptr=Database->blist;bptr;bptr=bptr->bnext)
  41.  
  42.  
  43. #define IsIdentChar(x)  ((isalnum(x))||((x)=='_')||((x)=='$'))
  44.  
  45.  
  46. #ifdef IBMPC
  47. #define DirChar  '\\'
  48. #else
  49. #define DirChar  '/'
  50. #endif
  51.  
  52.  
  53. #define ErrSyntax        0
  54. #define ErrBigNum        1
  55. #define ErrBadOpt        2
  56. #define ErrParam         3
  57. #define ErrFilNam        4
  58. #define ErrBadLoad       5
  59. #define ErrNotNum        6
  60. #define ErrNotSep        7
  61. #define ErrNotBrac       8
  62. #define ErrNoCol         9
  63. #define ErrColour       10
  64. #define ErrBadArg       11
  65. #define ErrBadExpr      12
  66. #define ErrParen        13
  67. #define ErrScript       14
  68. #define ErrFunc         15
  69. #define ErrSetName      16
  70. #define ErrBadSet       17
  71.  
  72.  
  73. static char *ErrorMsg[] = {
  74.         "Invalid command syntax",            /* ErrSyntax  */
  75.         "Integer argument too large",        /* ErrBigNum  */
  76.         "Invalid parameter setting",         /* ErrBadOpt  */
  77.         "Invalid parameter name",            /* ErrParam   */
  78.         "Filename string expected",          /* ErrFilNam  */
  79.         "Molecule database loaded",          /* ErrBadLoad */
  80.         "Integer value expected",            /* ErrNotNum  */
  81.         "Comma separator missing",           /* ErrNotSep  */
  82.         "Close bracket ']' expected",        /* ErrNotBrac */
  83.         "No colour specified",               /* ErrNoCol   */
  84.         "Unknown or incorrect colour",       /* ErrColour  */
  85.         "Invalid command argument",          /* ErrBadArg  */
  86.         "Syntax error in expression",        /* ErrBadExpr */
  87.         "Close parenthesis ')' expected",    /* ErrParen   */
  88.         "Script command stack too deep",     /* ErrScript  */
  89.         "Open parenthesis '(' expected",     /* ErrFunc    */
  90.         "Invalid or missing atom set name",  /* ErrSetName */
  91.         "Not enough memory to define set"    /* ErrBadSet  */
  92.     };
  93.  
  94.  
  95. typedef struct {
  96.         char *ident;
  97.                 int token;
  98.                } KeywordEntry;
  99.  
  100. #define MAXKEYLEN 11
  101. static int KeyLen[MAXKEYLEN+1] = {
  102.         0, 3, 8, 25, 51, 79, 117, 140, 156, 168, 171, 176 };
  103.  
  104. static KeywordEntry Keyword[] = {
  105.             { "X",  XTok },
  106.             { "Y",  YTok },
  107.         { "Z",  ZTok },  /* 3 */
  108.  
  109.             { "AT", ATTok   },
  110.             { "CG", CGTok   },
  111.             { "ON", TrueTok },
  112.         { "OR", OrTok   },
  113.         { "PS", EPSFTok },  /* 8 */
  114.  
  115.             { "ALL", AllTok   },
  116.             { "AND", AndTok   },
  117.             { "BMP", BMPTok   },
  118.             { "CPK", CPKTok   },
  119.             { "DNA", DNATok   },
  120.             { "GIF", GIFTok   },
  121.             { "ION", IonTok   },
  122.             { "NOT", NotTok   },
  123.             { "OFF", FalseTok },
  124.             { "PDB", PDBTok   },
  125.             { "PPM", PPMTok   },
  126.             { "RED", RedTok   },
  127.             { "RNA", RNATok   },
  128.             { "SET", SetTok   },
  129.             { "SUN", SUNTok   },
  130.             { "XYZ", XYZTok   },
  131.             { "ZAP", ZapTok   }, /* 25 */
  132.  
  133.             { "ATOM", AtomTok },
  134.             { "AXES", AxesTok },
  135.             { "AXIS", AxesTok },
  136.             { "BLUE", BlueTok },
  137.             { "BOND", BondTok },
  138.             { "CYAN", CyanTok },
  139.             { "ECHO", EchoTok },
  140.             { "EPSF", EPSFTok },
  141.             { "EXIT", QuitTok },
  142.             { "HALF", HalfTok },
  143.             { "HELP", HelpTok },
  144.             { "INFO", InfoTok },
  145.             { "IONS", IonTok  },
  146.             { "LOAD", LoadTok },
  147.             { "MONO", MonoTok },
  148.             { "NONE", NoneTok },
  149.             { "QUIT", QuitTok },
  150.             { "SAVE", SaveTok },
  151.             { "SHOW", ShowTok },
  152.             { "SLAB", SlabTok },
  153.             { "TRUE", TrueTok },
  154.             { "TURN", TurnTok },
  155.             { "TYPE", TypeTok },
  156.             { "USER", UserTok },
  157.             { "WAIT", WaitTok },
  158.             { "ZOOM", ZoomTok }, /* 51 */
  159.  
  160.             { "ALPHA", AlphaTok  },
  161.             { "AMINO", AminoTok  },
  162.             { "ATOMS", AtomTok   },
  163.             { "BASIC", BasicTok  },
  164.             { "BLACK", BlackTok  },
  165.             { "BONDS", BondTok   },
  166.             { "CHAIN", ChainTok  },
  167.             { "COLOR", ColourTok },
  168.             { "FALSE", FalseTok  },
  169.             { "GREEN", GreenTok  },
  170.             { "GROUP", GroupTok  },
  171.             { "HBOND", HBondTok  },
  172.             { "HELIX", HelixTok  },
  173.             { "LARGE", LargeTok  },
  174.             { "MOUSE", MouseTok  },
  175.             { "PAUSE", WaitTok   },
  176.             { "POLAR", PolarTok  },
  177.             { "RENUM", RenumTok  },
  178.             { "RESET", ResetTok  },
  179.             { "RESNO", ResNoTok  },
  180.             { "SHEET", SheetTok  },
  181.             { "SMALL", SmallTok  },
  182.             { "SOLID", SolidTok  },
  183.             { "TRACE", TraceTok  },
  184.             { "TURNS", TurnTok   },
  185.             { "WATER", WaterTok  },
  186.             { "WHITE", WhiteTok  },
  187.             { "WRITE", WriteTok  },  /* 79 */
  188.  
  189.             { "ACIDIC", AcidicTok },
  190.             { "ATOMNO", AtomNoTok },
  191.             { "BONDED", BondedTok },
  192.             { "BURIED", BuriedTok },
  193.             { "CENTER", CentreTok },
  194.             { "CENTRE", CentreTok },
  195.             { "COLOUR", ColourTok },
  196.             { "CYCLIC", CyclicTok },
  197.             { "DEFINE", DefineTok },
  198.             { "HBONDS", HBondTok  },
  199.             { "HETERO", HeteroTok },
  200.             { "HOLLOW", HollowTok },
  201.             { "LIGAND", LigandTok },
  202.             { "MEDIUM", MediumTok },
  203.             { "MONOPS", MonoPSTok },
  204.             { "NORMAL", NormalTok },
  205.             { "ORANGE", OrangeTok },
  206.             { "PURINE", PurineTok },
  207.             { "PURPLE", PurpleTok },
  208.             { "QUANTA", QuantaTok },
  209.             { "RADIUS", RadiusTok },
  210.             { "RASMOL", RasMolTok },
  211.             { "RASWIN", RasMolTok },
  212.             { "REJECT", RejectTok },
  213.             { "RESIZE", ResizeTok },
  214.             { "RIBBON", RibbonTok },
  215.             { "ROTATE", RotateTok },
  216.             { "SCRIPT", ScriptTok },
  217.             { "SELECT", SelectTok },
  218.             { "SHADOW", ShadowTok },
  219.             { "SHEETS", SheetTok  },
  220.             { "SSBOND", SSBondTok },
  221.             { "SUNRLE", SUNRLETok },
  222.             { "VECTPS", VectPSTok },
  223.             { "VIOLET", VioletTok },
  224.             { "WATERS", WaterTok  },
  225.             { "WITHIN", WithinTok },
  226.             { "YELLOW", YellowTok },  /* 117 */
  227.  
  228.             { "ACYCLIC", AcyclicTok },
  229.             { "ALCHEMY", AlchemyTok },
  230.             { "AMBIENT", AmbientTok },
  231.             { "CHARGED", ChargedTok },
  232.             { "CYSTINE", CystineTok },
  233.             { "DISPLAY", DisplayTok },
  234.             { "HELICES", HelixTok   },
  235.             { "INSIGHT", InsightTok },
  236.             { "LIGANDS", LigandTok  },
  237.             { "MAGENTA", MagentaTok },
  238.             { "NEUTRAL", NeutralTok },
  239.             { "NUCLEIC", NucleicTok },
  240.             { "PROTEIN", ProteinTok },
  241.             { "PURINES", PurineTok  },
  242.             { "RESIDUE", GroupTok   },
  243.             { "RIBBONS", RibbonTok  },
  244.             { "SECTION", SectionTok },
  245.             { "SHADOWS", ShadowTok  },
  246.             { "SHAPELY", ShapelyTok },
  247.             { "SOLVENT", SolventTok },
  248.             { "SSBONDS", SSBondTok  },
  249.             { "STRANDS", StrandsTok },
  250.             { "SURFACE", SurfaceTok },  /* 140 */
  251.  
  252.             { "AROMATIC", AromaticTok },
  253.             { "BACKBONE", BackboneTok },
  254.             { "BONDMODE", BondModeTok },
  255.             { "BOUNDBOX", BoundBoxTok },
  256.             { "HYDROGEN", HydrogenTok },
  257.             { "NEGATIVE", AcidicTok   },
  258.             { "POSITIVE", BasicTok    },
  259.             { "RENUMBER", RenumTok    },
  260.             { "RESTRICT", RestrictTok },
  261.             { "SELECTED", SelectedTok },
  262.             { "SEQUENCE", SequenceTok },
  263.             { "SLABMODE", SlabModeTok },
  264.             { "SOLVENTS", SolventTok  },
  265.             { "SPECULAR", SpecularTok },  
  266.             { "SYMMETRY", SymmetryTok },
  267.             { "UNITCELL", UnitCellTok },  /* 156 */
  268.  
  269.             { "ALIPHATIC", AliphaticTok },
  270.             { "GREENBLUE", GreenblueTok },
  271.             { "HOURGLASS", HourGlassTok },
  272.             { "MOLSCRIPT", MolScriptTok },
  273.             { "MOUSEMODE", MouseTok     },
  274.             { "REDORANGE", RedorangeTok },
  275.             { "SIDECHAIN", SidechainTok },
  276.             { "SPACEFILL", SpacefillTok },
  277.             { "SPECPOWER", SpecPowerTok },
  278.             { "STRUCTURE", StructureTok },
  279.             { "TRANSLATE", TranslateTok },
  280.             { "WIREFRAME", WireframeTok },  /* 168 */
  281.  
  282.             { "BACKGROUND", BackgroundTok },
  283.             { "MONOCHROME", MonoTok       },
  284.             { "PYRIMIDINE", PyrimidineTok },  /* 171 */
  285.  
  286.             { "BOUNDINGBOX", BoundBoxTok    },
  287.             { "HYDROPHOBIC", HydrophobicTok },
  288.             { "INFORMATION", InfoTok        },
  289.             { "PYRIMIDINES", PyrimidineTok, },
  290.             { "TEMPERATURE", TemperatureTok }  /* 176 */
  291.                 };
  292.  
  293.  
  294. typedef struct _HlpEntry {
  295.         struct _HlpEntry __far *next;
  296.         struct _HlpEntry __far *info;
  297.         char __far *keyword;
  298.                 Long fpos;
  299.                 } HlpEntry;
  300.  
  301. #define HelpPool   16
  302. static char *HelpFileName;
  303. static char HelpFileBuf[80];
  304. static HlpEntry __far *FreeInfo;
  305. static HlpEntry __far *HelpInfo;
  306.  
  307.  
  308. #define STACKSIZE  10
  309. static char *NameStack[STACKSIZE];
  310. static int LineStack[STACKSIZE];
  311.  
  312. #define HISTSIZE    4096
  313. #define HISTMASK    4095
  314. static char HistBuff[HISTSIZE];
  315. static int MinHist,MaxHist;
  316. static int CurHist;
  317.  
  318. static char *CurPrompt;
  319. static int CurPos,MaxPos;
  320. static int FileDepth;
  321.  
  322. static int TokenValue;
  323. static int TokenLength;
  324. static char TokenIdent[128];
  325. static char *TokenStart;
  326. static char *TokenPtr;
  327. static int CurToken;
  328.  
  329.  
  330. static int RVal, GVal, BVal;
  331.  
  332. #if defined(__STDC__) || defined(IBMPC)
  333. /* Forward Declarations */
  334. int ExecuteCommand();
  335. int ProcessLine();
  336. #endif
  337.  
  338.  
  339.  
  340. static void UpdateLine()
  341. {
  342.     register int i;
  343.  
  344.     for( i=CurPos; i<MaxPos; i++ )
  345.         WriteChar(CurLine[i]);
  346.     WriteChar(' ');
  347.     for( i=MaxPos+1; i>CurPos; i-- )
  348.         WriteChar(0x08);
  349. }
  350.  
  351. static void CopyHistory()
  352. {
  353.     register int i;
  354.  
  355.     for( i=CurPos; i>0; i-- )
  356.         WriteChar(0x08);
  357.     for( i=0; i<MaxPos; i++ )
  358.         WriteChar(' ');
  359.     WriteChar(0x0D);
  360.     WriteString(CurPrompt);
  361.  
  362.     CurPos = 0;
  363.     if( (i=CurHist) != MaxHist )
  364.         while( HistBuff[i] )
  365.         {   CurLine[CurPos++] = HistBuff[i];
  366.             WriteChar(HistBuff[i]);
  367.             i = (i+1) & HISTMASK;
  368.         }
  369.     CurLine[CurPos] = 0;
  370.     MaxPos = CurPos;
  371. }
  372.  
  373.  
  374. int ProcessCharacter( ch )
  375.     char ch;
  376. {
  377.     register int i;
  378.  
  379.  
  380.     if( !ch ) return( False );
  381.     if( (ch>=' ') && (ch<='~') )
  382.     {   if( MaxPos<MAXLINELEN )
  383.         {   for( i=MaxPos; i>CurPos; i-- )
  384.                 CurLine[i] = CurLine[i-1];
  385.             CurLine[CurPos++] = ch;
  386.             CurLine[++MaxPos] = 0;
  387.  
  388.             WriteChar(ch);
  389.             if( CurPos<MaxPos )
  390.                 UpdateLine();
  391.         } else 
  392.             WriteChar(0x07);
  393.         
  394.     } else
  395.         switch( ch )
  396.         {    case( 0x7f ):  /* DEL and ^H */
  397.              case( 0x08 ):  if( CurPos>0 )
  398.                             {   for( i=CurPos; i<=MaxPos; i++ )
  399.                                     CurLine[i-1] = CurLine[i];
  400.                                 CurPos--; MaxPos--;
  401.                                 WriteChar(0x08);
  402.                                 UpdateLine();
  403.                             }
  404.                             break;
  405.  
  406.              case( 0x04 ):  if( CurPos<MaxPos ) /* ^D */
  407.                             {   for( i=CurPos; i<MaxPos; i++ )
  408.                                     CurLine[i] = CurLine[i+1];
  409.                                 MaxPos--; UpdateLine();
  410.                             }
  411.                             break;
  412.  
  413.              case( 0x0d ):  /* ^M and ^J */
  414.              case( 0x0a ):  WriteChar('\n');
  415.                             if( MaxPos )
  416.                                 for( i=0; i<=MaxPos; i++ )
  417.                                 {    HistBuff[MaxHist] = CurLine[i];
  418.                                      MaxHist=(MaxHist+1)&HISTMASK;
  419.                                      if( MaxHist==MinHist )
  420.                                      {   while( HistBuff[MinHist] )
  421.                                              MinHist=(MinHist+1)&HISTMASK;
  422.                                          MinHist=(MinHist+1)&HISTMASK;
  423.                                      }
  424.                                 }
  425.                             CommandActive = False;
  426.                             return( True );
  427.                             break;
  428.  
  429.              case( 0x02 ):  if( CurPos>0 )  /* ^B */
  430.                             {    WriteChar(0x08);
  431.                                  CurPos--;
  432.                             }
  433.                             break;
  434.  
  435.              case( 0x06 ):  if( CurPos<MaxPos )  /* ^F */
  436.                                 WriteChar(CurLine[CurPos++]);
  437.                             break;
  438.  
  439.              case( 0x01 ):  while( CurPos>0 )   /* ^A */
  440.                             {    WriteChar(0x08);
  441.                                  CurPos--;
  442.                             }
  443.                             break;
  444.  
  445.              case( 0x05 ):  while( CurPos<MaxPos )  /* ^E */
  446.                                 WriteChar(CurLine[CurPos++]);
  447.                             break;
  448.  
  449.              case( 0x0c ):  WriteChar('\n');    /* ^L */
  450.                             WriteString(CurPrompt);
  451.                             for( i=0; i<MaxPos; i++ )
  452.                                 WriteChar(CurLine[i]);
  453.                             for( i=CurPos; i<MaxPos; i++ )
  454.                                 WriteChar(0x08);
  455.                             break;
  456.  
  457.              case( 0x10 ):  if( CurHist!=MinHist ) /* ^P */
  458.                             {   CurHist -= 2;
  459.                                 if( CurHist<0 )
  460.                                     CurHist += HISTSIZE;
  461.                                 while( HistBuff[CurHist] )
  462.                                     CurHist=CurHist?CurHist-1:HISTMASK;
  463.                                 CurHist = (CurHist+1)&HISTMASK;
  464.                                 CopyHistory();
  465.                             }
  466.                             break;
  467.  
  468.              case( 0x0e ):  if( CurHist!=MaxHist ) /* ^N */
  469.                             {   while( HistBuff[CurHist] )
  470.                                     CurHist = (CurHist+1)&HISTMASK;
  471.                                 CurHist = (CurHist+1)&HISTMASK;
  472.                             }
  473.                             CopyHistory();
  474.                             break;
  475.         }
  476.     return( False );
  477. }
  478.  
  479.  
  480. void ResetCommandLine( state )
  481.      int state;
  482. {
  483.     if( state )
  484.     {   MenuDisable = (state!=1);
  485.         switch( CurState=state )
  486.         {   case(1):   CurPrompt="RasMol> ";           break;
  487.             case(2):   CurPrompt="PDB file name:";     break;
  488.             case(3):   CurPrompt="Output file name:";  break;
  489.         }
  490.     }
  491.  
  492.     if( CommandActive )
  493.         WriteChar('\n');
  494.     CommandActive = True;
  495.     WriteString(CurPrompt);
  496.  
  497.     CurHist = MaxHist;
  498.     CurPos = MaxPos = 0;
  499.     CurLine[0] = 0;
  500. }
  501.  
  502.  
  503.  
  504. static void CommandError( error )
  505.     register char *error;
  506. {
  507.     register char *ptr;
  508.     char buffer[40];
  509.  
  510.     if( TokenPtr )
  511.     {   if( FileDepth > -1 )
  512.         {   if( CommandActive )
  513.                 WriteChar('\n');
  514.             CommandActive=False;
  515.             
  516.             WriteString(CurLine);
  517.             WriteChar('\n');
  518.         } else WriteString("        ");
  519.  
  520.         for( ptr=CurLine; ptr<TokenStart; ptr++ )
  521.             WriteChar(' ');
  522.         WriteString("^\n");
  523.     }
  524.  
  525.     if( FileDepth > -1 )
  526.     {   if( LineStack[FileDepth] )
  527.         {   if( NameStack[FileDepth] )
  528.             {   WriteChar('"');
  529.                 WriteString(NameStack[FileDepth]);
  530.                 WriteString("\",");
  531.             }
  532.             sprintf(buffer,"line %d: ",LineStack[FileDepth]);
  533.             WriteString(buffer);
  534.         } else
  535.         {   WriteString(NameStack[FileDepth]);
  536.             WriteString(": ");
  537.         }
  538.     }
  539.  
  540.     if( error )
  541.     {   WriteString(error);
  542.         WriteString("!\n");
  543.     }
  544.     CommandActive = False;
  545.     CurToken = 0;
  546. }
  547.  
  548.  
  549. static char *ProcessFileName( name )
  550.     char *name;
  551. {
  552. #if !defined(IBMPC) && !defined(VMS)
  553.     register struct passwd *entry;
  554.     register char *temp;
  555.     char username[64];
  556. #endif
  557.     register char *ptr;
  558.  
  559.  
  560.     while( *name==' ' )
  561.         name++;
  562.  
  563. #if defined(IBMPC) || defined(VMS)
  564.     ptr = DataFileName;
  565.     while( *name && (*name!=' ') )
  566.     {   *ptr++ = islower(*name)? toupper(*name) : *name;
  567.         name++;
  568.     }
  569. #else
  570.     /* Perform filename globbing */
  571.     if( *name=='~' )
  572.     {   ptr = username;  name++;
  573.         while( *name && (*name!=' ') && (*name!='/') )
  574.             *ptr++ = *name++;
  575.         *ptr = '\0';
  576.  
  577.         ptr = DataFileName;
  578.         if( *username )
  579.         {   if( entry=getpwnam(username) )
  580.             {   temp = entry->pw_dir;
  581.                 endpwent();
  582.             } else /* Unknown user! */
  583.             {   temp = username;
  584.                 *ptr++ = '~';
  585.             }
  586.  
  587.         } else if( !(temp=(char*)getenv("HOME")) )
  588.             temp = ".";
  589.  
  590.         while( *temp )
  591.             *ptr++ = *temp++;
  592.     } else ptr = DataFileName;
  593.  
  594.     while( *name && (*name!=' ') )
  595.         *ptr++ = *name++;
  596. #endif
  597.     *ptr = '\0';
  598.     return ptr;
  599. }
  600.  
  601.  
  602. /* Filename extensions! */
  603. #define MaxFileExt  4
  604. static char *FileExt[] = { "", ".Z", ".gz", ".z" };
  605.  
  606. static FILE *OpenDataFile( begin, end )
  607.     char *begin, *end;
  608. {
  609.     register FILE *fp;
  610. #ifndef IBMPC
  611.     register char *src, *dst;
  612.     register int i;
  613.     
  614.     for( i=0; i<MaxFileExt; i++ )
  615.     {   dst = end; src = FileExt[i];
  616.         while( *dst++ = *src++ );
  617.         if( fp=fopen(begin,"r") )
  618.             break;
  619.     }
  620. #else
  621.     fp = fopen(begin,"r");
  622. #endif
  623.     *end = '\0';
  624.     return fp;
  625. }
  626.  
  627.  
  628. int FetchFile( format, info, name )
  629.     int format, info;
  630.     char *name;
  631. {
  632. #ifndef IBMPC
  633.     register int ch, comp;
  634. #endif
  635.     register char *src,*dst;
  636.     register int done;
  637.     register FILE *fp;
  638.     char buffer[128];
  639.  
  640.     name = ProcessFileName(name);
  641.     fp = OpenDataFile(DataFileName,name);
  642.  
  643.     /* Try using a default file path! */
  644.     if( !fp )
  645.     {   switch( format )
  646.         {   case(FormatAlchemy): src = (char*)getenv("RASMOLMOLPATH");  break;
  647.             case(FormatPDB):     src = (char*)getenv("RASMOLPDBPATH");  break;
  648.             case(FormatXYZ):     src = (char*)getenv("RASMOLXYZPATH");  break;
  649.             default:             src = NULL;
  650.         }
  651.  
  652.         if( src && *src )
  653.         {   dst = buffer;
  654.             while( *src ) *dst++ = *src++;
  655.             if( *(dst-1) != DirChar )
  656.                 *dst++ = DirChar;
  657.  
  658.             for( src=DataFileName; *dst = *src++; dst++ )
  659.                 if( *dst == DirChar ) break;
  660.  
  661.             if( !(*dst) && (fp=OpenDataFile(buffer,dst)) )
  662.             {   dst = DataFileName;  src=buffer;
  663.                 while( *dst++ = *src++ );
  664.             }
  665.         }
  666.     }
  667.  
  668.  
  669.     if( !fp )
  670.     {   *name = '\0';
  671.         if( CommandActive )
  672.             WriteChar('\n');
  673.         WriteString("Error: File '");
  674.         WriteString(DataFileName);
  675.         WriteString("' not found!\n\n");
  676.         CommandActive=False;
  677.         return( False );
  678.     }
  679.  
  680. #if !defined(IBMPC) && !defined(VMS)
  681.     done = getc(fp);
  682.     if( done == 0x1f )
  683.     {   done = getc(fp);
  684.         fclose(fp);
  685.  
  686.         if( done == 0x9d )
  687.         {   sprintf(buffer,"uncompress -c %s 2> /dev/null\n",DataFileName);
  688.         } else if( done == 0x8b )
  689.         {   sprintf(buffer,"gzip -cdq %s 2> /dev/null\n",DataFileName);
  690.         } else /* bad magic number! */
  691.         {   if( CommandActive )
  692.                 WriteChar('\n');
  693.             WriteString("Error: Unrecognised compression format!\n\n");
  694.             CommandActive=False;
  695.             return( False );
  696.         }
  697.    
  698.         comp = True;
  699.         if( !(fp=popen(buffer,"r")) )
  700.         {   if( CommandActive )
  701.                 WriteChar('\n');
  702.             WriteString("Error: Unable to decompress file!\n\n");
  703.             CommandActive=False;
  704.             return( False );
  705.         }
  706.     } else /* Uncompressed! */
  707.     {   ungetc(done,fp);
  708.         comp = False;
  709.     }
  710. #endif
  711.  
  712.     done = False;
  713.     switch( format )
  714.     {   case(FormatAlchemy): done = LoadAlchemyMolecule(fp); break;
  715.         case(FormatPDB):     done = LoadPDBMolecule(fp);     break;
  716.         case(FormatXYZ):     done = LoadXYZMolecule(fp);     break;
  717.     }
  718.  
  719. #if !defined(IBMPC) && !defined(VMS)
  720.     if( comp )
  721.     {   if( pclose(fp) )
  722.         {   if( CommandActive )
  723.                 WriteChar('\n');
  724.             WriteString("Error: Unable to decompress file!\n\n");
  725.             CommandActive=False;
  726.             return(False);
  727.         }
  728.     } else fclose(fp);
  729. #else
  730.     fclose(fp);
  731. #endif
  732.  
  733.     if( !done ) 
  734.     {   return( False );
  735.     } else if( !Database ) 
  736.         return( True );
  737.  
  738.     if( info )
  739.         DescribeMolecule();
  740.  
  741. #ifndef IBMPC        
  742.     if( Interactive ) 
  743.        FetchEvent(False);
  744. #endif
  745.  
  746.     ReDrawFlag |= RFInitial;
  747.     CreateMoleculeBonds(info);
  748.     InitialTransform();
  749.  
  750.     VoxelsClean = False;
  751.     ApplyTransform();
  752.     return( True );
  753. }
  754.  
  755.  
  756. void LoadScriptFile( fileptr, name )
  757.     FILE *fileptr;
  758.     char *name;
  759. {
  760.     register char *ptr;
  761.     register int ch,len;
  762.  
  763.     if( fileptr )
  764.     {   len = 1;
  765.         for( ptr=name; *ptr; ptr++ )
  766.             len++;
  767.  
  768.         FileDepth++;
  769.         ptr = (char*)malloc( len );
  770.         NameStack[FileDepth] = ptr;
  771.         while( *ptr++ = *name++ );
  772.         LineStack[FileDepth] = 0;
  773.  
  774.         do {
  775.             len = 0;
  776.             ch = getc(fileptr);
  777.             while( (ch!='\n') && (ch!=EOF) )
  778.             {   if( len<MAXBUFFLEN )
  779.                     CurLine[len++] = ch;
  780.                 ch = getc(fileptr);
  781.             }
  782.  
  783.             LineStack[FileDepth]++;
  784.             if( len<MAXBUFFLEN )
  785.             {   CurLine[len] = '\0';
  786.                 if( ExecuteCommand() )
  787.                     break;
  788.             } else CommandError("Script command line too long");
  789.         } while( ch!=EOF );
  790.         free(NameStack[FileDepth]);
  791.         fclose( fileptr );
  792.         FileDepth--;
  793.     } else
  794.     {   CommandError( (char*)NULL );
  795.         WriteString("Cannot open script file '");
  796.         WriteString(name);  WriteString("'\n");
  797.     }
  798. }
  799.  
  800. #if defined(__STDC__) || defined(IBMPC) 
  801. /* Function Prototypes */
  802. static int CompareStrings( char __far*, char __far* );
  803. static int PrefixString( char __far*, char __far* );
  804. #endif
  805.  
  806. static int CompareStrings( str1, str2 )
  807.     register char __far *str1, __far *str2;
  808. {
  809.     while( *str1 == *str2++ )
  810.         if( *str1++ == '\0' )
  811.             return(0);
  812.     return( *str1 - *--str2 );
  813. }
  814.  
  815. static int PrefixString( str1, str2 )
  816.     register char __far *str1, __far *str2;
  817. {
  818.     while( *str1 == *str2++ )
  819.         if( *str1++ == '\0' )
  820.             return( True );
  821.     return( *str1 == '\0' );
  822. }
  823.  
  824.  
  825. static HlpEntry __far *EnterHelpInfo( text )
  826.     register char *text;
  827. {
  828.     register HlpEntry __far * __far *tmp;
  829.     register HlpEntry __far *ptr;
  830.     register int res,len,i;
  831.     register char ch;
  832.  
  833.     char keyword[32];
  834.  
  835.     ptr = (void __far*)0;
  836.     while( *text && (*text!='\n') )
  837.     {   while( *text && (*text!='\n') && (*text==' ') )
  838.             text++;
  839.  
  840.         len = 0;
  841.         while( *text && (*text!='\n') && (*text!=' ') )
  842.             if( len<31 )
  843.             {   ch = *text++;
  844.                 keyword[len++] = islower(ch)? toupper(ch) : ch;
  845.             } else text++;
  846.         keyword[len]='\0';
  847.  
  848.         if( ptr )
  849.         {   tmp = &ptr->info;
  850.             ptr = (void __far*)0;
  851.         } else tmp = &HelpInfo;
  852.  
  853.         while( *tmp )
  854.         {   res = CompareStrings(keyword,(*tmp)->keyword);
  855.             if( res==0 ) /* Exact Match */
  856.             {   ptr = *tmp;
  857.                 break;
  858.             } else if( res<0 )
  859.                 break;
  860.             tmp = &(*tmp)->next;
  861.         }
  862.  
  863.         if( !ptr )
  864.         {   if( !FreeInfo )
  865.             {   ptr = (HlpEntry __far*)_fmalloc(HelpPool*sizeof(HlpEntry));
  866.                 if( !ptr ) 
  867.                     RasMolFatalExit("Command Error: Insufficient memory!");
  868.                 for( i=1; i<HelpPool; i++ )
  869.                 {   ptr->next = FreeInfo;
  870.                     FreeInfo = ptr++;
  871.                 }
  872.             } else
  873.             {   ptr = FreeInfo;
  874.                 FreeInfo = ptr->next;
  875.             }
  876.  
  877.             ptr->keyword = (char __far*)_fmalloc(len+1);
  878.             for( i=0; i<=len; i++ )
  879.                 ptr->keyword[i] = keyword[i];
  880.  
  881.             ptr->info = (void __far*)0;
  882.             ptr->next = *tmp;
  883.             ptr->fpos = 0;
  884.             *tmp = ptr;
  885.         }
  886.     }
  887.     return( ptr );
  888. }
  889.  
  890. static void InitHelpFile()
  891. {
  892.     register char *src,*dst;
  893.     register HlpEntry __far *fix;
  894.     register HlpEntry __far *ptr;
  895.     register FILE *fp;
  896.     register Long pos;
  897.  
  898.     char buffer[82];
  899.  
  900.  
  901.     HelpFileName = "rasmol.hlp";
  902.     fp=fopen(HelpFileName,"r");
  903.  
  904. #ifndef IBMPC
  905.     if( !fp )
  906.     {   HelpFileName = "/usr/local/lib/rasmol/rasmol.hlp";
  907.         fp = fopen(HelpFileName,"r");
  908.     }
  909. #endif
  910.  
  911.     if( !fp && (src=(char*)getenv("RASMOLPATH")) )
  912.     {   HelpFileName = dst = HelpFileBuf; 
  913.         while( *src )
  914.             *dst++ = *src++;
  915. #ifdef IBMPC
  916.         *dst++ = '\\';
  917. #else
  918.         *dst++ = '/';
  919. #endif
  920.                             
  921.         src = "rasmol.hlp"; 
  922.         while( *dst++ = *src++ );
  923.         fp = fopen(HelpFileName,"r");
  924.     }
  925.  
  926.     if( !fp )
  927.     {   if( CommandActive )
  928.             WriteChar('\n');
  929.         CommandActive = False;
  930.         
  931.         WriteString("Unable to find RasMol help file!\n");
  932.         HelpFileName = NULL;
  933.         return;
  934.     }
  935.  
  936.     pos = 0;
  937.     fgets(buffer,80,fp);
  938.     while( !feof(fp) )
  939.     {    fix = (void __far*)0;
  940.          while( *buffer=='?' )
  941.          {   if( ptr = EnterHelpInfo(buffer+1) )
  942.              {   ptr->info = fix;
  943.                  fix = ptr;
  944.              }
  945.  
  946.              pos = ftell(fp);
  947.              if( !fgets(buffer,80,fp) )
  948.                  break;
  949.          }
  950.  
  951.          while( fix )
  952.          {   ptr = fix->info;
  953.              fix->info = (void __far*)0;
  954.              fix->fpos = pos;
  955.              fix = ptr;
  956.          }
  957.  
  958.          while( fgets(buffer,80,fp) )
  959.              if( *buffer=='?' )
  960.                  break;
  961.     }
  962.     fclose(fp);
  963. }
  964.  
  965. static void FindHelpInfo()
  966. {
  967.     register HlpEntry __far * __far *tmp;
  968.     register HlpEntry __far *ptr;
  969.     register int res,len;
  970.     register Long pos;
  971.     register FILE *fp;
  972.     register char ch;
  973.  
  974.     char keyword[32];
  975.     char buffer[82];
  976.  
  977.     while( *TokenPtr && (*TokenPtr==' ') )
  978.         TokenPtr++;
  979.  
  980.     if( *TokenPtr )
  981.     {   ptr = NULL;
  982.         do {
  983.             len = 0;
  984.             while( *TokenPtr && (*TokenPtr!=' ') )
  985.                 if( len<31 )
  986.                 {   ch = *TokenPtr++;
  987.                     keyword[len++] = islower(ch)? toupper(ch): ch;
  988.                 } else TokenPtr++;
  989.             keyword[len]='\0';
  990.  
  991.             if( ptr )
  992.             {   tmp = &ptr->info;
  993.                 ptr = (void __far*)0;
  994.             } else tmp = &HelpInfo;
  995.  
  996.             while( *tmp )
  997.             {   res = CompareStrings(keyword,(*tmp)->keyword);
  998.                 if( res<0 )
  999.                 {   if( PrefixString(keyword,(*tmp)->keyword) )
  1000.                     {   ptr = *tmp;
  1001.                         if( ptr->next && 
  1002.                             PrefixString(keyword,ptr->next->keyword) )
  1003.                         {   if( CommandActive ) WriteChar('\n');
  1004.                             WriteString("Ambiguous help topic requested!\n");
  1005.                             CommandActive = False;
  1006.                             return;
  1007.                         } else break;
  1008.                     } else break;
  1009.                 } else if( res==0 ) 
  1010.                 {   ptr = *tmp;
  1011.                     break;
  1012.                 }
  1013.                 tmp = &(*tmp)->next;
  1014.             }
  1015.  
  1016.             while( *TokenPtr && (*TokenPtr==' ') )
  1017.                 TokenPtr++;
  1018.         } while( *TokenPtr && ptr );
  1019.  
  1020.         if( !ptr || !ptr->fpos )
  1021.         {   if( CommandActive )
  1022.                 WriteChar('\n');
  1023.             WriteString("No available help on requested topic!\n");
  1024.             CommandActive=False;
  1025.             return;
  1026.         } else pos=ptr->fpos;
  1027.     } else pos=0;
  1028.  
  1029.  
  1030.     if( !(fp=fopen(HelpFileName,"r")) )
  1031.         RasMolFatalExit("Command Error: Unable to reopen help file!");
  1032.  
  1033.     if( CommandActive )
  1034.         WriteChar('\n');
  1035.     CommandActive = False;
  1036.  
  1037.     fseek(fp,pos,0);
  1038.     while( fgets(buffer,80,fp) )
  1039.         if( *buffer!='?' )
  1040.         {   WriteString(buffer);
  1041.         } else break;
  1042.     fclose(fp);
  1043. }
  1044.  
  1045.  
  1046. static int LookUpKeyword()
  1047. {
  1048.     register int mid,res;
  1049.     register int lo, hi;
  1050.  
  1051.     if( TokenLength>MAXKEYLEN )
  1052.         return( IdentTok );
  1053.  
  1054.     lo = KeyLen[TokenLength-1];
  1055.     hi = KeyLen[TokenLength]-1;
  1056.  
  1057.     while( hi>=lo )
  1058.     {   mid = (hi+lo)>>1;
  1059.         res = CompareStrings(TokenIdent,Keyword[mid].ident);
  1060.         if( !res ) return( Keyword[mid].token );
  1061.  
  1062.         if( res>0 )
  1063.         {      lo = mid+1;
  1064.         } else hi = mid-1;
  1065.     }
  1066.     return( IdentTok );
  1067. }
  1068.  
  1069.  
  1070. static int FetchToken()
  1071. {
  1072.     register char ch;
  1073.  
  1074.     CurToken = 0;
  1075.     while( True )
  1076.     {    ch = *TokenPtr++;
  1077.          if( !ch || (ch=='#') ) 
  1078.              return(0);
  1079.          if( isspace(ch) )
  1080.              continue;
  1081.  
  1082.          TokenStart = TokenPtr-1;
  1083.          if( isalpha(ch) )
  1084.          {   TokenLength = 1;
  1085.              *TokenIdent = islower(ch)? toupper(ch) : ch;
  1086.              while( IsIdentChar(*TokenPtr) && (TokenLength<32) )
  1087.              {   ch = *TokenPtr++;
  1088.                  if( islower(ch) ) ch = toupper(ch);
  1089.                  TokenIdent[TokenLength++] = ch;
  1090.              }
  1091.              if( TokenLength==32 )
  1092.              {   CommandError("Identifier too long");
  1093.                  return(0);
  1094.              } else TokenIdent[TokenLength] = '\0';
  1095.              return( CurToken = LookUpKeyword() );
  1096.  
  1097.          } else if( isdigit(ch) )
  1098.          {   TokenValue = ch-'0';
  1099.              while( isdigit(*TokenPtr) )
  1100.                  TokenValue = 10*TokenValue + (*TokenPtr++)-'0';
  1101.              return( CurToken = NumberTok );
  1102.  
  1103.          } else if( (ch=='\'') || (ch=='\"') || (ch=='`') )
  1104.          {   TokenLength = 0;
  1105.              while( *TokenPtr && (TokenLength<128) && (*TokenPtr!=ch) )
  1106.                  TokenIdent[TokenLength++] = *TokenPtr++;
  1107.  
  1108.              if( ch != *TokenPtr )
  1109.              {   if( *TokenPtr )
  1110.                  {   CommandError("String constant unterminated");
  1111.                  } else CommandError("String constant too long");
  1112.                  return( 0 );
  1113.              } else TokenPtr++;
  1114.  
  1115.              TokenIdent[TokenLength]='\0';
  1116.              return( CurToken = StringTok );
  1117.          } else if( ispunct(ch) )
  1118.              return( CurToken = ch );
  1119.     }
  1120. }
  1121.  
  1122.  
  1123. static int NextIf( token, error )
  1124.     int token, error;
  1125. {
  1126.     if( FetchToken()!=token )
  1127.     {   CommandError(ErrorMsg[error]);
  1128.         return( True );
  1129.     } else return( False );
  1130. }
  1131.  
  1132.  
  1133. static int ParseColour()
  1134. {
  1135.     switch( CurToken )
  1136.     {   case(BlueTok):        RVal=0;   GVal=0;   BVal=255; break;
  1137.         case(BlackTok):       RVal=0;   GVal=0;   BVal=0;   break;
  1138.         case(CyanTok):        RVal=0;   GVal=255; BVal=255; break;
  1139.         case(GreenTok):       RVal=0;   GVal=255; BVal=0;   break;
  1140.         case(GreenblueTok):   RVal=46;  GVal=139; BVal=87;  break;
  1141.         case(MagentaTok):     RVal=255; GVal=0;   BVal=255; break;
  1142.         case(OrangeTok):      RVal=255; GVal=165; BVal=0;   break;
  1143.         case(PurpleTok):      RVal=160; GVal=32;  BVal=240; break;
  1144.         case(RedTok):         RVal=255; GVal=0;   BVal=0;   break;
  1145.         case(RedorangeTok):   RVal=255; GVal=69;  BVal=0;   break;
  1146.         case(VioletTok):      RVal=238; GVal=130; BVal=238; break;
  1147.         case(WhiteTok):       RVal=255; GVal=255; BVal=255; break; 
  1148.         case(YellowTok):      RVal=255; GVal=255; BVal=0;   break;
  1149.  
  1150.         case('['):    RVal = GVal = BVal = 0;
  1151.  
  1152.                       if( NextIf(NumberTok,ErrNotNum) ) { return(False);
  1153.                       } else if( TokenValue>255 )
  1154.                       {   CommandError(ErrorMsg[ErrBigNum]); return( False );
  1155.                       } else RVal = TokenValue;
  1156.  
  1157.                       if( NextIf(',',ErrNotSep) ) return(False);
  1158.                       if( NextIf(NumberTok,ErrNotNum) ) { return(False);
  1159.                       } else if( TokenValue>255 )
  1160.                       {   CommandError(ErrorMsg[ErrBigNum]); return( False );
  1161.                       } else GVal = TokenValue;
  1162.  
  1163.                       if( NextIf(',',ErrNotSep) ) return(False);
  1164.                       if( NextIf(NumberTok,ErrNotNum) ) { return(False);
  1165.                       } else if( TokenValue>255 )
  1166.                       {   CommandError(ErrorMsg[ErrBigNum]); return( False );
  1167.                       } else BVal = TokenValue;
  1168.  
  1169.                       return( !NextIf(']',ErrNotBrac) );
  1170.  
  1171.         case(IdentTok): if( Interactive )
  1172.                         return( LookUpColour(TokenIdent,&RVal,&GVal,&BVal) );
  1173.                       
  1174.         default:  return(False);
  1175.     }
  1176.     return( True );
  1177. }
  1178.  
  1179.  
  1180. void DisplaySelectCount()
  1181. {
  1182.     char buffer[40];
  1183.  
  1184.     if( FileDepth == -1 )
  1185.     {   if( CommandActive )
  1186.            WriteChar('\n');
  1187.         CommandActive=False;
  1188.     
  1189.         if( SelectCount==0 )
  1190.         {   WriteString("No atoms selected!\n");
  1191.         } else if( SelectCount>1 )
  1192.         {   sprintf(buffer,"%ld atoms selected!\n",SelectCount);
  1193.             WriteString(buffer);
  1194.         } else WriteString("1 atom selected!\n");
  1195.     }
  1196.  
  1197.     if( DisplayMode )
  1198.         ReDrawFlag |= RFRefresh;
  1199. }
  1200.  
  1201.  
  1202. static void SelectZoneExpr( expr )
  1203.     Expr *expr;
  1204. {
  1205.     register Bond __far *bptr;
  1206.  
  1207.     if( !Database )
  1208.         return;
  1209.  
  1210.     SelectCount = 0;
  1211.     for( QChain=Database->clist; QChain; QChain=QChain->cnext )
  1212.         for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext )
  1213.             for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext )
  1214.                 if( EvaluateExpr(expr) )
  1215.                 {   QAtom->flag |= SelectFlag;
  1216.                     SelectCount++;
  1217.                 } else QAtom->flag &= ~SelectFlag;
  1218.     DisplaySelectCount();
  1219.  
  1220.     if( ZoneBoth )
  1221.     {   ForEachBond
  1222.            if( (bptr->srcatom->flag&bptr->dstatom->flag) & SelectFlag )
  1223.            {   bptr->flag |= SelectFlag;
  1224.            } else bptr->flag &= ~SelectFlag;
  1225.     } else
  1226.         ForEachBond
  1227.            if( (bptr->srcatom->flag|bptr->dstatom->flag) & SelectFlag )
  1228.            {   bptr->flag |= SelectFlag;
  1229.            } else bptr->flag &= ~SelectFlag;
  1230. }
  1231.  
  1232.  
  1233. static void RestrictZoneExpr( expr )
  1234.     Expr *expr;
  1235. {
  1236.     register Bond __far *bptr;
  1237.     register int flag;
  1238.  
  1239.     if( !Database )
  1240.         return;
  1241.  
  1242.     DrawAtoms = False;   MaxAtomRadius = 0;
  1243.     DrawBonds = False;   MaxBondRadius = 0;
  1244.  
  1245.     SelectCount = 0;
  1246.     for( QChain=Database->clist; QChain; QChain=QChain->cnext )
  1247.         for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext )
  1248.             for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext )
  1249.                 if( EvaluateExpr(expr) )
  1250.                 {   QAtom->flag |= SelectFlag;
  1251.                     SelectCount++;
  1252.  
  1253.                     if( QAtom->flag & SphereFlag )
  1254.                     {   DrawAtoms = True;
  1255.                         if( QAtom->irad>MaxAtomRadius )
  1256.                             MaxAtomRadius = QAtom->irad;
  1257.                     }
  1258.                 }  else QAtom->flag &= ~(SelectFlag|SphereFlag);
  1259.     DisplaySelectCount();
  1260.  
  1261.     ForEachBond
  1262.     {   /* Ignore ZoneBoth setting! */
  1263.         flag = bptr->dstatom->flag & bptr->srcatom->flag;
  1264.         if( flag & SelectFlag )
  1265.         {   bptr->flag |= SelectFlag;
  1266.             if( bptr->flag & CylinderFlag )
  1267.             {   DrawBonds = True;
  1268.                 if( bptr->irad>MaxBondRadius )
  1269.                     MaxBondRadius = bptr->irad;
  1270.             } else if( bptr->flag&WireFlag )
  1271.                 DrawBonds = True;
  1272.         } else bptr->flag &= ~(SelectFlag|DrawBondFlag);
  1273.     }
  1274.  
  1275.     DetermineClipping();
  1276.     VoxelsClean = False;
  1277.     BucketFlag = False;
  1278. }
  1279.  
  1280.  
  1281. static void CentreZoneExpr( expr )
  1282.     Expr *expr;
  1283. {
  1284.     register Real x, y, z;
  1285.     register Long count;
  1286.  
  1287.     if( !Database )
  1288.         return;
  1289.  
  1290.     count = 0;
  1291.     x = y = z = 0.0;
  1292.     for( QChain=Database->clist; QChain; QChain=QChain->cnext )
  1293.         for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext )
  1294.             for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext )
  1295.                 if( EvaluateExpr(expr) )
  1296.                 {   x += (Real)QAtom->xorg;
  1297.                     y += (Real)QAtom->yorg;
  1298.                     z += (Real)QAtom->zorg;
  1299.                     count++;
  1300.                 }
  1301.  
  1302.     if( count )
  1303.     {   CenX = (Long)(x/count);
  1304.         CenY = (Long)(y/count);
  1305.         CenZ = (Long)(z/count);
  1306.     } else
  1307.     {   if( CommandActive ) WriteChar('\n');
  1308.         WriteString("No Atoms to Centre!\n");
  1309.         CommandActive = False;
  1310.     }
  1311. }
  1312.  
  1313.  
  1314. static Expr *ParseRange( neg )
  1315.     int neg;
  1316. {
  1317.     register Expr *tmp1,*tmp2;
  1318.  
  1319.     tmp1 = AllocateNode();
  1320.     tmp1->type = OpLftProp|OpRgtVal;
  1321.     tmp1->rgt.val = neg? -TokenValue : TokenValue;
  1322.     tmp1->lft.val = PropResId;
  1323.     if( FetchToken()!='-' )
  1324.     {   tmp1->type |= OpEqual;
  1325.         return( tmp1 );
  1326.     }
  1327.  
  1328.     if( FetchToken() == '-' )
  1329.     {   FetchToken();
  1330.         neg = True;
  1331.     } else neg = False;
  1332.  
  1333.     if( CurToken != NumberTok )
  1334.     {   CommandError(ErrorMsg[ErrNotNum]);
  1335.         DeAllocateExpr( tmp1 );
  1336.         return( (Expr*)NULL );
  1337.     }
  1338.  
  1339.     tmp1->type |= OpMoreEq;
  1340.     tmp2 = AllocateNode();
  1341.     tmp2->rgt.ptr = tmp1;
  1342.     tmp2->type = OpAnd;
  1343.  
  1344.     tmp1 = AllocateNode();
  1345.     tmp1->type = OpLftProp|OpRgtVal|OpLessEq;
  1346.     tmp1->rgt.val = neg? -TokenValue : TokenValue;
  1347.     tmp1->lft.val = PropResId;
  1348.     tmp2->lft.ptr = tmp1;
  1349.  
  1350.     FetchToken();
  1351.     return( tmp2 );
  1352. }
  1353.  
  1354.  
  1355. static Expr *ParseExpression( level )
  1356.     int level;
  1357. {
  1358.     register Expr *tmp1,*tmp2;
  1359.     register int done, pred;
  1360.     register int neg;
  1361.  
  1362.     switch( level )
  1363.     {    case(0): /* Disjunctions */
  1364.                   tmp1 = ParseExpression(1);
  1365.                   while( (CurToken==OrTok) || (CurToken=='|') ||
  1366.                          (CurToken==',') )
  1367.                   {   if( CurToken=='|' )
  1368.                       {   if( FetchToken()=='|' )
  1369.                               FetchToken();
  1370.                       } else FetchToken();
  1371.  
  1372.                       tmp2 = AllocateNode();
  1373.                       tmp2->type = OpOr;
  1374.                       tmp2->lft.ptr = tmp1;
  1375.                       tmp2->rgt.ptr = NULL;
  1376.                       if( !(tmp1=ParseExpression(1)) )
  1377.                       {   DeAllocateExpr(tmp2);
  1378.                           return( tmp1 );
  1379.                       }
  1380.                       tmp2->rgt.ptr = tmp1;
  1381.                       tmp1 = tmp2;
  1382.                   }
  1383.                   return( tmp1 );
  1384.  
  1385.          case(1): /* Conjunctions */
  1386.                   tmp1 = ParseExpression(2);
  1387.                   while( (CurToken==AndTok) || (CurToken=='&') )
  1388.                   {   if( CurToken=='&' )
  1389.                       {   if( FetchToken()=='&' )
  1390.                               FetchToken();
  1391.                       } else FetchToken();
  1392.  
  1393.                       tmp2 = AllocateNode();
  1394.                       tmp2->type = OpAnd;
  1395.                       tmp2->lft.ptr = tmp1;
  1396.                       tmp2->rgt.ptr = NULL;
  1397.                       if( !(tmp1=ParseExpression(2)) )
  1398.                       {   DeAllocateExpr(tmp2);
  1399.                           return( tmp1 );
  1400.                       }
  1401.                       tmp2->rgt.ptr = tmp1;
  1402.                       tmp1 = tmp2;
  1403.                   }
  1404.                   return( tmp1 );
  1405.  
  1406.          case(2): /* Primitives */
  1407.                   if( IsPredTok(CurToken) )
  1408.                   {   switch( CurToken )
  1409.                       {   case(HelixTok):    if( InfoHelixCount<0 )
  1410.                                                  DetermineStructure();
  1411.                                              pred = PredHelix;
  1412.                                              break;
  1413.                           case(SheetTok):    if( InfoLadderCount<0 )
  1414.                                                  DetermineStructure();
  1415.                                              pred = PredSheet;
  1416.                                              break;
  1417.               case(TurnTok):     if( InfoTurnCount<0 )
  1418.                                                  DetermineStructure();
  1419.                                              pred = PredTurn;
  1420.                                              break;
  1421.                           case(CystineTok):  if( InfoSSBondCount<0 )
  1422.                                                  FindDisulphideBridges();
  1423.                                              pred = PredCystine;     
  1424.                                              break;
  1425.                           case(SelectedTok): pred = PropSelect;      break;
  1426.                           default:  pred = PredAbsChr(PredTokOrd(CurToken));
  1427.                       }
  1428.  
  1429.                       tmp1 = AllocateNode();
  1430.                       tmp1->type = OpConst|OpLftProp|OpRgtVal;
  1431.                       tmp1->lft.val = pred;
  1432.                       FetchToken();
  1433.                       return( tmp1 );
  1434.  
  1435.                   } else if( IsPropTok(CurToken) )
  1436.                   {   tmp1 = AllocateNode();
  1437.                       tmp1->type = OpLftProp|OpRgtVal;
  1438.                       switch( CurToken )
  1439.                       {   case(TemperatureTok): pred = PropTemp;   break;
  1440.                           case(RadiusTok):      pred = PropRad;    break;
  1441.                           case(AtomNoTok):      pred = PropIdent;  break;
  1442.                           case(ResNoTok):       pred = PropResId;  break;
  1443.                       }
  1444.                       tmp1->lft.val = pred;
  1445.  
  1446.                       FetchToken();
  1447.                       if( CurToken=='=' )
  1448.                       {   tmp1->type |= OpEqual;
  1449.                           if( FetchToken()=='=' )
  1450.                               FetchToken();
  1451.                       } else if( CurToken=='<' )
  1452.                       {   FetchToken();
  1453.                           if( CurToken=='>' )
  1454.                           {   tmp1->type |= OpNotEq;
  1455.                               FetchToken();
  1456.                           } else if( CurToken=='=' )
  1457.                           {   tmp1->type |= OpLessEq;
  1458.                               FetchToken();
  1459.                           } else tmp1->type |= OpLess;
  1460.                       } else if( CurToken=='>' )
  1461.                       {   if( FetchToken()=='=' )
  1462.                           {   tmp1->type |= OpMoreEq;
  1463.                               FetchToken();
  1464.                           } else tmp1->type |= OpMore;
  1465.                       } else if( (CurToken=='!') || (CurToken=='/') )
  1466.                       {   if( NextIf('=',ErrBadExpr) )
  1467.                           {   DeAllocateExpr( tmp1 );
  1468.                               return( (Expr*)NULL );
  1469.                           } else tmp1->type |= OpNotEq;
  1470.                           FetchToken();
  1471.                       } else
  1472.                       {   CommandError(ErrorMsg[ErrBadExpr]);
  1473.                           DeAllocateExpr( tmp1 );
  1474.                           return( (Expr*)NULL );
  1475.                       }
  1476.  
  1477.  
  1478.                       if( CurToken == '-' )
  1479.                       {   FetchToken();
  1480.                           neg = True;
  1481.                       } else neg = False;
  1482.  
  1483.                       if( CurToken!=NumberTok )
  1484.                       {   CommandError(ErrorMsg[ErrNotNum]);
  1485.                           DeAllocateExpr( tmp1 );
  1486.                           return( (Expr*)NULL );
  1487.                       } 
  1488.  
  1489.                       tmp1->rgt.val = neg? -TokenValue : TokenValue;
  1490.                       FetchToken();
  1491.                       return( tmp1 );
  1492.                       
  1493.                   } else switch( CurToken )
  1494.                   {   case('('):    FetchToken();
  1495.                                     if( !(tmp1=ParseExpression(0)) )
  1496.                                         return( (Expr*)NULL );
  1497.  
  1498.                                     if( CurToken!=')' )
  1499.                                     {   CommandError(ErrorMsg[ErrParen]);
  1500.                                         DeAllocateExpr( tmp1 );
  1501.                                         return( (Expr*)NULL );
  1502.                                     }
  1503.                                     FetchToken();
  1504.                                     return(tmp1);
  1505.  
  1506.                       case('!'): case('~'):
  1507.                       case(NotTok): FetchToken();
  1508.                                     if( !(tmp1=ParseExpression(2)) )
  1509.                                         return( (Expr*)NULL );
  1510.  
  1511.                                     tmp2 = AllocateNode();
  1512.                                     tmp2->type = OpNot | OpRgtVal;
  1513.                                     tmp2->lft.ptr = tmp1;
  1514.                                     return( tmp2 );
  1515.  
  1516.                       case('-'):    if( NextIf(NumberTok,ErrNotNum) )
  1517.                                         return( (Expr*)NULL );
  1518.                                     return( ParseRange(True) );
  1519.  
  1520.                       case(NumberTok):
  1521.                                     return( ParseRange(False) );
  1522.  
  1523.                       case(WithinTok):
  1524.                                     if( NextIf('(',ErrFunc) )
  1525.                                         return( (Expr*)NULL );
  1526.                                     if( NextIf(NumberTok,ErrNotNum) )
  1527.                                         return( (Expr*)NULL );
  1528.                                     if( TokenValue>10000 )
  1529.                                     {   CommandError(ErrorMsg[ErrBigNum]);
  1530.                                         return( (Expr*)NULL );
  1531.                                     } else pred = TokenValue;
  1532.                                     if( NextIf(',',ErrNotSep) )
  1533.                                         return( (Expr*)NULL );
  1534.  
  1535.                                     FetchToken();
  1536.                                     if( !(tmp1=ParseExpression(0)) )
  1537.                                         return( (Expr*)NULL );
  1538.  
  1539.                                     if( CurToken!=')' )
  1540.                                     {   CommandError(ErrorMsg[ErrParen]);
  1541.                                         DeAllocateExpr( tmp1 );
  1542.                                         return( (Expr*)NULL );
  1543.                                     }
  1544.  
  1545.                                     FetchToken();
  1546.                                     if( !pred )
  1547.                                         return( tmp1 );
  1548.  
  1549.                                     tmp2 = AllocateNode();
  1550.                                     tmp2->type = OpWithin;
  1551.                                     tmp2->lft.limit = (Long)pred*pred;
  1552.                                     tmp2->rgt.set = BuildAtomSet(tmp1);
  1553.                     DeAllocateExpr(tmp1);
  1554.                                     return( tmp2 );
  1555.  
  1556.                       default:      if( CurToken==IdentTok )
  1557.                                     {   tmp1 = LookUpSetExpr(TokenIdent);
  1558.                                         if( tmp1 )
  1559.                                         {   FetchToken();
  1560.                                             return(tmp1);
  1561.                                         }
  1562.                                     }
  1563.  
  1564.                                     TokenPtr = TokenStart;
  1565.                                     done = ParsePrimitiveExpr(&TokenPtr);
  1566.                                     FetchToken();
  1567.  
  1568.                                     if( !done )
  1569.                                     {   CommandError(ErrorMsg[ErrBadExpr]);
  1570.                                         DeAllocateExpr( QueryExpr );
  1571.                                         return( (Expr*)NULL );
  1572.                                     } else return( QueryExpr );
  1573.                   }
  1574.     }
  1575.     return( (Expr*)NULL );
  1576. }
  1577.  
  1578. static void ExecuteSetCommand()
  1579. {
  1580.     register int option;
  1581.  
  1582.     switch( FetchToken() )
  1583.     {   case(SlabModeTok):
  1584.             option = -1;
  1585.             FetchToken();
  1586.             if( CurToken==RejectTok )
  1587.             {   option = SlabReject;
  1588.             } else if( CurToken==HalfTok )
  1589.             {   option = SlabHalf;
  1590.             } else if( CurToken==HollowTok )
  1591.             {   option = SlabHollow;
  1592.             } else if( CurToken==SolidTok )
  1593.             {   option = SlabClose;
  1594.             } else if( CurToken==SectionTok )
  1595.                 option = SlabSection;
  1596.  
  1597.             if( option != -1 )
  1598.             {   if( UseSlabPlane && (SlabMode!=option) )
  1599.                     ReDrawFlag |= RFRefresh;
  1600.                 SlabMode = option;
  1601.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1602.             break;
  1603.  
  1604.         case(ShadowTok):
  1605.             FetchToken();
  1606.             if( CurToken==TrueTok )
  1607.             {   UseShadow = True;
  1608.                 ReviseInvMatrix();
  1609.                 VoxelsClean = False;
  1610.                 UseSlabPlane = False;
  1611.                 ReDrawFlag |= RFRefresh;
  1612.                 ReAllocBuffers();
  1613.             } else if( CurToken==FalseTok )
  1614.             {   ReDrawFlag |= RFRefresh;
  1615.                 UseShadow = False;
  1616.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1617.             break;
  1618.                                   
  1619.         case(SpecularTok):
  1620.             FetchToken();
  1621.             if( CurToken==TrueTok )
  1622.             {   FakeSpecular = True;
  1623.                 ReDrawFlag |= RFColour;
  1624.             } else if( CurToken==FalseTok )
  1625.             {   FakeSpecular = False;
  1626.                 ReDrawFlag |= RFColour;
  1627.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1628.             break;
  1629.  
  1630.         case(SpecPowerTok):
  1631.             FetchToken();
  1632.             if( !CurToken )
  1633.             {   SpecPower = 8;
  1634.                 ReDrawFlag |= RFColour;
  1635.             } else if( CurToken==NumberTok )
  1636.             {   if( TokenValue<=100 )
  1637.                 {   ReDrawFlag |= RFColour;
  1638.                     SpecPower = TokenValue;
  1639.                 } else 
  1640.                     CommandError(ErrorMsg[ErrBigNum]);
  1641.             } else CommandError(ErrorMsg[ErrNotNum]);
  1642.             break;
  1643.  
  1644.         case(AmbientTok):
  1645.             FetchToken();
  1646.             if( !CurToken )
  1647.             {   ReDrawFlag |= RFColour;
  1648.                 Ambient = DefaultAmbient;
  1649.             } else if( CurToken==NumberTok )
  1650.             {   if( TokenValue<=100 )
  1651.                 {   Ambient = TokenValue/100.0;
  1652.                     ReDrawFlag |= RFColour;
  1653.                 } else
  1654.                     CommandError(ErrorMsg[ErrBigNum]);
  1655.             } else CommandError(ErrorMsg[ErrNotNum]);
  1656.             break;
  1657.  
  1658.         case(HeteroTok):
  1659.             FetchToken();
  1660.             if( CurToken==TrueTok )
  1661.             {   HetaGroups = True;
  1662.             } else if( CurToken==FalseTok )
  1663.             {   HetaGroups = False;
  1664.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1665.             break;
  1666.                                   
  1667.         case(HydrogenTok):
  1668.             FetchToken();
  1669.             if( CurToken==TrueTok )
  1670.             {   Hydrogens = True;
  1671.             } else if( CurToken==FalseTok )
  1672.             {   Hydrogens = False;
  1673.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1674.             break;
  1675.                                   
  1676.  
  1677.         case(BackgroundTok):
  1678.             FetchToken();
  1679.             if( !CurToken )
  1680.             {   CommandError(ErrorMsg[ErrNoCol]);
  1681.             } else if( ParseColour() )
  1682.             {   ReDrawFlag |= RFColour;
  1683.                 BackR = RVal;
  1684.                 BackG = GVal;
  1685.                 BackB = BVal;
  1686. #ifndef IBMPC
  1687.                 FBClear = False;
  1688. #endif
  1689.             } else if( CurToken )
  1690.                 CommandError(ErrorMsg[ErrColour]);
  1691.             break;
  1692.  
  1693.         case(BondModeTok):
  1694.             FetchToken();
  1695.             if( !CurToken || (CurToken==OrTok) )
  1696.             {   ZoneBoth = False;
  1697.             } else if( CurToken==AndTok )
  1698.             {   ZoneBoth = True;
  1699.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1700.             break;
  1701.             
  1702.         case(HBondTok):
  1703.             FetchToken();
  1704.             if( !CurToken || (CurToken==SidechainTok) )
  1705.             {   ReDrawFlag |= RFRefresh;
  1706.                 HBondMode = False;
  1707.             } else if( CurToken==BackboneTok )
  1708.             {   ReDrawFlag |= RFRefresh;
  1709.                 HBondMode = True;
  1710.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1711.             break;
  1712.  
  1713.         case(SSBondTok):
  1714.             FetchToken();
  1715.             if( !CurToken || (CurToken==SidechainTok) )
  1716.             {   ReDrawFlag |= RFRefresh;
  1717.                 SSBondMode = False;
  1718.             } else if( CurToken==BackboneTok )
  1719.             {   ReDrawFlag |= RFRefresh;
  1720.                 SSBondMode = True;
  1721.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1722.             break;
  1723.  
  1724.         case(HourGlassTok):
  1725.             FetchToken();
  1726.             if( CurToken==TrueTok )
  1727.             {   UseHourGlass = True;
  1728.             } else if( CurToken==FalseTok )
  1729.             {   UseHourGlass = False;
  1730.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1731.             break;
  1732.  
  1733.         case(StrandsTok):
  1734.             FetchToken();
  1735.             if( !CurToken )
  1736.             {   ReDrawFlag |= RFRefresh;
  1737.                 SplineCount = 5;
  1738.             } else if( CurToken==NumberTok )
  1739.             {   if( (TokenValue>0) && (TokenValue<=5) )
  1740.                 {   SplineCount = TokenValue;
  1741.                     ReDrawFlag |= RFRefresh;
  1742.                 } else if( TokenValue==9 )
  1743.                 {   ReDrawFlag |= RFRefresh;
  1744.                     SplineCount = 9;
  1745.                 } else CommandError(ErrorMsg[ErrBadOpt]);
  1746.             } else CommandError(ErrorMsg[ErrNotNum]);
  1747.             break;
  1748.  
  1749.         case(MouseTok):
  1750.             FetchToken();
  1751.             if( !CurToken || (CurToken==RasMolTok) )
  1752.             {   if( Interactive )
  1753.                     SetMouseMode( MMRasMol );
  1754.             } else if( CurToken==InsightTok )
  1755.             {   if( Interactive )
  1756.                     SetMouseMode( MMInsight );
  1757.             } else if( CurToken==QuantaTok )
  1758.             {   if( Interactive )
  1759.                     SetMouseMode( MMQuanta );
  1760.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1761.             break;
  1762.  
  1763.         case(DisplayTok):
  1764.             FetchToken();
  1765.             if( !CurToken || (CurToken==NormalTok) )
  1766.             {   ReDrawFlag |= RFRefresh | RFColour;
  1767.                 DisplayMode = 0;
  1768.             } else if( CurToken==SelectedTok )
  1769.             {   ReDrawFlag |= RFRefresh | RFColour;
  1770.                 DisplayMode = 1;
  1771.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1772.             break;
  1773.  
  1774.         case(RibbonTok):
  1775.             FetchToken();
  1776.             if( !CurToken || (CurToken==SolidTok) )
  1777.             {   ReDrawFlag |= RFRefresh;
  1778.                 RibbonMode = 1;
  1779.             } else if( (CurToken==WireframeTok) || (CurToken==StrandsTok) )
  1780.             {   ReDrawFlag |= RFRefresh;
  1781.                 RibbonMode = 0;
  1782.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1783.             break;
  1784.  
  1785.         case(AxesTok):
  1786.             FetchToken();
  1787.             if( !CurToken || (CurToken==FalseTok) )
  1788.             {   ReDrawFlag |= RFRefresh;
  1789.                 DrawAxes = False;
  1790.             } else if( CurToken == TrueTok )
  1791.             {   ReDrawFlag |= RFRefresh;
  1792.                 DrawAxes = True;
  1793.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1794.             break;
  1795.  
  1796.         case(BoundBoxTok):
  1797.             FetchToken();
  1798.             if( !CurToken || (CurToken==FalseTok) )
  1799.             {   ReDrawFlag |= RFRefresh;
  1800.                 DrawBoundBox = False;
  1801.             } else if( CurToken == TrueTok )
  1802.             {   ReDrawFlag |= RFRefresh;
  1803.                 DrawBoundBox = True;
  1804.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1805.             break;
  1806.  
  1807.         case(UnitCellTok):
  1808.             FetchToken();
  1809.             if( !CurToken || (CurToken==FalseTok) )
  1810.             {   ReDrawFlag |= RFRefresh;
  1811.                 DrawUnitCell = False;
  1812.             } else if( CurToken == TrueTok )
  1813.             {   ReDrawFlag |= RFRefresh;
  1814.                 DrawUnitCell = True;
  1815.             } else CommandError(ErrorMsg[ErrBadOpt]);
  1816.             break;
  1817.  
  1818.         default:
  1819.             CommandError(ErrorMsg[ErrParam]);
  1820.     }
  1821. }
  1822.  
  1823.  
  1824. static void ExecuteColourCommand()
  1825. {
  1826.     switch( FetchToken() )
  1827.     {   case(AtomTok):
  1828.             FetchToken();
  1829.         default:
  1830.             if( !CurToken )
  1831.             {   CommandError(ErrorMsg[ErrNoCol]);
  1832.             } else switch( CurToken )
  1833.             {   case(CPKTok):         CPKColourAttrib(); 
  1834.                                       ReDrawFlag |= RFColour; break;
  1835.  
  1836.                 case(AminoTok):       AminoColourAttrib();
  1837.                                       ReDrawFlag |= RFColour; break;
  1838.  
  1839.                 case(ShapelyTok):     ShapelyColourAttrib();
  1840.                                       ReDrawFlag |= RFColour; break;
  1841.                 
  1842.                 case(UserTok):        UserMaskAttrib(MaskColourFlag);
  1843.                                       ReDrawFlag |= RFColour; break;
  1844.  
  1845.                 case(GroupTok):       ScaleColourAttrib(GroupAttr);
  1846.                                       ReDrawFlag |= RFColour; break;
  1847.  
  1848.                 case(ChainTok):       ScaleColourAttrib(ChainAttr);
  1849.                                       ReDrawFlag |= RFColour; break;
  1850.  
  1851.                 case(TemperatureTok): ScaleColourAttrib(TempAttr);
  1852.                                       ReDrawFlag |= RFColour; break;
  1853.  
  1854.                 case(StructureTok):   StructColourAttrib();
  1855.                                       ReDrawFlag |= RFColour; break;
  1856.  
  1857.                 default:  if( ParseColour() )
  1858.                           {   MonoColourAttrib(RVal,GVal,BVal);
  1859.                               ReDrawFlag |= RFColour;
  1860.                           } else CommandError(ErrorMsg[ErrColour]);
  1861.             }
  1862.             break;
  1863.  
  1864.         case(BondTok):    
  1865.             FetchToken();
  1866.             if( !CurToken )
  1867.             {   CommandError(ErrorMsg[ErrNoCol]);
  1868.             } else if( CurToken==NoneTok )
  1869.             {   ColourBondNone();
  1870.                 ReDrawFlag |= RFColour;
  1871.             } else if( ParseColour() )
  1872.             {   ColourBondAttrib(RVal,GVal,BVal);
  1873.                 ReDrawFlag |= RFColour;
  1874.             } else CommandError(ErrorMsg[ErrColour]);
  1875.             break;
  1876.  
  1877.         case(TraceTok):
  1878.         case(BackboneTok):
  1879.             FetchToken();
  1880.             if( !CurToken )
  1881.             {   CommandError(ErrorMsg[ErrNoCol]);
  1882.             } else if( CurToken==NoneTok )
  1883.             {   ColourBackNone();
  1884.                 ReDrawFlag |= RFColour;
  1885.             } else if( ParseColour() )
  1886.             {   ColourBackAttrib(RVal,GVal,BVal);
  1887.                 ReDrawFlag |= RFColour;
  1888.             } else CommandError(ErrorMsg[ErrColour]);
  1889.             break;
  1890.  
  1891.         case(SSBondTok):
  1892.             FetchToken();
  1893.             if( !CurToken )
  1894.             {   CommandError(ErrorMsg[ErrNoCol]);
  1895.             } else if( CurToken==NoneTok )
  1896.             {   ReDrawFlag |= RFColour;
  1897.                 ColourHBondNone( False );
  1898.             } else if( ParseColour() )
  1899.             {   ReDrawFlag |= RFColour;
  1900.                 ColourHBondAttrib(False,RVal,GVal,BVal);
  1901.             } else CommandError(ErrorMsg[ErrColour]);
  1902.             break;
  1903.  
  1904.         case(HBondTok):
  1905.             FetchToken();
  1906.             if( !CurToken )
  1907.             {   CommandError(ErrorMsg[ErrNoCol]);
  1908.             } else if( CurToken==NoneTok )
  1909.             {   ReDrawFlag |= RFColour;
  1910.                 ColourHBondNone( True );
  1911.             } else if( CurToken==TypeTok )
  1912.             {   ReDrawFlag |= RFColour;
  1913.                 ColourHBondType();
  1914.             } else if( ParseColour() )
  1915.             {   ReDrawFlag |= RFColour;
  1916.                 ColourHBondAttrib(True,RVal,GVal,BVal);
  1917.             } else CommandError(ErrorMsg[ErrColour]);
  1918.             break;
  1919.  
  1920.         case(RibbonTok):
  1921.             FetchToken();
  1922.             if( !CurToken )
  1923.             {   CommandError(ErrorMsg[ErrNoCol]);
  1924.             } else if( CurToken==NoneTok )
  1925.             {   ReDrawFlag |= RFColour;
  1926.                 ColourRibbonNone();
  1927.             } else if( ParseColour() )
  1928.             {   ReDrawFlag |= RFColour;
  1929.                 ColourRibbonAttrib(RVal,GVal,BVal);
  1930.             } else CommandError(ErrorMsg[ErrColour]);
  1931.             break;
  1932.     }
  1933. }
  1934.  
  1935.  
  1936. static void ExecuteShowCommand()
  1937. {
  1938.     register Chain __far *chn;
  1939.     register Group __far *grp;
  1940.     register int chain,count;
  1941.     register char *str;
  1942.     char buffer[40];
  1943.  
  1944.     switch( FetchToken() )
  1945.     {   case(InfoTok):
  1946.                 DescribeMolecule();
  1947.                 break;
  1948.  
  1949.         case(SequenceTok):
  1950.                 if( CommandActive )
  1951.                     WriteChar('\n');
  1952.                 CommandActive = False;
  1953.             
  1954.                 for( chn=Database->clist; chn; chn=chn->cnext )
  1955.                 {   chain = (InfoChainCount<2);  count = 0;
  1956.                     for( grp=chn->glist; grp; grp=grp->gnext )
  1957.                         if( grp->alist && !(grp->alist->flag&HeteroFlag) )
  1958.                         {   if( !chain )
  1959.                             {   WriteString("Chain ");
  1960.                                 WriteChar(chn->ident);
  1961.                                 WriteString(":\n");
  1962.                                 chain = True;
  1963.                             }
  1964.  
  1965.                             if( count == 10 )
  1966.                             {   WriteChar('\n');
  1967.                                 count = 1;
  1968.                             } else count++;
  1969.  
  1970.                             str = Residue[grp->refno];
  1971.                             WriteChar(str[0]);
  1972.                             WriteChar(str[1]);
  1973.                             WriteChar(str[2]);
  1974.  
  1975.                             sprintf(buffer,"%-3d ",grp->serno);
  1976.                             WriteString(buffer);
  1977.                         }
  1978.                     WriteChar('\n');
  1979.                 }
  1980.  
  1981.                 WriteChar('\n');
  1982.                 break;
  1983.  
  1984.         case(SymmetryTok):
  1985.                 if( CommandActive )
  1986.                     WriteChar('\n');
  1987.                 CommandActive = False;
  1988.  
  1989.                 if( *InfoSpaceGroup )
  1990.                 {   sprintf(buffer,"Space Group ... %s\n",InfoSpaceGroup);
  1991.                     WriteString(buffer);
  1992.                 } else WriteString("No Crystal Symmetry Data!\n");
  1993.                 WriteChar('\n');
  1994.                 break;
  1995.  
  1996.         default:
  1997.             CommandError(ErrorMsg[ErrBadArg]);
  1998.     }
  1999. }
  2000.  
  2001. void ZapDatabase()
  2002. {
  2003.     register int i;
  2004.  
  2005.     for( i=0; i<8; i++ )
  2006.         DialValue[i] = 0.0;
  2007.  
  2008.     DestroyDatabase();
  2009.     ResetSymbolTable();
  2010.     ResetTransform();
  2011.     ResetRenderer();
  2012.  
  2013.     ZoneBoth = False;
  2014.     HetaGroups = True;    
  2015.     Hydrogens = True;
  2016.  
  2017.     ResetColourMap();
  2018.     DefineColourMap();
  2019.     ClearBuffers();
  2020.     ReDrawFlag = 0;
  2021.  
  2022.     if( Interactive )
  2023.     {   UpdateScrollBars();
  2024.         ClearImage();
  2025.     }
  2026. }
  2027.  
  2028.  
  2029. static void WriteImageFile( name, type )
  2030.     char *name;  int type;
  2031. {
  2032.     if( !type )
  2033. #ifdef EIGHTBIT
  2034.         type = GIFTok;
  2035. #else
  2036.         type = PPMTok;
  2037. #endif
  2038.  
  2039.  
  2040.     switch( type )
  2041.     {   case(GIFTok):     WriteGIFFile(name);             break;
  2042.         case(BMPTok):     WriteBMPFile(name);             break;
  2043.         case(PPMTok):     WritePPMFile(name,True);        break;
  2044.         case(SUNTok):     WriteRastFile(name,False);      break;
  2045.         case(SUNRLETok):  WriteRastFile(name,True);       break;
  2046.         case(EPSFTok):    WriteEPSFFile(name,True,True);  break;
  2047.         case(MonoPSTok):  WriteEPSFFile(name,False,True); break;
  2048.         case(VectPSTok):  WriteVectPSFile(name);          break;
  2049.  
  2050.         case(MolScriptTok):  WriteMolScriptFile(name);  break;
  2051.         case(ScriptTok):     WriteScriptFile(name);     break;
  2052.     }
  2053. }
  2054.  
  2055.  
  2056. int ExecuteCommand()
  2057. {
  2058.     register char *param;
  2059.     register int option;
  2060.     register int i,done;
  2061.     FILE *script;
  2062.  
  2063.     TokenPtr = CurLine;
  2064.     if( !FetchToken() )
  2065.     {   TokenPtr = NULL;
  2066.         return( False );
  2067.     }
  2068.  
  2069.     switch( CurToken )
  2070.     {   case(LoadTok):    if( !Database )
  2071.                           {   FetchToken();
  2072.                               option = FormatPDB;
  2073.                               if( !*TokenPtr || *TokenPtr==' ' )
  2074.                               {   if( CurToken==PDBTok )
  2075.                                   {   FetchToken();  option = FormatPDB;
  2076.                                   } else if( CurToken==XYZTok )
  2077.                                   {   FetchToken();  option = FormatXYZ;
  2078.                                   } else if( CurToken==AlchemyTok )
  2079.                                   {   FetchToken();  option = FormatAlchemy;
  2080.                                   }
  2081.                               }
  2082.  
  2083.                               done = (FileDepth = -1);
  2084.                               if( !CurToken )
  2085.                               {   CommandError(ErrorMsg[ErrFilNam]);
  2086.                                   break;
  2087.                               } else if( CurToken==StringTok )
  2088.                               {      FetchFile(option,done,TokenIdent);
  2089.                               } else FetchFile(option,done,TokenStart);
  2090.                               CurToken = 0;
  2091.  
  2092.                               if( Database )
  2093.                               {   ReDrawFlag |= RFRefresh | RFColour;
  2094.                                   if( InfoBondCount < 1 )
  2095.                                   {   EnableBackBone(False,80);
  2096.                                   } else EnableWireFrame(True,0);
  2097.                                   CPKColourAttrib();
  2098.                               }
  2099.                           } else CommandError(ErrorMsg[ErrBadLoad]);
  2100.                           break;
  2101.  
  2102.         case(SelectTok):  FetchToken();
  2103.                           if( !CurToken )
  2104.                           {   option = NormAtomFlag;
  2105.                               if( HetaGroups ) option |= HeteroFlag;
  2106.                               if( Hydrogens )  option |= HydrogenFlag;
  2107.                               SelectZone(option);
  2108.                           } else if( CurToken==AllTok )
  2109.                           {   SelectZone(AllAtomFlag);
  2110.                           } else if( CurToken==NoneTok )
  2111.                           {   SelectZone(0x00);
  2112.                           } else
  2113.                               if( QueryExpr=ParseExpression(0) )
  2114.                               {   if( !CurToken )
  2115.                                   {   SelectZoneExpr(QueryExpr);
  2116.                                   } else CommandError(ErrorMsg[ErrSyntax]);
  2117.                       DeAllocateExpr(QueryExpr);
  2118.                               }
  2119.                           break;
  2120.  
  2121.         case(RestrictTok):
  2122.                           FetchToken();
  2123.                           if( !CurToken )
  2124.                           {   option = NormAtomFlag;
  2125.                               if( HetaGroups ) option |= HeteroFlag;
  2126.                               if( Hydrogens )  option |= HydrogenFlag;
  2127.                               RestrictZone(option);
  2128.                               ReDrawFlag |= RFRefresh;
  2129.                           } else if( CurToken==AllTok )
  2130.                           {   RestrictZone(AllAtomFlag);
  2131.                               ReDrawFlag |= RFRefresh;
  2132.                           } else if( CurToken==NoneTok )
  2133.                           {   RestrictZone(0x00);
  2134.                               ReDrawFlag |= RFRefresh;
  2135.                           } else
  2136.                               if( QueryExpr=ParseExpression(0) )
  2137.                               {   if( !CurToken )
  2138.                                   {   RestrictZoneExpr(QueryExpr);
  2139.                                       ReDrawFlag |= RFRefresh;
  2140.                                   } else CommandError(ErrorMsg[ErrSyntax]);
  2141.                       DeAllocateExpr(QueryExpr);
  2142.                               } 
  2143.                           break;
  2144.  
  2145.  
  2146.         case(ColourTok):  ExecuteColourCommand();
  2147.                           break;
  2148.  
  2149.  
  2150.         case(WireframeTok):
  2151.                           FetchToken();
  2152.                           if( CurToken==FalseTok )
  2153.                           {   ReDrawFlag |= RFRefresh;
  2154.                               DisableWireFrame();
  2155.                           } else if( (CurToken==TrueTok) || !CurToken )
  2156.                           {   ReDrawFlag |= RFRefresh;
  2157.                               EnableWireFrame(True,0);
  2158.                           } else if( CurToken==NumberTok )
  2159.                           {   if( TokenValue<500 )
  2160.                               {   EnableWireFrame(False,TokenValue);
  2161.                                   ReDrawFlag |= RFRefresh;
  2162.                               } else CommandError(ErrorMsg[ErrBigNum]);
  2163.                           } else CommandError(ErrorMsg[ErrBadArg]);
  2164.                           break;
  2165.  
  2166.         case(TraceTok):
  2167.         case(BackboneTok):
  2168.                           FetchToken();
  2169.                           if( CurToken==FalseTok )
  2170.                           {   ReDrawFlag |= RFRefresh;
  2171.                               DisableBackBone();
  2172.                           } else if( (CurToken==TrueTok) || !CurToken )
  2173.                           {   ReDrawFlag |= RFRefresh;
  2174.                               EnableBackBone(True,0);
  2175.                           } else if( CurToken==NumberTok )
  2176.                           {   if( TokenValue<500 )
  2177.                               {   EnableBackBone(False,TokenValue);
  2178.                                   ReDrawFlag |= RFRefresh;
  2179.                               } else CommandError(ErrorMsg[ErrBigNum]);
  2180.                           } else CommandError(ErrorMsg[ErrBadArg]);
  2181.                           break;
  2182.  
  2183.         case(SpacefillTok):
  2184.                           FetchToken();
  2185.                           if( CurToken==FalseTok )
  2186.                           {   ReDrawFlag |= RFRefresh;
  2187.                               DisableSpacefill();
  2188.                           } else if( CurToken==NumberTok )
  2189.                           {   if( TokenValue<=500 )
  2190.                               {   SetRadiusValue( MaxFun(TokenValue,1) );
  2191.                                   ReDrawFlag |= RFRefresh;
  2192.                               } else CommandError(ErrorMsg[ErrBigNum]);
  2193.                           } else if( CurToken==UserTok )
  2194.                           {   UserMaskAttrib(MaskRadiusFlag);
  2195.                               ReDrawFlag |= RFRefresh;
  2196.                           } else if( CurToken==TemperatureTok )
  2197.                           {   ReDrawFlag |= RFRefresh;
  2198.                               SetRadiusTemperature();
  2199.                           } else if( (CurToken==TrueTok) || !CurToken )
  2200.                           {   ReDrawFlag |= RFRefresh;
  2201.                               SetVanWaalRadius();
  2202.                           } else CommandError(ErrorMsg[ErrBadArg]);
  2203.                           break;
  2204.  
  2205.         case(SSBondTok):  FetchToken();
  2206.                           if( CurToken==NumberTok )
  2207.                           {   if( TokenValue<=500 )
  2208.                               {   SetHBondStatus(False,True,TokenValue);
  2209.                                   ReDrawFlag |= RFRefresh;
  2210.                               } else CommandError(ErrorMsg[ErrBigNum]);
  2211.                           } else if( CurToken==FalseTok )
  2212.                           {   ReDrawFlag |= RFRefresh;
  2213.                               SetHBondStatus(False,False,0);
  2214.                           } else if( (CurToken==TrueTok) || !CurToken )
  2215.                           {   ReDrawFlag |= RFRefresh;
  2216.                               SetHBondStatus(False,True,0);
  2217.                           } else CommandError(ErrorMsg[ErrBadArg]);
  2218.                           break;
  2219.  
  2220.         case(HBondTok):   FetchToken();
  2221.                           if( CurToken==NumberTok )
  2222.                           {   if( TokenValue<=500 )
  2223.                               {   SetHBondStatus(True,True,TokenValue);
  2224.                                   ReDrawFlag |= RFRefresh;
  2225.                               } else CommandError(ErrorMsg[ErrBigNum]);
  2226.                           } else if( CurToken==FalseTok )
  2227.                           {   ReDrawFlag |= RFRefresh;
  2228.                               SetHBondStatus(True,False,0);
  2229.                           } else if( (CurToken==TrueTok) || !CurToken )
  2230.                           {   ReDrawFlag |= RFRefresh;
  2231.                               SetHBondStatus(True,True,0);
  2232.                           } else CommandError(ErrorMsg[ErrBadArg]);
  2233.                           break;
  2234.  
  2235.         case(RibbonTok):  FetchToken();
  2236.                           if( CurToken==NumberTok )
  2237.                           {   if( TokenValue<=1000 )
  2238.                               {   SetRibbonStatus(True,TokenValue);
  2239.                                   ReDrawFlag |= RFRefresh;
  2240.                               } else CommandError(ErrorMsg[ErrBigNum]);
  2241.                           } else if( CurToken==FalseTok )
  2242.                           {   ReDrawFlag |= RFRefresh;
  2243.                               SetRibbonStatus(False,0);
  2244.                           } else if( (CurToken==TrueTok) || !CurToken )
  2245.                           {   ReDrawFlag |= RFRefresh;
  2246.                               SetRibbonStatus(True,0);
  2247.                           } else CommandError(ErrorMsg[ErrBadArg]);
  2248.                           break;
  2249.  
  2250.         case(SlabTok):    FetchToken();
  2251.                           if( CurToken==NumberTok )
  2252.                           {   if( TokenValue<=100 )
  2253.                               {   DialValue[7] = (TokenValue-50)/50.0;
  2254.                                   /* UpdateScrollBars(); */
  2255.                                   ReDrawFlag |= RFSlab;
  2256.                                   UseSlabPlane = True;
  2257.                                   UseShadow = False;
  2258.                               } else 
  2259.                                   CommandError(ErrorMsg[ErrBigNum]);
  2260.                           } else if( CurToken==FalseTok )
  2261.                           {   if( UseSlabPlane )
  2262.                               {   ReDrawFlag |= RFRefresh;
  2263.                                   UseSlabPlane = False;
  2264.                               }
  2265.                           } else if( !CurToken || (CurToken==TrueTok) )
  2266.                           {   if( !UseSlabPlane )
  2267.                               {   ReDrawFlag |= RFRefresh;
  2268.                                   UseSlabPlane = True;
  2269.                                   UseShadow = False;
  2270.                               }
  2271.                           } else CommandError(ErrorMsg[ErrSyntax]);
  2272.                           break;
  2273.  
  2274.         case(ZoomTok):    FetchToken();
  2275.                           if( CurToken==NumberTok )
  2276.                           {   if( TokenValue<=100 )
  2277.                               {   DialValue[3] = (TokenValue-100)/100.0;
  2278.                                   ReDrawFlag |= RFZoom;
  2279.                               } else /* Magnification */
  2280.                               {   TokenValue -= 100;
  2281.                                   if( TokenValue<=(int)(100*MaxZoom) )
  2282.                                   {   DialValue[3] = TokenValue/(100*MaxZoom);
  2283.                                       ReDrawFlag |= RFZoom;
  2284.                                   } else CommandError(ErrorMsg[ErrBigNum]);
  2285.                               }
  2286.                           } else if( CurToken==TrueTok )
  2287.                           {   ReDrawFlag |= RFZoom;
  2288.                               DialValue[3] = 0.5;
  2289.                           } else if( !CurToken || (CurToken==FalseTok) )
  2290.                           {   ReDrawFlag |= RFZoom;
  2291.                               DialValue[3] = 0.0;
  2292.                           } else CommandError(ErrorMsg[ErrSyntax]);
  2293.                           /* UpdateScrollBars(); */
  2294.                           break;
  2295.  
  2296.         case(RotateTok):  FetchToken();
  2297.                           if( CurToken==XTok )
  2298.                           {   option = 0;
  2299.                           } else if( CurToken==YTok )
  2300.                           {   option = 1;
  2301.                           } else if( CurToken==ZTok )
  2302.                           {   option = 2;
  2303.                           } else
  2304.                           {   CommandError(ErrorMsg[ErrSyntax]);
  2305.                               break;
  2306.                           }
  2307.  
  2308.                           FetchToken();
  2309.                           if( done=(CurToken=='-') )
  2310.                               FetchToken();
  2311. #ifdef INVERT
  2312.                           if( option != 1 )
  2313.                   done = !done;
  2314. #endif
  2315.                           if( CurToken==NumberTok )
  2316.                           {   if( TokenValue )
  2317.                               {   if( ReDrawFlag & RFRotate )
  2318.                                       PrepareTransform();
  2319.  
  2320.                                   ReDrawFlag |= (1<<option);
  2321.                                   if( done ) TokenValue = -TokenValue;
  2322.                                   DialValue[option] += TokenValue/180.0;
  2323.  
  2324.                                   while( DialValue[option]<-1.0 )
  2325.                                       DialValue[option] += 2.0;
  2326.                                   while( DialValue[option]>1.0 )
  2327.                                       DialValue[option] -= 2.0;
  2328.                                   if( Interactive )
  2329.                                       UpdateScrollBars();
  2330.                               }
  2331.                           } else CommandError(ErrorMsg[ErrNotNum]);
  2332.                           break;
  2333.  
  2334.         case(TranslateTok):
  2335.                           FetchToken();
  2336.                           if( CurToken==XTok )
  2337.                           {   option = 4;
  2338.                           } else if( CurToken==YTok )
  2339.                           {   option = 5;
  2340.                           } else if( CurToken==ZTok )
  2341.                           {   option = 6;
  2342.                           } else
  2343.                           {   CommandError(ErrorMsg[ErrSyntax]);
  2344.                               break;
  2345.                           }
  2346.  
  2347.                           FetchToken();
  2348.                           if( done=(CurToken=='-') )
  2349.                               FetchToken();
  2350. #ifdef INVERT
  2351.               if( option == 5 )
  2352.                   done = !done;
  2353. #endif
  2354.  
  2355.                           if( CurToken==NumberTok )
  2356.                           {   if( TokenValue<=100 )
  2357.                               {   ReDrawFlag |= (1<<option);
  2358.                                   if( done ) TokenValue = -TokenValue;
  2359.                                   DialValue[option] = TokenValue/100.0;
  2360.                                   /* UpdateScrollBars(); */
  2361.                               } else CommandError(ErrorMsg[ErrBigNum]);
  2362.                           } else CommandError(ErrorMsg[ErrNotNum]);
  2363.                           break;
  2364.  
  2365.         case(CentreTok):  FetchToken();
  2366.                           if( !CurToken || (CurToken==AllTok) )
  2367.                           {   CenX = CenY = CenZ = 0;
  2368.                           } else
  2369.                               if( QueryExpr=ParseExpression(0) )
  2370.                               {   if( !CurToken )
  2371.                                   {   CentreZoneExpr(QueryExpr);
  2372.                                   } else CommandError(ErrorMsg[ErrSyntax]);
  2373.                       DeAllocateExpr(QueryExpr);
  2374.                               }
  2375.                           break;
  2376.  
  2377.         case(ResizeTok):  FetchToken();
  2378.                           break;
  2379.  
  2380.         case(ResetTok):   for( i=0; i<8; i++ )
  2381.                               DialValue[i] = 0.0;
  2382.                           ReDrawFlag |= RFDials;
  2383.               ResetTransform();
  2384.  
  2385.                           /* ReDrawFlag |= RFRefresh|RFColour; */
  2386.                           /* DisplayMode = 0;                  */
  2387.  
  2388.                           if( Interactive )
  2389.                               UpdateScrollBars();
  2390.                           break;
  2391.  
  2392.         case('?'):
  2393.         case(HelpTok):    if( !HelpFileName )
  2394.                               InitHelpFile();
  2395.                           if( HelpInfo )
  2396.                               FindHelpInfo();
  2397.               CurToken=0;
  2398.                           break;
  2399.  
  2400.         case(SetTok):     ExecuteSetCommand();
  2401.                           break;
  2402.  
  2403.         case(EchoTok):    FetchToken();
  2404.                           if( CommandActive )
  2405.                               WriteChar('\n');
  2406.                           CommandActive = False;
  2407.  
  2408.                           if( CurToken==StringTok )
  2409.                           {   WriteString(TokenIdent);
  2410.                           } else if( CurToken )
  2411.                               WriteString(TokenStart);
  2412.                           WriteChar('\n');
  2413.                           CurToken = 0;
  2414.                           break;
  2415.  
  2416.         case(DefineTok):  FetchToken();
  2417.                           if( CurToken != IdentTok ) 
  2418.                           {   CommandError(ErrorMsg[ErrSetName]);
  2419.                               break;
  2420.                           }
  2421.  
  2422.                           if( (param = (char*)malloc(TokenLength+1)) )
  2423.                           {   for( i=0; i<=TokenLength; i++ )
  2424.                                   param[i] = TokenIdent[i];
  2425.  
  2426.                               if( FetchToken() )
  2427.                               {   if( QueryExpr=ParseExpression(0) )
  2428.                                   {   done = DefineSetExpr(param,QueryExpr);
  2429.                                   } else done = True;
  2430.                               } else done = DefineSetExpr(param,(Expr*)NULL);
  2431.                           } else done = False;
  2432.  
  2433.                           if( !done )
  2434.                               CommandError(ErrorMsg[ErrBadSet]);
  2435.                           break;
  2436.  
  2437.         case(BackgroundTok):
  2438.                           FetchToken();
  2439.                           if( !CurToken )
  2440.                           {   CommandError(ErrorMsg[ErrNoCol]);
  2441.                           } else if( ParseColour() )
  2442.                           {   ReDrawFlag |= RFColour;
  2443.                               BackR = RVal;
  2444.                               BackG = GVal;
  2445.                               BackB = BVal;
  2446. #ifndef IBMPC
  2447.                               FBClear = False;
  2448. #endif
  2449.                           } else if( CurToken )
  2450.                               CommandError(ErrorMsg[ErrColour]);
  2451.                           break;
  2452.  
  2453.         case(SaveTok):    option = FetchToken();
  2454.                           if( IsMoleculeFormat(option) )
  2455.                           {   if( !*TokenPtr || *TokenPtr==' ' )
  2456.                                   FetchToken();
  2457.                           } else option = PDBTok;
  2458.  
  2459.                           if( !CurToken )
  2460.                           {   CommandError(ErrorMsg[ErrFilNam]);
  2461.                               break;
  2462.                           } else if( CurToken==StringTok )
  2463.                           {      ProcessFileName(TokenIdent);
  2464.                           } else ProcessFileName(TokenStart);
  2465.                           param = DataFileName;
  2466.                           CurToken = 0;
  2467.  
  2468.                           switch(option)
  2469.                           {   case(PDBTok):     SavePDBMolecule(param); break;
  2470.                               case(XYZTok):     SaveXYZMolecule(param); break;
  2471.                               case(AlchemyTok): SaveAlchemyMolecule(param);
  2472.                                                 break;
  2473.                           } break;
  2474.  
  2475.         case(WriteTok):   option = FetchToken();
  2476.                           if( IsImageFormat(option) || (option==ScriptTok) )
  2477.                           {   if( !*TokenPtr || *TokenPtr==' ' )
  2478.                       FetchToken();
  2479.                           } else option = 0;
  2480.  
  2481.                           if( !CurToken )
  2482.                           {   CommandError(ErrorMsg[ErrFilNam]);  
  2483.                               break;
  2484.                           } else if( CurToken==StringTok )
  2485.                           {      ProcessFileName(TokenIdent);
  2486.                           } else ProcessFileName(TokenStart);
  2487.                           param = DataFileName;
  2488.                           CurToken = 0;
  2489.  
  2490.                           if( ReDrawFlag ) RefreshScreen();
  2491.                           WriteImageFile( param, option );
  2492.                           break;
  2493.  
  2494.         case(ScriptTok):  FetchToken();
  2495.                           if( FileDepth<STACKSIZE )
  2496.                           {   if( !CurToken )
  2497.                               {   CommandError(ErrorMsg[ErrFilNam]);
  2498.                                   break;
  2499.                               } else if( CurToken==StringTok )
  2500.                               {      ProcessFileName(TokenIdent);
  2501.                               } else ProcessFileName(TokenStart);
  2502.                               CurToken = 0;
  2503.  
  2504.                               script = fopen(DataFileName,"r");
  2505.                               LoadScriptFile(script,DataFileName);
  2506.                           } else CommandError(ErrorMsg[ErrScript]);
  2507.                           break;
  2508.  
  2509.         case(RenumTok):   FetchToken();
  2510.                           if( CurToken )
  2511.                           {   if( done = (CurToken=='-') )
  2512.                                   FetchToken();
  2513.  
  2514.                               if( CurToken==NumberTok )
  2515.                               {   option = done? -TokenValue : TokenValue;
  2516.                                   RenumberMolecule( option );
  2517.                               } else CommandError(ErrorMsg[ErrNotNum]);
  2518.                           } else RenumberMolecule(1);
  2519.                           break;
  2520.  
  2521.         case(StructureTok):
  2522.                           DetermineStructure();
  2523.                           break;
  2524.  
  2525.         case(ShowTok):    ExecuteShowCommand();
  2526.                           break;
  2527.  
  2528.         case(ZapTok):     ZapDatabase();
  2529.                           break;
  2530.  
  2531.         case(QuitTok):    return( True );
  2532.         default:          CommandError("Unrecognised command");
  2533.                           break;
  2534.     }
  2535.  
  2536.     if( CurToken )
  2537.         if( FetchToken() )
  2538.             CommandError("Warning: Ignoring rest of command");
  2539.     TokenPtr = NULL;
  2540.     return( False );
  2541. }
  2542.  
  2543.  
  2544. #if defined(__STDC__) || defined(IBMPC)
  2545. int ExecuteIPCCommand( char __huge* );
  2546. #endif
  2547.  
  2548. int ExecuteIPCCommand( ptr )
  2549.     char __huge *ptr;
  2550. {
  2551.     register char *src,*dst;
  2552.     register int len,depth;
  2553.     register int result;
  2554.     auto char buffer[256];
  2555.  
  2556.     result = 0;
  2557.     FileDepth=0;
  2558.     *LineStack = 0;
  2559. #ifdef IBMPC
  2560.     *NameStack = "DDE Error";
  2561. #else
  2562.     *NameStack = "IPC Error";
  2563. #endif
  2564.  
  2565.     /* Save command line */
  2566.     src=CurLine;  dst=buffer;
  2567.     while( *dst++ = *src++ );
  2568.    
  2569.     while( *ptr && (*ptr==' ') )
  2570.         ptr++;
  2571.  
  2572.     if( *ptr=='[' )
  2573.     {   depth = 0;
  2574.         while( *ptr++ == '[' )
  2575.         {   dst = CurLine;
  2576.             depth=0;  len=1;
  2577.  
  2578.         
  2579.             do {
  2580.                 if( *ptr==']' )
  2581.                 {   if( !depth )
  2582.                     {   *dst = '\0';
  2583.                         ptr++; break;
  2584.                     } else depth--;
  2585.                 } else if( *ptr=='[' )
  2586.                     depth++;
  2587.  
  2588.                 if( len<255 )
  2589.                 {   *dst++ = *ptr;
  2590.                     len++;
  2591.                 }
  2592.             } while( *ptr++ );
  2593.  
  2594.             if( len==255 )
  2595.             {   if( CommandActive )
  2596.                     WriteChar('\n');
  2597.                 WriteString("Warning: Remote command too long!\n");
  2598.                 CommandActive = False;
  2599.             } else if( ExecuteCommand() )
  2600.                 result = 2;
  2601.  
  2602.             while( *ptr && ((*ptr==' ')||(*ptr==';')) )
  2603.                 ptr++;
  2604.         }
  2605.     } else if( *ptr )
  2606.     {   dst = CurLine;
  2607.         len = 0;
  2608.  
  2609.         while( True )
  2610.         {   if( len==255 )
  2611.             {   if( CommandActive )
  2612.                     WriteChar('\n');
  2613.                 WriteString("Warning: Remote command too long!\n");
  2614.                 CommandActive = False;
  2615.                 break;
  2616.             }
  2617.  
  2618.             if( !(*dst++ = *ptr++) )
  2619.             {   if( ExecuteCommand() )
  2620.                     result = 2;
  2621.                 break;
  2622.             } else len++;
  2623.         }
  2624.     }
  2625.  
  2626.     FileDepth = -1;
  2627.     if( CommandActive )
  2628.     {   src=buffer; dst=CurLine;
  2629.         while( *dst++ = *src++ );
  2630.         if( !result ) result = 1;
  2631.     }
  2632.  
  2633.     return( result );
  2634. }
  2635.  
  2636.  
  2637. void InitialiseCommand()
  2638. {
  2639.     MaxHist = MinHist = 1;
  2640.     HistBuff[0] = 0;
  2641.  
  2642.     HelpFileName = NULL;
  2643.     FreeInfo = (void __far*)0;
  2644.     HelpInfo = (void __far*)0;
  2645.  
  2646.     CommandActive = False;
  2647.     SelectCount = 0;
  2648.     TokenPtr = NULL;
  2649.     FileDepth = -1;
  2650. }
  2651.