UtilNewlinesFile.icl 3.43 KB
Newer Older
Jurrien Stutterheim's avatar
Jurrien Stutterheim committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
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	:==	NewlineConventionUnix

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)