Update a configuration file: Difference between revisions

m
→‎{{header|11l}}: new way of specifying file open mode
m (→‎version 1: added/changed comments, indentations, and whitespace.)
m (→‎{{header|11l}}: new way of specifying file open mode)
 
(42 intermediate revisions by 16 users not shown)
Line 5:
# This is a configuration file in standard configuration file format
#
# Lines beginningbegininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
Line 53:
 
 
;Related tasks
;See also:
* [[Read a configuration file]]
<br><br>
 
=={{header|11l}}==
{{trans|D}}
 
<syntaxhighlight lang="11l">T.enum EntryType
EMPTY
ENABLED
DISABLED
COMMENT
IGNORE
 
T Entry
EntryType etype
String name
String value
 
F (etype, name = ‘’, value = ‘’)
.etype = etype
.name = name
.value = value
 
T Config
String path
[Entry] entries
 
F (path)
.path = path
L(=line) File(path).read_lines()
line = line.ltrim(‘ ’)
I line.empty
.entries.append(Entry(EntryType.EMPTY))
E I line[0] == ‘#’
.entries.append(Entry(EntryType.COMMENT, line))
E
line = line.replace(re:‘[^a-zA-Z0-9\x20;]’, ‘’)
V m = re:‘^(;*)\s*([a-zA-Z0-9]+)\s*([a-zA-Z0-9]*)’.search(line)
I m & !m.group(2).empty
V t = I m.group(1).empty {EntryType.ENABLED} E EntryType.DISABLED
.addOption(m.group(2), m.group(3), t)
 
F enableOption(name)
Int? i = .getOptionIndex(name)
I i != N
.entries[i].etype = EntryType.ENABLED
 
F disableOption(name)
Int? i = .getOptionIndex(name)
I i != N
.entries[i].etype = EntryType.DISABLED
 
F setOption(name, value)
Int? i = .getOptionIndex(name)
I i != N
.entries[i].value = value
 
F addOption(name, val, t = EntryType.ENABLED)
.entries.append(Entry(t, name.uppercase(), val))
 
F removeOption(name)
Int? i = .getOptionIndex(name)
I i != N
.entries[i].etype = EntryType.IGNORE
 
F getOptionIndex(name) -> Int?
L(e) .entries
I e.etype !C (EntryType.ENABLED, EntryType.DISABLED)
L.continue
I e.name == name.uppercase()
R L.index
R N
 
F store()
V f = File(.path, WRITE)
L(e) .entries
I e.etype == EMPTY
f.write("\n")
E I e.etype == ENABLED
f.write("#. #.\n".format(e.name, e.value))
E I e.etype == DISABLED
f.write("; #. #.\n".format(e.name, e.value))
E I e.etype == COMMENT
f.write(e.name"\n")
 
V cfg = Config(‘config.txt’)
cfg.enableOption(‘seedsremoved’)
cfg.disableOption(‘needspeeling’)
cfg.setOption(‘numberofbananas’, ‘1024’)
cfg.addOption(‘numberofstrawberries’, ‘62000’)
cfg.store()</syntaxhighlight>
 
{{out}}
The same as in D.
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">; Author: AlephX, Aug 17 2011
data = %A_scriptdir%\rosettaconfig.txt
outdata = %A_scriptdir%\rosettaconfig.tmp
Line 149 ⟶ 241:
}
 
FileCopy, %A_scriptdir%\rosettaconfig.tmp, %A_scriptdir%\rosettaconfig.txt, 1</langsyntaxhighlight>
 
=={{header|BASIC}}==
{{works with|QBasic|1.1}}
{{works with|QuickBasic|4.5}}
{{works with|VB-DOS|1.0}}
{{works with|QB64|1.1}}
{{works with|PDS|7.1}}
 
This program is not tied to the task requested, but it can read and modify ANY configuration file. It is somewhat long, but includes functionality to modify or add variables and values to the configuration file, append remarks (#) to it, read and save values in an array (comma separated), toggle comment mode for variables in a configuration file, etc. It is even longer because is almost fully commented and in key procedures every parameter is explained. It includes a main program cycle to read the configuration file and modify its values.
<syntaxhighlight lang="qbasic">
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
' Read a Configuration File V1.0 '
' '
' Developed by A. David Garza Marín in VB-DOS for '
' RosettaCode. December 2, 2016. '
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
 
' OPTION EXPLICIT ' For VB-DOS, PDS 7.1
' OPTION _EXPLICIT ' For QB64
 
' SUBs and FUNCTIONs
DECLARE SUB AppendCommentToConfFile (WhichFile AS STRING, WhichComment AS STRING, LeaveALine AS INTEGER)
DECLARE SUB setNValToVarArr (WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS DOUBLE)
DECLARE SUB setSValToVar (WhichVariable AS STRING, WhatValue AS STRING)
DECLARE SUB setSValToVarArr (WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS STRING)
DECLARE SUB doModifyArrValueFromConfFile (WhichFile AS STRING, WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS STRING, Separator AS STRING, ToComment AS INTEGER)
DECLARE SUB doModifyValueFromConfFile (WhichFile AS STRING, WhichVariable AS STRING, WhatValue AS STRING, Separator AS STRING, ToComment AS INTEGER)
DECLARE FUNCTION CreateConfFile% (WhichFile AS STRING)
DECLARE FUNCTION ErrorMessage$ (WhichError AS INTEGER)
DECLARE FUNCTION FileExists% (WhichFile AS STRING)
DECLARE FUNCTION FindVarPos% (WhichVariable AS STRING)
DECLARE FUNCTION FindVarPosArr% (WhichVariable AS STRING, WhichIndex AS INTEGER)
DECLARE FUNCTION getArrayVariable$ (WhichVariable AS STRING, WhichIndex AS INTEGER)
DECLARE FUNCTION getVariable$ (WhichVariable AS STRING)
DECLARE FUNCTION getVarType% (WhatValue AS STRING)
DECLARE FUNCTION GetDummyFile$ (WhichFile AS STRING)
DECLARE FUNCTION HowManyElementsInTheArray% (WhichVariable AS STRING)
DECLARE FUNCTION IsItAnArray% (WhichVariable AS STRING)
DECLARE FUNCTION IsItTheVariableImLookingFor% (TextToAnalyze AS STRING, WhichVariable AS STRING)
DECLARE FUNCTION NewValueForTheVariable$ (WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS STRING, Separator AS STRING)
DECLARE FUNCTION ReadConfFile% (NameOfConfFile AS STRING)
DECLARE FUNCTION YorN$ ()
 
' Register for values located
TYPE regVarValue
VarName AS STRING * 20
VarType AS INTEGER ' 1=String, 2=Integer, 3=Real, 4=Comment
VarValue AS STRING * 30
END TYPE
 
' Var
DIM rVarValue() AS regVarValue, iErr AS INTEGER, i AS INTEGER, iHMV AS INTEGER
DIM iArrayElements AS INTEGER, iWhichElement AS INTEGER, iCommentStat AS INTEGER
DIM iAnArray AS INTEGER, iSave AS INTEGER
DIM otherfamily(1 TO 2) AS STRING
DIM sVar AS STRING, sVal AS STRING, sComment AS STRING
CONST ConfFileName = "config2.fil"
CONST False = 0, True = NOT False
 
' ------------------- Main Program ------------------------
DO
CLS
ERASE rVarValue
PRINT "This program reads a configuration file and shows the result."
PRINT
PRINT "Default file name: "; ConfFileName
PRINT
iErr = ReadConfFile(ConfFileName)
IF iErr = 0 THEN
iHMV = UBOUND(rVarValue)
PRINT "Variables found in file:"
FOR i = 1 TO iHMV
PRINT RTRIM$(rVarValue(i).VarName); " = "; RTRIM$(rVarValue(i).VarValue); " (";
SELECT CASE rVarValue(i).VarType
CASE 0: PRINT "Undefined";
CASE 1: PRINT "String";
CASE 2: PRINT "Integer";
CASE 3: PRINT "Real";
CASE 4: PRINT "Is a commented variable";
END SELECT
PRINT ")"
NEXT i
PRINT
 
INPUT "Type the variable name to modify (Blank=End)"; sVar
sVar = RTRIM$(LTRIM$(sVar))
IF LEN(sVar) > 0 THEN
i = FindVarPos%(sVar)
IF i > 0 THEN ' Variable found
iAnArray = IsItAnArray%(sVar)
IF iAnArray THEN
iArrayElements = HowManyElementsInTheArray%(sVar)
PRINT "This is an array of"; iArrayElements; " elements."
INPUT "Which one do you want to modify (Default=1)"; iWhichElement
IF iWhichElement = 0 THEN iWhichElement = 1
ELSE
iArrayElements = 1
iWhichElement = 1
END IF
PRINT "The current value of the variable is: "
IF iAnArray THEN
PRINT sVar; "("; iWhichElement; ") = "; RTRIM$(rVarValue(i + (iWhichElement - 1)).VarValue)
ELSE
PRINT sVar; " = "; RTRIM$(rVarValue(i + (iWhichElement - 1)).VarValue)
END IF
ELSE
PRINT "The variable was not found. It will be added."
END IF
PRINT
INPUT "Please, set the new value for the variable (Blank=Unmodified)"; sVal
sVal = RTRIM$(LTRIM$(sVal))
IF i > 0 THEN
IF rVarValue(i + (iWhichElement - 1)).VarType = 4 THEN
PRINT "Do you want to remove the comment status to the variable? (Y/N)"
iCommentStat = NOT (YorN = "Y")
iCommentStat = ABS(iCommentStat) ' Gets 0 (Toggle) or 1 (Leave unmodified)
iSave = (iCommentStat = 0)
ELSE
PRINT "Do you want to toggle the variable as a comment? (Y/N)"
iCommentStat = (YorN = "Y") ' Gets 0 (Uncommented) or -1 (Toggle as a Comment)
iSave = iCommentStat
END IF
END IF
' Now, update or add the variable to the conf file
IF i > 0 THEN
IF sVal = "" THEN
sVal = RTRIM$(rVarValue(i).VarValue)
END IF
ELSE
PRINT "The variable will be added to the configuration file."
PRINT "Do you want to add a remark for it? (Y/N)"
IF YorN$ = "Y" THEN
LINE INPUT "Please, write your remark: ", sComment
sComment = LTRIM$(RTRIM$(sComment))
IF sComment <> "" THEN
AppendCommentToConfFile ConfFileName, sComment, True
END IF
END IF
END IF
 
' Verifies if the variable will be modified, and applies the modification
IF sVal <> "" OR iSave THEN
IF iWhichElement > 1 THEN
setSValToVarArr sVar, iWhichElement, sVal
doModifyArrValueFromConfFile ConfFileName, sVar, iWhichElement, sVal, " ", iCommentStat
ELSE
setSValToVar sVar, sVal
doModifyValueFromConfFile ConfFileName, sVar, sVal, " ", iCommentStat
END IF
END IF
END IF
ELSE
PRINT ErrorMessage$(iErr)
END IF
PRINT
PRINT "Do you want to add or modify another variable? (Y/N)"
LOOP UNTIL YorN$ = "N"
' --------- End of Main Program -----------------------
PRINT
PRINT "End of program."
END
 
FileError:
iErr = ERR
RESUME NEXT
 
SUB AppendCommentToConfFile (WhichFile AS STRING, WhichComment AS STRING, LeaveALine AS INTEGER)
' Parameters:
' WhichFile: Name of the file where a comment will be appended.
' WhichComment: A comment. It is suggested to add a comment no larger than 75 characters.
' This procedure adds a # at the beginning of the string if there is no #
' sign on it in order to ensure it will be added as a comment.
 
' Var
DIM iFil AS INTEGER
 
iFil = FileExists%(WhichFile)
IF NOT iFil THEN
iFil = CreateConfFile%(WhichFile) ' Here, iFil is used as dummy to save memory
END IF
 
IF iFil THEN ' Everything is Ok
iFil = FREEFILE ' Now, iFil is used to be the ID of the file
WhichComment = LTRIM$(RTRIM$(WhichComment))
 
IF LEFT$(WhichComment, 1) <> "#" THEN ' Is it in comment format?
WhichComment = "# " + WhichComment
END IF
 
' Append the comment to the file
OPEN WhichFile FOR APPEND AS #iFil
IF LeaveALine THEN
PRINT #iFil, ""
END IF
PRINT #iFil, WhichComment
CLOSE #iFil
END IF
 
END SUB
 
FUNCTION CreateConfFile% (WhichFile AS STRING)
' Var
DIM iFile AS INTEGER
 
ON ERROR GOTO FileError
 
iFile = FREEFILE
OPEN WhichFile FOR OUTPUT AS #iFile
CLOSE iFile
 
ON ERROR GOTO 0
 
CreateConfFile = FileExists%(WhichFile)
END FUNCTION
 
SUB doModifyArrValueFromConfFile (WhichFile AS STRING, WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS STRING, Separator AS STRING, ToComment AS INTEGER)
' Parameters:
' WhichFile: The name of the Configuration File. It can include the full path.
' WhichVariable: The name of the variable to be modified or added to the conf file.
' WhichIndex: The index number of the element to be modified in a matrix (Default=1)
' WhatValue: The new value to set in the variable specified in WhichVariable.
' Separator: The separator between the variable name and its value in the conf file. Defaults to a space " ".
' ToComment: A value to set or remove the comment mode of a variable: -1=Toggle to Comment, 0=Toggle to not comment, 1=Leave as it is.
 
' Var
DIM iFile AS INTEGER, iFile2 AS INTEGER, iError AS INTEGER
DIM iMod AS INTEGER, iIsComment AS INTEGER
DIM sLine AS STRING, sDummyFile AS STRING, sChar AS STRING
 
' If conf file doesn't exists, create one.
iError = 0
iMod = 0
IF NOT FileExists%(WhichFile) THEN
iError = CreateConfFile%(WhichFile)
END IF
 
IF NOT iError THEN ' File exists or it was created
Separator = RTRIM$(LTRIM$(Separator))
IF Separator = "" THEN
Separator = " " ' Defaults to Space
END IF
sDummyFile = GetDummyFile$(WhichFile)
 
' It is assumed a text file
iFile = FREEFILE
OPEN WhichFile FOR INPUT AS #iFile
 
iFile2 = FREEFILE
OPEN sDummyFile FOR OUTPUT AS #iFile2
 
' Goes through the file to find the variable
DO WHILE NOT EOF(iFile)
LINE INPUT #iFile, sLine
sLine = RTRIM$(LTRIM$(sLine))
sChar = LEFT$(sLine, 1)
iIsComment = (sChar = ";")
IF iIsComment THEN ' Variable is commented
sLine = LTRIM$(MID$(sLine, 2))
END IF
 
IF sChar <> "#" AND LEN(sLine) > 0 THEN ' Is not a comment?
IF IsItTheVariableImLookingFor%(sLine, WhichVariable) THEN
sLine = NewValueForTheVariable$(WhichVariable, WhichIndex, WhatValue, Separator)
iMod = True
IF ToComment = True THEN
sLine = "; " + sLine
END IF
ELSEIF iIsComment THEN
sLine = "; " + sLine
END IF
 
END IF
 
PRINT #iFile2, sLine
LOOP
 
' Reviews if a modification was done, if not, then it will
' add the variable to the file.
IF NOT iMod THEN
sLine = NewValueForTheVariable$(WhichVariable, 1, WhatValue, Separator)
PRINT #iFile2, sLine
END IF
CLOSE iFile2, iFile
 
' Removes the conf file and sets the dummy file as the conf file
KILL WhichFile
NAME sDummyFile AS WhichFile
END IF
 
END SUB
 
SUB doModifyValueFromConfFile (WhichFile AS STRING, WhichVariable AS STRING, WhatValue AS STRING, Separator AS STRING, ToComment AS INTEGER)
' To see details of parameters, please see doModifyArrValueFromConfFile
doModifyArrValueFromConfFile WhichFile, WhichVariable, 1, WhatValue, Separator, ToComment
END SUB
 
FUNCTION ErrorMessage$ (WhichError AS INTEGER)
' Var
DIM sError AS STRING
 
SELECT CASE WhichError
CASE 0: sError = "Everything went ok."
CASE 1: sError = "Configuration file doesn't exist."
CASE 2: sError = "There are no variables in the given file."
END SELECT
 
ErrorMessage$ = sError
END FUNCTION
 
FUNCTION FileExists% (WhichFile AS STRING)
' Var
DIM iFile AS INTEGER
DIM iItExists AS INTEGER
SHARED iErr AS INTEGER
 
ON ERROR GOTO FileError
iFile = FREEFILE
iErr = 0
OPEN WhichFile FOR BINARY AS #iFile
IF iErr = 0 THEN
iItExists = LOF(iFile) > 0
CLOSE #iFile
 
IF NOT iItExists THEN
KILL WhichFile
END IF
END IF
ON ERROR GOTO 0
FileExists% = iItExists
 
END FUNCTION
 
FUNCTION FindVarPos% (WhichVariable AS STRING)
' Will find the position of the variable
FindVarPos% = FindVarPosArr%(WhichVariable, 1)
END FUNCTION
 
FUNCTION FindVarPosArr% (WhichVariable AS STRING, WhichIndex AS INTEGER)
' Var
DIM i AS INTEGER, iHMV AS INTEGER, iCount AS INTEGER, iPos AS INTEGER
DIM sVar AS STRING, sVal AS STRING, sWV AS STRING
SHARED rVarValue() AS regVarValue
 
' Looks for a variable name and returns its position
iHMV = UBOUND(rVarValue)
sWV = UCASE$(LTRIM$(RTRIM$(WhichVariable)))
sVal = ""
iCount = 0
DO
i = i + 1
sVar = UCASE$(RTRIM$(rVarValue(i).VarName))
IF sVar = sWV THEN
iCount = iCount + 1
IF iCount = WhichIndex THEN
iPos = i
END IF
END IF
LOOP UNTIL i >= iHMV OR iPos > 0
 
FindVarPosArr% = iPos
END FUNCTION
 
FUNCTION getArrayVariable$ (WhichVariable AS STRING, WhichIndex AS INTEGER)
' Var
DIM i AS INTEGER
DIM sVal AS STRING
SHARED rVarValue() AS regVarValue
 
i = FindVarPosArr%(WhichVariable, WhichIndex)
sVal = ""
IF i > 0 THEN
sVal = RTRIM$(rVarValue(i).VarValue)
END IF
 
' Found it or not, it will return the result.
' If the result is "" then it didn't found the requested variable.
getArrayVariable$ = sVal
 
END FUNCTION
 
FUNCTION GetDummyFile$ (WhichFile AS STRING)
' Var
DIM i AS INTEGER, j AS INTEGER
 
' Gets the path specified in WhichFile
i = 1
DO
j = INSTR(i, WhichFile, "\")
IF j > 0 THEN i = j + 1
LOOP UNTIL j = 0
 
GetDummyFile$ = LEFT$(WhichFile, i - 1) + "$dummyf$.tmp"
END FUNCTION
 
FUNCTION getVariable$ (WhichVariable AS STRING)
' Var
DIM i AS INTEGER, iHMV AS INTEGER
DIM sVal AS STRING
 
' For a single variable, looks in the first (and only)
' element of the array that contains the name requested.
sVal = getArrayVariable$(WhichVariable, 1)
 
getVariable$ = sVal
END FUNCTION
 
FUNCTION getVarType% (WhatValue AS STRING)
' Var
DIM sValue AS STRING, dValue AS DOUBLE, iType AS INTEGER
 
sValue = RTRIM$(WhatValue)
iType = 0
IF LEN(sValue) > 0 THEN
IF ASC(LEFT$(sValue, 1)) < 48 OR ASC(LEFT$(sValue, 1)) > 57 THEN
iType = 1 ' String
ELSE
dValue = VAL(sValue)
IF CLNG(dValue) = dValue THEN
iType = 2 ' Integer
ELSE
iType = 3 ' Real
END IF
END IF
END IF
 
getVarType% = iType
END FUNCTION
 
FUNCTION HowManyElementsInTheArray% (WhichVariable AS STRING)
' Var
DIM i AS INTEGER, iHMV AS INTEGER, iCount AS INTEGER, iPos AS INTEGER, iQuit AS INTEGER
DIM sVar AS STRING, sVal AS STRING, sWV AS STRING
SHARED rVarValue() AS regVarValue
 
' Looks for a variable name and returns its value
iHMV = UBOUND(rVarValue)
sWV = UCASE$(LTRIM$(RTRIM$(WhichVariable)))
sVal = ""
 
' Look for all instances of WhichVariable in the
' list. This is because elements of an array will not alwasy
' be one after another, but alternate.
FOR i = 1 TO iHMV
sVar = UCASE$(RTRIM$(rVarValue(i).VarName))
IF sVar = sWV THEN
iCount = iCount + 1
END IF
NEXT i
 
HowManyElementsInTheArray = iCount
END FUNCTION
 
FUNCTION IsItAnArray% (WhichVariable AS STRING)
' Returns if a Variable is an Array
IsItAnArray% = (HowManyElementsInTheArray%(WhichVariable) > 1)
 
END FUNCTION
 
FUNCTION IsItTheVariableImLookingFor% (TextToAnalyze AS STRING, WhichVariable AS STRING)
' Var
DIM sVar AS STRING, sDT AS STRING, sDV AS STRING
DIM iSep AS INTEGER
 
sDT = UCASE$(RTRIM$(LTRIM$(TextToAnalyze)))
sDV = UCASE$(RTRIM$(LTRIM$(WhichVariable)))
iSep = INSTR(sDT, "=")
IF iSep = 0 THEN iSep = INSTR(sDT, " ")
IF iSep > 0 THEN
sVar = RTRIM$(LEFT$(sDT, iSep - 1))
ELSE
sVar = sDT
END IF
 
' It will return True or False
IsItTheVariableImLookingFor% = (sVar = sDV)
END FUNCTION
 
FUNCTION NewValueForTheVariable$ (WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS STRING, Separator AS STRING)
' Var
DIM iItem AS INTEGER, iItems AS INTEGER, iFirstItem AS INTEGER
DIM i AS INTEGER, iCount AS INTEGER, iHMV AS INTEGER
DIM sLine AS STRING, sVar AS STRING, sVar2 AS STRING
SHARED rVarValue() AS regVarValue
 
IF IsItAnArray%(WhichVariable) THEN
iItems = HowManyElementsInTheArray(WhichVariable)
iFirstItem = FindVarPosArr%(WhichVariable, 1)
ELSE
iItems = 1
iFirstItem = FindVarPos%(WhichVariable)
END IF
iItem = FindVarPosArr%(WhichVariable, WhichIndex)
sLine = ""
sVar = UCASE$(WhichVariable)
iHMV = UBOUND(rVarValue)
 
IF iItem > 0 THEN
i = iFirstItem
DO
sVar2 = UCASE$(RTRIM$(rVarValue(i).VarName))
IF sVar = sVar2 THEN ' Does it found an element of the array?
iCount = iCount + 1
IF LEN(sLine) > 0 THEN ' Add a comma
sLine = sLine + ", "
END IF
IF i = iItem THEN
sLine = sLine + WhatValue
ELSE
sLine = sLine + RTRIM$(rVarValue(i).VarValue)
END IF
END IF
i = i + 1
LOOP UNTIL i > iHMV OR iCount = iItems
 
sLine = WhichVariable + Separator + sLine
ELSE
sLine = WhichVariable + Separator + WhatValue
END IF
 
NewValueForTheVariable$ = sLine
END FUNCTION
 
FUNCTION ReadConfFile% (NameOfConfFile AS STRING)
' Var
DIM iFile AS INTEGER, iType AS INTEGER, iVar AS INTEGER, iHMV AS INTEGER
DIM iVal AS INTEGER, iCurVar AS INTEGER, i AS INTEGER, iErr AS INTEGER
DIM dValue AS DOUBLE, iIsComment AS INTEGER
DIM sLine AS STRING, sVar AS STRING, sValue AS STRING
SHARED rVarValue() AS regVarValue
 
' This procedure reads a configuration file with variables
' and values separated by the equal sign (=) or a space.
' It needs the FileExists% function.
' Lines begining with # or blank will be ignored.
IF FileExists%(NameOfConfFile) THEN
iFile = FREEFILE
REDIM rVarValue(1 TO 10) AS regVarValue
OPEN NameOfConfFile FOR INPUT AS #iFile
WHILE NOT EOF(iFile)
LINE INPUT #iFile, sLine
sLine = RTRIM$(LTRIM$(sLine))
IF LEN(sLine) > 0 THEN ' Does it have any content?
IF LEFT$(sLine, 1) <> "#" THEN ' Is not a comment?
iIsComment = (LEFT$(sLine, 1) = ";")
IF iIsComment THEN ' It is a commented variable
sLine = LTRIM$(MID$(sLine, 2))
END IF
iVar = INSTR(sLine, "=") ' Is there an equal sign?
IF iVar = 0 THEN iVar = INSTR(sLine, " ") ' if not then is there a space?
 
GOSUB AddASpaceForAVariable
iCurVar = iHMV
IF iVar > 0 THEN ' Is a variable and a value
rVarValue(iHMV).VarName = LEFT$(sLine, iVar - 1)
ELSE ' Is just a variable name
rVarValue(iHMV).VarName = sLine
rVarValue(iHMV).VarValue = ""
END IF
 
IF iVar > 0 THEN ' Get the value(s)
sLine = LTRIM$(MID$(sLine, iVar + 1))
DO ' Look for commas
iVal = INSTR(sLine, ",")
IF iVal > 0 THEN ' There is a comma
rVarValue(iHMV).VarValue = RTRIM$(LEFT$(sLine, iVal - 1))
GOSUB AddASpaceForAVariable
rVarValue(iHMV).VarName = rVarValue(iHMV - 1).VarName ' Repeats the variable name
sLine = LTRIM$(MID$(sLine, iVal + 1))
END IF
LOOP UNTIL iVal = 0
rVarValue(iHMV).VarValue = sLine
 
END IF
 
' Determine the variable type of each variable found in this step
FOR i = iCurVar TO iHMV
IF iIsComment THEN
rVarValue(i).VarType = 4 ' Is a comment
ELSE
GOSUB DetermineVariableType
END IF
NEXT i
 
END IF
END IF
WEND
CLOSE iFile
IF iHMV > 0 THEN
REDIM PRESERVE rVarValue(1 TO iHMV) AS regVarValue
iErr = 0 ' Everything ran ok.
ELSE
REDIM rVarValue(1 TO 1) AS regVarValue
iErr = 2 ' No variables found in configuration file
END IF
ELSE
iErr = 1 ' File doesn't exist
END IF
 
ReadConfFile = iErr
 
EXIT FUNCTION
 
AddASpaceForAVariable:
iHMV = iHMV + 1
 
IF UBOUND(rVarValue) < iHMV THEN ' Are there space for a new one?
REDIM PRESERVE rVarValue(1 TO iHMV + 9) AS regVarValue
END IF
RETURN
 
DetermineVariableType:
sValue = RTRIM$(rVarValue(i).VarValue)
IF LEN(sValue) > 0 THEN
IF ASC(LEFT$(sValue, 1)) < 48 OR ASC(LEFT$(sValue, 1)) > 57 THEN
rVarValue(i).VarType = 1 ' String
ELSE
dValue = VAL(sValue)
IF CLNG(dValue) = dValue THEN
rVarValue(i).VarType = 2 ' Integer
ELSE
rVarValue(i).VarType = 3 ' Real
END IF
END IF
END IF
RETURN
 
END FUNCTION
 
SUB setNValToVar (WhichVariable AS STRING, WhatValue AS DOUBLE)
' Sets a numeric value to a variable
setNValToVarArr WhichVariable, 1, WhatValue
END SUB
 
SUB setNValToVarArr (WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS DOUBLE)
' Sets a numeric value to a variable array
' Var
DIM sVal AS STRING
sVal = FORMAT$(WhatValue)
setSValToVarArr WhichVariable, WhichIndex, sVal
END SUB
 
SUB setSValToVar (WhichVariable AS STRING, WhatValue AS STRING)
' Sets a string value to a variable
setSValToVarArr WhichVariable, 1, WhatValue
END SUB
 
SUB setSValToVarArr (WhichVariable AS STRING, WhichIndex AS INTEGER, WhatValue AS STRING)
' Sets a string value to a variable array
' Var
DIM i AS INTEGER
DIM sVar AS STRING
SHARED rVarValue() AS regVarValue
 
i = FindVarPosArr%(WhichVariable, WhichIndex)
IF i = 0 THEN ' Should add the variable
IF UBOUND(rVarValue) > 0 THEN
sVar = RTRIM$(rVarValue(1).VarName)
IF sVar <> "" THEN
i = UBOUND(rVarValue) + 1
REDIM PRESERVE rVarValue(1 TO i) AS regVarValue
ELSE
i = 1
END IF
ELSE
REDIM rVarValue(1 TO i) AS regVarValue
END IF
rVarValue(i).VarName = WhichVariable
END IF
 
' Sets the new value to the variable
rVarValue(i).VarValue = WhatValue
rVarValue(i).VarType = getVarType%(WhatValue)
END SUB
 
FUNCTION YorN$ ()
' Var
DIM sYorN AS STRING
 
DO
sYorN = UCASE$(INPUT$(1))
IF INSTR("YN", sYorN) = 0 THEN
BEEP
END IF
LOOP UNTIL sYorN = "Y" OR sYorN = "N"
 
YorN$ = sYorN
END FUNCTION
</syntaxhighlight>
 
In the following example, the user can modify the variables, their comment status and add the NUMBEROFSTRAWBERRIES variable with the value of 64000. In this case, the user is modifying the value of the NUMBEROFBANANAS variable in the configuration file.
 
<pre>
This program reads a configuration file and shows the result.
 
Default file name: config.fil
 
Variables found in file:
FAVOURITEFRUIT = banana (String)
NEEDSPEELING = (Undefined)
SEEDSREMOVED = (Is a commented variable)
NUMBEROFBANANAS = 48 (Integer)
 
Type the variable name to modify (Blank=End)? numberofbananas
The current value of the variable is:
NUMBEROFBANANAS = 48
 
Please, set the new value for the variable (Blank=Unmodified)? 1024
Do you want to toggle the variable as a comment? (Y/N)
 
Do you want to add or modify another variable? (Y/N)
</pre>
 
=={{header|C}}==
Line 155 ⟶ 961:
C with POSIX <code>strcasecmp</code> function for case-insensitive comparing. Substitute your toolchain's version.
 
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Line 221 ⟶ 1,027:
{ fprintf(stderr, "failed\n");
return (EXIT_FAILURE); }
return 0; }</langsyntaxhighlight>
 
Run:
Line 254 ⟶ 1,060:
=={{header|D}}==
This type of file is really not very suitable for automated management, so this code is very basic.
<langsyntaxhighlight lang="d">import std.stdio, std.file, std.string, std.regex, std.path,
std.typecons;
 
Line 366 ⟶ 1,172:
cfg.addOption("numberofstrawberries", "62000");
cfg.store();
}</langsyntaxhighlight>
Input file:
<pre># This is a configuration file in standard configuration file format
Line 419 ⟶ 1,225:
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{libheader| uSettings}}
Requere '''uSettings.pas''' found in [[Read_a_configuration_file#Delphi]].
<syntaxhighlight lang="delphi">
program uConfigFile;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils,
uSettings;
 
const
FileName = 'uConf.txt';
 
var
Settings: TSettings;
 
procedure show(key: string; value: string);
begin
writeln(format('%14s = %s', [key, value]));
end;
 
begin
Settings := TSettings.Create;
Settings.LoadFromFile(FileName);
Settings['NEEDSPEELING'] := False;
Settings['SEEDSREMOVED'] := True;
Settings['NUMBEROFBANANAS'] := 1024;
Settings['numberofstrawberries'] := 62000;
 
for var k in Settings.Keys do
show(k, Settings[k]);
Settings.SaveToFile(FileName);
Settings.Free;
Readln;
end.</syntaxhighlight>
{{out}}
<pre> FAVOURITEFRUIT = banana
SEEDSREMOVED = True
NEEDSPEELING = False
NUMBEROFBANANAS = 1024
NUMBEROFSTRAWBERRIES = 62000</pre>
 
=={{header|Erlang}}==
Given the large number of very exact rules governing the update of this configuration file it is with some pleasure I add new options to the beginning of the file.
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( update_configuration_file ).
 
Line 517 ⟶ 1,367:
[Option | T] = string:tokens( String, " " ),
string:join( [string:to_upper(Option) | T], " " ).
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 549 ⟶ 1,399:
 
=={{header|Fortran}}==
Fortran has long had a built-in method for writing and reading a configuration file with ease, via the NAMELIST facility. The designers of the modern "configuration" files have paid not the slightest attention to the protocol, which is as follows: <langsyntaxhighlight Fortranlang="fortran"> PROGRAM TEST !Define some data aggregates, then write and read them.
CHARACTER*28 FAVOURITEFRUIT
LOGICAL NEEDSPEELING
Line 573 ⟶ 1,423:
READ (F,FRUIT) !Read who knows what.
WRITE (6,FRUIT)
END</langsyntaxhighlight>
Most of which is support stuff. The requirement is to declare a NAMELIST naming the variables of interest, then READ or WRITE using just the name of the NAMELIST. Only three statements, four if the file OPEN is counted.
Which produces a file in a standard layout.
 
''One statement to write them''
 
''One statement to read them''
 
''One statement to find them all, and in the NAMELIST bind them.''
 
(Apologies to J.R.R. Tolkien)
 
The result is a file in a standard layout.
<pre>
&FRUIT
Line 583 ⟶ 1,443:
/
</pre>
Evidently, the variables named in the NAMELIST are written out, one to a line in free-format with a style appropriate to its type, much as if they were assignment statements within a source file. Since Fortran compilers do not distinguish between upper and lower case, either may be used. The namelist's name starts the output, and the block of values ends with a line starting with a slash. On input, blocks will be skipped until the correct block name is found, so a single file may contain parameters for multiple usages. All output starts with column two so that column one can be used as a carriage control character if output is to go to a lineprinter. There is special provision for an array's value list whereby a run of equal values can be noted via <code>''n''*''value''</code> to save space, further, an input statement for an array can name a single element (the others being unaffected), and with F90, the usual array span facilities are available as in <code>A(6:10) = 5*3.14</code> Should an output list of values be too long for the standard line length (133, again to suit lineprinters, but this value can be changed by RECL = ''n'' in the OPEN statement) then the list will be split across lines after a comma. However, long CHARACTER variables will cross multiple lines and column one will be used, something of a mistake should such output go to a lineprinter as it may react badly to strange carriage control characters.
 
TheInput allows for a comma-separated list of assignments and the names may appear in any order. If a name appears more than once, andeach namesassignment will be accepted so that the last one counts. Names can be omitted - if so, the corresponding variable will be unaffected by a READ. ThisIt filewould couldbe ofnice courseif, bethe editedvariable beforehaving beingbeen read backdeclared in CamelStyle, the name would be printed that way, but alas. F90 introduces the ! character as an "escape" comment and this is recognised in the NAMELIST input, outside of text literals of course.
 
To remove the SeedsRemoved entry is straightforward, depending on context. If its name is removed from the NAMELIST then it will no longer be written. The parameter file could of course be edited before being read back in, perhaps by a human, or by the installation process of the new version, or by the new version first finding the unwanted line, backspacing the file one record and writing the right number of spaces to wipe it without changing the length of a record - though this ploy may not be available if the filesystem provides limited support. If however a new version of the programme is expected to read the old version's parameter file, then there will be trouble because an unknown name (or an array index out of bounds, but not a CHARACTER variable being shorter than the supplied text) will provoke an I/O error and the run will crash. This can be avoided via the ERR = ''label'' option in the READ statement, however entries after the erroneous one will not be processed.
Naturally, a parameter file could contain data in whatever format desired: such a file could be read and its components extracted via suitable code then written in the NAMELIST style to a scratch file and read back for the actual internalisation of values. The point of this is that a text name of a variable is associated with the actual computer variable via the NAMELIST facility, the programmer need not slog through some endless CASE statement on the names of the variables. This process would be reversed for output.
 
In a more general situation, it is helpful to have a routine that reads the NAMELIST style input and isolates the assignments so that each can individually be written to a scratch file in the NAMELIST style (i.e. providing the block head and tail lines, though some Fortrans allow NAMELIST input from a text variable and without this requirement) whereupon if ERR is provoked during the READ, the troublesome entry can be displayed for user appreciation before continuing with any remaining assignments.
 
Otherwise, the old NAMELIST could be used for input, with the undesired value simply ignored within the new version of the programme. For output, a new NAMELIST would be devised omitting the unwanted name - the same variables can be named in more than one NAMELIST. However, every NAMELIST's name must be unique within a routine and this would be the new block header name. So, read the parameter file in one routine which declares the old NAMELIST, complete with the name of the now unwanted variable, but write it via another routine which declares the new NAMELIST using the same name but omitting the names of undesired variables. The wanted variables would be in COMMON, or with F90 onwards be common names in a MODULE, or one could mess with parameter lists. <syntaxhighlight lang="fortran"> MODULE MONKEYFODDER
INTEGER FIELD !An I/O unit number.
CHARACTER*28 FAVOURITEFRUIT
LOGICAL NEEDSPEELING
INTEGER NUMBEROFBANANAS
CONTAINS
SUBROUTINE GETVALS(FNAME) !Reads values from some file.
CHARACTER*(*) FNAME !The file name.
LOGICAL SEEDSREMOVED !This variable is no longer wanted.
NAMELIST /FRUIT/ FAVOURITEFRUIT,NEEDSPEELING,SEEDSREMOVED, !But still appears in this list.
1 NUMBEROFBANANAS
OPEN(FIELD,FILE=FNAME,STATUS="OLD",ACTION="READ", !Hopefully, the file exists.
1 DELIM="QUOTE") !Expect quoting for CHARACTER variables.
READ (FIELD,FRUIT,ERR = 666) !Read who knows what.
666 CLOSE (FIELD) !Ignoring any misformats.
END SUBROUTINE GETVALS !A proper routine would offer error messages.
 
SUBROUTINE PUTVALS(FNAME) !Writes values to some file.
CHARACTER*(*) FNAME !The file name.
NAMELIST /FRUIT/ FAVOURITEFRUIT,NEEDSPEELING,NUMBEROFBANANAS
OPEN(FIELD,FILE=FNAME,STATUS="REPLACE",ACTION="WRITE", !Prepare a recipient file.
1 DELIM="QUOTE") !CHARACTER variables will be enquoted.
WRITE (FIELD,FRUIT) !Write however much is needed.
CLOSE (FIELD) !Finished for now.
END SUBROUTINE PUTVALS
END MODULE MONKEYFODDER
 
PROGRAM TEST !Updates the file created by an earlier version.
USE MONKEYFODDER
FIELD = 10 !This will do.
CALL GETVALS("Basket.txt") !Read the values, allowing for the previous version.
CALL PUTVALS("Basket.txt") !Save the values, as per the new version.
END</syntaxhighlight>
Whereupon the file now has
<pre>
&FRUIT
FAVOURITEFRUIT = "Banana ",
NEEDSPEELING = T,
NUMBEROFBANANAS = 48
/
</pre>
 
Naturally, a parameter file could contain data in whatever format was desired, and it might even employ a semicolon (of all things!) as a comment starter: such a file could be read and its components extracted via suitable code then written in the NAMELIST style to a scratch file and read back for the actual internalisation of values. The point of this is that a text name of a variable is associated with the actual computer variable via the NAMELIST facility, the programmer need not slog through some endless CASE statement on the names of the variables nor recognise the different data formats such as for complex numbers. This process would be reversed for output.
 
But given that the NAMELIST protocol is available without difficulty, why would a hard-core fortranner bother for a Fortran programme?
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64
 
Type ConfigData
favouriteFruit As String
needsPeeling As Boolean
seedsRemoved As Boolean
numberOfBananas As UInteger
numberOfStrawberries As UInteger
End Type
 
Sub updateConfigData(fileName As String, cData As ConfigData)
Dim fileNum As Integer = FreeFile
Open fileName For Input As #fileNum
If err > 0 Then
Print "File could not be opened"
Sleep
End
End If
Dim tempFileName As String = "temp_" + fileName
Dim fileNum2 As Integer = FreeFile
Open tempFileName For Output As #fileNum2
Dim As Boolean hadFruit, hadPeeling, hadSeeds, hadBananas, hadStrawberries '' all false by default
Dim As String ln
While Not Eof(fileNum)
Line Input #fileNum, ln
If ln = "" OrElse Left(ln, 1) = "#" Then
Print #fileNum2, ln
Continue While
End If
ln = Trim(LTrim(ln, ";"), Any !" \t")
If ln = "" Then Continue While
If UCase(Left(ln, 14)) = "FAVOURITEFRUIT" Then
If hadFruit Then Continue While
hadFruit = True
Print #fileNum2, "FAVOURITEFRUIT " + cData.favouriteFruit
ElseIf UCase(Left(ln, 12)) = "NEEDSPEELING" Then
If hadPeeling Then Continue While
hadPeeling = True
If cData.needsPeeling Then
Print #fileNum2, "NEEDSPEELING"
Else
Print #fileNum2, "; NEEDSPEELING"
End If
ElseIf UCase(Left(ln, 12)) = "SEEDSREMOVED" Then
If hadSeeds Then Continue While
hadSeeds = True
If cData.seedsRemoved Then
Print #fileNum2, "SEEDSREMOVED"
Else
Print #fileNum2, "; SEEDSREMOVED"
End If
ElseIf UCase(Left(ln, 15)) = "NUMBEROFBANANAS" Then
If hadBananas Then Continue While
hadBananas = True
Print #fileNum2, "NUMBEROFBANANAS " + Str(cData.numberOfBananas)
ElseIf UCase(Left(ln, 20)) = "NUMBEROFSTRAWBERRIES" Then
If hadStrawberries Then Continue While
hadStrawberries = True
Print #fileNum2, "NUMBEROFSTRAWBERRIES " + Str(cData.numberOfStrawBerries)
End If
Wend
 
If Not hadFruit Then
Print #fileNum2, "FAVOURITEFRUIT " + cData.favouriteFruit
End If
If Not hadPeeling Then
If cData.needsPeeling Then
Print #fileNum2, "NEEDSPEELING"
Else
Print #fileNum2, "; NEEDSPEELING"
End If
End If
If Not hadSeeds Then
If cData.seedsRemoved Then
Print #fileNum2, "SEEDSREMOVED"
Else
Print #fileNum2, "; SEEDSREMOVED"
End If
End If
If Not hadBananas Then
Print #fileNum2, "NUMBEROFBANANAS " + Str(cData.numberOfBananas)
End If
If Not hadStrawberries Then
Print #fileNum2, "NUMBEROFSTRAWBERRIES " + Str(cData.numberOfStrawBerries)
End If
 
Close #fileNum : Close #fileNum2
Kill(fileName)
Name (tempFileName fileName)
End Sub
 
Dim fileName As String = "config2.txt"
Dim cData As ConfigData
With cData
.favouriteFruit = "banana"
.needsPeeling = False
.seedsRemoved = True
.numberOfBananas = 1024
.numberOfStrawberries = 62000
End With
 
updateConfigData fileName, cData
Print
Print "Press any key to quit"
Sleep</syntaxhighlight>
 
The contents of config2.txt after updating are:
{{out}}
<pre>
# This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
; NEEDSPEELING
 
# This boolean is commented out
SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 795 ⟶ 1,838:
c.Set("NUMBEROFSTRAWBERRIES", "62000")
c.Write(os.Stdout)
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
 
Necessary imports
 
<syntaxhighlight lang="haskell">import Data.Char (toUpper)
import qualified System.IO.Strict as S</syntaxhighlight>
 
Definition of datatypes:
 
<syntaxhighlight lang="haskell">data INI = INI { entries :: [Entry] } deriving Show
 
data Entry = Comment String
| Field String String
| Flag String Bool
| EmptyLine
 
instance Show Entry where
show entry = case entry of
Comment text -> "# " ++ text
Field f v -> f ++ " " ++ v
Flag f True -> f
Flag f False -> "; " ++ f
EmptyLine -> ""
 
instance Read Entry where
readsPrec _ s = [(interprete (clean " " s), "")]
where
clean chs = dropWhile (`elem` chs)
interprete ('#' : text) = Comment text
interprete (';' : f)= flag (clean " ;" f) False
interprete entry = case words entry of
[] -> EmptyLine
[f] -> flag f True
f : v -> field f (unwords v)
field f = Field (toUpper <$> f)
flag f = Flag (toUpper <$> f)</syntaxhighlight>
 
Getting and setting fields in INI data:
 
<syntaxhighlight lang="haskell">setValue :: String -> String -> INI -> INI
setValue f v = INI . replaceOn (eqv f) (Field f v) . entries
 
setFlag :: String -> Bool -> INI -> INI
setFlag f v = INI . replaceOn (eqv f) (Flag f v) . entries
 
enable f = setFlag f True
disable f = setFlag f False
 
eqv f entry = (toUpper <$> f) == (toUpper <$> field entry)
where field (Field f _) = f
field (Flag f _) = f
field _ = ""
 
replaceOn p x lst = prev ++ x : post
where
(prev,post) = case break p lst of
(lst, []) -> (lst, [])
(lst, _:xs) -> (lst, xs)</syntaxhighlight>
 
IO stuff:
 
<syntaxhighlight lang="haskell">readIni :: String -> IO INI
readIni file = INI . map read . lines <$> S.readFile file
 
writeIni :: String -> INI -> IO ()
writeIni file = writeFile file . unlines . map show . entries
 
updateIni :: String -> (INI -> INI) -> IO ()
updateIni file f = readIni file >>= writeIni file . f
 
main = updateIni "test.ini" $
disable "NeedsPeeling" .
enable "SeedsRemoved" .
setValue "NumberOfBananas" "1024" .
setValue "NumberOfStrawberries" "62000"</syntaxhighlight>
 
=={{header|J}}==
Line 801 ⟶ 1,920:
Since the task does not specify the line end character, we assume that the last character in the file is the line end character.
 
<langsyntaxhighlight Jlang="j">require 'regex strings'
 
normalize=:3 :0
Line 836 ⟶ 1,955:
upd=. y,' ',":x
(<m) 1!:2~ normalize (,upd,{:);<@rxrplc~&(pat;upd) t
)</langsyntaxhighlight>
 
Note that, aside from the line end issue, the task is ambiguous because it specifies a set of operations rather than a file format. If the consequences of these ambiguities are troubling, you might prefer to replace normalize with normalize^:_
Line 842 ⟶ 1,961:
Example use:
 
<langsyntaxhighlight Jlang="j"> 'example.file' disable 'needspeeling'
'example.file' enable 'seedsremoved'
1024 'example.file' set 'numberofbananas'
62000 'example.file' set 'numberofstrawberries'</langsyntaxhighlight>
 
Here's how the file specified in the task description looks after these steps have been executed:
Line 880 ⟶ 1,999:
{{trans|D}}
{{works with|Java|7}}
<langsyntaxhighlight lang="java">import java.io.*;
import java.util.*;
import java.util.regex.*;
Line 1,013 ⟶ 2,132:
}
}
}</langsyntaxhighlight>
 
Input file:
Line 1,070 ⟶ 2,189:
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000</pre>
 
=={{header|Julia}}==
Designed similarly to the way multiple small functions in a Julia module for general editing of this file type might be written.
<syntaxhighlight lang="julia">function cleansyntax(line)
line = strip(line)
if line == ""
return "#=blank line=#"
elseif line[1] == '#'
return line
elseif line[1] == ';'
line = replace(line, r"^;[;]+" => ";")
else # active option
o, p = splitline(line)
line = p == nothing ? uppercase(o) : uppercase(o) * " " * p
end
join(filter(c -> isascii(c[1]) && !iscntrl(c[1]), split(line, "")), "")
end
 
"""
Run to clean up the configuration file lines prior to other function application.
"""
cleansyntax!(lines) = (for (i, li) in enumerate(lines) lines[i] = cleansyntax(li) end; lines)
 
isdisabled(line) = startswith(line, [';', '#'])
isenabled(line) = !isdisabled(line)
 
function splitline(line)
arr = split(line, r"\s+", limit=2)
if length(arr) < 2
return (arr[1], nothing)
end
return (arr[1], arr[2])
end
 
function disable!(lines, opt)
for (i, li) in enumerate(lines)
if isenabled(li) && splitline(li)[1] == uppercase(opt)
lines[i] = ";" * li
break # note: only first one found is disabled
end
end
lines
end
 
function enable!(lines, opt)
for (i, li) in enumerate(lines)
if isdisabled(li)
s = li[2:end]
if splitline(s)[1] == uppercase(opt)
lines[i] = s
break # note: only first one found is enabled
end
end
end
lines
end
 
function changeparam!(lines, opt, newparam)
for (i, li) in enumerate(lines)
if isenabled(li)
o, p = splitline(li)
if o == opt
lines[i] = o * " " * string(newparam)
break # note: only first one found is changed
end
end
end
lines
end
 
function activecfg(lines)
cfgdict = Dict()
for li in lines
if isenabled(li)
o, p = splitline(li)
cfgdict[o] = p
end
end
cfgdict
end
 
const filename = "fruit.cfg"
const cfh = open(filename)
const cfglines = cleansyntax!(readlines(cfh))
close(cfh)
 
const cfg = activecfg(cfglines)
 
disable!(cfglines, "NEEDSPEELING")
enable!(cfglines, "SEEDSREMOVED")
changeparam!(cfglines, "NUMBEROFBANANAS", 1024)
 
if !haskey(cfg, "NUMBEROFSTRAWBERRIES")
push!(cfglines, "NUMBEROFSTRAWBERRIES 62000")
end
cfg["NUMBEROFSTRAWBERRIES"] = 62000
changeparam!(cfglines, "NUMBEROFSTRAWBERRIES", 62000)
 
const cfw = open(filename, "w")
for li in cfglines
if li != ""
if li == "#=blank line=#"
li = ""
end
write(cfw, li * "\n")
end
end
</syntaxhighlight> {{output}} <pre>
Contents of the revised file:
# This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
# This is a favourite fruit
FAVOURITEFRUIT banana
# This is a boolean that should be set
;NEEDSPEELING
# This boolean is commented out
; SEEDSREMOVED
# How many bananas we have
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000
</pre>
 
=={{header|Kotlin}}==
{{trans|FreeBASIC}}
<syntaxhighlight lang="scala">// version 1.2.0
 
import java.io.File
 
class ConfigData(
val favouriteFruit: String,
val needsPeeling: Boolean,
val seedsRemoved: Boolean,
val numberOfBananas: Int,
val numberOfStrawberries: Int
)
 
fun updateConfigFile(fileName: String, cData: ConfigData) {
val inp = File(fileName)
val lines = inp.readLines()
val tempFileName = "temp_$fileName"
val out = File(tempFileName)
val pw = out.printWriter()
var hadFruit = false
var hadPeeling = false
var hadSeeds = false
var hadBananas = false
var hadStrawberries = false
 
for (line in lines) {
if (line.isEmpty() || line[0] == '#') {
pw.println(line)
continue
}
val ln = line.trimStart(';').trim(' ', '\t').toUpperCase()
if (ln.isEmpty()) continue
if (ln.take(14) == "FAVOURITEFRUIT") {
if (hadFruit) continue
hadFruit = true
pw.println("FAVOURITEFRUIT ${cData.favouriteFruit}")
}
else if (ln.take(12) == "NEEDSPEELING") {
if (hadPeeling) continue
hadPeeling = true
if (cData.needsPeeling)
pw.println("NEEDSPEELING")
else
pw.println("; NEEDSPEELING")
}
else if (ln.take(12) == "SEEDSREMOVED") {
if (hadSeeds) continue
hadSeeds = true
if (cData.seedsRemoved)
pw.println("SEEDSREMOVED")
else
pw.println("; SEEDSREMOVED")
}
else if(ln.take(15) == "NUMBEROFBANANAS") {
if (hadBananas) continue
hadBananas = true
pw.println("NUMBEROFBANANAS ${cData.numberOfBananas}")
}
else if(ln.take(20) == "NUMBEROFSTRAWBERRIES") {
if (hadStrawberries) continue
hadStrawberries = true
pw.println("NUMBEROFSTRAWBERRIES ${cData.numberOfStrawberries}")
}
}
 
if (!hadFruit) {
pw.println("FAVOURITEFRUIT ${cData.favouriteFruit}")
}
 
if (!hadPeeling) {
if (cData.needsPeeling)
pw.println("NEEDSPEELING")
else
pw.println("; NEEDSPEELING")
}
 
if (!hadSeeds) {
if (cData.seedsRemoved)
pw.println("SEEDSREMOVED")
else
pw.println("; SEEDSREMOVED")
}
 
if (!hadBananas) {
pw.println("NUMBEROFBANANAS ${cData.numberOfBananas}")
}
 
if (!hadStrawberries) {
pw.println("NUMBEROFSTRAWBERRIES ${cData.numberOfStrawberries}")
}
 
pw.close()
inp.delete()
out.renameTo(inp)
}
 
fun main(args: Array<String>) {
val fileName = "config.txt"
val cData = ConfigData("banana", false, true, 1024, 62000)
updateConfigFile(fileName, cData)
}</syntaxhighlight>
 
Contents of file 'config.txt' after updating:
<pre>
# This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
; NEEDSPEELING
 
# This boolean is commented out
SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000
</pre>
 
=={{header|Lasso}}==
Config type definition
<langsyntaxhighlight Lassolang="lasso">#!/usr/bin/lasso9
 
define config => type {
Line 1,171 ⟶ 2,557:
}
 
}</langsyntaxhighlight>
 
How to call it:
<syntaxhighlight lang="lasso">
<lang Lasso>
local(
config = config,
Line 1,189 ⟶ 2,575:
#config -> set('numberofbananas', 1024)
 
#config -> write</langsyntaxhighlight>
 
Initial config file:
Line 1,263 ⟶ 2,649:
NUMBEROFSTRAWBERRIES 62000
</pre>
 
=={{header|Nim}}==
{{trans|D}}
<syntaxhighlight lang="nim">import os, re, strutils
 
let regex = re(r"^(;*)\s*([A-Z0-9]+)\s*([A-Z0-9]*)", {reIgnoreCase, reStudy})
 
type
 
EntryType {.pure.} = enum Empty, Enabled, Disabled, Comment, Ignore
 
Entry = object
etype: EntryType
name: string
value: string
 
Config = object
entries: seq[Entry]
path: string
 
 
# Forward reference.
proc addOption*(config: var Config; name, value: string; etype = Enabled)
 
 
proc initConfig*(path: string): Config =
 
if not path.isValidFilename:
raise newException(IOError, "invalid file name.")
 
result.path = path
if not path.fileExists: return
 
for line in path.lines:
var line = line.strip
if line.len == 0:
result.entries.add Entry(etype: Empty)
elif line[0] == '#':
result.entries.add Entry(etype: Comment, value: line)
else:
line = line.replace(re"^a-zA-Z0-9\x20;")
var matches = newSeq[string](3)
if line.match(regex, matches) and matches[1].len != 0:
let etype = if matches[0].len == 0: Enabled else: Disabled
result.addOption(matches[1], matches[2], etype)
 
 
proc getOptionIndex(config: Config; name: string): int =
for i, e in config.entries:
if e.etype notin [Enabled, Disabled]: continue
if e.name == name.toUpperAscii:
return i
result = -1
 
 
proc enableOption*(config: var Config; name: string) =
let i = config.getOptionIndex(name)
if i >= 0:
config.entries[i].etype = Enabled
 
 
proc disableOption*(config: var Config; name: string) =
let i = config.getOptionIndex(name)
if i >= 0:
config.entries[i].etype = Disabled
 
 
proc setOption*(config: var Config; name, value: string) =
let i = config.getOptionIndex(name)
if i >= 0:
config.entries[i].value = value
 
 
proc addOption*(config: var Config; name, value: string; etype = Enabled) =
config.entries.add Entry(etype: etype, name: name.toUpperAscii, value: value)
 
 
proc removeOption*(config: var Config; name: string) =
let i = config.getOptionIndex(name)
if i >= 0:
config.entries[i].etype = Ignore
 
 
proc store*(config: Config) =
let f = open(config.path, fmWrite)
for e in config.entries:
case e.etype
of Empty: f.writeLine("")
of Enabled: f.writeLine(e.name, ' ', e.value)
of Disabled: f.writeLine("; ", e.name, ' ', e.value)
of Comment: f.writeLine(e.value)
of Ignore: discard
 
 
when isMainModule:
 
var cfg = initConfig("update_demo.config")
cfg.enableOption("seedsremoved")
cfg.disableOption("needspeeling")
cfg.setOption("numberofbananas", "1024")
cfg.addOption("numberofstrawberries", "62000")
cfg.store()</syntaxhighlight>
 
{{out}}
Original file:
<pre># This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
NEEDSPEELING
 
# This boolean is commented out
; SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 48</pre>
 
Modified file:
<pre># This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
; NEEDSPEELING
 
# This boolean is commented out
SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000</pre>
 
Differences:
<pre>18c18
< NEEDSPEELING
---
> ; NEEDSPEELING
21c21
< ; SEEDSREMOVED
---
> SEEDSREMOVED
24c24,25
< NUMBEROFBANANAS 48
---
> NUMBEROFBANANAS 1024
> NUMBEROFSTRAWBERRIES 62000</pre>
 
=={{header|Perl}}==
 
<langsyntaxhighlight Perllang="perl">use warnings;
use strict;
 
Line 1,363 ⟶ 2,920:
 
# How many bananas we have
NUMBEROFBANANAS 48</langsyntaxhighlight>
 
=={{header|Perl 6Phix}}==
Very basic (and contains most of the code from the read configuration file example)<br>
Note in particular there is no real attempt to distinguish between booleans and integers.
<!--<syntaxhighlight lang="phix">-->
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RCTEST.INI"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"r"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">get_text</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #004600;">GT_LF_STRIPPED</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">dini</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">and</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"#;"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">li</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">rest</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$]</span>
<span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #7060A8;">putd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #7060A8;">putd</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">),</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">deld</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"NEEDSPEELING"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">setd</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"SEEDSREMOVED"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">setd</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"NUMBEROFBANANAS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1024</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">setd</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"NUMBEROFSTRAWBERRIES"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">62000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'#'</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">';'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">li</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">rest</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$]</span>
<span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getd_index</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"; "</span><span style="color: #0000FF;">&</span><span style="color: #000000;">li</span><span style="color: #0000FF;">&</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">&</span><span style="color: #000000;">rest</span>
<span style="color: #008080;">else</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">o</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getd_by_index</span><span style="color: #0000FF;">(</span><span style="color: #000000;">k</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #004080;">string</span><span style="color: #0000FF;">(</span><span style="color: #000000;">o</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">o</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">o</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">&</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">&</span><span style="color: #000000;">o</span>
<span style="color: #7060A8;">deld</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">li</span>
<span style="color: #7060A8;">deld</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"; "</span><span style="color: #0000FF;">&</span><span style="color: #000000;">li</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">visitor</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">data</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000080;font-style:italic;">/*user_data*/</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #000000;">key</span><span style="color: #0000FF;">&</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">&</span><span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">data</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">traverse_dict</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"visitor"</span><span style="color: #0000FF;">),</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dini</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RCTEST.INI"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"w"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
Resulting RCTEST.INI file:
<pre>
# This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
Implemented as a command-line script which can make arbitrary in-place updates to such config files.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
Assuming that the script is saved as <tt>conf-update</tt> and the config file as <tt>test.cfg</tt>, the four changes required by the task description could be performed with the command:
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
<pre>conf-update --/needspeeling --seedsremoved --numberofbananas=1024 --numberofstrawberries=62000 test.cfg</pre>
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
The script:
; NEEDSPEELING
 
# This boolean is commented out
<lang perl6>#!/usr/bin/env perl6
SEEDSREMOVED
 
# How many bananas we have
my $tmpfile = tmpfile;
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000
</pre>
 
=={{header|PHP}}==
sub MAIN ($file, *%changes) {
%changes.=map({; .key.uc => .value });
my %seen;
my $out = open $tmpfile, :w;
for $file.IO.lines {
when /:s ^ ('#' .* | '') $/ {
say $out: ~$0;
}
when /:s ^ (';'+)? [(\w+) (\w+)?]? $/ {
next if !$1 or %seen{$1.uc}++;
my $new = %changes{$1.uc}:delete;
say $out: format-line $1, |( !defined($new) ?? ($2, !$0) !!
$new ~~ Bool ?? ($2, $new) !! ($new, True) );
}
default {
note "Malformed line: $_\nAborting.";
exit 1;
}
}
say $out: format-line .key, |(.value ~~ Bool ?? (Nil, .value) !! (.value, True))
for %changes;
run 'mv', $tmpfile, $file; # work-around for NYI `move $tmpfile, $file;`
}
 
<syntaxhighlight lang="php"><?php
END { unlink $tmpfile if $tmpfile.IO.e }
 
$conf = file_get_contents('update-conf-file.txt');
 
// Disable the needspeeling option (using a semicolon prefix)
sub format-line ($key, $value, $enabled) {
$conf = preg_replace('/^(needspeeling)(|\s*\S*)$/mi', '; $1', $conf);
("; " if !$enabled) ~ $key.uc ~ (" $value" if defined $value);
 
// Enable the seedsremoved option by removing the semicolon and any leading whitespace
$conf = preg_replace('/^;?\s*(seedsremoved)/mi', '$1', $conf);
 
// Change the numberofbananas parameter to 1024
$conf = preg_replace('/^(numberofbananas)(|\s*\S*)$/mi', '$1 1024', $conf);
 
// Enable (or create if it does not exist in the file) a parameter for numberofstrawberries with a value of 62000
if (preg_match('/^;?\s*(numberofstrawberries)/mi', $conf, $matches)) {
$conf = preg_replace('/^(numberofstrawberries)(|\s*\S*)$/mi', '$1 62000', $conf);
} else {
$conf .= 'NUMBEROFSTRAWBERRIES 62000' . PHP_EOL;
}
 
echo $conf;</syntaxhighlight>
sub tmpfile {
 
$*SPEC.catfile: $*SPEC.tmpdir, ("a".."z").roll(20).join
{{in}}
}</lang>
<pre># This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
NEEDSPEELING
 
# This boolean is commented out
; SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 48</pre>
 
{{out}}
<pre># This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
; NEEDSPEELING
 
# This boolean is commented out
SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000</pre>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(let Data # Read all data
(in "config"
(make
Line 1,474 ⟶ 3,151:
(out "config"
(for L Data
(prinl (glue " " (if (car L) L (cdr L)))) ) ) )</langsyntaxhighlight>
 
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
function Update-ConfigurationFile
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$false,
Position=0)]
[ValidateScript({Test-Path $_})]
[string]
$Path = ".\config.txt",
 
[Parameter(Mandatory=$false)]
[string]
$FavouriteFruit,
 
[Parameter(Mandatory=$false)]
[int]
$NumberOfBananas,
 
[Parameter(Mandatory=$false)]
[int]
$NumberOfStrawberries,
 
[Parameter(Mandatory=$false)]
[ValidateSet("On", "Off")]
[string]
$NeedsPeeling,
 
[Parameter(Mandatory=$false)]
[ValidateSet("On", "Off")]
[string]
$SeedsRemoved
)
 
[string[]]$lines = Get-Content $Path
 
Clear-Content $Path
 
if (-not ($lines | Select-String -Pattern "^\s*NumberOfStrawberries" -Quiet))
{
"", "# How many strawberries we have", "NumberOfStrawberries 0" | ForEach-Object {$lines += $_}
}
 
foreach ($line in $lines)
{
$line = $line -replace "^\s*","" ## Strip leading whitespace
 
if ($line -match "[;].*\s*") {continue} ## Strip semicolons
switch -Regex ($line)
{
"(^$)|(^#\s.*)" ## Blank line or comment
{
$line = $line
}
"^FavouriteFruit\s*.*" ## Parameter FavouriteFruit
{
if ($FavouriteFruit)
{
$line = "FAVOURITEFRUIT $FavouriteFruit"
}
}
"^NumberOfBananas\s*.*" ## Parameter NumberOfBananas
{
if ($NumberOfBananas)
{
$line = "NUMBEROFBANANAS $NumberOfBananas"
}
}
"^NumberOfStrawberries\s*.*" ## Parameter NumberOfStrawberries
{
if ($NumberOfStrawberries)
{
$line = "NUMBEROFSTRAWBERRIES $NumberOfStrawberries"
}
}
".*NeedsPeeling\s*.*" ## Parameter NeedsPeeling
{
if ($NeedsPeeling -eq "On")
{
$line = "NEEDSPEELING"
}
elseif ($NeedsPeeling -eq "Off")
{
$line = "; NEEDSPEELING"
}
}
".*SeedsRemoved\s*.*" ## Parameter SeedsRemoved
{
if ($SeedsRemoved -eq "On")
{
$line = "SEEDSREMOVED"
}
elseif ($SeedsRemoved -eq "Off")
{
$line = "; SEEDSREMOVED"
}
}
Default ## Whatever...
{
$line = $line
}
}
 
Add-Content $Path -Value $line -Force
}
}
</syntaxhighlight>
<syntaxhighlight lang="powershell">
Update-ConfigurationFile -NumberOfStrawberries 62000 -NumberOfBananas 1024 -SeedsRemoved On -NeedsPeeling Off
 
Invoke-Item -Path ".\config.txt"
</syntaxhighlight>
{{Out}}
<pre>
# This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
; NEEDSPEELING
 
# This boolean is commented out
SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 1024
 
# How many strawberries we have
NUMBEROFSTRAWBERRIES 62000
</pre>
 
=={{header|Python}}==
<langsyntaxhighlight Pythonlang="python">#!/usr/bin/env python
 
#----------------------------------------------------------------------------
Line 1,695 ⟶ 3,518:
cfg.enable_option('numberofstrawberries', 62000)
print cfg
</syntaxhighlight>
</lang>
 
Output:
Line 1,731 ⟶ 3,554:
Use the shared <tt>[[Racket/Options|options.rkt]]</tt> code.
 
<syntaxhighlight lang="racket">
<lang Racket>
#lang racket
 
Line 1,750 ⟶ 3,573:
;; numberofstrawberries with a value of 62000
(set! numberofstrawberries 62000)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
Implemented as a command-line script which can make arbitrary in-place updates to such config files.
 
Assuming that the script is saved as <tt>conf-update</tt> and the config file as <tt>test.cfg</tt>, the four changes required by the task description could be performed with the command:
 
<pre>conf-update --/needspeeling --seedsremoved --numberofbananas=1024 --numberofstrawberries=62000 test.cfg</pre>
 
The script:
 
<syntaxhighlight lang="raku" line>use File::Temp;
 
my ($tmpfile, $out) = tempfile;
 
sub MAIN ($file, *%changes) {
%changes.=map({; .key.uc => .value });
my %seen;
 
for $file.IO.lines {
when /:s ^ ('#' .* | '') $/ {
say $out: ~$0;
}
when /:s ^ (';'+)? [(\w+) (\w+)?]? $/ {
next if !$1 or %seen{$1.uc}++;
my $new = %changes{$1.uc}:delete;
say $out: format-line $1, |( !defined($new) ?? ($2, !$0) !!
$new ~~ Bool ?? ($2, $new) !! ($new, True) );
}
default {
note "Malformed line: $_\nAborting.";
exit 1;
}
}
 
say $out: format-line .key, |(.value ~~ Bool ?? (Nil, .value) !! (.value, True))
for %changes;
 
$out.close;
 
copy $tmpfile, $file;
}
 
sub format-line ($key, $value, $enabled) {
("; " if !$enabled) ~ $key.uc ~ (" $value" if defined $value);
}</syntaxhighlight>
 
=={{header|REXX}}==
Line 1,763 ⟶ 3,632:
 
Programming note: &nbsp; not all REXXes support the closing of files using the &nbsp; '''lineout''' &nbsp; BIF with a single argument.
<langsyntaxhighlight lang="rexx">/*REXX program demonstrates how to update a configuration file (four specific tasks).*/
parse arg iFID oFID . /*obtain optional arguments from the CL*/
if iFID=='' | iFID=="," then iFID= 'UPDATECF.TXT' /*Not given? Then use default.*/
Line 1,807 ⟶ 3,676:
cpy: call lineout oFID, arg(1); return /*write one line of text ───► oFID. */
dos: ''arg(1) word(arg(2) "2>nul",1); return /*execute a DOS command (quietly). */
new: z=arg(1); changed=1; return /*use new Z, indicate changed record. */</langsyntaxhighlight>
'''output''' &nbsp; when using the default input file (which has additional removable statements) and input options:
<pre>
Line 1,870 ⟶ 3,739:
 
===version 2===
<langsyntaxhighlight lang="rexx">fid='updatecf.txt'
oid='updatecf.xxx'; 'erase' oid
options=translate('FAVOURITEFRUIT NEEDSPEELING SEEDSREMOVED NUMBEROFBANANAS numberofstrawberries')
Line 1,912 ⟶ 3,781:
done.option=1
End
Return </langsyntaxhighlight>
{{out}}
same as for solution 'D'
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">require 'stringio'
 
class ConfigFile
Line 2,056 ⟶ 3,925:
 
# How many bananas we have
NUMBEROFBANANAS 48</langsyntaxhighlight>
outputs
<pre># This is a configuration file in standard configuration file format
Line 2,087 ⟶ 3,956:
=={{header|Tcl}}==
Creating this to be a general solution:
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
oo::class create Config {
variable filename contents
Line 2,162 ⟶ 4,031:
}
}
}</langsyntaxhighlight>
Applying to the task at hand (assuming a file in the current directory called <tt>sample.cfg</tt>):
<langsyntaxhighlight lang="tcl">set cfg [Config new "sample.cfg"]
$cfg disable needspeeling
$cfg enable seedsremoved
$cfg set numberofbananas 1024
$cfg set numberofstrawberries 62000
$cfg save</langsyntaxhighlight>
 
=={{header|TXR}}==
Line 2,185 ⟶ 4,054:
This works by reading the configuration into a variable, and then making multiple passes over it, using the same constructs that normally operate on files or pipes. The first 30% of the script deals with reading the configuration file and parsing each command line argument, and converting its syntax into configuration syntax, stored in <code>new_opt_line</code>. For each argument, the configuration is then scanned and filtered from <code>config</code> to <code>new_config</code>, using the same syntax which could be used to do the same job with temporary files. When the interesting variable is encountered in the config, using one of the applicable pattern matches, then the prepared configuration line is substituted for it. While this is going on, the encountered variable names (bindings for <code>var_other</code>) are also being collected into a list. This list is then later used to check via the directive <code>@(bind opt_there option)</code> to determine whether the option occurred in the configuration or not. The bind construct will not only check whether the left and right hand side are equal, but if nested lists are involved, it checks whether either side occurs in the other as a subtree. <code>option</code> binds with <code>opt_other</code> if it matches one of the option names in <code>opt_other</code>. Finally, the updated config is regurgitated.
 
<langsyntaxhighlight lang="txr">@(next :args)
@configfile
@(maybe)
Line 2,260 ⟶ 4,129:
@config
@ (end)
@(end)</langsyntaxhighlight>
 
Sample invocation:
Line 2,308 ⟶ 4,177:
{{omit from|Lilypond}}
{{omit from|Openscad}}
{{omit from|TI-83 BASIC|Does not have a filesystem.}}
 
=={{header|VBScript}}==
<syntaxhighlight lang="vb">
<lang vb>
Set objFSO = CreateObject("Scripting.FileSystemObject")
 
Line 2,368 ⟶ 4,238:
Set objFSO = Nothing
Set objParamLookup = Nothing
</syntaxhighlight>
</lang>
 
{{In}}
Line 2,400 ⟶ 4,270:
 
{{Out}}
<pre>
# This is a configuration file in standard configuration file format
#
# Lines begininning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.
 
# The first word on each non comment line is the configuration option.
# Remaining words or numbers on the line are configuration parameter
# data fields.
 
# Note that configuration option names are not case sensitive. However,
# configuration parameter data is case sensitive and the lettercase must
# be preserved.
 
# This is a favourite fruit
FAVOURITEFRUIT banana
 
# This is a boolean that should be set
; NEEDSPEELING
 
# This boolean is commented out
SEEDSREMOVED
 
# How many bananas we have
NUMBEROFBANANAS 1024
NUMBEROFSTRAWBERRIES 62000
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-ioutil}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "io" for File
import "./ioutil" for FileUtil
import "./dynamic" for Tuple
import "./str" for Str
 
var fields = ["favouriteFruit", "needsPeeling", "seedsRemoved", "numberOfBananas", "numberOfStrawberries"]
var ConfigData = Tuple.create("ConfigData", fields)
 
var updateConfigFile = Fn.new { |fileName, cData|
var lines = File.read(fileName).trimEnd().split(FileUtil.lineBreak)
var tempFileName = "temp_%(fileName)"
var out = File.create(tempFileName)
var hadFruit = false
var hadPeeling = false
var hadSeeds = false
var hadBananas = false
var hadStrawberries = false
 
for (line in lines) {
var cont = false
if (line.isEmpty || line[0] == "#") {
out.writeBytes(line + "\n")
cont = true
}
if (!cont) {
var ln = Str.upper(line.trimStart(";").trim())
if (!ln.isEmpty) {
if (ln.take(14).join() == "FAVOURITEFRUIT") {
if (!hadFruit) {
hadFruit = true
out.writeBytes("FAVOURITEFRUIT %(cData.favouriteFruit)\n")
}
} else if (ln.take(12).join() == "NEEDSPEELING") {
if (!hadPeeling) {
hadPeeling = true
if (cData.needsPeeling) {
out.writeBytes("NEEDSPEELING\n")
} else {
out.writeBytes("; NEEDSPEELING\n")
}
}
} else if (ln.take(12).join() == "SEEDSREMOVED") {
if (!hadSeeds) {
hadSeeds = true
if (cData.seedsRemoved) {
out.writeBytes("SEEDSREMOVED\n")
} else {
out.writeBytes("; SEEDSREMOVED\n")
}
}
} else if (ln.take(15).join() == "NUMBEROFBANANAS") {
if (!hadBananas) {
hadBananas = true
out.writeBytes("NUMBEROFBANANAS %(cData.numberOfBananas)\n")
}
} else if (ln.take(20).join() == "NUMBEROFSTRAWBERRIES") {
if (!hadStrawberries) {
hadStrawberries = true
out.writeBytes("NUMBEROFSTRAWBERRIES %(cData.numberOfStrawberries)\n")
}
}
}
}
}
 
if (!hadFruit) {
out.writeBytes("FAVOURITEFRUIT %(cData.favouriteFruit)\n")
}
 
if (!hadPeeling) {
if (cData.needsPeeling) {
out.writeBytes("NEEDSPEELING\n")
} else {
out.writeBytes("; NEEDSPEELING\n")
}
}
 
if (!hadSeeds) {
if (cData.seedsRemoved) {
out.writeBytes("SEEDSREMOVED\n")
} else {
out.writeBytes("; SEEDSREMOVED\n")
}
}
 
if (!hadBananas) {
out.writeBytes("NUMBEROFBANANAS %(cData.numberOfBananas)\n")
}
 
if (!hadStrawberries) {
out.writeBytes("NUMBEROFSTRAWBERRIES %(cData.numberOfStrawberries)\n")
}
 
out.close()
FileUtil.move(tempFileName, fileName, true)
}
 
var fileName = "config.txt"
var cData = ConfigData.new("banana", false, true, 1024, 62000)
updateConfigFile.call(fileName, cData)</syntaxhighlight>
 
{{out}}
<pre>
# This is a configuration file in standard configuration file format
1,480

edits