user: Converte this assembly snippet into its equivalent C code:

```asm
<_validate_utf8>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  sub    $0x40,%rsp
  mov    %rdi,-0x28(%rbp)
  mov    %esi,-0x2c(%rbp)
  mov    %rdx,-0x38(%rbp)
  mov    -0x28(%rbp),%rax
  mov    (%rax),%rax
  mov    %rax,-0x8(%rbp)
  movl   $0x0,-0x14(%rbp)
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  test   %al,%al
  je     L104
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  test   %al,%al
  js     L104
  mov    -0x8(%rbp),%rax
  lea    0x1(%rax),%rdx
  mov    %rdx,-0x8(%rbp)
  movzbl (%rax),%eax
  movsbl %al,%edx
  mov    -0x38(%rbp),%rax
  mov    %edx,%esi
  mov    %rax,%rdi
  call   <buf_putchar@plt>
  test   %eax,%eax
  jne    L51
  mov    $0x0,%eax
  jmp    L192
L51:
  movl   $0x1,-0x14(%rbp)
  jmp    L236
L104:
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  movzbl %al,%eax
  mov    %eax,%edi
  call   <mb_num_chars@plt>
  mov    %eax,-0xc(%rbp)
  cmpl   $0x1,-0xc(%rbp)
  jbe    L110
  movl   $0x1,-0x10(%rbp)
  jmp    L250
L237:
  addl   $0x1,-0x10(%rbp)
L250:
  mov    -0x10(%rbp),%eax
  cmp    -0xc(%rbp),%eax
  ja     L205
  mov    -0x14(%rbp),%edx
  mov    -0x10(%rbp),%eax
  add    %eax,%edx
  mov    -0x2c(%rbp),%eax
  cmp    %eax,%edx
  jae    L205
  mov    -0x10(%rbp),%edx
  mov    -0x8(%rbp),%rax
  add    %rdx,%rax
  movzbl (%rax),%eax
  movzbl %al,%eax
  mov    %eax,%edi
  call   <mb_is_cont@plt>
  test   %rax,%rax
  jne    L237
L205:
  mov    -0xc(%rbp),%eax
  sub    $0x5,%eax
  cmp    $0x1,%eax
  ja     L199
  mov    -0x38(%rbp),%rax
  mov    $0x3f,%esi
  mov    %rax,%rdi
  call   <buf_putchar@plt>
  test   %eax,%eax
  jne    L210
  mov    $0x0,%eax
  jmp    L192
L199:
  mov    -0x10(%rbp),%eax
  cmp    -0xc(%rbp),%eax
  jne    L27
  mov    -0xc(%rbp),%edx
  mov    -0x8(%rbp),%rax
  mov    %edx,%esi
  mov    %rax,%rdi
  call   <mb_is_shortest@plt>
  test   %eax,%eax
  je     L27
  mov    -0xc(%rbp),%edx
  mov    -0x8(%rbp),%rax
  mov    %edx,%esi
  mov    %rax,%rdi
  call   <mb_is_surrogate@plt>
  test   %eax,%eax
  jne    L27
  mov    -0xc(%rbp),%edx
  mov    -0x8(%rbp),%rax
  mov    %edx,%esi
  mov    %rax,%rdi
  call   <mb_is_illegal@plt>
  test   %eax,%eax
  jne    L27
  mov    -0xc(%rbp),%edx
  mov    -0x8(%rbp),%rcx
  mov    -0x38(%rbp),%rax
  mov    %rcx,%rsi
  mov    %rax,%rdi
  call   <buf_append@plt>
  test   %eax,%eax
  jne    L226
  mov    $0x0,%eax
  jmp    L192
L27:
  mov    -0x38(%rbp),%rax
  mov    $0x3f,%esi
  mov    %rax,%rdi
  call   <buf_putchar@plt>
  test   %eax,%eax
  jne    L173
  mov    $0x0,%eax
  jmp    L192
L226:
  jmp    L173
L210:
  nop
  jmp    L220
L173:
  nop
L220:
  mov    -0x10(%rbp),%eax
  mov    %eax,-0x14(%rbp)
  mov    -0x10(%rbp),%eax
  add    %rax,-0x8(%rbp)
  jmp    L236
L110:
  mov    -0x38(%rbp),%rax
  mov    $0x3f,%esi
  mov    %rax,%rdi
  call   <buf_putchar@plt>
  test   %eax,%eax
  jne    L68
  mov    $0x0,%eax
  jmp    L192
L68:
  movl   $0x1,-0x14(%rbp)
  addq   $0x1,-0x8(%rbp)
L236:
  mov    -0x28(%rbp),%rax
  mov    -0x8(%rbp),%rdx
  mov    %rdx,(%rax)
  mov    -0x14(%rbp),%eax
L192:
  leave
  ret
```

assistant: ```c
int _validate_utf8(unsigned char **s, int l, struct template_buffer *buf) {
  unsigned char *ptr = *s;
  unsigned int o = 0, v, n;
  if ((*(ptr + 0) >= 0x01) && (*(ptr + 0) <= 0x7F)) {
    if (!buf_putchar(buf, *ptr++))
      return 0;
    o = 1;
  } else if ((n = mb_num_chars(*ptr)) > 1) {
    for (v = 1; (v <= n) && ((o + v) < l) && mb_is_cont(*(ptr + v)); v++)
      ;
    switch (n) {
    case 6:
    case 5:
      if (!buf_putchar(buf, '?'))
        return 0;
      break;
    default:
      if ((v == n) && mb_is_shortest(ptr, n) && !mb_is_surrogate(ptr, n) && !mb_is_illegal(ptr, n)) {
        if (!buf_append(buf, ptr, n))
          return 0;
      } else {
        if (!buf_putchar(buf, '?'))
          return 0;
      }
      break;
    }
    o = v;
    ptr += v;
  } else {
    if (!buf_putchar(buf, '?'))
      return 0;
    o = 1;
    ptr++;
  }
  *s = ptr;
  return o;
}
```