program project1; // Robert Rozee, 2024
uses SysUtils, Process, Classes;
var PortList:TStringList;
I, J, K:integer;
S, T:string;
flag:boolean;
const letters=['a'..'z', 'A'..'Z'];
numbers=['0'..'9'];
begin
PortList:=TStringList.Create; // create object to hold list of port names
PortList.Sorted:=true; // list always remains sorted
PortList.Duplicates:=dupIgnore; // .Duplicates requires Sorted:=true
//if RunCommand('/bin/bash',['-c','dmesg | grep "tty"'], S) then // the 'strictly correct' version
if RunCommand('bash -c dmesg | grep "tty"', S) then // shorter version seems to work fine!
begin
I:=pos('tty', S); // look for first occurrence of "tty"
while I<>0 do
begin
if (I>1) and (S[I-1] in letters) then delete(S, 1, I+2) else // eg, matches "getty" -> discard up to "y"
begin
delete(S, 1, I-1); // delete everything preceding the port name
I:=1;
while S[I] in letters do inc(I); // skip over letters, such as "ttyUSB"
while S[I] in numbers do inc(I); // ... now skip over any trailing numbers
PortList.Add(copy(S, 1, I-1)); // add the found port name to the list of ports
delete(S, 1, I-1) // remove found port name from input string
end;
I:=pos('tty', S) // look for next occurrence of "tty"
end
end;
if PortList.Find('tty', I) then PortList.Delete(I); // .Find also requires Sorted:=true
if PortList.Find('tty0', I) then PortList.Delete(I); // "tty" and "tty0" are not useful to us
PortList.Sorted:=false; // we don't need this setting for any of the below code
for I:=PortList.Count-1 downto 0 do // remove any tty devices that are not present in /dev/tty*
if not FileExists('/dev/'+PortList.Strings[I]) then PortList.Delete(I); // these are (generally) going to be removable USB devices
// that have been unplugged
flag:=true;
while (PortList.Count>1) and flag do // excessively complicated sort routine, tries to ensure the
begin // 'fixed' serial ports appear first, and that port numbers
flag:=false; // are ordered correctly: 0,1,2...,8,9,10,11, etc.
for I:=0 to PortList.Count-2 do
begin
S:=PortList[I];
T:=PortList[I+1];
J:=1+length(S);
K:=1+length(T);
if (J-K)<0 then begin // pack S with zeros to left of numeric part
while (J>1) and (S[J-1] in ['0'..'9']) do dec(J);
while length(S)<length(T) do insert('0', S, J)
end else
if (K-J)<0 then begin // pack T with zeros to left of numeric part
while (K>1) and (T[K-1] in ['0'..'9']) do dec(K);
while length(T)<length(S) do insert('0', T, K)
end;
J:=pos('ttyS',S); // =1 if is a 'fixed' serial port
K:=pos('ttyS',T); // =1 if is a 'fixed' serial port
if ((J<>1) and (K=1)) or // bubble ttyS* ports to top of the list
((J=K) and (S>T)) then // within respective groups sort alphabetically
begin
PortList.Exchange(I, I+1);
flag:=true // flag set if at least one swap during this pass
end
end
end;
if PortList.Count=0 then writeln('no serial ports found')
else for I:=0 to PortList.Count-1 do writeln(PortList.Strings[I]);
PortList.Free
end.