#!/usr/bin/env perl
# Copyright (c) 2021 OceanBase
# OceanBase CE is licensed under Mulan PubL v2.
# You can use this software according to the terms and conditions of the Mulan PubL v2.
# You may obtain a copy of Mulan PubL v2 at:
#          http://license.coscl.org.cn/MulanPubL-2.0
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PubL v2 for more details.

use strict;
use warnings;
open my $fh, '<', "os_errno.def";
my %os_map;
my $error_count=0;

while(<$fh>) {
  if (/^DEFINE_OS_ERROR\(([^,]+),\s*([^,]*),\s*([^,]*),\s*("[^,]*")/) {
    ++$error_count;
    #print "\"$1\", $1, $2\n";
    $os_map{$1} = [$2, $3, "$1", $4];
  } 
}

print "total error code: $error_count\n";
print "please wait for writing files ...\n";
# check duplicate error number
my %dedup;
for my $oberr (keys % os_map) {
  my $errno = $os_map{$oberr}->[0];
  if (defined $dedup{$errno})
  {
    print "Error: error code($errno) is duplicated for $oberr and $dedup{$errno}\n";
    exit 1;
  } else {
    $dedup{$errno} = $oberr;
  }
}

# sort
my @os_pairs = map {[$_, $os_map{$_}->[0] ]} keys %os_map;
my @os_sorted = sort {$b->[1] <=> $a->[1]} @os_pairs;
my @os_errors = map {$_->[0]} @os_sorted;

# generate os_errno.h
open my $fh_header_os, '>', "os_errno.h";
print $fh_header_os '/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

// DO NOT EDIT. This file is automatically generated from `ob_errno.def\'.
#ifndef OBERROR_OS_ERRNO_H
#define OBERROR_OS_ERRNO_H

// linux
#include <errno.h>

namespace oceanbase {
namespace common {

// The length of the second dimension, in order to solve the conflict of multiple identical error codes
constexpr int OS_MAX_SAME_ERROR_COUNT = 2;

constexpr int OS_MAX_ERROR_CODE = 135;
';
  for my $oserr (@os_errors) {
    print $fh_header_os "constexpr int $oserr = $os_map{$oserr}->[0];\n";
  }
print $fh_header_os '
const char* str_os_error_name(const int err);
const char* str_os_error_msg(const int err);
int os_errno(const int err);
} // end namespace common
} // end namespace oceanbase

#endif /* OBERROR_OS_ERRNO_H */
';

# generate os_errno.cpp
open my $fh_cpp_os, '>', "os_errno.cpp";
print $fh_cpp_os '/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

// DO NOT EDIT. This file is automatically generated from `ob_errno.def\'.

#include "os_errno.h"
#include <string.h>
#include <cstdio>
using namespace oceanbase::common;

static const char *OS_ERRNO_NAME[OS_MAX_ERROR_CODE];
static const char *OS_ERRNO_MSG[OS_MAX_ERROR_CODE];
static int OS_ERRNO[OS_MAX_ERROR_CODE];

static struct OSStrErrorInit
{
  OSStrErrorInit() {
    memset(OS_ERRNO_NAME, 0, sizeof(OS_ERRNO_NAME));
    memset(OS_ERRNO_MSG, 0, sizeof(OS_ERRNO_MSG));
    memset(OS_ERRNO, 0, sizeof(OS_ERRNO));

';
    for my $oserr (@os_errors) {
      if (0 > $os_map{$oserr}->[0]) {
        print $fh_cpp_os "    OS_ERRNO_NAME[-$oserr] = \"$os_map{$oserr}->[2]\";\n";
        print $fh_cpp_os "    OS_ERRNO_MSG[-$oserr] = $os_map{$oserr}->[3];\n";
        print $fh_cpp_os "    OS_ERRNO[-$oserr] = $os_map{$oserr}->[1];\n";
      }
    }
  print $fh_cpp_os '
  }
} local_init;

namespace oceanbase {
namespace common {
const char *str_os_error_name(const int err)
{
  const char *ret = "Unknown error";
  if (0 == err) {
    ret = "OB_SUCCESS";
  } else if (0 > err && err > -OS_MAX_ERROR_CODE) {
    ret = OS_ERRNO_NAME[-err];
    if (NULL == ret || \'\0\' == ret[0])
    {
      ret = "Unknown Error";
    }
  }
  return ret;
}
const char *str_os_error_msg(const int err)
{
  const char *ret = NULL;
  if (0 == err) {
    ret = NULL;
  } else if (0 > err && err > -OS_MAX_ERROR_CODE) {
    ret = OS_ERRNO_MSG[-err];
    if (NULL == ret || \'\0\' == ret[0])
    {
      ret = NULL;
    }
  }
  return ret;
}
int os_errno(const int err)
{
  int ret = -1;
  if (0 >= err && err > -OS_MAX_ERROR_CODE) {
    ret = OS_ERRNO[-err];
  }
  return ret;
}
} // end namespace common
} // end namespace oceanbase
 ';
