diff --git a/gapstr.go b/gapstr.go new file mode 100644 index 0000000..ea607f3 --- /dev/null +++ b/gapstr.go @@ -0,0 +1,82 @@ +package netshovel + +import ( +) + +type GapString []int + +func (g GapString) Missing() int { + var n int = 0 + for _, b := range g { + if b == -1 { + n += 1 + } + } + return n +} + +func (g GapString) Append(h GapString) GapString { + return append(g, h...) +} + +func (g GapString) Xor(mask ...int) GapString { + ret := make(GapString, len(g)) + for i := range g { + b := mask[i%len(mask)] + if g[i] == -1 || b == -1 { + ret[i] = -1 + } else { + ret[i] = g[i] ^ b + } + } + return ret +} + +func (g GapString) Bytes(gap ...byte) []byte { + ret := make([]byte, len(g)) + length := 0 + for i, v := range g { + if g[i] == -1 { + if len(gap) > 0 { + ret[length] = gap[i % len(gap)] + length += 1 + } + } else { + ret[length] = byte(v) + length += 1 + } + } + return ret[:length] +} + +func (g GapString) String(gap string) string { + return string(g.Bytes([]byte(gap)...)) +} + +func (g GapString) Apppend(other ...GapString) GapString { + var out []byte + for _, o := range other { + out = append(out, o.Bytes(0)...) + } + return GapStringOfBytes(out) +} + +func GapStringOfBytes(b []byte) GapString { + ret := make(GapString, len(b)) + for i, v := range b { + ret[i] = int(v) + } + return ret +} + +func GapStringOfString(s string) GapString { + return GapStringOfBytes([]byte(s)) +} + +func GapStringOfGap(n int) GapString { + ret := make(GapString, n) + for i := 0; i < n; i += 1 { + ret[i] = -1 + } + return ret +} \ No newline at end of file diff --git a/gapstr.py b/gapstr.py deleted file mode 100644 index 7e9a547..0000000 --- a/gapstr.py +++ /dev/null @@ -1,246 +0,0 @@ -#! /usr/bin/python - -## 2008 Massive Blowout - -"""Functions to treat a list as a byte array with gaps. - -Lists should have only byte and numeric items. - -""" - -import __init__ -import sys - -class GapString: - def __init__(self, init=None, drop='?'): - self.contents = [] - self.length = 0 - self.drop = drop - - if init: - self.append(init) - - def __len__(self): - return int(self.length) - - def loss(self): - ret = 0 - for i in self.contents: - try: - ret += i - except TypeError: - pass - return ret - - def __repr__(self): - return '' % self.length - - def append(self, i): - try: - self.length += len(i) - self.contents.append(i) - except TypeError: - self.length += i - self.contents.append(i) - - def pop(self, idx=-1): - item = self.contents.pop(idx) - try: - self.length -= item - except TypeError: - self.length -= len(item) - return GapString(item) - - - def __str__(self): - ret = [] - for i in self.contents: - try: - ret.append(self.drop * i) - except TypeError: - ret.append(i) - return ''.join(ret) - - def __iter__(self): - for i in self.contents: - try: - for c in i: - yield c - except TypeError: - for j in range(i): - yield self.drop - - def __nonzero__(self): - return self.length > 0 - - def hasgaps(self): - for i in self.contents: - try: - len(i) - except TypeError: - return True - return False - - def hexdump(self, fd=sys.stdout): - offset = 0 - - d = __init__.HexDumper(fd) - for i in self.contents: - try: - for j in xrange(i): - d.dump_drop() - except TypeError: - for c in i: - d.dump_chr(c) - d.finish() - - def extend(self, other): - self.contents += other.contents - self.length += other.length - - def __getslice__(self, start, end): - end = min(self.length, end) - start = min(self.length, start) - - new = self.__class__(drop=self.drop) - new.length = max(end - start, 0) - if new.length == 0: - new.contents = [] - return new - new.contents = self.contents[:] - - l = self.length - new.length - start - - # Trim off the beginning - while start >= 0: - i = new.contents.pop(0) - try: - start -= i - if start < 0: - new.contents.insert(0, -start) - except TypeError: - start -= len(i) - if start < 0: - new.contents.insert(0, i[start:]) - - # Trim off the end - while l >= 0: - i = new.contents.pop() - try: - l -= i - if l < 0: - new.contents.append(-l) - except TypeError: - l -= len(i) - if l < 0: - new.contents.append(i[:-l]) - - return new - - def __getitem__(self, idx): - if False: - c = self[idx:idx+1] - if c.hasgaps(): - return self.drop[0] - else: - return c.contents[0][0] - else: - l = 0 - for i in self.contents: - try: - l += len(i) - except TypeError: - l += i - if l > idx: - offs = idx - l - try: - return i[offs] - except: - return self.drop[0] - raise IndexError('Out of bounds') - - def __add__(self, other): - if isinstance(other, str): - self.append(other) - else: - new = self.__class__(drop=self.drop) - new.extend(self) - new.extend(other) - return new - - def __xor__(self, mask): - try: - mask = [ord(c) for c in mask] - except TypeError: - pass - try: - masklen = len(mask) - except TypeError: - masklen = 1 - mask = [mask] - - new = self.__class__(drop=self.drop) - for i in self.contents: - try: - r = [] - offset = len(new) % masklen - for c in i: - o = ord(c) - r.append(chr(o ^ mask[offset])) - offset = (offset + 1) % masklen - new.append(''.join(r)) - except TypeError: - new.append(i) - return new - - def index(self, needle): - pos = 0 - for i in self.contents: - try: - return pos + i.index(needle) - except AttributeError: - pos += i - except ValueError: - pos += len(i) - raise ValueError('substring not found') - - def split(self, pivot=' ', times=None): - ret = [] - cur = self - while (not times) or (len(ret) < times): - try: - pos = cur.index(pivot) - except ValueError: - break - ret.append(cur[:pos]) - cur = cur[pos+len(pivot):] - ret.append(cur) - return ret - - def startswith(self, what): - return (what == str(self[:len(what)])) - - def endswith(self, what): - return (what == str(self[-len(what):])) - - -if __name__ == '__main__': - gs = GapString() - gs.append('hi') - assert str(gs) == 'hi' - assert str(gs[:40]) == 'hi' - gs.append(3) - assert str(gs) == 'hi???' - assert str(gs[:40]) == 'hi???' - assert str(gs[:3]) == 'hi?' - assert str(gs[-4:]) == 'i???' - assert str(gs + gs) == 'hi???hi???' - assert str(gs ^ 1) == 'ih???' - - gs = GapString() - gs.append('123456789A') - assert str(gs[:4]) == '1234' - assert len(gs[:4]) == 4 - assert len(gs[6:]) == 4 - assert str(gs[:0]) == '' - diff --git a/gapstr_test.go b/gapstr_test.go new file mode 100644 index 0000000..1f340f1 --- /dev/null +++ b/gapstr_test.go @@ -0,0 +1,47 @@ +package netshovel + +import ( + "testing" +) + +func TestAll(t *testing.T) { + str := "Hello World" + g := GapStringOfString(str) + var h GapString + + if g.String("") != str { + t.Error("String conversion") + } + if g.String("") != string(g.Bytes()) { + t.Error("String() != string(Bytes())") + } + + if g.Xor(0x20).String("") != "hELLO\x00wORLD" { + t.Error("xor failed") + } + + if g.Append(GapStringOfString("!")).String("") != "Hello World!" { + t.Error("Appending") + } + + mt := GapStringOfGap(10) + if mt.Missing() != 10 { + t.Error("Missing count") + } + if mt.Missing() != len(mt) { + t.Error("All gaps len != missing") + } + + h = g.Append(mt).Append(GapStringOfString("!!!!")) + if len(h) != len(g) + len(mt) + 4 { + t.Error("Append length") + } + + if h.String("DROP") != "Hello WorldPDROPDROPD!!!!" { + t.Error("Gap fill with DROP") + } + + if h.String("") != "Hello World!!!!" { + t.Error("Gap fill with empty string") + } +}