Files handling

Listing files

Enumerating a files directory content:

module "/pliant/language/unsafe.pli"
module "/pliant/admin/file.pli"
var Array:FileInfo files := file_list "file:/some_directory/some_sudirectory/" extended
for (var Int i) 0 files:size-1
  console files:i:name "   " files:i:datetime "   " files:i:size "   " files:i:options

Many flags can be provided as the second argument. They are defined in /pliant/language/stream/listmode.pli
First of all, one of 'reduced' 'standard' 'extended' should be provided. 'reduced' means get only file names, 'standard' means name, plus date and size, 'extended' means also get options (as an example Unix access rights).
'recursive' means list also files in sub directories.
'relative' means the names will not contain the full path, but only the file name (or subpath if 'recursive' was provided).
'sorted' means sort files according to name.
'directories' means return also directories, not only plain files.
'nolinks' means ignore Unix soft link.
'deadlinks' means list also Unix soft links that point to no file or directory.
'linkrecursive' means list also files in directories pointed by soft links; use with care since it might result in infinite number of files, so ungraceful program stop due to memory starvation.
'notifyfailure' is used to differentiate an empty result because the directory contains no file from a empty result because the directory scan failed (broken network connection to a remote directory). If the flag is set and scan fails, a single file with the name of the directory will be returned, and it will have failure flag set, I mean ' files:size=1 and files:0=failure' expression will be true.

Getting informations about a single file:

var FileInfo info := file_query "file:/some_directory/some_subdirectory/some_file" standard
if info=success
  console "file size is " info:size eol
else
  console "file does not exist" eol

Here are a few helper functions for 'FileInfo' data type. They are defined in /pliant/language/stream/filebase1.pli:

'path' method returns the path contained in the file name, that is the directory the file is in:

console info:path eol

'name_without_path' returns the name of the file, without the path:

console info:name_without_path eol

'stripped_name' returns the name of the file, without the path, and without the file extension:

console info:stripped_name eol

'extension' returns the file extension. The result string is either empty, or starting with a dot sign.

console info:extension eol

'is_link' returns a boolean specifying if the file is a soft link in facts:

if info:is_link
  console "This is a soft link" eol

'link' returns the soft link value:

console info:link eol

'is_directory' returns a boolean specifying if the file is a directory in facts:

if info:is_directory
  console "This is a directory" eol

'is_file' returns a boolean specifying if the file is a real file as opposed to a directory, a link, or a device:

if info:is_file
  console "This is a real file" eol

'is_device' returns a boolean specifying if the file is a device in facts:

if info:is_device
  console "This is a device" eol

Creating, copying, moving and deleting files

This is implemented in /pliant/admin/file.pli module.

module "/pliant/admin/file.pli"
var ExtendedStatus s := file_tree_create "file:/tmp/foo/bar/"

Creates the specified directory if it does not already exists. If some subdirectory must be created to enable the creation of the specified directory, it will be done automatically.

var ExtendedStatus s := file_delete "file:/tmp/test"

Deletes the specified file or directory. A non empty directory cannot be deleted using 'file_delete'.

var ExtendedStatus s := file_tree_delete "file:/tmp/foo/"

Deletes the specified directory including all the files and directories it might contain.

var ExtendedStatus s := file_link "file:/pliant/binary/pliant_debug1.exe" "file:/bin/pliant"

Creates a Unix soft link. The first parameter is the existing file, and the second the name of the softlink to create. See 'file_move' bellow for the thrird optional parameter.

var ExtendedStatus s := file_clone "file:/tmp/test" "file:/tmp/another"

Creates a Unix hard link. Please notice that Linux does not support directories hard links.

var ExtendedStatus s := file_copy "file:/tmp/test" "file:/tmp/another" extended

Copy the file content. The first parameter is the source, the second is the target.
If the third parameter can be either 'reduced' 'standard' or 'extended', plus some optional flags listed bellow. 'reduced' means copy only the file content, so the new file date and time will be the current one.

Here are some of the optional flags:

file_copy "file:/tmp/test" "file:/tmp/another" extended+lazy

Copy only if the destination file does not exist or has not the same size of date and time as the source one.

file_copy "file:/tmp/test" "file:/tmp/another" extended+bidirectional

If the target file exists, and is newer than the source file, then the target file will be copied to the source file.

var ExtendedStatus s := file_tree_copy "file:/tmp/foo/" "file:/backup/foo/" extended

Copy all the directory and all files and subdirectories it contains.

file_tree_copy "file:/tmp/foo/" "file:/backup/foo/" extended+delete

If some file is in the target directory, but not in the source directory, then it will be removed.
The all three 'lazy' 'bidirectional' and 'delete' flags should be usable at once, but please, make tests before.

file_tree_copy "file:/tmp/foo/" "file:/backup/foo/" extended+linktransparent

'linktransparent' attributes says that if there is a soft link in the source tree, it will not be copied as as a soft link in the target tree. It's content will rather be copied.

var ExtendedStatus s := file_move "file:/tmp/test" "file:/tmp/newname"

Moves some file or directory. Pliant will first try to use the operating system 'move' instruction, because it's more efficient. If it fails, Pliant will silently try to do copy then delete.

'file_link' 'file_clone' and 'file_move' accept a third 'force' optional parameter. If it's value is true and the target file already exists, it will be overwritten:

file_move "file:/tmp/test" "file:/tmp/newname" true

file_tree_cleanup "file:/tmp/foo/"

Deletes all empty directories in the specified directory and it's subdirectories.

file_extract "file:/tmp/foo.tgz" "file:/tmp/foo/"

Unpack a Unix or Windows standard tarball file to the specified directory. Supported tarball extensions are '.tgz', '.tar.gz', '.tar.bz2', '.tar' (under Unix only) and '.zip' (all plateforms).
This is not a native Pliant implementation, but just a frontend to Unix 'tar' utility, except for ZIP format.

There is no specific tool for creating tarballs. Please use 'execute' instruction.

Changing files attributes

The main instruction for changing files attributes is 'file_configure':

var ExtendedStatus s := file_configure "file:/tmp/test" "datetime "+string:(date 2009 1 1 0 0 0 0)
if s=failure
  console "It failed (" s:message ")" eol

There are several attributes you can change through 'file_configure'. The main one is the file date that we have just seen. The file owner and access rights can be changed using 'file_configure' instruction, but using 'file_rights' instruction described bellow is probably easier. You might also want to use 'file_configure' operation to set files details such as Linux EXT3 journaling flag, but then you should just review 'configure' method in /pliant/language/stream/native.pli module to see all possibilities.

file_rights "file:/tmp/test" undefined undefined 6*8^2+4*8+4 0

Changes Unix access rights of the specified file.
The first argument is either 'undefined' or will change the file owner specified as an integer value.
The second argument is either 'undefined' or will change the file group.
The third argument specifies the access bits that have to be set in the file permission field.
The fourth argument specifies thet acces bits that have to be cleared in the file permission field.

file_tree_rights "file:/tmp/foo/" undefined undefined 6*8^2+4*8+4 0 7*8^2+7*8+7 0

Same, but changes access rights of all files and directories in the specified path.
Arguments 3 and 4 specify permissions bits to be repectively set and cleared for files.
Arguments 5 and 6 specify permissions bits to be repectively set and cleared for directories.

Temporary files

The name of a tempory file shall be obtained through calling 'file_temporary' function:

var Str temp := file_temporary
(var Stream) s open temp out+safe
...
s close
...
file_delete temp

Editing ascii files

Scripting and automation often requires to apply a few changes to an ASCII configuration file.
A 'AsciiFile' type is provided in module /pliant/admin/asciifile.pli to help do that in very few lines in your application.

Basic usage

The 'AsciiFile' data type is a superset of 'Array:Str', so the following methods are available:

module "/pliant/admin/asciifile.pli"
var AsciiFile af
console af:size eol # the number of lines
console af:0 eol # the content of the first line
af += "one more line" # adds a line at the end.

The following extra methods are also available:

af insert 3 "my line"

Inserts a new line. The lines with index ranging from 3 to the end are shifted. Once again, the first line has index 0, not 1.

af remove 3

Removes the line with index 3. The lines with index ranging from 4 to the end are shifted.

af get "CC" "="

Gets the value after the '=' sign in the line that looks like:

CC = anything

af set "CC" "=" "CC = gcc272"

Changes the line.

af load "file:/tmp/test"
change the content
af store

Guess what it does.

Advanced matching

A complete sample could be (extracted from module /pliant/linux/kernel/build_kernel.pli):

(var AsciiFile makefile) load "file:/usr/src/linux/Makefile"
makefile fuzzy_set "SMP" "=" "SMP = 1"
makefile set "HOSTCC" "=" "HOSTCC=gcc272"
makefile set "CC" "=" "CC=$(CROSS_COMPILE)gcc272 -D__KERNEL__ -I$(HPATH)"
makefile store

The main difference between 'set' and 'fuzzy_set' is that 'fuzzy_set' will accept a line that as something in front of the requested indentifier.
So,

makefile set "SMP" "=" "SMP = 1"

would change line

SMP = 0

to

SMP = 1

but would not change

# SMP = 1

On the other hand,

makefile fuzzy_set "SMP" "=" "SMP = 1"

would change both.

In the following example:

(var AsciiFile f) load "target:/etc/login.defs"
f set "PASS_MAX_LEN" "" "PASS_MAX_LEN 256"f store

the second argument is "", so the line:

PASS_MAX_LEN 8

will be changed to

PASS_MAX_LEN 256

'set' and 'fuzzy_set' do change only the first occurrence.
'set_all' can be used to change all occurrences.

Lastly 'replace' can be used to replace any occurrence of the first provided parameter with the second.
Please notice that 'replace' does not require the occurrence to be a whole word:

replace "clic" "click"