cmake_minimum_required(VERSION 3.16)

project(des_undes VERSION 1.1.0 LANGUAGES C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

set(CRYPTLIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/cryptlib-0.99")

# CRYPTLIB 0.99 registers all algorithms in crypt.c at startup, so all of the
# original algorithm backends must be linked even though DES/UNDES itself uses
# only CRYPT_ALGO_3DES + CRYPT_MODE_CBC.
add_library(cryptlib099 STATIC
    ${CRYPTLIB_DIR}/crypt.c
    ${CRYPTLIB_DIR}/lib_3des.c
    ${CRYPTLIB_DIR}/lib_des.c
    ${CRYPTLIB_DIR}/lib_idea.c
    ${CRYPTLIB_DIR}/lib_mdc.c
    ${CRYPTLIB_DIR}/lib_null.c
    ${CRYPTLIB_DIR}/lib_rc4.c
    ${CRYPTLIB_DIR}/lib_safr.c
    ${CRYPTLIB_DIR}/idea/idea.c
    ${CRYPTLIB_DIR}/libdes/3ecb_enc.c
    ${CRYPTLIB_DIR}/libdes/ecb_enc.c
    ${CRYPTLIB_DIR}/libdes/pcbc_enc.c
    ${CRYPTLIB_DIR}/libdes/set_key.c
    ${CRYPTLIB_DIR}/rc4/rc4.c
    ${CRYPTLIB_DIR}/safer/safer.c
    ${CRYPTLIB_DIR}/mdc/shs.c
)

target_include_directories(cryptlib099 PUBLIC
    ${CRYPTLIB_DIR}
)


# The original makefile used __UNIX__ for Unix builds.
if(UNIX)
    target_compile_definitions(cryptlib099 PRIVATE __UNIX__)
endif()

add_library(des_common STATIC des_common.c)
target_include_directories(des_common PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CRYPTLIB_DIR}
)
target_link_libraries(des_common PUBLIC cryptlib099)

add_executable(des des.c)
add_executable(undes undes.c)

target_link_libraries(des PRIVATE des_common)
target_link_libraries(undes PRIVATE des_common)

# des.c and undes.c deliberately retain the original DOS-style <io.h>, read()
# and fileno() calls.  POSIX systems have these declarations in <unistd.h>, so
# provide a tiny generated compatibility header without changing the recovered
# source files.
if(UNIX)
    set(COMPAT_DIR "${CMAKE_CURRENT_BINARY_DIR}/compat")
    file(MAKE_DIRECTORY "${COMPAT_DIR}")
    file(WRITE "${COMPAT_DIR}/io.h" "#ifndef DES_COMPAT_IO_H\n#define DES_COMPAT_IO_H\n#include <unistd.h>\n#endif\n")
    target_include_directories(des PRIVATE "${COMPAT_DIR}")
    target_include_directories(undes PRIVATE "${COMPAT_DIR}")
endif()

# Modern Microsoft C uses underscored names for these POSIX-compatible calls.
#if(MSVC)
#    target_compile_definitions(des PRIVATE
#        _CRT_SECURE_NO_WARNINGS
#        fileno=_fileno
#        read=_read
#    )
#    target_compile_definitions(undes PRIVATE
#        _CRT_SECURE_NO_WARNINGS
#        fileno=_fileno
#        read=_read
#    )
#    target_compile_definitions(cryptlib099 PRIVATE __WINDOWS__ _CRT_SECURE_NO_WARNINGS)
#endif()

if(MSVC)
    target_compile_definitions(cryptlib099 PRIVATE
        _CRT_SECURE_NO_WARNINGS
    )

    target_compile_definitions(des PRIVATE
        _CRT_SECURE_NO_WARNINGS
        fileno=_fileno
        read=_read
    )

    target_compile_definitions(undes PRIVATE
        _CRT_SECURE_NO_WARNINGS
        fileno=_fileno
        read=_read
    )
endif()


install(TARGETS des undes RUNTIME DESTINATION bin)
