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