sys

A set of unix utils in hare!
Log | Files | Refs | README

file.ha (4417B)


      1 use fmt;
      2 
      3 use util;
      4 
      5 export type lines = struct {
      6 	next: nullable *lines,
      7 	prev: nullable *lines,
      8 	s: str
      9 };
     10 
     11 // returns a new allocated line, the caller should free this value
     12 export fn newline(s: str) *lines = alloc(lines{next = null, prev = null, s = s})!;
     13 @test fn newline() void = assert(newline("hello world").s == "hello world");
     14 
     15 // returns the last line of [[lines]]
     16 export fn getend(ls: *lines) *lines = {
     17 	let current = ls;
     18 	for (let i = 0; true; i += 1) 
     19 		current = match (current.next) {
     20 		case let ls: *lines => yield ls;
     21 		case null => return current;
     22 		};
     23 };
     24 @test fn getend() void = {
     25 	let line = newline("hello world");
     26 	assert(getend(line) == line);
     27 };
     28 @test fn getend() void = {
     29 	let line = newline("hello world");
     30 	line.next = newline("bye world");
     31 	assert(getend(line) == line.next);
     32 };
     33 
     34 // inserts [[l]] at [[where]] into [[ls]], and returns a new value for [[ls]],
     35 // the caller should override [[ls]], with the return value
     36 export fn insertline(ls: *lines, l: *lines, where: size) *lines = {
     37 	if (where == 0) {
     38 		l.next = ls;	//todo, make this work for multiple lines in l
     39 		ls.prev = l;
     40 		return l;
     41 	};
     42 
     43 	let current = getline(ls, where - 1);
     44 
     45 	let tmp = match (current.next) {
     46 	case let ls: *lines => yield ls;
     47 	case null =>
     48 		current.next = l;
     49 		l.prev = current;
     50 		return ls;
     51 	};
     52 	let end = getend(l);
     53 
     54 	current.next = l;
     55 	l.prev = current;
     56 	end.next = tmp;
     57 	tmp.prev = end;
     58 
     59 	return ls;
     60 };
     61 @test fn insertline() void = {
     62 	let ls = newline("file");
     63 	let line = newline("hello world");
     64 	ls = insertline(ls, line, 1);
     65 	assert((ls.next as *lines).s == "hello world");
     66 	assert(ls.s == "file");
     67 };
     68 @test fn insertline() void = {
     69 	let ls = newline("file");
     70 	let line = newline("hello world");
     71 	ls = insertline(ls, line, 0);
     72 	assert(ls.s == "hello world");
     73 	assert((ls.next as *lines).s == "file");
     74 };
     75 
     76 // gets the [[where]]'th line from [[ls]]
     77 export fn getline(ls: *lines, where: size) *lines = {
     78 	let current = ls;
     79 	for (let i = 0z; i < where; i += 1) 
     80 		current = match (current.next) {
     81 		case let ls: *lines => yield ls;
     82 		case null => abort();
     83 		};
     84 
     85 	return current;
     86 };
     87 @test fn getline() void = {
     88 	let ls = newline("file");
     89 	let line = newline("hello world");
     90 	ls = insertline(ls, line, 1);
     91 	assert(getline(ls, 0).s == "file");
     92 };
     93 @test fn getline() void = {
     94 	let ls = newline("file");
     95 	let line = newline("hello world");
     96 	ls = insertline(ls, line, 1);
     97 	assert(getline(ls, 1).s == "hello world");
     98 };
     99 @test fn getline() void = {
    100 	let ls = newline("file");
    101 	let line = newline("hello world");
    102 	ls = insertline(ls, line, 0);
    103 	assert(getline(ls, 0).s == "hello world");
    104 };
    105 @test fn getline() void = {
    106 	let ls = newline("file");
    107 	let line = newline("hello world");
    108 	ls = insertline(ls, line, 0);
    109 	assert(getline(ls, 1).s == "file");
    110 };
    111 
    112 // counts how many lines are in [[ls]]
    113 export fn countlines(ls: *lines) size = {
    114 	let current = ls;
    115 	for (let i = 0z; true; i += 1) 
    116 		current = match (current.next) {
    117 		case let ls: *lines => yield ls;
    118 		case null => return i + 1;
    119 		};
    120 };
    121 @test fn countlines() void = {
    122 	let ls = newline("file");
    123 	let line = newline("hello world");
    124 	ls = insertline(ls, line, 0);
    125 	assert(countlines(ls) == 2);
    126 };
    127 
    128 // deletes line at [[where]] from [[ls]], the caller should override [[ls]] with
    129 // the return value
    130 export fn deleteline(ls: *lines, where: size) *lines = {
    131 	if (where == 0) return ls.next as *lines;
    132 
    133 	let current = getline(ls, where);
    134 
    135 	(current.prev as *lines).next = current.next;
    136 	if (where != countlines(ls)) 
    137 		(current.next as *lines).prev = current.prev;
    138 
    139 	free(current);
    140 	return ls;
    141 };
    142 @test fn deleteline() void = {
    143 	let ls = newline("file");
    144 	let line = newline("hello world");
    145 	let line2 = newline("fuck");
    146 	ls = insertline(ls, line, 1);
    147 	ls = insertline(ls, line2, 2);
    148 	ls = deleteline(ls, 0);
    149 	assert(ls.s == "hello world");
    150 	assert((ls.next as *lines).s == "fuck");
    151 };
    152 @test fn deleteline() void = {
    153 	let ls = newline("file");
    154 	let line = newline("hello world");
    155 	let line2 = newline("fuck");
    156 	ls = insertline(ls, line, 1);
    157 	ls = insertline(ls, line2, 2);
    158 	ls = deleteline(ls, 1);
    159 	assert(ls.s == "file");
    160 	assert((ls.next as *lines).s == "fuck");
    161 };
    162 @test fn deleteline() void = {
    163 	let ls = newline("file");
    164 	let line = newline("hello world");
    165 	let line2 = newline("fuck");
    166 	ls = insertline(ls, line, 1);
    167 	ls = insertline(ls, line2, 2);
    168 	ls = deleteline(ls, 2);
    169 	assert(ls.s == "file");
    170 	assert((ls.next as *lines).s == "hello world");
    171 };