Projeto final de cblc (Clone do coreutils paste) #28

Open
opened 2025-07-05 16:51:36 -03:00 by NRZCode · 2 comments

Fala pessoal,

postando aqui minha solução do projeto de conclusão de curso para o clone do paste

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdbool.h>
/**
 * Uso: paste [OPÇÃO]... [ARQUIVO]...
 * Escreve linhas constituídas das linhas sequencialmente correspondentes de
 * cada ARQUIVO, separadas por tabulações, para a saída padrão.
 *
 * Se ARQUIVO não for especificado ou for -, lê a entrada padrão.
 *
 * Argumentos obrigatórios para opções longas também o são para opções curtas.
 *   -d, --delimiters=LISTA  reutiliza caracteres da LISTA em vez de tabulações
 *   -s, --serial            cola um arquivo por vez em de todos em paralelo
 *   -z, --zero-terminated     delimitador de linha é NULO, não nova linha
 *       --help        mostra esta ajuda e sai
 *       --version     mostra informação da versão e sai
 *
 * Página de ajuda do GNU coreutils: <https://www.gnu.org/software/coreutils/>
 * Relate erros de tradução para <https://translationproject.org/team/pt_BR.html>
 * Documentação completa em <https://www.gnu.org/software/coreutils/paste>
 * ou disponível localmente via: info "(coreutils) paste invocation"
 */
FILE *openstream(FILE *file, char *str) {
    file = stdin;
    if (strcmp(str, "-") != 0)
        file = fopen(str, "r");
    if (!file) {
        perror(str);
        exit(EXIT_FAILURE);
    }
    return file;
}

int is_endoffiles(char *list) {
    for (int i = 0; list[i] != '\0'; i++) {
        if (list[i] == '0')
            return 0;
    }
    // str = "111111...";
    return 1;
}

/**
 * Abertura de arquivos em paralelo
 */
int print_parallel(char **flist, int argc, char sep) {
    int i;
    char buffer[BUFSIZ];
    FILE *files[argc];
    /**
     * eofstr = "000000..." (args)
     */
    char eofstr[argc+1];
    for (i = 0; i < argc; i++) {
        files[i] = openstream(files[i], flist[i]);
        eofstr[i] = '0';
    }
    while (!is_endoffiles(eofstr)) {
        for (i = 0; i < argc; i++) {
            if (fgets(buffer, BUFSIZ, files[i]) == NULL) {
                strcpy(buffer, "\n");
                // buffer[0] = '\n';
                // buffer[1] = '\0';
                eofstr[i] = '1';
                if (is_endoffiles(eofstr))
                    continue;
            }
            if (i < argc-1)
                buffer[strcspn(buffer, "\n")] = sep;
            printf("%s", buffer);
        }
    }
    for (i = 0; i < argc; i++) {
        fclose(files[i]);
    }
    return EXIT_SUCCESS;
}

/**
 * Abertura de arquivos serial
 */
int print_serial(char **flist, int argc, char sep) {
    char buffer[BUFSIZ];
    for (int i = 0; i < argc; i++) {
        FILE *stream = openstream(stream, flist[i]);
        while (fgets(buffer, BUFSIZ, stream) != NULL) {
            buffer[strcspn(buffer, "\n")] = sep;
            printf("%s", buffer);
        }
        putchar('\n');
        fclose(stream);
    }
    return EXIT_SUCCESS;
}

int main(int argc, char **argv) {
    int opt;
    char sep = '\t';
    bool mode_serial = false;
    while ((opt = getopt(argc, argv, "d:shv")) != -1) {
        if (opt == 0) {
            continue;
        }
        switch (opt) {
            case 'd':
                sep = optarg[0];
                optind++;
                break;
            case 's':
                mode_serial = true;
                break;
            default:
                abort();
        }
    }
    optind--;
    if (mode_serial) {
        print_serial(argv + optind, argc - optind, sep);
        return EXIT_SUCCESS;
    }

    print_parallel(argv + optind, argc - optind, sep);
    return EXIT_SUCCESS;
}
Fala pessoal, postando aqui minha solução do projeto de conclusão de curso para o clone do paste ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #include <stdbool.h> /** * Uso: paste [OPÇÃO]... [ARQUIVO]... * Escreve linhas constituídas das linhas sequencialmente correspondentes de * cada ARQUIVO, separadas por tabulações, para a saída padrão. * * Se ARQUIVO não for especificado ou for -, lê a entrada padrão. * * Argumentos obrigatórios para opções longas também o são para opções curtas. * -d, --delimiters=LISTA reutiliza caracteres da LISTA em vez de tabulações * -s, --serial cola um arquivo por vez em de todos em paralelo * -z, --zero-terminated delimitador de linha é NULO, não nova linha * --help mostra esta ajuda e sai * --version mostra informação da versão e sai * * Página de ajuda do GNU coreutils: <https://www.gnu.org/software/coreutils/> * Relate erros de tradução para <https://translationproject.org/team/pt_BR.html> * Documentação completa em <https://www.gnu.org/software/coreutils/paste> * ou disponível localmente via: info "(coreutils) paste invocation" */ FILE *openstream(FILE *file, char *str) { file = stdin; if (strcmp(str, "-") != 0) file = fopen(str, "r"); if (!file) { perror(str); exit(EXIT_FAILURE); } return file; } int is_endoffiles(char *list) { for (int i = 0; list[i] != '\0'; i++) { if (list[i] == '0') return 0; } // str = "111111..."; return 1; } /** * Abertura de arquivos em paralelo */ int print_parallel(char **flist, int argc, char sep) { int i; char buffer[BUFSIZ]; FILE *files[argc]; /** * eofstr = "000000..." (args) */ char eofstr[argc+1]; for (i = 0; i < argc; i++) { files[i] = openstream(files[i], flist[i]); eofstr[i] = '0'; } while (!is_endoffiles(eofstr)) { for (i = 0; i < argc; i++) { if (fgets(buffer, BUFSIZ, files[i]) == NULL) { strcpy(buffer, "\n"); // buffer[0] = '\n'; // buffer[1] = '\0'; eofstr[i] = '1'; if (is_endoffiles(eofstr)) continue; } if (i < argc-1) buffer[strcspn(buffer, "\n")] = sep; printf("%s", buffer); } } for (i = 0; i < argc; i++) { fclose(files[i]); } return EXIT_SUCCESS; } /** * Abertura de arquivos serial */ int print_serial(char **flist, int argc, char sep) { char buffer[BUFSIZ]; for (int i = 0; i < argc; i++) { FILE *stream = openstream(stream, flist[i]); while (fgets(buffer, BUFSIZ, stream) != NULL) { buffer[strcspn(buffer, "\n")] = sep; printf("%s", buffer); } putchar('\n'); fclose(stream); } return EXIT_SUCCESS; } int main(int argc, char **argv) { int opt; char sep = '\t'; bool mode_serial = false; while ((opt = getopt(argc, argv, "d:shv")) != -1) { if (opt == 0) { continue; } switch (opt) { case 'd': sep = optarg[0]; optind++; break; case 's': mode_serial = true; break; default: abort(); } } optind--; if (mode_serial) { print_serial(argv + optind, argc - optind, sep); return EXIT_SUCCESS; } print_parallel(argv + optind, argc - optind, sep); return EXIT_SUCCESS; } ```

Pessoal,

Segue minha solução para o projeto de conclusão de curso cblc: clone do utilitário paste (coreutils).

/*
 *c_paste - Emula o utilitário paste (coreutils)
 * Com as opções:
 * -d Delimitador;
 * -s Impressão em série ao invés da padrão em paralelo;
 * -h Ajuda.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv) {

  char *delimiter = "\t";
  char *argv_files[argc];
  int argc_files=0;
  int parallel_print = 1;
  
  // Verificação do número de argumentos.
  if (argc < 2) {
    fprintf(stderr, "%s: Número incorreto de argumentos!\n",argv[0]);
    return EXIT_FAILURE;
  }else{

    // Verificação dos argumentos passados.    
    for(int i=1; argv[i] != NULL; i++){
      
      if (argv[i][0] == '-') {
    	if (strcmp(argv[i], "-d") == 0) {
    	  delimiter = argv[i+1]; // Recebe o delimitador.
    	  
    	  //*** Implementar lista de caracteres igual ao paste
    	  
    	} else if (strcmp(argv[i], "-s") == 0) {
    	  parallel_print = 0;   // Modo de impressa serial ou paralelo.
      
    	} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
    	  // Imprime ajuda e termina.
    	  fprintf(stdout,
    		  "Uso: %s [OPÇÕES] -d -s -h [ARQUIVOS]... \n\n"
    		  "-d # Delimitador ao invés do padrão TAB.\n"
    		  "-s   Impressão serial ao invés do padrão paralelo.\n"
    		  "-h   Ajuda\n", argv[0]);
    	  
    	  return EXIT_SUCCESS;
    	  
    	} else {
    	  // Imprime Argumentos inválidos e termina.
    	  fprintf(stderr, "Argumento inválido! (%s)\n",argv[i]);
    	  return EXIT_FAILURE;
    	}
          }else if (strcmp(argv[i-1], "-d") != 0) {
    	argv_files[argc_files] = argv[i];  // Recebe apenas os nomes dos arquivos.
    	argc_files++; // Controla quantidade apenas dos arquivos.
          }      
    }
       
    // Array de ponteiros para os arquivos.
    const int total_files = argc_files;
    FILE *files[total_files];
    char buf[BUFSIZ];
    
    // Abertura dos arquivos com verificação de erro.
    for(int i = 0; i < argc_files; i++) {  
      files[i] = fopen(argv_files[i], "r");

      //Trata o erro ao abrir um arquivo.
      if(files[i] == NULL) {
	fprintf(stderr, "Erro ao abrir o arquivo: %s\n", argv_files[i]);

	// Fechamento dos arquivos em caso de erro.
	for(int j = 0; j < i; j++) {
	  fclose(files[j]);
	}
	return EXIT_FAILURE;
      }
    }

    //Variáveis para controle das linhas e aquivos.
    int iline=0;
    int nextline=1;
    int ifile;
    int num_delimiter;
    
    if (parallel_print){
      // Impressão em paralelo.
     
      // Controle da leitura linha linha.
      while(iline < nextline) {

	iline = nextline;
	num_delimiter = 0;
	
	//Leitura da linha de todos arquivos.
	for(ifile = 0; ifile < argc_files; ifile++) {

	  if(fgets(buf, BUFSIZ, files[ifile]) != NULL) {

	    // Remove a quebra de linha.
	    size_t len = strlen(buf);
	    if (len > 0 && buf[len - 1] == '\n') {
	      buf[len - 1] = '\0';
	    }

	    // Imprime delimitadores dos arquivos em EOF.
	    if(ifile > 0){
	      for(int idel = 0; idel < num_delimiter; idel++){ 
		printf("%s", delimiter);
	      }
	      num_delimiter = 0;
	    }

	    // Impressão do conteúdo.
	    if(ifile < argc_files-1 ){ // Se último arquivo não imprime delimitador.
	      printf("%s%s", buf,delimiter); // Imprime conteúdo com delimitador.
	    }else{
	      printf("%s", buf); // Imprime conteúdo sem delimitador.
	    }
  	    
	    //Algum aquivo ainda tem conteúdo, próxima linha.
	    if (nextline <= iline){
	      nextline++; 
	    }         
	  }else{
	    num_delimiter++; // Arquivo em EOF, controle do número de delimitadores.
	  }
	}
	if(iline < nextline) {
	  putchar('\n');  // Nova linha.
	}
      }   
    }else{
      //Impressão em série.

      // Controle da leitura dos arquivos.
      for(ifile = 0; ifile < argc_files; ifile++) {
  
	//Leitura de todas as linhas de cada arquivo
	while(fgets(buf, BUFSIZ, files[ifile]) != NULL) {

	  // Remove a quebra de linha.
	  size_t len = strlen(buf);
	  if (len > 0 && buf[len - 1] == '\n') {
	    buf[len - 1] = '\0';
	  }
	
	  // Imprime o delimitador.
	  if(iline > 0) {
	    printf("%s", delimiter);
	  }
	  // Imprime o conteúdo.
	  printf("%s", buf); 
	  iline++;  //Contagem das linhas.
	} 
	putchar('\n');  // Nova linha.
	iline = 0;  //Reinicia a contagem das linhas
      }
    }

    // Fechamento dos arquivos.
    for(int i = 0; i < argc_files; i++) {
      fclose(files[i]);
    }
  }
  
  return EXIT_SUCCESS;
}

Pessoal, Segue minha solução para o projeto de conclusão de curso cblc: clone do utilitário paste (coreutils). ```c /* *c_paste - Emula o utilitário paste (coreutils) * Com as opções: * -d Delimitador; * -s Impressão em série ao invés da padrão em paralelo; * -h Ajuda. */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char **argv) { char *delimiter = "\t"; char *argv_files[argc]; int argc_files=0; int parallel_print = 1; // Verificação do número de argumentos. if (argc < 2) { fprintf(stderr, "%s: Número incorreto de argumentos!\n",argv[0]); return EXIT_FAILURE; }else{ // Verificação dos argumentos passados. for(int i=1; argv[i] != NULL; i++){ if (argv[i][0] == '-') { if (strcmp(argv[i], "-d") == 0) { delimiter = argv[i+1]; // Recebe o delimitador. //*** Implementar lista de caracteres igual ao paste } else if (strcmp(argv[i], "-s") == 0) { parallel_print = 0; // Modo de impressa serial ou paralelo. } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { // Imprime ajuda e termina. fprintf(stdout, "Uso: %s [OPÇÕES] -d -s -h [ARQUIVOS]... \n\n" "-d # Delimitador ao invés do padrão TAB.\n" "-s Impressão serial ao invés do padrão paralelo.\n" "-h Ajuda\n", argv[0]); return EXIT_SUCCESS; } else { // Imprime Argumentos inválidos e termina. fprintf(stderr, "Argumento inválido! (%s)\n",argv[i]); return EXIT_FAILURE; } }else if (strcmp(argv[i-1], "-d") != 0) { argv_files[argc_files] = argv[i]; // Recebe apenas os nomes dos arquivos. argc_files++; // Controla quantidade apenas dos arquivos. } } // Array de ponteiros para os arquivos. const int total_files = argc_files; FILE *files[total_files]; char buf[BUFSIZ]; // Abertura dos arquivos com verificação de erro. for(int i = 0; i < argc_files; i++) { files[i] = fopen(argv_files[i], "r"); //Trata o erro ao abrir um arquivo. if(files[i] == NULL) { fprintf(stderr, "Erro ao abrir o arquivo: %s\n", argv_files[i]); // Fechamento dos arquivos em caso de erro. for(int j = 0; j < i; j++) { fclose(files[j]); } return EXIT_FAILURE; } } //Variáveis para controle das linhas e aquivos. int iline=0; int nextline=1; int ifile; int num_delimiter; if (parallel_print){ // Impressão em paralelo. // Controle da leitura linha linha. while(iline < nextline) { iline = nextline; num_delimiter = 0; //Leitura da linha de todos arquivos. for(ifile = 0; ifile < argc_files; ifile++) { if(fgets(buf, BUFSIZ, files[ifile]) != NULL) { // Remove a quebra de linha. size_t len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') { buf[len - 1] = '\0'; } // Imprime delimitadores dos arquivos em EOF. if(ifile > 0){ for(int idel = 0; idel < num_delimiter; idel++){ printf("%s", delimiter); } num_delimiter = 0; } // Impressão do conteúdo. if(ifile < argc_files-1 ){ // Se último arquivo não imprime delimitador. printf("%s%s", buf,delimiter); // Imprime conteúdo com delimitador. }else{ printf("%s", buf); // Imprime conteúdo sem delimitador. } //Algum aquivo ainda tem conteúdo, próxima linha. if (nextline <= iline){ nextline++; } }else{ num_delimiter++; // Arquivo em EOF, controle do número de delimitadores. } } if(iline < nextline) { putchar('\n'); // Nova linha. } } }else{ //Impressão em série. // Controle da leitura dos arquivos. for(ifile = 0; ifile < argc_files; ifile++) { //Leitura de todas as linhas de cada arquivo while(fgets(buf, BUFSIZ, files[ifile]) != NULL) { // Remove a quebra de linha. size_t len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') { buf[len - 1] = '\0'; } // Imprime o delimitador. if(iline > 0) { printf("%s", delimiter); } // Imprime o conteúdo. printf("%s", buf); iline++; //Contagem das linhas. } putchar('\n'); // Nova linha. iline = 0; //Reinicia a contagem das linhas } } // Fechamento dos arquivos. for(int i = 0; i < argc_files; i++) { fclose(files[i]); } } return EXIT_SUCCESS; } ```
Owner

Só um ponto de partida a mais para quem quiser tentar:

/*
  Mescla em colunas o conteúdo dos arquivos passados
  como argumentos e imprime no terminal.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

// Estilo ANSI: negrito + amarelo
#define STYLE_ERROR "\033[1;33m"
#define STYLE_RESET "\033[0m"

// Mensagem de uso e ajuda...
const char *MSG_USAGE =
    "Merge Files (merge) 0.1\n\n"
    "Uso: %s [OPÇÕES] ARQUIVO1 ARQUIVO2 [ARQUIVOS...]\n\n"
    "Mescla em colunas as linhas dos arquivos passados\n"
    "como argumentos e imprime na saída padrão.\n\n"
    "OPÇÕES:\n"
    "    -h    Exibe esta ajuda.\n\n";

// Mensagens de erro...
const char *MSG_ARGC_ERROR = "Número incorreto de argumentos.\n\n";
const char *MSG_TOO_MANY_FILES_ERROR = "Número excessivo de arquivos.\n\n";
const char *MSG_FOPEN_ERROR = "Erro na abertura do arquivo ";

// Nùmero máximo de arquivos...
#define FILES_MAX 11

// Delimitador...
const char *DELIMITER = "\t";

int is_tty_stderr();
void print_error(const char *msg);
int print_usage(int status, const char *prog_name);
int print_error_usage(const char *err, const char *prog_name);
void close_files(FILE **files);
void trim_string(char *str, int size);

int main(int argc, char **argv) {

    // Checagem de argumentos...
    if (argc < 3) {
        print_error_usage(MSG_ARGC_ERROR, argv[0]);
        return EXIT_FAILURE;
    } else if (argc > (1 + FILES_MAX)) {
        print_error_usage(MSG_TOO_MANY_FILES_ERROR, argv[0]);
        return EXIT_FAILURE;
    }

    // Handlers dos arquivos...
    FILE *file_handler[FILES_MAX];

    // Abertura de arquivos...
    int nfiles = argc - 1;
    int count_files = 0;
    for (int i = 0; i < nfiles; i++) {
        file_handler[count_files] = fopen(argv[i + 1], "r");
        if (!file_handler[i]) {
            print_error(MSG_FOPEN_ERROR);
            fprintf(stderr, "%s.\n" ,argv[i + 1]);
            close_files(file_handler);
            return EXIT_FAILURE;
        }
        count_files++;
    }
    file_handler[count_files] = NULL;

    // Leitura e impressão das linhas...
    int has_lines = 1;
    int end_file = nfiles - 1;
    char buffer[BUFSIZ];
    char line[BUFSIZ * nfiles];
    const char *sep;
    while (has_lines) {
        count_files = 0;
        has_lines = 0;
        line[0] = '\0';
        while (file_handler[count_files] != NULL) {
            char temp[BUFSIZ] = "";
            if (fgets(buffer, BUFSIZ, file_handler[count_files])) {
                trim_string(buffer, strlen(buffer));
                snprintf(temp, sizeof(temp), "%s", buffer);
                has_lines++;
            }
            strncat(line, temp, sizeof(line) - strlen(line) - 1);
            sep = "\n";
            if (count_files < end_file) sep = DELIMITER;
            strncat(line, sep, sizeof(line) - strlen(line) - 1);
            count_files++;
        }
        if (has_lines) fputs(line, stdout);
    }

    // Fechamento dos arquivos...
    close_files(file_handler);
    
    return 0;
}

// Remove quebra de linha final, se houver.
void trim_string(char *str, int size) {
    int i = 0;
    while (i < size && str[i] != '\0') {
        if (str[i] == '\n') {
            str[i] = '\0';
            break;
        }
        i++;
    }
}

// Fecha todos os arquivos abertos.
void close_files(FILE **files) {
    int i = 0;
    while (files[i] != NULL) {
        fclose(files[i]);
        i++;
    }
}
    
// Retorna sucesso se stderr estiver ligada ao terminal.
int is_tty_stderr() {
    return isatty(fileno(stderr));
}

// Imprime mensagens de erro sem argumentos.
void print_error(const char *msg) {
    if (is_tty_stderr())
        fprintf(stderr, STYLE_ERROR "%s" STYLE_RESET, msg);
    else
        fprintf(stderr, "%s", msg);
}

// Imprime versão e ajuda e retorna status.
int print_usage(int status, const char *prog_name) {
    FILE *stream = stderr;
    if (status == EXIT_SUCCESS) stream = stdout;
    fprintf(stream, MSG_USAGE, prog_name);
    return status;
}

// Imprime mensagem de erro e ajuda.
int print_error_usage(const char *err, const char *prog_name) {
        print_error(err);
        return print_usage(EXIT_FAILURE, prog_name);
}
Só um ponto de partida a mais para quem quiser tentar: ```c /* Mescla em colunas o conteúdo dos arquivos passados como argumentos e imprime no terminal. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> // Estilo ANSI: negrito + amarelo #define STYLE_ERROR "\033[1;33m" #define STYLE_RESET "\033[0m" // Mensagem de uso e ajuda... const char *MSG_USAGE = "Merge Files (merge) 0.1\n\n" "Uso: %s [OPÇÕES] ARQUIVO1 ARQUIVO2 [ARQUIVOS...]\n\n" "Mescla em colunas as linhas dos arquivos passados\n" "como argumentos e imprime na saída padrão.\n\n" "OPÇÕES:\n" " -h Exibe esta ajuda.\n\n"; // Mensagens de erro... const char *MSG_ARGC_ERROR = "Número incorreto de argumentos.\n\n"; const char *MSG_TOO_MANY_FILES_ERROR = "Número excessivo de arquivos.\n\n"; const char *MSG_FOPEN_ERROR = "Erro na abertura do arquivo "; // Nùmero máximo de arquivos... #define FILES_MAX 11 // Delimitador... const char *DELIMITER = "\t"; int is_tty_stderr(); void print_error(const char *msg); int print_usage(int status, const char *prog_name); int print_error_usage(const char *err, const char *prog_name); void close_files(FILE **files); void trim_string(char *str, int size); int main(int argc, char **argv) { // Checagem de argumentos... if (argc < 3) { print_error_usage(MSG_ARGC_ERROR, argv[0]); return EXIT_FAILURE; } else if (argc > (1 + FILES_MAX)) { print_error_usage(MSG_TOO_MANY_FILES_ERROR, argv[0]); return EXIT_FAILURE; } // Handlers dos arquivos... FILE *file_handler[FILES_MAX]; // Abertura de arquivos... int nfiles = argc - 1; int count_files = 0; for (int i = 0; i < nfiles; i++) { file_handler[count_files] = fopen(argv[i + 1], "r"); if (!file_handler[i]) { print_error(MSG_FOPEN_ERROR); fprintf(stderr, "%s.\n" ,argv[i + 1]); close_files(file_handler); return EXIT_FAILURE; } count_files++; } file_handler[count_files] = NULL; // Leitura e impressão das linhas... int has_lines = 1; int end_file = nfiles - 1; char buffer[BUFSIZ]; char line[BUFSIZ * nfiles]; const char *sep; while (has_lines) { count_files = 0; has_lines = 0; line[0] = '\0'; while (file_handler[count_files] != NULL) { char temp[BUFSIZ] = ""; if (fgets(buffer, BUFSIZ, file_handler[count_files])) { trim_string(buffer, strlen(buffer)); snprintf(temp, sizeof(temp), "%s", buffer); has_lines++; } strncat(line, temp, sizeof(line) - strlen(line) - 1); sep = "\n"; if (count_files < end_file) sep = DELIMITER; strncat(line, sep, sizeof(line) - strlen(line) - 1); count_files++; } if (has_lines) fputs(line, stdout); } // Fechamento dos arquivos... close_files(file_handler); return 0; } // Remove quebra de linha final, se houver. void trim_string(char *str, int size) { int i = 0; while (i < size && str[i] != '\0') { if (str[i] == '\n') { str[i] = '\0'; break; } i++; } } // Fecha todos os arquivos abertos. void close_files(FILE **files) { int i = 0; while (files[i] != NULL) { fclose(files[i]); i++; } } // Retorna sucesso se stderr estiver ligada ao terminal. int is_tty_stderr() { return isatty(fileno(stderr)); } // Imprime mensagens de erro sem argumentos. void print_error(const char *msg) { if (is_tty_stderr()) fprintf(stderr, STYLE_ERROR "%s" STYLE_RESET, msg); else fprintf(stderr, "%s", msg); } // Imprime versão e ajuda e retorna status. int print_usage(int status, const char *prog_name) { FILE *stream = stderr; if (status == EXIT_SUCCESS) stream = stdout; fprintf(stream, MSG_USAGE, prog_name); return status; } // Imprime mensagem de erro e ajuda. int print_error_usage(const char *err, const char *prog_name) { print_error(err); return print_usage(EXIT_FAILURE, prog_name); } ```
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: blau_araujo/cblc#28
No description provided.