Skip to content

Commit

Permalink
Add C stdarg library, support for C va_list
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Nov 11, 2020
1 parent 18eaaec commit 1cb7912
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 14 deletions.
14 changes: 14 additions & 0 deletions lib/C/stdarg.nelua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'C'

## cinclude '<stdarg.h>'

global va_list <cimport, nodecl> = @record{}

function C.va_start(ap: va_list, paramN: auto) <cimport'va_start',nodecl> end
function C.va_end(ap: va_list) <cimport'va_end',nodecl> end

function C.va_arg(ap: va_list, T: type) <inline>
local arg: T <noinit>
## cemit(function(emitter) emitter:add_indent_ln('arg = va_arg(ap, ', T.value, ');') end)
return arg
end
15 changes: 8 additions & 7 deletions lib/C/stdio.nelua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'C'
require 'C.stdarg'

## cinclude '<stdio.h>'

Expand All @@ -24,19 +25,19 @@ function C.scanf(format: cstring, ...: cvarargs): cint <cimport'scanf',nodecl> e
function C.fscanf(stream: *FILE, format: cstring, ...: cvarargs): cint <cimport'fscanf',nodecl> end
function C.sscanf(s: cstring, format: cstring, ...: cvarargs): cint <cimport'sscanf',nodecl> end

function C.vscanf(format: cstring, ...: cvarargs): cint <cimport'vscanf',nodecl> end
function C.vfscanf(stream: *FILE, format: cstring, ...: cvarargs): cint <cimport'vfscanf',nodecl> end
function C.vsscanf(s: cstring, format: cstring, ...: cvarargs): cint <cimport'vsscanf',nodecl> end
function C.vscanf(format: cstring, arg: va_list): cint <cimport'vscanf',nodecl> end
function C.vfscanf(stream: *FILE, format: cstring, arg: va_list): cint <cimport'vfscanf',nodecl> end
function C.vsscanf(s: cstring, format: cstring, arg: va_list): cint <cimport'vsscanf',nodecl> end

function C.printf(format: cstring, ...: cvarargs): cint <cimport'printf',nodecl> end
function C.fprintf(stream: *FILE, format: cstring, ...: cvarargs): cint <cimport'fprintf',nodecl> end
function C.sprintf(s: cstring, format: cstring, ...: cvarargs): cint <cimport'sprintf',nodecl> end
function C.snprintf(s: cstring, maxlen: csize, format: cstring, ...: cvarargs): cint <cimport'snprintf',nodecl> end

function C.vprintf(format: cstring, ...: cvarargs): cint <cimport'vprintf',nodecl> end
function C.vfprintf(stream: *FILE, format: cstring, ...: cvarargs): cint <cimport'vfprintf',nodecl> end
function C.vsprintf(s: cstring, format: cstring, ...: cvarargs): cint <cimport'vsprintf',nodecl> end
function C.vsnprintf(s: cstring, maxlen: csize, format: cstring, ...: cvarargs): cint <cimport'vsnprintf',nodecl> end
function C.vprintf(format: cstring, arg: va_list): cint <cimport'vprintf',nodecl> end
function C.vfprintf(stream: *FILE, format: cstring, arg: va_list): cint <cimport'vfprintf',nodecl> end
function C.vsprintf(s: cstring, format: cstring, arg: va_list): cint <cimport'vsprintf',nodecl> end
function C.vsnprintf(s: cstring, maxlen: csize, format: cstring, arg: va_list): cint <cimport'vsnprintf',nodecl> end

-- Character input/output
function C.getc(stream: *FILE): cint <cimport'getc',nodecl> end
Expand Down
10 changes: 9 additions & 1 deletion nelua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,15 @@ end
-- Set a new codename for this type, storing it in the typeid table.
function Type:set_codename(codename)
self.codename = codename
typeid_by_codename[codename] = self.id
local id = typeid_by_codename[codename]
if not id then
typeid_by_codename[codename] = self.id
elseif id ~= self.id then
-- id for the codename already exists,
-- this happens when changing codename after a type is declared like in
-- the <codename> annotation, hijack this type id so is_equal works
self.id = id
end
end

-- Set a nickname for this type if not set yet.
Expand Down
1 change: 1 addition & 0 deletions rockspecs/nelua-dev-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ build = {
['lib/C/locale.nelua'] = 'lib/C/locale.nelua',
['lib/C/math.nelua'] = 'lib/C/math.nelua',
['lib/C/signal.nelua'] = 'lib/C/signal.nelua',
['lib/C/stdarg.nelua'] = 'lib/C/stdarg.nelua',
['lib/C/stdio.nelua'] = 'lib/C/stdio.nelua',
['lib/C/stdlib.nelua'] = 'lib/C/stdlib.nelua',
['lib/C/string.nelua'] = 'lib/C/string.nelua',
Expand Down
50 changes: 44 additions & 6 deletions tests/libc_test.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,53 @@ require 'C.errno'
require 'C.locale'
require 'C.math'
require 'C.signal'
require 'C.stdarg'
require 'C.stdio'
require 'C.stdlib'
require 'C.string'
require 'C.time'

assert(C.fabs(-1.0) == 1.0)
assert(C.fabsf(-2.0_f32) == 2.0_f32)
assert(C.fabsl(-3.0_clongdouble) == 3.0_clongdouble)
do -- math
assert(C.fabs(-1.0) == 1.0)
assert(C.fabsf(-2.0_f32) == 2.0_f32)
assert(C.fabsl(-3.0_clongdouble) == 3.0_clongdouble)

assert(C.isnan(C.NAN))
assert(C.isinf(C.INFINITY))
assert(C.NAN ~= C.NAN)
assert(C.isnan(C.NAN))
assert(C.isinf(C.INFINITY))
assert(C.NAN ~= C.NAN)
end

do -- va_list
local function fill_numbers(numbers: *[0]number, n: integer, ...: cvarargs)
local vl: va_list
C.va_start(vl, n)
for i=0,<n do
numbers[i] = C.va_arg(vl, @number)
end
C.va_end(vl)
end

local numbers: [4]number
fill_numbers(&numbers, 0)
fill_numbers(&numbers, 1, 0.5)
assert(numbers[0] == 0.5)
fill_numbers(&numbers, 2, 1.0, 0.5)
assert(numbers[0] == 1.0 and numbers[1] == 0.5)
fill_numbers(&numbers, 3, 2.0, 1.0, 0.5)
assert(numbers[0] == 2.0 and numbers[1] == 1.0 and numbers[2] == 0.5)
end

do -- vsscanf
local function get_matches(str: cstring, format: cstring, ...: cvarargs)
local args: va_list
C.va_start(args, format)
C.vsscanf(str, format, args)
C.va_end(args)
end

local val: cint
local buf: [100]cchar
get_matches("99 bottles of water", "%d %s", &val, &buf[0]);
assert(val == 99)
assert(&buf[0] == 'bottles')
end

0 comments on commit 1cb7912

Please sign in to comment.