// functions imported from C: function isspace(ch: integer): integer; cdecl; external 'msvcrt.dll' name 'isspace'; function strchr(s: PChar; ch: integer): PChar; cdecl; external 'msvcrt.dll' name 'strchr'; function isdigit(ch: integer): integer; cdecl; external 'msvcrt.dll' name 'isdigit'; function strlwr(s1: PChar): PChar; cdecl; external 'msvcrt.dll' name '_strlwr'; function isctrl(ch: integer): integer; cdecl; external 'msvcrt.dll' name 'iscntrl'; function c_strlen(s: PChar): integer; cdecl; external 'msvcrt.dll' name 'strlen'; // remove trailing spaces from null-terminated string function TrimRightSz(psz: PChar): PChar; var pch: PChar; begin if psz^<>#0 then begin pch:=psz+strlen(psz)-1; while ((isspace(integer(pch^))<>0)or(isctrl(integer(pch^))<>0)) and(pch>psz) do begin pch^:=#0; Dec(pch); end; end; Result:=psz; end; function NextToken_(var psz: PChar; ch: string): PChar; begin Result:= TrimRightSz(NextParsel(psz, PChar(ch))); end; // returns the next "parsel" of characters up to the specified delimiter(s), // and removes that parsel from input string. // skips leading spaces even if a space is one of the delimiters; // ignores delimiters within quotes; // if delimiter string is empty, returns entire input string (minus leading spaces) function NextParsel(var psz: PChar; pszDelimiters: PChar): PChar; stdcall; var bQuoted: boolean; begin bQuoted:=false; // skip leading spaces while isspace(Integer(psz^))<>0 do Inc(psz); Result := psz; while psz^<>#0 do begin if psz^='"' then bQuoted := not bQuoted; if (strchr(pszDelimiters,Integer(psz^))<>nil) and not bQuoted then break; Inc(psz); end; if psz^<>#0 then begin psz^:=#0; Inc(psz); end; end; // translate AW coords (s) -> SDK coords (sWorld,Z,X,Y,W); // (Z=NS, X=WE, Y=Alt W=yaw); // returns true if successful, false if fails (invalid input) function GetSDKCoords(s: string; var sWorld: string; var Z: integer; var X: integer; var Y: integer; var W: integer): boolean; var sz: array [0..200] of char; psz1,psz: PChar; b: boolean; i: integer; dZ,dX,dY,dW: double; begin StrLCopy(@sz,PChar(Trim(s)),200); psz1:=strlwr(sz); psz:=NextToken_(psz1,' '); // get world name or Z if isdigit(integer(psz^))=0 then begin // must be a world name sWorld:=Copy(psz,1,strlen(psz)); psz:=NextToken_(psz1,' '); // get next parsel, hopefully Z coord end else sWorld:=''; // first thing was Z Z:=0; X:=0; Y:=0; W:=0; Result:=false; i:=c_strlen(psz)-1; if i<0 then exit; if psz[i]='s' then begin // it's south b:=true; psz[i]:=#0; end else begin if psz[i]<>'n' then exit; // neither south nor north, error b:=false; psz[i]:=#0; end; try dZ:=StrToFloat(string(psz)); // read the number except exit; end; if b then dZ:=-dZ; // invert it if it was south if psz1^=#0 then exit; // only Z given, error psz:=NextToken_(psz1,' '); // get X i:=c_strlen(psz)-1; if i<0 then exit; if psz[i]='e' then begin // it's east b:=true; psz[i]:=#0; end else begin if psz[i]<>'w' then exit; // neither east nor west, error b:=false; psz[i]:=#0; end; try dX:=StrToFloat(string(psz)); // read it except exit; end; if b then dX:=-dX; // invert it if it was east // default if none found dY:=0.0; dW:=0.0; if psz1^<>#0 then begin // there is an alt and/or yaw psz:=NextToken_(psz1,' '); // alt or maybe yaw i:=strlen(psz)-1; if psz[i]='a' then begin // it was alt b:=false; psz[i]:=#0; end else begin // it was yaw b:=true; end; try dY:=StrToFloat(string(psz)); except exit; end; if b then begin dW:=dY; // it's yaw not alt dY:=0; end else // it was alt, so now look for yaw if psz1^<>#0 then begin psz:=NextToken_(psz1,' '); try dW:=StrToFloat(string(psz)); except exit; end; end; // was no yaw, so use default end; Z:=INT_(dZ * 1000.0); X:=INT_(dX * 1000.0); Y:=INT_(dY * 100.0); W:=INT_(dW * 10.0); Result:=true; end; // the AW coords button: procedure TfrmMain.btnAWCoordsClick(Sender: TObject); var X,Y,Z,W: integer; s,sWorld: string; begin GetAWCoords(edWorld.Text,spinNS.value,spinWE.Value,spinAlt.value,spinYaw.value,s); if not InputQuery('Coordinates','Enter AW-style coordinates',s) then exit; if GetSDKCoords(s,sWorld,Z,X,Y,W) then begin if sWorld<>'' then edWorld.Text:=sWorld; spinNS.value:=Z; spinWE.value:=X; spinAlt.value:=Y; spinYaw.value:=W; end else MessageDlg('Invalid AW coordinates',mtError,[mbOk],0); end;