Skuteczne czyszczenie dwuwymiarowej tablicy dynamicznej char

0

Witam!

Mam wielki problem ze skutecznym wyczyszczeniem tablicy char**. Otóż mam do napisania shell z obsługą potoków. Aby to zrobić, dzielę linię ze standardowego wejścia na komendy i zapisuję każdą z nich do dynamicznej tablicy commands aby mieć do nich dostęp przy obsłudze potoków. Problem pojawia się przy kolejnych wywołaniach wiersza poleceń. Pierwsze zawsze wykonuje mi się poprawnie więc podejrzewam, że wina leży po stronie złego resetowania tablicy commands.

Np. po wpisaniu:
ls -l | grep *-
jest wszystko ok. Jeśli jednak potem wpiszę:
ls -l | grep -
to jakoś dziwnie do pierwszego polecenia dodaje "-".
Już powoli tracę na to siły. Byćmoże popełniam jakiś kardynalny błąd i tego nie widzę. Czy ktoś mógłby mi wskazać rozwiązanie lub ewentualnie inny sposób na podzielenie poleceń względem znaku "|" potoku i zapisanie go do tablicy char? Z góry szczere dziękuję.

#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

void shellcmd(int cmd_num);

char line[BUFSIZ];
char command[BUFSIZ];
char** commands;

int main(void)
{
    int i;
	int cmd_index, cmd_num, last;
    /*
     * Forever...
     */
    for (;;) {
        printf("Enter a command: ");
		
		//wyczyści bufor linii
		memset(line, 0, BUFSIZ * sizeof(char));
		
		//jeżeli nic nie wpisano to po prostu przejdź do nowej linii
        if (fgets(line, sizeof(line), stdin) == NULL) {
            putchar('\n');
            exit(0);
        }
        line[strlen(line)-1] = '\0';
		//policzy ile jest komend
		cmd_num = 1;
		for (i = 0; i < strlen(line); i++)
		{
			if (line[i] == '|')
				cmd_num++;
		}
		
		//zaalokowanie pamięci potrzebnej do przechowania cmd_num komend
		commands = (char**)malloc(cmd_num * sizeof(char*));
		for (i = 0; i < cmd_num; i++) {
			commands[i] = (char*)malloc(BUFSIZ * sizeof(char));
		}
		
		//podział linii na komendy oddzielone znakiem "|"
		//spacje po "|" są pomijane
		
		//wyzerowanie cmd_index
		cmd_index = 0;
		
		//wyzerowanie last
		last = 0;
		
		//przejdź po całej linii
		for (i = 0; i < strlen(line); i++)
		{
			//jeżeli to już ostatni znak w linii
			if (i == strlen(line) - 1)
			{
				
				command[i - last] = line[i];
				strcpy(commands[cmd_index], command);
				memset(command, 0, BUFSIZ * sizeof(char));
			}
			if (line[i] == '|')
			{
				strcpy(commands[cmd_index], command);
				memset(command, 0, BUFSIZ * sizeof(char));
				cmd_index++;
				//jeżeli jest spacja po "|"
				//to przejdź do następnego znaku
				if (line[i+1] == ' ')
					i++;
				last = i;
				last++;
			}
			else
			{
				command[i - last] = line[i];
			}
		}
		//usuwanie spacji z końców komend
		for (i = 0; i < cmd_num; i++)
		{
			if (commands[i][strlen(commands[i])-1] == ' ')
				commands[i][strlen(commands[i])-1] = '\0';
			printf("Command: '%s'\n", commands[i]);
		}
		//wywołanie komend w potoku
        shellcmd(cmd_num);
		
		//zwolnienie pamięci dla tablicy commands
		for (i=0; i<cmd_num; i++)
		{
			memset(commands[i], 0, BUFSIZ * sizeof(char));
			free(commands[i]);
		}
		free(commands);
    }
}
void shellcmd(int cmd_num)
{
    int status, i;
    pid_t pid;
    extern int errno;
	int old_fd[2];
	int new_fd[2];
	
	for (i = 0; i < cmd_num; i++)
	{
		//jeżeli jest następna komenda
		if (i < cmd_num - 1)
		{
			//to utwórz deskryptory dla nowego potoku
			if (pipe(new_fd) != 0)
				perror("Blad podczas wczytywania deskryptorow potokow");
		}
		if ((pid = fork()) < 0)
			status = -1;
		if (pid == 0) /* child */
		{
			//jeżeli była wcześniejsza komenda
			if (i > 0)
			{
				dup2(old_fd[0], 0);
				close(old_fd[0]);
				close(old_fd[1]);
			}
			//jeżeli jest następna komenda
			if (i < cmd_num - 1)
			{
				close(new_fd[0]);
				dup2(new_fd[1], 1);
				close(new_fd[1]);
			}
			//system(commands[i]);
			execlp("/bin/sh", "sh", "-c", commands[i], 0);
			//execl("/bin/sh", "sh", "-c", , 0);
		}
		else /* parent */
		{
			//jeżeli była wcześniejsza komenda
			if (i > 0)
			{
				close(old_fd[0]);
				close(old_fd[1]);
			}
			if (i < cmd_num - 1)
			{
				old_fd[0] = new_fd[0];
				old_fd[1] = new_fd[1];
			}
			while (waitpid(pid, &status, 0) < 0) {
				if (errno != EINTR) {
					status = -1;
					break;
				}
			}
		}
	}
	if (cmd_num > 1)
	{
		close(old_fd[0]);
		close(old_fd[1]);
	}
}
1
 
line[strlen(line)-1] = '\0';

A teraz zastanów się jak działa strlen i dlaczego ta linijka jest kompletnie bez sensu a działa za pierwszym razem tylko przypadkiem.

0

Faktycznie, trochę niepotrzebna ta linijka. Została tam po kodzie shella, którego to za zadanie miałem przerobić by obsługiwał potoki (tzn. samemu trzeba go było wykryć i obsłużyć). Dziękuję za pomoc :-)

1 użytkowników online, w tym zalogowanych: 0, gości: 1