implementation module UtilNewlinesFile import StdFile, StdInt, StdChar, StdString, StdArray, StdBool, StdClass, StdTuple, StdMisc // simple sequence operator (:-) infixl 0 (:-) f a :== a f :: NewlineConvention = NewlineConventionNone | NewlineConventionMac | NewlineConventionUnix | NewlineConventionDos HostNativeNewlineConvention :== NewlineConventionDos instance == NewlineConvention where (==) NewlineConventionNone NewlineConventionNone = True (==) NewlineConventionMac NewlineConventionMac = True (==) NewlineConventionUnix NewlineConventionUnix = True (==) NewlineConventionDos NewlineConventionDos = True (==) _ _ = False instance toString NewlineConvention where toString NewlineConventionNone = "" toString NewlineConventionMac = "\xd" toString NewlineConventionUnix = "\xa" toString NewlineConventionDos = "\xd\xa" // slice that returns a unique array (%.) infixl 9 :: !.{#Char} !(!Int,!Int) -> .{#Char} (%.) string indices = code { .inline %. .d 1 2 ii jsr sliceAC .o 1 0 .end } // this should be added to the Clean rts, so that the string doesn't have to be copied downSize :: Int *{#Char} -> *{#Char} downSize newSize string = string %. (0, newSize-1) convertLine :: !*{#Char} -> (NewlineConvention, *{#Char}) convertLine line #! maxIndex = size line - 1 | maxIndex >= 0 #! lastChar = line.[maxIndex] | lastChar == '\xa' | maxIndex >= 1 #! lastButOneChar = line.[maxIndex-1] | lastButOneChar == '\xd' = (NewlineConventionDos, {downSize maxIndex line & [maxIndex-1] = '\n'}) // otherwise = (NewlineConventionUnix, {line & [maxIndex] = '\n'}) // otherwise = (NewlineConventionUnix, {line & [maxIndex] = '\n'}) | lastChar == '\xd' = (NewlineConventionMac, {line & [maxIndex] = '\n'}) // otherwise = (NewlineConventionNone, line) // otherwise = (NewlineConventionNone, line) readAnyLine :: !*File -> (NewlineConvention, !.{#Char}, !*File) readAnyLine file # (line, file) = freadline file (convention, line) = convertLine line = (convention, line, file) readLine file :== (line, file`) where (_, line, file`) = readAnyLine file writeAnyLine :: !{#Char} !{#Char} !*File -> *File writeAnyLine line newlineString file # maxIndex = size line - 1 lastChar = line.[maxIndex] | maxIndex >= 0 && lastChar == '\n' = file :- fwrites (line %. (0, maxIndex-1)) :- fwrites newlineString // otherwise = file :- fwrites line //-- readConvLines :: !*File -> (NewlineConvention,[String],*File) readConvLines file # (conv,line,more,file) = readAnyLine` file (eof, file) = fend file | eof | more // last line ends in a newline? = (conv,[line,""], file) = (conv,[line], file) # (_,lines,file) = readConvLines file = (conv,[line:lines], file) //readAnyLine` :: !*File -> (NewlineConvention, !.{#Char}, !*File) readAnyLine` file # (line, file) = freadline file #! maxIndex = size line - 1 | maxIndex >= 0 # lastChar = line.[maxIndex] | lastChar == '\xa' | maxIndex >= 1 # lastButOneChar = line.[maxIndex-1] | lastButOneChar == '\xd' = (NewlineConventionDos, downSize (dec maxIndex) line, True, file) = (NewlineConventionUnix, downSize maxIndex line, True, file) = (NewlineConventionUnix, downSize maxIndex line, True, file) | lastChar == '\xd' = (NewlineConventionMac, downSize maxIndex line, True, file) = (NewlineConventionNone, line, False, file) = (NewlineConventionNone, line, False, file)