实现一个基于命令行的文本编辑器
功能:
1、 打开文件
2、 保存文件
3、 能够对文件进行查找
4、 能够对文件进行替换
5、 能够对文件进行删除
/*
file: textproc.h
compiler: Dev-C++ OR TC2.0 (#define COMPILER_TC)
Define Macros And Tool Functions
*/
/* Define Result File Name */
#define RESULT_FILE_NAME "010588_result.txt"
/* Define Debug Flag */
/* #define DO_DEBUG 1 */
/* Define Compiler Flag Dev-C++ OR TC2.0*/
/* #define COMPILER_TC 1 */
/* Define Error Code */
#define ERR_OPTR_UNKOWN -1
#define ERR_OPND_NOT_MATCH -2
/* #define ERR_DIR_FMT_INVALID -3 */
#define ERR_FILE_CANT_FOUND -4
#define ERR_FILE_CANT_OPEN -5
#define ERR_FILE_WRITE_ERROR -6
#define ERR_FILE_READ_ERROR -7
#define ERR_MEMORY_OVERFLOW -8
/* Define Max Value */
#define MAX_ARG_NUM 5
#define MAX_CMD_LEN 1024
#define MAX_STR_LEN 256
/* Define for EnvType */
typedef struct
{
char exePath[MAX_STR_LEN+1];
char curPath[MAX_STR_LEN+1];
int textLen;
char *text;
int arrLen;
char *arr;
}EnvType;
/* Define for ffblk Struct for TC2.0 */
typedef struct
{
char ff_reserved[21]; /* DOS Reserved Word*/
char ff_attrib; /* File Attrib*/
int ff_ftime; /* File Time*/
int ff_fdate; /* File Date*/
long ff_fsize; /* File Size*/
char ff_name[13]; /* File Name*/
}ffblk;
/* Split fileName, Extract pathName */
int SplitDir(char pathName[], char fileName[])
{
int i, flag = 1;
if (fileName[0]!='//' && fileName[1]!=':')
flag = 0;
for (i=strlen(fileName)-1; i>=0 && fileName[i]!='//'; i--);
pathName[i+1] = '/0';
while (i >= 0)
{
pathName[i] = fileName[i];
i--;
}
return flag;
}
/* Dynamic Programming, Calc nextVal for KMP */
void GetNextVal(int nextVal[], char T[], int T_len)
{
int i = 0, j = -1;
nextVal[0] = -1;
while (i < T_len-1)
{
if (j==-1 || T[i]==T[j])
{
++i; ++j;
if (T[i] != T[j])
nextVal[i] = j;
else
nextVal[i] = nextVal[j];
}
else
j = nextVal[j];
}
}
/* Index SubString (KMP) */
int IndexKMP(char S[], int S_len, char T[], int T_len, int nextVal[], int pos)
{
int i = pos, j = 0;
while (i<S_len && j<T_len)
{
if (j==-1 || S[i]==T[j])
{
++i; ++j;
}
else
j = nextVal[j];
}
if (j >= T_len)
return i-T_len;
else
return -1;
}
/* BASIC OPERATION: Mark markArr Array, Using KMP Index */
int GetMarkArr(int markArr[], char S[], int S_len, char T[], int T_len)
{
int i, res, nextVal[MAX_STR_LEN], markCnt = 0;
GetNextVal(nextVal, T, T_len);
#ifdef DO_DEBUG
printf("NEXTVAL_DEBUG_BEGIN/nnextVal:/n");
for (i=0; i<T_len; i++)
printf("%d ", nextVal[i]);
printf("/nNEXTVAL_DEBUG_END/n");
#endif
for (i=0; i<S_len; i++)
markArr[i] = 0;
i = 0;
do {
res = IndexKMP(S, S_len, T, T_len, nextVal, i);
if (res != -1)
{
markArr[res] = 1;
markCnt++;
i = res+T_len;
}
} while (i<S_len && res!=-1);
return markCnt;
}
/* BASIC OPERATION: Replace SubString */
void ReplaceStr(char arr[], char text[], int textLen, int markArr[], int lenSrc, char strDest[], int lenDest)
{
int i = 0, j = 0, k;
while (i < textLen)
{
if (markArr[i])
{
for (k=0; k<lenDest; k++)
{
arr[j] = strDest[k];
j++;
}
i += lenSrc;
}
else
{
arr[j] = text[i];
j++; i++;
}
}
}
/*
file: textproc.cpp
compiler: Dev-C++ OR TC2.0 (#define COMPILER_TC)
Text Process Tools
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include "textproc.h"
/* Open File Proc for Cmd "-o" */
int OpenProc(EnvType *env, char fileName[])
{
char pathName[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
#ifdef COMPILER_TC
ffblk fileInfo;
#else
struct _finddata_t fileInfo;
#endif
int fileHandle;
FILE *fp;
if (!SplitDir(pathName, fileName))
{
strcpy(tmp, env->exePath);
strcat(tmp, pathName);
strcpy(pathName, tmp);
strcpy(tmp, env->exePath);
strcat(tmp, fileName);
strcpy(fileName, tmp);
/* return ERR_DIR_FMT_INVALID; */
}
#ifdef COMPILER_TC
fileHandle = findfirst(fileName, &fileInfo);
#else
fileHandle = _findfirst(fileName, &fileInfo);
#endif
if (fileHandle == -1)
return ERR_FILE_CANT_FOUND;
#ifndef COMPILER_TC
_findclose(fileHandle);
#endif
fp = fopen(fileName, "rb");
if (fp == NULL)
return ERR_FILE_CANT_OPEN;
if (env->text != NULL)
{
free(env->text);
env->text = NULL;
env->textLen = 0;
}
if (env->arr != NULL)
{
free(env->arr);
env->arr = NULL;
env->arrLen = 0;
}
strcpy(env->curPath, pathName);
#ifdef COMPILER_TC
env->textLen = fileInfo.ff_fsize;
#else
env->textLen = fileInfo.size;
#endif
env->text = (char *)malloc(env->textLen*sizeof(char));
if (env->text == NULL)
return ERR_MEMORY_OVERFLOW;
if (fread(env->text, sizeof(char), env->textLen, fp) != env->textLen)
{
fclose(fp);
return ERR_FILE_READ_ERROR;
}
fclose(fp);
return 0;
}
/* Save File Proc for Cmd "-s" */
int SaveProc(EnvType *env, char fileName[])
{
char pathName[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
FILE *fp;
if (!SplitDir(pathName, fileName))
{
strcpy(tmp, env->exePath);
strcat(tmp, pathName);
strcpy(pathName, tmp);
strcpy(tmp, env->exePath);
strcat(tmp, fileName);
strcpy(fileName, tmp);
/* return ERR_DIR_FMT_INVALID; */
}
fp = fopen(fileName, "wb");
if (fp == NULL)
return ERR_FILE_CANT_OPEN;
if (env->arr != NULL)
{
free(env->text);
env->text = env->arr;
env->textLen = env->arrLen;
env->arr = NULL;
env->arrLen = 0;
}
strcpy(env->curPath, pathName);
if (fwrite(env->text, sizeof(char), env->textLen, fp) != env->textLen)
{
fclose(fp);
return ERR_FILE_WRITE_ERROR;
}
fclose(fp);
return 0;
}
/* Find SubString, for Cmd "-f" */
int FindProc(EnvType *env, char strFind[], int strLen)
{
int i, markCnt, *markArr = (int *)malloc(env->textLen*sizeof(int));
char fileName[MAX_STR_LEN+1];
FILE *fp;
if (markArr == NULL)
return ERR_MEMORY_OVERFLOW;
markCnt = GetMarkArr(markArr, env->text, env->textLen, strFind, strLen);
printf("-f%d/n/n", markCnt);
#ifdef DO_DEBUG
printf("MARKARR_DEBUG_BEGIN/nmarkArr:/n");
for (i=0; i<env->textLen; i++)
printf("%d ", markArr[i]);
printf("/nMARKARR_DEBUG_END/n");
#endif
strcpy(fileName, env->curPath);
strcat(fileName, RESULT_FILE_NAME);
fp = fopen(fileName, "ab");
if (fp == NULL)
return ERR_FILE_CANT_OPEN;
fprintf(fp, "-f%d/r/n/r/n", markCnt);
free(markArr);
fclose(fp);
return 0;
}
/* Replace String AND Delete SubString for Cmd "-r" AND "-d" */
int ReplaceProc(EnvType *env, char strSrc[], int lenSrc, char strDest[], int lenDest)
{
int i, markCnt, *markArr = (int *)malloc(env->textLen*sizeof(int));
char fileName[MAX_STR_LEN+1];
FILE *fp;
if (markArr == NULL)
return ERR_MEMORY_OVERFLOW;
markCnt = GetMarkArr(markArr, env->text, env->textLen, strSrc, lenSrc);
if (lenDest == 0)
printf("-d%d/n/n", markCnt);
else
printf("-r%d/n/n", markCnt);
#ifdef DO_DEBUG
printf("MARKARR_DEBUG_BEGIN/nmarkArr:/n");
for (i=0; i<env->textLen; i++)
printf("%d ", markArr[i]);
printf("/nMARKARR_DEBUG_END/n");
#endif
strcpy(fileName, env->curPath);
strcat(fileName, RESULT_FILE_NAME);
fp = fopen(fileName, "ab");
if (fp == NULL)
return ERR_FILE_CANT_OPEN;
if (lenDest == 0)
fprintf(fp, "-d%d/r/n", markCnt);
else
fprintf(fp, "-r%d/r/n", markCnt);
if (env->arr != NULL)
{
free(env->arr);
env->arr = NULL;
env->arrLen = 0;
}
env->arrLen = env->textLen+markCnt*(lenDest-lenSrc);
env->arr = (char *)malloc(env->arrLen*sizeof(char));
if (env->arr == NULL)
return ERR_MEMORY_OVERFLOW;
ReplaceStr(env->arr, env->text, env->textLen, markArr, lenSrc, strDest, lenDest);
free(markArr);
if (fwrite(env->arr, sizeof(char), env->arrLen, fp) != env->arrLen)
{
fclose(fp);
return ERR_FILE_WRITE_ERROR;
}
fprintf(fp, "/r/n/r/n");
fclose(fp);
return 0;
}
/* Init WorkSpace */
void Init(EnvType *env)
{
getcwd(env->exePath, MAX_STR_LEN);
strcat(env->exePath, "//");
env->curPath[0] = '/0';
env->text = env->arr = NULL;
env->textLen = env->arrLen = 0;
}
/* Clear WorkSpace */
void Clear(EnvType *env)
{
if (env->text != NULL)
{
free(env->text);
env->text = NULL;
env->textLen = 0;
}
if (env->arr != NULL)
{
free(env->arr);
env->arr = NULL;
env->arrLen = 0;
}
}
/* Read Cmd Line */
int ReadCmd(int *argc, char argv[][MAX_STR_LEN+1], int argl[])
{
int i;
char line[MAX_CMD_LEN+1];
gets(line);
*argc = 0;
argl[*argc] = 0;
for (i=0; line[i]!='/0'; i++)
{
if (line[i]==' ' || line[i]=='/t')
{
if (argl[*argc] > 0)
{
argv[*argc][argl[*argc]] = '/0';
(*argc)++;
argl[*argc] = 0;
}
}
else
{
argv[*argc][argl[*argc]] = line[i];
argl[*argc]++;
}
}
if (argl[*argc] > 0)
{
argv[*argc][argl[*argc]] = '/0';
(*argc)++;
}
if (*argc==1 && strcmp(argv[0], "-q")==0)
return 0;
else
return 1;
}
/* Display Usage */
void DisplayUsage()
{
printf(" CMD_FORMAT: OPTR [OPND1 [OPND2]]/n");
printf(" OPTR CMD_TYPE OPND_LIST/n");
printf(" -o Open File. OPND1 = filename/n");
printf(" -h Help Info./n");
printf(" -s Save File. OPND1 = filename/n");
printf(" -f Find SubString. OPND1 = stringtofind/n");
printf(" -r Replace SubString. OPND1 = sourcestring/n");
printf(" OPND2 = targetstring/n");
printf(" -d Delete SubString. OPND1 = stringtodelete/n");
printf(" -q Quit./n");
printf(" -e Display Env Info (Debug)./n");
}
/* Display Env Info for Debug */
void DisplayEnv(EnvType env)
{
int i;
printf("ENV_DEBUG_BEGIN/nexePath = %s/n", env.exePath);
printf("curPath = %s/n", env.curPath);
printf("textLen = %d, text:/n", env.textLen);
printf("-------------------/n");
for (i=0; i<env.textLen; i++)
printf("%c", env.text[i]);
printf("/n-------------------/n");
printf("arrLen = %d, arr:/n", env.arrLen);
printf("-------------------/n");
for (i=0; i<env.arrLen; i++)
printf("%c", env.arr[i]);
printf("/n-------------------/nENV_DEBUG_END/n");
}
/* Display Error Info for Debug */
void DisplayError(int errCode)
{
switch (errCode)
{
case ERR_FILE_READ_ERROR: printf("ERR_FILE_READ_ERROR/n"); break;
case ERR_FILE_WRITE_ERROR: printf("ERR_FILE_WRITE_ERROR"); break;
/* case ERR_DIR_FMT_INVALID: printf("ERR_DIR_FMT_INVALID/n"); break; */
case ERR_FILE_CANT_FOUND: printf("ERR_FILE_CANT_FOUND/n"); break;
case ERR_FILE_CANT_OPEN: printf("ERR_FILE_CANT_OPEN/n"); break;
case ERR_MEMORY_OVERFLOW: printf("ERR_MEMORY_OVERFLOW/n"); break;
case ERR_OPTR_UNKOWN: printf("ERR_OPTR_UNKOWN/n"); break;
case ERR_OPND_NOT_MATCH: printf("ERR_OPND_NOT_MATCH/n"); break;
default: printf("ERR_UNKOWN/n");
}
}
/* Main Function */
int main()
{
EnvType env;
int i, argc, argl[MAX_ARG_NUM+1], errCode;
char argv[MAX_ARG_NUM+1][MAX_STR_LEN+1];
Init(&env);
while (ReadCmd(&argc, argv, argl))
{
#ifdef DO_DEBUG
printf("ARG_DEBUG_BEGIN/nargc = %d/n", argc);
for (i=0; i<argc; i++)
printf("%d %s/n", argl[i], argv[i]);
printf("ARG_DEBUG_END/n");
#endif
if (argc==0 || argl[0]!=2 || argv[0][0]!='-')
{
DisplayUsage();
continue;
}
errCode = 0;
switch (argv[0][1])
{
case 'o': if (argc != 2)
errCode = ERR_OPND_NOT_MATCH;
else
errCode = OpenProc(&env, argv[1]);
break;
case 'h': if (argc != 1)
errCode = ERR_OPND_NOT_MATCH;
else
DisplayUsage();
break;
case 's': if (argc != 2)
errCode = ERR_OPND_NOT_MATCH;
else
errCode = SaveProc(&env, argv[1]);
break;
case 'f': if (argc != 2)
errCode = ERR_OPND_NOT_MATCH;
else
errCode = FindProc(&env, argv[1], argl[1]);
break;
case 'r': if (argc != 3)
errCode = ERR_OPND_NOT_MATCH;
else
errCode = ReplaceProc(&env, argv[1], argl[1], argv[2], argl[2]);
break;
case 'd': if (argc != 2)
errCode = ERR_OPND_NOT_MATCH;
else
errCode = ReplaceProc(&env, argv[1], argl[1], "", 0);
break;
case 'q': if (argc != 1)
errCode = ERR_OPND_NOT_MATCH;
break;
case 'e': if (argc != 1) /* Used For Debug */
errCode = ERR_OPND_NOT_MATCH;
else
DisplayEnv(env);
break;
default: errCode = ERR_OPTR_UNKOWN;
}
#ifdef DO_DEBUG
DisplayEnv(env);
#endif
if (errCode != 0)
DisplayError(errCode);
}
Clear(&env);
return 0;
}