├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── cmake ├── BundleIcon.icns ├── CTestConfig.cmake ├── Config.cmake.in ├── CustomVolumeIcon.icns ├── Info.plist ├── MultiCPackConfig.cmake ├── README.txt ├── Welcome.txt └── config.h.in ├── img ├── .code └── demo.png ├── main.c ├── requirements.txt └── src ├── CMakeLists.txt ├── example └── CMakeLists.txt ├── internal ├── error.c └── error.h ├── prettyerr_export.h └── termcolor └── CMakeLists.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.a 4 | demo 5 | .DS_Store 6 | debug/main.dSYM/Contents/Info.plist 7 | debug/main.dSYM/Contents/Resources/DWARF/main 8 | main.E 9 | debug/main 10 | *_export.h 11 | .idea 12 | *build* 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(prettyerr VERSION 0.0.1 LANGUAGES C) 3 | 4 | set(CMAKE_C_STANDARD 90) 5 | cmake_policy(SET CMP0063 NEW) 6 | set(CMAKE_C_VISIBILITY_PRESET hidden) 7 | set(CMAKE_VISIBILITY_INLINES_HIDDEN YES) 8 | 9 | option(BUILD_SHARED_LIBS "Build using shared libraries" OFF) 10 | if (BUILD_SHARED_LIBS) 11 | set(LIBRARY_TYPE_FLAG "SHARED") 12 | else () 13 | set(LIBRARY_TYPE_FLAG "STATIC") 14 | endif () 15 | 16 | # control where the static and shared libraries are built so that on windows 17 | # we don't need to tinker with the path to run the executable 18 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") 19 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") 20 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") 21 | 22 | add_library("${PROJECT_NAME}_compiler_flags" INTERFACE) 23 | target_compile_features("${PROJECT_NAME}_compiler_flags" INTERFACE "c_std_${CMAKE_C_STANDARD}") 24 | 25 | set(gcc_like "$") 26 | set(msvc "$") 27 | # -g -fsanitize=address -fno-omit-frame-pointer 28 | target_compile_options( 29 | "${PROJECT_NAME}_compiler_flags" 30 | INTERFACE 31 | "$<${gcc_like}:$>" 32 | "$<${msvc}:$>" 33 | ) 34 | if (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang") 35 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") 36 | set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") 37 | endif() 38 | 39 | # configure a header file to pass the version number only 40 | configure_file( 41 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in" 42 | "${PROJECT_NAME}Config.h" 43 | ) 44 | 45 | add_subdirectory("src") 46 | 47 | install( 48 | FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.h" 49 | DESTINATION "include" 50 | ) 51 | 52 | include(InstallRequiredSystemLibraries) 53 | set(CPACK_BUNDLE_NAME "${PROJECT_NAME}") 54 | set(CPACK_PACKAGE_VENDOR "Vasiliy Tereshkov") 55 | set(CPACK_PACKAGE_DESCRIPTION "A C library for displaying informative, clean and readable errors") 56 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A C library for displaying informative, clean and readable errors") 57 | if (APPLE) 58 | set(CPACK_BUNDLE_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Info.plist") 59 | set(CPACK_BUNDLE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Info.plist") 60 | set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CustomVolumeIcon.icns") 61 | endif() 62 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License") 63 | set(CPACK_PACKAGE_VERSION_MAJOR "${${PROJECT_NAME}_VERSION_MAJOR}") 64 | set(CPACK_PACKAGE_VERSION_MINOR "${${PROJECT_NAME}_VERSION_MINOR}") 65 | set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/cmake/README.txt") 66 | set(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Welcome.txt") 67 | set(CPACK_PACKAGE_CONTACT "https://github.com/fennecdjay/lib${PROJECT_NAME}") 68 | 69 | include(CPack) 70 | include(CMakePackageConfigHelpers) 71 | 72 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON) 73 | if (BUILD_SHARED_LIBS) 74 | set(LIBRARY_TYPE_FLAG "SHARED") 75 | else () 76 | set(LIBRARY_TYPE_FLAG "STATIC") 77 | endif () 78 | 79 | option(BUILD_EXAMPLE "Build example" ON) 80 | if (BUILD_EXAMPLE) 81 | add_subdirectory("src/example") 82 | endif (BUILD_EXAMPLE) 83 | 84 | # generate the config file that is includes the exports 85 | configure_package_config_file( 86 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in" 87 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 88 | INSTALL_DESTINATION "lib/cmake/example" 89 | NO_SET_AND_CHECK_MACRO 90 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 91 | ) 92 | 93 | # generate the version file for the config file 94 | write_basic_package_version_file( 95 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" 96 | VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}" 97 | COMPATIBILITY AnyNewerVersion 98 | ) 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS += -Isrc -fPIC 2 | WARNINGS += -Wall -Wextra 3 | PREFIX ?= /usr/local 4 | 5 | #SRC := $(shell find src -type f -name '*.c') 6 | SRC := src/internal/error.c 7 | OBJ := ${SRC:.c=.o} 8 | PRG := libprettyerr 9 | 10 | ifeq ($(shell uname), Darwin) 11 | AR = /usr/bin/libtool 12 | AR_OPT = -static $^ -o $@ 13 | else 14 | AR = ar 15 | AR_OPT = rcs $@ $^ 16 | endif 17 | 18 | CFLAGS += ${WARNINGS} 19 | 20 | all: static dynamic demo 21 | 22 | .PHONY: static dynamic 23 | static: ${PRG}.a 24 | dynamic: ${PRG}.so 25 | 26 | ${PRG}.a: ${OBJ} 27 | $(info building $@ ${OBJ}) 28 | ${AR} ${AR_OPT} 29 | 30 | ${PRG}.so: ${OBJ} 31 | $(info building $@) 32 | ${CC} -shared $< -o $@ ${LDFLAGS} 33 | 34 | demo: ${PRG}.a 35 | ${CC} main.c ${CFLAGS} $< -o $@ ${LDFLAGS} 36 | 37 | .c.o: 38 | ${CC} ${CFLAGS} $< -c -o ${<:.c=.o} 39 | 40 | clean: 41 | rm -rf ${PRG}.a ${PRG}.so ${OBJ} 42 | 43 | install: ${PRG}.a ${PRG}.so 44 | cp ${PRG}.a ${PRG}.so ${PREFIX}/lib 45 | mkdir -p /usr/local/include/${PRG} 46 | cp src/prettyerr.h ${PREFIX}/include/${PRG} 47 | 48 | uninstall: 49 | rm ${PREFIX}/lib/${PRG}.a ${PREFIX/lib/${PRG}.so 50 | rm ${PREFIX}/include/${PRG}/termcolor.h 51 | rmdir /usr/local/include/${PRG} 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | (archiving, the lib was moved to [gwion-util](https://github.com/Gwion/gwion-util) 2 | 3 | # libprettyerr 4 | 5 | A C library for displaying informative, clean and readable errors 6 | 7 | `libprettyerr` provides a simple api to nicely display error messages 8 | for your programming language. 9 | 10 | Backed by [libtermcolor](https://github.com/euppal/libtermcolor), 11 | it allows for displaying colored messages within the error. 12 | 13 | ![](img/demo.png) 14 | 15 | is generated by this [example file](main.c) 16 | 17 | 18 | ## Using prettyerr in your project 19 | 20 | Add the repo as a submodule and build it 21 | 22 | ```sh 23 | git submodule add https://github.com/fennecdjay/libprettyerr 24 | cd libprettyerr 25 | make 26 | ``` 27 | 28 | Add `-Ilibprettyerr/src` to your project's `CFLAGS` 29 | And `-Llibprettyerr -l prettyerr` to your project's `LDFLAGS` 30 | 31 | You can then start using libprettyerr. 32 | 33 | > If you're unsure about usage, look at the [example file](main.c) 34 | -------------------------------------------------------------------------------- /cmake/BundleIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fennecdjay/libprettyerr/840de36d8aa3eeb35cda60b33bfda053f0153fdb/cmake/BundleIcon.icns -------------------------------------------------------------------------------- /cmake/CTestConfig.cmake: -------------------------------------------------------------------------------- 1 | set(CTEST_PROJECT_NAME "libprettyerr") 2 | set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") 3 | 4 | set(CTEST_DROP_METHOD "http") 5 | set(CTEST_DROP_SITE "my.cdash.org") 6 | set(CTEST_DROP_LOCATION "/submit.php?project=libprettyerr") 7 | set(CTEST_DROP_SITE_CDASH TRUE) 8 | -------------------------------------------------------------------------------- /cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | 2 | @PACKAGE_INIT@ 3 | 4 | include ( "${CMAKE_CURRENT_LIST_DIR}/prettyerrTargets.cmake" ) 5 | -------------------------------------------------------------------------------- /cmake/CustomVolumeIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fennecdjay/libprettyerr/840de36d8aa3eeb35cda60b33bfda053f0153fdb/cmake/CustomVolumeIcon.icns -------------------------------------------------------------------------------- /cmake/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | BundleGeneratorTest 7 | CFBundleIconFile 8 | BundleGeneratorTest.icns 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | APPL 13 | 14 | 15 | -------------------------------------------------------------------------------- /cmake/MultiCPackConfig.cmake: -------------------------------------------------------------------------------- 1 | include("release/CPackConfig.cmake") 2 | 3 | set(CPACK_INSTALL_CMAKE_PROJECTS 4 | "debug;libprettyerr;ALL;/" 5 | "release;libprettyerr;ALL;/" 6 | ) 7 | -------------------------------------------------------------------------------- /cmake/README.txt: -------------------------------------------------------------------------------- 1 | A C library for displaying informative, clean and readable errors 2 | -------------------------------------------------------------------------------- /cmake/Welcome.txt: -------------------------------------------------------------------------------- 1 | A C library for displaying informative, clean and readable errors 2 | 3 | `libprettyerr` provides a simple api to nicely display error messages for your programming language. 4 | 5 | https://github.com/fennecdjay/libprettyerr 6 | -------------------------------------------------------------------------------- /cmake/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef PRETTYERR_CONFIG_H 2 | #define PRETTYERR_CONFIG_H 3 | 4 | #define PRETTYERR_VERSION_MAJOR @prettyerr_VERSION_MAJOR@ 5 | #define PRETTYERR_VERSION_MINOR @prettyerr_VERSION_MINOR@ 6 | #define PRETTYERR_VERSION_PATCH @prettyerr_VERSION_PATCH@ 7 | #define PRETTYERR_VERSION "@prettyerr_VERSION@" 8 | 9 | #endif /* PRETTYERR_CONFIG_H */ 10 | -------------------------------------------------------------------------------- /img/.code: -------------------------------------------------------------------------------- 1 | Name: libprettyerr 2 | Build: debug 3 | -------------------------------------------------------------------------------- /img/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fennecdjay/libprettyerr/840de36d8aa3eeb35cda60b33bfda053f0153fdb/img/demo.png -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "prettyerr.h" 2 | #include 3 | 4 | #ifdef __attribute__ 5 | #undef __attribute__ 6 | #endif 7 | #ifndef __GNUC__ 8 | #define __attribute__(...) /* nothing */ 9 | #endif 10 | 11 | #define NUSED __attribute__((unused)) 12 | 13 | #define FILENAME "faux.gw" 14 | #define _ERROR_CODE 42 15 | #define ERROR_CODE "E0042" 16 | 17 | const char src[] = "int main() {\n 42 => const int owo;\n 12 => owo;\n}"; 18 | 19 | int main(int argc NUSED, const char *argv[] NUSED) { 20 | // Initialize the error printer 21 | perr_printer_t printer; 22 | perr_printer_init(&printer, stderr /* our stream is standard error */, 23 | src /* source code */, true /* use utf8 */, 24 | perr_runner_basic_style /* basic style*/ 25 | ); 26 | 27 | /* uncomment this to get rounded corners */ 28 | // printer.rounded = true; 29 | 30 | // Create a faux error 31 | const perr_t err = PERR_Error( 32 | PERR_ERROR /* error */, PERR_Str(3, src + 25) /* location of error */, 33 | PERR_Pos(40, 2) /* occurs at src[40] through src[41] */, 34 | "Invalid assignement" /* main error message */, 35 | "`{+/}owo{0}` is immutable" /* example explanatory error message */, 36 | "Take a reference to `{+/}owo{0}{-}` and mutate that 😄" /* fix message */, 37 | _ERROR_CODE, /* error code */ 38 | FILENAME /* filename */ 39 | ); 40 | 41 | // Create a faux "secondary-style" error 42 | const perr_t sec = PERR_Secondary( 43 | PERR_WARNING /* error */, PERR_Str(2, src + 15) /* location of error */, 44 | PERR_Pos(21, 5) /* occurs at src[21] through src[25] */, 45 | "`{+/}owo{0}` declared `{+/}const{0}` here" /* main error message */, 46 | "See {/+}https:/gwion.github.io/errors/" ERROR_CODE 47 | "{0}{-} for more information on this error, " 48 | " or use `{+/}gwion --explain=" ERROR_CODE "{0}`", 49 | FILENAME /* filename */ 50 | ); 51 | 52 | // Display our error 53 | perr_print_error(&printer, &err); 54 | printer.runner = perr_runner_secondary_style; 55 | perr_print_error(&printer, &sec); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | git+git://github.com/euppal/libtermcolor 2 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LIBRARY_NAME "${PROJECT_NAME}") 2 | 3 | # TODO: Remove once PR is merged to libtermcolor 4 | add_subdirectory("termcolor") 5 | 6 | set(Header_Files "internal/error.h" "prettyerr.h") 7 | source_group("Header Files" FILES "${Header_Files}") 8 | 9 | set(Source_Files "internal/error.c") 10 | source_group("Source Files" FILES "${Source_Files}") 11 | 12 | add_library("${LIBRARY_NAME}" "${LIBRARY_TYPE_FLAG}" "${Header_Files}" "${Source_Files}") 13 | 14 | target_include_directories( 15 | "${LIBRARY_NAME}" 16 | PUBLIC 17 | "$" 18 | "$" 19 | "$" 20 | ) 21 | target_link_libraries("${LIBRARY_NAME}" PUBLIC "termcolor") 22 | set_target_properties( 23 | "${LIBRARY_NAME}" 24 | PROPERTIES 25 | LINKER_LANGUAGE 26 | C 27 | ) 28 | 29 | # Symbol exporter 30 | include(GenerateExportHeader) 31 | set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/${LIBRARY_NAME}_export.h") 32 | generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}") 33 | 34 | ################# 35 | # install rules # 36 | ################# 37 | 38 | # setup the version numbering 39 | set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") 40 | set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") 41 | 42 | set(installable_libs "${LIBRARY_NAME}" "${PROJECT_NAME}_compiler_flags") 43 | install(FILES "${Header_Files}" "${_export_file}" DESTINATION "include") 44 | 45 | if (TARGET "${DEPENDANT_LIBRARY}") 46 | list(APPEND installable_libs "${DEPENDANT_LIBRARY}") 47 | endif () 48 | install(TARGETS ${installable_libs} 49 | DESTINATION "lib" 50 | EXPORT "${LIBRARY_NAME}Targets") 51 | -------------------------------------------------------------------------------- /src/example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(EXEC_NAME "${PROJECT_NAME}_c") 2 | 3 | set(Source_Files "../../main.c") 4 | source_group("Source Files" FILES "${Source_Files}") 5 | 6 | add_executable("${EXEC_NAME}" "${Source_Files}") 7 | 8 | target_link_libraries("${EXEC_NAME}" PRIVATE "${PROJECT_NAME}") 9 | 10 | set_target_properties( 11 | "${EXEC_NAME}" 12 | PROPERTIES 13 | LINKER_LANGUAGE 14 | C 15 | ) 16 | 17 | ################# 18 | # install rules # 19 | ################# 20 | 21 | set(installable_libs "${EXEC_NAME}" "${PROJECT_NAME}_compiler_flags") 22 | 23 | if (TARGET "${DEPENDANT_LIBRARY}") 24 | list(APPEND installable_libs "${DEPENDANT_LIBRARY}") 25 | endif () 26 | install(TARGETS ${installable_libs} 27 | DESTINATION "bin" 28 | EXPORT "${EXEC_NAME}Targets") 29 | -------------------------------------------------------------------------------- /src/internal/error.c: -------------------------------------------------------------------------------- 1 | // libprettyerr: error.c 2 | // Copyright (C) 2021 Ethan Uppal 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include "prettyerr_export.h" 23 | 24 | // Used to declare isatty if on Unix 25 | #if defined(__unix__) || defined(__unix) || \ 26 | (defined(__APPLE__) && defined(__MACH__)) 27 | #include 28 | #endif 29 | 30 | #define _PRINTF(...) tcol_fprintf(printer->stream, __VA_ARGS__) 31 | #define _PUTCHR(...) fputc(__VA_ARGS__, printer->stream) 32 | 33 | static char const _tcol_lookup[5] = {'G', 'R', 'M', 'W', 'Y'}; 34 | 35 | static char const *_ascii_box_lookup[8] = {"|", "|", "+", "-", "+", "|"}; 36 | // static char const* _utf8_box_lookup[8] = { "┃", "╵", "┌", "─", "└", "│"}; 37 | static char const *_utf8_box_lookup[8] = {"┃", "╵", "┌", "╭", 38 | "─", "└", "╰", "│"}; 39 | 40 | static const char *_errtype_lookup[5] = {"succes", "error", "warning", "info", 41 | "note"}; 42 | 43 | void perr_printer_init(perr_printer_t *printer, FILE *stream, 44 | const char *source, bool utf8, perr_runner_t style) { 45 | printer->source = source; 46 | printer->stream = stream; 47 | 48 | // Enables ANSI colors only in Unix terminals. False by default on Windows. 49 | #if defined(__unix__) || defined(__unix) || \ 50 | (defined(__APPLE__) && defined(__MACH__)) 51 | const int fd = fileno(stream); 52 | // if (fd < 0) { 53 | // perror("fileno"); 54 | // } 55 | printer->color = isatty(fd); 56 | #else 57 | printer->color = false; 58 | #endif 59 | 60 | if ((printer->utf8 = utf8)) { 61 | printer->box_lookup = _utf8_box_lookup; 62 | } else { 63 | printer->box_lookup = _ascii_box_lookup; 64 | } 65 | printer->runner = style; 66 | } 67 | 68 | static void perr_print_column(const perr_printer_t *printer, const char *color, 69 | const size_t column) { 70 | _PRINTF(" %s%s{0} %*s", color, printer->box_lookup[PERR_BOX_THICK_VERT], 71 | (int)column, ""); 72 | } 73 | 74 | static inline void _perr_print_filename(const perr_printer_t *printer, 75 | const perr_t * err, 76 | const size_t column) { 77 | _PRINTF("{0}{+}%s{0}:%zu:%zu: ", err->filename, err->primary.line, column); 78 | } 79 | 80 | static void _perr_print_error(const perr_printer_t *printer, const perr_t *err, 81 | const char *color) { 82 | _PRINTF("%s%s", color, _errtype_lookup[err->type]); 83 | if (err->error_code) 84 | _PRINTF("[%c%04d]", toupper(_errtype_lookup[err->type][0]), 85 | err->error_code); 86 | _PRINTF("{0}: "); 87 | } 88 | 89 | // Print the line number and a | to denote the start of the line. 90 | void perr_print_line_number(const perr_printer_t *printer, const perr_t *err, 91 | const char *color) { 92 | _PRINTF("{-}%5zu{0} %s%s{0} ", err->primary.line, color, 93 | printer->box_lookup[PERR_BOX_THICK_VERT]); 94 | } 95 | 96 | // Print the line. 97 | static void _perr_print_offending_line(const perr_printer_t *printer, 98 | const perr_t * err, 99 | const char * error_line, 100 | const char *color, const size_t column) { 101 | _PRINTF("%.*s", (int)column, error_line); 102 | const char *bug = error_line + column; 103 | _PRINTF("%s{-}%.*s{0}", color, (int)err->error_position.length, bug); 104 | const char *end = bug + err->error_position.length; 105 | char * nl = strstr(end, "\n"); 106 | ptrdiff_t nl_index = nl ? nl - end : (ptrdiff_t)strlen(end) - 1; 107 | _PRINTF("%.*s\n", (int)nl_index, end); 108 | } 109 | 110 | // Print a series of '^' showing where the error occurs. 111 | static inline void _perr_print_highlight_error(const perr_printer_t *printer, 112 | const perr_t * err, 113 | const char * error_line, 114 | const char * color, 115 | const size_t column, 116 | const bool small) { 117 | perr_print_column(printer, color, 0); 118 | char* line = (char*)error_line; 119 | size_t i = 0; 120 | while(i < column) { 121 | if(*line =='\t') _PRINTF("\t"); 122 | else _PRINTF(" "); 123 | i++; 124 | line++; 125 | } 126 | const enum libprettyerr_boxtype type = 127 | (!small ? PERR_BOX_THIN_UL : PERR_BOX_THIN_BL) + printer->rounded; 128 | if (err->error_position.length > 1) { 129 | _PRINTF("%s{-}%s", color, printer->box_lookup[type]); 130 | { 131 | size_t i; 132 | for (i = 1; i < err->error_position.length; i++) { 133 | _PRINTF(printer->box_lookup[PERR_BOX_THIN_HORIZ]); 134 | } 135 | } 136 | } else 137 | _PRINTF("%s{-}%s", color, printer->box_lookup[PERR_BOX_THIN_VERT]); 138 | _PRINTF("{0}\n"); 139 | } 140 | 141 | // Print the fix, dimmed 142 | static inline void _perr_print_fix(const perr_printer_t *printer, 143 | const char * fix) { 144 | _PRINTF("{-}"); 145 | _PRINTF(fix); 146 | _PRINTF("{0}\n"); 147 | } 148 | 149 | static void lookup_color(char *color, enum libprettyerr_errtype type) { 150 | char _color[16]; 151 | sprintf(_color, "+%c", _tcol_lookup[type]); 152 | size_t len; 153 | const int status = tcol_color_parse(color, 16, _color, 2, &len); 154 | if (status != TermColorErrorNone) { 155 | color[0] = 0; 156 | // error 157 | } else 158 | color[len] = 0; 159 | } 160 | 161 | static inline void perr_print_basic_style(const perr_printer_t *printer, 162 | const perr_t * err) { 163 | // Normal errors: 164 | // 165 | // $filename:$line:$col: $type: $msg 166 | // $line | 167 | // | ^^^^ 168 | 169 | // Here we scan backwards until we reach the start of the line (or the 170 | // start of the source code). This allows us to retrieve the line that has 171 | // the error. 172 | size_t idx_cpy = err->error_position.index; 173 | while (idx_cpy > 0 && printer->source[idx_cpy - 1] != '\n') { idx_cpy--; } 174 | const char *error_line = (printer->source + idx_cpy); 175 | error_line += (printer->source[idx_cpy] == '\n') ? 1 : 0; 176 | 177 | // The column is how far the error's index is from the start-of-line's 178 | // index. 179 | const size_t column = err->error_position.index - idx_cpy; 180 | 181 | char color[17]; 182 | lookup_color(color, err->type); 183 | 184 | // Here we print the first row of the error message which provides general 185 | // information such as filename, line, column, error type and a message. 186 | _perr_print_filename(printer, err, column); 187 | _perr_print_error(printer, err, color); 188 | _PRINTF(err->main); 189 | _PUTCHR('\n'); 190 | 191 | perr_print_line_number(printer, err, color); 192 | _perr_print_offending_line(printer, err, error_line, color, column); 193 | _perr_print_highlight_error(printer, err, error_line, color, column, !err->explain); 194 | 195 | // Adds a subsidiary error note, if applicable 196 | if (err->explain) { 197 | perr_print_column(printer, color, column); 198 | _PRINTF("{-}%s%s{0}\n", color, printer->box_lookup[PERR_BOX_THIN_HIGH]); 199 | perr_print_column(printer, color, column); 200 | _PRINTF(err->explain); 201 | _PUTCHR('\n'); 202 | } 203 | 204 | // Displays a fix, if applicable. 205 | if (err->fix) { _perr_print_fix(printer, err->fix); } 206 | } 207 | 208 | /* 209 | static inline void perr_print_complex(const perr_printer_t* printer, 210 | const perr_t* err) { 211 | // IDK COPY BRENDANZAB (DONT) 212 | } 213 | */ 214 | 215 | static inline void perr_print_secondary_style(const perr_printer_t *printer, 216 | const perr_t * err) { 217 | size_t idx_cpy = err->error_position.index; 218 | while (idx_cpy > 0 && printer->source[idx_cpy - 1] != '\n') { idx_cpy--; } 219 | const char *error_line = (printer->source + idx_cpy); 220 | error_line += (printer->source[idx_cpy] == '\n') ? 1 : 0; 221 | 222 | // The column is how far the error's index is from the start-of-line's 223 | // index. 224 | const size_t column = err->error_position.index - idx_cpy; 225 | 226 | char color[17]; 227 | lookup_color(color, err->type); 228 | 229 | _perr_print_filename(printer, err, column); 230 | _PUTCHR('\n'); 231 | 232 | perr_print_line_number(printer, err, color); 233 | _perr_print_offending_line(printer, err, error_line, color, column); 234 | _perr_print_highlight_error(printer, err, error_line, color, column, false); 235 | 236 | perr_print_column(printer, color, column); 237 | _PRINTF("{-}%s%s%.*s{0} ", color, 238 | printer->box_lookup[PERR_BOX_THIN_BL + printer->rounded], 3, 239 | printer->box_lookup[PERR_BOX_THIN_HORIZ]); 240 | _PRINTF(err->main); 241 | _PUTCHR('\n'); 242 | // Displays a fix, if applicable. 243 | if (err->fix) { _perr_print_fix(printer, err->fix); } 244 | } 245 | 246 | void perr_print_error(const perr_printer_t *printer, const perr_t *err) { 247 | printer->runner(printer, err); 248 | } 249 | 250 | perr_runner_t perr_runner_basic_style = perr_print_basic_style; 251 | perr_runner_t perr_runner_secondary_style = perr_print_secondary_style; 252 | -------------------------------------------------------------------------------- /src/internal/error.h: -------------------------------------------------------------------------------- 1 | // libprettyerr: error.h 2 | // Copyright (C) 2021 Ethan Uppal 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #ifndef _LIBPRETTYERR_ERROR_H 18 | #define _LIBPRETTYERR_ERROR_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "prettyerr_export.h" 25 | 26 | struct libprettyerr_str { 27 | size_t line; 28 | const char* start; 29 | }; 30 | 31 | #define PERR_Str(line_, start_) \ 32 | (struct libprettyerr_str){ .line = line_, .start = start_ } 33 | #define PERR_Str_None() \ 34 | PERR_Str(0, NULL) 35 | 36 | struct libprettyerr_pos { 37 | size_t index; 38 | size_t length; 39 | }; 40 | 41 | #define PERR_Pos(index_, length_) \ 42 | (struct libprettyerr_pos){ .index = index_, .length = length_ } 43 | 44 | enum libprettyerr_errtype { 45 | PERR_SUCCESS, // bold green 46 | PERR_ERROR, // bold red 47 | PERR_WARNING, // red 48 | PERR_INFO, // bold white 49 | PERR_NOTE // bold yellow 50 | }; 51 | 52 | enum libprettyerr_boxtype { 53 | PERR_BOX_THICK_VERT, 54 | PERR_BOX_THIN_HIGH, 55 | PERR_BOX_THIN_UL, 56 | PERR_BOX_THIN_UL_ROUNDED, 57 | PERR_BOX_THIN_HORIZ, 58 | PERR_BOX_THIN_BL, 59 | PERR_BOX_THIN_BL_ROUNDED, 60 | PERR_BOX_THIN_VERT, 61 | PERR_BOX_MAX, 62 | }; 63 | 64 | struct libprettyerr_error { 65 | enum libprettyerr_errtype type; 66 | 67 | struct libprettyerr_str primary; 68 | struct libprettyerr_pos error_position; 69 | 70 | const char* main; 71 | const char* explain; 72 | const char* fix; 73 | short error_code; 74 | 75 | const char* filename; 76 | }; 77 | 78 | #define PERR_Error(type_, primary_, error_position_, main_, explain_, fix_, error_code_, filename_) \ 79 | (struct libprettyerr_error){ \ 80 | .type = type_, .primary = primary_, .error_position = error_position_, \ 81 | .main = main_, .explain = explain_, .fix = fix_, .error_code = error_code_, \ 82 | .filename = filename_ \ 83 | } 84 | 85 | #define PERR_Secondary(type_, primary_, error_position_, main_, fix_, filename_) \ 86 | (struct libprettyerr_error){ \ 87 | .type = type_, .primary = primary_, .error_position = error_position_, \ 88 | .main = main_, .fix=fix_, .filename = filename_ \ 89 | } 90 | 91 | struct libprettyerr_printer; 92 | typedef void (*libprettyerr_runner_t)(const struct libprettyerr_printer*, const struct libprettyerr_error*); 93 | struct libprettyerr_printer { 94 | const char* source; 95 | FILE* stream; 96 | const char** box_lookup; 97 | libprettyerr_runner_t runner; 98 | bool color; 99 | bool utf8; 100 | bool rounded; 101 | }; 102 | 103 | #define PRETTYERR_EXPORT 104 | 105 | // Initializes a printer 106 | PRETTYERR_EXPORT 107 | void perr_printer_init(struct libprettyerr_printer* printer, FILE* stream, 108 | const char* source, bool utf8, libprettyerr_runner_t style); 109 | 110 | // Uses the printer to display the provided error in 111 | PRETTYERR_EXPORT 112 | void perr_print_error(const struct libprettyerr_printer* printer, 113 | const struct libprettyerr_error* err); 114 | 115 | // prints source filename and position 116 | PRETTYERR_EXPORT 117 | void perr_print_line_number(const struct libprettyerr_printer* printer, 118 | const struct libprettyerr_error* err, 119 | const char *color); 120 | #endif /* _LIBPRETTYERR_ERROR_H */ 121 | -------------------------------------------------------------------------------- /src/prettyerr_export.h: -------------------------------------------------------------------------------- 1 | // libprettyerr: error.h 2 | // Copyright (C) 2021 Ethan Uppal 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #ifndef _LIBPRETTYERR_PRETTYERR_H 18 | #define _LIBPRETTYERR_PRETTYERR_H 19 | 20 | #include "internal/error.h" 21 | 22 | typedef struct libprettyerr_error perr_t; 23 | typedef struct libprettyerr_printer perr_printer_t; 24 | typedef libprettyerr_runner_t perr_runner_t; 25 | extern PRETTYERR_EXPORT perr_runner_t perr_runner_basic_style; 26 | extern PRETTYERR_EXPORT perr_runner_t perr_runner_secondary_style; 27 | 28 | #endif /* _LIBPRETTYERR_PRETTYERR_H */ 29 | -------------------------------------------------------------------------------- /src/termcolor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | get_filename_component(LIBRARY_NAME "${CMAKE_CURRENT_SOURCE_DIR}" NAME) 2 | 3 | set(download_dir "${PROJECT_BINARY_DIR}/termcolor") 4 | set(termcolor_header "${download_dir}/termcolor.h") 5 | if (NOT EXISTS "${termcolor_header}") 6 | file(DOWNLOAD https://raw.githubusercontent.com/euppal/libtermcolor/92eca6c/include/termcolor.h 7 | "${termcolor_header}" 8 | EXPECTED_HASH "SHA256=a3aea7b0157b22e690bc74c44a1f91a95bc2b20e0d330e32475100ca4ff54a4b") 9 | endif (NOT EXISTS "${termcolor_header}") 10 | 11 | set(termcolor_src "${download_dir}/termcolor.c") 12 | if (NOT EXISTS "${termcolor_src}") 13 | file(DOWNLOAD https://raw.githubusercontent.com/euppal/libtermcolor/92eca6c/src/termcolor.c 14 | "${termcolor_src}" 15 | EXPECTED_HASH "SHA256=ab84d8f3b2d9aa6d1f13fe5794eabb8aad1a92943e2bb0abc00e1eb757af99d7") 16 | endif (NOT EXISTS "${termcolor_src}") 17 | 18 | set(Header_Files "${termcolor_header}") 19 | source_group("Header Files" FILES "${Header_Files}") 20 | 21 | set(Source_Files "${termcolor_src}") 22 | source_group("Source Files" FILES "${Source_Files}") 23 | 24 | add_library("${LIBRARY_NAME}" "${LIBRARY_TYPE_FLAG}" "${Header_Files}" "${Source_Files}") 25 | 26 | target_include_directories( 27 | "${LIBRARY_NAME}" 28 | PUBLIC 29 | "$" 30 | "$" 31 | "$" 32 | ) 33 | set_target_properties( 34 | "${LIBRARY_NAME}" 35 | PROPERTIES 36 | LINKER_LANGUAGE 37 | C 38 | ) 39 | 40 | ################# 41 | # install rules # 42 | ################# 43 | 44 | include(GenerateExportHeader) 45 | set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/${LIBRARY_NAME}_export.h") 46 | generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}") 47 | 48 | # setup the version numbering 49 | set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") 50 | set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") 51 | 52 | set(installable_libs "${LIBRARY_NAME}" "${PROJECT_NAME}_compiler_flags") 53 | install(FILES "${Header_Files}" "${_export_file}" DESTINATION "include") 54 | 55 | if (TARGET "${DEPENDANT_LIBRARY}") 56 | list(APPEND installable_libs "${DEPENDANT_LIBRARY}") 57 | endif () 58 | install(TARGETS ${installable_libs} 59 | DESTINATION "lib" 60 | EXPORT "${LIBRARY_NAME}Targets") 61 | --------------------------------------------------------------------------------