user: Please show me the C implementation that matches the assembly code listed below:

```asm
<fnmatch>:
  endbr64
  push   %r15
  push   %r14
  push   %r13
  push   %r12
  push   %rbp
  push   %rbx
  sub    $0x8,%rsp
  mov    %rdi,%rbx
  mov    %rsi,%r13
  mov    %edx,%r12d
  mov    %rsi,%rbp
  mov    %edx,%r14d
  and    $0x4,%r14d
  jmp    L400
L164:
  test   %dil,%dil
  je     L641
  cmp    $0x2a,%dil
  jne    L408
  movzbl 0x1(%rbx),%edx
  cmp    $0x2a,%dl
  jne    L388
L633:
  add    $0x1,%rax
  movzbl (%rax),%edx
  cmp    $0x2a,%dl
  je     L633
  mov    %rax,%rbx
L456:
  movzbl 0x0(%rbp),%r15d
  cmp    $0x2e,%r15b
  je     L10
L220:
  test   %dl,%dl
  je     L376
  cmp    $0x2f,%dl
  jne    L303
  test   $0x2,%r12b
  je     L303
  mov    $0x2f,%esi
  mov    %rbp,%rdi
  call   <strchr@plt>
  mov    %rax,%rbp
  test   %rax,%rax
  jne    L400
  mov    $0x1,%eax
  jmp    L440
L408:
  mov    %rax,%rbx
  jmp    L462
L553:
  mov    %rax,%rbx
  jmp    L462
L641:
  test   $0x8,%r12b
  je     L62
  mov    $0x0,%eax
  cmpb   $0x2f,0x0(%rbp)
  je     L440
L62:
  cmpb   $0x0,0x0(%rbp)
  setne  %al
  movzbl %al,%eax
L440:
  add    $0x8,%rsp
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  pop    %r15
  ret
L401:
  movzbl 0x0(%rbp),%edx
  test   %dl,%dl
  je     L244
  cmp    $0x2f,%dl
  je     L231
  cmp    $0x2e,%dl
  jne    L485
  test   %r14d,%r14d
  je     L485
  cmp    %r13,%rbp
  je     L248
  test   $0x2,%r12b
  je     L485
  cmpb   $0x2f,-0x1(%rbp)
  jne    L485
  mov    $0x1,%eax
  jmp    L440
L231:
  test   $0x2,%r12b
  jne    L212
L485:
  add    $0x1,%rbp
  mov    %rax,%rbx
  jmp    L400
L388:
  mov    %rax,%rbx
  jmp    L456
L10:
  test   %r14d,%r14d
  je     L220
  cmp    %r13,%rbp
  je     L228
  test   $0x2,%r12b
  je     L220
  cmpb   $0x2f,-0x1(%rbp)
  jne    L220
  mov    $0x1,%eax
  jmp    L440
L376:
  mov    %r12d,%eax
  and    $0x2,%eax
  je     L440
  mov    $0x0,%eax
  test   $0x8,%r12b
  jne    L440
  mov    $0x2f,%esi
  mov    %rbp,%rdi
  call   <strchr@plt>
  test   %rax,%rax
  setne  %al
  movzbl %al,%eax
  jmp    L440
L78:
  add    $0x1,%rbp
  movzbl 0x0(%rbp),%r15d
  test   %r15b,%r15b
  je     L158
L587:
  mov    %r13d,%edx
  mov    %rbp,%rsi
  mov    %rbx,%rdi
  call   <fnmatch>
  test   %eax,%eax
  je     L440
  cmp    $0x2f,%r15b
  jne    L78
  test   $0x2,%r12b
  je     L78
  mov    $0x1,%eax
  jmp    L440
L158:
  mov    $0x1,%eax
  jmp    L440
L303:
  mov    %r12d,%r13d
  and    $0xfffffffb,%r13d
  mov    $0x1,%eax
  test   %r15b,%r15b
  jne    L587
  jmp    L440
L502:
  movzbl 0x0(%rbp),%esi
  test   %sil,%sil
  je     L622
  cmp    $0x2f,%sil
  jne    L149
  test   $0x2,%r12b
  jne    L554
L149:
  movsbl %sil,%esi
  mov    %r12d,%edx
  mov    %rax,%rdi
  call   <rangematch@plt>
  mov    %rax,%rbx
  test   %rax,%rax
  je     L381
  add    $0x1,%rbp
  jmp    L400
L283:
  mov    %rax,%rbx
L462:
  cmp    %dil,0x0(%rbp)
  je     L222
  test   $0x10,%r12b
  je     L126
  movzbl %dil,%edi
  call   <tolower@plt>
  mov    %eax,%r15d
  movzbl 0x0(%rbp),%edi
  call   <tolower@plt>
  cmp    %eax,%r15d
  jne    L572
L222:
  add    $0x1,%rbp
L400:
  lea    0x1(%rbx),%rax
  movzbl (%rbx),%edi
  cmp    $0x3f,%dil
  je     L401
  jle    L164
  cmp    $0x5b,%dil
  je     L502
  cmp    $0x5c,%dil
  jne    L553
  test   $0x1,%r12b
  jne    L283
  movzbl 0x1(%rbx),%edx
  test   %dl,%dl
  je     L48
  add    $0x2,%rbx
  mov    %edx,%edi
  jmp    L462
L48:
  mov    %rax,%rbx
  jmp    L462
L244:
  mov    $0x1,%eax
  jmp    L440
L212:
  mov    $0x1,%eax
  jmp    L440
L248:
  mov    $0x1,%eax
  jmp    L440
L228:
  mov    $0x1,%eax
  jmp    L440
L622:
  mov    $0x1,%eax
  jmp    L440
L554:
  mov    $0x1,%eax
  jmp    L440
L381:
  mov    $0x1,%eax
  jmp    L440
L126:
  mov    $0x1,%eax
  jmp    L440
L572:
  mov    $0x1,%eax
  jmp    L440
```

assistant: ```c
int fnmatch(const char *pattern, const char *string, int flags) {
  const char *stringstart;
  char c;
  char test;
  for (stringstart = string;;)
    switch (c = *pattern++) {
    case '\0':
      if ((flags & 0x08) && *string == '/')
        return (0);
      return (*string == '\0' ? 0 : 1);
    case '?':
      if (*string == '\0')
        return (1);
      if (*string == '/' && (flags & 0x02))
        return (1);
      if (*string == '.' && (flags & 0x04) && (string == stringstart || ((flags & 0x02) && *(string - 1) == '/')))
        return (1);
      ++string;
      break;
    case '*':
      c = *pattern;
      while (c == '*')
        c = *++pattern;
      if (*string == '.' && (flags & 0x04) && (string == stringstart || ((flags & 0x02) && *(string - 1) == '/')))
        return (1);
      if (c == '\0')
        if (flags & 0x02)
          return ((flags & 0x08) || strchr(string, '/') == NULL ? 0 : 1);
        else
          return (0);
      else if (c == '/' && flags & 0x02) {
        if ((string = strchr(string, '/')) == NULL)
          return (1);
        break;
      }
      while ((test = *string) != '\0') {
        if (!fnmatch(pattern, string, flags & ~0x04))
          return (0);
        if (test == '/' && flags & 0x02)
          break;
        ++string;
      }
      return (1);
    case '[':
      if (*string == '\0')
        return (1);
      if (*string == '/' && flags & 0x02)
        return (1);
      if ((pattern = rangematch(pattern, *string, flags)) == NULL)
        return (1);
      ++string;
      break;
    case '\\':
      if (!(flags & 0x01)) {
        if ((c = *pattern++) == '\0') {
          c = '\\';
          --pattern;
        }
      }
    default:
      if (c == *string)
        ;
      else if ((flags & 0x10) && (tolower((unsigned char)c) == tolower((unsigned char)*string)))
        ;
      else
        return (1);
      string++;
      break;
    }
}
```