; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;   Description: Macto library for global variables handling.
;
;   Target OS: Any
;
;   Dependencies:
;
;   Notes:
;_________________________________________________________________________________________

;------------------------------------------------------------------
; use "iglobal" for inserting initialized global data definitions.
;------------------------------------------------------------------
macro iglobal {
  IGlobals equ IGlobals,
  macro __IGlobalBlock \{
}


;-------------------------------------------------------------
; use 'uglobal' for inserting uninitialized global definitions.
; even when you define some data values, these variables
; will be stored as uninitialized data.
;-------------------------------------------------------------
macro uglobal {
  UGlobals equ UGlobals,
  macro __UGlobalBlock \{
}

; Use endg for ending iglobal and uglobal blocks.
endg fix }


macro IncludeIGlobals {
  macro IGlobals dummy, [n] \{
    __IGlobalBlock
    purge __IGlobalBlock
  \}
  match I, IGlobals \{
    I
  \}
}


macro IncludeUGlobals {
  macro UGlobals dummy, [n] \{
    \common
      \local begin, size
      begin = $
      virtual at $
    \forward
        __UGlobalBlock
        purge __UGlobalBlock
    \common
        size = $ - begin
      end virtual
      rb size
  \}
  match U, UGlobals \{
    U
  \}
}


; Safe fallback of the strings data macros.

;macro __InitStringsEngine {
;  local r,v,c
;  c equ 0
;
;  struc text [val] \{
;    \common
;      if ~val eqtype 1
;      virtual at 0
;    \forward
;        db val
;    \common
;      .length = $
;      end virtual
;      end if
;    rept 1 x:c+1 \\{
;      c equ x
;      r\\#x equ .
;      v\\#x equ val
;    \\}
;  \}
;
;  macro __IncludeAllStrings \{
;    \common
;    \local ..start, len, i, j, f, ch1, ch2
;    label ..start byte
;    if defined options.ShowSizes and options.ShowSizes
;      disp 3, 'String data address: $', <..start, 16>, 13
;      disp 3, 'String count: ', <c, 10>, 13
;    end if
;
;    rept c x \\{
;      if used r\\#x
;        if ~v\\#x eqtype 1
;          r\\#x db v\\#x, 0
;        else
;          label r\\#x byte at v\\#x
;        end if
;      end if
;    \\}
;  \}
;}


macro __InitStringEngine {
local ..hashtable, ..strbase, strlist

  virtual at 0
    ..hashtable::
         dd 65536 dup ($ffffffff)
  end virtual

  strlist equ 0

  struc text [arg] \{
  \common
    rept 1 x:strlist+1 \\{
      strlist equ x
      strlist\\#x equ ., arg
      .@here = 0
    \\}
  \}

  macro _add_one_str lbl, [dta] \{
  \common
    \local ..buff, sz, h, sh, ch1, ch2, i, f
    if used lbl
      virtual at 0
        ..buff::
            db dta, 0
            sz = $
      end virtual

      h = $811C9DC5
      repeat sz
        load ch1 byte from ..buff:(%-1)
        h = ((h xor ch1) * $01000193) and $ffffffff
      end repeat

      h = ((h shr 16) xor h) and $ffff
      sh = h

      while 1
        load i dword from ..hashtable: h*4
        if i = $ffffffff
          break
        else
          f = 1
          repeat sz/8
            load ch1 qword from ..buff:((%-1)*8)
            load ch2 qword from $$+i+(%-1)*8
            if ch1<>ch2
              f = 0
              break
            end if
          end repeat
          if f
            repeat sz mod 8
              load ch1 byte from ..buff:((sz and $fffffff8)+(%-1))
              load ch2 byte from $$+i+(sz and $fffffff8)+(%-1)
              if ch1<>ch2
                f = 0
                break
              end if
            end repeat
          end if
          if f
            break
          end if
        end if
        h = (h+1) and $ffff
        if h = sh
          err "Hash table full."
        end if
      end while
      if i = $ffffffff
        store dword $-$$ at ..hashtable:4*h
        lbl db dta, 0
        align 4
      else
        label lbl byte at i+$$
      end if
      lbl\#.length = sz-1
    else
      if defined options.ShowSkipped & options.ShowSkipped
        display 1, 'String <', dta, '> skipped, because not used.', 13
      end if
    end if
  \}

  macro _IncludeAllStrings \{
    ..strbase:
    rept strlist x \\{
      match onestr, _add_one_str strlist\\#x \\\{ onestr \\\}
    \\}
  \}
}


__InitStringEngine


macro IncludeAllGlobals {
  local ..start

  align 4
  ..start = $
  disp 3, 'Initialized data address: $', <..start, 16>, 13
  IncludeIGlobals
  DispSize 'Initialized data', ($ - ..start)

  align 4
  ..start = $
  disp 3, 'Strings address: $', <..start, 16>, 13
  _IncludeAllStrings
  DispSize 'String data', ($ - ..start)

  align 4
  ..start = $
  disp 3, 'I18n strings data:', <..start, 16>, 13
  __IncludeI18nStrings
  DispSize 'I18n strings data', ($ - ..start)

  align 4
  ..start = $
  disp 3, 'Uninitialized data address: $', <..start, 16>, 13
  IncludeUGlobals
  DispSize 'Uninitialized data', ($ - ..start)

  align 4
  ..start = $
  disp 3, 'I18n strings placeholders: $', <..start, 16>, 13
  IncludeI18nLabels
  DispSize 'I18n strings placeholders', ($ - ..start)
}



macro var expr {
common
  match name==value, expr \{
    if used name
      name dd value
    else
      name = 0
    end if
  \}
}


macro movx target, txt {
common
  local ..txt
  ..txt text txt
        mov     target, ..txt
}


iglobal
endg

uglobal
endg
