winstr

    Dark Mode

This module contains new string types and utilities to deal with strings in Windows. Windows SDK use following types to represent a char or a string:

type
  CHAR = char
  WCHAR = uint16
  LPSTR|LPCSTR = cstring # however, it should be ansi string, not utf8 string
  LPWSTR|LPCWSTR = ptr WCHAR
  BSTR = distinct ptr WCHAR # BSTR is not binary compatible with LPWSTR
  (ptr) array[I, CHAR] # sometimes string defined as array[1, CHAR] but not only one char
  (ptr) array[I, WCHAR] # sometimes string defined as array[1, WCHAR] but not only one widechar

By default, Nim's string type is utf8 encoding. However, Windows use wide character string (aka. unicode string) or multibyte character string (aka. ansi string). So, this module introduce following string types.

type
  string # nim built-in string type, utf8 encoding by default, can be ansi string sometimes.
  cstring # compatible to the type char* in Ansi C
  wstring = distinct string # new string type to store unicode string
  mstring = distinct string # new string type to store ansi string

Some type classes are also defined for convenience to deal with strings.

type
  SomeChar = byte | char | WCHAR
  SomeString = string | mstring | wstring
  SomeBuffer[I] = ptr SomeChar | array[I, SomeChar] | ptr array[I, SomeChar] |
    ptr UncheckedArray[SomeChar] | openArray[SomeChar] | seq[SomeChar]
  Stringable = SomeChar | SomeString | SomeBuffer | cstring | BSTR

Here are the pseudocode for most useful functions introduced by this module.

proc `&`(s: cstring|string|wstring|mstring): pointer
  # Get address of the first char of a string.
  # For string, it has a similar meaning to cstring(s).

proc `$`(x: Stringable): string
proc `+$`(x: Stringable): wstring
proc `-$`(x: Stringable): mstring
  # Convert any stringable type to string, wstring, or mstring.
  # These operators assume string|cstring|ptr char|openArray[char] are utf8 encoding.
  # setOpenArrayStringable() can be used to switch the behavior of `$` operator.

proc `$$`(x: Stringable): string
proc `+$$`(x: Stringable): wstring
proc `-$$`(x: Stringable): mstring
  # Convert any stringable type to string, wstring, or mstring.
  # These operators assume string|cstring|ptr char|openArray[char] are ansi encoding.
  # For mstring|wstring|LPWSTR etc, these operators are the same as `$`, `+$`, `-$`.

template `<<`(s: SomeString, b: SomeBuffer)
template `<<`(b: SomeBuffer, s: SomeString)
template `<<<`(b: SomeBuffer, s: SomeString)
template `>>`(a: typed, b: typed) = b << a
template `>>>`(a: typed, b: typed) = b <<< a
  # String << Buffer or Buffer >> String: Fill string by buffer.
  # Buffer << String or String >> Buffer: Fill buffer by string.
  # Buffer <<< String or String >>> Buffer: Fill buffer by string, include a null.
  
  # These operators don't convert the encoding (copy byte by byte).
  # Please make sure both side have the same character size.
  # If destination don't have the length information (e.g. pointer or UncheckedArray),
  # please make sure the buffer size is large enough.

proc nullTerminate(s: var SomeString)
  # Assume a string is null terminated and set the correct length.

proc nullTerminated[T: SomeString](s: T): T
  # Assume a string is null terminated and return the length-corrected string.

template L(s: string): wstring
  # Generate wstring at compile-time if possible.
  # Only const string or string literal can be converted to unicode string at compile-time,
  # otherwise it is just `+$`.

template T(s: string): mstring|wstring
  # Generate wstring or mstring depend on conditional symbol: useWinAnsi.
  # For example: (this code works under both unicode and ansi mode)
    
    MessageBox(0, T"hello, world", T"Nim is Powerful 中文測試", 0)

template T(n: Natural): mstring|wstring
  # Generate wstring or mstring buffer depend on conditional symbol: useWinAnsi.
  # Use `&` to get the buffer address and then pass to Windows API.

converter winstrConverter(s: SomeString): SomeBuffer
  # With these converters, pass string to Windows API is more easy.
  #   Following converters don't need encoding conversion:
  #     string => LPSTR (built-in)|ptr char
  #     mstring => LPSTR|ptr char
  #     wstring => LPWSTR|BSTR
  #     cstring => ptr char
  #     BSTR => LPWSTR
  #
  #   Some converters DO need encoding conversion (utf8 to unicode).
  #   New memory block will be allocated. However, they are useful and convenience.
  #     cstring|string => LPWSTR|BSTR
  #
  # Winim don't use built-in WideCString, but still support it by converter.
  #   WideCString => LPWSTR
  #   WideCString => wstring
  #   wstring => WideCString

There are also new string functions to deal with wstring and mstring just like built-in string type.

proc newWString(len: Natural): wstring
  # Generate wstring buffer
proc newMString(len: Natural): mstring
  # Generate mstring buffer

proc setLen(s: var mstring|wstring, newLen: Natural)
proc substr(s: wstring|mstring, first = 0): wstring|mstring
proc substr(s: wstring|mstring, first, last: int): wstring|mstring
proc len(s: wstring|mstring): int
proc high(s: wstring|mstring): int
proc low(s: wstring|mstring): int
proc repr(s: wstring|mstring): string
proc toHex(s: wstring|mstring): string

proc `[]`(s: wstring|mstring, i: int): WCHAR|mstring
proc `[]=`(s: wstring|mstring, i: int, u: WCHAR|CHAR)
proc `[]=`(s: wstring|mstring, i: int, u: wstring|mstring)
proc `[]`(s: wstring|mstring, x: HSlice)
proc `[]=`(s: var wstring|var mstring, x: HSlice[int], b: wstring|mstring)
proc `==`(x, y: wstring|mstring): bool
proc `<=`(x, y: wstring|mstring): bool
proc `<`(x, y: wstring|mstring): bool
proc cmp(x, y: wstring|mstring): int
proc `&`(s: wstring|mstring, t: wstring|mstring): wstring|mstring

iterator items(s: wstring|mstring): WCHAR|mstring
iterator mitems(s: var wstring): WCHAR
iterator pairs(s: wstring|mstring): tuple[key: int|mIndex, val: WCHAR|mstring]
iterator mpairs(s: var wstring): WCHAR

Types

wstring = distinct string
New string type to store wide character string (aka. unicode string).
mstring = distinct string
New string type to store multibyte character string (aka. ansi string).
mIndex = distinct int
Use mIndex in substr, [] or []= for mstring means index by MBCS characters, not by bytes.
SomeChar = byte | char | WCHAR
Type class matching all char types.
SomeString = string | mstring | wstring
Type class matching all string types.
SomeBuffer[I] = ptr SomeChar | array[I, SomeChar] | ptr array[I, SomeChar] |
    ptr UncheckedArray[SomeChar] |
    openArray[SomeChar] |
    seq[SomeChar]
Type class matching all string buffer types.
Stringable = SomeChar | SomeString | SomeBuffer | cstring | BSTR
Type class matching all stringable types.
TString = wstring
wstring or mstring depend on conditional symbol: useWinAnsi.

Procs

proc toHex(s: cstring): string {...}{.inline, raises: [], tags: [].}
Converts a cstring to its hexadecimal representation. No prefix like 0x is generated.
proc newWString(L: Natural): wstring {...}{.raises: [], tags: [].}
Returns a new wstring of length L, counting by wide characters.
proc newMString(L: Natural): mstring {...}{.raises: [], tags: [].}
Returns a new mstring of length L, counting by bytes.
proc len(s: wstring): int {...}{.inline, raises: [], tags: [].}
Returns the length of wstring, counting by wide characters.
proc len(s: mstring): int {...}{.inline, raises: [], tags: [].}
Returns the length of mstring, counting by bytes.
proc newWStringOfCap(L: Natural): wstring {...}{.raises: [], tags: [].}
Returns a new wstring of length 0 but with capacity L, counting by wide characters.
proc newMStringOfCap(L: Natural): mstring {...}{.raises: [], tags: [].}
Returns a new mstring of length 0 but with capacity L, counting by bytes.
proc setLen(s: var wstring; L: Natural) {...}{.inline, raises: [], tags: [].}
Sets the length of wstring s to L, counting by wide characters.
proc setLen(s: var mstring; L: Natural) {...}{.inline, raises: [], tags: [].}
Sets the length of mstring s to L, counting by wide bytes.
proc `&`(s: string): ptr char {...}{.inline, raises: [], tags: [].}
Get address of the first char of a string.
proc `&`(s: cstring): ptr char {...}{.inline, raises: [], tags: [].}
Get address of the first char of a cstring.
proc `&`(s: wstring): ptr WCHAR {...}{.inline, raises: [], tags: [].}
Get address of the first WCHAR of a wstring.
proc `&`(s: mstring): ptr char {...}{.inline, raises: [], tags: [].}
Get address of the first char of a mstring.
proc high(s: wstring): int {...}{.inline, raises: [], tags: [].}
Returns the highest possible index of wstring.
proc low(s: wstring): int {...}{.inline, raises: [], tags: [].}
Returns the lowest possible index of wstring.
proc cmp(x, y: wstring): int {...}{.borrow.}
Compare proc for wstring (in binary format only).
proc `==`(x, y: wstring): bool {...}{.borrow.}
Checks for equality between two wstring.
proc `<=`(x, y: wstring): bool {...}{.borrow.}
Lexicographic <= operator for wstring.
proc `<`(x, y: wstring): bool {...}{.borrow.}
Lexicographic < operator for wstring.
proc substr(s: wstring; first, last: int): wstring {...}{.raises: [], tags: [].}
Copies a slice of s into a new wstring and returns it.
proc substr(s: wstring; first = 0): wstring {...}{.inline, raises: [], tags: [].}
Copies a slice of s into a new wstring and returns it.
proc `[]`(s: wstring; i: int): WCHAR {...}{.inline, raises: [IndexDefect], tags: [].}
Index operator for wstring.
proc `[]=`(s: var wstring; i: int; c: WCHAR | char) {...}{.inline.}
Index assignment operator for wstring.
proc `[]`[T, U](s: wstring; x: HSlice[T, U]): wstring
Slice operation for wstring.
proc `[]=`[T, U](s: var wstring; x: HSlice[T, U]; b: wstring)
Slice assignment for wstring.
proc add(s: var wstring; c: char | WCHAR)
Appends c to s in place.
proc add(s: var wstring; u: wstring) {...}{.raises: [], tags: [].}
Appends u to s in place.
proc `&`(s: wstring; c: WCHAR | char): wstring {...}{.inline.}
Concatenates s with c.
proc `&`(s, u: wstring): wstring {...}{.inline, raises: [], tags: [].}
Concatenates s with u.
proc toHex(s: wstring): string {...}{.inline, raises: [], tags: [].}
Converts wstring to its hexadecimal representation. No prefix like 0x is generated.
proc repr(s: wstring): string {...}{.raises: [], tags: [].}
Returns string representation of wstring.
proc mlen(s: mstring): int {...}{.raises: [], tags: [].}
Returns the length of mstring, counting by MBCS characters.
proc high(s: mstring): int {...}{.borrow.}
Returns the highest possible index of mstring.
proc low(s: mstring): int {...}{.borrow.}
Returns the lowest possible index of mstring.
proc cmp(x, y: mstring): int {...}{.borrow.}
Compare proc for mstring (in binary format only).
proc `==`(x, y: mstring): bool {...}{.borrow.}
Checks for equality between two mstring.
proc `<=`(x, y: mstring): bool {...}{.borrow.}
Lexicographic <= operator for mstring.
proc `<`(x, y: mstring): bool {...}{.borrow.}
Lexicographic < operator for mstring.
proc substr(s: mstring; first, last: int): mstring {...}{.borrow.}
Copies a slice of s into a new mstring and returns it, counting by bytes.
proc substr(s: mstring; first = 0): mstring {...}{.borrow.}
Copies a slice of s into a new mstring and returns it, counting by bytes.
proc `[]`(s: mstring; i: int): char {...}{.inline, raises: [], tags: [].}
Index operator for mstring, counting by bytes.
proc `[]=`(s: var mstring; i: int; x: char | byte) {...}{.inline.}
Index assignment operator for mstring, counting by bytes.
proc substr(s: mstring; first, last: mIndex): mstring {...}{.raises: [], tags: [].}
Copies a slice of s into a new mstring and returns it, counting by MBCS characters.
proc substr(s: mstring; first: mIndex = 0.mIndex): mstring {...}{.raises: [], tags: [].}
Copies a slice of s into a new mstring and returns it, counting by MBCS characters.
proc `[]`(s: mstring; i: mIndex): mstring {...}{.raises: [IndexDefect], tags: [].}
Index operator for mstring, counting by MBCS characters.
proc `[]=`(s: var mstring; i: mIndex; u: mstring) {...}{.raises: [IndexDefect], tags: [].}
Index assignment operator for mstring, counting by MBCS characters, and only first MBCS characters of u will be used.
proc `[]`[T, U](s: mstring; x: HSlice[T, U]): mstring
Slice operation for mstring.
proc `[]=`[T, U](s: var mstring; x: HSlice[T, U]; u: mstring)
Slice assignment for mstrings.
proc add(x: var mstring; y: char) {...}{.borrow.}
Appends y to x in place.
proc add(x: var mstring; y: string) {...}{.borrow.}
Appends y to x in place.
proc add(x: var mstring; y: mstring) {...}{.borrow.}
Appends y to x in place.
proc add(x: var mstring; y: byte) {...}{.inline, raises: [], tags: [].}
Appends y to x in place.
proc `&`(x: mstring; y: char): mstring {...}{.borrow.}
Concatenates x with y.
proc `&`(x, y: mstring): mstring {...}{.borrow.}
Concatenates x with y.
proc `&`(x: char; y: mstring): mstring {...}{.borrow.}
Concatenates x with y.
proc toHex(s: mstring): string {...}{.inline, raises: [], tags: [].}
Converts mstring to its hexadecimal representation. No prefix like 0x is generated.
proc repr(s: mstring): string {...}{.raises: [], tags: [].}
Returns string representation of mstring.
proc setOpenArrayStringable(flag: bool): bool {...}{.inline, discardable, raises: [],
    tags: [].}
Nim's system.`$` will return array representation for openArray[SomeChar]. After turn this option on, winstr will overwrite the defualt behavior for $ and treats openArray[SomeChar] as string.
proc `$`(s: Stringable): string {...}{.inline.}
Convert any stringable type to string. This operator assume string|cstring|ptr char|openArray[char] is utf8 encoding.
proc `%$`(s: Stringable): string {...}{.inline.}
Convert any stringable type to string. Always treat openArray[SomeChar] as string. This operator assume string|cstring|ptr char|openArray[char] is utf8 encoding.
proc `+$`(s: Stringable): wstring {...}{.inline.}
Convert any stringable type to wstring. This operator assume string|cstring|ptr char|openArray[char] is utf8 encoding.
proc `-$`(s: Stringable): mstring {...}{.inline.}
Convert any stringable type to mstring. This operator assume string|cstring|ptr char|openArray[char] is utf8 encoding.
proc `$$`(s: Stringable): string {...}{.inline.}
Convert any stringable type to string. This operator assume string|cstring|ptr char|openArray[char] is ansi encoding.
proc `+$$`(s: Stringable): wstring {...}{.inline.}
Convert any stringable type to wstring. This operator assume string|cstring|ptr char|openArray[char] is ansi encoding.
proc `-$$`(s: Stringable): mstring {...}{.inline.}
Convert any stringable type to mstring. This operator assume string|cstring|ptr char|openArray[char] is ansi encoding.
proc nullTerminate(s: var SomeString) {...}{.inline.}
Assume a string is null terminated and set the correct length.
proc nullTerminated[T: SomeString](s: T): T {...}{.inline.}
Assume a string is null terminated and return the length-corrected string.
proc newWString(s: cstring | string | mstring): wstring {...}{.inline,
    deprecated: "use `+$` instead".}
Deprecated: use `+$` instead
Return a new wstring.
proc newMString(s: string | cstring | wstring): mstring {...}{.inline,
    deprecated: "use `-$` instead".}
Deprecated: use `-$` instead
Return a new mstring.

Iterators

iterator items(s: wstring): WCHAR {...}{.raises: [], tags: [].}
Iterates over each WCHAR of wstring.
iterator mitems(s: var wstring): var WCHAR {...}{.raises: [], tags: [].}
Iterates over each WCHAR of wstring so that you can modify the yielded value.
iterator pairs(s: wstring): tuple[key: int, val: WCHAR] {...}{.raises: [], tags: [].}
Iterates over each WCHAR of wstring. Yields (int, WCHAR) pairs.
iterator mpairs(s: var wstring): tuple[key: int, val: var WCHAR] {...}{.raises: [], tags: [].}
Iterates over each WCHAR of wstring. Yields (int, var WCHAR) pairs.
iterator items(s: mstring): mstring {...}{.raises: [], tags: [].}
Iterates over each MBCS character of mstring.
iterator pairs(s: mstring): tuple[key: mIndex, val: mstring] {...}{.raises: [], tags: [].}
Iterates over each MBCS character of mstring. Yields (mIndex, mstring) pairs.

Converters

converter winstrConverterWStringToLPWSTR(x: wstring): LPWSTR {...}{.raises: [], tags: [].}
Converts wstring to LPWSTR automatically.
converter winstrConverterWStringToBSTR(x: wstring): BSTR {...}{.raises: [], tags: [].}
Converts wstring to BSTR automatically.
converter winstrConverterBSTRToLPWSTR(x: BSTR): LPWSTR {...}{.raises: [], tags: [].}
Converts BSTR to LPWSTR automatically.
converter winstrConverterStringToPtrChar(x: string): ptr char {...}{.raises: [], tags: [].}
Converts string to ptr char automatically.
converter winstrConverterCStringToPtrChar(x: cstring): ptr char {...}{.raises: [], tags: [].}
Converts cstring to ptr char automatically.
converter winstrConverterMStringToPtrChar(x: mstring): ptr char {...}{.raises: [], tags: [].}
Converts mstring to ptr char automatically.
converter winstrConverterMStringToLPSTR(x: mstring): LPSTR {...}{.raises: [], tags: [].}
Converts mstring to LPSTR automatically.
converter winstrConverterWideCStringToLPWSTR(x: WideCString): LPWSTR {...}{.raises: [],
    tags: [].}
Converts WideCString to LPWSTR automatically.
converter winstrConverterWideCStringToWString(x: WideCString): wstring {...}{.raises: [],
    tags: [].}
Converts WideCString to wstring automatically.
converter winstrConverterWStringToWideCString(x: wstring): WideCString {...}{.raises: [],
    tags: [].}
Converts wstring to WideCString automatically.
converter winstrConverterStringToLPWSTR(x: string): LPWSTR {...}{.raises: [], tags: [].}
Converts string to LPWSTR automatically.
converter winstrConverterCStringToLPWSTR(x: cstring): LPWSTR {...}{.raises: [], tags: [].}
Converts cstring to LPWSTR automatically.
converter winstrConverterStringToBSTR(x: string): BSTR {...}{.raises: [], tags: [].}
Converts string to BSTR automatically.
converter winstrConverterCStringToBSTR(x: cstring): BSTR {...}{.raises: [], tags: [].}
Converts cstring to BSTR automatically.

Templates

template `<<`[A; B](a: A; b: B)
Fill operator for SomeBuffer and SomeString. Please make sure both side have the same character size. If destination don't have the length information (e.g. pointer or UncheckedArray), please make sure the buffer size is large enough.
template `<<<`[A; ](a: A; b: SomeString)
Fill buffer by string, include a null. Please make sure both side have the same character size. If destination don't have the length information (e.g. pointer or UncheckedArray), please make sure the buffer size is large enough.
template `>>`(a: typed; b: typed)
This is the same as b << a.
template `>>>`(a: typed; b: typed)
This is the same as b <<< a.
template L(x: static[string]): wstring
Generate const wstring from static[string] at compile-time.
template L(x: string): wstring
Same as +$ for dynamic string (string at run-time).
template T(x: string): untyped
Generate wstring or mstring depend on conditional symbol: useWinAnsi.
template T(x: Natural): untyped
Generate wstring or mstring buffer depend on conditional symbol: useWinAnsi. Use & to get the buffer address and then pass to Windows API.