1% file_path_name_ext.pro -- a utility to construct or deconstruct file, path, name and extension
    2:- module(filename,[
    3    file_path_name_ext/4,
    4    file_path_name_ext/5,
    5    lastchar/2,
    6    firstchar/2
    7]).
 file_path_name_ext(+File:atom, -Path:atom, -Name:atom, -Extension:atom) is semidet
file_path_name_ext(-File:atom, ?Path:atom, +Name:atom, +Extension:atom) is multi
 file_path_name_ext(+File:atom, +DExt:atom, -Path:atom, -Name:atom, ?Extension:atom) is semidet
file_path_name_ext(-File:atom, -DExt:atom, ?Path:atom, +Name:atom, +Extension:atom) is multi
Separate a (full) URL into Path, Name and Extension, or construct the absolute file name from Path (optional), Name and Extension (or DExt).

Note: In alignment with URI formats, filenames may end with #, typically in cases where the filename is used as a prefix for entities. In this case, the # is stripped from the name and ignored.

Arguments:
File- If input, then an "expandable" file path and name. Extension is optional, if a default extension DExt is given. Input may optionally have a scheme prefix of `file://`. Input may also have an ending URI entity suffix (#) which will be stripped. If output, then the absolute file path and name.
Path- If input, then an "expandable" path. Trailing slashes are optional for resulting absolute file names. If output, then absolute path, including trailing slash.
Name- Filename without extension
DExt- Default filename extension (e.g. txt) without the dot prefix
Extension- Filename extension (e.g. txt) without the dot prefix

Example use:

:- file_path_name_ext('~/.config/swi-prolog/init.pl',P,N,E).
P = '/home/myusername/.config/swi-prolog/''
N = init
E = pl

:- file_path_name_ext(F,library(pldoc),doc_process,pl).
F = '/home/myusername/.config/swi-prolog/library/pldoc/doc_process.pl';
F = '/usr/lib/swi-prolog/library/pldoc/doc_process.pl';
...etc.
   44file_path_name_ext(File,Path,Name,Ext):- file_path_name_ext(File,_,Path,Name,Ext).
   45file_path_name_ext(Filename,DExt,Path,Name,Ext):-
   46    nonvar(Filename),
   47    absolute_file_name(Filename,Full,[expand(true)]),
   48    ( lastchar(Full,'#') -> After=1; After=0),  % maybe remove '#'
   49    ( atom_prefix(Full,'file://') -> Before=7; Before=0),  % maybe remove 'file://'
   50    sub_string(Full,Before,_,After,File),
   51    file_name_extension(PathName,X,File),
   52    file_base_name(File,BaseName),
   53    file_base_name(PathName,Name),
   54    (   X = ''   % check if extension is empty, but default extension exists
   55    ->  ( (Name= BaseName, ground(DExt)) -> Ext= DExt; Ext= X ) 
   56    ;   Ext = X 
   57    ),
   58    file_directory_name(File,P),
   59    atom_concat(P,'/',Path).
   60    
   61file_path_name_ext(Filename,DExt,Path,Name,Ex):-
   62    var(Filename),
   63    (   (atom(Name),lastchar(Name,'#'))  % maybe remove '#'
   64    ->  sub_string(Name,0,_,1,Nam)
   65    ;   Nam = Name
   66    ),
   67    ( Ex=DExt; true ),		% maybe use default extension
   68    (		firstchar(Ex,'.') % maybe remove extra '.' from extension
   69    ->	sub_string(Ex,1,_,0,Ext)
   70	 ;		Ext=Ex    	
   71    ),
   72    ( working_directory(Path,Path); true),
   73    (		lastchar(Path,'/') % maybe remove extra slash from path
   74    ->	sub_string(Path,0,_,1,FPath)
   75    ;		FPath=Path
   76    ),!,
   77    expand_file_search_path(FPath,FullPath),
   78    atomic_list_concat([FullPath,'/',Nam,'.',Ext],Filename).
 lastchar(+Text:atomic, ?Char:char) is semidet
Get or check the last character of a string or atom
Arguments:
Text- string or atom
Char- the last character of Text

Example use:

:- lastchar('Hello World!',C).
C = '!'
   92lastchar(String,Char):-
   93    atom_string(Text,String),
   94    sub_atom(Text,_,1,0,Char).
 firstchar(+Text:atomic, ?Char:char) is semidet
Get or check the first character of a string or atom
Arguments:
String- string or atom
Char- the first character of Text

Example use:

:- fistchar('Hello World!',C).
C = 'H'
  108firstchar(String,Char):-
  109    atom_string(Text,String),
  110    sub_atom(Text,0,1,_,Char)