学生信息管理系统SIMS

学生信息管理系统SIMS

[root@matrix sims]# ll
总计 108
-rwxr-xr-x 1 root root 23947 05-08 23:50 a
-rw-r--r-- 1 root root   198 05-04 12:00 ABOUT
-rw-r--r-- 1 root root    43 05-07 16:44 demo.c
-rw-r--r-- 1 root root   288 05-05 13:58 EXAMPLE
-rw-r--r-- 1 root root   401 05-08 23:50 main.c
-rw-r--r-- 1 root root   291 05-04 20:22 Makefile
-rw-r--r-- 1 root root 17960 05-07 20:17 misc.c
-rw-r--r-- 1 root root  3088 05-07 20:17 misc.h
-rw-r--r-- 1 root root   140 05-04 12:03 README
[root@matrix sims]# make
gcc -c main.c
gcc -c misc.c
gcc -o a main.o misc.o
[root@matrix sims]# a

欢迎使用(学生信息管理系统SIMS)\\\\\\\\
______________________________________________
用户名: root
口令: hacker
认证失败,请检查字母大小写是否正确。
用户名: root
口令: hacking
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
[X]记录查询失败!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 1
______________________________________________
当前位置(主页/添加记录)
学号: 101
姓名: Jeff Conrad
性别: M
年龄: 24
电话: 10086
出生(年): 1988
出生(月): 3
出生(日): 24
语文成绩: 78
数学成绩: 78
英语成绩: 88
本次索引节点为1
[V]记录添加成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 1
______________________________________________
当前位置(主页/添加记录)
学号: 102
姓名: Junkie Pro
性别: F
年龄: 25
电话: 10000
出生(年): 1988
出生(月): 4
出生(日): 3
语文成绩: 99
数学成绩: 34
英语成绩: 55
本次索引节点为2
[V]记录添加成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 1
______________________________________________
当前位置(主页/添加记录)
学号: 101
[X]ID冲突!
学号: 103
姓名: Lady GaGa
性别: M
年龄: 35
电话: 12580
出生(年): 1978
出生(月): 8
出生(日): 3
语文成绩: 99
数学成绩: 56
英语成绩: 44
本次索引节点为3
[V]记录添加成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
学号 姓名         性别 年龄 电话        出生       语文 数学 英语 节点
......................................................................
101  Jeff Conrad  M    24   10086       1988-03-24 78   78   88   1  
102  Junkie Pro   F    25   10000       1988-04-03 99   34   55   2  
103  Lady GaGa    M    35   12580       1978-08-03 99   56   44   3  
......................................................................
记录: 共3项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 1
关键字: a
学号 姓名         性别 年龄 电话        出生       语文 数学 英语 节点
......................................................................
101  Jeff Conrad  M    24   10086       1988-03-24 78   78   88   1  
103  Lady GaGa    M    35   12580       1978-08-03 99   56   44   3  
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 2
资料: 学号( 0) 姓名( 1) 性别( 2) 年龄( 3) 电话( 4) 
生日: 年份( 5) 月份( 6) 号数( 7) 
成绩: 语文( 8) 数学( 9) 英语(10)
序号: 2
性别: M
101  Jeff Conrad  M    24   10086       1988-03-24 78   78   88   1  
103  Lady GaGa    M    35   12580       1978-08-03 99   56   44   3  
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 2
______________________________________________
学号: 104
[X]ID无效!
学号: 103
确定删除? (y or n): y
[V]记录删除成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
学号 姓名         性别 年龄 电话        出生       语文 数学 英语 节点
......................................................................
101  Jeff Conrad  M    24   10086       1988-03-24 78   78   88   1  
102  Junkie Pro   F    25   10000       1988-04-03 99   34   55   2  
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 3
______________________________________________
学号: 101
姓名: Jeff Conrad
性别: F
年龄: 10086
电话: 10086
出生(年): 1989
出生(月): 3
出生(日): 26
语文成绩: 99
数学成绩: 98
英语成绩: 98
[V]记录修改成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
学号 姓名         性别 年龄 电话        出生       语文 数学 英语 节点
......................................................................
101  Jeff Conrad  F    1008610086       1989-03-26 99   98   98   1  
102  Junkie Pro   F    25   10000       1988-04-03 99   34   55   2  
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 6
______________________________________________
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
功能模块:
        增加  删除  修改  查询
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
按下回车键返回: 
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 7
______________________________________________
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                欢迎使用SIMS v3
版本: 3.0.0
发行者: Junkie Pro
创建日期: 2013年05月01日
QQ: 614616185
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
按下回车键返回: 
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 0
______________________________________________
______________________________________________
\\\\\\\\感谢使用(学生信息管理系统SIMS)
[root@matrix sims]# 




[root@matrix sims]# '/root/project/sims/ABOUT' 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		欢迎使用SIMS v3
版本: 3.0.0
发行者: Junkie Pro
创建日期: 2013年05月01日
QQ: 614616185
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


[root@matrix sims]# '/root/project/sims/README' 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
功能模块:
	增加  删除  修改  查询
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



[root@matrix sims]# '/root/project/sims/Makefile' 
a: misc.h main.o misc.o
	gcc -o a main.o misc.o
misc.o: misc.h misc.c
	gcc -c misc.c
main.o: misc.h main.c
	gcc -c main.c
clean:
	rm -f *.o
reset: 
	rm -f DATABASE.DB
restore: 
	ls -l EXAMPLE && cp -f EXAMPLE DATABASE.DB && echo RESTORE OK || echo NO EXAMPLE
help:
	clear
	cat README | more


[root@matrix sims]# '/root/project/sims/DATABASE.DB' 



[root@matrix sims]# '/root/project/sims/EXAMPLE' 


[root@matrix sims]# '/root/project/sims/main.c' 
#include "misc.h"
int main(){
	system("clear");
	Head();
	if (Login("root", "hacking", 3)){//待办----文件
		Tail();
		return -1;
	}
	while (1){
		DividingLine('_', 1, 46);
		Body();
		int cn = ChoiceNumber("", OPTION_EXIT, OPTION_ABOUT, 3);
		if (-1 == cn){
			Tail();
			return -1;//建议不在此使用break;以增强程序的扩展性
		}
		if (Execute(cn))
			break;
	}
	Tail();
	return 0;
}


[root@matrix sims]# '/root/project/sims/misc.h' 
#ifndef __MISC_H__
#define __MISC_H__
#define DATABASE "DATABASE.DB"
#define TABLE_HEAD 128
#define TABLE_TAIL 256
#define KEYWORD_LIMIT 100//关键字上限为100个字符(百度一下,你就知道)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//enum枚举: 默认从0开始递增, 手动起始值(保险起见)
enum {DATATYPE_CHAR = 0, DATATYPE_INT, DATATYPE_FLOAT, DATATYPE_DOUBLE, DATATYPE_STRING};
enum {OPTION_EXIT = 0, OPTION_ADD, OPTION_DEL, OPTION_EDIT, OPTION_QUERY, OPTION_SETTING, OPTION_HELP, OPTION_ABOUT};
typedef enum {QUERY_ALL, QUERY_LIKE, QUERY_WHERE} query_e;//将QUERY_ALL排在第一位是因为键盘布局
typedef enum {CON_ID = 0, CON_NAME, CON_SEX, CON_AGE, CON_TELEPHONE, CON_YEAR, CON_MONTH, CON_DAY, CON_CHINESE, CON_MATH, CON_ENGLISH, } CONDITION;//看个人习惯,建议设置为0,而不是1
enum {SYMBOL_YES, SYMBOL_NO};//数字数位
typedef struct {size_t year, month, day;} date_s;
typedef struct {
	char fill_a:3;
	size_t content;
	char fill_b:5;
} table_s;
typedef struct {
	table_s start;
	size_t id;
	char name[20];
	char sex[4];
	size_t age;
	char telephone[12];
	date_s birth;
	struct result_s {
		size_t chinese, math, english;
	} score;
	size_t inode;
	table_s end;
} student_s;
int Login(const char *username, const char *password, size_t n);//登录
void CleanStdin(void);//清理stdin流中残留数据
int ClearLF(char *str, size_t n);//清除字符串中'\n'字符 LF(line feed)
int IsNull(const char *str);//检测字符串是否为空
void Head(void);//显示系统头部信息
void Body(void);//显示系统主要信息
void Tail(void);//显示系统退出信息
int ChoiceNumber(const char *prompt, int begin, int end, size_t n);//选择数字
int IsExistID(size_t s_id);//检测ID是否存在
int Edit(size_t n);//修改记录
int Del(size_t n);//删除记录
int Execute(size_t n);//执行对应功能
int IsExistFile(const char *path);//检测文件是否存在
int ReadText(const char *path);//显示文本文件内容
void DividingLine(int c, size_t row, size_t col);//打印分界线
int Add(const size_t etc);//添加记录
int GetData(const char *prompt, int type, void *var, size_t n);//输入数据
int GetString(const char *prompt, char *ptr, size_t len, size_t n);//输入字符串
int ProduceInode(void);//生成索引节点
int CountRecord(void);//统计记录条目
int SearchString(const char *keyword, const char *content);//搜索字符串
void InitCA(char *ca, size_t n);//初始化字符数组
int Query(int flag);//查询所有数据
void ShowMe(const char *path, const char *object);//显示指定文本内容
int ChooseKey(const char *prompt);//获取一个按键
int NumericDigits(int integer, int flag);
int DigitalConversionString(int integer, char *buf, size_t size, int flag);
int ReverseString(char *src, size_t len);//逆转字符串
void Debug(void);
#endif//__MISC_H__
//增加重建索引节点,序列递增修改原始节点号,
//1,3,5//在生成新节点后删除了2号节点
//1,2,3//重建索引节点后
//可以按照索引节点进行数据库排序



[root@matrix sims]# '/root/project/sims/misc.c' 
#include "misc.h"
int Login(const char *username, const char *password, size_t n){;
	if (!(username && password))
		return -1;
	size_t len_user = strlen(username), 
		   len_pswd = strlen(password);
	if (!(len_user && len_pswd))
		return -1;
	char rec_user[len_user + 2], 
		 rec_pswd[len_pswd + 2];//多一个字节用于检测用户是否过多输入
	size_t siz_user = sizeof(rec_user), 
		   siz_pswd = sizeof(rec_pswd);
	while(n--){
		printf("用户名: ");
		fgets(rec_user, siz_user, stdin);
		if (IsNull(rec_user))
			if (ClearLF(rec_user, strlen(rec_user)))
				CleanStdin();
		printf("口令: ");
		fgets(rec_pswd, siz_pswd, stdin);
		if (IsNull(rec_pswd))
			if (ClearLF(rec_pswd, strlen(rec_pswd)))
				CleanStdin();
		if (strcmp(username, rec_user) || strcmp(password, rec_pswd)){
			puts("认证失败,请检查字母大小写是否正确。");
			continue;
		}
		return 0;
	}
	return -1;
}
void CleanStdin(void){
	scanf("%*[^\n]");
	scanf("%*c");
}
int ClearLF(char *str, size_t n){
	int i = 0;
	for (i = 0; i < n; i++)
		if ('\n' == str[i]){
			str[i] = '\0';
			return 0;
		}
	return -1;
}
int IsNull(const char *str){;
	if (!str)
		return 0;
	return strlen(str) > 0 ? -1 : 0;
}
void Head(void){
	puts("欢迎使用(学生信息管理系统SIMS)\\\\\\\\\\\\\\\\");
	DividingLine('_', 1, 46);
}
void Body(void){
	printf("增加(%d)\t删除(%d)\t修改(%d)\t查询(%d)\n设置(%d)\t帮助(%d)\t关于(%d)\t退出(%d)\n", 
			OPTION_ADD, OPTION_DEL, OPTION_EDIT, OPTION_QUERY, OPTION_SETTING, OPTION_HELP, OPTION_ABOUT, OPTION_EXIT);
}
void Tail(void){
	DividingLine('_', 1, 46);
	puts("\\\\\\\\\\\\\\\\感谢使用(学生信息管理系统SIMS)");
}
int ChoiceNumber(const char *prompt, int begin, int end, size_t n){
	while(n--){
		int num = -1;
		printf("%s: ", IsNull(prompt) ? prompt : "选项");
		int sv = scanf("%d", &num);
		CleanStdin();
		if (sv && num >= begin && num <= end)
			return num;
		printf("[X]错误%s!\n", IsNull(prompt) ? prompt : "选项");
	}
	return -1;
}
int IsExistID(size_t s_id){
	int res = -1;
	if (IsExistFile(DATABASE))
		return -1;
	FILE *fp = fopen(DATABASE, "rb");
	if (!fp)
		return -1;
	student_s t = {};
	while(!feof(fp)){
		if (1 != fread(&t, sizeof(student_s), 1, fp))
			break;
		if (s_id == t.id){
			res = 0;
			break;
		}
	}
	fclose(fp);
	fp = NULL;
	return res;
}
int Edit(size_t n){;
	if (IsExistFile(DATABASE))
		return -1;
	int dest = -1;
	int sid = -1;
	while(n--){
		if (!GetData("学号", DATATYPE_INT, &sid, 1))
			if (!IsExistID(sid)){
				dest = 0;
				break;
			}
			else 
				puts("[X]ID无效!");
	}
	if (dest)
		return -1;
	FILE *fp = fopen(DATABASE, "rb+");
	if (!fp)
		return -1;
	student_s tmp = {};
	int res = !0;
	while (!feof(fp)){
		if (1 != fread(&tmp, sizeof(student_s), 1, fp))
			break;
		if (sid == tmp.id){
			res = res && 
				!GetString("姓名", tmp.name, sizeof(tmp.name) / sizeof(*tmp.name), 2) && 
				!GetString("性别", tmp.sex, sizeof(tmp.sex) / sizeof(*tmp.sex), 2) && 
				!GetData("年龄", DATATYPE_INT, &tmp.age, 2) && 
				!GetString("电话", tmp.telephone, sizeof(tmp.telephone) / sizeof(*tmp.telephone), 2) && 
				!GetData("出生(年)", DATATYPE_INT, &tmp.birth.year, 2) && 
				!GetData("出生(月)", DATATYPE_INT, &tmp.birth.month, 2) && 
				!GetData("出生(日)", DATATYPE_INT, &tmp.birth.day, 2) && 
				!GetData("语文成绩", DATATYPE_INT, &tmp.score.chinese, 2) && 
				!GetData("数学成绩", DATATYPE_INT, &tmp.score.math, 2) && 
				!GetData("英语成绩", DATATYPE_INT, &tmp.score.english, 2);
			if (res){
				fseek(fp, -sizeof(student_s), SEEK_CUR);
				if (1 == fwrite(&tmp, sizeof(tmp), 1, fp)){
					fclose(fp);
					fp = NULL;
					return 0;
				}
			}
			fclose(fp);
			fp = NULL;
			return -1;
		}
	}
}
int Del(size_t n){
	size_t sid = 0;
	if (IsExistFile(DATABASE))
		return -1;
	while (n--){
		if (!GetData("学号", DATATYPE_INT, &sid, 1)){
			if (IsExistID(sid))
				puts("[X]ID无效!");
			else
				break;
		}
	}
	if (-1 == n)
		return -1;
	n = 3;
	int cn = 0;
	while(n--){
		cn = ChooseKey("确定删除? (y or n)");
		if ('n' == cn)
			return -1;
		else if ('y' == cn)
			break;
	}
	if (-1 == n)
		return -1;
	FILE *fp = fopen(DATABASE, "rb");
	if (!fp){
		fclose(fp);
		fp = NULL;
		return -1;
	}
	int con = 1;
	while (con){
		char *tfa = "tmp_";
		int tfb = rand();
		char tf[strlen(tfa) + NumericDigits(tfb, SYMBOL_NO) + 1];
		InitCA(tf, sizeof(tf));
		sprintf(tf, "%s%d", tfa, tfb);
		tf[sizeof(tf) - 1] = 0;
		if (IsExistFile(tf)){
			con = 0;
			FILE *dest = fopen(tf, "wb+");
			if (!dest)
				return -1;
			FILE *src = fopen(DATABASE, "rb");
			if (!src){
				fclose(dest);
				dest = NULL;
				return -1;
			}
			student_s ts = {};
			while(!feof(src)){
				if (1 != fread(&ts, sizeof(student_s), 1, src))
					break;
				if (sid != ts.id)
					if (1 != fwrite(&ts, sizeof(student_s), 1, dest))
						break;
			}
			fclose(dest);
			fclose(src);
			dest = src = NULL;
			remove(DATABASE);
			rename(tf, DATABASE);
			return 0;
		}
	}
	return -1;
}

int Execute(size_t n){
	DividingLine('_', 1, 46);
	switch(n){
		case OPTION_EXIT:
			return -1;
		case OPTION_ADD:
			if (Add(3))
				puts("[X]记录添加失败!");
			else
				puts("[V]记录添加成功!");
			break;
		case OPTION_DEL:
			if (Del(3))
				puts("[X]记录删除失败!");
			else
				puts("[V]记录删除成功!");
			break;
		case OPTION_EDIT:
			if (Edit(3))
				puts("[X]记录修改失败!");
			else
				puts("[V]记录修改成功!");
			break;
		case OPTION_QUERY:
			printf("全部(%d) 模糊(%d) 条件(%d)\n", QUERY_ALL, QUERY_LIKE, QUERY_WHERE);
			query_e flag = QUERY_ALL;
			flag = ChoiceNumber("查询方式", QUERY_ALL, QUERY_WHERE, 3);
			if (CountRecord() <= 0 || Query(flag))//目前可以省略CountRecord();该形式表达式可以在其它功能中采用
				puts("[X]记录查询失败!");
			else
				puts("[V]记录查询成功!");
			break;
		case OPTION_SETTING:
			puts("初始化数据库?");
			break;
		case OPTION_HELP:
			ShowMe("README", "帮助文档");
			break;
		case OPTION_ABOUT:
			ShowMe("ABOUT", "关于文档");
			break;
		default:;
	}
	return 0;//为了扩展性暂时不写在default范围内
}
int IsExistFile(const char *path){;
	if (!IsNull(path))
		return -1;
	FILE *fp = fopen(path, "r");
	if (fp){
		fclose(fp);
		fp = NULL;
		return 0;
	}
	return -1;
}
int ReadText(const char *path){
	FILE *fp = fopen(path, "rt");
	int c = -1;
	if (fp){
		while((c = fgetc(fp)) != EOF)
			putc(c, stdout);
		fclose(fp);
		fp = NULL;
	}
	else
		return -1;
	return 0;
}
void DividingLine(int c, size_t row, size_t col){
	int i = 0;
	while (row--){
		for (i = 0; i < col; i++)
			printf("%c", c);
		puts("");
	}
}
int Add(const size_t etc){
	puts("当前位置(主页/添加记录)");//可以使用函数来改写
	FILE *fp = NULL;
	if (IsExistFile(DATABASE)){
		fp = fopen(DATABASE, "wb+");
		if (!fp)
			return -1;
	}
	else {
		fp = fopen(DATABASE, "ab+");//追加总是在末尾写入,rb+覆盖写入,不允许追加,在原有基础上修改
		if (!fp)
			return -1;
	}
	int n = etc;
	//使用结构体指针,巩固知识点。
	student_s dat = {0};
	dat.start.content = TABLE_HEAD;
	dat.end.content = TABLE_TAIL;
	int res = 0;
	int tms = 2;
	while(tms--){
		if (!GetData("学号", DATATYPE_INT, &dat.id, 1))
			if (IsExistID(dat.id)){
				res = !0;
				break;
			}
			else
				puts("[X]ID冲突!");
	}
	res = res && 
		!GetString("姓名", dat.name, sizeof(dat.name) / sizeof(*dat.name), 2) && 
		!GetString("性别", dat.sex, sizeof(dat.sex) / sizeof(*dat.sex), 2) && 
		!GetData("年龄", DATATYPE_INT, &dat.age, 2) && 
		!GetString("电话", dat.telephone, sizeof(dat.telephone) / sizeof(*dat.telephone), 2) && 
		!GetData("出生(年)", DATATYPE_INT, &dat.birth.year, 2) && 
		!GetData("出生(月)", DATATYPE_INT, &dat.birth.month, 2) && 
		!GetData("出生(日)", DATATYPE_INT, &dat.birth.day, 2) && 
		!GetData("语文成绩", DATATYPE_INT, &dat.score.chinese, 2) && 
		!GetData("数学成绩", DATATYPE_INT, &dat.score.math, 2) && 
		!GetData("英语成绩", DATATYPE_INT, &dat.score.english, 2) && 
		!(-1 == (dat.inode = ProduceInode()));//在即将写入文件时删除数据文件返回失败状态(-1)
	if (res){
		if (1 != fwrite(&dat, sizeof(student_s), 1, fp)){
			puts("[X]写入数据时发生错误!");
			fclose(fp);
			fp = NULL;//FILE*关闭后仍可用,虽不能真正写入文件,但程序可能照常运行,置为空指针,则写入是会段错误,便于发现潜在隐患
			return -1; 
		}
		printf("本次索引节点为%d\n", dat.inode);
		fclose(fp);
		fp = NULL;
		return 0;
	}
	fclose(fp);
	fp = NULL;
	return -1;
}
int GetData(const char *prompt, int type, void *var, size_t n){
	while (n--){
		printf("%s: ", prompt);
		int is = 0;
		switch (type){
			case DATATYPE_CHAR:
				is = scanf("%c", var);
				break;
			case DATATYPE_INT:
				is = scanf("%d", var);
				break;
			case DATATYPE_FLOAT:
			case DATATYPE_DOUBLE:
				is = scanf("%f", var);
				break;
			case DATATYPE_STRING:
				//is = fgets/scanf("%s")
				break;
			default:
				return -1;
		}
		CleanStdin();
		if (is)
			return 0;
		puts("[X]输入错误!");
	}
	return -1;
}
int GetString(const char *prompt, char *ptr, size_t len, size_t n){
	while(n--){
		printf("%s: ", prompt);
		fgets(ptr, len, stdin);
		if (IsNull(ptr)){
			if (ClearLF(ptr, strlen(ptr)))
				CleanStdin();
			if (IsNull(ptr))
				return 0;
		}
	}
	return -1;
}
int ProduceInode(void){;
	size_t inode = 0;
	if (IsExistFile(DATABASE))
		return -1;
	FILE *fp = fopen(DATABASE, "rb");
	if (!fp)
		return -1;
	student_s t = {};
	while(!feof(fp))
		if (1 == fread(&t, sizeof(student_s), 1, fp))
			inode = t.inode > inode ? t.inode : inode;
	fclose(fp);
	fp = NULL;
	return ++inode;
}
int CountRecord(void){;
	size_t count = 0;
	if (IsExistFile(DATABASE))
		return -1;
	FILE *fp = fopen(DATABASE, "rb");
	if (!fp)
		return -1;
	student_s t;
	while(!feof(fp))
		if (1 == fread(&t, sizeof(student_s), 1, fp)){
			if (t.start.content != TABLE_HEAD || t.end.content != TABLE_TAIL)//主要检测表头
				return -1;
			count++;
		}
	if (ftell(fp) != count * sizeof(student_s))//检测表尾
		return -1;
	fclose(fp);
	fp = NULL;
	return count;
}
int SearchString(const char *keyword, const char *content){;
	if (!(IsNull(keyword) && IsNull(content)))
		return -1;
	size_t len_k = strlen(keyword), 
		   len_c = strlen(content);
	if (len_k > len_c)
		return -1;
	int i = 0, j = 0;
	char match[len_k + 1];
	for (i = 0; i < len_c - len_k + 1; i++){//关系类型: 一对多
		InitCA(match, sizeof(match));
		for (j = i; j < i + len_k; j++)
			match[j - i] = content[j];
		match[j - i] = 0;
		if (!strcmp(match, keyword))
			return 0;
	}
	return -1;
}
void InitCA(char *ca, size_t n){
	int i = 0;
	for (i = 0; i < n; i++)
		ca[i] = 0;
}
//usleep(500000);//睡眠0.1秒钟
//检测字段是否为ASCII字符集中数据,否则认为是汉子,占用不同的位宽//编写整数转换字符串函数sprintf
int Query(int flag){;
	if (CountRecord() <= 0)
		return -1;
	FILE *fp = fopen(DATABASE, "rb");
	if (!fp)
		return -1;
	student_s t = {};
	size_t cnt = 0;
	void Header(void){
		puts("学号 姓名         性别 年龄 电话        出生       语文 数学 英语 节点");
		DividingLine('.', 1, 70);
	}
	void Footer(const char *NullPrompt){
		DividingLine('.', 1, 70);
		if (!cnt)
			if (IsNull(NullPrompt))
				puts(NullPrompt);
			else
				puts("[*]数据库文件已发生变化!");
		printf("记录: 共%u项\n", cnt);
	}
	void format(char *buf){//根据非ASCII字符个数和ASCII个数来确定%s,其它数据类型保持不变

	}
	int SAll(void){
		Header();
		while (!feof(fp)) {
			if (1 != fread(&t, sizeof(student_s), 1, fp))
				break;
			printf("%-5u%-13s%-5s%-5u%-12s%04u-%02u-%02u %-5u%-5u%-5u%-3u\n", t.id, t.name, t.sex, t.age, t.telephone, t.birth.year, t.birth.month, t.birth.day, t.score.chinese, t.score.math, t.score.english, t.inode), cnt++;
		}
		fclose(fp);
		fp = NULL;
		Footer(NULL);
		return 0;
	}
	int SLike(const char *keyword){
		Header();
		char buf[KEYWORD_LIMIT + 1] = {0};
		while (!feof(fp)) {
			if (1 != fread(&t, sizeof(student_s), 1, fp))
				break;
			int c = -1;
#define MATCHING(Flag, Var) \
			InitCA(buf, sizeof(buf)); \
			sprintf(buf, #Flag, Var); \
			/*printf("正在匹配第%d项中的%s\n", ftell(fp) / sizeof(student_s), #Var);*/ \
			c = c && SearchString(keyword, buf); \
			if (!c) break;//该行语句属于宏MATCHING
			int wc = 1;
			while (wc--){
				MATCHING(%u,  t.id);
				MATCHING(%s,  t.name);
				MATCHING(%s,  t.sex);
				MATCHING(%u,  t.age);
				MATCHING(%s,  t.telephone);
				MATCHING(%u,  t.birth.year);
				MATCHING(%u,  t.birth.month);
				MATCHING(%u,  t.birth.day);
				MATCHING(%u,  t.score.chinese);
				MATCHING(%u,  t.score.math);
				MATCHING(%u,  t.score.english);
			}
			if (!c)
				printf("%-5u%-13s%-5s%-5u%-12s%04u-%02u-%02u %-5u%-5u%-5u%-3u\n", t.id, t.name, t.sex, t.age, t.telephone, t.birth.year, t.birth.month, t.birth.day, t.score.chinese, t.score.math, t.score.english, t.inode), cnt++;
		}
		fclose(fp);
		fp = NULL;
		Footer("[*]没有匹配内容!");
		return 0;
	}
	int SWhere(void){
#define PREC printf("%-5u%-13s%-5s%-5u%-12s%04u-%02u-%02u %-5u%-5u%-5u%-3u\n", src.id, src.name, src.sex, src.age, src.telephone, src.birth.year, src.birth.month, src.birth.day, src.score.chinese, src.score.math, src.score.english, src.inode), cnt++;
		printf("资料: 学号(%2d) 姓名(%2d) 性别(%2d) 年龄(%2d) 电话(%2d) \n生日: 年份(%2d) 月份(%2d) 号数(%2d) \n成绩: 语文(%2d) 数学(%2d) 英语(%2d)\n", 
				CON_ID, CON_NAME, CON_SEX, CON_AGE, CON_TELEPHONE, CON_YEAR, CON_MONTH, CON_DAY, CON_CHINESE, CON_MATH, CON_ENGLISH);
		int cn = ChoiceNumber("序号", CON_ID, CON_ENGLISH, 3);
		if (-1 == cn)
			return -1;
		student_s dest = {0}, src = {0};
		int res = -1;
#define DECIDE(C) \
		if (-1 == (C)) {\
			fclose(fp); \
			fp = NULL; \
			return -1; \
		}
#define DPI(arg1, arg2) \
		while (!feof(fp)) {\
			if (1 != fread(&src, sizeof(student_s), 1, fp)) break;\
			if (arg1 == arg2) PREC;}
#define DPS(arg1, arg2) \
		while (!feof(fp)) {\
			if (1 != fread(&src, sizeof(student_s), 1, fp)) break;\
			if (!strcmp(arg1, arg2)) PREC;}
		switch (cn) {
			case CON_ID:
				DECIDE(GetData("学号", DATATYPE_INT, &dest.id, 2));
				DPI(dest.id, src.id);
				break;
			case CON_NAME:
				DECIDE(GetString("姓名", dest.name, sizeof(dest.name) / sizeof(*dest.name), 2));
				DPS(dest.name, src.name);
				break;
			case CON_SEX:
				DECIDE(GetString("性别", dest.sex, sizeof(dest.sex) / sizeof(*dest.sex), 2));
				DPS(dest.sex, src.sex);
				break;
			case CON_AGE:
				DECIDE(GetData("年龄", DATATYPE_INT, &dest.age, 2));
				DPI(dest.age, src.age);
				break;
			case CON_TELEPHONE:
				DECIDE(GetString("电话", dest.telephone, sizeof(dest.telephone) / sizeof(*dest.telephone), 2));
				DPS(dest.telephone, src.telephone);
				break;
			case CON_YEAR:
				DECIDE(GetData("年份", DATATYPE_INT, &dest.birth.year, 2));
				DPI(dest.birth.year, src.birth.year);
				break;
			case CON_MONTH:
				DECIDE(GetData("月份", DATATYPE_INT, &dest.birth.month, 2));
				DPI(dest.birth.month, src.birth.month);
				break;
			case CON_DAY:
				DECIDE(GetData("号数", DATATYPE_INT, &dest.birth.day, 2));
				DPI(dest.birth.day, src.birth.day);
				break;
			case CON_CHINESE:
				DECIDE(GetData("语文", DATATYPE_INT, &dest.score.chinese, 2));
				DPI(dest.score.chinese, src.score.chinese);
				break;
			case CON_MATH:
				DECIDE(GetData("数学", DATATYPE_INT, &dest.score.math, 2));
				DPI(dest.score.math, src.score.math);
				break;
			case CON_ENGLISH:
				DECIDE(GetData("英语", DATATYPE_INT, &dest.score.english, 2));
				DPI(dest.score.english, src.score.english);
				break;
		}
		fclose(fp);
		fp = NULL;
		Footer("[*]没有匹配内容!");
		return 0;
	}
	if (QUERY_ALL == flag){
		return SAll();
	}
	else if (QUERY_LIKE == flag){
		char keyword[KEYWORD_LIMIT + 1];
		InitCA(keyword, sizeof(keyword));
		if (GetString("关键字", keyword, sizeof(keyword), 3)){
			fclose(fp);
			fp = NULL;
			return -1;
		}
		return SLike(keyword);
	}
	else if (QUERY_WHERE == flag){
		return SWhere();
	}
	else
		return -1;
}
void ShowMe(const char *path, const char *object){
	if (IsExistFile(path)){
		printf("[X]打开%s失败!\n", object);
		return ;
	}
	ReadText(path);
	ChooseKey(NULL);
}
int ChooseKey(const char *prompt){
	int c = 0;
	if (!IsNull(prompt))
		prompt = "按下回车键返回";
	printf("%s: ", prompt);
	if ('\n' != (c = fgetc(stdin)))
		CleanStdin();
	return c;	
}
int NumericDigits(int integer, int flag){//条件查询可能不用这个函数,条件查询中直接比较两个值是否完全相等,包含数据类型
	int count = 0;
	if (SYMBOL_YES == flag)//仅限于符号
		count = integer < 0 ? 1 : 0;
	else if (SYMBOL_NO == flag);
	else
		return -1;
	integer = integer < 0 ? -1 * integer : integer;
	do {
		count++;
		integer /= 10;
	} while (integer);
	return count;
}
int DigitalConversionString(int integer, char *buf, size_t size, int flag){//字符串转换数字,使用逆向算法即可int-'0'
	InitCA(buf, size);
	if (SYMBOL_YES == flag){
		if (integer < 0)
			*buf++ = '-';
	}
	else if (SYMBOL_NO == flag);
	else
		return -1;
	integer = integer < 0 ? -1 * integer : integer;//可以省略该条语句,直接对负数操作效果一样
	do {
		*buf++ = '0' + integer % 10;
		integer /= 10;
	} while (integer);
	return 0;
}
int ReverseString(char *src, size_t len){//将来为了支持WHERE *str*;
	char buf[len + 1];
	InitCA(buf, sizeof(buf));
	strcpy(buf, src);
	int i = 0;
	for (i = 0; i < len; i++){
		src[i] = buf[len - i - 1];
	}
	puts(buf);
	puts(src);
}
void Debug(void){
	int i = -54321;
	int is = NumericDigits(i, SYMBOL_YES);
	char buf[is + 1];
	printf("-----%d\n", sizeof(buf));
	DigitalConversionString(i, buf, is, SYMBOL_YES);
	DigitalConversionString(i, buf, is, SYMBOL_YES);
	puts(buf);
	ReverseString(buf, strlen(buf));
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值