初始化状态机实现

main.h

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>

typedef enum {
    NOT_INIT,
    INIT_PWD_FIRST,
    INIT_PWD_SECOND,
    INIT_COMPARE_PWD,
    INIT_DONE,
    INIT_FAILED
} INIT_STATE_FINAL;

void read_pwd(char* pwd, size_t len);
int compare_str(char* str1, char* str2);

void read_password(char *password, size_t size) {
    struct termios old_termios, new_termios;

    // 获取当前终端属性
    tcgetattr(STDIN_FILENO, &old_termios);
    new_termios = old_termios;

    // 禁用回显功能
    new_termios.c_lflag &= ~ECHO;

    // 设置新的终端属性
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_termios);

    // 提示用户输入密码
    printf("请输入密码: ");
    fgets(password, size, stdin);

    // 恢复原来的终端属性
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_termios);

    // 去除换行符
    size_t len = 0;
    while (password[len] != '\0' && password[len] != '\n') {
        len++;
    }
    password[len] = '\0';
}

typedef enum{
    STATE_NOT_INIT,
    STATE_INITING,
    STATE_INIT_DONE
} INIT_STATE;

typedef enum{
    EVENT_PROMPRT,
    EVENT_UNAME,
    EVENT_PWD,
    EVENT_DONE
} INIT_EVENT;

void read_uname(char* uname, size_t* out_len)
{
    char buffer[100];
 
    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        // fgets 会读取换行符,如果需要可以去掉
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len-1] == '\n') {
            buffer[len-1] = '\0'; // 去掉换行符
        }
        printf("You entered: %s\n", buffer);
        strncpy(uname, buffer, sizeof(buffer) - 1);
    } else {
        printf("Error reading input.\n");
    }
}

void process_init(INIT_STATE* cur_state, INIT_EVENT cur_event, char* str, size_t len)
{
    switch (*cur_state) {
    case STATE_NOT_INIT:
        if (cur_event == EVENT_PROMPRT) {
            printf("enter init\n");
            *cur_state = STATE_INITING;
        }
        break;
    case STATE_INITING:
        if (cur_event == EVENT_UNAME) {
            printf("please input uname:");
            char uname[100] = {0};
            //获取用户名
            read_uname(uname, sizeof(uname));
            strncpy(str, uname, sizeof(uname));
            //*cur_state = STATE_INITING;
        }else if (cur_event == EVENT_PWD) {
            char pwd01[100] = {0};
            read_pwd(pwd01, sizeof(pwd01));
            //状态未变化
            strncpy(str, pwd01, sizeof(pwd01) - 1);
            memset(pwd01, 0, sizeof(pwd01));
        }else if (cur_event == EVENT_DONE) {
            printf("init success\n");
            *cur_state = STATE_INIT_DONE;
        }
        break;
    case STATE_INIT_DONE:
        if (cur_event == EVENT_DONE) {
            printf("init done\n");
        }
        break;
    default:
        break;
    }
}

void test_switch()
{
    char uname[100] = {0};
    char pwd[100] = {0};
    char confirm_pwd[100] = {0};
    INIT_STATE cur_state = STATE_NOT_INIT;

    // 提示
    process_init(&cur_state, EVENT_PROMPRT, NULL, 0);
    process_init(&cur_state, EVENT_UNAME, uname, sizeof(uname));
    process_init(&cur_state, EVENT_PWD, pwd, sizeof(pwd));
    process_init(&cur_state, EVENT_PWD, confirm_pwd, sizeof(confirm_pwd));

    if (0 == compare_str(pwd, confirm_pwd)) {
        printf("pwd is equal\n");
    }else {
        printf("pwd is not equal\n");
    }

    process_init(&cur_state, EVENT_DONE, NULL, 0);
    process_init(&cur_state, EVENT_DONE, NULL, 0);

    printf("uname is [%s], pwd is [%s]\n", uname, pwd);

}

int compare_str(char* str1, char* str2)
{
    if(str1[0] == '\0' || str2[0] == '\0') {
        return -1;
    }

    int i = 0;
    while (str1[i] != '\0') {
        
        if (str1[i] != str2[i]) {
            break;
        }
        ++i;

        if(str1[i] == '\0' && str2[i] == '\0') {
            return 0;
        } else if(str1[i] == '\0' || str2[i] == '\0') {
            break;
        }
    }

    return -1;
}

void read_pwd(char* pwd, size_t len)
{
    const char* tmpPasswd = NULL;
    tmpPasswd = getpass("please input passwd:");
    strncpy(pwd, tmpPasswd, len);
    printf("pwd is [%s]\n", pwd);
    if (tmpPasswd[0] != '\0') {
        //避免memset被编译器优化
        volatile char *volatile_password = (volatile char *)tmpPasswd;
        memset((void *)volatile_password, 0, strlen(tmpPasswd));
    }
}


void read_pwd_twice()
{
    const char* tmpPasswd = NULL;
    char passwd[2][128] = {{0}};
    tmpPasswd = getpass("please input passwd:");
    //密码复杂度检查
    strncpy(passwd[0], tmpPasswd, sizeof(passwd[0]) - 1);
    // volatile char *volatile_password = (volatile char *)tmpPasswd;
    // memset((void *)volatile_password, 0, strlen(volatile_password));

    printf("pwd01 [%s]\n", passwd[0]);
    tmpPasswd = NULL;
    tmpPasswd = getpass("please input confirm passwd:");

    strncpy(passwd[1], tmpPasswd, sizeof(passwd[0]) - 1);
    printf("pwd02 [%s]\n", passwd[1]);

    if (compare_str(passwd[0], passwd[1])) { //密码不匹配
        //重新读取密码
    }

}

void init_machine()
{
    int init_flag = 1;
    int max_init_times = 3;
    INIT_STATE_FINAL cur_state = NOT_INIT;
    char pwd01[100] = {0};
    char pwd02[100] = {0};

    while (init_flag) { // init done or reach max retry
        if (max_init_times == 0) {
            printf("block\n");
            break;
        }

        switch (cur_state) {
        case NOT_INIT:
                printf("enter init\n");
                cur_state = INIT_PWD_FIRST;
            break;
        case INIT_PWD_FIRST:
                read_pwd(pwd01, sizeof(pwd01));
                cur_state = INIT_PWD_SECOND;
            break;
        case INIT_PWD_SECOND:
            read_pwd(pwd02, sizeof(pwd02));
            cur_state = INIT_COMPARE_PWD;
            break;
        case INIT_COMPARE_PWD:
            if (compare_str(pwd01, pwd02)) {
                //重新输入密码
                printf("password set failed\n");
                cur_state = INIT_FAILED;
            }
            else {
                printf("password set success\n");
                cur_state = INIT_DONE;
            }
            break;
        case INIT_DONE:
            init_flag = 0;
            max_init_times = 0;
            printf("init success\n");
            break;
        case INIT_FAILED:
            max_init_times--;
            cur_state = INIT_PWD_FIRST;
            memset(pwd01, 0, sizeof(pwd01));
            memset(pwd02, 0, sizeof(pwd02));
            break;
        default:
            break;
        }
    }
}

main.c

#include "main.h"
#include <stdio.h>
#include <unistd.h>
int main()
{
#if 0
    // 方式1: 修改终端属性
    char passwd[100] = {0};
    read_password(passwd, sizeof(passwd));
    printf("\npasswd [%s]\n", passwd);
    #else
    // 方式2:调用系统接口
    // const char* pwd = NULL;
    // pwd = getpass("please input passwd:");

    // printf("pwd is %s\n", pwd);
    /*
    char pwd01[100] = {0};
    char pwd02[100] = {0};
    read_pwd(pwd01, sizeof(pwd01));
    read_pwd(pwd02, sizeof(pwd02));
    if (compare_str(pwd01, pwd02)) {
        //重新输入密码
        printf("password set failed\n");
    }
    else {
        printf("password set success\n");
    }*/
    #endif
    
    // 进程间通信
    // init_machine();
    // 进程间通信
    test_switch();
    return 0;
}
posted @   菠萝超级酸  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示