gcc -o channeldb channel.c -db -Wall
# -Wall参数等价于执行lint,即:进行代码的静态分析,它可以指出未初始化的变量,未使用的变量
#include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <db.h> #include <sys/types.h> #include <getopt.h> //define DATABASE "/work/stat/read/newstat/data/userlist/historydb/channel.db" #define DATABASE "/mnt/disk1/ucshuqi/touch/userlist/historydb/channel.db" #define YES 1 #define NO 0 /* ViewData Module */ struct ViewData { int date; }; void setDate(struct ViewData *data,char *s) { assert(data!=NULL && s!= NULL && strlen(s) == 8); data->date = atoi(s); } // the function return YES when query.date >= stored.date int isHistoryViewInfo(struct ViewData *query , struct ViewData *stored) { assert(query != NULL && stored != NULL); printf("query date is %d , stored date is %d \n",query->date, stored->date); if(query->date >= stored->date) { return YES; } else { return NO; } } void printViewData(struct ViewData *data) { printf("print view date : %d\n",data->date); } /* string helper module */ char *trim(char *s) { int i = strlen(s); for(;i>0;i--) { if(s[i]==' ' || s[i]=='\n' || s[i]=='\0' || s[i]=='\t') { s[i] = '\0'; } else { break; } } return s; } /* database helper module */ DB *openDb() { int ret; DB *dbp = NULL; ret = db_create(&dbp, NULL, 0); if(ret != 0) { fprintf(stderr,"create Db error!\n"); exit(1); } ret = dbp->open(dbp, NULL, DATABASE, NULL, DB_BTREE, DB_CREATE,0664); if(ret != 0) { fprintf(stderr,"open Db error!\n"); exit(1); } return dbp; } /* business module */ int saveViewInfo(DB *dbp, char *user, struct ViewData *data) { DBT key,value; memset(&key, 0, sizeof(key)); key.data = user; key.size = strlen(user) + 1; memset(&value, 0, sizeof(value)); value.data = data; value.size = sizeof(*data); if(dbp->put(dbp, NULL, &key, &value, 0) == 0) { //printf("save ---> %s, %d\n", key.data, key.size); printViewData(value.data); return YES; } else { return NO; } } int findViewInfo(DB *dbp, char *user, struct ViewData *data) { DBT key,value; memset(&key, 0, sizeof(key)); key.data = user; key.size = strlen(user) + 1; memset(&value,0,sizeof(value)); // must !!! if(dbp->get(dbp, NULL, &key, &value, 0) == 0) { memcpy((char*)data,(char*)value.data,value.size); //printViewData(data); return YES; //view in database } else { return NO; //view not in database } } void recordNewView(FILE *fp, char *user) { char buffer[1024] = {0}; assert(fp != NULL && user != NULL); printf("%s is new view\n", user); sprintf(buffer, "%s found\n", user); fwrite(buffer, sizeof(char), strlen(buffer), fp); } void saveViewFile(char *from, char *to, struct ViewData *writeData) { DB *dbp = openDb(); struct ViewData stored; char buffer[1024 * 4]; FILE *fp = fopen(from,"r"); FILE *fpResult = fopen(to,"w"); assert(fp != NULL && fpResult != NULL && writeData != NULL); while(fgets((char*)buffer, 1024*4, fp)!=NULL) { char *user = trim((char*)buffer); memset(&stored, 0, sizeof(stored)); if(findViewInfo(dbp, user, &stored) == YES) { if(isHistoryViewInfo(writeData,&stored) == NO) { recordNewView(fpResult, user); } continue; } recordNewView(fpResult, user); if(saveViewInfo(dbp, user, writeData) == NO) { printf("save %s faild\n", user); } memset(&buffer, 0, 1024 * 4); } dbp->close(dbp, 0); fclose(fp); fclose(fpResult); } void hasViewInfo(char *user, struct ViewData *query) { DB *dbp = NULL; struct ViewData stored; dbp = openDb(); assert(user != NULL); memset(&stored, 0 ,sizeof(stored)); user = trim(user); if(findViewInfo(dbp, user, &stored) == YES) { if(isHistoryViewInfo(query, &stored) == YES) { printf("found %s\n",user); } else { //printf("%s in db\n",user); printf("not found %s\n",user); } } else { printf("%s not in db\n",user); printf("not found %s\n",user); } dbp->close(dbp, 0); } int main (int argc, char *argv[]) { int oc; extern char *optarg; extern int optind, opterr, optopt; char *from = NULL; char *to = NULL; struct ViewData viewData; memset(&viewData, 0, sizeof(viewData)); while((oc=getopt(argc,argv,"f:s:t:")) != -1) { switch(oc) { case 's': setDate(&viewData,argv[optind]); hasViewInfo(optarg, &viewData); break; case 'f': from = optarg; to = argv[optind++]; setDate(&viewData,argv[optind]); saveViewFile(from, to, &viewData); break; } } return 0; }
我开始把ViewData写成了这样:
struct ViewData{ char date[12]; }; void setDate(char *date, char *s) { assert(date != NULL && s!= NULL); strncpy(&date,s,12); } //call setDate struct ViewData viewData; memset(viewData,0,sizeof(viewData)); setDate(&viewData.date,"20130808");
后来还是觉得viewData直接存int更好:
struct ViewData{ int date; }; void setDate(int *date, char *s) { assert(date != NULL && s!= NULL); *date = atoi(s); } //call setDate struct ViewData viewData; memset(viewData,0,sizeof(viewData)); setDate(&viewData.date,"20130808");
看似没啥问题,但其实我已经暴露了ViewData的实现!
//call setDate struct ViewData viewData; memset(viewData,0,sizeof(viewData)); setDate(&viewData.date,"20130808"); //断言设置之后的日期等于20130808,用户这么写是因为已经暴露了ViewData的date是字符串这个事情! assert(strcmp(viewData.date,"20130808")==0);
那你说,不怎么写我想知道是不是设置成功了怎么办?
//call setDate struct ViewData viewData; memset(viewData,0,sizeof(viewData)); setDate(&viewData.date,"20130808"); //断言设置之后的日期等于20130808,这个函数由ViewData模块提供 verifyDate(&viewDate,"20130808");