summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 12:56:51 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 12:56:59 -0300
commitb7b08a7d29d84de187dd8a55e0c94de66b07a572 (patch)
tree7e55661d3eca3cf3b16aada6e87eabee68802fb9 /src
downloadasm-0.1.0.tar.gz
Initial importv0.1.0
Diffstat (limited to 'src')
-rw-r--r--src/abi.inc58
-rw-r--r--src/cep.S53
-rw-r--r--src/client.S879
-rw-r--r--src/csv.S297
-rw-r--r--src/defs.inc79
-rw-r--r--src/http.S759
-rw-r--r--src/json.S482
-rw-r--r--src/models.S716
-rw-r--r--src/util.S190
9 files changed, 3513 insertions, 0 deletions
diff --git a/src/abi.inc b/src/abi.inc
new file mode 100644
index 0000000..490c4b1
--- /dev/null
+++ b/src/abi.inc
@@ -0,0 +1,58 @@
+#ifndef CEPIS_ABI_INC
+#define CEPIS_ABI_INC
+
+.macro FUNC name
+ .text
+ .globl \name
+ .hidden \name
+ .type \name, @function
+ .p2align 4
+\name:
+.endm
+
+.macro PUBFUNC name
+ .text
+ .globl \name
+ .type \name, @function
+ .p2align 4
+\name:
+.endm
+
+.macro ENDFUNC name
+ .size \name, . - \name
+.endm
+
+.macro PROLOGUE n=8
+.if (\n % 16) != 8
+ .error "PROLOGUE frame size must be congruent to 8 modulo 16"
+.endif
+ push %rbp
+ mov %rsp, %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ sub $\n, %rsp
+.endm
+
+.macro EPILOGUE
+ lea -40(%rbp), %rsp
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbx
+ pop %rbp
+.endm
+
+#define LOCAL0 -48
+#define LOCAL1 -56
+#define LOCAL2 -64
+#define LOCAL3 -72
+#define LOCAL4 -80
+#define LOCAL5 -88
+#define LOCAL6 -96
+#define LOCAL7 -104
+
+#endif
diff --git a/src/cep.S b/src/cep.S
new file mode 100644
index 0000000..8b7661d
--- /dev/null
+++ b/src/cep.S
@@ -0,0 +1,53 @@
+#include "abi.inc"
+#include "defs.inc"
+
+ .text
+
+PUBFUNC cepis_normalize_cep
+ test %rsi, %rsi
+ jz .Lnorm_usage
+ movb $0, (%rsi)
+ test %rdi, %rdi
+ jz .Lnorm_bad
+ xor %ecx, %ecx
+.Lnorm_loop:
+ movzbl (%rdi), %eax
+ inc %rdi
+ test %al, %al
+ jz .Lnorm_done
+ cmp $'-', %al
+ je .Lnorm_loop
+ cmp $'.', %al
+ je .Lnorm_loop
+ cmp $' ', %al
+ je .Lnorm_loop
+ cmp $9, %al
+ jb .Lnorm_digit
+ cmp $13, %al
+ jbe .Lnorm_loop
+.Lnorm_digit:
+ cmp $'0', %al
+ jb .Lnorm_bad
+ cmp $'9', %al
+ ja .Lnorm_bad
+ cmp $8, %rcx
+ jae .Lnorm_bad
+ mov %al, (%rsi, %rcx, 1)
+ inc %rcx
+ jmp .Lnorm_loop
+.Lnorm_done:
+ cmp $8, %rcx
+ jne .Lnorm_bad
+ movb $0, 8(%rsi)
+ xor %eax, %eax
+ ret
+.Lnorm_bad:
+ movb $0, (%rsi)
+ mov $CEPIS_ERR_INVALID_CEP, %eax
+ ret
+.Lnorm_usage:
+ mov $CEPIS_ERR_USAGE, %eax
+ ret
+ENDFUNC cepis_normalize_cep
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/src/client.S b/src/client.S
new file mode 100644
index 0000000..469f0f2
--- /dev/null
+++ b/src/client.S
@@ -0,0 +1,879 @@
+#include "abi.inc"
+#include "defs.inc"
+
+#define LK_URL -72
+#define LK_BODY -96
+#define LK_TMP -112
+#define LK_STATUS -120
+#define LK_MSG -128
+
+#define HL_URL -72
+#define HL_BODY -96
+#define HL_STATUS -104
+
+#define LM_IDX -48
+#define LM_CHUNK -56
+#define LM_SENT -64
+#define LM_MAP -72
+#define LM_ROWS -80
+#define LM_NROWS -88
+#define LM_STATUS -96
+#define LM_TMP -112
+#define LM_URL -136
+#define LM_BODY -160
+#define LM_J -168
+#define LM_K -176
+
+#define JF_KEY -48
+#define JF_VAL -56
+#define JF_OUT -64
+
+ .text
+
+PUBFUNC cepis_version
+ lea .Ls_version(%rip), %rax
+ ret
+ENDFUNC cepis_version
+
+PUBFUNC cepis_strerror
+ lea cepis__errnames(%rip), %rax
+ cmp $0, %edi
+ jl .Lse_unknown
+ cmp $8, %edi
+ jg .Lse_unknown
+ movslq %edi, %rdi
+ mov (%rax, %rdi, 8), %rax
+ ret
+.Lse_unknown:
+ lea .Ls_unknown(%rip), %rax
+ ret
+ENDFUNC cepis_strerror
+
+FUNC cepis__err_reset
+ test %rdi, %rdi
+ jz .Ler_out
+ movl $0, E_STATUS(%rdi)
+ movl $0, E_HTTP_STATUS(%rdi)
+ movq $0, E_RETRY_AFTER(%rdi)
+ movb $0, E_MESSAGE(%rdi)
+.Ler_out:
+ ret
+ENDFUNC cepis__err_reset
+
+FUNC cepis__err_set
+ PROLOGUE 8
+ test %rdi, %rdi
+ jz .Les_out
+ mov %esi, E_STATUS(%rdi)
+ mov %rdx, %r10
+ lea E_MESSAGE(%rdi), %rdi
+ mov $E_MSGLEN, %esi
+ mov %r10, %rdx
+ xor %eax, %eax
+ call snprintf@PLT
+.Les_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis__err_set
+
+FUNC cepis__json_field
+ PROLOGUE 40
+ mov %rsi, %r15
+ movq $0, JF_KEY(%rbp)
+ movq $0, JF_VAL(%rbp)
+ movq $0, JF_OUT(%rbp)
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $'{', (%r12)
+ jne .Ljf_out
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $'}', (%r12)
+ je .Ljf_out
+.Ljf_pair:
+ cmpb $'"', (%r12)
+ jne .Ljf_out
+ mov %r12, %rdi
+ lea JF_KEY(%rbp), %rsi
+ call cepis__js_string
+ test %rax, %rax
+ jz .Ljf_out
+ mov %rax, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $':', (%r12)
+ jne .Ljf_out
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpq $0, JF_OUT(%rbp)
+ jne .Ljf_skip
+ mov JF_KEY(%rbp), %rdi
+ mov %r15, %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jnz .Ljf_skip
+ movzbl (%r12), %eax
+ cmp $'{', %al
+ je .Ljf_skip
+ cmp $'[', %al
+ je .Ljf_skip
+ mov %r12, %rdi
+ lea JF_VAL(%rbp), %rsi
+ call cepis__js_scalar_text
+ test %rax, %rax
+ jz .Ljf_out
+ mov %rax, %r12
+ mov JF_VAL(%rbp), %rax
+ mov %rax, JF_OUT(%rbp)
+ jmp .Ljf_next
+.Ljf_skip:
+ mov %r12, %rdi
+ call cepis__js_skip
+ test %rax, %rax
+ jz .Ljf_out
+ mov %rax, %r12
+.Ljf_next:
+ mov JF_KEY(%rbp), %rdi
+ call free@PLT
+ movq $0, JF_KEY(%rbp)
+ mov %r12, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $',', (%r12)
+ jne .Ljf_out
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ jmp .Ljf_pair
+.Ljf_out:
+ mov JF_KEY(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Ljf_ret
+ call free@PLT
+.Ljf_ret:
+ mov JF_OUT(%rbp), %rax
+ EPILOGUE
+ ret
+ENDFUNC cepis__json_field
+
+PUBFUNC cepis_client_new
+ PROLOGUE 40
+ mov %rsi, %r14
+ test %r14, %r14
+ jz .Lcn_usage
+ movq $0, (%r14)
+ mov %rdi, %r15
+ test %r15, %r15
+ jz .Lcn_alloc
+ mov C_MAX_ATTEMPTS(%r15), %eax
+ cmp $0, %eax
+ jl .Lcn_usage
+.Lcn_alloc:
+ mov $1, %rdi
+ mov $CL_SIZE, %rsi
+ call calloc@PLT
+ test %rax, %rax
+ jz .Lcn_nomem
+ mov %rax, %rbx
+ lea .Ls_default_url(%rip), %r12
+ test %r15, %r15
+ jz .Lcn_url
+ mov C_BASE_URL(%r15), %rax
+ test %rax, %rax
+ jz .Lcn_url
+ mov %rax, %r12
+.Lcn_url:
+ mov %r12, %rdi
+ call cepis__strdup
+ test %rax, %rax
+ jz .Lcn_nomem_free
+ mov %rax, CL_BASE_URL(%rbx)
+ mov %rax, %rdi
+ call strlen@PLT
+ mov CL_BASE_URL(%rbx), %rdx
+.Lcn_strip:
+ test %rax, %rax
+ jz .Lcn_ua
+ cmpb $'/', -1(%rdx, %rax, 1)
+ jne .Lcn_ua
+ dec %rax
+ movb $0, (%rdx, %rax, 1)
+ jmp .Lcn_strip
+.Lcn_ua:
+ lea .Ls_default_ua(%rip), %r12
+ test %r15, %r15
+ jz .Lcn_ua_dup
+ mov C_USER_AGENT(%r15), %rax
+ test %rax, %rax
+ jz .Lcn_ua_dup
+ mov %rax, %r12
+.Lcn_ua_dup:
+ mov %r12, %rdi
+ call cepis__strdup
+ test %rax, %rax
+ jz .Lcn_nomem_free
+ mov %rax, CL_USER_AGENT(%rbx)
+ movsd .Ld_timeout(%rip), %xmm0
+ movl $3, %eax
+ mov %eax, CL_MAX_ATTEMPTS(%rbx)
+ movsd %xmm0, CL_TIMEOUT(%rbx)
+ movsd .Ld_backoff_base(%rip), %xmm0
+ movsd %xmm0, CL_BACKOFF_BASE(%rbx)
+ movsd .Ld_backoff_max(%rip), %xmm0
+ movsd %xmm0, CL_BACKOFF_MAX(%rbx)
+ xorpd %xmm0, %xmm0
+ movsd %xmm0, CL_TOTAL_TIMEOUT(%rbx)
+ test %r15, %r15
+ jz .Lcn_seed
+ movsd C_TIMEOUT(%r15), %xmm0
+ xorpd %xmm1, %xmm1
+ comisd %xmm1, %xmm0
+ jbe .Lcn_attempts
+ movsd %xmm0, CL_TIMEOUT(%rbx)
+.Lcn_attempts:
+ mov C_MAX_ATTEMPTS(%r15), %eax
+ test %eax, %eax
+ jz .Lcn_bbase
+ mov %eax, CL_MAX_ATTEMPTS(%rbx)
+.Lcn_bbase:
+ movsd C_BACKOFF_BASE(%r15), %xmm0
+ xorpd %xmm1, %xmm1
+ comisd %xmm1, %xmm0
+ jbe .Lcn_bmax
+ movsd %xmm0, CL_BACKOFF_BASE(%rbx)
+.Lcn_bmax:
+ movsd C_BACKOFF_MAX(%r15), %xmm0
+ xorpd %xmm1, %xmm1
+ comisd %xmm1, %xmm0
+ jbe .Lcn_total
+ movsd %xmm0, CL_BACKOFF_MAX(%rbx)
+.Lcn_total:
+ movsd C_TOTAL_TIMEOUT(%r15), %xmm0
+ xorpd %xmm1, %xmm1
+ comisd %xmm1, %xmm0
+ jbe .Lcn_seed
+ movsd %xmm0, CL_TOTAL_TIMEOUT(%rbx)
+.Lcn_seed:
+ xor %edi, %edi
+ lea LOCAL1(%rbp), %rsi
+ call clock_gettime@PLT
+ mov LOCAL1(%rbp), %rax
+ mov LOCAL0(%rbp), %rdx
+ imul $1000000007, %rax, %rax
+ xor %rdx, %rax
+ xor %rbx, %rax
+ mov $1, %rdx
+ lock xadd %rdx, cepis__seed_counter(%rip)
+ imul $1103515245, %rdx, %rdx
+ xor %rdx, %rax
+ test %rax, %rax
+ jnz .Lcn_store_seed
+ movabs $0x9E3779B97F4A7C15, %rax
+.Lcn_store_seed:
+ mov %rax, CL_RNG(%rbx)
+ mov %rbx, (%r14)
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lcn_nomem_free:
+ mov %rbx, %rdi
+ call cepis_client_free
+.Lcn_nomem:
+ mov $CEPIS_ERR_NOMEM, %eax
+ EPILOGUE
+ ret
+.Lcn_usage:
+ mov $CEPIS_ERR_USAGE, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis_client_new
+
+PUBFUNC cepis_client_free
+ PROLOGUE 8
+ test %rdi, %rdi
+ jz .Lcf_out
+ mov %rdi, %rbx
+ mov CL_BASE_URL(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lcf_ua
+ call free@PLT
+.Lcf_ua:
+ mov CL_USER_AGENT(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lcf_self
+ call free@PLT
+.Lcf_self:
+ mov %rbx, %rdi
+ call free@PLT
+.Lcf_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis_client_free
+
+PUBFUNC cepis_default_client
+ PROLOGUE 24
+ mov cepis__default_client(%rip), %rax
+ test %rax, %rax
+ jnz .Ldc_out
+ xor %edi, %edi
+ lea LOCAL0(%rbp), %rsi
+ call cepis_client_new
+ test %eax, %eax
+ jnz .Ldc_fail
+ mov LOCAL0(%rbp), %rbx
+ xor %eax, %eax
+ lock cmpxchgq %rbx, cepis__default_client(%rip)
+ jz .Ldc_won
+ mov %rax, %r12
+ mov %rbx, %rdi
+ call cepis_client_free
+ mov %r12, %rax
+ EPILOGUE
+ ret
+.Ldc_won:
+ mov %rbx, %rax
+.Ldc_out:
+ EPILOGUE
+ ret
+.Ldc_fail:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis_default_client
+
+FUNC cepis__default_client_destroy
+ PROLOGUE 8
+ xor %eax, %eax
+ xchg %rax, cepis__default_client(%rip)
+ test %rax, %rax
+ jz .Ldd_out
+ mov %rax, %rdi
+ call cepis_client_free
+.Ldd_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis__default_client_destroy
+
+FUNC cepis__resolve
+ test %rdi, %rdi
+ jz .Lrc_default
+ mov %rdi, %rax
+ ret
+.Lrc_default:
+ jmp cepis_default_client
+ENDFUNC cepis__resolve
+
+PUBFUNC cepis_lookup
+ PROLOGUE 88
+ mov %rdi, %rbx
+ mov %rsi, %r13
+ mov %rdx, %r14
+ mov %rcx, %r15
+ test %r14, %r14
+ jz .Llk_usage
+ movq $0, (%r14)
+ mov %r15, %rdi
+ call cepis__err_reset
+ mov %rbx, %rdi
+ call cepis__resolve
+ test %rax, %rax
+ jz .Llk_nomem_bare
+ mov %rax, %rbx
+ movq $0, LK_URL(%rbp)
+ movq $0, LK_URL+8(%rbp)
+ movq $0, LK_URL+16(%rbp)
+ movq $0, LK_BODY(%rbp)
+ movq $0, LK_BODY+8(%rbp)
+ movq $0, LK_BODY+16(%rbp)
+ mov %r13, %rdi
+ lea LK_TMP(%rbp), %rsi
+ call cepis_normalize_cep
+ test %eax, %eax
+ jnz .Llk_invalid_input
+ lea LK_URL(%rbp), %rdi
+ mov CL_BASE_URL(%rbx), %rsi
+ call cepis__buf_appendz
+ test %eax, %eax
+ jnz .Llk_nomem
+ lea LK_URL(%rbp), %rdi
+ mov $'/', %esi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Llk_nomem
+ lea LK_URL(%rbp), %rdi
+ lea LK_TMP(%rbp), %rsi
+ call cepis__buf_appendz
+ test %eax, %eax
+ jnz .Llk_nomem
+ mov %rbx, %rdi
+ mov LK_URL(%rbp), %rsi
+ xor %edx, %edx
+ lea LK_STATUS(%rbp), %rcx
+ lea LK_BODY(%rbp), %r8
+ mov %r15, %r9
+ call cepis__http_get
+ test %eax, %eax
+ jnz .Llk_httperr
+ mov LK_STATUS(%rbp), %eax
+ cmp $404, %eax
+ je .Llk_notfound
+ cmp $400, %eax
+ je .Llk_badcep
+ cmp $200, %eax
+ jne .Llk_badresp
+ mov LK_BODY(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llk_badresp
+ mov %r14, %rsi
+ call cepis__address_from_json
+ mov %eax, %r12d
+ test %eax, %eax
+ jz .Llk_done
+ cmp $CEPIS_ERR_NOMEM, %eax
+ je .Llk_nomem
+ mov %r15, %rdi
+ mov $CEPIS_ERR_INVALID_RESPONSE, %esi
+ lea .Lfmt_badjson(%rip), %rdx
+ mov LK_URL(%rbp), %rcx
+ xor %r8d, %r8d
+ call cepis__err_set
+ mov $CEPIS_ERR_INVALID_RESPONSE, %r12d
+ jmp .Llk_ret
+.Llk_done:
+ xor %r12d, %r12d
+.Llk_ret:
+ lea LK_URL(%rbp), %rdi
+ call cepis__buf_free
+ lea LK_BODY(%rbp), %rdi
+ call cepis__buf_free
+ mov %r12d, %eax
+ EPILOGUE
+ ret
+.Llk_httperr:
+ mov %eax, %r12d
+ jmp .Llk_ret
+.Llk_notfound:
+ mov %r15, %rdi
+ mov $CEPIS_ERR_NOT_FOUND, %esi
+ lea .Lfmt_notfound(%rip), %rdx
+ lea LK_TMP(%rbp), %rcx
+ xor %r8d, %r8d
+ call cepis__err_set
+ mov $CEPIS_ERR_NOT_FOUND, %r12d
+ jmp .Llk_ret
+.Llk_badcep:
+ movq $0, LK_MSG(%rbp)
+ mov LK_BODY(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llk_badcep_msg
+ lea .Ls_mensagem(%rip), %rsi
+ call cepis__json_field
+ mov %rax, LK_MSG(%rbp)
+.Llk_badcep_msg:
+ mov LK_MSG(%rbp), %r8
+ test %r8, %r8
+ jnz .Llk_badcep_emit
+ lea .Ls_rejected(%rip), %r8
+.Llk_badcep_emit:
+ mov %r15, %rdi
+ mov $CEPIS_ERR_INVALID_CEP, %esi
+ lea .Lfmt_badcep(%rip), %rdx
+ lea LK_TMP(%rbp), %rcx
+ call cepis__err_set
+ mov LK_MSG(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llk_badcep_done
+ call free@PLT
+.Llk_badcep_done:
+ mov $CEPIS_ERR_INVALID_CEP, %r12d
+ jmp .Llk_ret
+.Llk_badresp:
+ mov %r15, %rdi
+ mov $CEPIS_ERR_INVALID_RESPONSE, %esi
+ lea .Lfmt_status(%rip), %rdx
+ mov LK_STATUS(%rbp), %ecx
+ mov LK_URL(%rbp), %r8
+ call cepis__err_set
+ mov $CEPIS_ERR_INVALID_RESPONSE, %r12d
+ jmp .Llk_ret
+.Llk_invalid_input:
+ mov %r15, %rdi
+ mov $CEPIS_ERR_INVALID_CEP, %esi
+ lea .Lfmt_notdigits(%rip), %rdx
+ mov %r13, %rcx
+ test %rcx, %rcx
+ jnz .Llk_invalid_emit
+ lea .Ls_nullstr(%rip), %rcx
+.Llk_invalid_emit:
+ xor %r8d, %r8d
+ call cepis__err_set
+ mov $CEPIS_ERR_INVALID_CEP, %r12d
+ jmp .Llk_ret
+.Llk_nomem:
+ mov $CEPIS_ERR_NOMEM, %r12d
+ jmp .Llk_ret
+.Llk_nomem_bare:
+ mov $CEPIS_ERR_NOMEM, %eax
+ EPILOGUE
+ ret
+.Llk_usage:
+ mov $CEPIS_ERR_USAGE, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis_lookup
+
+PUBFUNC cepis_health
+ PROLOGUE 72
+ mov %rdi, %rbx
+ mov %rsi, %r14
+ mov %rdx, %r15
+ test %r14, %r14
+ jz .Lhl_usage
+ movq $0, (%r14)
+ mov %r15, %rdi
+ call cepis__err_reset
+ mov %rbx, %rdi
+ call cepis__resolve
+ test %rax, %rax
+ jz .Lhl_nomem_bare
+ mov %rax, %rbx
+ movq $0, HL_URL(%rbp)
+ movq $0, HL_URL+8(%rbp)
+ movq $0, HL_URL+16(%rbp)
+ movq $0, HL_BODY(%rbp)
+ movq $0, HL_BODY+8(%rbp)
+ movq $0, HL_BODY+16(%rbp)
+ lea HL_URL(%rbp), %rdi
+ mov CL_BASE_URL(%rbx), %rsi
+ call cepis__buf_appendz
+ test %eax, %eax
+ jnz .Lhl_nomem
+ lea HL_URL(%rbp), %rdi
+ lea .Ls_health_path(%rip), %rsi
+ call cepis__buf_appendz
+ test %eax, %eax
+ jnz .Lhl_nomem
+ mov %rbx, %rdi
+ mov HL_URL(%rbp), %rsi
+ mov $1, %edx
+ lea HL_STATUS(%rbp), %rcx
+ lea HL_BODY(%rbp), %r8
+ mov %r15, %r9
+ call cepis__http_get
+ test %eax, %eax
+ jnz .Lhl_httperr
+ mov HL_BODY(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Lhl_badresp
+ mov %r14, %rsi
+ call cepis__health_from_json
+ mov %eax, %r12d
+ test %eax, %eax
+ jz .Lhl_ret
+ cmp $CEPIS_ERR_NOMEM, %eax
+ je .Lhl_nomem
+ jmp .Lhl_badresp
+.Lhl_ret:
+ lea HL_URL(%rbp), %rdi
+ call cepis__buf_free
+ lea HL_BODY(%rbp), %rdi
+ call cepis__buf_free
+ mov %r12d, %eax
+ EPILOGUE
+ ret
+.Lhl_httperr:
+ mov %eax, %r12d
+ jmp .Lhl_ret
+.Lhl_badresp:
+ mov %r15, %rdi
+ mov $CEPIS_ERR_INVALID_RESPONSE, %esi
+ lea .Lfmt_badjson(%rip), %rdx
+ mov HL_URL(%rbp), %rcx
+ xor %r8d, %r8d
+ call cepis__err_set
+ mov $CEPIS_ERR_INVALID_RESPONSE, %r12d
+ jmp .Lhl_ret
+.Lhl_nomem:
+ mov $CEPIS_ERR_NOMEM, %r12d
+ jmp .Lhl_ret
+.Lhl_nomem_bare:
+ mov $CEPIS_ERR_NOMEM, %eax
+ EPILOGUE
+ ret
+.Lhl_usage:
+ mov $CEPIS_ERR_USAGE, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis_health
+
+PUBFUNC cepis_lookup_many
+ PROLOGUE 136
+ mov %rdi, %rbx
+ mov %rsi, %r12
+ mov %rdx, %r13
+ mov %rcx, %r14
+ mov %r8, %r15
+ test %r14, %r14
+ jz .Llm_usage
+ movq $0, (%r14)
+ mov %r15, %rdi
+ call cepis__err_reset
+ test %r13, %r13
+ jz .Llm_check_ptr
+ test %r12, %r12
+ jz .Llm_usage
+.Llm_check_ptr:
+ mov %rbx, %rdi
+ call cepis__resolve
+ test %rax, %rax
+ jz .Llm_nomem_bare
+ mov %rax, %rbx
+ mov %r13, %rdi
+ test %rdi, %rdi
+ jnz .Llm_alloc
+ mov $1, %rdi
+.Llm_alloc:
+ mov $8, %rsi
+ call calloc@PLT
+ test %rax, %rax
+ jz .Llm_nomem_bare
+ mov %rax, (%r14)
+ movq $0, LM_MAP(%rbp)
+ movq $0, LM_ROWS(%rbp)
+ movq $0, LM_URL(%rbp)
+ movq $0, LM_URL+8(%rbp)
+ movq $0, LM_URL+16(%rbp)
+ movq $0, LM_BODY(%rbp)
+ movq $0, LM_BODY+8(%rbp)
+ movq $0, LM_BODY+16(%rbp)
+ movq $0, LM_IDX(%rbp)
+.Llm_chunk:
+ mov LM_IDX(%rbp), %rax
+ cmp %r13, %rax
+ jae .Llm_done
+ mov %r13, %rcx
+ sub %rax, %rcx
+ cmp $CEPIS_MAX_BATCH, %rcx
+ jbe .Llm_chunk_set
+ mov $CEPIS_MAX_BATCH, %rcx
+.Llm_chunk_set:
+ mov %rcx, LM_CHUNK(%rbp)
+ mov %rcx, %rdi
+ mov $8, %rsi
+ call calloc@PLT
+ test %rax, %rax
+ jz .Llm_nomem
+ mov %rax, LM_MAP(%rbp)
+ lea LM_URL(%rbp), %rdi
+ call cepis__buf_reset
+ lea LM_URL(%rbp), %rdi
+ mov CL_BASE_URL(%rbx), %rsi
+ call cepis__buf_appendz
+ test %eax, %eax
+ jnz .Llm_nomem
+ lea LM_URL(%rbp), %rdi
+ lea .Ls_csv_path(%rip), %rsi
+ call cepis__buf_appendz
+ test %eax, %eax
+ jnz .Llm_nomem
+ movq $0, LM_SENT(%rbp)
+ movq $0, LM_J(%rbp)
+.Llm_build:
+ mov LM_J(%rbp), %rax
+ cmp LM_CHUNK(%rbp), %rax
+ jae .Llm_request
+ add LM_IDX(%rbp), %rax
+ mov (%r12, %rax, 8), %rdi
+ lea LM_TMP(%rbp), %rsi
+ call cepis_normalize_cep
+ test %eax, %eax
+ jnz .Llm_build_next
+ cmpq $0, LM_SENT(%rbp)
+ je .Llm_build_first
+ lea LM_URL(%rbp), %rdi
+ mov $',', %esi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Llm_nomem
+.Llm_build_first:
+ lea LM_URL(%rbp), %rdi
+ lea LM_TMP(%rbp), %rsi
+ call cepis__buf_appendz
+ test %eax, %eax
+ jnz .Llm_nomem
+ mov LM_J(%rbp), %rax
+ add LM_IDX(%rbp), %rax
+ mov LM_MAP(%rbp), %rcx
+ mov LM_SENT(%rbp), %rdx
+ mov %rax, (%rcx, %rdx, 8)
+ incq LM_SENT(%rbp)
+.Llm_build_next:
+ incq LM_J(%rbp)
+ jmp .Llm_build
+.Llm_request:
+ cmpq $0, LM_SENT(%rbp)
+ je .Llm_next_chunk
+ lea LM_BODY(%rbp), %rdi
+ call cepis__buf_reset
+ mov %rbx, %rdi
+ mov LM_URL(%rbp), %rsi
+ xor %edx, %edx
+ lea LM_STATUS(%rbp), %rcx
+ lea LM_BODY(%rbp), %r8
+ mov %r15, %r9
+ call cepis__http_get
+ test %eax, %eax
+ jnz .Llm_fail
+ cmpl $200, LM_STATUS(%rbp)
+ jne .Llm_badstatus
+ mov LM_BODY(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llm_badstatus
+ lea LM_ROWS(%rbp), %rsi
+ lea LM_NROWS(%rbp), %rdx
+ call cepis__csv_addresses
+ test %eax, %eax
+ jnz .Llm_fail
+ movq $0, LM_K(%rbp)
+.Llm_assign:
+ mov LM_K(%rbp), %rax
+ cmp LM_SENT(%rbp), %rax
+ jae .Llm_drop_extra
+ cmp LM_NROWS(%rbp), %rax
+ jae .Llm_drop_extra
+ mov LM_ROWS(%rbp), %rcx
+ mov (%rcx, %rax, 8), %rdx
+ movq $0, (%rcx, %rax, 8)
+ mov LM_MAP(%rbp), %rcx
+ mov (%rcx, %rax, 8), %rcx
+ mov (%r14), %rsi
+ mov %rdx, (%rsi, %rcx, 8)
+ incq LM_K(%rbp)
+ jmp .Llm_assign
+.Llm_drop_extra:
+ mov LM_ROWS(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llm_free_map
+ mov LM_NROWS(%rbp), %rsi
+ call cepis_address_list_free
+ movq $0, LM_ROWS(%rbp)
+ movq $0, LM_NROWS(%rbp)
+.Llm_free_map:
+ mov LM_MAP(%rbp), %rdi
+ call free@PLT
+ movq $0, LM_MAP(%rbp)
+.Llm_next_chunk:
+ mov LM_MAP(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llm_advance
+ call free@PLT
+ movq $0, LM_MAP(%rbp)
+.Llm_advance:
+ mov LM_CHUNK(%rbp), %rax
+ add %rax, LM_IDX(%rbp)
+ jmp .Llm_chunk
+.Llm_done:
+ lea LM_URL(%rbp), %rdi
+ call cepis__buf_free
+ lea LM_BODY(%rbp), %rdi
+ call cepis__buf_free
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Llm_badstatus:
+ mov %r15, %rdi
+ mov $CEPIS_ERR_INVALID_RESPONSE, %esi
+ lea .Lfmt_status(%rip), %rdx
+ mov LM_STATUS(%rbp), %ecx
+ mov LM_URL(%rbp), %r8
+ call cepis__err_set
+ mov $CEPIS_ERR_INVALID_RESPONSE, %eax
+.Llm_fail:
+ mov %eax, %r12d
+ mov LM_ROWS(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llm_fail_map
+ mov LM_NROWS(%rbp), %rsi
+ call cepis_address_list_free
+ movq $0, LM_ROWS(%rbp)
+.Llm_fail_map:
+ mov LM_MAP(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Llm_fail_bufs
+ call free@PLT
+ movq $0, LM_MAP(%rbp)
+.Llm_fail_bufs:
+ lea LM_URL(%rbp), %rdi
+ call cepis__buf_free
+ lea LM_BODY(%rbp), %rdi
+ call cepis__buf_free
+ mov (%r14), %rdi
+ mov %r13, %rsi
+ call cepis_address_list_free
+ movq $0, (%r14)
+ mov %r12d, %eax
+ EPILOGUE
+ ret
+.Llm_nomem:
+ mov $CEPIS_ERR_NOMEM, %eax
+ jmp .Llm_fail
+.Llm_nomem_bare:
+ mov $CEPIS_ERR_NOMEM, %eax
+ EPILOGUE
+ ret
+.Llm_usage:
+ mov $CEPIS_ERR_USAGE, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis_lookup_many
+
+ .section .rodata
+.Ls_version: .asciz "0.1.0"
+.Ls_default_url: .asciz "https://cep.is"
+.Ls_default_ua: .asciz "cepis-asm/0.1.0 (+https://cep.is)"
+.Ls_health_path: .asciz "/health"
+.Ls_csv_path: .asciz "/csv?ceps="
+.Ls_mensagem: .asciz "mensagem"
+.Ls_rejected: .asciz "rejected by the API"
+.Ls_nullstr: .asciz "(null)"
+.Ls_unknown: .asciz "unknown error"
+.Lfmt_notfound: .asciz "CEP %s does not exist in the DNE database"
+.Lfmt_badcep: .asciz "CEP %s rejected: %s"
+.Lfmt_notdigits: .asciz "CEP must be 8 digits, got \"%s\""
+.Lfmt_badjson: .asciz "unparseable response from %s"
+.Lfmt_status: .asciz "unexpected status %d from %s"
+
+.Le_ok: .asciz "ok"
+.Le_invalid: .asciz "invalid CEP"
+.Le_notfound: .asciz "CEP not found"
+.Le_rate: .asciz "rate limited"
+.Le_server: .asciz "server error"
+.Le_network: .asciz "network error"
+.Le_badresp: .asciz "invalid response"
+.Le_nomem: .asciz "out of memory"
+.Le_usage: .asciz "invalid argument"
+
+ .section .data.rel.ro,"aw",@progbits
+ .p2align 3
+cepis__errnames:
+ .quad .Le_ok, .Le_invalid, .Le_notfound, .Le_rate, .Le_server
+ .quad .Le_network, .Le_badresp, .Le_nomem, .Le_usage
+
+ .section .rodata
+ .p2align 3
+.Ld_timeout: .double 10.0
+.Ld_backoff_base: .double 0.5
+.Ld_backoff_max: .double 8.0
+
+ .data
+ .p2align 3
+ .globl cepis__default_client
+ .hidden cepis__default_client
+cepis__default_client:
+ .quad 0
+cepis__seed_counter:
+ .quad 0
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/src/csv.S b/src/csv.S
new file mode 100644
index 0000000..9c16a8e
--- /dev/null
+++ b/src/csv.S
@@ -0,0 +1,297 @@
+#include "abi.inc"
+#include "defs.inc"
+
+#define CBUF -72
+
+#define CA_ROWS -72
+#define CA_STATE -80
+#define CA_NF -88
+#define CA_FIELDS -344
+#define CA_MAP -472
+
+ .text
+
+FUNC cepis__csv_row
+ PROLOGUE 56
+ mov %rdi, %rbx
+ mov %rsi, %r14
+ mov %rdx, %r15
+ movl $0, (%r15)
+ mov (%rbx), %r12
+ cmpb $0, (%r12)
+ je .Lrow_eof
+ xor %r13d, %r13d
+.Lfield:
+ cmpb $'"', (%r12)
+ je .Lquoted
+ mov %r12, %rax
+.Lbare_scan:
+ movzbl (%rax), %ecx
+ test %cl, %cl
+ jz .Lbare_end
+ cmp $',', %cl
+ je .Lbare_end
+ cmp $10, %cl
+ je .Lbare_end
+ cmp $13, %cl
+ je .Lbare_end
+ inc %rax
+ jmp .Lbare_scan
+.Lbare_end:
+ mov %rax, LOCAL0(%rbp)
+ mov %rax, %rsi
+ sub %r12, %rsi
+ mov %r12, %rdi
+ call cepis__strndup
+ test %rax, %rax
+ jz .Lrow_err
+ mov LOCAL0(%rbp), %r12
+ jmp .Lstore
+.Lquoted:
+ movq $0, CBUF(%rbp)
+ movq $0, CBUF+8(%rbp)
+ movq $0, CBUF+16(%rbp)
+ inc %r12
+.Lq_loop:
+ movzbl (%r12), %eax
+ test %al, %al
+ jz .Lq_done
+ cmp $'"', %al
+ je .Lq_quote
+ lea CBUF(%rbp), %rdi
+ movzbl (%r12), %esi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lq_err
+ inc %r12
+ jmp .Lq_loop
+.Lq_quote:
+ cmpb $'"', 1(%r12)
+ jne .Lq_close
+ lea CBUF(%rbp), %rdi
+ mov $'"', %esi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lq_err
+ add $2, %r12
+ jmp .Lq_loop
+.Lq_close:
+ inc %r12
+.Lq_skip:
+ movzbl (%r12), %eax
+ test %al, %al
+ jz .Lq_done
+ cmp $',', %al
+ je .Lq_done
+ cmp $10, %al
+ je .Lq_done
+ cmp $13, %al
+ je .Lq_done
+ inc %r12
+ jmp .Lq_skip
+.Lq_done:
+ cmpq $0, CBUF(%rbp)
+ jne .Lq_take
+ call cepis__empty
+ test %rax, %rax
+ jz .Lrow_err
+ jmp .Lstore
+.Lq_take:
+ lea CBUF(%rbp), %rdi
+ call cepis__buf_take
+.Lstore:
+ cmp $32, %r13
+ jae .Ldrop
+ mov %rax, (%r14, %r13, 8)
+ inc %r13
+ jmp .Lsep
+.Ldrop:
+ mov %rax, %rdi
+ call free@PLT
+.Lsep:
+ movzbl (%r12), %eax
+ cmp $',', %al
+ jne .Lrow_end
+ inc %r12
+ jmp .Lfield
+.Lrow_end:
+ cmpb $13, (%r12)
+ jne .Lrow_nl
+ inc %r12
+.Lrow_nl:
+ cmpb $10, (%r12)
+ jne .Lrow_fin
+ inc %r12
+.Lrow_fin:
+ mov %r12, (%rbx)
+ mov %r13d, (%r15)
+ mov $1, %eax
+ EPILOGUE
+ ret
+.Lrow_eof:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lq_err:
+ lea CBUF(%rbp), %rdi
+ call cepis__buf_free
+.Lrow_err:
+ xor %r12d, %r12d
+.Lrow_err_loop:
+ cmp %r13, %r12
+ jae .Lrow_err_out
+ mov (%r14, %r12, 8), %rdi
+ call free@PLT
+ inc %r12
+ jmp .Lrow_err_loop
+.Lrow_err_out:
+ movl $0, (%r15)
+ mov $-1, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__csv_row
+
+FUNC cepis__csv_addresses
+ PROLOGUE 440
+ mov %rsi, %r14
+ mov %rdx, %r15
+ movq $0, (%r14)
+ movq $0, (%r15)
+ movq $0, CA_ROWS(%rbp)
+ movq $0, CA_ROWS+8(%rbp)
+ movq $0, CA_ROWS+16(%rbp)
+ cmpb $0xEF, (%rdi)
+ jne .Lca_nobom
+ cmpb $0xBB, 1(%rdi)
+ jne .Lca_nobom
+ cmpb $0xBF, 2(%rdi)
+ jne .Lca_nobom
+ add $3, %rdi
+.Lca_nobom:
+ mov %rdi, CA_STATE(%rbp)
+ lea CA_STATE(%rbp), %rdi
+ lea CA_FIELDS(%rbp), %rsi
+ lea CA_NF(%rbp), %rdx
+ call cepis__csv_row
+ cmp $1, %eax
+ je .Lca_header
+ cmp $0, %eax
+ je .Lca_invalid
+ jmp .Lca_nomem
+.Lca_header:
+ xor %r12d, %r12d
+.Lca_hdr_loop:
+ movslq CA_NF(%rbp), %rax
+ cmp %rax, %r12
+ jae .Lca_rows
+ mov CA_FIELDS(%rbp, %r12, 8), %rdi
+ call cepis__addr_field_offset
+ lea CA_MAP(%rbp), %rcx
+ mov %eax, (%rcx, %r12, 4)
+ mov CA_FIELDS(%rbp, %r12, 8), %rdi
+ call free@PLT
+ inc %r12
+ jmp .Lca_hdr_loop
+.Lca_rows:
+ lea CA_STATE(%rbp), %rdi
+ lea CA_FIELDS(%rbp), %rsi
+ lea CA_NF(%rbp), %rdx
+ call cepis__csv_row
+ cmp $1, %eax
+ je .Lca_row
+ cmp $0, %eax
+ je .Lca_done
+ jmp .Lca_nomem
+.Lca_row:
+ cmpl $1, CA_NF(%rbp)
+ jne .Lca_build
+ mov CA_FIELDS(%rbp), %rdi
+ cmpb $0, (%rdi)
+ jne .Lca_build
+ call free@PLT
+ jmp .Lca_rows
+.Lca_build:
+ call cepis__address_new
+ test %rax, %rax
+ jz .Lca_nomem_fields
+ mov %rax, %rbx
+ xor %r12d, %r12d
+.Lca_assign:
+ movslq CA_NF(%rbp), %rax
+ cmp %rax, %r12
+ jae .Lca_check
+ lea CA_MAP(%rbp), %rcx
+ movslq (%rcx, %r12, 4), %r13
+ cmp $0, %r13
+ jl .Lca_assign_drop
+ mov %rbx, %rdi
+ mov %r13, %rsi
+ mov CA_FIELDS(%rbp, %r12, 8), %rdx
+ call cepis__addr_set
+ jmp .Lca_assign_next
+.Lca_assign_drop:
+ mov CA_FIELDS(%rbp, %r12, 8), %rdi
+ call free@PLT
+.Lca_assign_next:
+ inc %r12
+ jmp .Lca_assign
+.Lca_check:
+ mov A_LOCALIDADE(%rbx), %rdi
+ cmpb $0, (%rdi)
+ jne .Lca_push
+ mov %rbx, %rdi
+ call cepis_address_free
+ xor %ebx, %ebx
+.Lca_push:
+ mov %rbx, LOCAL0(%rbp)
+ lea CA_ROWS(%rbp), %rdi
+ lea LOCAL0(%rbp), %rsi
+ mov $8, %rdx
+ call cepis__buf_append
+ test %eax, %eax
+ jnz .Lca_nomem_row
+ jmp .Lca_rows
+.Lca_done:
+ mov CA_ROWS+8(%rbp), %rax
+ shr $3, %rax
+ mov %rax, (%r15)
+ lea CA_ROWS(%rbp), %rdi
+ call cepis__buf_take
+ mov %rax, (%r14)
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lca_nomem_row:
+ mov %rbx, %rdi
+ call cepis_address_free
+ jmp .Lca_nomem
+.Lca_nomem_fields:
+ xor %r12d, %r12d
+.Lca_nmf_loop:
+ movslq CA_NF(%rbp), %rax
+ cmp %rax, %r12
+ jae .Lca_nomem
+ mov CA_FIELDS(%rbp, %r12, 8), %rdi
+ call free@PLT
+ inc %r12
+ jmp .Lca_nmf_loop
+.Lca_nomem:
+ mov $CEPIS_ERR_NOMEM, %r13d
+ jmp .Lca_cleanup
+.Lca_invalid:
+ mov $CEPIS_ERR_INVALID_RESPONSE, %r13d
+.Lca_cleanup:
+ mov CA_ROWS(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Lca_cleanup_done
+ mov CA_ROWS+8(%rbp), %rsi
+ shr $3, %rsi
+ call cepis_address_list_free
+ movq $0, CA_ROWS(%rbp)
+.Lca_cleanup_done:
+ mov %r13d, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__csv_addresses
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/src/defs.inc b/src/defs.inc
new file mode 100644
index 0000000..4a64e0e
--- /dev/null
+++ b/src/defs.inc
@@ -0,0 +1,79 @@
+#ifndef CEPIS_DEFS_INC
+#define CEPIS_DEFS_INC
+
+#define CEPIS_OK 0
+#define CEPIS_ERR_INVALID_CEP 1
+#define CEPIS_ERR_NOT_FOUND 2
+#define CEPIS_ERR_RATE_LIMITED 3
+#define CEPIS_ERR_SERVER 4
+#define CEPIS_ERR_NETWORK 5
+#define CEPIS_ERR_INVALID_RESPONSE 6
+#define CEPIS_ERR_NOMEM 7
+#define CEPIS_ERR_USAGE 8
+
+#define GEO_LAT 0
+#define GEO_LON 8
+#define GEO_RAIO_M 16
+#define GEO_PRECISAO 24
+#define GEO_SIZE 32
+
+#define A_CEP 0
+#define A_LOGRADOURO 8
+#define A_COMPLEMENTO 16
+#define A_UNIDADE 24
+#define A_BAIRRO 32
+#define A_LOCALIDADE 40
+#define A_UF 48
+#define A_ESTADO 56
+#define A_REGIAO 64
+#define A_IBGE 72
+#define A_GIA 80
+#define A_DDD 88
+#define A_SIAFI 96
+#define A_GEO 104
+#define A_RAW 112
+#define A_SIZE 120
+#define A_NFIELDS 13
+
+#define H_STATUS 0
+#define H_DNE 8
+#define H_CEPS 16
+#define H_GEO 24
+#define H_BASE_GERADA 32
+#define H_RAW 40
+#define H_SIZE 48
+
+#define E_STATUS 0
+#define E_HTTP_STATUS 4
+#define E_RETRY_AFTER 8
+#define E_MESSAGE 16
+#define E_MSGLEN 256
+#define E_SIZE 272
+
+#define C_BASE_URL 0
+#define C_TIMEOUT 8
+#define C_MAX_ATTEMPTS 16
+#define C_BACKOFF_BASE 24
+#define C_BACKOFF_MAX 32
+#define C_TOTAL_TIMEOUT 40
+#define C_USER_AGENT 48
+#define C_SIZE 56
+
+#define CL_BASE_URL 0
+#define CL_USER_AGENT 8
+#define CL_TIMEOUT 16
+#define CL_BACKOFF_BASE 24
+#define CL_BACKOFF_MAX 32
+#define CL_TOTAL_TIMEOUT 40
+#define CL_MAX_ATTEMPTS 48
+#define CL_RNG 56
+#define CL_SIZE 64
+
+#define B_DATA 0
+#define B_LEN 8
+#define B_CAP 16
+#define B_SIZE 24
+
+#define CEPIS_MAX_BATCH 500
+
+#endif
diff --git a/src/http.S b/src/http.S
new file mode 100644
index 0000000..9ff6a53
--- /dev/null
+++ b/src/http.S
@@ -0,0 +1,759 @@
+#include "abi.inc"
+#include "defs.inc"
+
+#define CURLOPT_URL 10002
+#define CURLOPT_WRITEFUNCTION 20011
+#define CURLOPT_WRITEDATA 10001
+#define CURLOPT_HEADERFUNCTION 20079
+#define CURLOPT_HEADERDATA 10029
+#define CURLOPT_USERAGENT 10018
+#define CURLOPT_HTTPHEADER 10023
+#define CURLOPT_TIMEOUT_MS 155
+#define CURLOPT_CONNECTTIMEOUT_MS 156
+#define CURLOPT_ACCEPT_ENCODING 10102
+#define CURLOPT_NOSIGNAL 99
+#define CURLOPT_ERRORBUFFER 10010
+#define CURLOPT_FOLLOWLOCATION 52
+#define CURLINFO_RESPONSE_CODE 2097154
+#define CURL_GLOBAL_DEFAULT 3
+#define CURL_ERRSZ 256
+
+#define HC_VALUE 0
+#define HC_HAVE 128
+#define HC_SIZE 136
+
+#define HG_HDR -184
+#define HG_ERRBUF -440
+#define HG_HANDLE -448
+#define HG_SLIST -456
+#define HG_DEADLINE -464
+#define HG_HASDL -472
+#define HG_RA -480
+#define HG_HASRA -488
+#define HG_LASTST -496
+#define HG_CODE -504
+#define HG_ATTEMPT -512
+#define HG_ACC503 -520
+#define HG_OUTST -528
+#define HG_CURLRC -536
+#define HG_WAIT -544
+#define HG_TMPL -552
+
+#define RA_TM -104
+#define RA_END -112
+#define RA_DAY -120
+#define RA_MON -128
+#define RA_YEAR -136
+#define RA_HH -144
+#define RA_MI -152
+#define RA_SS -160
+
+.macro COPT_LONG opt, val
+ mov HG_HANDLE(%rbp), %rdi
+ mov $\opt, %esi
+ mov $\val, %rdx
+ xor %eax, %eax
+ call curl_easy_setopt@PLT
+.endm
+
+.macro COPT_REG opt, reg
+ mov HG_HANDLE(%rbp), %rdi
+ mov $\opt, %esi
+ mov \reg, %rdx
+ xor %eax, %eax
+ call curl_easy_setopt@PLT
+.endm
+
+ .text
+
+PUBFUNC cepis_global_init
+ PROLOGUE 8
+ xor %eax, %eax
+ mov $1, %ecx
+ lock cmpxchgl %ecx, cepis__curl_state(%rip)
+ jne .Lonce_out
+ mov $CURL_GLOBAL_DEFAULT, %edi
+ call curl_global_init@PLT
+ movl $2, cepis__curl_state(%rip)
+.Lonce_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis_global_init
+
+PUBFUNC cepis_global_cleanup
+ PROLOGUE 8
+ call cepis__default_client_destroy
+ cmpl $0, cepis__curl_state(%rip)
+ je .Lgc_out
+ movl $0, cepis__curl_state(%rip)
+ call curl_global_cleanup@PLT
+.Lgc_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis_global_cleanup
+
+FUNC cepis__mono
+ PROLOGUE 24
+ mov $1, %edi
+ lea LOCAL1(%rbp), %rsi
+ call clock_gettime@PLT
+ cvtsi2sdq LOCAL1(%rbp), %xmm0
+ cvtsi2sdq LOCAL0(%rbp), %xmm1
+ mulsd .Lnano(%rip), %xmm1
+ addsd %xmm1, %xmm0
+ EPILOGUE
+ ret
+ENDFUNC cepis__mono
+
+FUNC cepis__sleep
+ PROLOGUE 40
+ xorpd %xmm1, %xmm1
+ comisd %xmm1, %xmm0
+ jbe .Lsleep_out
+ cvttsd2siq %xmm0, %rax
+ mov %rax, LOCAL1(%rbp)
+ cvtsi2sdq %rax, %xmm1
+ subsd %xmm1, %xmm0
+ mulsd .Lgiga(%rip), %xmm0
+ cvttsd2siq %xmm0, %rax
+ cmp $0, %rax
+ jge .Lsleep_store
+ xor %eax, %eax
+.Lsleep_store:
+ mov %rax, LOCAL0(%rbp)
+.Lsleep_call:
+ lea LOCAL1(%rbp), %rdi
+ lea LOCAL3(%rbp), %rsi
+ call nanosleep@PLT
+ test %eax, %eax
+ jz .Lsleep_out
+ call __errno_location@PLT
+ cmpl $4, (%rax)
+ jne .Lsleep_out
+ mov LOCAL3(%rbp), %rax
+ mov %rax, LOCAL1(%rbp)
+ mov LOCAL2(%rbp), %rax
+ mov %rax, LOCAL0(%rbp)
+ jmp .Lsleep_call
+.Lsleep_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis__sleep
+
+FUNC cepis__rand01
+ mov CL_RNG(%rdi), %rax
+.Lrand_loop:
+ mov %rax, %r8
+ mov %r8, %rdx
+ shl $13, %rdx
+ xor %rdx, %r8
+ mov %r8, %rdx
+ shr $7, %rdx
+ xor %rdx, %r8
+ mov %r8, %rdx
+ shl $17, %rdx
+ xor %rdx, %r8
+ lock cmpxchgq %r8, CL_RNG(%rdi)
+ jne .Lrand_loop
+ mov %r8, %rax
+ shr $11, %rax
+ cvtsi2sdq %rax, %xmm0
+ mulsd .Ltwo53(%rip), %xmm0
+ ret
+ENDFUNC cepis__rand01
+
+FUNC cepis__backoff
+ PROLOGUE 24
+ mov %rdi, %rbx
+ test %edx, %edx
+ jz .Lbo_calc
+ movsd CL_BACKOFF_MAX(%rbx), %xmm1
+ minsd %xmm1, %xmm0
+ xorpd %xmm1, %xmm1
+ maxsd %xmm1, %xmm0
+ EPILOGUE
+ ret
+.Lbo_calc:
+ movsd CL_BACKOFF_BASE(%rbx), %xmm0
+ movsd CL_BACKOFF_MAX(%rbx), %xmm1
+ mov %esi, %ecx
+ dec %ecx
+.Lbo_loop:
+ test %ecx, %ecx
+ jle .Lbo_cap
+ comisd %xmm1, %xmm0
+ jae .Lbo_cap
+ addsd %xmm0, %xmm0
+ dec %ecx
+ jmp .Lbo_loop
+.Lbo_cap:
+ minsd %xmm1, %xmm0
+ movsd %xmm0, LOCAL0(%rbp)
+ mov %rbx, %rdi
+ call cepis__rand01
+ mulsd LOCAL0(%rbp), %xmm0
+ EPILOGUE
+ ret
+ENDFUNC cepis__backoff
+
+FUNC cepis__read_uint
+ xor %ecx, %ecx
+ xor %r8d, %r8d
+ movl $0, (%rsi)
+.Lru_loop:
+ cmp %edx, %r8d
+ jae .Lru_end
+ movzbl (%rdi), %eax
+ cmp $'0', %al
+ jb .Lru_end
+ cmp $'9', %al
+ ja .Lru_end
+ sub $'0', %eax
+ imul $10, %ecx, %ecx
+ add %eax, %ecx
+ inc %rdi
+ inc %r8d
+ jmp .Lru_loop
+.Lru_end:
+ test %r8d, %r8d
+ jz .Lru_bad
+ mov %ecx, (%rsi)
+ mov %rdi, %rax
+ ret
+.Lru_bad:
+ xor %eax, %eax
+ ret
+ENDFUNC cepis__read_uint
+
+FUNC cepis__skip_blanks
+.Lsb_loop:
+ movzbl (%rdi), %eax
+ cmp $' ', %al
+ je .Lsb_adv
+ cmp $9, %al
+ je .Lsb_adv
+ mov %rdi, %rax
+ ret
+.Lsb_adv:
+ inc %rdi
+ jmp .Lsb_loop
+ENDFUNC cepis__skip_blanks
+
+FUNC cepis__retry_after
+ PROLOGUE 120
+ mov %rsi, %r14
+ call cepis__skip_blanks
+ mov %rax, %rbx
+ cmpb $0, (%rbx)
+ je .Lra_bad
+ mov %rbx, %rdi
+ lea RA_END(%rbp), %rsi
+ call strtod@PLT
+ mov RA_END(%rbp), %rax
+ cmp %rbx, %rax
+ je .Lra_date
+ movsd %xmm0, LOCAL0(%rbp)
+ mov %rax, %rdi
+ call cepis__skip_blanks
+ movzbl (%rax), %ecx
+ test %cl, %cl
+ jz .Lra_numeric
+ cmp $13, %cl
+ je .Lra_numeric
+ cmp $10, %cl
+ je .Lra_numeric
+ jmp .Lra_date
+.Lra_numeric:
+ movsd LOCAL0(%rbp), %xmm0
+ xorpd %xmm1, %xmm1
+ maxsd %xmm1, %xmm0
+ movsd %xmm0, (%r14)
+ mov $1, %eax
+ EPILOGUE
+ ret
+.Lra_date:
+ mov %rbx, %r12
+.Lra_findnum:
+ movzbl (%r12), %eax
+ test %al, %al
+ jz .Lra_bad
+ cmp $'0', %al
+ jb .Lra_findnum_adv
+ cmp $'9', %al
+ jbe .Lra_day
+.Lra_findnum_adv:
+ inc %r12
+ jmp .Lra_findnum
+.Lra_day:
+ mov %r12, %rdi
+ lea RA_DAY(%rbp), %rsi
+ mov $2, %edx
+ call cepis__read_uint
+ test %rax, %rax
+ jz .Lra_bad
+ mov %rax, %rdi
+ call cepis__skip_blanks
+ mov %rax, %r12
+ xor %r13d, %r13d
+.Lra_mon_loop:
+ cmp $12, %r13d
+ jae .Lra_bad
+ lea cepis__months(%rip), %rax
+ mov (%rax, %r13, 8), %rsi
+ mov %r12, %rdi
+ mov $3, %rdx
+ call strncasecmp@PLT
+ test %eax, %eax
+ jz .Lra_mon_hit
+ inc %r13d
+ jmp .Lra_mon_loop
+.Lra_mon_hit:
+ mov %r13d, RA_MON(%rbp)
+ lea 3(%r12), %rdi
+ call cepis__skip_blanks
+ mov %rax, %rdi
+ lea RA_YEAR(%rbp), %rsi
+ mov $4, %edx
+ call cepis__read_uint
+ test %rax, %rax
+ jz .Lra_bad
+ mov %rax, %rdi
+ call cepis__skip_blanks
+ mov %rax, %rdi
+ lea RA_HH(%rbp), %rsi
+ mov $2, %edx
+ call cepis__read_uint
+ test %rax, %rax
+ jz .Lra_bad
+ cmpb $':', (%rax)
+ jne .Lra_bad
+ lea 1(%rax), %rdi
+ lea RA_MI(%rbp), %rsi
+ mov $2, %edx
+ call cepis__read_uint
+ test %rax, %rax
+ jz .Lra_bad
+ cmpb $':', (%rax)
+ jne .Lra_bad
+ lea 1(%rax), %rdi
+ lea RA_SS(%rbp), %rsi
+ mov $2, %edx
+ call cepis__read_uint
+ test %rax, %rax
+ jz .Lra_bad
+ lea RA_TM(%rbp), %rdi
+ xor %esi, %esi
+ mov $56, %rdx
+ call memset@PLT
+ mov RA_SS(%rbp), %eax
+ mov %eax, RA_TM+0(%rbp)
+ mov RA_MI(%rbp), %eax
+ mov %eax, RA_TM+4(%rbp)
+ mov RA_HH(%rbp), %eax
+ mov %eax, RA_TM+8(%rbp)
+ mov RA_DAY(%rbp), %eax
+ mov %eax, RA_TM+12(%rbp)
+ mov RA_MON(%rbp), %eax
+ mov %eax, RA_TM+16(%rbp)
+ mov RA_YEAR(%rbp), %eax
+ sub $1900, %eax
+ mov %eax, RA_TM+20(%rbp)
+ movl $-1, RA_TM+32(%rbp)
+ lea RA_TM(%rbp), %rdi
+ call timegm@PLT
+ cmp $-1, %rax
+ je .Lra_bad
+ mov %rax, %rbx
+ xor %edi, %edi
+ call time@PLT
+ sub %rax, %rbx
+ cmp $0, %rbx
+ jge .Lra_diff
+ xor %ebx, %ebx
+.Lra_diff:
+ cvtsi2sdq %rbx, %xmm0
+ movsd %xmm0, (%r14)
+ mov $1, %eax
+ EPILOGUE
+ ret
+.Lra_bad:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__retry_after
+
+FUNC cepis__write_cb
+ PROLOGUE 24
+ mov %rdi, %r12
+ mov %rsi, %rax
+ imul %rdx, %rax
+ mov %rax, %r13
+ mov %rcx, %rdi
+ mov %r12, %rsi
+ mov %r13, %rdx
+ call cepis__buf_append
+ test %eax, %eax
+ jnz .Lwcb_fail
+ mov %r13, %rax
+ EPILOGUE
+ ret
+.Lwcb_fail:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__write_cb
+
+FUNC cepis__header_cb
+ PROLOGUE 24
+ mov %rdi, %r12
+ mov %rsi, %rax
+ imul %rdx, %rax
+ mov %rax, %r13
+ mov %rcx, %rbx
+ cmp $12, %r13
+ jb .Lhcb_out
+ mov %r12, %rdi
+ lea .Lhdr_retry_after(%rip), %rsi
+ mov $12, %rdx
+ call strncasecmp@PLT
+ test %eax, %eax
+ jnz .Lhcb_out
+ lea 12(%r12), %r14
+ mov %r12, %r15
+ add %r13, %r15
+.Lhcb_lead:
+ cmp %r15, %r14
+ jae .Lhcb_copy
+ movzbl (%r14), %eax
+ cmp $' ', %al
+ je .Lhcb_lead_adv
+ cmp $9, %al
+ jne .Lhcb_trail
+.Lhcb_lead_adv:
+ inc %r14
+ jmp .Lhcb_lead
+.Lhcb_trail:
+ cmp %r15, %r14
+ jae .Lhcb_copy
+ movzbl -1(%r15), %eax
+ cmp $' ', %al
+ je .Lhcb_trail_adv
+ cmp $9, %al
+ je .Lhcb_trail_adv
+ cmp $13, %al
+ je .Lhcb_trail_adv
+ cmp $10, %al
+ je .Lhcb_trail_adv
+ jmp .Lhcb_copy
+.Lhcb_trail_adv:
+ dec %r15
+ jmp .Lhcb_trail
+.Lhcb_copy:
+ mov %r15, %rdx
+ sub %r14, %rdx
+ cmp $127, %rdx
+ jbe .Lhcb_do
+ mov $127, %rdx
+.Lhcb_do:
+ mov %rdx, LOCAL0(%rbp)
+ mov %rbx, %rdi
+ mov %r14, %rsi
+ call memcpy@PLT
+ mov LOCAL0(%rbp), %rdx
+ movb $0, (%rbx, %rdx, 1)
+ movl $1, HC_HAVE(%rbx)
+.Lhcb_out:
+ mov %r13, %rax
+ EPILOGUE
+ ret
+ENDFUNC cepis__header_cb
+
+FUNC cepis__http_get
+ PROLOGUE 520
+ mov %rdi, %rbx
+ mov %rsi, %r12
+ mov %edx, %eax
+ mov %eax, HG_ACC503(%rbp)
+ mov %rcx, HG_OUTST(%rbp)
+ mov %r8, %r13
+ mov %r9, %r14
+ movl $0, (%rcx)
+ movl $0, HG_LASTST(%rbp)
+ movl $0, HG_HASRA(%rbp)
+ movl $0, HG_CURLRC(%rbp)
+ movq $0, HG_RA(%rbp)
+ movb $0, HG_ERRBUF(%rbp)
+ call cepis_global_init
+ movsd CL_TOTAL_TIMEOUT(%rbx), %xmm0
+ xorpd %xmm1, %xmm1
+ comisd %xmm1, %xmm0
+ jbe .Lhg_nodl
+ call cepis__mono
+ addsd CL_TOTAL_TIMEOUT(%rbx), %xmm0
+ movsd %xmm0, HG_DEADLINE(%rbp)
+ movl $1, HG_HASDL(%rbp)
+ jmp .Lhg_start
+.Lhg_nodl:
+ movl $0, HG_HASDL(%rbp)
+.Lhg_start:
+ movl $1, HG_ATTEMPT(%rbp)
+.Lhg_attempt:
+ cmpl $0, HG_HASDL(%rbp)
+ je .Lhg_go
+ call cepis__mono
+ comisd HG_DEADLINE(%rbp), %xmm0
+ jae .Lhg_exhausted
+.Lhg_go:
+ mov %r13, %rdi
+ call cepis__buf_reset
+ lea HG_HDR(%rbp), %rdi
+ movl $0, HC_HAVE(%rdi)
+ movb $0, HC_VALUE(%rdi)
+ movb $0, HG_ERRBUF(%rbp)
+ movq $0, HG_SLIST(%rbp)
+ call curl_easy_init@PLT
+ test %rax, %rax
+ jz .Lhg_nomem
+ mov %rax, HG_HANDLE(%rbp)
+ xor %edi, %edi
+ lea .Lhdr_accept(%rip), %rsi
+ call curl_slist_append@PLT
+ mov %rax, HG_SLIST(%rbp)
+ COPT_REG CURLOPT_URL, %r12
+ lea cepis__write_cb(%rip), %rax
+ COPT_REG CURLOPT_WRITEFUNCTION, %rax
+ COPT_REG CURLOPT_WRITEDATA, %r13
+ lea cepis__header_cb(%rip), %rax
+ COPT_REG CURLOPT_HEADERFUNCTION, %rax
+ lea HG_HDR(%rbp), %rax
+ COPT_REG CURLOPT_HEADERDATA, %rax
+ mov CL_USER_AGENT(%rbx), %rax
+ COPT_REG CURLOPT_USERAGENT, %rax
+ mov HG_SLIST(%rbp), %rax
+ COPT_REG CURLOPT_HTTPHEADER, %rax
+ lea .Lidentity(%rip), %rax
+ COPT_REG CURLOPT_ACCEPT_ENCODING, %rax
+ lea HG_ERRBUF(%rbp), %rax
+ COPT_REG CURLOPT_ERRORBUFFER, %rax
+ COPT_LONG CURLOPT_NOSIGNAL, 1
+ COPT_LONG CURLOPT_FOLLOWLOCATION, 0
+ movsd CL_TIMEOUT(%rbx), %xmm0
+ mulsd .Lthousand(%rip), %xmm0
+ cvttsd2siq %xmm0, %rax
+ cmp $1, %rax
+ jge .Lhg_tmo
+ mov $1, %rax
+.Lhg_tmo:
+ mov %rax, HG_TMPL(%rbp)
+ COPT_REG CURLOPT_TIMEOUT_MS, %rax
+ mov HG_TMPL(%rbp), %rax
+ COPT_REG CURLOPT_CONNECTTIMEOUT_MS, %rax
+ mov HG_HANDLE(%rbp), %rdi
+ call curl_easy_perform@PLT
+ mov %eax, HG_CURLRC(%rbp)
+ test %eax, %eax
+ jnz .Lhg_network
+ mov HG_HANDLE(%rbp), %rdi
+ mov $CURLINFO_RESPONSE_CODE, %esi
+ lea HG_CODE(%rbp), %rdx
+ xor %eax, %eax
+ call curl_easy_getinfo@PLT
+ mov HG_CODE(%rbp), %rax
+ mov %eax, %r15d
+ cmp $200, %r15d
+ je .Lhg_accept
+ cmpl $0, HG_ACC503(%rbp)
+ je .Lhg_notaccept
+ cmp $503, %r15d
+ je .Lhg_accept
+.Lhg_notaccept:
+ cmp $429, %r15d
+ je .Lhg_retriable
+ cmp $500, %r15d
+ je .Lhg_retriable
+ cmp $502, %r15d
+ je .Lhg_retriable
+ cmp $503, %r15d
+ je .Lhg_retriable
+ cmp $504, %r15d
+ je .Lhg_retriable
+.Lhg_accept:
+ mov HG_OUTST(%rbp), %rax
+ mov %r15d, (%rax)
+ lea HG_HANDLE(%rbp), %rdi
+ lea HG_SLIST(%rbp), %rsi
+ call cepis__curl_release
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lhg_retriable:
+ mov %r15d, HG_LASTST(%rbp)
+ movl $0, HG_HASRA(%rbp)
+ lea HG_HDR(%rbp), %rax
+ cmpl $0, HC_HAVE(%rax)
+ je .Lhg_after
+ lea HG_HDR(%rbp), %rdi
+ lea HG_RA(%rbp), %rsi
+ call cepis__retry_after
+ mov %eax, HG_HASRA(%rbp)
+ jmp .Lhg_after
+.Lhg_network:
+ movl $0, HG_LASTST(%rbp)
+ movl $0, HG_HASRA(%rbp)
+.Lhg_after:
+ lea HG_HANDLE(%rbp), %rdi
+ lea HG_SLIST(%rbp), %rsi
+ call cepis__curl_release
+ mov HG_ATTEMPT(%rbp), %eax
+ cmp CL_MAX_ATTEMPTS(%rbx), %eax
+ jge .Lhg_exhausted
+ mov %rbx, %rdi
+ mov HG_ATTEMPT(%rbp), %esi
+ movsd HG_RA(%rbp), %xmm0
+ mov HG_HASRA(%rbp), %edx
+ call cepis__backoff
+ movsd %xmm0, HG_WAIT(%rbp)
+ cmpl $0, HG_HASDL(%rbp)
+ je .Lhg_sleep
+ call cepis__mono
+ movsd HG_DEADLINE(%rbp), %xmm1
+ subsd %xmm0, %xmm1
+ xorpd %xmm2, %xmm2
+ comisd %xmm2, %xmm1
+ jbe .Lhg_exhausted
+ movsd HG_WAIT(%rbp), %xmm0
+ minsd %xmm1, %xmm0
+ movsd %xmm0, HG_WAIT(%rbp)
+.Lhg_sleep:
+ movsd HG_WAIT(%rbp), %xmm0
+ call cepis__sleep
+ incl HG_ATTEMPT(%rbp)
+ jmp .Lhg_attempt
+.Lhg_exhausted:
+ mov CL_MAX_ATTEMPTS(%rbx), %r15d
+ cmpl $429, HG_LASTST(%rbp)
+ je .Lhg_rate
+ cmpl $0, HG_LASTST(%rbp)
+ jne .Lhg_server
+ test %r14, %r14
+ jz .Lhg_ret_network
+ mov HG_CURLRC(%rbp), %edi
+ call curl_easy_strerror@PLT
+ mov %rax, %r9
+ cmpb $0, HG_ERRBUF(%rbp)
+ je .Lhg_net_msg
+ lea HG_ERRBUF(%rbp), %r9
+.Lhg_net_msg:
+ lea E_MESSAGE(%r14), %rdi
+ mov $E_MSGLEN, %esi
+ lea .Lfmt_network(%rip), %rdx
+ mov %r12, %rcx
+ mov %r15d, %r8d
+ xor %eax, %eax
+ call snprintf@PLT
+ movl $CEPIS_ERR_NETWORK, E_STATUS(%r14)
+.Lhg_ret_network:
+ mov $CEPIS_ERR_NETWORK, %eax
+ EPILOGUE
+ ret
+.Lhg_server:
+ test %r14, %r14
+ jz .Lhg_ret_server
+ mov HG_LASTST(%rbp), %eax
+ mov %eax, E_HTTP_STATUS(%r14)
+ movl $CEPIS_ERR_SERVER, E_STATUS(%r14)
+ lea E_MESSAGE(%r14), %rdi
+ mov $E_MSGLEN, %esi
+ lea .Lfmt_server(%rip), %rdx
+ mov HG_LASTST(%rbp), %ecx
+ mov %r12, %r8
+ mov %r15d, %r9d
+ xor %eax, %eax
+ call snprintf@PLT
+.Lhg_ret_server:
+ mov $CEPIS_ERR_SERVER, %eax
+ EPILOGUE
+ ret
+.Lhg_rate:
+ test %r14, %r14
+ jz .Lhg_ret_rate
+ movl $429, E_HTTP_STATUS(%r14)
+ movl $CEPIS_ERR_RATE_LIMITED, E_STATUS(%r14)
+ cmpl $0, HG_HASRA(%rbp)
+ je .Lhg_rate_msg
+ movsd HG_RA(%rbp), %xmm0
+ movsd %xmm0, E_RETRY_AFTER(%r14)
+.Lhg_rate_msg:
+ lea E_MESSAGE(%r14), %rdi
+ mov $E_MSGLEN, %esi
+ lea .Lfmt_rate(%rip), %rdx
+ mov %r12, %rcx
+ mov %r15d, %r8d
+ xor %eax, %eax
+ call snprintf@PLT
+.Lhg_ret_rate:
+ mov $CEPIS_ERR_RATE_LIMITED, %eax
+ EPILOGUE
+ ret
+.Lhg_nomem:
+ mov $CEPIS_ERR_NOMEM, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__http_get
+
+FUNC cepis__curl_release
+ PROLOGUE 8
+ mov %rdi, %rbx
+ mov %rsi, %r12
+ mov (%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lrel_slist
+ call curl_easy_cleanup@PLT
+ movq $0, (%rbx)
+.Lrel_slist:
+ mov (%r12), %rdi
+ test %rdi, %rdi
+ jz .Lrel_out
+ call curl_slist_free_all@PLT
+ movq $0, (%r12)
+.Lrel_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis__curl_release
+
+ .section .rodata
+ .p2align 3
+.Lnano: .double 1e-9
+.Lgiga: .double 1e9
+.Ltwo53: .double 1.1102230246251565e-16
+.Lthousand: .double 1000.0
+.Lhdr_retry_after: .asciz "retry-after:"
+.Lhdr_accept: .asciz "Accept: application/json, text/csv;q=0.9, */*;q=0.1"
+.Lidentity: .asciz "identity"
+.Lfmt_network: .asciz "could not reach %s after %d attempt(s): %s"
+.Lfmt_server: .asciz "the API answered %d at %s after %d attempt(s)"
+.Lfmt_rate: .asciz "rate limit reached at %s after %d attempt(s)"
+.Ls_jan: .asciz "Jan"
+.Ls_feb: .asciz "Feb"
+.Ls_mar: .asciz "Mar"
+.Ls_apr: .asciz "Apr"
+.Ls_may: .asciz "May"
+.Ls_jun: .asciz "Jun"
+.Ls_jul: .asciz "Jul"
+.Ls_aug: .asciz "Aug"
+.Ls_sep: .asciz "Sep"
+.Ls_oct: .asciz "Oct"
+.Ls_nov: .asciz "Nov"
+.Ls_dec: .asciz "Dec"
+ .section .data.rel.ro,"aw",@progbits
+ .p2align 3
+cepis__months:
+ .quad .Ls_jan, .Ls_feb, .Ls_mar, .Ls_apr, .Ls_may, .Ls_jun
+ .quad .Ls_jul, .Ls_aug, .Ls_sep, .Ls_oct, .Ls_nov, .Ls_dec
+
+ .data
+ .p2align 2
+cepis__curl_state:
+ .long 0
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/src/json.S b/src/json.S
new file mode 100644
index 0000000..58c5077
--- /dev/null
+++ b/src/json.S
@@ -0,0 +1,482 @@
+#include "abi.inc"
+#include "defs.inc"
+
+#define JBUF -72
+
+ .text
+
+FUNC cepis__js_ws
+.Lws_loop:
+ movzbl (%rdi), %eax
+ cmp $' ', %al
+ je .Lws_adv
+ cmp $9, %al
+ jb .Lws_end
+ cmp $13, %al
+ jbe .Lws_adv
+.Lws_end:
+ mov %rdi, %rax
+ ret
+.Lws_adv:
+ inc %rdi
+ jmp .Lws_loop
+ENDFUNC cepis__js_ws
+
+FUNC cepis__js_hex4
+ xor %ecx, %ecx
+ mov $4, %r8d
+.Lhex_loop:
+ movzbl (%rdi), %eax
+ inc %rdi
+ cmp $'0', %al
+ jb .Lhex_bad
+ cmp $'9', %al
+ jbe .Lhex_digit
+ or $0x20, %al
+ cmp $'a', %al
+ jb .Lhex_bad
+ cmp $'f', %al
+ ja .Lhex_bad
+ sub $('a' - 10), %eax
+ jmp .Lhex_acc
+.Lhex_digit:
+ sub $'0', %eax
+.Lhex_acc:
+ shl $4, %ecx
+ or %eax, %ecx
+ dec %r8d
+ jnz .Lhex_loop
+ mov %ecx, %eax
+ ret
+.Lhex_bad:
+ mov $-1, %eax
+ ret
+ENDFUNC cepis__js_hex4
+
+FUNC cepis__js_raw_string
+ cmpb $'"', (%rdi)
+ jne .Lraw_bad
+ inc %rdi
+.Lraw_loop:
+ movzbl (%rdi), %eax
+ test %al, %al
+ jz .Lraw_bad
+ cmp $'\\', %al
+ je .Lraw_esc
+ cmp $'"', %al
+ je .Lraw_close
+ inc %rdi
+ jmp .Lraw_loop
+.Lraw_esc:
+ cmpb $0, 1(%rdi)
+ je .Lraw_bad
+ add $2, %rdi
+ jmp .Lraw_loop
+.Lraw_close:
+ lea 1(%rdi), %rax
+ ret
+.Lraw_bad:
+ xor %eax, %eax
+ ret
+ENDFUNC cepis__js_raw_string
+
+FUNC cepis__js_skip
+ PROLOGUE 8
+ call cepis__js_ws
+ mov %rax, %rbx
+ movzbl (%rbx), %eax
+ test %al, %al
+ jz .Lskip_bad
+ cmp $'"', %al
+ je .Lskip_str
+ cmp $'{', %al
+ je .Lskip_nest
+ cmp $'[', %al
+ je .Lskip_nest
+ jmp .Lskip_token
+.Lskip_str:
+ mov %rbx, %rdi
+ call cepis__js_raw_string
+ EPILOGUE
+ ret
+.Lskip_token:
+ mov %rbx, %r12
+.Lskip_token_loop:
+ movzbl (%r12), %eax
+ cmp $'0', %al
+ jb .Lskip_token_sym
+ cmp $'9', %al
+ jbe .Lskip_token_adv
+ or $0x20, %al
+ cmp $'a', %al
+ jb .Lskip_token_end
+ cmp $'z', %al
+ jbe .Lskip_token_adv
+ jmp .Lskip_token_end
+.Lskip_token_sym:
+ cmp $'+', %al
+ je .Lskip_token_adv
+ cmp $'-', %al
+ je .Lskip_token_adv
+ cmp $'.', %al
+ je .Lskip_token_adv
+ jmp .Lskip_token_end
+.Lskip_token_adv:
+ inc %r12
+ jmp .Lskip_token_loop
+.Lskip_token_end:
+ cmp %rbx, %r12
+ je .Lskip_bad
+ mov %r12, %rax
+ EPILOGUE
+ ret
+.Lskip_nest:
+ xor %r13d, %r13d
+.Lskip_nest_loop:
+ movzbl (%rbx), %eax
+ test %al, %al
+ jz .Lskip_bad
+ cmp $'"', %al
+ je .Lskip_nest_str
+ cmp $'{', %al
+ je .Lskip_nest_open
+ cmp $'[', %al
+ je .Lskip_nest_open
+ cmp $'}', %al
+ je .Lskip_nest_close
+ cmp $']', %al
+ je .Lskip_nest_close
+ inc %rbx
+ jmp .Lskip_nest_loop
+.Lskip_nest_str:
+ mov %rbx, %rdi
+ call cepis__js_raw_string
+ test %rax, %rax
+ jz .Lskip_bad
+ mov %rax, %rbx
+ jmp .Lskip_nest_loop
+.Lskip_nest_open:
+ inc %r13d
+ inc %rbx
+ jmp .Lskip_nest_loop
+.Lskip_nest_close:
+ dec %r13d
+ inc %rbx
+ test %r13d, %r13d
+ jz .Lskip_nest_done
+ jmp .Lskip_nest_loop
+.Lskip_nest_done:
+ mov %rbx, %rax
+ EPILOGUE
+ ret
+.Lskip_bad:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__js_skip
+
+FUNC cepis__js_string
+ PROLOGUE 40
+ mov %rsi, %r14
+ movq $0, JBUF(%rbp)
+ movq $0, JBUF+8(%rbp)
+ movq $0, JBUF+16(%rbp)
+ movq $0, (%r14)
+ cmpb $'"', (%rdi)
+ jne .Lstr_fail
+ lea 1(%rdi), %rbx
+.Lstr_loop:
+ movzbl (%rbx), %eax
+ test %al, %al
+ jz .Lstr_fail
+ cmp $'"', %al
+ je .Lstr_done
+ cmp $'\\', %al
+ je .Lstr_esc
+ lea JBUF(%rbp), %rdi
+ movzbl (%rbx), %esi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+ inc %rbx
+ jmp .Lstr_loop
+.Lstr_esc:
+ movzbl 1(%rbx), %eax
+ test %al, %al
+ jz .Lstr_fail
+ cmp $'u', %al
+ je .Lstr_uesc
+ mov %eax, %r12d
+ cmp $'"', %al
+ je .Lstr_emit
+ cmp $'\\', %al
+ je .Lstr_emit
+ cmp $'/', %al
+ je .Lstr_emit
+ cmp $'b', %al
+ je .Lstr_bs
+ cmp $'f', %al
+ je .Lstr_ff
+ cmp $'n', %al
+ je .Lstr_nl
+ cmp $'r', %al
+ je .Lstr_cr
+ cmp $'t', %al
+ je .Lstr_tab
+ jmp .Lstr_fail
+.Lstr_bs:
+ mov $8, %r12d
+ jmp .Lstr_emit
+.Lstr_ff:
+ mov $12, %r12d
+ jmp .Lstr_emit
+.Lstr_nl:
+ mov $10, %r12d
+ jmp .Lstr_emit
+.Lstr_cr:
+ mov $13, %r12d
+ jmp .Lstr_emit
+.Lstr_tab:
+ mov $9, %r12d
+.Lstr_emit:
+ lea JBUF(%rbp), %rdi
+ mov %r12d, %esi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+ add $2, %rbx
+ jmp .Lstr_loop
+.Lstr_uesc:
+ lea 2(%rbx), %rdi
+ call cepis__js_hex4
+ test %eax, %eax
+ js .Lstr_fail
+ mov %eax, %r12d
+ add $6, %rbx
+ cmp $0xD800, %r12d
+ jb .Lstr_encode
+ cmp $0xDBFF, %r12d
+ ja .Lstr_low
+ cmpb $'\\', (%rbx)
+ jne .Lstr_repl
+ cmpb $'u', 1(%rbx)
+ jne .Lstr_repl
+ lea 2(%rbx), %rdi
+ call cepis__js_hex4
+ test %eax, %eax
+ js .Lstr_repl
+ mov %eax, %r13d
+ cmp $0xDC00, %r13d
+ jb .Lstr_repl
+ cmp $0xDFFF, %r13d
+ ja .Lstr_repl
+ add $6, %rbx
+ sub $0xD800, %r12d
+ shl $10, %r12d
+ sub $0xDC00, %r13d
+ add %r13d, %r12d
+ add $0x10000, %r12d
+ jmp .Lstr_encode
+.Lstr_low:
+ cmp $0xDFFF, %r12d
+ ja .Lstr_encode
+.Lstr_repl:
+ mov $0xFFFD, %r12d
+.Lstr_encode:
+ cmp $0x80, %r12d
+ jb .Lstr_enc1
+ cmp $0x800, %r12d
+ jb .Lstr_enc2
+ cmp $0x10000, %r12d
+ jb .Lstr_enc3
+ mov %r12d, %esi
+ shr $18, %esi
+ or $0xF0, %esi
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+ mov %r12d, %esi
+ shr $12, %esi
+ and $0x3F, %esi
+ or $0x80, %esi
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+ jmp .Lstr_enc_tail2
+.Lstr_enc3:
+ mov %r12d, %esi
+ shr $12, %esi
+ or $0xE0, %esi
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+.Lstr_enc_tail2:
+ mov %r12d, %esi
+ shr $6, %esi
+ and $0x3F, %esi
+ or $0x80, %esi
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+ jmp .Lstr_enc_tail1
+.Lstr_enc2:
+ mov %r12d, %esi
+ shr $6, %esi
+ or $0xC0, %esi
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+.Lstr_enc_tail1:
+ mov %r12d, %esi
+ and $0x3F, %esi
+ or $0x80, %esi
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+ jmp .Lstr_loop
+.Lstr_enc1:
+ mov %r12d, %esi
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_appendc
+ test %eax, %eax
+ jnz .Lstr_fail
+ jmp .Lstr_loop
+.Lstr_done:
+ inc %rbx
+ cmpq $0, JBUF(%rbp)
+ jne .Lstr_take
+ call cepis__empty
+ test %rax, %rax
+ jz .Lstr_fail
+ mov %rax, (%r14)
+ mov %rbx, %rax
+ EPILOGUE
+ ret
+.Lstr_take:
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_take
+ mov %rax, (%r14)
+ mov %rbx, %rax
+ EPILOGUE
+ ret
+.Lstr_fail:
+ lea JBUF(%rbp), %rdi
+ call cepis__buf_free
+ movq $0, (%r14)
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__js_string
+
+FUNC cepis__js_scalar_text
+ PROLOGUE 24
+ mov %rsi, %r14
+ movq $0, (%r14)
+ call cepis__js_ws
+ mov %rax, %rbx
+ movzbl (%rbx), %eax
+ cmp $'"', %al
+ je .Lsc_string
+ cmp $'{', %al
+ je .Lsc_fail
+ cmp $'[', %al
+ je .Lsc_fail
+ mov %rbx, %rdi
+ call cepis__js_skip
+ test %rax, %rax
+ jz .Lsc_fail
+ mov %rax, %r12
+ mov %r12, %r13
+ sub %rbx, %r13
+ cmp $4, %r13
+ jne .Lsc_copy
+ mov %rbx, %rdi
+ lea .Lsc_null(%rip), %rsi
+ mov $4, %rdx
+ call memcmp@PLT
+ test %eax, %eax
+ jnz .Lsc_copy
+ call cepis__empty
+ test %rax, %rax
+ jz .Lsc_fail
+ mov %rax, (%r14)
+ mov %r12, %rax
+ EPILOGUE
+ ret
+.Lsc_copy:
+ mov %rbx, %rdi
+ mov %r13, %rsi
+ call cepis__strndup
+ test %rax, %rax
+ jz .Lsc_fail
+ mov %rax, (%r14)
+ mov %r12, %rax
+ EPILOGUE
+ ret
+.Lsc_string:
+ mov %rbx, %rdi
+ mov %r14, %rsi
+ call cepis__js_string
+ EPILOGUE
+ ret
+.Lsc_fail:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__js_scalar_text
+
+FUNC cepis__js_number
+ PROLOGUE 40
+ mov %rsi, %r14
+ call cepis__js_ws
+ mov %rax, %rbx
+ cmpb $'"', (%rbx)
+ je .Lnum_quoted
+ mov %rbx, %rdi
+ lea LOCAL0(%rbp), %rsi
+ call strtod@PLT
+ mov LOCAL0(%rbp), %rax
+ cmp %rbx, %rax
+ je .Lnum_fail
+ movsd %xmm0, (%r14)
+ EPILOGUE
+ ret
+.Lnum_quoted:
+ mov %rbx, %rdi
+ lea LOCAL1(%rbp), %rsi
+ call cepis__js_string
+ test %rax, %rax
+ jz .Lnum_fail
+ mov %rax, %r12
+ mov LOCAL1(%rbp), %rdi
+ lea LOCAL0(%rbp), %rsi
+ call strtod@PLT
+ movsd %xmm0, LOCAL2(%rbp)
+ mov LOCAL1(%rbp), %rbx
+ mov LOCAL0(%rbp), %r13
+ mov %rbx, %rdi
+ call free@PLT
+ cmp %rbx, %r13
+ je .Lnum_fail
+ movsd LOCAL2(%rbp), %xmm0
+ movsd %xmm0, (%r14)
+ mov %r12, %rax
+ EPILOGUE
+ ret
+.Lnum_fail:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__js_number
+
+ .section .rodata
+.Lsc_null:
+ .ascii "null"
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/src/models.S b/src/models.S
new file mode 100644
index 0000000..77218f4
--- /dev/null
+++ b/src/models.S
@@ -0,0 +1,716 @@
+#include "abi.inc"
+#include "defs.inc"
+
+ .text
+
+FUNC cepis__addr_field_offset
+ PROLOGUE 24
+ mov %rdi, %rbx
+ lea cepis__addr_fields(%rip), %r12
+.Lfo_loop:
+ mov (%r12), %rsi
+ test %rsi, %rsi
+ jz .Lfo_none
+ mov %rbx, %rdi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lfo_hit
+ add $16, %r12
+ jmp .Lfo_loop
+.Lfo_hit:
+ mov 8(%r12), %rax
+ EPILOGUE
+ ret
+.Lfo_none:
+ mov $-1, %rax
+ EPILOGUE
+ ret
+ENDFUNC cepis__addr_field_offset
+
+FUNC cepis__addr_set
+ PROLOGUE 24
+ mov %rdi, %rbx
+ mov %rsi, %r12
+ mov %rdx, %r13
+ mov (%rbx, %r12, 1), %rdi
+ test %rdi, %rdi
+ jz .Lset_store
+ call free@PLT
+.Lset_store:
+ mov %r13, (%rbx, %r12, 1)
+ EPILOGUE
+ ret
+ENDFUNC cepis__addr_set
+
+FUNC cepis__address_new
+ PROLOGUE 24
+ mov $1, %rdi
+ mov $A_SIZE, %rsi
+ call calloc@PLT
+ test %rax, %rax
+ jz .Lanew_out
+ mov %rax, %rbx
+ xor %r12d, %r12d
+.Lanew_loop:
+ cmp $(A_NFIELDS * 8), %r12
+ jae .Lanew_done
+ call cepis__empty
+ test %rax, %rax
+ jz .Lanew_fail
+ mov %rax, (%rbx, %r12, 1)
+ add $8, %r12
+ jmp .Lanew_loop
+.Lanew_done:
+ mov %rbx, %rax
+.Lanew_out:
+ EPILOGUE
+ ret
+.Lanew_fail:
+ mov %rbx, %rdi
+ call cepis_address_free
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__address_new
+
+PUBFUNC cepis_address_free
+ PROLOGUE 24
+ test %rdi, %rdi
+ jz .Lafree_out
+ mov %rdi, %rbx
+ xor %r12d, %r12d
+.Lafree_loop:
+ cmp $(A_NFIELDS * 8), %r12
+ jae .Lafree_geo
+ mov (%rbx, %r12, 1), %rdi
+ test %rdi, %rdi
+ jz .Lafree_next
+ call free@PLT
+.Lafree_next:
+ add $8, %r12
+ jmp .Lafree_loop
+.Lafree_geo:
+ mov A_GEO(%rbx), %r13
+ test %r13, %r13
+ jz .Lafree_raw
+ mov GEO_PRECISAO(%r13), %rdi
+ test %rdi, %rdi
+ jz .Lafree_geo_self
+ call free@PLT
+.Lafree_geo_self:
+ mov %r13, %rdi
+ call free@PLT
+.Lafree_raw:
+ mov A_RAW(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lafree_self
+ call free@PLT
+.Lafree_self:
+ mov %rbx, %rdi
+ call free@PLT
+.Lafree_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis_address_free
+
+PUBFUNC cepis_address_list_free
+ PROLOGUE 24
+ test %rdi, %rdi
+ jz .Llfree_out
+ mov %rdi, %rbx
+ mov %rsi, %r12
+ xor %r13d, %r13d
+.Llfree_loop:
+ cmp %r12, %r13
+ jae .Llfree_self
+ mov (%rbx, %r13, 8), %rdi
+ call cepis_address_free
+ inc %r13
+ jmp .Llfree_loop
+.Llfree_self:
+ mov %rbx, %rdi
+ call free@PLT
+.Llfree_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis_address_list_free
+
+PUBFUNC cepis_health_free
+ PROLOGUE 24
+ test %rdi, %rdi
+ jz .Lhfree_out
+ mov %rdi, %rbx
+ mov H_STATUS(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lhfree_1
+ call free@PLT
+.Lhfree_1:
+ mov H_DNE(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lhfree_2
+ call free@PLT
+.Lhfree_2:
+ mov H_BASE_GERADA(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lhfree_3
+ call free@PLT
+.Lhfree_3:
+ mov H_RAW(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lhfree_self
+ call free@PLT
+.Lhfree_self:
+ mov %rbx, %rdi
+ call free@PLT
+.Lhfree_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis_health_free
+
+PUBFUNC cepis_geo_is_precise
+ xor %eax, %eax
+ test %rdi, %rdi
+ jz .Lprec_out
+ mov GEO_PRECISAO(%rdi), %rdi
+ test %rdi, %rdi
+ jz .Lprec_out
+ lea .Ls_logradouro_val(%rip), %rsi
+ jmp cepis__streq_tail
+.Lprec_out:
+ ret
+ENDFUNC cepis_geo_is_precise
+
+FUNC cepis__streq_tail
+ PROLOGUE 8
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lseq_yes
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lseq_yes:
+ mov $1, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__streq_tail
+
+PUBFUNC cepis_address_formatted_cep
+ test %rsi, %rsi
+ jz .Lfmt_out
+ movb $0, (%rsi)
+ test %rdi, %rdi
+ jz .Lfmt_out
+ mov A_CEP(%rdi), %rdi
+ test %rdi, %rdi
+ jz .Lfmt_out
+ xor %ecx, %ecx
+ xor %edx, %edx
+.Lfmt_loop:
+ cmp $9, %rcx
+ jae .Lfmt_end
+ movzbl (%rdi, %rcx, 1), %eax
+ test %al, %al
+ jz .Lfmt_end
+ cmp $5, %rcx
+ jne .Lfmt_put
+ movb $'-', (%rsi, %rdx, 1)
+ inc %rdx
+.Lfmt_put:
+ mov %al, (%rsi, %rdx, 1)
+ inc %rdx
+ inc %rcx
+ jmp .Lfmt_loop
+.Lfmt_end:
+ movb $0, (%rsi, %rdx, 1)
+.Lfmt_out:
+ ret
+ENDFUNC cepis_address_formatted_cep
+
+FUNC cepis__geo_parse
+ PROLOGUE 88
+ mov %rsi, %r14
+ movq $0, (%r14)
+ movq $0, LOCAL3(%rbp)
+ xor %r15d, %r15d
+ cmpb $'{', (%rdi)
+ jne .Lgeo_fail
+ lea 1(%rdi), %rdi
+ call cepis__js_ws
+ mov %rax, %rbx
+ cmpb $'}', (%rbx)
+ je .Lgeo_finish
+.Lgeo_pair:
+ cmpb $'"', (%rbx)
+ jne .Lgeo_fail
+ mov %rbx, %rdi
+ lea LOCAL4(%rbp), %rsi
+ call cepis__js_string
+ test %rax, %rax
+ jz .Lgeo_fail
+ mov %rax, %rdi
+ call cepis__js_ws
+ mov %rax, %rbx
+ cmpb $':', (%rbx)
+ jne .Lgeo_fail_key
+ inc %rbx
+ mov LOCAL4(%rbp), %rdi
+ lea .Ls_lat(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lgeo_lat
+ mov LOCAL4(%rbp), %rdi
+ lea .Ls_lon(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lgeo_lon
+ mov LOCAL4(%rbp), %rdi
+ lea .Ls_raio_m(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lgeo_raio
+ mov LOCAL4(%rbp), %rdi
+ lea .Ls_precisao(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lgeo_prec
+ mov %rbx, %rdi
+ call cepis__js_skip
+ jmp .Lgeo_after
+.Lgeo_lat:
+ mov %rbx, %rdi
+ lea LOCAL0(%rbp), %rsi
+ call cepis__js_number
+ or $1, %r15d
+ jmp .Lgeo_after
+.Lgeo_lon:
+ mov %rbx, %rdi
+ lea LOCAL1(%rbp), %rsi
+ call cepis__js_number
+ or $2, %r15d
+ jmp .Lgeo_after
+.Lgeo_raio:
+ mov %rbx, %rdi
+ lea LOCAL2(%rbp), %rsi
+ call cepis__js_number
+ or $4, %r15d
+ jmp .Lgeo_after
+.Lgeo_prec:
+ mov LOCAL3(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Lgeo_prec_go
+ call free@PLT
+ movq $0, LOCAL3(%rbp)
+.Lgeo_prec_go:
+ mov %rbx, %rdi
+ lea LOCAL3(%rbp), %rsi
+ call cepis__js_scalar_text
+ or $8, %r15d
+.Lgeo_after:
+ mov %rax, %r12
+ mov LOCAL4(%rbp), %rdi
+ call free@PLT
+ movq $0, LOCAL4(%rbp)
+ test %r12, %r12
+ jz .Lgeo_fail
+ mov %r12, %rdi
+ call cepis__js_ws
+ mov %rax, %rbx
+ cmpb $',', (%rbx)
+ je .Lgeo_comma
+ cmpb $'}', (%rbx)
+ je .Lgeo_finish
+ jmp .Lgeo_fail
+.Lgeo_comma:
+ lea 1(%rbx), %rdi
+ call cepis__js_ws
+ mov %rax, %rbx
+ jmp .Lgeo_pair
+.Lgeo_finish:
+ cmp $15, %r15d
+ jne .Lgeo_fail
+ cmpq $0, LOCAL3(%rbp)
+ je .Lgeo_fail
+ mov $1, %rdi
+ mov $GEO_SIZE, %rsi
+ call calloc@PLT
+ test %rax, %rax
+ jz .Lgeo_fail
+ mov %rax, %rbx
+ movsd LOCAL0(%rbp), %xmm0
+ movsd %xmm0, GEO_LAT(%rbx)
+ movsd LOCAL1(%rbp), %xmm0
+ movsd %xmm0, GEO_LON(%rbx)
+ cvttsd2si LOCAL2(%rbp), %rax
+ mov %rax, GEO_RAIO_M(%rbx)
+ mov LOCAL3(%rbp), %rax
+ mov %rax, GEO_PRECISAO(%rbx)
+ movq $0, LOCAL3(%rbp)
+ mov %rbx, (%r14)
+ EPILOGUE
+ ret
+.Lgeo_fail_key:
+ mov LOCAL4(%rbp), %rdi
+ call free@PLT
+.Lgeo_fail:
+ mov LOCAL3(%rbp), %rdi
+ test %rdi, %rdi
+ jz .Lgeo_fail_out
+ call free@PLT
+.Lgeo_fail_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis__geo_parse
+
+FUNC cepis__address_from_json
+ PROLOGUE 40
+ mov %rsi, %r14
+ movq $0, (%r14)
+ mov %rdi, %r15
+ call cepis__address_new
+ test %rax, %rax
+ jz .Lafj_nomem
+ mov %rax, %rbx
+ mov %r15, %rdi
+ call cepis__strdup
+ test %rax, %rax
+ jz .Lafj_nomem_free
+ mov %rax, A_RAW(%rbx)
+ mov %r15, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $'{', (%r12)
+ jne .Lafj_invalid
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $'}', (%r12)
+ je .Lafj_ok
+.Lafj_pair:
+ cmpb $'"', (%r12)
+ jne .Lafj_invalid
+ mov %r12, %rdi
+ lea LOCAL0(%rbp), %rsi
+ call cepis__js_string
+ test %rax, %rax
+ jz .Lafj_invalid
+ mov %rax, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $':', (%r12)
+ jne .Lafj_invalid_key
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ mov LOCAL0(%rbp), %rdi
+ lea .Ls_geo(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lafj_geo
+ mov LOCAL0(%rbp), %rdi
+ call cepis__addr_field_offset
+ cmp $0, %rax
+ jl .Lafj_unknown
+ mov %rax, %r13
+ movzbl (%r12), %eax
+ cmp $'{', %al
+ je .Lafj_unknown
+ cmp $'[', %al
+ je .Lafj_unknown
+ mov %r12, %rdi
+ lea LOCAL1(%rbp), %rsi
+ call cepis__js_scalar_text
+ test %rax, %rax
+ jz .Lafj_invalid_key
+ mov %rax, %r12
+ mov %rbx, %rdi
+ mov %r13, %rsi
+ mov LOCAL1(%rbp), %rdx
+ call cepis__addr_set
+ jmp .Lafj_next
+.Lafj_unknown:
+ mov %r12, %rdi
+ call cepis__js_skip
+ test %rax, %rax
+ jz .Lafj_invalid_key
+ mov %rax, %r12
+ jmp .Lafj_next
+.Lafj_geo:
+ mov %r12, %rdi
+ call cepis__js_skip
+ test %rax, %rax
+ jz .Lafj_invalid_key
+ mov %rax, %r13
+ cmpb $'{', (%r12)
+ jne .Lafj_geo_done
+ mov %r12, %rdi
+ lea LOCAL2(%rbp), %rsi
+ call cepis__geo_parse
+ mov LOCAL2(%rbp), %rax
+ test %rax, %rax
+ jz .Lafj_geo_done
+ mov %rax, A_GEO(%rbx)
+.Lafj_geo_done:
+ mov %r13, %r12
+.Lafj_next:
+ mov LOCAL0(%rbp), %rdi
+ call free@PLT
+ movq $0, LOCAL0(%rbp)
+ mov %r12, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $',', (%r12)
+ je .Lafj_comma
+ cmpb $'}', (%r12)
+ je .Lafj_ok
+ jmp .Lafj_invalid
+.Lafj_comma:
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ jmp .Lafj_pair
+.Lafj_ok:
+ mov %rbx, (%r14)
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lafj_invalid_key:
+ mov LOCAL0(%rbp), %rdi
+ call free@PLT
+.Lafj_invalid:
+ mov %rbx, %rdi
+ call cepis_address_free
+ mov $CEPIS_ERR_INVALID_RESPONSE, %eax
+ EPILOGUE
+ ret
+.Lafj_nomem_free:
+ mov %rbx, %rdi
+ call cepis_address_free
+.Lafj_nomem:
+ mov $CEPIS_ERR_NOMEM, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__address_from_json
+
+FUNC cepis__health_from_json
+ PROLOGUE 40
+ mov %rsi, %r14
+ movq $0, (%r14)
+ mov %rdi, %r15
+ mov $1, %rdi
+ mov $H_SIZE, %rsi
+ call calloc@PLT
+ test %rax, %rax
+ jz .Lhfj_nomem
+ mov %rax, %rbx
+ call cepis__empty
+ test %rax, %rax
+ jz .Lhfj_nomem_free
+ mov %rax, H_STATUS(%rbx)
+ call cepis__empty
+ test %rax, %rax
+ jz .Lhfj_nomem_free
+ mov %rax, H_DNE(%rbx)
+ call cepis__empty
+ test %rax, %rax
+ jz .Lhfj_nomem_free
+ mov %rax, H_BASE_GERADA(%rbx)
+ mov %r15, %rdi
+ call cepis__strdup
+ test %rax, %rax
+ jz .Lhfj_nomem_free
+ mov %rax, H_RAW(%rbx)
+ mov %r15, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $'{', (%r12)
+ jne .Lhfj_invalid
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $'}', (%r12)
+ je .Lhfj_ok
+.Lhfj_pair:
+ cmpb $'"', (%r12)
+ jne .Lhfj_invalid
+ mov %r12, %rdi
+ lea LOCAL0(%rbp), %rsi
+ call cepis__js_string
+ test %rax, %rax
+ jz .Lhfj_invalid
+ mov %rax, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $':', (%r12)
+ jne .Lhfj_invalid_key
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ mov LOCAL0(%rbp), %rdi
+ lea .Ls_status(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lhfj_status
+ mov LOCAL0(%rbp), %rdi
+ lea .Ls_dne(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lhfj_dne
+ mov LOCAL0(%rbp), %rdi
+ lea .Ls_base_gerada(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lhfj_base
+ mov LOCAL0(%rbp), %rdi
+ lea .Ls_ceps(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lhfj_ceps
+ mov LOCAL0(%rbp), %rdi
+ lea .Ls_geo(%rip), %rsi
+ call strcmp@PLT
+ test %eax, %eax
+ jz .Lhfj_geo
+ mov %r12, %rdi
+ call cepis__js_skip
+ test %rax, %rax
+ jz .Lhfj_invalid_key
+ mov %rax, %r12
+ jmp .Lhfj_next
+.Lhfj_status:
+ mov $H_STATUS, %r13
+ jmp .Lhfj_text
+.Lhfj_dne:
+ mov $H_DNE, %r13
+ jmp .Lhfj_text
+.Lhfj_base:
+ mov $H_BASE_GERADA, %r13
+.Lhfj_text:
+ movzbl (%r12), %eax
+ cmp $'{', %al
+ je .Lhfj_skipval
+ cmp $'[', %al
+ je .Lhfj_skipval
+ mov %r12, %rdi
+ lea LOCAL1(%rbp), %rsi
+ call cepis__js_scalar_text
+ test %rax, %rax
+ jz .Lhfj_invalid_key
+ mov %rax, %r12
+ mov (%rbx, %r13, 1), %rdi
+ call free@PLT
+ mov LOCAL1(%rbp), %rax
+ mov %rax, (%rbx, %r13, 1)
+ jmp .Lhfj_next
+.Lhfj_skipval:
+ mov %r12, %rdi
+ call cepis__js_skip
+ test %rax, %rax
+ jz .Lhfj_invalid_key
+ mov %rax, %r12
+ jmp .Lhfj_next
+.Lhfj_ceps:
+ mov $H_CEPS, %r13
+ jmp .Lhfj_int
+.Lhfj_geo:
+ mov $H_GEO, %r13
+.Lhfj_int:
+ movzbl (%r12), %eax
+ cmp $'{', %al
+ je .Lhfj_skipval
+ cmp $'[', %al
+ je .Lhfj_skipval
+ mov %r12, %rdi
+ lea LOCAL1(%rbp), %rsi
+ call cepis__js_number
+ test %rax, %rax
+ jz .Lhfj_skipval
+ mov %rax, %r12
+ cvttsd2si LOCAL1(%rbp), %rax
+ mov %rax, (%rbx, %r13, 1)
+.Lhfj_next:
+ mov LOCAL0(%rbp), %rdi
+ call free@PLT
+ movq $0, LOCAL0(%rbp)
+ mov %r12, %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ cmpb $',', (%r12)
+ je .Lhfj_comma
+ cmpb $'}', (%r12)
+ je .Lhfj_ok
+ jmp .Lhfj_invalid
+.Lhfj_comma:
+ lea 1(%r12), %rdi
+ call cepis__js_ws
+ mov %rax, %r12
+ jmp .Lhfj_pair
+.Lhfj_ok:
+ mov %rbx, (%r14)
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lhfj_invalid_key:
+ mov LOCAL0(%rbp), %rdi
+ call free@PLT
+.Lhfj_invalid:
+ mov %rbx, %rdi
+ call cepis_health_free
+ mov $CEPIS_ERR_INVALID_RESPONSE, %eax
+ EPILOGUE
+ ret
+.Lhfj_nomem_free:
+ mov %rbx, %rdi
+ call cepis_health_free
+.Lhfj_nomem:
+ mov $CEPIS_ERR_NOMEM, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__health_from_json
+
+ .section .rodata
+
+.Ls_cep: .asciz "cep"
+.Ls_logradouro: .asciz "logradouro"
+.Ls_complemento: .asciz "complemento"
+.Ls_unidade: .asciz "unidade"
+.Ls_bairro: .asciz "bairro"
+.Ls_localidade: .asciz "localidade"
+.Ls_uf: .asciz "uf"
+.Ls_estado: .asciz "estado"
+.Ls_regiao: .asciz "regiao"
+.Ls_ibge: .asciz "ibge"
+.Ls_gia: .asciz "gia"
+.Ls_ddd: .asciz "ddd"
+.Ls_siafi: .asciz "siafi"
+.Ls_geo: .asciz "geo"
+.Ls_lat: .asciz "lat"
+.Ls_lon: .asciz "lon"
+.Ls_raio_m: .asciz "raio_m"
+.Ls_precisao: .asciz "precisao"
+.Ls_status: .asciz "status"
+.Ls_dne: .asciz "dne"
+.Ls_ceps: .asciz "ceps"
+.Ls_base_gerada: .asciz "base_gerada_em"
+.Ls_logradouro_val: .asciz "logradouro"
+
+ .section .data.rel.ro,"aw",@progbits
+ .p2align 3
+ .globl cepis__addr_fields
+ .hidden cepis__addr_fields
+cepis__addr_fields:
+ .quad .Ls_cep, A_CEP
+ .quad .Ls_logradouro, A_LOGRADOURO
+ .quad .Ls_complemento, A_COMPLEMENTO
+ .quad .Ls_unidade, A_UNIDADE
+ .quad .Ls_bairro, A_BAIRRO
+ .quad .Ls_localidade, A_LOCALIDADE
+ .quad .Ls_uf, A_UF
+ .quad .Ls_estado, A_ESTADO
+ .quad .Ls_regiao, A_REGIAO
+ .quad .Ls_ibge, A_IBGE
+ .quad .Ls_gia, A_GIA
+ .quad .Ls_ddd, A_DDD
+ .quad .Ls_siafi, A_SIAFI
+ .quad 0, 0
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/src/util.S b/src/util.S
new file mode 100644
index 0000000..447f66c
--- /dev/null
+++ b/src/util.S
@@ -0,0 +1,190 @@
+#include "abi.inc"
+#include "defs.inc"
+
+ .text
+
+FUNC cepis__strndup
+ PROLOGUE 24
+ mov %rdi, %r12
+ mov %rsi, %r13
+ lea 1(%r13), %rdi
+ call malloc@PLT
+ test %rax, %rax
+ jz .Lstrndup_out
+ mov %rax, %rbx
+ test %r13, %r13
+ jz .Lstrndup_term
+ mov %rbx, %rdi
+ mov %r12, %rsi
+ mov %r13, %rdx
+ call memcpy@PLT
+.Lstrndup_term:
+ movb $0, (%rbx, %r13, 1)
+ mov %rbx, %rax
+.Lstrndup_out:
+ EPILOGUE
+ ret
+ENDFUNC cepis__strndup
+
+FUNC cepis__strdup
+ PROLOGUE 8
+ test %rdi, %rdi
+ jz .Lstrdup_null
+ mov %rdi, %rbx
+ call strlen@PLT
+ mov %rbx, %rdi
+ mov %rax, %rsi
+ call cepis__strndup
+ EPILOGUE
+ ret
+.Lstrdup_null:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__strdup
+
+FUNC cepis__empty
+ PROLOGUE 8
+ lea .Lempty_str(%rip), %rdi
+ xor %esi, %esi
+ call cepis__strndup
+ EPILOGUE
+ ret
+ENDFUNC cepis__empty
+
+FUNC cepis__buf_reserve
+ PROLOGUE 24
+ mov %rdi, %rbx
+ mov B_LEN(%rbx), %rax
+ add %rsi, %rax
+ add $1, %rax
+ cmp B_CAP(%rbx), %rax
+ jbe .Lreserve_ok
+ mov %rax, %r12
+ mov B_CAP(%rbx), %r13
+ test %r13, %r13
+ jnz .Lreserve_grow
+ mov $64, %r13
+.Lreserve_grow:
+ cmp %r12, %r13
+ jae .Lreserve_alloc
+ shl $1, %r13
+ jmp .Lreserve_grow
+.Lreserve_alloc:
+ mov B_DATA(%rbx), %rdi
+ mov %r13, %rsi
+ call realloc@PLT
+ test %rax, %rax
+ jz .Lreserve_fail
+ mov %rax, B_DATA(%rbx)
+ mov %r13, B_CAP(%rbx)
+.Lreserve_ok:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lreserve_fail:
+ mov $-1, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__buf_reserve
+
+FUNC cepis__buf_append
+ PROLOGUE 24
+ mov %rdi, %rbx
+ mov %rsi, %r12
+ mov %rdx, %r13
+ mov %rbx, %rdi
+ mov %r13, %rsi
+ call cepis__buf_reserve
+ test %eax, %eax
+ jnz .Lappend_fail
+ test %r13, %r13
+ jz .Lappend_term
+ mov B_DATA(%rbx), %rdi
+ add B_LEN(%rbx), %rdi
+ mov %r12, %rsi
+ mov %r13, %rdx
+ call memcpy@PLT
+.Lappend_term:
+ add %r13, B_LEN(%rbx)
+ mov B_DATA(%rbx), %rax
+ mov B_LEN(%rbx), %rcx
+ movb $0, (%rax, %rcx, 1)
+ xor %eax, %eax
+ EPILOGUE
+ ret
+.Lappend_fail:
+ mov $-1, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__buf_append
+
+FUNC cepis__buf_appendc
+ PROLOGUE 24
+ mov %esi, %eax
+ movb %al, LOCAL0(%rbp)
+ lea LOCAL0(%rbp), %rsi
+ mov $1, %rdx
+ call cepis__buf_append
+ EPILOGUE
+ ret
+ENDFUNC cepis__buf_appendc
+
+FUNC cepis__buf_appendz
+ PROLOGUE 24
+ test %rsi, %rsi
+ jz .Lappendz_ok
+ mov %rdi, %rbx
+ mov %rsi, %r12
+ mov %rsi, %rdi
+ call strlen@PLT
+ mov %rbx, %rdi
+ mov %r12, %rsi
+ mov %rax, %rdx
+ call cepis__buf_append
+ EPILOGUE
+ ret
+.Lappendz_ok:
+ xor %eax, %eax
+ EPILOGUE
+ ret
+ENDFUNC cepis__buf_appendz
+
+FUNC cepis__buf_reset
+ movq $0, B_LEN(%rdi)
+ mov B_DATA(%rdi), %rax
+ test %rax, %rax
+ jz .Lreset_out
+ movb $0, (%rax)
+.Lreset_out:
+ ret
+ENDFUNC cepis__buf_reset
+
+FUNC cepis__buf_free
+ PROLOGUE 8
+ mov %rdi, %rbx
+ mov B_DATA(%rbx), %rdi
+ test %rdi, %rdi
+ jz .Lbfree_zero
+ call free@PLT
+.Lbfree_zero:
+ movq $0, B_DATA(%rbx)
+ movq $0, B_LEN(%rbx)
+ movq $0, B_CAP(%rbx)
+ EPILOGUE
+ ret
+ENDFUNC cepis__buf_free
+
+FUNC cepis__buf_take
+ mov B_DATA(%rdi), %rax
+ movq $0, B_DATA(%rdi)
+ movq $0, B_LEN(%rdi)
+ movq $0, B_CAP(%rdi)
+ ret
+ENDFUNC cepis__buf_take
+
+ .section .rodata
+.Lempty_str:
+ .byte 0
+
+ .section .note.GNU-stack,"",@progbits