在ATS中实现getenv()

时间:2018-05-24 07:52:28

标签: ats

在(至少)Linux中,argvenvp具有相同的类型:它们指向以NULL结尾的指向NUL终止字符串的指针数组,并且它们的存储在生命周期中持续存在该过程,无需管理。 envp的字符串格式为“KEY = VALUE”,因此getenv("KEY")可以遍历envp的字符串,将它们的前导字节与“KEY”进行比较,然后返回指针找到'='后开始的字符串。

因此,查找可以根本不涉及内存分配,但查找比使用哈希表得到的要慢。

当您获得envp时,操作系统会保证该类型的有效性,但它没有说明数组的大小。

我想编写一个使用此类型的getenv(),因为它实际上是在内存中布局的,并且我希望将指针返回到其字符串中,并且分配最少。

我希望这样的事情有效:

fun getenv_from(key: string, env: magic): [b:bool] option_vt(string, b) =
    if string2ptr(ptr[0]) > the_null_pointer then (
            case+ string_is_prefix(string_append(key, "="), env[0]) of
            | true => Some_vt(string_make_suffix(env[0], string_length(key)+1))
            | false => getenv_from(key, succ(env))
    ) else None_vt()

其中magic应该是envp的{​​{1}}加上,我想,有些ptr证明断言告诉ATS我告诉过你这个类型的内容。

我想出了一个解决方法,就是假装praxi确实有envp的类型:

argv

这很有效,但现在你还必须打败涉及#include "share/atspre_staload.hats" extern fun fake_free{n:int}: argv(n) -> void = "mac#" %{ void fake_free(void *arg) {} %} // print out the first environment variable, as an example implement main{n:int}(argc, argv, envp) = let val env2 = $UNSAFE.castvwtp1{argv(n)}(envp) in if argc > 0 then print_string(env2[0]); print_newline(); fake_free(env2); 0 end 的虚假约束(实际上与argc无关),以及处理线性打字,这是不必要的。

环顾ATS的图书馆,我认为envp可能有用,但我找不到parray_v的任何示例用途。

注意:作为一个纯粹的实际问题,使用C自己的getenv()从ATS代码中很容易,就像使用各种parray_vgetenv_gcgetenv_opt $ UNSAFE.ptr_xxx一样`来电;即使使用原始指针,我也不想丢弃可证明安全的内存访问的ATS优势。

2 个答案:

答案 0 :(得分:1)

答案 1 :(得分:0)

这是一个适用于抽象类型envp的解决方案。这仍然很便宜。我正在寻找的更像是保留envp原始类型ptr的版本,它具有相同的功能,但仅将功能限制为envp - 就像{ {1}}通过证明系统。我不是从ptr开始,而是从$UNSAFE.cast开始。

lemma_this_ptr_is_envp

用法:

#include "share/atspre_staload.hats"
#include "share/atspre_staload_libats_ML.hats"

abstype envp = ptr
extern fn envp_get(env: envp):<> string = "mac#"
fn envp_get_at{n:int|n==0}(env: envp, n: int(n)): string = envp_get(env)
extern fn add_envp_int{n:int|n==1}(env: envp, n: int(n)): envp = "mac#"
extern fn string_make_suffix: (string, size_t) -> string = "mac#"
overload [] with envp_get_at
overload + with add_envp_int

%{
char *envp_get(void *s) { return ((char **)s)[0]; }
void *add_envp_int(void *p, int n) { return &(((char **)p)[n]); }
char *string_make_suffix(char *s, int start) { return s+start; }
%}

fun getenv_from(key: string, env: envp): [b:bool] option_vt(string, b) =
    if string2ptr(env[0]) > the_null_ptr then (
        case+ string_is_prefix(string_append(key, "="), env[0]) of
        | true => Some_vt(string_make_suffix(env[0], string_length(key)+1))
        | false => getenv_from(key, env+1)
    ) else None_vt()

implement main{n:int}(argc, argv, envp) =
    let
        val envp = $UNSAFE.cast{envp}(envp)
        val reps =
            case+ getenv_from("reps", envp) of
            | ~Some_vt(r) => g0string2int(r)
            | ~None_vt() => 10
        val msg =
            case+ getenv_from("msg", envp) of
            | ~Some_vt(s) => s
            | ~None_vt() => "Hello."
        fun loop(i: int, s: string): void =
            if i > 0 then (
                println!(s);
                loop(i-1, s)
            )
    in
        loop(reps, msg);
        0
    end