LINUX.ORG.RU

Помогите реализовать блочный ввод- вывод.


0

1

Код:

#define _LARGEFILE64_SOURCE
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h> 
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "getopt.h"
char* itoa(unsigned int val);
void dchk(int f);
int ferr();
int usage();
int main(int argc, char** argv){
	register int ch, filenum;//filenum- FILE NUMber;
	int longIndex;
	register short sht=0, shn=0, shcc=0, num=0, num_nonblank=0;
	//sht- SHow Tabulation; shn- SHow '\n' symbol(carriage return); shcc- SHow Control Characters; num- NUMber;
	static const struct option longOpts[] = {
	{ "show-nonprinting", no_argument, NULL, 'v' },
	{ "show-tabs", no_argument, NULL, 'T' },
	{ "show-ends", no_argument, NULL, 'E' },
	{ "show-all", no_argument, NULL, 'A' },
	{ "number", no_argument, NULL, 'n' },
	{ "version", no_argument, NULL, 0 },
    { NULL, no_argument, NULL, 0 }
	};
	while((ch=getopt_long(argc, argv, "ETAethuni",longOpts,&longIndex))!= -1){
        switch (ch) {
				case 'n':
                    num = 1;
                    break;
                case 'i':
                    num_nonblank = 1;
                    break;
                case 'E':
                    shn = 1;
                    break;
                case 'T':
                    sht=1;
                    break;
                case 'A':{
					shn=1;
					sht=1;
					shcc=1;
					break;
					}
                case 'v':
                	shcc=1;
                	break;
                case 'e':{
                	shcc=1;
                	shn=1;
                	break;
					}
                case 't':{
                	shcc=1;
                	sht=1;
                	break;
					}
				case '?':
				case 'h':
					usage();
				case 'u':
					break;
				case 0:if(strcmp( "version",longOpts[longIndex].name)==0){
					write(STDOUT_FILENO,"sysccat version 0.1\n",20);
					_exit(0);
					}
					else usage();
                }
        }
	argv+=optind;
	argc-=optind;
	if(argc==0)usage();
//if no options defined
	if(!sht&&!shn&&!shcc&&!num)for(filenum=0;filenum<argc;++filenum){
												int fd=open(argv[filenum],O_RDONLY);
												if(fd<0)ferr();
												dchk(fd);
												off_t filesize=lseek(fd,0,SEEK_END);
												lseek(fd,0,SEEK_SET);
												char *c;
												c=malloc(4096);
												while(4096<filesize){
													read(fd,c,4096);
													write(STDOUT_FILENO,c,4096);
													filesize-=4096;
												}
												free(c);
												c=malloc(filesize);
												read(fd,c,filesize);
												write(STDOUT_FILENO,c,filesize);
												free(c);
												close(fd);
												}
//if any option defined
		else for(filenum=0;filenum<argc;++filenum){
			char a;
			int fd=open(argv[filenum],O_RDONLY);
			if(fd<0)ferr();
			dchk(fd);
			if(num)write(STDOUT_FILENO,"1: ",3);
			register int numline=1;//numline- NUMber of Line
			while(read(fd,&a,1)>0){
				if(num&&a=='\n'){
								if(read(fd,&a,1)==0){
													if(shn)write(STDOUT_FILENO,"$",1);
													write(STDOUT_FILENO,&a,1);
													}
								else{
									if(shn)write(STDOUT_FILENO,"$",1);
									write(STDOUT_FILENO,"\n",1);
									++numline;
									write(STDOUT_FILENO,itoa(numline),strlen(itoa(numline)));
									write(STDOUT_FILENO,": ",2);
									lseek(fd, -1, SEEK_CUR);
									}
				}
				else if(sht&&a=='\t')write(STDOUT_FILENO,"^I",2);
					else if(shn&&a=='\n')write(STDOUT_FILENO,"$\n",2);
						else if(shcc&&iscntrl(a)&&a!='\n'&&a!='\t'){
																	a+=64;
																	write(STDOUT_FILENO,"^",1);
																	write(STDOUT_FILENO,&a,1);
																	}
							else write(STDOUT_FILENO,&a,1);
			}
		close(fd);
	}
	_exit(0);
}
int usage(){
	write(STDOUT_FILENO,"Usage: sysccat [OPTIONS]... [FILE]...\n"
	"-h or --help Displays this info and exit.\n"
	"-n or --number Numbers the output strings.\n"
	"--version Displays version and exit.\n"
	"-v or --show-nonprinting Displays non-printing(control) characters, except for tabulation and carriage return/end-of-line symbols.\n"
	"-A, -vET or --show-all Displays all control characters.\n"
	"-t or -vT Displays all control characters, except for carriage return/end-of-line symbol.\n"
	"-u Ignored; for POSIX compatibility.\n"
	"-e or -vE Displays all control characters, except for tabulation symbol.\n",547);
	_exit(0);
	}
char* itoa(unsigned int val){
	static char buf[11];
	short i=10;
	for(;val&&i;--i,val/=10)buf[i]=val%10+48;
	return &buf[i+1];
}
int ferr(){
	write(STDERR_FILENO,strerror(errno),strlen(strerror(errno)));
	write(STDERR_FILENO,".\n",2);
	_exit(1);
}
void dchk(int f){
	struct stat fs;
	fstat(f,&fs);
	if(S_ISDIR(fs.st_mode)){
		write(STDERR_FILENO,"It's a directory.\n",18);
		close(f);
		_exit(1);
		}
}
Блочный ввод-вывод нужно реализовать в части, начинающейся после //if any option defined Пока ничего путного в голову не пришло- индуизмы одни. Заранее спасибо.
P.S.: #include «getopt.h» ибо у меня свой getopt_long- с блэкджеком, шлюхами и не требующий #define _GNU_SOURCE, базирующийся на коде этой функции из Open и Net BSD.

★★

Последнее исправление: Dorif (всего исправлений: 1)

read(fd,c,4096);
write(STDOUT_FILENO,c,4096);

Нет проверки возвращаемого значения. Лень проверять, поставь хотя бы заглушки.

pathfinder ★★★★
()
c=malloc(4096);
...
free(c);

Зачем выделять в куче массив известного размера? Может лучше в стеке?

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

а смысл?

while(4096<filesize){
                                       read(fd,c,4096);
                                       write(STDOUT_FILENO,c,4096);
                                       filesize-=4096;
                                    }
же. Если остаток файла меньше либо равен 4096 это и не выполнится, а просто считается оставшаяся часть файла.

Dorif ★★
() автор топика
Ответ на: комментарий от pathfinder

Ибо потом пойдёт неизвестный размер оставшейся части. К. О.

Dorif ★★
() автор топика
c=malloc(filesize);
read(fd,c,filesize);
write(STDOUT_FILENO,c,filesize);
free(c);

Зачем ещё раз выделять новый массив в куче, если известно, что он будет меньше 4096 байт? Старый массив вполне может уместить последний блок данных.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Код GNU Cat читал? Если нет- вперёд. Он, конечно. комментирован. но всё равно малопонятен.

Dorif ★★
() автор топика
Ответ на: комментарий от Dorif

«Меньше 4096» не равно «меньше либо равно 4096»

Ладно, давай я приведу свой вариант, а ты скажешь почему это не катит.

char block_buffer[4096];
int to_write = filesize;
while(to_write>0)
{
  int block_size=MIN(to_write,sizeof(block_buffer));
  call_helper( read(fd,block_buffer,block_size) );
  call_helper( write(fd,block_buffer,block_size) );
  to_write-=block_size;  
}

call_helper - некий макрос заглушка, который проверяет возвращаемое значение и завершает, в случае ошибки, программу с выбросом осмысленного сообщения на экран.

Так же делается предположение, что read/write считают/запишут весь блок данных за один вызов. Для регулярных файлов так можно, для всяких COM-портов нельзя.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Так же делается предположение, что read/write считают/запишут весь блок данных за один вызов. Для регулярных файлов так можно, для всяких COM-портов нельзя.

Спасибо, сделаю проверку типа файла! Касательно кода: подумайте о тех. кому его потом читать. Хотя, я кажись кое- что придумал по этой подсказке. Проще и быстрее. Напишу и проверю после еды и скину сюда.

Dorif ★★
() автор топика
Ответ на: комментарий от Dorif

Таким кодом пытать можно.
И зачем знать сколько байтов в файле?
read вроде возвращает кол-во прочитанных байт и пляски с размером не нужны.

rg-400
()
Ответ на: комментарий от Dorif

а смысл?

Если бы все программисты писали программы правильно, ошибок бы не было. Правило настолько простое, насколько далекое от реальности. Ошибки в программах были, есть, и будут. Сегодня этот код корректен, а завтра могут что-то в логике изменить. Ты думаешь ты настолько крут, что никогда не совершаешь ошибок? Любой, даже потенциальный, undefined behavior не нужен. Завершение программы с указанием места и причины ошибки всегда лучше чем непредсказуемое поведение программы.

pathfinder ★★★★
()
Ответ на: комментарий от Dorif

Касательно кода: подумайте о тех. кому его потом читать.

А что такого не читаемого в моем коде?

проверю после еды

Удачной тебе еды.

pathfinder ★★★★
()
Ответ на: комментарий от rg-400

Затем, что это нужно для блочного ввода- вывода(при этом не читая весь файл однм блоком- на это уйдёт уйма времени и потом столькоже на вывод этого). Не зная размера это будет трудновато реализовать и получтся индокод.

Dorif ★★
() автор топика
Ответ на: комментарий от pathfinder

> для всяких COM-портов нельзя

даже в блокирующем режиме? ;)

а в случае «непредвиденных» ситуаций запись всего блока и в обычный файл не гарантирована: она может быть прервана сигналом, например.

arsi ★★★★★
()
Ответ на: комментарий от pathfinder

Трудно читаемого- разбирающемуся в коде после меня ещё придётся разбираться в этом call_helper, который, судя по всему. будет нетривиальным. Плюс это снизит скорость работы. А сейчас моя прога работает со скоростью. примерно равной скорости GNU Cat при меньших индуизмах в коде.

Dorif ★★
() автор топика
Ответ на: комментарий от pathfinder

Ну. вряд ли изменят логику языка С, ибо это кажется самый консервативный язык в мире.

Dorif ★★
() автор топика
Ответ на: комментарий от Dorif

К тому же здесь логика такя. которая работает хоть в сях. хоть в Паскале.

Dorif ★★
() автор топика
Ответ на: комментарий от arsi

для всяких COM-портов нельзя

даже в блокирующем режиме? ;)

Даже в блокирующем режиме. Делаешь read(fd,buffer,1024), а считывается 30 байт.

а в случае «непредвиденных» ситуаций запись всего блока и в обычный файл не гарантирована: она может быть прервана сигналом, например.

Не может, это уже в какой-то ветке обсуждалось.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Не может, это уже в какой-то ветке обсуждалось.

Может произойти лишь ошибка ввода/вывода, но тогда что-то дозаписывать бесполезно.

pathfinder ★★★★
()
Ответ на: комментарий от Dorif
if ((buff = malloc(buffsize)) == NULL) {
		perror("cat: no memory");
		return (1);
}
while ((n = read(fd, buff, buffsize)) == 0) {
	if (n == -1) {
		...
	}
	offset = 0;
	do {
		nwritten = write(fileno(stdout), &buff[offset], n);
		if (nwritten <= 0) {
			...
		}
		offset += nwritten;
	} while ((n -= nwritten) > 0);
}

трудно? + добавить обработку ошибок (прерывание сигналом и т.п.).

rg-400
()
Ответ на: комментарий от Dorif

Кстати, какой тип файла у портов?

Символьное устройство (character device). А вообще забей на это.

И из каких ещё файлов блоками не читается?

Сокеты, пайпы не гарантируют атомарную запись всего блока данных за один вызов.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

> Даже в блокирующем режиме. Делаешь read(fd,buffer,1024), а считывается 30 байт.

а, ну да, я о таймаутах и прерываниям по спецсимволам забыл. переведи порт в raw-режим и убери таймауты.

> Не может, это уже в какой-то ветке обсуждалось.

ищи ссылку, почитаю, т.к. это противоречит тому, что написано в мане.

arsi ★★★★★
()
Ответ на: комментарий от rg-400

а) базовые утилиты на то и пишутся маленькими, чтобы памяти хватало. А моя прога легковеснее того же GNU Cat. Хотя и там таких проверок нет- почитайте его код. Нет, проверки ошибок хороши. Но не до маразма же. б) Вас в цикле ничего не напрягает? read возвращает число прочитанных байтов, следовательно условие цикла не имеет смысла. Так же, как не имеет смысла условие «Если н равно -1», ибо прямо до этого вы уже проверили. равно ли оно нулю.

Dorif ★★
() автор топика
Ответ на: комментарий от Dorif

это часть исходника cat 1980 года. На что вам памяти не хватает? 4086 байт это так много? Это у вас в голове нет смысла, читать исходники и маны вы не умеете.

rg-400
()
Ответ на: комментарий от arsi

переведи порт в raw-режим и убери таймауты.

Это ничего не изменит. Попробуй считать гигабайт из COM-порта. Буфер драйвера не резиновый и как правило небольшого размера.

pathfinder ★★★★
()
Ответ на: комментарий от rg-400

А POSIX принят в 1988. Я говорю про POSIX совместимый read и вообще: подразумевается совместимость с POSIX by default. Так что не надо ля-ля.

Dorif ★★
() автор топика
Ответ на: комментарий от arsi

ищи ссылку, почитаю, т.к. это противоречит тому, что написано в мане.

Там по ссылке я пытался убедить в обратном. Пусть тебя это не вводит в заблуждение. В конце меня переубедили. Читай лучше самый конец.

http://www.linux.org.ru/forum/development/4719110

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Вот мой новый код. как и обещал:

char c[4096];
												while(4096<=filesize){
													read(fd,&c,4096);
													write(STDOUT_FILENO,&c,4096);
													filesize-=4096;
												}
												read(fd,c,filesize);
												write(STDOUT_FILENO,c,filesize);
Ругайте.

Dorif ★★
() автор топика
Ответ на: комментарий от Dorif

Obvious fix:

                                    read(fd,c,filesize);
                                    write(STDOUT_FILENO,c,filesize);

Dorif ★★
() автор топика
Ответ на: комментарий от rg-400

Каких7 как они возникнуть- то могут?

Dorif ★★
() автор топика

547?

[code]
int usage(){
write(STDOUT_FILENO,«Usage: sysccat [OPTIONS]... [FILE]...\n»
"-h or --help Displays this info and exit.\n"
"-n or --number Numbers the output strings.\n"
"--version Displays version and exit.\n"
"-v or --show-nonprinting Displays non-printing(control) characters, except for tabulation and carriage return/end-of-line symbols.\n"
"-A, -vET or --show-all Displays all control characters.\n"
"-t or -vT Displays all control characters, except for carriage return/end-of-line symbol.\n"
"-u Ignored; for POSIX compatibility.\n"
"-e or -vE Displays all control characters, except for tabulation symbol.\n",547);
[/code]

[code]
write(STDOUT_FILENO,«Usage: sysccat [OPTIONS]...,547);
[/code]

[code]
547
[/code]

epic

google sizeof

anonymous
()
Ответ на: комментарий от Dorif

> Напишите свой, выложите- обсудим. Или почитайте сорцы GNU Cat.

google «сперва добейся». Такие вещи здесь не прокатывают :)

P.S. also try to google «usability» & start to use damn spaces!

anonymous
()
Ответ на: 547? от anonymous

Нафиг лишний sizeof, если размер строки известен заранее и не меняется?

Dorif ★★
() автор топика
Ответ на: комментарий от Dorif

lmao

> Нафиг лишний sizeof, если размер строки известен заранее и не меняется?

facepalm.

Индусокод такой индусокод.

anonymous
()
Ответ на: комментарий от anonymous

По части удобства для пользователя- здесь таки всё для людей. И кода минимум, следовательно читать можно без напряга.

Dorif ★★
() автор топика
Ответ на: lmao от anonymous

При чём здесь индокод? Вы что, меняете содержание help'а прямо по ходу работы программы? А это и есть хелп.

Dorif ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.