선우의 코딩일지

C) C언어로 회원가입/로그인 시스템 구현하기! 본문

C

C) C언어로 회원가입/로그인 시스템 구현하기!

sunwookim05 2023. 3. 19. 00:22

얼마 전 친구들이 디코에서 회원가입/로그인 시스템을 만들고 있길래 재밌어 보여서 C로 만들어 봤다.

https://github.com/sunwookim05/Member-management-system

 

GitHub - sunwookim05/Member-management-system

Contribute to sunwookim05/Member-management-system development by creating an account on GitHub.

github.com

먼저 main.h 를 만든다 모든 코드의 베이스가 됄 코드이다.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>

#pragma once
#ifndef __MAIN_H
#define __MAIN_H

#define import extern
#define final const
#define null NULL
#define false 0
#define true 1

typedef char *String;
typedef char byte;
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char ubyte;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef uint8_t boolean;

#pragma warning(pop)
#endif

그리고 전에 만들었던 Scanner-with-C 를 활용하고 싶어 Scanner와 System 클래스를 구현했다.

 

System.h

#include "main.h"

#pragma once
#ifndef __SYSTEM_H
#define __SYSTEM_H

struct __stdin_t;

#pragma pack(push, 1)
/**
 * The {@code System} class contains several useful class fields
 * and methods. It cannot be instantiated.
 *
 * Among the facilities provided by the {@code System} class
 * are standard input, standard output, and error output streams;
 * access to externally defined properties and environment
 * variables; a means of loading files and libraries; and a utility
 * method for quickly copying a portion of an array.
 *
 * @since   1.0
 */
typedef struct _System{
    struct __stdout_t{
        /**
        * @brief System out print function
        * @param format
        * @return void
        */
        void (*print)(const String, ...);
        /** 
        * @brief System out println function
        * @param format
        * @return void
        */
        void (*println)(const String, ...);
    }out;
    struct __stdin_t{
        int (*read)();
    } in;
}SYSTEM;
#pragma pack(pop)

#pragma warning(pop)
#endif

Scanner.h

#include "main.h"

#pragma once
#ifndef __Scanner_H
#define __Scanner_H

struct __stdin_t;

#pragma pack(push, 1)
/** 
 * @brief Scanner class
 */
typedef struct Scanner{
    /**
    * @brief User input char
    * @param void
    * @return char
    */    
    char (*nextChar)(void);

    /**
     * @brief User input Byte
     * @param void
     * @return byte
     */
    byte (*nextByte)(void);

    /**
     * @brief User input Short
     * @param void
     * @return int16_t
     */
    int16_t (*nextShort)(void);

    /**
     * @brief User input Int
     * @param void
     * @return int32_t
     */
    int32_t (*nextInt)(void);

    /**
     * @brief User input Long
     * @param void
     * @return int64_t
     */
    int64_t (*nextLong)(void);

    /**
     * @brief User input Unsigned Byte
     * @param void
     * @return ubyte
     */
    ubyte (*nextUByte)(void);

    /**
     * @brief User input Unsigned Short
     * @param void
     * @return uint16_t
     */
    uint16_t (*nextUShort)(void);

    /**
     * @brief User input Unsigned Int
     * @param void
     * @return uint32_t
     */
    uint32_t (*nextUInt)(void);

    /**
     * @brief User input Unsigned Long
     * @param void
     * @return uint64_t
     */
    uint64_t (*nextULong)(void);

    /**
     * @brief User input boolean
     * @param void
     * @return boolean
     */
    boolean (*nextBoolean)(void);

    /**
     * @brief User input Float
     * @param void
     * @return float
     */
    float (*nextFloat)(void);

    /**
     * @brief User input Double
     * @param void
     * @return double
     */
    double (*nextDouble)(void);

    /**
     * @brief User input Long Double
     * @param void
     * @return long double
     */
    long double (*nextLDouble)(void);

    /**
     * @brief User input String no Spaces
     * @param void
     * @return String
     */
    String (*next)(void);

    /**
     * @brief User input String with Spaces
     * @param void
     * @return String
     */
    String (*nextLine)(void);
}Scanner;
#pragma pack(pop)

Scanner new_Scanner(struct __stdin_t);

#pragma warning(pop)
#endif

Systemout.c

#include "main.h"
#include "System.h"

void print(const String format, ...) {va_list ap;char buf[4096];va_start(ap, format);vsprintf(buf, format, ap);va_end(ap);fprintf(stdout, "%s", buf);}
void println(const String format, ...) {va_list ap;char buf[4096];va_start(ap, format);vsprintf(buf, format, ap);va_end(ap);fprintf(stdout, "%s\n", buf);}

SYSTEM System = {print, println};

Scanner.c

#include "main.h"
#include "System.h"
#include "Scanner.h"

char nextChar(void){
    char c;
    scanf("%c", &c);
    getchar();
    return c;
}

int8_t nextByte(void){
    int8_t b;
    scanf("%hhd", &b);
    getchar();
    return b;
}

int16_t nextShort(void){
    int16_t s;
    scanf("%hd", &s);
    getchar();
    return s;
}

int32_t nextInt(void){
    int32_t i;
    scanf("%d", &i);
    getchar();
    return i;
}

int64_t nextLong(void){
    int64_t l;
    scanf("%lld", &l);
    getchar();
    return l;
}

uint8_t nextUByte(void){
    uint8_t b;
    scanf("%hhu", &b);
    getchar();
    return b;
}

uint16_t nextUShort(void){
    uint16_t s;
    scanf("%hu", &s);
    getchar();
    return s;
}

uint32_t nextUInt(void){
    uint32_t i;
    scanf("%u", &i);
    getchar();
    return i;
}

uint64_t nextULong(void){
    uint64_t l;
    scanf("%llu", &l);
    getchar();
    return l;
}

boolean nextBoolean(void){
    String s = (String)calloc(0, sizeof(char) * 5);
    scanf("%s", s);
    if(atoi(s)|| !strncmp(s, "true", 4) || !strncmp(s, "True", 4) || !strncmp(s, "TRUE", 4)){
        free(s);
        return true;
    }else{
        free(s);
        return false;
    }
}

float nextFloat(void){
    float f;
    scanf("%f", &f);
    getchar();
    return f;
}

double nextDouble(void){
    double d;
    scanf("%lf", &d);
    getchar();
    return d;
}

long double nextLDouble(void){
    long double ld;
    scanf("%Lf", &ld);
    getchar();
    return ld;
}

String next(void){
    String s = (String)calloc(0, sizeof(char) * 4096);
    scanf("%s", s);
    s = (String)realloc(s, sizeof(char) * (strlen(s) + 1));
    getchar();
    return s;
}

String nextLine(void){
    String s = (String)calloc(0, sizeof(char) * 4096);
    scanf("%[^\n]", s);
    getchar();
    return s;
}

/**
* Constructs a new {@code Scanner} that produces values scanned
* from the specified input stream. Bytes from the stream are converted
* into characters using the underlying platform's
*
* @param  source An input stream to be scanned
*/
Scanner new_Scanner(struct __stdin_t source){
    Scanner scanner = {
        .nextChar = nextChar,
        .nextByte = nextByte,
        .nextShort = nextShort,
        .nextInt = nextInt,
        .nextLong = nextLong,
        .nextUByte = nextUByte,
        .nextUShort = nextUShort,
        .nextUInt = nextUInt,
        .nextULong = nextULong,
        .nextBoolean = nextBoolean,
        .nextFloat = nextFloat,
        .nextDouble = nextDouble,
        .nextLDouble = nextLDouble,
        .next = next,
        .nextLine = nextLine
    };
    return scanner;
}

다음으론 User 의 정보를 저장하고 처리할 수 있는 User 클래스를 구현하기 위해 User.h 와 User.c 를 만들었다.

 

User.h

#include "main.h"

#pragma once
#ifndef __User_H
#define __User_H

typedef struct __USERDATA__{
    String id;
    String password;
}USERDATA;

typedef struct __USERS__{
    void (*writeLog)(uint8_t, USERDATA, FILE *);
    boolean (*logout)(USERDATA *);
    boolean (*signup)(USERDATA *, FILE *);
    boolean (*login)(USERDATA *, FILE *);
}USERS;

typedef enum __MENU__{
    SIGNUP = 1, LOGIN, LOGOUT, USERINFO,  EXIT
}__MENU__;

typedef uint8_t MENU;

USERS new_User();
USERDATA new_UserData();
void delete_UserData(USERDATA *);

#pragma warning(pop)
#endif

User.c

#include "User.h"
#include "System.h"
#include "Scanner.h"

import SYSTEM System;

void delete_UserData(USERDATA *info){
    free(info->id);
    free(info->password);
}

void writeLog(uint8_t logCate, USERDATA info, FILE *fp){
    String logCateStr[3] = {"SIGNUP", "LOGIN", "LOGOUT"};
    time_t t = time(NULL);
    struct tm tm = *localtime(&t);
    fp = fopen("log.txt", "a");
    fprintf(fp, "%d-%d-%d %d:%d:%d %s\nID: %s\nPassword: %s\n\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, logCateStr[logCate - 1], info.id, info.password);
    fclose(fp);
}

boolean signup(USERDATA *info, FILE *fp){
    Scanner sc = new_Scanner(System.in);
    fp = fopen("user.txt", "r");
    System.out.println("Sign up");
    System.out.print("ID: ");
    info->id = sc.next();
    System.out.print("Password: ");
    info->password = sc.next();

    USERDATA user = new_UserData();
    while (fscanf(fp, "%s", user.id) != EOF){
        if(!strcmp(info->id, user.id)){
            delete_UserData(&user);
            return false;
        }
    }
    delete_UserData(&user);
    fclose(fp);

    fp = fopen("user.txt", "a");
    fprintf(fp, "%s %s\n", info->id, info->password);
    fclose(fp);
    return true;
}

boolean login(USERDATA *user, FILE *fp){
    Scanner sc = new_Scanner(System.in);
    fp = fopen("user.txt", "r");
    System.out.println("Login");
    System.out.print("ID: ");
    user->id = sc.next();
    System.out.print("Password: ");
    user->password = sc.next();
    
    USERDATA info = new_UserData();
    
    while (fscanf(fp, "%s %s", info.id, info.password) != EOF){
        if(!strcmp(user->id, info.id) && !strcmp(user->password, info.password)){
            delete_UserData(&info);
            fclose(fp);
            return true;
        }
    }
    fclose(fp);
    delete_UserData(&info);
    return false;
}

boolean logout(USERDATA *info){
    Scanner sc = new_Scanner(System.in);
    System.out.print("Do you want to logout? (y/n): ");
    char bf = sc.nextChar();
    if(bf == 'y' | 'Y'){
        info->id = NULL;
        info->password = NULL;
        delete_UserData(info);
        System.out.println("Logout success");
        return true;
    }else{
        System.out.println("Logout failed");
        return false;
    }
}

USERS new_User(){
    USERS user;
    user.logout = logout;
    user.signup = signup;
    user.login = login;
    user.writeLog = writeLog;
    return user;
}

USERDATA new_UserData(){
    USERDATA info;
    info.id = (String)calloc(0, sizeof(char) * 20);
    info.password = (String)calloc(0, sizeof(char) * 20);
    return info;
}

마지막으로 클래스들을 활용하여 호출할 메인 클레스를 만든다.

 

main.c

#include "main.h"
#include "System.h"
#include "Scanner.h"
#include "User.h"

import SYSTEM System;

int main(void){
    Scanner sc = new_Scanner(System.in);
    USERS users = new_User();
    USERDATA user = new_UserData();
    FILE *fp;
    boolean isSignup = false;
    boolean isLogin = false;
    boolean isLogout = true;
    MENU menu = 0;

    while (true){
        System.out.print("Select menu\n1. Sign up\n2. Login\n3. Logout\n4. LOGININFO\n5. EXIT\n");
        menu = sc.nextUByte();
        if(menu == SIGNUP){
            isSignup = users.signup(&user, fp);
            System.out.println(isSignup ? "Sign up success" : "Sign up failed");
            if (isSignup) users.writeLog(SIGNUP, user, fp);
        }else if(menu == LOGIN){
            if(isLogin){
                System.out.println("Already login");
            }else{
                isLogin = users.login(&user, fp);
                System.out.println(isLogin ? "Login success" : "Login failed");
                users.writeLog(LOGIN, user, fp);
            }
        }else if(menu == LOGOUT){
            if(!isLogin){
                System.out.println("Already logout");
            }else{
                users.writeLog(LOGOUT, user, fp);
                isLogout = users.logout(&user);
                if(isLogout) isLogin = false;
            }
        }else if(menu == USERINFO){
            if(isLogin) System.out.println("ID: %s\nPassword: %s", user.id, user.password);
            else System.out.println("Please login");
        }else if(menu == EXIT){
            break;
        }else{
            System.out.println("Wrong menu");
        }
    }

    delete_UserData(&user);
    return 0;
}

콘솔에 이렇게 입력하면 실행이 된다.

gcc -c src\main.c -I inc\

gcc -c src\Scanner.c -I inc\

gcc -c src\Systemout.c -I inc\

gcc -c src\User.c -I inc\

gcc -o main main.o Scanner.o Systemout.o User.o

.\main

 

Comments