#define _POSIX_C_SOURCE 200809L #include /* assert */ #include /* err, warn */ #include /* errno, ENOENT */ #include /* memcmp */ #include /* lseek, open, openat */ #include /* open, openat */ #include /* open, openat */ #include /* close, lseek, read, unlink, write */ /* Implementujte podprogram ‹split›, který bude načítat záznamy * pevné délky ze vstupního souboru a na základě jejich parity * zkopíruje jejich hlavičky (prvních 8 bajtů) do jednoho ze dvou * výstupních popisovačů. * * Parametry budou: * * • ‹fd_in› – vstupní popisovač, * • ‹len› – délka záznamu v bajtech (včetně hlavičky), * • ‹fd_out1› – první výstupní popisovač, * • ‹fd_out2› – druhý výstupní popisovač. * * Hlavičky záznamů s lichou paritou zapisujte do popisovače * ‹fd_out1›, se sudou paritou pak do popisovače ‹fd_out2›. Parita * je počet jedničkových bitů (celého záznamu, tzn. včetně * hlavičky). * * Návratová hodnota bude: * * • počet zpracovaných záznamů, 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. Délka * záznamu není omezena. Můžete předpokládat, že ‹len ≥ 8›. */ int split( int fd_in, int len, int fd_out1, int fd_out2 ); /* ┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄┄┄┄ 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, int mode ) { unlink_if_exists( name ); int fd; if ( ( fd = openat( AT_FDCWD, name, O_CREAT | O_TRUNC | mode, 0666 ) ) == -1 ) err( 2, "creating %s", name ); return fd; } static int write_file( const char *name, const unsigned char *str, int len, int mode ) { int fd = create_file( name, mode ); if ( write( fd, str, len ) == -1 ) err( 2, "writing file %s", name ); if ( lseek( fd, 0, SEEK_SET ) == ( off_t ) -1 ) err( 2, "lseek on %s", name ); return fd; } static int cmp_output( const char *name, const unsigned char *expected, int size ) { char buffer[ 256 ]; int fd = open( name, O_RDONLY ); if ( fd == -1 ) err( 2, "opening %s", name ); int rv = 0; int out_size = 0; while ( ( rv = read( fd, buffer, sizeof( buffer ) ) ) > 0 ) { if ( out_size + rv > size ) { rv = -1; goto end; } if ( memcmp( expected + out_size, buffer, rv ) != 0 ) { rv = -1; goto end; } out_size += rv; } end: close_or_warn( fd, name ); return out_size != size ? -1 : rv; } int main() { const unsigned char data1[] = { 0x42, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x68, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x69, 0x13, 0x14, 0x15, 0x16, 0x17, 0x16, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x2E, 0x1F }; const unsigned char odd1[] = { 0x08, 0x09, 0x0A, 0x0B, 0x68, 0x0D, 0x0E, 0x0F, 0x16, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x2E, 0x1F }; const unsigned char even1[] = { 0x42, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x69, 0x13, 0x14, 0x15, 0x16, 0x17 }; int fd_in = write_file( "zt.p6_in", data1, sizeof( data1 ), O_RDWR ); int fd_out1 = create_file( "zt.p6_out_odd", O_WRONLY ); int fd_out2 = create_file( "zt.p6_out_even", O_WRONLY ); assert( split( fd_in, 8, fd_out1, fd_out2 ) == 4 ); assert( cmp_output( "zt.p6_out_odd", odd1, sizeof( odd1 ) ) == 0 ); assert( cmp_output( "zt.p6_out_even", even1, sizeof( even1 ) ) == 0 ); close_or_warn( fd_in, "zt.p6_in" ); close_or_warn( fd_out1, "zt.p6_out_odd" ); close_or_warn( fd_out2, "zt.p6_out_even" ); const unsigned char data2[] = { 0x41, 0x6e, 0x64, 0x20, 0x73, 0x6f, 0x20, 0x53, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x77, 0x61, 0x69, 0x74, 0x0a, 0x53, 0x68, 0x65, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x74, 0x6f, 0x6f, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x0a, 0x41, 0x73, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x79, 0x0a, 0x48, 0x65, 0x72, 0x20, 0x73, 0x6f, 0x75, 0x6c, 0x20, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x73, 0x20, 0x61, 0x77, 0x61, 0x79, 0x0a, 0x42, 0x75, 0x74, 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x0a, 0x49, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x73, 0x61, 0x79, 0x0a, 0x44, 0x6f, 0x73, 0x69 }; const unsigned char odd2[] = { 0x72, 0x65, 0x20, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x20, 0x62, 0x79, 0x0a, 0x48, 0x65, 0x72, 0x20, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x61, 0x79, 0x0a, 0x44, 0x6f, 0x73 }; const unsigned char even2[] = { 0x41, 0x6e, 0x64, 0x20, 0x73, 0x6f, 0x20, 0x53, 0x63, 0x61, 0x6e, 0x20, 0x77, 0x61, 0x69, 0x74, 0x6b, 0x6e, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x6f, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x0a, 0x41, 0x75, 0x74, 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x69, 0x6e, 0x72, 0x0a, 0x49, 0x20, 0x68, 0x65, 0x61, 0x72 }; fd_in = write_file( "zt.p6_in", data2, sizeof( data2 ), O_RDWR ); fd_out1 = create_file( "zt.p6_out_odd", O_WRONLY ); fd_out2 = create_file( "zt.p6_out_even", O_WRONLY ); assert( split( fd_in, 13, fd_out1, fd_out2 ) == 11 ); assert( cmp_output( "zt.p6_out_odd", odd2, sizeof( odd2 ) ) == 0 ); assert( cmp_output( "zt.p6_out_even", even2, sizeof( even2 ) ) == 0 ); close_or_warn( fd_in, "zt.p6_in" ); close_or_warn( fd_out1, "zt.p6_out_odd" ); close_or_warn( fd_out2, "zt.p6_out_even" ); unlink_if_exists( "zt.p6_in" ); unlink_if_exists( "zt.p6_out_odd" ); unlink_if_exists( "zt.p6_out_even" ); return 0; }