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

```asm
<print_string>:
  endbr64
  push   %r15
  push   %r14
  mov    %ecx,%r14d
  push   %r13
  mov    %edi,%r13d
  push   %r12
  mov    %edi,%r12d
  push   %rbp
  mov    %edx,%ebp
  push   %rbx
  mov    %rsi,%rbx
  sub    $0x8,%rsp
  test   %rsi,%rsi
  je     L168
L23:
  test   %ebp,%ebp
  jns    L96
  test   %r13b,%r13b
  je     L25
L96:
  test   %r14b,%r14b
  je     L116
  test   %ebp,%ebp
  je     L178
L49:
  xor    %r15d,%r15d
  lea    D24(%rip),%r14
  lea    D31(%rip),%r13
L165:
  movzbl (%rbx),%esi
  mov    %esi,%eax
  or     %r12b,%al
  je     L178
L36:
  test   %sil,%sil
  jne    L127
  mov    %r13,%rdi
  xor    %eax,%eax
  call   <printf@plt>
L37:
  add    $0x1,%r15d
  cmp    %ebp,%r15d
  jae    L178
  add    $0x1,%rbx
  mov    %r12d,%eax
  or     (%rbx),%al
  je     L165
  mov    $0x3a,%edi
  call   <putchar@plt>
  movzbl (%rbx),%esi
  mov    %esi,%eax
  or     %r12b,%al
  jne    L36
L178:
  add    $0x8,%rsp
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  pop    %r15
  ret
  nopl   0x0(%rax)
L116:
  test   %ebp,%ebp
  je     L178
L101:
  add    %rbx,%rbp
  jmp    L12
  nopl   0x0(%rax)
L120:
  mov    $0x2d,%edi
  call   <putchar@plt>
L84:
  cmp    %rbp,%rbx
  je     L178
L12:
  movzbl (%rbx),%edi
  mov    %edi,%eax
  or     %r12b,%al
  je     L178
  add    $0x1,%rbx
  test   %dil,%dil
  je     L120
  call   <putchar@plt>
  jmp    L84
  nopl   0x0(%rax)
L25:
  lea    D11(%rip),%rdi
  xor    %eax,%eax
  lea    D42(%rip),%rsi
  call   <printf@plt>
  mov    $0xffffffff,%edi
  call   <exit@plt>
  test   %r14b,%r14b
  jne    L49
  jmp    L101
  nopw   0x0(%rax,%rax,1)
L127:
  mov    %r14,%rdi
  xor    %eax,%eax
  call   <printf@plt>
  jmp    L37
  nopw   0x0(%rax,%rax,1)
L168:
  lea    D35(%rip),%rsi
  lea    D11(%rip),%rdi
  xor    %eax,%eax
  call   <printf@plt>
  mov    $0xffffffff,%edi
  call   <exit@plt>
  jmp    L23
```

tool_calls: name: unpack_data
arguments: tag: D24
type_guessed: string
name: unpack_data
arguments: tag: D31
type_guessed: string
name: unpack_data
arguments: tag: D11
type_guessed: string
name: unpack_data
arguments: tag: D42
type_guessed: string
name: unpack_data
arguments: tag: D35
type_guessed: string

tool: D24: %02X

tool: D31: --

tool: D11: Error:	%s


tool: D42: Invalid Argument Exception - must end with length or null value

tool: D35: Null Pointer Exception - print_string

assistant: ```c
void print_string(char ignore_nulls_flag, char *str, int len, char hex_flag) {
  int n = 0;
  unsigned char c = 0;
  if (str == 0) {
    printf("Error:\t%s\n", "Null Pointer Exception - print_string");
    exit(-1);
  }
  if ((len < 0 && !ignore_nulls_flag)) {
    printf("Error:\t%s\n", "Invalid Argument Exception - must end with length or null value");
    exit(-1);
  }
  if (hex_flag) {
    for (n = 0; (n < len || len < 0) && (*str || ignore_nulls_flag); n++) {
      c = (unsigned char)(*str++);
      if (c == 0) {
        printf("--");
      } else {
        printf("%02X", c);
      }
      if ((n + 1 < len || len < 0) && (*str || ignore_nulls_flag))
        printf(":");
    }
  } else {
    for (n = 0; (n < len || len < 0) && (*str || ignore_nulls_flag); n++) {
      c = (unsigned char)(*str++);
      if (c == 0) {
        printf("-");
      } else {
        printf("%c", c);
      }
    }
  }
}
```