Many systems offer the ability to open a file for writing, such that any data written will be appended to the end of the file. Further, the file operations will always adjust the position pointer to guarantee the end of the file, even in a multitasking environment.

This feature is most useful in the case of log files, where many jobs may be appending to the log file at the same time, or where care must be taken to avoid concurrently overwriting the same record from another job.



Task

Given a two record sample for a mythical "passwd" file:

 Write these records out in the typical system format.
 Ideally these records will have named fields of various types.
 Close the file, then reopen the file for append.
 Append a new record to the file and close the file again.
 Take appropriate care to avoid concurrently overwrites from another job.
 Open the file and demonstrate the new record has indeed written to the end.

 Source record field types and contents.


account
password
UID
GID
fullname,office,extension,homephone,email
directory
shell


string
string
int
int
struct(string,string,string,string,string)
string
string


jsmith
x
1001
1000
Joe Smith,Room 1007,(234)555-8917,(234)555-0077,jsmith@rosettacode.org
/home/jsmith
/bin/bash


jdoe
x
1002
1000
Jane Doe,Room 1004,(234)555-8914,(234)555-0044,jdoe@rosettacode.org
/home/jdoe
/bin/bash


 Record to be appended.


account
password
UID
GID
fullname,office,extension,homephone,email
directory
shell


string
string
int
int
struct(string,string,string,string,string)
string
string


xyz
x
1003
1000
X Yz,Room 1003,(234)555-8913,(234)555-0033,xyz@rosettacode.org
/home/xyz
/bin/bash

Resulting file format: should mimic Linux's /etc/passwd file format with particular attention to the "," separator used in the GECOS field. But if the specific language has a particular or unique format of storing records in text file, then this format should be named and demonstrated with an additional example.

Expected output:

Appended record: xyz:x:1003:1000:X Yz,Room 1003,(234)555-8913,(234)555-0033,xyz@rosettacode.org:/home/xyz:/bin/bash

Finally: Provide a summary of the language's "append record" capabilities in a table. eg.


 Append Capabilities.


 Data Representation

 IO
Library

 Append
Possible

 Automatic
Append

 Multi-tasking
Safe


 In core 
 On disk


 C struct 
 CSV text file 
 glibc/stdio 
 ☑ 
 ☑ 
 ☑ (Not all, eg NFS)

Alternatively: If the language's appends can not guarantee its writes will always append, then note this restriction in the table. If possible, provide an actual code example (possibly using file/record locking) to guarantee correct concurrent appends.




Module TestThis {
	Class passwd {
		account$, password$
		UID, GID
		group GECOS {
			fullname$,office$,extension$,homephone$,email$
			function Line$() {
				=format$("{0},{1} {2},{3},{4}", .fullname$,.office$,.extension$,.homephone$,.email$)
			}
		}
		directory$, shell$
		Function Line$() {
			=format$("{0}:{1}:{2}:{3}:{4}:{5}:{6}",.account$,.password$, .UID, .GID, .GECOS.Line$(), .directory$, .shell$)
		}
	class:
		Module passwd {
			if match("SSNNSSSSSSS") then
				Read .account$, .password$
				Read .UID, .GID
				For .GECOS {
					Read .fullname$,.office$,.extension$,.homephone$,.email$
				}
				Read .directory$, .shell$
			Else.If Match("S") then
				Dim a$(), b$()
				a$()=Piece$(letter$, ":")
				.account$<=a$(0)
				.password$<=a$(1)
				.UID<=Val(a$(2))
				.GID<=Val(a$(3))
				For .GECOS {
					b$()=Piece$(a$(4), ",")
					.fullname$<=b$(0)
					.office$<=Piece$(b$(1), " ")(0)
					.extension$<=Piece$(b$(1), " ")(1)
					.homephone$<=b$(2)
					.email$<=b$(3)
				}
				.directory$<=a$(5)
				.shell$<=a$(6)
			End if
		}
	}
	Flush
	Data PASSWD("jsmith", "x", 1001, 1000, "Joe Smith", "Room", "1007","(234)555-8917","(234)555-0077","jsmith@rosettacode.org","/home/jsmith","/bin/bash")
	Data PASSWD("jdoe:x:1002:1000:Jane Doe,Room 1004,(234)555-8914,(234)555-0044:jdoe@rosettacode.org:/home/jdoe")
	\\ we have to make the file if not exist before we use APPEND
	if not exist("passwd") then
		Open "passwd" for Output as #F
		Close #F
	end if
	Open "passwd" for wide append as #F
	While not empty
		read A
		Print #F, A.Line$()
	End While
	Close #F
	Ret=PASSWD("xyz","x",1003,1000,"X Yz", "Room", "1003", "(234)555-8913", "(234)555-0033", "xyz@rosettacode.org","/home/xyz","/bin/bash")
	Repeat
		Try ok {
			Open "passwd" for wide append exclusive as F
			Print #F, Ret.Line$()
			close #F
		}
 
	Until  Not (Error or Not ok)
	I=1
	Document Ret$
	Open "passwd" for wide input as #F
	While not Eof(#F)
		Line Input #F, record$
		Ret$=Format$("{0}|{1}",Str$(I,"0000"),Record$)+{
		}
		I++
	End While
	Close #F
	ClipBoard Ret$
	Report Ret$
}
TestThis
 