#define _POSIX_C_SOURCE 200809L #include /* assert */ #include /* err, warn */ #include /* errno, EBADF, ENOENT */ #include /* memcmp */ #include /* close, read, unlink, write */ #include /* open, openat */ #include /* open, openat */ #include /* open, openat */ /* Implementujte podprogram ‹align›, který doplní „zubatou“ matici * (s různě dlouhými řádky) na matici obdélníkovou. Vstupní matici * načtěte z popisovače ‹fd_in›. Vstupní matice sestává * z jednotlivých řádků, přitom každý řádek začíná jednobajtovým * počtem sloupců a pokračuje příslušným počtem čtyřbajtových hodnot * (čísel). * * Parametry budou: * * • ‹fd_in› – vstupní popisovač, * • ‹cols› – délka zarovnaných řádků (počet sloupců), * • ‹fd_out› – výstupní popisovač. * * Podprogram bude do výstupního popisovače zapisovat řádky délky * právě ‹cols› hodnot. Je-li vstupní řádek kratší, bude zprava * doplněn nulami, je-li delší, bude ořezán na ‹cols› čísel. * Výstupní řádky sestávají pouze z čísel (nejsou předcházeny počtem * sloupců). * * Návratová hodnota bude: * * • počet řádků zapsané matice, proběhlo-li vše v pořádku, * • ‹-1› v případě systémové chyby. * * Podprogram smí použít nejvýše konstantní množství paměti. */ int align( int fd_in, int cols, int fd_out ); /* ┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄┄┄┄ následují testy ┄┄┄┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄ */ static void unlink_if_exists( const char *file ) { if ( unlink( file ) == -1 && errno != ENOENT ) err( 2, "unlink" ); } static void close_or_warn( int fd, const char *name ) { if ( close( fd ) == -1 ) warn( "closing %s", name ); } static int create_file( const char *name ) { unlink_if_exists( name ); int fd; if ( ( fd = openat( AT_FDCWD, name, O_CREAT | O_TRUNC | O_WRONLY, 0666 ) ) == -1 ) err( 2, "creating %s", name ); return fd; } static int check_output( const char* expected, const size_t size ) { const char *name = "zt.p5_align_out"; char buffer[ 256 ]; int read_fd = openat( AT_FDCWD, name, O_RDONLY ); if ( read_fd == -1 ) err( 2, "opening %s", name ); ssize_t bytes; size_t already_read = 0; while ( ( bytes = read( read_fd, buffer, sizeof( buffer ) ) ) > 0 ) { if ( memcmp( expected + already_read, buffer, bytes ) != 0 ) return 0; already_read += bytes; } if ( bytes == -1 ) err( 2, "reading %s", name ); close_or_warn( read_fd, name ); return already_read == size ? 1 : 0; } static void write_file( const char *name, const char *buf, size_t size ) { int fd = create_file( name ); if ( write( fd, buf, size ) == -1 ) err( 2, "writing file %s", name ); close_or_warn( fd, name ); } static int check_align(const char *data, size_t size, int cols) { const char *name_in = "zt.p5_align_in"; const char *name_out = "zt.p5_align_out"; int read_fd, write_fd, retval; write_file( name_in, data, size ); write_fd = openat( AT_FDCWD, name_out, O_CREAT | O_TRUNC | O_WRONLY, 0666 ); if ( write_fd == -1 ) err( 2, "creating %s", name_out ); read_fd = openat( AT_FDCWD, name_in, O_RDONLY ); if ( read_fd == -1 ) err( 2, "opening %s", name_in ); retval = align( read_fd, cols, write_fd ); close_or_warn( write_fd, name_out ); close_or_warn( read_fd, name_in ); return retval; } int main( void ) { unlink_if_exists( "zt.p5_align_in" ); unlink_if_exists( "zt.p5_align_out" ); const char zeroes[ 256 ] = { 0 }; const char data_0[] = { 0x01, 0x00, 0x00, 0x00, 0x00, }; const char data_1[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }; const char data_2[] = { 0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, }; const char data_2_out[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, }; assert( check_align( data_0, sizeof( data_0 ), 1 ) == 1 ); assert( check_output( zeroes, 4 ) ); assert( check_align( data_1, sizeof( data_1 ), 4 ) == 2 ); assert( check_output( zeroes, 32 ) ); assert( check_align( data_1, sizeof( data_1 ), 2 ) == 2 ); assert( check_output( zeroes, 16 ) ); assert( check_align( data_1, sizeof( data_1 ), 6 ) == 2 ); assert( check_output( zeroes, 48 ) ); assert( check_align( data_2, sizeof( data_2 ), 4 ) == 4 ); assert( check_output( data_2_out, sizeof( data_2_out ) ) ); int fd_wronly = open( "/dev/null", O_WRONLY ); if ( fd_wronly == -1 ) err( 2, "/dev/null" ); assert( align( fd_wronly, 1, fd_wronly ) == -1 ); assert( errno == EBADF ); close_or_warn( fd_wronly , "/dev/null"); unlink_if_exists( "zt.p5_align_in" ); unlink_if_exists( "zt.p5_align_out" ); return 0; }