home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 12 / CD_ASCQ_12_0294.iso / maj / 535 / readscpt.pas < prev    next >
Pascal/Delphi Source File  |  1994-01-02  |  17KB  |  688 lines

  1. {$A-,B-,E+,F-,G-,I+,N-,O-,P-,Q-,R-,S-,T-,V-,X+}
  2.  
  3. Unit ReadScpt;
  4.  
  5. Interface
  6.  
  7. uses Dos, Objects;
  8.  
  9. const
  10.   MaxParam = 6;   {number of extra parameters}
  11. Type
  12.   {various types of controls which may be found in script file. -1 indicates
  13.    end}
  14.   RecType = (Dlg, Button, SText, CText, InputL, Labl, Histry, ILong, CheckB,
  15.              RadioB, MultiCB, ListB, Memo, ScrollB);
  16.   {various types of validators for TInputLine}
  17.   ValType = (Picture, Range, Filter, StringLookup);
  18.  
  19.   BlockType = record   {all controls have this standard data block}
  20.     BaseObj,            {like TInputLine}
  21.     Obj : PString;      {like PInputLine or PMyInputLine}
  22.     X1, Y1, X2, Y2,     {the TRect}
  23.     DefOptns, Optns,    {default and actual options for control}
  24.     DefEvMsk, EvMsk,    {default and actual eventmask for control}
  25.     HCtx,               {HelpCtx value}
  26.     Grow : integer;     {GrowMode value}
  27.     Param : array[1..MaxParam] of PString;    {possible the extra parameters}
  28.     HelpCtxSym,         {like hcNoContext}
  29.     FieldName,          {field name you chose for data record}
  30.     VarName : PString;  {variable name you chose or 'Control'}
  31.     end;
  32.  
  33.   ScriptRec = record  {the variant record for the various controls}
  34.     MainBlock : BlockType;  {the fixed part for all controls}
  35.     case Kind: RecType of
  36.       Dlg:  (Palette, WinFlags : word;    {the dialog itself}
  37.              DlgFuncName,        {like MakeDialog}
  38.              KeyString,          {ID string for resource}
  39.              Title : PString;);  {dialog title}
  40.       Button:
  41.             (CommandName,           {like cmOK}
  42.              ButtonText : PString;  {like O~k~}
  43.              CommandValue,          {word value for Command}
  44.              Flags : word;);        {flags}
  45.       SText, CText:               {static and colored text}
  46.             (Attrib : word;
  47.              Text : PString;);
  48.       InputL:
  49.             (StringLeng : word;     {AMaxLen parameter}
  50.              ValPtrName : PString;  {like PPXPictureString}
  51.              case ValKind : ValType of    {ValKind = -1 if no validator}
  52.                Picture:
  53.                   (AutoFill : Byte;
  54.                    PictureString : PString;);
  55.                Range:
  56.                   (LowLim, UpLim : LongInt;
  57.                    Transfer : word;);    {non-zero if voTransfer bit set}
  58.                StringLookUp:
  59.                   (List : PString;);
  60.                Filter:
  61.                   (CharSet : PString;     {like "['a'..'z', '0'..'9']" }
  62.                    {following represents the actual character set}
  63.                    ActualCharSet : array[0..7] of LongInt;
  64.                   );
  65.              );
  66.       ILong:
  67.             (LongLabelText : PString; {text of the label--not used in Pascal}
  68.              LongStrLeng : word;      {AMaxlen parameter}
  69.              LLim, ULim : LongInt;
  70.              ILOptions : word;);
  71.       LabL: (LabelText,
  72.              LinkName : PString;);    {variable name of control to which
  73.                                        label is linked, often just 'Control'}
  74.       Histry:
  75.             (HistoryID : word;
  76.              HistoryLink : PString;); {variable name of control to which
  77.                                        label is linked, often just 'Control'}
  78.  
  79.       CheckB, RadioB, MultiCB:
  80.             (Items : word;         {number of labels}
  81.              Mask : LongInt;
  82.              LabelColl : PStringCollection;  {collection of labels}
  83.              MCBFlags : word;      {multi checkbox flags}
  84.              SelRange : byte;      {multi checkbox SelRange}
  85.              States : PString;);   {multi checkbox States}
  86.       ListB:
  87.             (Columns : word;
  88.              ScrollBar : PString;);   {variable name of scrollbar}
  89.       Memo: (TextFieldName : PString; {the second DataRec fieldname required by TMemo}
  90.              BufSize : word;          {size of buffer}
  91.              VScroll, HScroll : PString;);   {variable name of scrollbars}
  92.     end;
  93.   PScriptRec = ^ScriptRec;
  94.  
  95.   BitFunction = function(W : word): string;
  96.  
  97. var
  98.   P, Dialog : PScriptRec;
  99.   ScriptColl : PCollection;
  100.   Present : array[Dlg..ScrollB] of boolean; {which types are present}
  101.  
  102. const
  103.   ValidatorPresent : boolean = False;
  104.  
  105. procedure ChkIOerror(S : string);
  106. {main script reading procedure}
  107. procedure ReadScriptFile(FName : string);
  108. {given a byte, word, longint, return the string hex equivalent}
  109. function Hex2(B : Byte) : String;
  110. function Hex4(W : word) : string;
  111. function Hex8(L : LongInt) : string;
  112. {compare two strings without regard to case}
  113. function SameString(const S1, S2 : String) : Boolean;
  114.  
  115. {if the  filename has no extension, add the default extension}
  116. function DefaultExt(const FName, DefExt : string) : string;
  117.  
  118. {functions use by OptionStr}
  119. function GetWinFlagWords(W : word): string;
  120. function GetEventWords(W : word): string;
  121. function GetOptionWords(W : word): string;
  122.  
  123. {given default and actual options (or eventmask), come up with a source
  124.  code phrase something like 'or ofFramed and not ofSelectable'.   Func is
  125.  a function appropriate to the type of bits being looked at.
  126.  It's known that Actual and Default are not equal on entry}
  127. function OptionStr(Actual, Default : word; Func : BitFunction): string;
  128.  
  129. Implementation
  130.  
  131. Const
  132.   VersionID = 'SCRIPT1';
  133.   Tab = #9;
  134.  
  135. type
  136.   PairType = array[0..1] of Char;   {reads two characters at once}
  137.  
  138. var
  139.   Spair : PairType;
  140.   LCh : Char absolute SPair;  {same address as SPair so LCh = Spair[0]}
  141.   Chi, LineNo : integer;
  142.   St : String;
  143.   Inf : Text;
  144.   L : LongInt;
  145.  
  146. function GetWinFlagWords(W : word): string;
  147. const
  148.   FlagArray : array[0..3] of String[7] =
  149.        ('wfMove', 'wfGrow', 'wfClose', 'wfZoom');
  150. var
  151.   S : string;
  152.   I : integer;
  153. begin
  154. S := '';
  155. for I := 0 to 3 do
  156.   begin
  157.   if (W and 1 = 1) then
  158.     S := S+FlagArray[I] + ' or ';
  159.   W := W shr 1;
  160.   end;
  161. if Length(S) > 4 then Dec(S[0], 4);  {remove last ' or '}
  162. GetWinFlagWords := S;
  163. end;
  164.  
  165. function GetEventWords(W : word): string;
  166. const
  167.   FlagArray : array[0..15] of String[11] =
  168.        ('evMouseDown', 'evMouseUp', 'evMouseMove', 'evMouseAuto',
  169.         'evKeyDown', '$20', '$40', '$80', 'evCommand', 'evBroadcast',
  170.         '$400', '$800', '$1000', '$2000', '$4000', '$8000');
  171. var
  172.   S : string;
  173.   I : integer;
  174. begin
  175. S := '';
  176. for I := 0 to 15 do
  177.   begin
  178.   if (W and 1 = 1) and (FlagArray[I] <> '') then
  179.     S := S+FlagArray[I] + ' or ';
  180.   W := W shr 1;
  181.   end;
  182. if Length(S) > 4 then Dec(S[0], 4);  {remove last ' or '}
  183. GetEventWords := S;
  184. end;
  185.  
  186. function GetOptionWords(W : word): string;
  187. const
  188.   FlagArray : array[0..15] of String[13] =
  189.        ('ofSelectable', 'ofTopSelect', 'ofFirstClick', 'ofFramed',
  190.         'ofPreProcess', 'ofPostProcess', 'ofBuffered', 'ofTileable',
  191.         'ofCenterX', 'ofCenterY', 'ofValidate', '$800', 'ofVersion20',
  192.         '$2000', '$4000', 'ofShoehorn');
  193. var
  194.   S : string;
  195.   I : integer;
  196. begin
  197. S := '';
  198. for I := 0 to 15 do
  199.   begin
  200.   if (W and 1 = 1) and (FlagArray[I] <> '') then
  201.     S := S+FlagArray[I] + ' or ';
  202.   W := W shr 1;
  203.   end;
  204. if Length(S) > 4 then Dec(S[0], 4);  {remove last ' or '}
  205. GetOptionWords := S;
  206. end;
  207.  
  208. function BitCount(W : word): integer;  {number of set bits in W}
  209. var
  210.   I, Count : integer;
  211. begin
  212. Count := 0;
  213. for I := 0 to 15 do
  214.   begin
  215.   if W and 1 = 1 then
  216.     Inc(Count);
  217.   W := W shr 1;
  218.   end;
  219. BitCount := Count;
  220. end;
  221.  
  222. function OptionStr(Actual, Default : word; Func : BitFunction): string;
  223. {given default and actual options (or eventmask), come up with a source
  224.  code phrase something like 'or ofFramed and not ofSelectable'.   Func is
  225.  a function appropriate to the type of bits being looked at.
  226.  It's known that Actual and Default are not equal on entry}
  227. var
  228.   S : string;
  229.   NOTs, ORs, Diff : word;
  230. begin
  231. Diff := Actual xor Default;  {the bits that are different}
  232. if BitCount(Diff) > 4 then
  233.   begin   {this is too complex--output hex number}
  234.   OptionStr := '$'+Hex4(Actual)+';';
  235.   Exit;
  236.   end;
  237. NOTs := Diff and Default;  {the bits not in default}
  238. ORs := Diff and Actual;    {the extra bits in actual}
  239. S := '';
  240. if NOTs <> 0 then
  241.   if BitCount(NOTs) = 1 then
  242.     S := ' and not ' + Func(NOTs)
  243.   else
  244.     S := ' and not(' + Func(NOTs) + ')';
  245. if ORs <> 0 then
  246.   S := S + ' or ' + Func(ORs);
  247. OptionStr := S + ';';
  248. end;
  249.  
  250. function DefaultExt(const FName, DefExt : string) : string;
  251. {if no extension, add DefExt (which must contain the '.')}
  252. var
  253.   Dir : PathStr;
  254.   Name : NameStr;
  255.   Ext : ExtStr;
  256. begin
  257. FSplit(FName, Dir, Name, Ext);
  258. if Ext = '' then Ext := DefExt;
  259. DefaultExt := Dir+Name+Ext;
  260. end;
  261.  
  262. function SameString(const S1, S2 : String) : Boolean;
  263. var
  264.   I : Integer;
  265. begin
  266. SameString := False;
  267. if S1[0] <> S2[0] then Exit;
  268. for I := 1 to Length(S1) do
  269.   if UpCase(S1[I]) <> UpCase(S2[I]) then Exit;
  270. SameString := True;
  271. end;
  272.  
  273. function Hex2(B : Byte) : String;
  274. Const
  275.   HexArray : array[0..15] of char = '0123456789ABCDEF';
  276. begin
  277. Hex2[0] := #2;
  278. Hex2[1] := HexArray[B shr 4];
  279. Hex2[2] := HexArray[B and $F];
  280. end;
  281.  
  282. function Hex4(W : word) : string;
  283. begin
  284. Hex4 := Hex2(Hi(W)) + Hex2(Lo(W));
  285. end;
  286.  
  287. function Hex8(L : LongInt) : string;
  288. begin
  289. Hex8 := Hex4(LongRec(L).Hi)+Hex4(LongRec(L).Lo);
  290. end;
  291.  
  292. function MyNewStr(const S: String): PString;
  293. {like NewStr but never returns a Nil pointer}
  294. var
  295.   P: PString;
  296. begin
  297. if S = '' then
  298.   begin
  299.   GetMem(P, 1);  {kind of silly, but saves a lot of testing here}
  300.   P^[0] := #0;
  301.   end
  302. else P := NewStr(S);
  303. MyNewStr := P;
  304. end;
  305.  
  306. PROCEDURE Error(const S : String);  {handle file read errors}
  307. Var
  308.   X : Integer;
  309.   NewS : String;
  310.   Ch : char;
  311.  
  312.   function Spaces(N : integer) : String;
  313.   var
  314.     S : string;
  315.     I : integer;
  316.   begin
  317.   S := '';
  318.   for I := 1 to N do
  319.     S := S+' ';
  320.   Spaces := S;
  321.   end;
  322.  
  323. begin
  324. Dec(St[0]);   {remove the ^M added by GetCh}
  325. WriteLn(St);
  326. X := Chi-1;
  327. if X < 1 then X := 1;
  328. Str(LineNo, NewS);
  329. NewS := 'Line ' + NewS + ' Error, ' + S;
  330. if X > Length(NewS) then
  331.   WriteLn(Spaces(X-Length(NewS)-1), NewS, '^')
  332. else
  333.   WriteLn(Spaces(X-1), '^', NewS);
  334. Close(Inf);
  335. Halt(1);
  336. end;
  337.  
  338. {-------------ChkIOerror}
  339. Procedure ChkIOerror(S : string);
  340. Var
  341.   IOerr : Integer;
  342.   S1 : string[20];
  343. begin
  344. IOerr := IOResult;
  345. if IOerr <> 0 then
  346.   begin
  347.   if IOerr = 2 then Write('Can''t find '+S)
  348.   else
  349.     begin
  350.     Str(IOerr, S1);
  351.     Write('I/O Error ', S1, ' in file ', S);
  352.     end;
  353.   Halt(1);
  354.   end;
  355. end;
  356.  
  357. {-------------GetCh}
  358. PROCEDURE GetCh;
  359. {Return next character in LCh, next two characters in SPair}
  360. begin
  361. if Chi > Length(St) then
  362.   begin      {need to read a line}
  363.   if not Eof(Inf) then
  364.     begin
  365.     ReadLn(Inf,St);
  366.     Inc(LineNo);
  367.     St:=St+^M;  {Add EOL}
  368.     Chi := 1;
  369.     end
  370.   else
  371.     Error('Unexpected end of file');
  372.   end;
  373. word(SPair) := MemW[DSeg : Ofs(St[Chi])];      {LCh same as SPair[0]}
  374. Inc(Chi);
  375. end;
  376.  
  377. {-------------SkipWhiteSpace}
  378. procedure SkipWhiteSpace;
  379. begin
  380. while (LCh in [' ', Tab, ^M]) do
  381.   GetCh;
  382. end;
  383.  
  384. function GetString : PString;   {read a quoted string and return pointer to
  385.  result.  Never returns Nil}
  386. var
  387.   S : string;
  388. begin
  389. S := '';
  390. SkipWhiteSpace;
  391. if LCh <> '"' then
  392.   Error('Quoted string expected');
  393. GetCh;
  394. while (LCh <> '"') or (SPair = '"+') do  {+ is continuation char}
  395.   begin
  396.   if SPair = '\"' then  {SPair has same address as LCh}
  397.     begin
  398.     S := S+'"';
  399.     GetCh;        {use up the extra character}
  400.     end
  401.   else if SPair = '\\' then
  402.     begin
  403.     S := S + '\';
  404.     GetCh;
  405.     end
  406.   else if SPair = '\n' then
  407.     begin
  408.     S := S + ^M;
  409.     GetCh;
  410.     end
  411.   else if SPair = '"+' then
  412.     begin
  413.     GetCh;  {skip '"'}
  414.     GetCh;  {skip '+'}
  415.     SkipWhiteSpace;
  416.     if LCh <> '"' then
  417.       Error('Quoted string continuation expected');
  418.     end
  419.   else S := S+LCh;  {Normal case}
  420.   GetCh;
  421.   end;
  422. GetCh;    {use up last "}
  423. GetString := MyNewStr(S);  {GetString is never Nil}
  424. end;
  425.  
  426. function GetNumber : LongInt;  {read a decimal number from script file}
  427. var
  428.   S : string[20];
  429.   Code : integer;
  430.   V : LongInt;
  431. begin
  432. S := '';
  433. SkipWhiteSpace;
  434. if LCh = '-' then
  435.   begin
  436.   S := '-';
  437.   GetCh;
  438.   end;
  439. if not (LCh in ['0'..'9']) then
  440.   Error('Number expected');
  441. while LCh in ['0'..'9'] do
  442.   begin
  443.   S := S + LCh;
  444.   GetCh;
  445.   end;
  446. Val(S, V, code);
  447. if code <> 0 then
  448.   Error('Numerical error');
  449. GetNumber := V;
  450. end;
  451.  
  452. procedure ReadLabel(P : PScriptRec);  {read variant part of label record}
  453. begin
  454. with P^ do
  455.   begin
  456.   LabelText := GetString;
  457.   LinkName := GetString;
  458.   end;
  459. end;
  460.  
  461. procedure ReadStaticText(P : PScriptRec);
  462. begin
  463. with P^ do
  464.   begin
  465.   Attrib := GetNumber;
  466.   Text := GetString;
  467.   end;
  468. end;
  469.  
  470. procedure ReadHistory(P : PScriptRec);
  471. begin
  472. with P^ do
  473.   begin
  474.   HistoryID := GetNumber;
  475.   HistoryLink := GetString;
  476.   end;
  477. end;
  478.  
  479. procedure ReadInputLine(P : PScriptRec);
  480. var
  481.   I : integer;
  482. begin
  483. with P^ do
  484.   begin
  485.   StringLeng := GetNumber;
  486.   ValKind:= ValType(GetNumber);
  487.   ValPtrName := GetString;
  488.   ValidatorPresent := ValidatorPresent or (ord(ValKind) <> -1);
  489.   case ValKind of     {ValKind = -1 if no validator}
  490.     Picture:
  491.       begin
  492.       AutoFill := GetNumber;
  493.       PictureString := GetString;
  494.       end;
  495.     Range:
  496.       begin
  497.       LowLim := GetNumber;
  498.       UpLim := GetNumber;
  499.       Transfer := GetNumber;
  500.       end;
  501.     StringLookUp:
  502.       List := GetString;
  503.     Filter:
  504.       begin
  505.       Charset := GetString;
  506.       for I := 0 to 7 do
  507.         ActualCharSet[I] := GetNumber;
  508.       end;
  509.     end;
  510.   end;
  511. end;
  512.  
  513. procedure ReadInputLong(P : PScriptRec);
  514. begin
  515. with P^ do
  516.   begin
  517.   LongLabelText := GetString;
  518.   LongStrLeng := GetNumber;
  519.   LLim := GetNumber;
  520.   ULim := GetNumber;
  521.   ILOptions := GetNumber;
  522.   end;
  523. end;
  524.  
  525. procedure ReadListBox(P : PScriptRec);
  526. begin
  527. with P^ do
  528.   begin
  529.   Columns := GetNumber;
  530.   ScrollBar := GetString;
  531.   end;
  532. end;
  533.  
  534. procedure ReadButton(P : PScriptRec);
  535. begin
  536. with P^ do
  537.   begin
  538.   CommandName := GetString;
  539.   ButtonText := GetString;
  540.   CommandValue := GetNumber;
  541.   Flags := GetNumber;
  542.   end;
  543. end;
  544.  
  545. procedure ReadMemo(P : PScriptRec);
  546. begin
  547. with P^ do
  548.   begin
  549.   TextFieldName := GetString;
  550.   BufSize := GetNumber;
  551.   VScroll := GetString;
  552.   HScroll := GetString;
  553.   end;
  554. end;
  555.  
  556. procedure ReadCheckRadio(P : PScriptRec);
  557. var
  558.   I : integer;
  559. begin
  560. with P^ do
  561.   begin
  562.   Items := GetNumber;
  563.   Mask := GetNumber;
  564.   if Items > 0 then
  565.     begin
  566.     New(LabelColl, Init(10,10));    {a collection of labels}
  567.     for I := 0 to Items-1 do        {insert from 1st to last, don't sort}
  568.       LabelColl^.AtInsert(I, GetString);
  569.     end;
  570.   if Kind = MultiCB then
  571.     begin
  572.     MCBFlags := GetNumber;
  573.     SelRange := GetNumber;
  574.     States := GetString;
  575.     end;
  576.   end;
  577. end;
  578.  
  579. procedure ReadDialog(P : PScriptRec); {read the variant part of dialog record}
  580. begin
  581. with P^ do
  582.   begin
  583.   Palette := GetNumber;
  584.   WinFlags := GetNumber;
  585.   DlgFuncName := GetString;
  586.   KeyString := GetString;
  587.   Title := GetString;
  588.   end;
  589. end;
  590.  
  591. procedure ReadMainBlock(P : PScriptRec; ThisKind : RecType);
  592. {read the non-variant part of the control's record}
  593. var
  594.   I : integer;
  595. begin
  596. with P^, MainBlock do
  597.   begin
  598.   Kind := ThisKind;
  599.   BaseObj := GetString;
  600.   Obj := GetString;
  601.   X1 := GetNumber;
  602.   Y1 := GetNumber;
  603.   X2 := GetNumber;
  604.   Y2 := GetNumber;
  605.   DefOptns := GetNumber;
  606.   Optns := GetNumber;
  607.   DefEvMsk := GetNumber;
  608.   EvMsk := GetNumber;
  609.   HCtx := GetNumber;
  610.   Grow := GetNumber;
  611.   for I := 1 to MaxParam do
  612.     Param[I] := GetString;
  613.   HelpCtxSym := GetString;
  614.   FieldName := GetString;
  615.   VarName := GetString;
  616.   end;
  617. end;
  618.  
  619. Procedure ReadScriptFile(FName : string);
  620. var
  621.   ThisKind : RecType;
  622. begin
  623. FillChar(Present, Sizeof(Present), 0);
  624. New(ScriptColl, Init(10,10));
  625.  
  626. {$I-}
  627. Assign(Inf, FName);
  628. Reset(Inf);
  629. ChkIOError(FName);
  630. {$I+}
  631.  
  632. ReadLn(Inf, St);
  633. if St <> VersionID then
  634.   begin
  635.   WriteLn('File is not a valid script file');
  636.   Close(Inf);
  637.   Halt(1);
  638.   end;
  639. LineNo := 1;
  640. St := '';  Chi := 999;  {get the reading started}
  641. GetCh;
  642. GetString;         {reserved--of no use here}
  643. L := GetNumber;    {Field number--of no use here}
  644.  
  645. ThisKind := RecType(GetNumber);
  646. if ThisKind <> Dlg then
  647.   Error('First item is not TDialog type');
  648. New(Dialog);            {'Dialog' will hold the dialog info}
  649. ReadMainBlock(Dialog, ThisKind);
  650. Present[Dlg] := True;
  651. ReadDialog(Dialog);
  652. SkipWhiteSpace;
  653.  
  654. ThisKind := RecType(GetNumber);   {find out what kind of control this is}
  655. while (Ord(ThisKind) > 0) do  {-1 terminates}
  656.   begin
  657.   if not (ThisKind in [Button..ScrollB]) then
  658.      Error('Unrecognized control type');
  659.   Present[ThisKind] := True;
  660.   New(P);
  661.   ReadMainBlock(P, ThisKind);
  662.   with P^ do
  663.     begin
  664.     case ThisKind of   {read the variant part of the control's record}
  665.       Button : ReadButton(P);
  666.       InputL : ReadInputLine(P);
  667.       LabL : ReadLabel(P);
  668.       Histry : ReadHistory(P);
  669.       ILong : ReadInputLong(P);
  670.       CheckB, RadioB, MultiCB :
  671.               ReadCheckRadio(P);
  672.       ListB: ReadListBox(P);
  673.       ScrollB :;   {already completely read}
  674.       Memo: ReadMemo(P);
  675.       SText, CText : ReadStaticText(P);
  676.       end;
  677.     ScriptColl^.Insert(P);  {insert in the collection of controls}
  678.     SkipWhiteSpace;
  679.     end;
  680.   ThisKind := RecType(GetNumber);
  681.   end;
  682.  
  683. Close(Inf);
  684. end;
  685.  
  686. end.
  687.  
  688.