# # # Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## Regular expression support for Nim. Consider using the pegs module ## instead. ## This module is implemented by providing a wrapper around the ## `PRCE (Perl-Compatible Regular Expressions) `_ ## C library. This means that your application will depend on the PRCE ## library's licence when using this module, which should not be a problem ## though. ## PRCE's licence follows: ## ## .. include:: ../doc/regexprs.txt ## import pcre, strutils const MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that can be captured. ## More subpatterns cannot be captured! type RegexFlag* = enum ## options for regular expressions reIgnoreCase = 0, ## do caseless matching reMultiLine = 1, ## ``^`` and ``$`` match newlines within data reDotAll = 2, ## ``.`` matches anything including NL reExtended = 3, ## ignore whitespace and ``#`` comments reStudy = 4 ## study the expression (may be omitted if the ## expression will be used only once) RegexDesc = object h: PPcre e: ptr TExtra Regex* = ref RegexDesc ## a compiled regular expression RegexError* = object of ValueError ## is raised if the pattern is no valid regular expression. {.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex, EInvalidRegEx: RegexError].} proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} = var e: ref RegexError new(e) e.msg = msg raise e proc rawCompile(pattern: string, flags: cint): PPcre = var msg: cstring offset: cint result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil) if result == nil: raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n") proc finalizeRegEx(x: Regex) = # XXX This is a hack, but PCRE does not export its "free" function properly. # Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``). # Fortunately the implementation is unlikely to change. pcre.free_substring(cast[cstring](x.h)) if not isNil(x.e): pcre.free_substring(cast[cstring](x.e)) proc re*(s: string, flags = {reExtended, reStudy}): Regex = ## Constructor of regular expressions. Note that Nim's ## extended raw string literals support this syntax ``re"[abc]"`` as ## a short form for ``re(r"[abc]")``. new(result, finalizeRegEx) result.h = rawCompile(s, cast[cint](flags - {reStudy})) if reStudy in flags: var msg: cstring result.e = pcre.study(result.h, 0, msg) if not isNil(msg): raiseInvalidRegex($msg) proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string], start, flags: cint): cint = var rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start, flags, cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: return res for i in 1..int(res)-1: var a = rawMatches[i * 2] var b = rawMatches[i * 2 + 1] if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1) else: matches[i-1] = nil return rawMatches[1] - rawMatches[0] proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], start = 0): tuple[first, last: int] = ## returns the starting position and end position of `pattern` in `s` ## and the captured ## substrings in the array `matches`. If it does not match, nothing ## is written into `matches` and ``(-1,0)`` is returned. var rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: return (-1, 0) for i in 1..int(res)-1: var a = rawMatches[i * 2] var b = rawMatches[i * 2 + 1] if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1) else: matches[i-1] = nil return (rawMatches[0].int, rawMatches[1].int - 1) proc findBounds*(s: string, pattern: Regex, matches: var openArray[tuple[first, last: int]], start = 0): tuple[first, last: int] = ## returns the starting position and end position of ``pattern`` in ``s`` ## and the captured substrings in the array `matches`. ## If it does not match, nothing is written into `matches` and ## ``(-1,0)`` is returned. var rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: return (-1, 0) for i in 1..int(res)-1: var a = rawMatches[i * 2] var b = rawMatches[i * 2 + 1] if a >= 0'i32: matches[i-1] = (int(a), int(b)-1) el
discard """
  file: "tmemmapstreams.nim"
  output: '''Created size: 10
Position after writing: 5
Position after writing one char: 6
Peeked data: Hello
Position after peeking: 0
Readed data: Hello!
Position after reading line: 7
Position after setting position: 6
Readed line: Hello!
Position after reading line: 7'''
"""
import os, streams, memfiles
const
  fn = "test.mmapstream"
var
  mms: MemMapFileStream

if fileExists(fn): removeFile(fn)

# Create a new memory mapped file, data all zeros
mms = newMemMapFileStream(fn, mode = fmReadWrite, fileSize = 10)
mms.close()
if fileExists(fn): echo "Created size: ", getFileSize(fn)

# write, flush, peek, read
mms = newMemMapFileStream(fn, mode = fmReadWrite)
let s = "Hello"

mms.write(s)
mms.flush
echo "Position after writing: ", mms.getPosition()
mms.write('!')
mms.flush
echo "Position after writing one char: ", mms.getPosition()
mms.close()

mms = newMemMapFileStream(fn, mode = fmRead)
echo "Peeked data: ", mms.peekStr(s.len)
echo "Position after peeking: ", mms.getPosition()
echo "Readed data: ", mms.readLine
echo "Position after reading line: ", mms.getPosition()
mms.setPosition(mms.getPosition() - 1)
echo "Position af