
One of the great features of Linux is that you can do just about anything from the command line. If we’re able to gain access to command line instructions from our Delphi applications, this will give us a very powerful API for the system. In this video I’m going to show you how to access the Linux command line from your Delphi applications.
*note* In this video I am assuming you are already configured to deploy an application to Linux and understand how to launch it from the Linux command line. If this is not the case, see my earlier posts covering these subjects:
- http://chapmanworld.com/2017/02/28/embarcadero-delphi-linux-bootcamp/
- http://chapmanworld.com/2016/12/29/configure-delphi-and-redhat-or-ubuntu-for-linux-development/
Best Viewed Full Screen:
Here is the source code for the ‘myls’ application featured in the video…
program myls; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, Posix.Base, Posix.Fcntl; type TStreamHandle = pointer; /// <summary> /// Man Page: http://man7.org/linux/man-pages/man3/popen.3.html /// </summary> function popen(const command: MarshaledAString; const _type: MarshaledAString): TStreamHandle; cdecl; external libc name _PU + 'popen'; /// <summary> /// Man Page: http://man7.org/linux/man-pages/man3/pclose.3p.html /// </summary> function pclose(filehandle: TStreamHandle): int32; cdecl; external libc name _PU + 'pclose'; /// <summary> /// Man Page: http://man7.org/linux/man-pages/man3/fgets.3p.html /// </summary> function fgets(buffer: pointer; size: int32; Stream: TStreamHAndle): pointer; cdecl; external libc name _PU + 'fgets'; /// <summary> /// Utility function to return a buffer of ASCII-Z data as a string. /// </summary> function BufferToString( Buffer: pointer; MaxSize: uint32 ): string; var cursor: ^uint8; EndOfBuffer: nativeuint; begin Result := ''; if not assigned(Buffer) then begin exit; end; cursor := Buffer; EndOfBuffer := NativeUint(cursor) + MaxSize; while (NativeUint(cursor)<EndOfBuffer) and (cursor^<>0) do begin Result := Result + chr(cursor^); cursor := pointer( succ(NativeUInt(cursor)) ); end; end; var Handle: TStreamHandle; Data: array[0..511] of uint8; begin try Handle := popen('/bin/ls -lart','r'); try while fgets(@data[0],Sizeof(Data),Handle)<>nil do begin Write(BufferToString(@Data[0],sizeof(Data))); end; finally pclose(Handle); end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.







Hi,Anderson Dapper Rocha
when I use your code in console, It’s ok.
when I use your code in gui enviroument, the program has no response, no focus.
what should i do ?
Thank’s a lot.
Apologies that it’s been a while since you posted this question.
I’m not sure how you’re running the code in GUI because Delphi for Linux does not support GUI applications, which may be the problem in it’s self.
If you’re using some Delphi GUI for Linux framework, such as CrossVCL or other, you may need to remove the Write/Writeln calls from the code.
The simplest solution for UTF8 is to completely replace the BufferToString() function with the Delphi system function Utf8ToString()….
while fgets(@data[0],Sizeof(Data),Handle)<>nil do begin
Write(Utf8ToString(@Data[0]));
end;
However, Utf8ToString() does not have a character limiter to stop it from overrunning the end of the buffer. In order to resolve this you would need to pass a pre-zero’d buffer into fGets() and pass the size of the buffer less one byte (to protect the terminating zero). Or otherwise, simply pass a buffer large enough for the content + zero byte.
Hi Craig,
Nice post and very useful one!
In practice your BufferToString function works incorrectly with non-ascii symbols (e.g. UTF8)