Um programa estilo cat (com vários argumentos e leitura de stdin) #25

Open
opened 2025-06-17 13:04:21 -03:00 by NRZCode · 2 comments

Uma versão diferente da que fizemos ontem, trabalhando com os argumentos de print_file.

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

void print_bytes(char *buf) {
    int i = 0;
    while(1) {
        printf("%02x ", (unsigned char)buf[i]);
        if (buf[i] == '\0') {
            break;
        }
        i++;
    }
    putchar('\n');
}

void print_file(char *buf, int size, FILE *stream) {
    while (fgets(buf, size, stream) != NULL)
        fputs(buf, stdout);
        // fprintf(stdout, "%s", buf);
        // printf("%s", buf);
        // print_bytes(buf);
}

#define MAXBUF 4096
// BUFSIZ = 8192

int main(int argc, char **argv) {
    char buf[BUFSIZ];
    int is_dash = 1;
    if (argc < 2) {
        print_file(buf, BUFSIZ, stdin);
        return EXIT_SUCCESS;
    }
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-") == 0) {
            if (is_dash)
                print_file(buf, BUFSIZ, stdin);
            is_dash = 0;
            continue;
        }
        FILE *arquivo = fopen(argv[i], "r");
        if (!arquivo) {
            perror(argv[i]);
            continue;
        }
        print_file(buf, BUFSIZ, arquivo);
        fclose(arquivo);
    }
    return EXIT_SUCCESS;
}
Uma versão diferente da que fizemos ontem, trabalhando com os argumentos de print_file. ```c #include <stdio.h> #include <stdlib.h> #include <string.h> void print_bytes(char *buf) { int i = 0; while(1) { printf("%02x ", (unsigned char)buf[i]); if (buf[i] == '\0') { break; } i++; } putchar('\n'); } void print_file(char *buf, int size, FILE *stream) { while (fgets(buf, size, stream) != NULL) fputs(buf, stdout); // fprintf(stdout, "%s", buf); // printf("%s", buf); // print_bytes(buf); } #define MAXBUF 4096 // BUFSIZ = 8192 int main(int argc, char **argv) { char buf[BUFSIZ]; int is_dash = 1; if (argc < 2) { print_file(buf, BUFSIZ, stdin); return EXIT_SUCCESS; } for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-") == 0) { if (is_dash) print_file(buf, BUFSIZ, stdin); is_dash = 0; continue; } FILE *arquivo = fopen(argv[i], "r"); if (!arquivo) { perror(argv[i]); continue; } print_file(buf, BUFSIZ, arquivo); fclose(arquivo); } return EXIT_SUCCESS; } ```
Owner

@NRZCode Bem melhor, usando stdin em fgets!

Também poderia fazer, em vez disso:

for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-") == 0) {
            if (is_dash)
                print_file(buf, BUFSIZ, stdin);
            is_dash = 0;
            continue;
        }
/* ... */

Isso aqui:

for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-") == 0) {
            if (!is_dash) continue; // Se 0, segue o loop...
            print_file(buf, BUFSIZ, stdin);
            is_dash = 0;
            continue;
        }
/* ... */
@NRZCode Bem melhor, usando `stdin` em `fgets`! Também poderia fazer, em vez disso: ```c for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-") == 0) { if (is_dash) print_file(buf, BUFSIZ, stdin); is_dash = 0; continue; } /* ... */ ``` Isso aqui: ```c for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-") == 0) { if (!is_dash) continue; // Se 0, segue o loop... print_file(buf, BUFSIZ, stdin); is_dash = 0; continue; } /* ... */ ```

Aproveitando para não ter que abrir uma nova issue com o msm assunto, o codigo final desenvolvido ontem foi:

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

void print_file(char *file, char *line, int size) {

	FILE *fstr = fopen(file,"r");
	if (!fstr) {
		perror("fopen");
		exit(EXIT_FAILURE);
	}

	while (fgets(line, size, fstr) != NULL) {
		printf("%s",line);
	}

	fclose(fstr);
}

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

	char line [BUFSIZ];

	if (argc == 1) {
		while (fgets(line, BUFSIZ, stdin) != NULL) {
			printf("%s", line);
		}

		return EXIT_SUCCESS;
	}

	int is_dash = 1;

	for (int i=1;i<argc;i++) {
		char *file = argv[i];

		if (strcmp(argv[i], "-") == 0) {
			if (is_dash) {
				print_file("/dev/stdin", line, BUFSIZ);
				is_dash = 0;
			}
		} else {
			print_file(file, line, BUFSIZ);
		}
	}

	return EXIT_SUCCESS;
} 

O aplicativo foi compitado com o nome de saida cat.out.

$ gcc cat.c -o cat.out

Onde foi explorado 3 saidas diferentes, baseadas nas seguintes entradas:

  • Com arquivos de texto:
$ ./cat.out texto1 text2
12345
1
2
3
4
5
  • Com nenhuma entrada (entrando no modo de digitação, sendo necessario força saida CTRL+d):
$ ./cat.out
1
1
teste
teste
  • Com redirecionamento de saida:
$ ./cat.out - /etc/shells - < /etc/crontab 
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
# You can also override PATH, but by default, newer versions inherit it from the environment
#PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6    * * 7   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6    1 * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
#
# /etc/shells: valid login shells
/bin/sh
/usr/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/usr/bin/dash
/usr/bin/tmux

Aproveitando para não ter que abrir uma nova issue com o msm assunto, o codigo final desenvolvido ontem foi: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> void print_file(char *file, char *line, int size) { FILE *fstr = fopen(file,"r"); if (!fstr) { perror("fopen"); exit(EXIT_FAILURE); } while (fgets(line, size, fstr) != NULL) { printf("%s",line); } fclose(fstr); } int main(int argc, char **argv) { char line [BUFSIZ]; if (argc == 1) { while (fgets(line, BUFSIZ, stdin) != NULL) { printf("%s", line); } return EXIT_SUCCESS; } int is_dash = 1; for (int i=1;i<argc;i++) { char *file = argv[i]; if (strcmp(argv[i], "-") == 0) { if (is_dash) { print_file("/dev/stdin", line, BUFSIZ); is_dash = 0; } } else { print_file(file, line, BUFSIZ); } } return EXIT_SUCCESS; } ``` O aplicativo foi compitado com o nome de saida `cat.out`. ``` $ gcc cat.c -o cat.out ``` Onde foi explorado 3 saidas diferentes, baseadas nas seguintes entradas: - Com arquivos de texto: ``` $ ./cat.out texto1 text2 12345 1 2 3 4 5 ``` - Com nenhuma entrada (entrando no modo de digitação, sendo necessario força saida `CTRL+d`): ``` $ ./cat.out 1 1 teste teste ``` - Com redirecionamento de saida: ``` $ ./cat.out - /etc/shells - < /etc/crontab # /etc/crontab: system-wide crontab # Unlike any other crontab you don't have to run the `crontab' # command to install the new version when you edit this file # and files in /etc/cron.d. These files also have username fields, # that none of the other crontabs do. SHELL=/bin/sh # You can also override PATH, but by default, newer versions inherit it from the environment #PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed 17 * * * * root cd / && run-parts --report /etc/cron.hourly 25 6 * * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; } 47 6 * * 7 root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; } 52 6 1 * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; } # # /etc/shells: valid login shells /bin/sh /usr/bin/sh /bin/bash /usr/bin/bash /bin/rbash /usr/bin/rbash /usr/bin/dash /usr/bin/tmux ```
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#25
No description provided.