### 7.6 System Interface ¶

If `(provided? 'getenv)`:

Function: getenv name ¶

  Looks up name, a string, in the program environment. If name is found a string of its value is returned. Otherwise, `#f` is returned.

If `(provided? 'system)`:

Function: system command-string ¶

  Executes the command-string on the computer and returns the integer status code. This behaves the same as the POSIX `system` call.

If `(provided? 'program-arguments)`:

Function: program-arguments ¶

  Returns a list of strings, the first of which is the program name followed by the command-line arguments.

#### 7.6.1 Directories ¶

`(require 'directory)`

Function: current-directory ¶

  `current-directory` returns a string containing the absolute file name representing the current working directory. If this string cannot be obtained, #f is returned.

  If `current-directory` cannot be supported by the platform, then #f is returned.

Function: make-directory name ¶

  Creates a sub-directory name of the current-directory. If successful, `make-directory` returns #t; otherwise #f.

Function: directory-for-each proc directory ¶

  proc must be a procedure taking one argument. ‘`Directory-For-Each`’ applies proc to the (string) name of each file in directory. The dynamic order in which proc is applied to the filenames is unspecified. The value returned by ‘`directory-for-each`’ is unspecified.

Function: directory-for-each proc directory pred ¶

  Applies proc only to those filenames for which the procedure pred returns a non-false value.

Function: directory-for-each proc directory match ¶

  Applies proc only to those filenames for which `(filename:match?? match)` would return a non-false value (see Filenames in SLIB).

      (require 'directory)
      (directory-for-each print "." "[A-Z]*.scm")
      -|
      "Bev2slib.scm"
      "Template.scm"

Function: directory*-for-each proc path-glob ¶

  path-glob is a pathname whose last component is a (wildcard) pattern (see Filenames in SLIB). proc must be a procedure taking one argument. ‘`directory*-for-each`’ applies proc to the (string) name of each file in the current directory. The dynamic order in which proc is applied to the filenames is unspecified. The value returned by ‘`directory*-for-each`’ is unspecified.

#### 7.6.2 Transactions ¶

If `system` is provided by the Scheme implementation, the transact package provides functions for file-locking and file-replacement transactions.

`(require 'transact)`

#### File Locking ¶

Unix file-locking is focussed on write permissions for segments of a existing file. While this might be employed for (binary) database access, it is not used for everyday contention (between users) for text files.

Microsoft has several file-locking protocols. Their model denies write access to a file if any reader has it open. This is too restrictive. Write access is denied even when the reader has reached end-of-file. And tracking read access (which is much more common than write access) causes havoc when remote hosts crash or disconnect.

It is bizarre that the concept of multi-user contention for modifying files has not been adequately addressed by either of the large operating system development efforts. There is further irony that both camps support contention detection and resolution only through weak conventions of some their document editing programs.

The file-lock procedures implement a transaction method for file replacement compatible with the methods used by the GNU emacs text editor on Unix systems and the Microsoft Word editor.

Both protocols employ what I term a certificate containing the user, hostname, time, and (on Unix) process-id. Intent to replace file is indicated by adding to file’s directory a certificate object whose name is derived from file.

The Microsoft Word certificate is contained in a 162 byte file named for the visited file with a ‘`~$`’ prefix. Emacs/Unix creates a symbolic link to a certificate named for the visited file prefixed with ‘`.#`’. Because Unix systems can import Microsoft file systems, these routines maintain and check both Emacs and Word certificates.

Function: file-lock-owner path ¶

  Returns the string ‘`user@hostname`’ associated with the lock owner of file path if locked; and #f otherwise.

Procedure: file-lock! path email ¶
Procedure: file-lock! path ¶

  path must be a string naming the file to be locked. If supplied, email must be a string formatted as ‘`user@hostname`’. If absent, email defaults to the value returned by `user-email-address`.

  If path is already locked, then `file-lock!` returns ‘`#f`’. If path is unlocked, then `file-lock!` returns the certificate string associated with the new lock for file path.

Procedure: file-unlock! path certificate ¶

  path must be a string naming the file to be unlocked. certificate must be the string returned by `file-lock!` for path.

  If path is locked with certificate, then `file-unlock!` removes the locks and returns ‘`#t`’. Otherwise, `file-unlock!` leaves the file system unaltered and returns ‘`#f`’.

Function: describe-file-lock path prefix ¶
Function: describe-file-lock path ¶

  path must be a string naming a file. Optional argument prefix is a string printed before each line of the message. `describe-file-lock` prints to `(current-error-port)` that path is locked for writing and lists its lock-files.

      (describe-file-lock "my.txt" ">> ")
      -|
      >> "my.txt" is locked for writing by 'luser@no.com.4829:1200536423'
      >> (lock files are "~$my.txt" and ".#my.txt")

#### File Transactions ¶

Function: emacs:backup-name path backup-style ¶

  path must be a string. backup-style must be a symbol. Depending on backup-style, `emacs:backup-name` returns:

  none

    #f

  simple

    the string "path~"

  numbered

    the string "path.~n~", where n is one greater than the highest number appearing in a filename matching "path.~*~". n defauls to 1 when no filename matches.

  existing

    the string "path.~n~" if a numbered backup already exists in this directory; otherwise. "path~"

  orig

    the string "path.orig"

  bak

    the string "path.bak"

Function: transact-file-replacement proc path backup-style certificate ¶
Function: transact-file-replacement proc path backup-style ¶
Function: transact-file-replacement proc path ¶

  path must be a string naming an existing file. backup-style is one of the symbols none, simple, numbered, existing, orig, bak or #f; with meanings described above; or a string naming the location of a backup file. backup-style defaults to #f. If supplied, certificate is the certificate with which path is locked.

  proc must be a procedure taking two string arguments:

  - path, the original filename (to be read); and
  - a temporary file-name.

  If path is locked by other than certificate, or if certificate is supplied and path is not locked, then `transact-file-replacement` returns #f. If certificate is not supplied, then, `transact-file-replacement` creates temporary (Emacs and Word) locks for path during the transaction. The lock status of path will be restored before `transact-file-replacement` returns.

  `transact-file-replacement` calls proc with path (which should not be modified) and a temporary file path to be written. If proc returns any value other than #t, then the file named by path is not altered and `transact-file-replacement` returns #f. Otherwise, `emacs:backup-name` is called with path and backup-style. If it returns a string, then path is renamed to it.

  Finally, the temporary file is renamed path. `transact-file-replacement` returns #t if path was successfully replaced; and #f otherwise.

#### Identification ¶

Function: user-email-address ¶

  `user-email-address` returns a string of the form ‘`username@hostname`’. If this e-mail address cannot be obtained, #f is returned.

#### 7.6.3 CVS ¶

`(require 'cvs)`

Function: cvs-files directory/ ¶

  Returns a list of the local pathnames (with prefix directory/) of all CVS controlled files in directory/ and in directory/’s subdirectories.

Function: cvs-directories directory/ ¶

  Returns a list of all of directory/ and all directory/’s CVS controlled subdirectories.

Function: cvs-root path/ ¶

  Returns the (string) contents of path/CVS/Root; or `(getenv "CVSROOT")` if Root doesn’t exist.

Function: cvs-repository directory/ ¶

  Returns the (string) contents of directory/CVS/Root appended with directory/CVS/Repository; or #f if directory/CVS/Repository doesn’t exist.

Procedure: cvs-set-root! new-root directory/ ¶

  Writes new-root to file CVS/Root of directory/.

Procedure: cvs-set-roots! new-root directory/ ¶

  Writes new-root to file CVS/Root of directory/ and all its CVS subdirectories.

Function: cvs-vet directory/ ¶

  Signals an error if CVS/Repository or CVS/Root files in directory/ or any subdirectory do not match.