一个基于命令行的文本编辑器

来源:互联网 发布:voip网络电话交换机 编辑:程序博客网 时间:2024/04/28 03:47

实现一个基于命令行的文本编辑器

功能:
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;
}