Patch title: Release 93 bulk changes
Abstract:
File: /admin/asciifile.pli
Key:
    Removed line
    Added line
# Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# version 2 along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


abstract
  [This modules provides basic functions for changing settings in ascii configuration files.]

doc
  [The 'AsciiFile' data type is a superset of 'Array:Str', so the following methods are available:]
  listing
    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.
  para
    [The following extra methods are also available:]
    listing
      af insert 3 "my line"
    [Inserts a new line. The lines with indices ranging from 3 to the end are shifted.]
    listing
      af remove 3
    [Removes the line with index 3. The lines with indices ranging from 4 to the end are shifted.]
    listing
      af get "CC" "="
    [Gets the value after the '=' sign in the line that looks like:]
    listing
       CC = anything
    listing
      af set "CC" "=" "CC = gcc272"
    [or]
    listing
      af set "CC" "=" "CC = gcc272"
    [Changes the line. ]
  para
    listing
      af load "file:/tmp/test"
      changing the content
      af store
    [Guess what it does.]


doc
  [A complete sample could be (extracted from ]
  link "/pliant/linux/kernel/build_kernel.pli" "/pliant/linux/kernel/build_kernel.pli"
  [):]
  listing
    (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
doc
  [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.] ; eol
  para
    [So,]
    listing
      makefile set "SMP" "=" "SMP = 1"
    [would change line]
    listing
      SMP = 0
    [to]
    listing
      SMP = 1
    [but would not change]
    listing
      # SMP = 1
    [On the other hand,]
    listing
      makefile fuzzy_set "SMP" "=" "SMP = 1"
    [would change both.]
  
doc
  [In the following example:]
  listing
    (var AsciiFile f) load "target:/etc/login.defs"
    f set "PASS_MAX_LEN" "" "PASS_MAX_LEN 256"
    f store
  [the second argument is [dq][dq], so the line:]
  listing
    PASS_MAX_LEN 8
  [will be changed to]
  listing
    PASS_MAX_LEN 256

doc
  [Now the fairly trivial listing:]


module "/pliant/language/unsafe.pli"
module "/pliant/language/stream.pli"


type AsciiFile
  field Str filename
  field Array:Str lines


method af reset filename
  arg_rw AsciiFile af ; arg Str filename
  af filename := filename
  af:lines size := 0

method af load filename
  arg_rw AsciiFile af ; arg Str filename
  af reset filename
  (var Stream f) open filename in+safe
  var Int i := 0
  while not f:atend
    if i>=af:lines:size
      af:lines size := max 2*af:lines:size 16
    af:lines i := f readline
    i += 1
  af:lines size := i

method af store -> status
  arg_rw AsciiFile af ; arg Status status
  (var Stream f) open af:filename out+mkdir+safe
  for (var Int i) 0 af:lines:size-1
    f writeline af:lines:i
  status := f close
    

method af size -> i
  arg AsciiFile af ; arg Int i
  i := af:lines size
  
method af '' i -> l
  arg AsciiFile af ; arg Int i ; arg_C Str l
  check i>=0 and i<af:lines:size
  l :> af:lines i
  
function '+=' af l
  arg_rw AsciiFile af ; arg Str l
  af lines += l

method af insert i l
  arg_rw AsciiFile af ; arg Int i ; arg Str l
  check i>=0 and i<=af:size
  af:lines size := af:size+1
  for (var Int j) af:size-2 i step -1
    af j+1 := af j
  af i := l
  
method af remove i
  arg_rw AsciiFile af ; arg Int i
  check i>=0 and i<af:size
  for (var Int j) i af:size-2
    af j := af j+1
  af:lines size := af:size-1
  

method af get ident sign -> value
  arg AsciiFile af ; arg Str ident sign value
  for (var Int i) 0 af:size-1
    if (shunt sign<>"" (af:i parse word:ident pattern:sign any:value) (af:i parse word:ident any:value))
      return
  value := ""

method af set ident sign line
  arg_rw AsciiFile af ; arg Str ident sign line
  for (var Int i) 0 af:size-1
    if (shunt sign<>"" (af:i parse word:ident pattern:sign any) (af:i parse word:ident any))
      af i := line
      return
  af += line

method af fuzzy_set ident sign line
  arg_rw AsciiFile af ; arg Str ident sign line
  for (var Int i) 0 af:size-1
    if (shunt sign<>"" (af:i parse any word:ident pattern:sign any) (af:i parse any word:ident any))
      af i := line
      return
  af += line

method af set_all ident sign line
  arg_rw AsciiFile af ; arg Str ident sign line
  for (var Int i) 0 af:size-1
    if (shunt sign<>"" (af:i parse word:ident pattern:sign any) (af:i parse word:ident any))
      af i := line

method af replace pattern with
  arg_rw AsciiFile af ; arg Str pattern with
  for (var Int i) 0 af:size-1
    af i := replace af:i pattern with


export AsciiFile '. reset' '. load' '. store'
export '. size' '' '+=' '. insert' '. remove'
export '. get' '. set' '. fuzzy_set' '. set_all'
export '. get' '. set' '. fuzzy_set' '. set_all' '. replace'


function file_replace filename pattern with
  arg Str filename pattern with
  var AsciiFile af
  af load filename
  # console af:size " line(s) in " filename eol
  af replace pattern with
  af store

export file_replace