user: Translate the below assembly code into C programming language:

```asm
<ustrtoul>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  mov    %rdi,-0x38(%rbp)
  mov    %rsi,-0x40(%rbp)
  mov    %edx,-0x44(%rbp)
  movq   $0x0,-0x28(%rbp)
  movq   $0x0,-0x18(%rbp)
  movq   $0x0,-0x10(%rbp)
  mov    -0x38(%rbp),%rax
  mov    %rax,-0x8(%rbp)
  jmp    L225
L32:
  addq   $0x1,-0x8(%rbp)
L225:
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x20,%al
  je     L32
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x9,%al
  je     L32
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x2d,%al
  jne    L154
  movq   $0x1,-0x18(%rbp)
  addq   $0x1,-0x8(%rbp)
  jmp    L158
L154:
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x2b,%al
  jne    L158
  addq   $0x1,-0x8(%rbp)
L158:
  cmpl   $0x0,-0x44(%rbp)
  je     L289
  cmpl   $0x10,-0x44(%rbp)
  jne    L243
L289:
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x30,%al
  jne    L243
  mov    -0x8(%rbp),%rax
  add    $0x1,%rax
  movzbl (%rax),%eax
  cmp    $0x78,%al
  je     L69
  mov    -0x8(%rbp),%rax
  add    $0x1,%rax
  movzbl (%rax),%eax
  cmp    $0x58,%al
  jne    L243
L69:
  addq   $0x2,-0x8(%rbp)
  movl   $0x10,-0x44(%rbp)
L243:
  cmpl   $0x0,-0x44(%rbp)
  jne    L136
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x30,%al
  jne    L71
  movl   $0x8,-0x44(%rbp)
  jmp    L136
L71:
  movl   $0xa,-0x44(%rbp)
L136:
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x2f,%al
  jle    L88
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x39,%al
  jg     L88
  mov    -0x8(%rbp),%rax
  lea    0x1(%rax),%rdx
  mov    %rdx,-0x8(%rbp)
  movzbl (%rax),%eax
  movsbl %al,%eax
  sub    $0x30,%eax
  cltq
  mov    %rax,-0x20(%rbp)
  jmp    L133
L88:
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x40,%al
  jle    L254
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x5a,%al
  jg     L254
  mov    -0x8(%rbp),%rax
  lea    0x1(%rax),%rdx
  mov    %rdx,-0x8(%rbp)
  movzbl (%rax),%eax
  movsbl %al,%eax
  sub    $0x37,%eax
  cltq
  mov    %rax,-0x20(%rbp)
  jmp    L133
L254:
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x60,%al
  jle    L112
  mov    -0x8(%rbp),%rax
  movzbl (%rax),%eax
  cmp    $0x7a,%al
  jg     L112
  mov    -0x8(%rbp),%rax
  lea    0x1(%rax),%rdx
  mov    %rdx,-0x8(%rbp)
  movzbl (%rax),%eax
  movsbl %al,%eax
  sub    $0x57,%eax
  cltq
  mov    %rax,-0x20(%rbp)
L133:
  mov    -0x44(%rbp),%eax
  cltq
  cmp    %rax,-0x20(%rbp)
  jb     L168
  subq   $0x1,-0x8(%rbp)
  jmp    L112
L168:
  mov    -0x44(%rbp),%eax
  cltq
  mov    -0x28(%rbp),%rdx
  imul   %rdx,%rax
  mov    %rax,-0x28(%rbp)
  mov    -0x20(%rbp),%rax
  add    %rax,-0x28(%rbp)
  movq   $0x1,-0x10(%rbp)
  jmp    L136
L112:
  cmpq   $0x0,-0x40(%rbp)
  je     L26
  cmpq   $0x0,-0x10(%rbp)
  je     L37
  mov    -0x8(%rbp),%rax
  jmp    L137
L37:
  mov    -0x38(%rbp),%rax
L137:
  mov    -0x40(%rbp),%rdx
  mov    %rax,(%rdx)
L26:
  cmpq   $0x0,-0x18(%rbp)
  je     L258
  mov    -0x28(%rbp),%rax
  neg    %rax
  jmp    L236
L258:
  mov    -0x28(%rbp),%rax
L236:
  pop    %rbp
  ret
```

assistant: ```c
unsigned long ustrtoul(const char *pcStr, const char **ppcStrRet, int iBase) {
  unsigned long ulRet, ulDigit, ulNeg, ulValid;
  const char *pcPtr;
  ;
  ;
  ulRet = 0;
  ulNeg = 0;
  ulValid = 0;
  pcPtr = pcStr;
  while ((*pcPtr == ' ') || (*pcPtr == '\t')) {
    pcPtr++;
  }
  if (*pcPtr == '-') {
    ulNeg = 1;
    pcPtr++;
  } else if (*pcPtr == '+') {
    pcPtr++;
  }
  if (((iBase == 0) || (iBase == 16)) && (*pcPtr == '0') && ((pcPtr[1] == 'x') || (pcPtr[1] == 'X'))) {
    pcPtr += 2;
    iBase = 16;
  }
  if (iBase == 0) {
    if (*pcPtr == '0') {
      iBase = 8;
    } else {
      iBase = 10;
    }
  }
  while (1) {
    if ((*pcPtr >= '0') && (*pcPtr <= '9')) {
      ulDigit = *pcPtr++ - '0';
    } else if ((*pcPtr >= 'A') && (*pcPtr <= 'Z')) {
      ulDigit = *pcPtr++ - 'A' + 10;
    } else if ((*pcPtr >= 'a') && (*pcPtr <= 'z')) {
      ulDigit = *pcPtr++ - 'a' + 10;
    } else {
      break;
    }
    if (ulDigit >= iBase) {
      pcPtr--;
      break;
    }
    ulRet *= iBase;
    ulRet += ulDigit;
    ulValid = 1;
  }
  if (ppcStrRet) {
    *ppcStrRet = ulValid ? pcPtr : pcStr;
  }
  return (ulNeg ? (0 - ulRet) : ulRet);
}
```