P08 lab code added
This commit is contained in:
		
							parent
							
								
									f4c374887c
								
							
						
					
					
						commit
						c7d4ec972e
					
				| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
 | 
			
		||||
 | 
			
		||||
TARGET     := bin/c-get-exec-list
 | 
			
		||||
MODULES    := 
 | 
			
		||||
SOURCES    := src/main.c $(MODULES)
 | 
			
		||||
TSTSOURCES := tests/tests.c $(MODULES)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
include $(SNP_SHARED_MAKEFILE)
 | 
			
		||||
 | 
			
		||||
# CFLAGS  += -Werror
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @mainpage SNP - P08: C implementation of P01-Bash get_exec_list_arg.sh
 | 
			
		||||
 *
 | 
			
		||||
 * @section Purpose
 | 
			
		||||
 *
 | 
			
		||||
 * This is a lab on POSIX file and directory attribute access.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,123 @@
 | 
			
		|||
/* ----------------------------------------------------------------------------
 | 
			
		||||
 * --  _____       ______  _____                                              -
 | 
			
		||||
 * -- |_   _|     |  ____|/ ____|                                             -
 | 
			
		||||
 * --   | |  _ __ | |__  | (___    Institute of Embedded Systems              -
 | 
			
		||||
 * --   | | | '_ \|  __|  \___ \   Zuercher Hochschule Winterthur             -
 | 
			
		||||
 * --  _| |_| | | | |____ ____) |  (University of Applied Sciences)           -
 | 
			
		||||
 * -- |_____|_| |_|______|_____/   8401 Winterthur, Switzerland               -
 | 
			
		||||
 * ----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * @brief Lab implementation
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>   // getenv, malloc, free, EXIT_SUCCESS, NULL
 | 
			
		||||
#include <string.h>   // strchr
 | 
			
		||||
#include <stdio.h>    // printf, sprintf
 | 
			
		||||
#include <sys/stat.h> // struct stat, S_ISDIR, S_ISREG
 | 
			
		||||
#include <unistd.h>   // stat, access
 | 
			
		||||
#include <dirent.h>   // opendir, closedir, readdir, DIR, struct dirent
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief  Creates a copy of the string on the heap.
 | 
			
		||||
 * @param  s [IN]  The original string.
 | 
			
		||||
 * @return Returns the allocated copy or NULL if s is NULL or if malloc failed.
 | 
			
		||||
 * @remark Suggestion: Use the functions malloc(), strcpy().
 | 
			
		||||
 */
 | 
			
		||||
static char *malloc_copy(const char *s)
 | 
			
		||||
{
 | 
			
		||||
    char *p = NULL;
 | 
			
		||||
    // BEGIN-STUDENTS-TO-ADD-CODE
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // END-STUDENTS-TO-ADD-CODE
 | 
			
		||||
    return p;       
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief  Replaces inplace in the buffer all occurances of sep by '\0'.
 | 
			
		||||
 * @param  buffer [INOUT] The string which gets searched and modified.
 | 
			
		||||
 * @param  sep    [IN]    The separator for which all instances in buffer get replaced by '\0'.
 | 
			
		||||
 * @return Returns the number of fields which are separated by sep, or 0 if buffer is NULL.
 | 
			
		||||
 * @remark Empty fields are allowed and to be supported, i.e. given by ":..." or by "...::..." or by "...:".
 | 
			
		||||
 * @remark Suggestion: Use the function strchr() to search for the separator.
 | 
			
		||||
 */
 | 
			
		||||
static size_t split_buffer_inplace(char buffer[], char sep)
 | 
			
		||||
{
 | 
			
		||||
    size_t n = 0;
 | 
			
		||||
    // BEGIN-STUDENTS-TO-ADD-CODE
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // END-STUDENTS-TO-ADD-CODE
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief  If path is an executable directory, list all executable files located directly in that directory - each such file as i:path:file.
 | 
			
		||||
 * @param  i [IN]    The number of the path to report.
 | 
			
		||||
 * @param  path [IN] The directory path to search for executables.
 | 
			
		||||
 * @remark Suggestion: Use the function is_accessible_dir(), is_executable_file(), opendir(), readdir(), closedir().
 | 
			
		||||
 */
 | 
			
		||||
static void list_executables(size_t i, const char *path)
 | 
			
		||||
{
 | 
			
		||||
    // bash:
 | 
			
		||||
    //   [ -n "$p" ] || p="."
 | 
			
		||||
    //   if [ -d "$p" ] && [ -x "$p" ]
 | 
			
		||||
    //   then
 | 
			
		||||
    //      find -L "$p" -maxdepth 1 -type f -executable -printf "$i:%h:%f\n"
 | 
			
		||||
    //   fi
 | 
			
		||||
    const char *p = path && strlen(path) ? path : "."; // replace an empty path by "." as current directory to allow for appending /name
 | 
			
		||||
    // BEGIN-STUDENTS-TO-ADD-CODE
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // END-STUDENTS-TO-ADD-CODE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// # from lab P01_Bash
 | 
			
		||||
// paths="$1"
 | 
			
		||||
// [ -n "$paths" ] || paths="$PATH"
 | 
			
		||||
// 
 | 
			
		||||
// # input-field-separator: tells the shell to split in the 'for' loop the $var by ":"
 | 
			
		||||
// IFS=":"
 | 
			
		||||
// 
 | 
			
		||||
// for p in $paths
 | 
			
		||||
// do
 | 
			
		||||
//   i=$((i+1))
 | 
			
		||||
//   [ -n "$p" ] || p="."
 | 
			
		||||
//   if [ -d "$p" ] && [ -x "$p" ]
 | 
			
		||||
//   then
 | 
			
		||||
//      find -L "$p" -maxdepth 1 -type f -executable -printf "$i:%h:%f\n" 2>/dev/null
 | 
			
		||||
//   fi
 | 
			
		||||
// done
 | 
			
		||||
 | 
			
		||||
int main(int argc, const char *argv[])
 | 
			
		||||
{
 | 
			
		||||
    char *paths = malloc_copy(argc > 1 && argv[1][0] ? argv[1] : getenv("PATH"));
 | 
			
		||||
    size_t n = split_buffer_inplace(paths, ':'); // replaces all ':' by '\0' and returns the number of the resulting fields
 | 
			
		||||
    char *p = paths;
 | 
			
		||||
    for(size_t i = 1; i <= n; i++) { // 1...n
 | 
			
		||||
        list_executables(i, p);
 | 
			
		||||
        p += strlen(p) + 1; // readover the field and the trailing '\0' to get to the next field
 | 
			
		||||
    }
 | 
			
		||||
    free(paths);
 | 
			
		||||
    return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
/* ----------------------------------------------------------------------------
 | 
			
		||||
 * --  _____       ______  _____                                              -
 | 
			
		||||
 * -- |_   _|     |  ____|/ ____|                                             -
 | 
			
		||||
 * --   | |  _ __ | |__  | (___    Institute of Embedded Systems              -
 | 
			
		||||
 * --   | | | '_ \|  __|  \___ \   Zuercher Hochschule Winterthur             -
 | 
			
		||||
 * --  _| |_| | | | |____ ____) |  (University of Applied Sciences)           -
 | 
			
		||||
 * -- |_____|_| |_|______|_____/   8401 Winterthur, Switzerland               -
 | 
			
		||||
 * ----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * @brief Test suite for the given package.
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <CUnit/Basic.h>
 | 
			
		||||
#include "test_utils.h"
 | 
			
		||||
 | 
			
		||||
#ifndef TARGET // must be given by the make file --> see test target
 | 
			
		||||
#error missing TARGET define
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/// @brief alias for EXIT_SUCCESS
 | 
			
		||||
#define OK   EXIT_SUCCESS
 | 
			
		||||
/// @brief alias for EXIT_FAILURE
 | 
			
		||||
#define FAIL EXIT_FAILURE
 | 
			
		||||
 | 
			
		||||
/// @brief The name of the STDOUT text file.
 | 
			
		||||
#define OUTFILE "stdout.txt"
 | 
			
		||||
/// @brief The name of the STDERR text file.
 | 
			
		||||
#define ERRFILE "stderr.txt"
 | 
			
		||||
 | 
			
		||||
#define TRACE_INDENT "\n                " ///< allow for better stdout formatting in case of error
 | 
			
		||||
 | 
			
		||||
#define PATH_SIZE 256
 | 
			
		||||
 | 
			
		||||
// setup & cleanup
 | 
			
		||||
static int setup(void)
 | 
			
		||||
{
 | 
			
		||||
    remove_file_if_exists(OUTFILE);
 | 
			
		||||
    remove_file_if_exists(ERRFILE);
 | 
			
		||||
    return 0; // success
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int teardown(void)
 | 
			
		||||
{
 | 
			
		||||
    // Do nothing.
 | 
			
		||||
    // Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
 | 
			
		||||
    return 0; // success
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tests
 | 
			
		||||
static void test_paths(void)
 | 
			
		||||
{
 | 
			
		||||
    // arrange
 | 
			
		||||
    const char *name = strrchr(XSTR(TARGET), '/');
 | 
			
		||||
    name = name ? name+1 : XSTR(TARGET);
 | 
			
		||||
 | 
			
		||||
    char buf[PATH_SIZE] = { 0 };
 | 
			
		||||
    snprintf(buf, PATH_SIZE, "4:../bin:%s\n", name);
 | 
			
		||||
    
 | 
			
		||||
    const char *out_txt[] =
 | 
			
		||||
        { "1:.:runtest\n"
 | 
			
		||||
          , buf
 | 
			
		||||
        };
 | 
			
		||||
    const char *err_txt[] = { NULL };
 | 
			
		||||
    // act
 | 
			
		||||
    int exit_code = system(XSTR(TARGET) " .::..:../bin 1>" OUTFILE " 2>" ERRFILE);
 | 
			
		||||
    // assert
 | 
			
		||||
    CU_ASSERT_EQUAL(WEXITSTATUS(exit_code), EXIT_SUCCESS);
 | 
			
		||||
    assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
 | 
			
		||||
    assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Registers and runs the tests.
 | 
			
		||||
 * @returns success (0) or one of the CU_ErrorCode (>0)
 | 
			
		||||
 */
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
    // setup, run, teardown
 | 
			
		||||
    TestMainBasic("lab test", setup, teardown
 | 
			
		||||
                  , test_paths
 | 
			
		||||
                  );
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue