From: Jean Privat Date: Tue, 15 Sep 2015 19:18:41 +0000 (-0400) Subject: Merge: vim plugin: intro NitExecute to interpret the current file with `nit` X-Git-Tag: v0.7.8~20 X-Git-Url: http://nitlanguage.org?hp=a1561a96f298ceef324529f34b11686893861844 Merge: vim plugin: intro NitExecute to interpret the current file with `nit` Adds the `:NitExecute` command (or `:NitE` as shortcut) to interpret the current file with `nit`. This is very similar to the manual `:!nit %` but it saves modified buffers to a temp file to execute the content of the current buffer and not the last saved content. This is completely up to you but I recommend mapping this to `ctrl-f` to fit between `ctrl-d -> Nitdoc` and `ctrl-g -> NitGitGrep`. Here are the required lines for `.vimrc`: ~~~ " Map the Nitdoc command to Ctrl-D map :Nitdoc " Map the NitGitGrep function to Ctrl-G map :call NitGitGrep() " Map the NitExecute function to Ctrl-F <------- The new one map :NitExecute ~~~ Pull-Request: #1717 Reviewed-by: Jean Privat --- diff --git a/contrib/crazy_moles/Makefile b/contrib/crazy_moles/Makefile index 3fc90f7..049e851 100644 --- a/contrib/crazy_moles/Makefile +++ b/contrib/crazy_moles/Makefile @@ -4,11 +4,14 @@ bin/moles: $(shell ../../bin/nitls -M src/moles_linux.nit) assets/images/drawing mkdir -p bin ../../bin/nitc -o bin/moles src/moles_linux.nit +android: bin/moles.apk bin/moles.apk: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png mkdir -p bin ../../bin/nitc -o bin/moles.apk src/moles_android.nit -android: bin/moles.apk +android-release: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png + mkdir -p bin + ../../bin/nitc -o bin/moles.apk src/moles_android.nit --release ../inkscape_tools/bin/svg_to_icons: $(MAKE) -C ../inkscape_tools diff --git a/contrib/friendz/Makefile b/contrib/friendz/Makefile index f236a1d..0cedb4c 100644 --- a/contrib/friendz/Makefile +++ b/contrib/friendz/Makefile @@ -4,11 +4,18 @@ linux: mkdir -p bin ../../bin/nitc -o bin/friendz src/friendz_linux.nit -android: - mkdir -p bin res - ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/ +android: res/drawable-hdpi/icon.png + mkdir -p bin ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit +android-release: res/drawable-hdpi/icon.png + mkdir -p bin + ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit --release + +res/drawable-hdpi/icon.png: art/icon.svg + mkdir -p res + ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/ + doc: mkdir -p doc ../../bin/nitdoc -d doc/ src/friendz.nit src/friendz_linux.nit diff --git a/contrib/mnit_test/Makefile b/contrib/mnit_test/Makefile index 73ed663..a198c27 100644 --- a/contrib/mnit_test/Makefile +++ b/contrib/mnit_test/Makefile @@ -9,5 +9,10 @@ android: ../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global ../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global +android-release: + mkdir -p bin + ../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global --release + ../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global --release + clean: rm -rf bin diff --git a/contrib/opportunity/src/opportunity_controller.nit b/contrib/opportunity/src/opportunity_controller.nit index 868dd9e..26a4ef6 100644 --- a/contrib/opportunity/src/opportunity_controller.nit +++ b/contrib/opportunity/src/opportunity_controller.nit @@ -16,7 +16,6 @@ module opportunity_controller import nitcorn -import sha1 import templates import opportunity_model diff --git a/contrib/opportunity/src/opportunity_model.nit b/contrib/opportunity/src/opportunity_model.nit index ef7654d..cc72f23 100644 --- a/contrib/opportunity/src/opportunity_model.nit +++ b/contrib/opportunity/src/opportunity_model.nit @@ -247,7 +247,7 @@ class Meetup redef fun commit(db) do if id == "" then var time = get_time - var tmpid = (name + date + place + time.to_s).sha1_to_s + var tmpid = (name + date + place + time.to_s).sha1.hexdigest if not db.execute("INSERT INTO meetups (id, name, date, place, answer_mode) VALUES({tmpid.to_sql_string}, {name.html_escape.to_sql_string}, {date.html_escape.to_sql_string}, {place.html_escape.to_sql_string}, {answer_mode});") then print "Error recording entry Meetup {self}" print db.error or else "Null error" diff --git a/contrib/tinks/Makefile b/contrib/tinks/Makefile index b22453a..ee13360 100644 --- a/contrib/tinks/Makefile +++ b/contrib/tinks/Makefile @@ -32,9 +32,12 @@ src/server/server_serialize.nit: $(shell ../../bin/nitls -M src/server/dedicated ../../bin/nitserial -o src/server/server_serialize.nit src/server/dedicated.nit # Android +android: bin/tinks.apk bin/tinks.apk: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit) - ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --compile-dir nit_compile - adb install -r bin/tinks.apk + ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit + +android-release: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit) + ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --release res/drawable-ldpi/icon.png: art/icon.svg ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/ diff --git a/contrib/tinks/art/icon.svg b/contrib/tinks/art/icon.svg index 20a590d..32229e4 100644 --- a/contrib/tinks/art/icon.svg +++ b/contrib/tinks/art/icon.svg @@ -241,8 +241,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.979899" - inkscape:cx="107.98668" - inkscape:cy="65.759563" + inkscape:cx="357.89925" + inkscape:cy="19.247995" inkscape:document-units="px" inkscape:current-layer="0splash" showgrid="false" @@ -305,9 +305,10 @@ transform="matrix(0.9571749,0,0,0.9571749,14.241487,126.08446)"> + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccccccccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccccccccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccc" /> TINKS! + TINKS! diff --git a/examples/calculator/art/icon.svg b/examples/calculator/art/icon.svg index ccd533c..618dc3d 100644 --- a/examples/calculator/art/icon.svg +++ b/examples/calculator/art/icon.svg @@ -24,9 +24,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.9899495" - inkscape:cx="58.64005" - inkscape:cy="380.00465" + inkscape:zoom="1.4" + inkscape:cx="160.56125" + inkscape:cy="282.40083" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -97,17 +97,14 @@ width="211.42856" id="rect2995" style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" /> - + + id="text2997"> + + - = + id="text3013"> + + diff --git a/examples/mnit_ballz/Makefile b/examples/mnit_ballz/Makefile index 4120b52..b9a0dfc 100644 --- a/examples/mnit_ballz/Makefile +++ b/examples/mnit_ballz/Makefile @@ -7,6 +7,10 @@ android: icon mkdir -p bin ../../bin/nitc -o bin/ballz.apk src/ballz_android.nit +android-release: icon + mkdir -p bin + ../../bin/nitc -o bin/ballz.apk src/ballz_android.nit --release + linux: mkdir -p bin ../../bin/nitc -o bin/ballz src/ballz_linux.nit diff --git a/examples/mnit_dino/Makefile b/examples/mnit_dino/Makefile index 42364bf..14faa98 100644 --- a/examples/mnit_dino/Makefile +++ b/examples/mnit_dino/Makefile @@ -8,6 +8,10 @@ android: android-icons mkdir -p bin ../../bin/nitc -o bin/dino.apk src/dino_android.nit +android-release: android-icons + mkdir -p bin + ../../bin/nitc -o bin/dino.apk src/dino_android.nit --release + ../../contrib/inkscape_tools/bin/svg_to_icons: $(MAKE) -C ../../contrib/inkscape_tools diff --git a/examples/rosettacode/sha_1.nit b/examples/rosettacode/sha_1.nit index 2eaf471..8776d48 100644 --- a/examples/rosettacode/sha_1.nit +++ b/examples/rosettacode/sha_1.nit @@ -9,4 +9,4 @@ module sha_1 import sha1 -print "Rosetta Code".sha1_to_s +print "Rosetta Code".sha1.hexdigest diff --git a/examples/shoot/Makefile b/examples/shoot/Makefile index 5e564d7..a42ffde 100644 --- a/examples/shoot/Makefile +++ b/examples/shoot/Makefile @@ -8,6 +8,10 @@ android: mkdir -p bin ../../bin/nitc -o bin/shoot.apk src/shoot_android.nit +android-release: + mkdir -p bin + ../../bin/nitc -o bin/shoot.apk src/shoot_android.nit --release + null: mkdir -p bin ../../bin/nitc -o bin/shoot_null src/shoot_null.nit diff --git a/lib/base64.nit b/lib/base64.nit index 5f1c920..4eae395 100644 --- a/lib/base64.nit +++ b/lib/base64.nit @@ -17,88 +17,76 @@ # Offers the base 64 encoding and decoding algorithms module base64 -redef class String - +redef class NativeString # Alphabet used by the base64 algorithm - private fun base64_chars : String + private fun base64_chars : SequenceRead[Byte] do - return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".bytes end + + # Reversed alphabet for base64 private fun inverted_base64_chars : HashMap[Byte, Byte] do var inv_base64_chars = new HashMap[Byte, Byte] - for k in [0..base64_chars.bytelen[ do - inv_base64_chars[base64_chars.bytes[k]] = k.to_b + var l = base64_chars.length + for k in [0 .. l[ do + inv_base64_chars[base64_chars[k]] = k.to_b end return inv_base64_chars end - # Encodes the receiver string to base64. + # Encodes `self` to base64. + # # By default, uses "=" for padding. - fun encode_base64 : String do return encode_base64_custom_padding('='.ascii.to_b) - - # Encodes the receiver string to base64 using a custom padding character. # - # If using the default padding character `=`, see `encode_base64`. - fun encode_base64_custom_padding(padding : Byte) : String - do - var base64_bytes = once base64_chars.bytes - var length = bytelen - + # assert "string".encode_base64 == "c3RyaW5n" + private fun encode_base64(length: Int, padding: nullable Byte): Bytes do + var base64_bytes = once base64_chars + if padding == null then padding = '='.ascii.to_b var steps = length / 3 var bytes_in_last_step = length % 3 var result_length = steps * 4 if bytes_in_last_step > 0 then result_length += 4 - var result = new NativeString(result_length + 1) - var bytes = self.bytes - result[result_length] = 0u8 - - var mask_6bit = 0b0011_1111 + var result = new Bytes.with_capacity(result_length) + var in_off = 0 for s in [0 .. steps[ do - var e = 0 - for ss in [0 .. 3[ do - e += bytes[s * 3 + ss].to_i << ((2 - ss) * 8) - end - for ss in [0..4[ do - result[s * 4 + 3 - ss] = base64_bytes[(e >> (ss * 6)) & mask_6bit] - end + var ind = ((self[in_off] & 0b1111_1100u8) >> 2).to_i + result.add base64_bytes[ind] + ind = ((self[in_off] & 0b0000_0011u8) << 4).to_i | ((self[in_off + 1] & 0b1111_0000u8) >> 4).to_i + result.add base64_bytes[ind] + ind = ((self[in_off + 1] & 0b0000_1111u8) << 2).to_i | ((self[in_off + 2] & 0b1100_0000u8) >> 6).to_i + result.add base64_bytes[ind] + ind = (self[in_off + 2] & 0b0011_1111u8).to_i + result.add base64_bytes[ind] + in_off += 3 end - - var out_off = result_length - 4 - var in_off = length - bytes_in_last_step if bytes_in_last_step == 1 then - result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i] - result[out_off + 1] = base64_bytes[((bytes[in_off] & 0b0000_0011u8) << 4).to_i] - out_off += 2 + result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i] + result.add base64_bytes[((self[in_off] & 0b0000_0011u8) << 4).to_i] else if bytes_in_last_step == 2 then - result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i] - result[out_off + 1] = base64_bytes[(((bytes[in_off] & 0b0000_0011u8) << 4) | ((bytes[in_off + 1] & 0b1111_0000u8) >> 4)).to_i] - result[out_off + 2] = base64_bytes[((bytes[in_off + 1] & 0b0000_1111u8) << 2).to_i] - out_off += 3 - end - if bytes_in_last_step > 0 then - for i in [out_off .. result_length[ do result[i] = padding + result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i] + result.add base64_bytes[(((self[in_off] & 0b0000_0011u8) << 4) | ((self[in_off + 1] & 0b1111_0000u8) >> 4)).to_i] + result.add base64_bytes[((self[in_off + 1] & 0b0000_1111u8) << 2).to_i] end + var rempad = if bytes_in_last_step > 0 then 3 - bytes_in_last_step else 0 + for i in [0 .. rempad[ do result.add padding - return result.to_s_with_length(result_length) + return result end - # Decodes the receiver string from base64. - # By default, uses "=" for padding. - fun decode_base64 : String do return decode_base64_custom_padding('='.ascii.to_b) - - # Decodes the receiver string to base64 using a custom padding character. + # Decodes `self` from base64 # - # If using the default padding character `=`, see `decode_base64`. - fun decode_base64_custom_padding(padding : Byte) : String - do + # assert "c3RyaW5n".decode_base64 == "string" + # + # REQUIRE: `length % 4 == 0` + private fun decode_base64(length: Int, padding: nullable Byte): Bytes do + if padding == null then padding = '='.ascii.to_b var inv = once inverted_base64_chars - var length = bytelen - if length == 0 then return "" + if length == 0 then return new Bytes.empty assert length % 4 == 0 else print "base64::decode_base64 only supports strings of length multiple of 4" - var bytes = self.bytes + var bytes = self var steps = length / 4 var result_length = steps * 3 @@ -113,17 +101,16 @@ redef class String if padding_len == 1 then result_length -= 1 if padding_len == 2 then result_length -= 2 - var result = new NativeString(result_length + 1) - result[result_length] = 0u8 + var result = new Bytes.with_capacity(result_length + 1) for s in [0 .. steps[ do var c0 = inv[bytes[s * 4]] var c1 = inv[bytes[s * 4 + 1]] var c2 = inv[bytes[s * 4 + 2]] var c3 = inv[bytes[s * 4 + 3]] - result[s * 3] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4) - result[s * 3 + 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2) - result[s * 3 + 2] = ((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8) + result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)) + result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)) + result.add (((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8)) end var last_start = steps * 4 @@ -131,14 +118,52 @@ redef class String var c0 = inv[bytes[last_start]] var c1 = inv[bytes[last_start + 1]] var c2 = inv[bytes[last_start + 2]] - result[result_length - 2] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4) - result[result_length - 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2) + result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)) + result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)) else if padding_len == 2 then var c0 = inv[bytes[last_start]] var c1 = inv[bytes[last_start + 1]] - result[result_length - 1] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4) + result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)) end - return result.to_s_with_length(result_length) + return result + end +end + +redef class Bytes + + # Encodes the receiver string to base64 using a custom padding character. + # + # If using the default padding character `=`, see `encode_base64`. + fun encode_base64(padding: nullable Byte): Bytes + do + return items.encode_base64(length, padding) + end + + # Decodes the receiver string to base64 using a custom padding character. + # + # Default padding character `=` + fun decode_base64(padding : nullable Byte) : Bytes + do + return items.decode_base64(length, padding) + end +end + +redef class String + + # Encodes the receiver string to base64 using a custom padding character. + # + # If using the default padding character `=`, see `encode_base64`. + fun encode_base64(padding: nullable Byte): String + do + return to_cstring.encode_base64(bytelen, padding).to_s + end + + # Decodes the receiver string to base64 using a custom padding character. + # + # Default padding character `=` + fun decode_base64(padding : nullable Byte) : String + do + return to_cstring.decode_base64(bytelen, padding).to_s end end diff --git a/lib/core/bytes.nit b/lib/core/bytes.nit index 59c4c5f..356f386 100644 --- a/lib/core/bytes.nit +++ b/lib/core/bytes.nit @@ -19,6 +19,61 @@ import kernel import collection::array intrude import text::flat +redef class Byte + # Write self as a string into `ns` at position `pos` + private fun add_digest_at(ns: NativeString, pos: Int) do + var tmp = (0xF0u8 & self) >> 4 + ns[pos] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8 + tmp = 0x0Fu8 & self + ns[pos + 1] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8 + end + + # Is `self` a valid hexadecimal digit (in ASCII) + # + # ~~~nit + # intrude import core::bytes + # assert not '/'.ascii.to_b.is_valid_hexdigit + # assert '0'.ascii.to_b.is_valid_hexdigit + # assert '9'.ascii.to_b.is_valid_hexdigit + # assert not ':'.ascii.to_b.is_valid_hexdigit + # assert not '@'.ascii.to_b.is_valid_hexdigit + # assert 'A'.ascii.to_b.is_valid_hexdigit + # assert 'F'.ascii.to_b.is_valid_hexdigit + # assert not 'G'.ascii.to_b.is_valid_hexdigit + # assert not '`'.ascii.to_b.is_valid_hexdigit + # assert 'a'.ascii.to_b.is_valid_hexdigit + # assert 'f'.ascii.to_b.is_valid_hexdigit + # assert not 'g'.ascii.to_b.is_valid_hexdigit + # ~~~ + private fun is_valid_hexdigit: Bool do + return (self >= 0x30u8 and self <= 0x39u8) or + (self >= 0x41u8 and self <= 0x46u8) or + (self >= 0x61u8 and self <= 0x66u8) + end + + # `self` as a hexdigit to its byte value + # + # ~~~nit + # intrude import core::bytes + # assert 0x39u8.hexdigit_to_byteval == 0x09u8 + # assert 0x43u8.hexdigit_to_byteval == 0x0Cu8 + # ~~~ + # + # REQUIRE: `self.is_valid_hexdigit` + private fun hexdigit_to_byteval: Byte do + if self >= 0x30u8 and self <= 0x39u8 then + return self - 0x30u8 + else if self >= 0x41u8 and self <= 0x46u8 then + return self - 0x37u8 + else if self >= 0x61u8 and self <= 0x66u8 then + return self - 0x57u8 + end + # Happens only if the requirement is not met. + # i.e. this abort is here to please the compiler + abort + end +end + # A buffer containing Byte-manipulation facilities # # Uses Copy-On-Write when persisted @@ -26,7 +81,7 @@ class Bytes super AbstractArray[Byte] # A NativeString being a char*, it can be used as underlying representation here. - private var items: NativeString + var items: NativeString # Number of bytes in the array redef var length @@ -63,6 +118,20 @@ class Bytes return items[i] end + # Returns self as a hexadecimal digest + fun hexdigest: String do + var elen = length * 2 + var ns = new NativeString(elen) + var i = 0 + var oi = 0 + while i < length do + self[i].add_digest_at(ns, oi) + i += 1 + oi += 2 + end + return new FlatString.full(ns, elen, 0, elen - 1, elen) + end + # var b = new Bytes.with_capacity(1) # b[0] = 101u8 # assert b.to_s == "e" @@ -146,80 +215,13 @@ class Bytes redef fun to_s do persisted = true var b = self - if not is_utf8 then - b = clean_utf8 - persisted = false - end - return new FlatString.with_infos(b.items, b.length, 0, b.length -1) + var r = b.items.to_s_with_length(length) + if r != items then persisted = false + return r end redef fun iterator do return new BytesIterator.with_buffer(self) - # Is the byte collection valid UTF-8 ? - fun is_utf8: Bool do - var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8] - var lobounds = once [0, 0x80, 0x800, 0x10000] - var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF] - var pos = 0 - var len = length - var mits = items - while pos < len do - var nxst = mits.length_of_char_at(pos) - var charst_index = (nxst - 1) * 2 - if mits[pos] & charst[charst_index] == charst[charst_index + 1] then - var c = mits.char_at(pos) - var cp = c.ascii - if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then - if cp >= 0xD800 and cp <= 0xDFFF or - cp == 0xFFFE or cp == 0xFFFF then return false - else - return false - end - else - return false - end - pos += nxst - end - return true - end - - # Cleans the bytes of `self` to be UTF-8 compliant - private fun clean_utf8: Bytes do - var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8] - var badchar = once [0xEFu8, 0xBFu8, 0xBDu8] - var lobounds = once [0, 0x80, 0x800, 0x10000] - var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF] - var pos = 0 - var len = length - var ret = new Bytes.with_capacity(len) - var mits = items - while pos < len do - var nxst = mits.length_of_char_at(pos) - var charst_index = (nxst - 1) * 2 - if mits[pos] & charst[charst_index] == charst[charst_index + 1] then - var c = mits.char_at(pos) - var cp = c.ascii - if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then - if cp >= 0xD800 and cp <= 0xDFFF or - cp == 0xFFFE or cp == 0xFFFF then - ret.append badchar - pos += 1 - else - var pend = pos + nxst - for i in [pos .. pend[ do ret.add mits[i] - pos += nxst - end - else - ret.append badchar - pos += 1 - end - else - ret.append badchar - pos += 1 - end - end - return ret - end end private class BytesIterator @@ -231,7 +233,7 @@ private class BytesIterator var max: Int - init with_buffer(b: Bytes) do init(b.items, 0, b.length - 1) + init with_buffer(b: Bytes) do init(b.items, 0, b.length) redef fun is_ok do return index < max @@ -253,6 +255,15 @@ redef class Text return b end + # Is `self` a valid hexdigest ? + # + # assert "0B1d3F".is_valid_hexdigest + # assert not "5G".is_valid_hexdigest + fun is_valid_hexdigest: Bool do + for i in bytes do if not i.is_valid_hexdigit then return false + return true + end + # Appends `self.bytes` to `b` fun append_to_bytes(b: Bytes) do for s in substrings do @@ -260,6 +271,24 @@ redef class Text b.append_ns_from(s.items, s.bytelen, from) end end + + # Returns a new `Bytes` instance with the digest as content + # + # assert "0B1F4D".hexdigest_to_bytes == [0x0Bu8, 0x1Fu8, 0x4Du8] + # + # REQUIRE: `self` is a valid hexdigest and hexdigest.length % 2 == 0 + fun hexdigest_to_bytes: Bytes do + var b = bytes + var pos = 0 + var max = bytelen + var ret = new Bytes.with_capacity(max / 2) + while pos < max do + ret.add((b[pos].hexdigit_to_byteval << 4) | + b[pos + 1].hexdigit_to_byteval) + pos += 2 + end + return ret + end end redef class FlatText diff --git a/lib/core/stream.nit b/lib/core/stream.nit index 2db319a..4b1e826 100644 --- a/lib/core/stream.nit +++ b/lib/core/stream.nit @@ -173,12 +173,13 @@ abstract class Reader # ~~~ fun read_all: String do var s = read_all_bytes - if not s.is_utf8 then s = s.clean_utf8 var slen = s.length if slen == 0 then return "" var rets = "" var pos = 0 - var sits = s.items + var str = s.items.clean_utf8(slen) + slen = str.bytelen + var sits = str.items var remsp = slen while pos < slen do # The 129 size was decided more or less arbitrarily diff --git a/lib/core/text/flat.nit b/lib/core/text/flat.nit index c8b6ecd..52de988 100644 --- a/lib/core/text/flat.nit +++ b/lib/core/text/flat.nit @@ -985,8 +985,7 @@ redef class NativeString redef fun to_s_with_length(length): FlatString do assert length >= 0 - var str = new FlatString.with_infos(self, length, 0, length - 1) - return str + return clean_utf8(length) end redef fun to_s_full(bytelen, unilen) do @@ -997,6 +996,8 @@ redef class NativeString redef fun to_s_with_copy: FlatString do var length = cstring_length + var r = clean_utf8(length) + if r.items != self then return r var new_self = new NativeString(length + 1) copy_to(new_self, length, 0, 0) var str = new FlatString.with_infos(new_self, length, 0, length - 1) @@ -1005,6 +1006,81 @@ redef class NativeString return str end + # Cleans a NativeString if necessary + fun clean_utf8(len: Int): FlatString do + var replacements: nullable Array[Int] = null + var end_length = len + var pos = 0 + var chr_ln = 0 + while pos < len do + var b = self[pos] + var nxst = length_of_char_at(pos) + var ok_st: Bool + if nxst == 1 then + ok_st = b & 0x80u8 == 0u8 + else if nxst == 2 then + ok_st = b & 0xE0u8 == 0xC0u8 + else if nxst == 3 then + ok_st = b & 0xF0u8 == 0xE0u8 + else + ok_st = b & 0xF8u8 == 0xF0u8 + end + if not ok_st then + if replacements == null then replacements = new Array[Int] + replacements.add pos + end_length += 2 + pos += 1 + chr_ln += 1 + continue + end + var ok_c: Bool + var c = char_at(pos) + var cp = c.ascii + if nxst == 1 then + ok_c = cp >= 0 and cp <= 0x7F + else if nxst == 2 then + ok_c = cp >= 0x80 and cp <= 0x7FF + else if nxst == 3 then + ok_c = cp >= 0x800 and cp <= 0xFFFF + ok_c = ok_c and not (cp >= 0xD800 and cp <= 0xDFFF) and cp != 0xFFFE and cp != 0xFFFF + else + ok_c = cp >= 0x10000 and cp <= 0x10FFFF + end + if not ok_c then + if replacements == null then replacements = new Array[Int] + replacements.add pos + end_length += 2 + pos += 1 + chr_ln += 1 + continue + end + pos += c.u8char_len + chr_ln += 1 + end + var ret = self + if end_length != len then + ret = new NativeString(end_length) + var old_repl = 0 + var off = 0 + var repls = replacements.as(not null) + var r = repls.items.as(not null) + var imax = repls.length + for i in [0 .. imax[ do + var repl_pos = r[i] + var chkln = repl_pos - old_repl + copy_to(ret, chkln, old_repl, off) + off += chkln + ret[off] = 0xEFu8 + ret[off + 1] = 0xBFu8 + ret[off + 2] = 0xBDu8 + old_repl = repl_pos + 1 + off += 3 + end + copy_to(ret, len - old_repl, old_repl, off) + end + return new FlatString.full(ret, end_length, 0, end_length - 1, chr_ln) + end + # Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8 # # Very unsafe, make sure to have room for this char prior to calling this function. @@ -1109,7 +1185,7 @@ redef class Array[E] end i += 1 end - return ns.to_s_with_length(sl) + return new FlatString.with_infos(ns, sl, 0, sl - 1) end end @@ -1146,7 +1222,7 @@ redef class NativeArray[E] end i += 1 end - return ns.to_s_with_length(sl) + return new FlatString.with_infos(ns, sl, 0, sl - 1) end end diff --git a/lib/sha1.nit b/lib/sha1.nit index 8a5acc9..2bd8fbe 100644 --- a/lib/sha1.nit +++ b/lib/sha1.nit @@ -1,7 +1,5 @@ # This file is part of NIT (http://www.nitlanguage.org). # -# Copyright 2014 Lucas Bajolet -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -219,22 +217,12 @@ in "C Header" `{ } `} -redef class String - - # Computes the SHA1 of the receiver - # - # Returns a digest of 20 bytes as a String, - # note that all the characters are not necessarily ASCII. - # If you want the hex string version of the digest, use - # sha1_to_s. - # - # import base64 - # assert "The quick brown fox jumps over the lazy dog".sha1.encode_base64 == "L9ThxnotKPzthJ7hu3bnORuT6xI=" - fun sha1: String import String.to_cstring, String.length, NativeString.to_s_with_length `{ +redef class NativeString + private fun sha1_intern(len: Int): NativeString `{ sha1nfo s; sha1_init(&s); - sha1_write(&s, String_to_cstring(self), String_length(self)); + sha1_write(&s, self, len); uint8_t* digest = sha1_result(&s); char* digested = malloc(21); @@ -243,35 +231,30 @@ redef class String digested[20] = '\0'; - return NativeString_to_s_with_length(digested, 20); + return digested; `} +end + +redef class String + + # Computes the SHA1 of the receiver + # + # Returns a digest of 20 bytes as a NativeString, + # note that all the characters are not necessarily ASCII. + # If you want the hex string version of the digest, use + # sha1_hexdigest. + # + # import base64 + # assert "The quick brown fox jumps over the lazy dog".sha1 == [0x2Fu8, 0xD4u8, 0xE1u8, 0xC6u8, 0x7Au8, 0x2Du8, 0x28u8, 0xFCu8, 0xEDu8, 0x84u8, 0x9Eu8, 0xE1u8, 0xBBu8, 0x76u8, 0xE7u8, 0x39u8, 0x1Bu8, 0x93u8, 0xEBu8, 0x12u8] + fun sha1: Bytes do + return new Bytes(to_cstring.sha1_intern(bytelen), 20, 20) + end # Computes the SHA1 of the receiver. # # Returns a 40 char String containing the Hexadecimal # Digest in its Char form. # - # assert "The quick brown fox jumps over the lazy dog".sha1_to_s == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12" - fun sha1_to_s: String import String.to_cstring, String.length, NativeString.to_s_with_length `{ - sha1nfo s; - - sha1_init(&s); - sha1_write(&s, String_to_cstring(self), String_length(self)); - uint8_t* digest = sha1_result(&s); - - char* ret_str = malloc(41); - char* hexmap = "0123456789ABCDEF"; - - int i; - for(i=0;i<20;i++){ - uint8_t q = digest[i]; - ret_str[i*2] = hexmap[q >> 4]; - ret_str[(i*2)+1] = hexmap[q & 0x0F]; - } - ret_str[40] = '\0'; - - return NativeString_to_s_with_length(ret_str, 40); - `} - + # assert "The quick brown fox jumps over the lazy dog".sha1_hexdigest == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12" + fun sha1_hexdigest: String do return sha1.hexdigest end - diff --git a/lib/websocket/websocket.nit b/lib/websocket/websocket.nit index c3fdaad..2a3c32f 100644 --- a/lib/websocket/websocket.nit +++ b/lib/websocket/websocket.nit @@ -114,7 +114,7 @@ class WebsocketConnection resp_map["Connection:"] = "Upgrade" var key = heads["Sec-WebSocket-Key"] key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - key = key.sha1.encode_base64 + key = key.sha1.encode_base64.to_s resp_map["Sec-WebSocket-Accept:"] = key var resp = resp_map.join("\r\n", " ") resp += "\r\n\r\n" diff --git a/src/nitcatalog.nit b/src/nitcatalog.nit index ba0cb1c..28ae918 100644 --- a/src/nitcatalog.nit +++ b/src/nitcatalog.nit @@ -86,6 +86,12 @@ class CatalogPage # Placeholder to include additional things before the ``. var more_head = new Template + # Relative path to the root directory (with the index file). + # + # Use "" for pages in the root directory + # Use ".." for pages in a subdirectory + var rootpath: String + redef init do add """ @@ -94,7 +100,7 @@ class CatalogPage - + """ add more_head @@ -116,7 +122,7 @@ class CatalogPage @@ -270,7 +276,7 @@ class Catalog # Compute information and generate a full HTML page for a package fun package_page(mpackage: MPackage): Writable do - var res = new CatalogPage + var res = new CatalogPage("..") var score = score[mpackage].to_f var name = mpackage.name.html_escape res.more_head.add """{{{name}}}""" @@ -369,7 +375,7 @@ class Catalog if cat == null then cat = t tag2proj[t].add mpackage t = t.html_escape - ts2.add "{t}" + ts2.add "{t}" end res.add_list(ts2, ", ", ", ") end @@ -377,7 +383,7 @@ class Catalog var t = "none" cat = t tag2proj[t].add mpackage - res.add "{t}" + res.add "{t}" end if cat != null then cat2proj[cat].add mpackage score += ts2.length.score @@ -496,7 +502,7 @@ class Catalog fun li_package(p: MPackage): String do var res = "" - var f = "{p.name}.html" + var f = "p/{p.name}.html" res += "{p}" var d = p.mdoc_or_fallback if d != null then res += " - {d.html_synopsis.write_to_string}" @@ -614,7 +620,7 @@ class Catalog res.add "" for p in mpackages do res.add "" - res.add "{p.name}" + res.add "{p.name}" var maint = "?" if p.maintainers.not_empty then maint = p.maintainers.first res.add "{maint}" @@ -700,7 +706,7 @@ if not opt_no_model.value then end var out = opt_dir.value or else "catalog.out" -out.mkdir +(out/"p").mkdir # Generate the css (hard coded) var css = """ @@ -806,13 +812,13 @@ css.write_to_file(out/"style.css") for p in model.mpackages do # print p - var f = "{p.name}.html" + var f = "p/{p.name}.html" catalog.package_page(p).write_to_file(out/f) end # INDEX -var index = new CatalogPage +var index = new CatalogPage("") index.more_head.add "Packages in Nit" index.add """ @@ -859,7 +865,7 @@ index.write_to_file(out/"index.html") # PEOPLE -var page = new CatalogPage +var page = new CatalogPage("") page.more_head.add "People of Nit" page.add """
\n

People of Nit

\n""" page.add "

By Maintainer

\n" @@ -871,7 +877,7 @@ page.write_to_file(out/"people.html") # TABLE -page = new CatalogPage +page = new CatalogPage("") page.more_head.add "Projets of Nit" page.add """
\n

People of Nit

\n""" page.add "

Table of Projets

\n" diff --git a/tests/sav/nitcg/test_text_stat.res b/tests/sav/nitcg/test_text_stat.res index 1066456..ff641cc 100644 --- a/tests/sav/nitcg/test_text_stat.res +++ b/tests/sav/nitcg/test_text_stat.res @@ -21,7 +21,7 @@ Calls to bytepos for each type: FlatString = 18 Calls to first_byte on FlatString 153 Calls to last_byte on FlatString 103 -FlatStrings allocated with length 81 (85.417%) +FlatStrings allocated with length 82 (86.458%) Length of travel for index distribution: * null = 20 => occurences 83.333%, cumulative 83.333% * 1 = 8 => occurences 21.053%, cumulative 73.684% diff --git a/tests/sav/nitserial_args1.res b/tests/sav/nitserial_args1.res index fe675df..ce7118b 100644 --- a/tests/sav/nitserial_args1.res +++ b/tests/sav/nitserial_args1.res @@ -13,6 +13,7 @@ redef class Deserializer if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self) if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self) if name == "Array[Object]" then return new Array[Object].from_deserializer(self) + if name == "Array[Int]" then return new Array[Int].from_deserializer(self) if name == "Array[Match]" then return new Array[Match].from_deserializer(self) if name == "Array[nullable Match]" then return new Array[nullable Match].from_deserializer(self) return super diff --git a/tests/sav/test_bytes_hexdigit.res b/tests/sav/test_bytes_hexdigit.res new file mode 100644 index 0000000..f00af0c --- /dev/null +++ b/tests/sav/test_bytes_hexdigit.res @@ -0,0 +1,3 @@ +0x0b +0x1f +0x4d diff --git a/tests/sav/test_text_stat.res b/tests/sav/test_text_stat.res index 49e9adc..f6e7b69 100644 --- a/tests/sav/test_text_stat.res +++ b/tests/sav/test_text_stat.res @@ -21,7 +21,7 @@ Calls to bytepos for each type: FlatString = 18 Calls to first_byte on FlatString 153 Calls to last_byte on FlatString 103 -FlatStrings allocated with length 81 (85.417%) +FlatStrings allocated with length 82 (86.458%) Length of travel for index distribution: * 0 = 20 => occurences 83.333%, cumulative 83.333% * 1 = 8 => occurences 21.053%, cumulative 73.684% diff --git a/tests/test_bytes_hexdigit.nit b/tests/test_bytes_hexdigit.nit new file mode 100644 index 0000000..28f51e3 --- /dev/null +++ b/tests/test_bytes_hexdigit.nit @@ -0,0 +1,17 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +var s = "0B1F4D".hexdigest_to_bytes + +for i in s do print i