#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 ‹pick›, který bude kopírovat části * záznamů ze zadaného vstupního popisovače na popisovač výstupní. * Parametry budou: * * • ‹fd_in› – vstupní popisovač, * • ‹len› – délka záznamu v bajtech, * • ‹skip› – počet bajtů záznamu, které se mají přeskočit, * • ‹count› – počet bajtů záznamu, které se mají kopírovat, * • ‹fd_out› – výstupní popisovač. * * Návratová hodnota bude: * * • počet záznamů na vstupu, proběhlo-li vše v pořádku, * • ‹-1› v případě selhání čtení nebo jiné systémové chyby. * * Je-li ‹skip + count > len›, nebo je poslední záznam příliš * krátký, nejedná se o chybu – výstupní záznam bude kratší než * ‹count› bajtů. Délka záznamu není omezena. Procedura smí použít * nejvýše konstantní množství paměti. */ int pick( int fd_in, int len, int skip, int count, 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, 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 unsigned char *expected, int len ) { const char *name = "zt.p4_out"; char buffer[ len ]; int fd = open( name, O_RDONLY ); if ( fd == -1 ) err( 2, "opening %s", name ); if ( lseek( fd, -len, SEEK_END ) == -1 ) err( 2, "lseek on %s", name ); int bytes = read( fd, buffer, len ); if ( bytes == -1 ) err( 2, "reading %s", name ); int cmp = len - bytes; if ( cmp == 0 ) cmp = memcmp( expected, buffer, len ); close_or_warn( fd, name ); return cmp; } static void lseek_to_start( int fd, const char *name ) { if ( lseek( fd, 0, SEEK_SET ) == -1 ) err( 2, "lseek on %s", name ); } int main( void ) { const unsigned char data[] = { 0, 1, 2, 3, 4, 5, 6 }, even[] = { 0, 2, 4, 6 }, odd[] = { 1, 3, 5 }; int fd_out; int fd_in = write_file( "zt.p4_in", data, 7, O_RDWR ); fd_out = create_file( "zt.p4_out", O_WRONLY ); assert( pick( fd_in, 1, 0, 1, fd_out ) == 7 ); assert( cmp_output( data, 7 ) == 0 ); close_or_warn( fd_out, "zt.p4_out" ); lseek_to_start( fd_in, "zt.p4_in" ); fd_out = create_file( "zt.p4_out", O_WRONLY ); assert( pick( fd_in, 2, 0, 1, fd_out ) == 4 ); assert( cmp_output( even, sizeof( even ) ) == 0 ); close_or_warn( fd_out, "zt.p4_out" ); lseek_to_start( fd_in, "zt.p4_in" ); fd_out = create_file( "zt.p4_out", O_WRONLY ); assert( pick( fd_in, 2, 1, 1, fd_out ) == 4 ); assert( cmp_output( odd, sizeof( odd ) ) == 0 ); close_or_warn( fd_out, "zt.p4_out" ); lseek_to_start( fd_in, "zt.p4_in" ); close_or_warn( fd_in, "zt.p4_in" ); unlink_if_exists( "zt.p4_in" ); unlink_if_exists( "zt.p4_out" ); return 0; }