简体   繁体   中英

Editing/Overwritting and printing contents of an array

Background

I have been trying to write a line editor like UNIX's ed and I've stumbled into a problem when printing an edited line.

Code

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define NOR 0  /* Normal mode for issuing commands, deleting or changing
                  lines */
#define INS 1  /* Insert mode for writing a line to a file */
#define OUT 2  /* This mode is not really mode but a state to tell the
                  program to graciously terminate */


int
main(int argc,char**argv)
{
  /* argc = 1 || argc = 2 */
  u_int32_t LINS, COLS;
  u_int32_t curr_line;
  u_int32_t curr_col_max[128];
  u_int32_t curr_line_max;
  int flag_no_file, flag_err, mode, fd_file, i;
  char*normal;char**buffer;
  ssize_t bytes_read;


  /* Atributions */
  LINS = 128; COLS = 120;
  curr_line = 0; curr_line_max = 0;
  normal = malloc(64*sizeof(char));
  buffer = (char**) malloc(LINS*sizeof(char *));
  for (i = 0; i <= LINS; i++)
    buffer[i] = (char *) malloc(COLS*sizeof(char));
  flag_err = 0;
  flag_no_file = 1;

  /* Error Checking and checking for existing file */
  if (argc == 2)
  {
    fd_file = open(argv[1], O_CREAT|O_WRONLY, 777);
    if (fd_file < 0)
    {
      write(2,"?\n", 2);
      flag_no_file = 1;
    }
    else flag_no_file = 0;
  }
  if (argc > 2) flag_err = 1; /* set so it is only editor name
                                 and file name */

  /* Code Logic */
  if (flag_err == 0)
  {
    mode = NOR;
    while (mode != OUT)
    {
      if (mode == NOR)
      {
        while (mode == NOR)
        {
          read(0, normal, COLS);
          switch(*normal)
          {
            case 'q': mode = OUT; break;/* exit command */
            case 'i': mode = INS; break;/* switch to insert mode */
            case 'a': mode = INS; 
                      curr_line_max++; 
                      curr_line++;
                      if (*(*buffer + curr_line-1) == '\0')
                        *(*buffer + curr_line-1) = '\n';
                      break;
            case '+': if (curr_line < curr_line_max)
                        curr_line++; /* if > curr_max */
                      else write(1,"?\n",2);
                      break;
            case '-': if (curr_line > 0)
                        curr_line--; /* if < 0 */
                      else write(1,"?\n",2);
                      break; 
            case 'p': if (buffer[curr_line][0] == '\0') write(1,"?\n",2);
                      else write(1,buffer[curr_line],(int) COLS);
                      break;
            case 'w': if (flag_no_file) write(1,"?\n",2);
                      else for (i = 0;
                                i < curr_line_max;
                                write(fd_file, buffer[i], curr_col_max[i]),
                                i++
                                ); /* the correct functioning of this 
                                      code is dependant
                                      on the correct opening and reading 
                                      of file to buffer */
                      break;
            case 'e': fd_file = open(normal, O_CREAT|O_WRONLY, 777);
                      /* normal must first remove the first two elements*/ 
                      if (fd_file < 0) write(1,"?\n",2);
                      else flag_no_file = 0;
                      /* Requires passing the contents of the file
                         to the buffer */
                      break;
            default: write(1, "?\n",2);
          }
        *normal = '\0'; /* reset the normal buffer */
        }
      }
      if (mode == INS)
      {
        **(buffer + curr_line) = '\0';
        bytes_read = read(0,buffer[curr_line],(int) COLS);
        *(*(buffer + curr_line)+bytes_read) = '\0';
        /*printf("%ld\n", bytes_read);
        fflush(stdin);*/
        curr_col_max[curr_line] = bytes_read;
        mode = NOR;
      }

    }
  }
  free(normal);
  for (i=0; i<LINS;free(buffer[i++]));
  free(buffer);
  return flag_err;
}

Algorithm and simulation of the unexpected output

  • INTENDED : editing a line should replace the entire line with the new content;
  • SOLUTION : as usual with C arrays, the next value after '\n' will be replaced with '\0';
  • PROBLEM : when using the 'p' command to write the line to the screen the contents of what was edited still remain, thus printing a '\0'(?) character.

The following is the output

$ ./a.out
i
some string
i
some
p
some
tring
q
$

Addendum

I am aware the first line in the insert mode condition can be replaced with

if (**(buffer + curr_line) != '\0')
          for (i=0; i<curr_col_max[curr_line];i++)
          *(*(buffer + curr_line) + i) = '\0';

Which I believe would fix this problem, however, it doesn't seem optimal at all, as i would much prefer if write only worked until the first '\0' in the buffer.

TLDR

  • DESIRED - Without using replacing any content in the buffer past the first '\0', write only up until there.

I think I figured it out on my own, the fact that write prints out '\0' should've been a red flag to the real issue, indeed I am writing up until COLS , it should be what is stored in the `curr_col_max' array!

write(1, buffer[curr_line], curr_col_max[curr_line]);

would be the solution to this issue, i believe.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM