Skip to content

Commit

Permalink
Merge pull request #1 from matyalatte/add_os_functions
Browse files Browse the repository at this point in the history
Add GetOSVersion(), GetOSProductName(), GetRealPath(), and PathExists()
  • Loading branch information
matyalatte committed Jun 7, 2024
2 parents 19b2e27 + 3f9c155 commit f31868c
Show file tree
Hide file tree
Showing 13 changed files with 684 additions and 54 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ docs/latex
# coverage report
coverage-report
*.log

# vscode
.vscode
1 change: 1 addition & 0 deletions Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ WARN_LOGFILE =
INPUT = ./include/env_utils.h \
./include/env_utils_windows.h \
./docs/README.md \
./docs/ReturnValues.md \
./docs/Doxygen.md

# This tag can be used to specify the character encoding of the source files
Expand Down
7 changes: 6 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

c-env-utils is a cross-platform C library to get environment information such as user name, working directory, and executable path.
c-env-utils is a cross-platform C library to get environment information such as executable path, user name, and OS version.

## Documentation

Expand Down Expand Up @@ -47,6 +47,11 @@ int main(void) {
printf("User: %s\n", username);
envuFree(username);

// OS
char *prodname = envuGetOSProductName();
printf("OS: %s\n", prodname);
envuFree(prodname);

// Parse the PATH variable
int count;
char **paths = envuGetEnvPaths(&count);
Expand Down
69 changes: 69 additions & 0 deletions docs/ReturnValues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Examples of Return Values

## envuGetOS* functions

Examples of return values for envuGetOS(), envuGetOSVersion(), and envuGetOSProductName().

| OS | Version | Product Name |
| -- | -- | -- |
| Darwin | 19.5.0 | Mac OS X 10.15.5 |
| Windows | 10.0.19045 | Microsoft Windows 10 Home |
| Linux | 5.15.0 | Ubuntu 20.04.6 LTS |
| Linux | 6.1.92 | Alpine Linux v3.18 |
| FreeBSD | 14.0 | FreeBSD 14.0 |
| NetBSD | 9.3 | NetBSD 9.3 |
| OpenBSD | 7.4 | OpenBSD 7.4 |
| SunOS | 5.11 | OpenIndiana Hipster 2024.04 |
| Haiku | 1 | Haiku R1/beta4 |

## envuGetFullPath

Examples of input paths and return values for envuGetFullPath()

### Windows

| Input | Return |
| -- | -- |
| "C:\usr\lib\." | "C:\usr\lib" |
| "C:\usr\lib\.." | "C:\usr" |
| "C:\usr\.\lib" | "C:\usr\lib" |
| "C:\usr\..\lib" | "C:\lib" |
| "C:\." | "C:\" |
| "C:\.." | "C:\" |
| "C:\usr\lib\" | "C:\usr\lib" |
| "usr" | "C:\path\to\cwd\usr" |
| "." | "C:\path\to\cwd" |
| "" | "C:\path\to\cwd" |
| NULL | NULL |

### Linux/Unix

| Input | Return |
| -- | -- |
| "/usr/lib" | "/usr/lib" |
| "/usr/lib" | "/usr" |
| "/usr/./lib" | "/usr/lib" |
| "/usr/../lib" | "/lib" |
| "/." | "/" |
| "/.." | "/" |
| "/usr/lib/" | "/usr/lib" |
| "usr" | "/path/to/cwd/usr" |
| "." | "/path/to/cwd" |
| "" | "/path/to/cwd" |
| NULL | NULL |

## envuGetDirectory

Examples of input paths and return values for envuGetDirecotry()

| Input | Return |
| -- | -- |
| "/usr/lib" | "/usr" |
| "/usr/" | "/" |
| "usr" | "." |
| "usr/" | "." |
| "/" | "/" |
| "." | "." |
| ".." | "." |
| "" | "." |
| NULL | NULL |
60 changes: 56 additions & 4 deletions include/env_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ extern "C" {
#define _ENVU_ENUM(s) typedef unsigned int s; enum

// Version info
#define ENVU_VERSION "0.2.0"
#define ENVU_VERSION_INT 200
#define ENVU_VERSION "0.3.0"
#define ENVU_VERSION_INT 300

/**
* Gets the version of c-env-utils.
Expand Down Expand Up @@ -55,15 +55,24 @@ _ENVU_EXTERN void envuFree(void *p);
_ENVU_EXTERN char *envuGetExecutablePath();

/**
* Returns if the specified path is a file for not.
* Returns if the specified path is a regular file for not.
*
* @param path A path.
* @returns If the specified path is a regular file or not.
*/
_ENVU_EXTERN int envuFileExists(const char *path);

/**
* Returns if the specified path exists for not.
*
* @param path A path.
* @returns If the specified path exists or not.
*/
_ENVU_EXTERN int envuPathExists(const char *path);

/**
* Gets a full path of the specified path.
* It resolves dot segments but ignores symlinks and the PATH variable.
*
* @note Strings that are returned from this method should be freed with envuFree().
*
Expand All @@ -72,6 +81,20 @@ _ENVU_EXTERN int envuFileExists(const char *path);
*/
_ENVU_EXTERN char *envuGetFullPath(const char *path);

/**
* Gets a real path of the specified path.
* It can resolve symlinks and refer the PATH variables.
* But it fails if the specified path does not exist.
*
* @warning This function can NOT resolve symlinks on Windows.
*
* @note Strings that are returned from this method should be freed with envuFree().
*
* @param path A path.
* @returns A real path of the specified path. Or a null pointer if failed.
*/
_ENVU_EXTERN char *envuGetRealPath(const char *path);

/**
* Gets a parent directory of the specified path.
*
Expand Down Expand Up @@ -150,13 +173,42 @@ _ENVU_EXTERN char *envuGetUsername();
/**
* Gets the name of running OS.
* e.g. "Windows" for Windows, "Darwin" for macOS, and "Linux" for Linux distros.
* You can see more examples [here](md_docs__return_values.html).
*
* @note Strings that are returned from this method should be freed with envuFree().
*
* @returns A string that represents running OS. Or a null pointer if failed.
* @returns A string that represents running OS.
* Or a null pointer if failed.
*/
_ENVU_EXTERN char *envuGetOS();

/**
* Gets the version of running OS.
* You can see examples of return values [here](md_docs__return_values.html).
*
* @note Strings that are returned from this method should be freed with envuFree().
*
* @returns A string that represents the version of running OS.
* Or a null pointer if failed.
*/
_ENVU_EXTERN char *envuGetOSVersion();

/**
* Gets the product name and its version of running OS.
* e.g. "Microsoft Windows 10 Home", "Mac OS X 10.15.5", and "Ubuntu 20.04 LTS".
* You can see more examples [here](md_docs__return_values.html).
*
* @warning Note that the return value can be disguised by users.
* Your program may execute unexpected codes
* if you use conditional branching by the return value.
*
* @note Strings that are returned from this method should be freed with envuFree().
*
* @returns A string that represents the product name and its version of running OS.
* Or a null pointer if failed.
*/
_ENVU_EXTERN char *envuGetOSProductName();

/**
* Gets the environment paths from the PATH variable.
*
Expand Down
46 changes: 32 additions & 14 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ project('c-env-utils', ['c'],
'cpp_eh=sc', # shut the compiler up in some cases
'cpp_winlibs=', # likewise as with c_winlibs
],
version: '0.2.0')
version: '0.3.0')

envu_link_args = []
envu_c_args = []
envu_OS = host_machine.system()
envu_compiler = meson.get_compiler('c').get_id()
envu_is_release = get_option('buildtype').startswith('release') or (get_option('buildtype').startswith('custom') and not get_option('debug'))

# Requires cpp on Windows and Haiku
if envu_OS == 'windows' or envu_OS == 'haiku'
add_languages('cpp', native: false, required: true)
endif

# set compiler and linker options
if envu_OS == 'darwin' and not meson.is_subproject()
languages = ['c']
Expand All @@ -40,38 +45,50 @@ if envu_OS == 'darwin' and not meson.is_subproject()
else
warning('Universal build is disabled since your SDKs do not support it.')
endif
elif envu_OS == 'haiku'
envu_link_args += ['-lbe']
endif

if envu_compiler != 'msvc'
# Some platforms (e.g. FreeBSD) seem to use '-Wstrict-prototypes' as default
envu_c_args += ['-Wno-strict-prototypes']
if envu_OS == 'freebsd'
# Ignore some warnings on FreeBSD
envu_c_args += ['-Wno-strict-prototypes', '-Wno-c11-extensions']
endif

# set source files
envu_sources = ['src/common.c']
if envu_OS == 'windows'
envu_sources += ['src/windows.c']
envu_sources += ['src/windows.c', 'src/wmi.cpp']
else
envu_sources += ['src/unix.c']
endif
if envu_OS == 'haiku'
envu_sources += ['src/haiku.cpp']
endif

# set winapi libraries
win_lib_deps = []
# set dynamic linked libraries
envu_lib_deps = []
if envu_OS == 'windows'
foreach lib : ['kernel32', 'advapi32']
win_lib_deps += [
foreach lib : ['kernel32', 'advapi32', 'ole32', 'oleaut32', 'wbemuuid']
envu_lib_deps += [
meson.get_compiler('c').find_library(lib,
required: true),
]
endforeach
elif envu_OS == 'darwin'
envu_lib_deps += [
dependency('appleframeworks',
modules : 'CoreFoundation',
required: true),
]
elif envu_OS == 'haiku'
envu_lib_deps += [
meson.get_compiler('c').find_library('be',
required: true),
]
endif

# main binary
env_utils = library('env_utils',
envu_sources,
dependencies: win_lib_deps,
dependencies: envu_lib_deps,
c_args: envu_c_args,
cpp_args: envu_c_args,
link_args: envu_link_args,
Expand All @@ -83,9 +100,10 @@ if envu_OS == 'windows'
install_headers('include/env_utils_windows.h')
endif

# dependency for other binaries
# dependency for other projects
env_utils_dep = declare_dependency(
include_directories: include_directories('./include'),
dependencies: envu_lib_deps,
link_with : env_utils)

if get_option('cli')
Expand All @@ -100,7 +118,7 @@ endif

# Build unit tests
if get_option('tests')
add_languages('cpp', required: true)
add_languages('cpp', native:false, required: true)

# get gtest
gtest_proj = subproject('gtest')
Expand Down
8 changes: 8 additions & 0 deletions src/env_utils_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ int main(void) {
PRINTF("OS: %s\n", os);
envuFree(os);

char *os_ver = envuGetOSVersion();
PRINTF("OS version: %s\n", os_ver);
envuFree(os_ver);

char *os_pn = envuGetOSProductName();
PRINTF("OS porduct name: %s\n", os_pn);
envuFree(os_pn);

int count;
char **paths = envuGetEnvPaths(&count);
PRINTF("%s", "PATH:\n");
Expand Down
14 changes: 14 additions & 0 deletions src/env_utils_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@
extern "C" {
#endif

#define is_numeric(c) ((c >= '0' && c <= '9') || c == '.')
#define is_alphabet(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))

extern char **ParseEnvPathsBase(const char *env_path, int *path_count, char delim);

extern char *AllocStr(size_t size);
#define AllocEmptyStr() AllocStr(0)
extern char *AllocStrWithConst(const char *c);

#ifdef _WIN32
extern wchar_t *AllocWstr(size_t size);
#define AllocEmptyWstr() AllocWstr(0)
extern wchar_t *AllocWstrWithConst(const wchar_t *c);
extern wchar_t *getOSInfoFromWMI(const wchar_t *key);
#endif

#ifdef __HAIKU__
extern char *getOSVersionHaiku();
#endif

#ifdef __cplusplus
}
#endif
Expand Down
33 changes: 33 additions & 0 deletions src/haiku.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <kernel/image.h>
#include <String.h>
#include <Path.h>
#include <FindDirectory.h>
#include <AppFileInfo.h>
#include "env_utils_priv.h"

// Use a method from SysInfoView::_GetABIVersion
// https://cgit.haiku-os.org/haiku/tree/src/apps/aboutsystem/AboutSystem.cpp
char *getOSVersionHaiku() {
BString abiVersion;

// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
BPath path;
if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
path.Append("libbe.so");

BAppFileInfo appFileInfo;
version_info versionInfo;
BFile file;
if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
&& appFileInfo.SetTo(&file) == B_OK
&& appFileInfo.GetVersionInfo(&versionInfo,
B_APP_VERSION_KIND) == B_OK
&& versionInfo.short_info[0] != '\0')
abiVersion = versionInfo.short_info;
}

if (abiVersion.IsEmpty())
abiVersion = "Unknown";

return AllocStrWithConst(abiVersion.String());
}
Loading

0 comments on commit f31868c

Please sign in to comment.