0

I have a C program which implements a small ncurses-based plain-text editor. The program can open only a single file during its runtime. The program is invoked from the command line as

$ ./tedit <filename>.

When invoked from the command line the program works as expected without problems. The problem arises when I try to run another instance of the program for another file. When the program is about to finish I ask the user to enter another file which he wants to open. This another file is to be opened in another instance of the program. So far, I have done it like this:

int
main(int argc, char **argv) {
    if (argc != 2) {
        show_usage();
    }
    /* parsing the arguments */
    PARSE_OPTS();

    atexit(&uninit_prog);
    signal(SIGABRT, &handle_sig);
    int err = setjmp(g_errjmp);
    if (err) {
        REPORT_ERR(err);
    }
    init_prog(argc, argv);
    DRAW_SCREEN();
    (void) setjmp(g_resizjmp);
    MAIN_LOOP();
    g_exitmode = true;
    if (g_document->dirty) {
        if (show_yesno_dlg("Save?[y/n]: ")) {
            (void) do_save();
        }
    }
    memset(g_strbuf, 0, MAX_DATA_LEN);
    wclear(stdscr);
    mvwprintw(stdscr, 0, 0, "File name: ");
    echo();
    if (wgetnstr(stdscr, g_strbuf, MAX_DATA_LEN) != ERR)
    {
        if (strcmp(g_strbuf, "q"))
        {
            pid_t id = fork();
            if (!id)
            {
                execl("./tedit", "tedit", g_strbuf, NULL);
                perror("execl failed");
                exit(EXIT_FAILURE);
            }
        }
    }
    return 0;
}  

In this code, initscr() is called from init_prog() and endwin() is called from uninit_prog(). And uninit_prog() is the parameter to atexit(). The problem begins after the echo(). When user enters his file name, I use fork() and execl() to start another instance of the program for this file. The new instance is invoked and I can see the program with the new file. But the problem is that, the cursor is not inside the program as expected but is at the bottom of the screen and it behaves itself as if it belongs to the terminal's command prompt. Is the problem with the way I create the new instance of the program?

I have tried execvp, execlp but the problem still remains

wangyu00
  • 1
  • 1
  • The choice of `exec*()` function is not a factor in the problem. After the fork, you have two programs both thinking that they control the same screen — at least one of them is going to get confused (and most likely both of them will be). The user will definitely be confused. You'd need to put the first invocation to sleep (so it is not reading any input, or displaying any new information) while the second is running. When the second completes, then you can refresh the original screen and continue onwards. _[…continued…]_ – Jonathan Leffler Jul 25 '23 at 05:54
  • 1
    `fork` and `exec` do nothing whatsoever to the terminal. Perhaps you ought to be doing `initscr` at the start of your program, and `endwin` before the exec? (And as Jonathan says, probably the parent ought to `wait()` until the child exits.) – Nate Eldredge Jul 25 '23 at 05:54
  • _[…continuation…]_ If you actually want the second invocation to replace the first, then you need to close curses in the first program before running the second without using `fork()` — just one of the `exec*()` family of functions. It is important to close curses so that when the second invocation exits, it can restore the terminal to a sane state. If you don't, its saved state will be suitable for curses and not for an ordinary command line application. – Jonathan Leffler Jul 25 '23 at 05:56
  • @JonathanLeffler Thank you for your reply. I am sorry for my unclear question-I have just edited it adding details on when `initscr()` and `endwin()` are called in the program. I already have `initscr()` and `endwin()` in the program. But I followed your suggestion and did the following: 1) added `endwin()` right before `execl()` and 2) added `else` to `if (!id)`. This `else` contains only one line `wait(NULL);`. Everything seems to work! – wangyu00 Jul 25 '23 at 06:39
  • @NateEldredge Thank you for your reply. I am sorry for my unclear question-I have just edited it adding details on when `initscr()` and `endwin()` are called in the program. I already have `initscr()` and `endwin()` in the program. But I followed your suggestion and did the following: 1) added `endwin()` right before `execl()` and 2) added `else` to `if (!id)`. This `else` contains only one line `wait(NULL);`. Everything seems to work! – wangyu00 Jul 25 '23 at 06:40
  • Sorry for two duplicate comments. Don't know how to mention two authors together in the same comment – wangyu00 Jul 25 '23 at 06:41
  • Write the comment once to one assistant. Write a second comment to the other along the lines of “@user2: see my comment to user1 — thank you for your help”. Or even mention both users in the first comment but add the second comment so that the second user is notified. – Jonathan Leffler Jul 25 '23 at 12:18

0 Answers0