当前位置: 首页 > news >正文

implement libwhich for Windows

因为windows没有类似unix的which命令

  • 现在实现尽量跨平台,且stb 风格的libwhich
// which.h
#ifndef LIBWHICH_H
#define LIBWHICH_H#ifdef __cplusplus
extern "C" {
#endif/** 查找可执行文件在系统中的路径* 参数:*   filename - 要查找的可执行文件名*   buffer   - 用于存储结果的缓冲区*   bufsize  - 缓冲区大小* 返回值:*   成功返回指向buffer的指针,失败返回NULL*/
char* libwhich(const char* filename, char* buffer, int bufsize);#ifdef __cplusplus
}
#endif#endif // LIBWHICH_H#ifdef LIBWHICH_IMPLEMENTATION#include <stdlib.h>
#include <string.h>
#include <stdio.h>#ifdef _WIN32
#include <windows.h>
#include <io.h>
#define access _access
#define F_OK 0
#else
#include <unistd.h>
#include <sys/stat.h>
#endif// 辅助函数:检查文件是否存在且可执行
static int is_executable(const char* path) {
#ifdef _WIN32// Windows系统检查文件是否存在return access(path, F_OK) == 0;
#else// Unix-like系统检查文件是否存在且可执行struct stat st;if (stat(path, &st) != 0)return 0;return (st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH);
#endif
}// 辅助函数:获取路径分隔符(PATH环境变量中分隔目录的符号)
static char get_path_separator() {
#ifdef _WIN32return ';';
#elsereturn ':';
#endif
}// 辅助函数:获取目录分隔符(路径中分隔目录的符号)
static char get_dir_separator() {
#ifdef _WIN32return '\\';
#elsereturn '/';
#endif
}// 检查文件名是否包含扩展名
static int has_extension(const char* filename) {const char* dot = strrchr(filename, '.');return dot != NULL && dot != filename && *(dot + 1) != '\0';
}char* libwhich(const char* filename, char* buffer, int bufsize) {if (!filename || !buffer || bufsize <= 0)return NULL;// 获取PATH环境变量const char* path_env = getenv("PATH");if (!path_env)return NULL;// 复制PATH以便处理char* path = strdup(path_env);if (!path)return NULL;char* result = NULL;char sep[2] = {get_path_separator(), '\0'};char dir_sep = get_dir_separator();// 拆分PATH中的各个目录char* dir = strtok(path, sep);while (dir != NULL) {size_t dir_len = strlen(dir);size_t file_len = strlen(filename);int need_sep = (dir_len > 0 && dir[dir_len - 1] != dir_sep) ? 1 : 0;// 检查缓冲区是否足够if (dir_len + need_sep + file_len + 1 > (size_t)bufsize) {dir = strtok(NULL, sep);continue;}// 构建完整路径strcpy(buffer, dir);if (need_sep) {buffer[dir_len] = dir_sep;strcpy(buffer + dir_len + 1, filename);} else {strcpy(buffer + dir_len, filename);}// 检查文件是否存在且可执行if (is_executable(buffer)) {result = buffer;break;}#ifdef _WIN32// Windows系统需要检查常见的可执行文件扩展名if (!has_extension(filename)) {const char* exts[] = {".exe", ".com", ".bat", ".cmd", ".ps1", NULL};for (int i = 0; exts[i] != NULL; i++) {size_t ext_len = strlen(exts[i]);if (dir_len + need_sep + file_len + ext_len + 1 > (size_t)bufsize)continue;// 构建带扩展名的路径strcpy(buffer, dir);if (need_sep) {buffer[dir_len] = dir_sep;strcpy(buffer + dir_len + 1, filename);} else {strcpy(buffer + dir_len, filename);}strcat(buffer, exts[i]);if (is_executable(buffer)) {result = buffer;goto cleanup; // 找到后跳出所有循环}}}
#endifdir = strtok(NULL, sep);}cleanup:free(path);return result;
}#endif // LIBWHICH_IMPLEMENTATION// 示例主程序,定义LIBWHICH_MAIN可编译为独立工具
#ifdef LIBWHICH_MAIN
#include <stdio.h>int main(int argc, char* argv[]) {if (argc != 2) {fprintf(stderr, "用法: %s <命令名>\n", argv[0]);return 1;}char buffer[1024];char* path = libwhich(argv[1], buffer, sizeof(buffer));if (path) {printf("%s\n", path);return 0;} else {fprintf(stderr, "%s: 未找到命令\n", argv[1]);return 1;}
}
#endif

build as program (view .h file as .c file)

> gcc -x c which.h -DLIBWHICH_MAIN -DLIBWHICH_IMPLEMENTATION> cl /DLIBWHICH_IMPLEMENTATION /DLIBWHICH_MAIN /Tcwhich.h /Fe:which.exe

build as lib (msvc for example)

> cl /DLIBWHICH_IMPLEMENTATION /Tcwhich.h /Fo:libwhich.obj> lib libwhich.obj /OUT:libwhich.lib

as lib usage

// probe.c#define LIBWHICH_IMPLEMENTATION
#include "which.h"
#include <stdio.h>int main() {char buffer[1024];char* path = libwhich("python", buffer, sizeof(buffer));if (path) {printf("找到python: %s\n", path);} else {printf("未找到python\n");}return 0;
}
http://www.dtcms.com/a/335178.html

相关文章:

  • 全面解析Tomcat生命周期原理及其关键实现细节
  • 牛 CDR3 单抗:抗病毒领域的 “纳米级精准导弹”
  • 掌握长尾关键词优化SEO技巧
  • [创业之路-550]:公司半年度经营分析会 - 常见差距与根因分析示例
  • Hugging Face 与 NLP
  • 【JavaEE】(13) Spring Web MVC 入门
  • (论文速读)低光照图像增强综述(一)
  • Web全栈项目中健康检查API的作用(现代云原生应用标准实践)(health check、healthcheck、livenessProbe、健康探针)
  • 从舒适度提升到能耗降低再到安全保障,楼宇自控作用关键
  • 机器学习——PCA算法
  • 《软件工程导论》实验报告五 设计建模工具的使用(一)类图
  • 单目 BEV有哪些开源项目
  • redis基本类型之哈希
  • 《后室Backrooms》中文版,购物误入异空间,怪物追逐,第一人称冒险逃生
  • 模版模版模版
  • 类的生命周期与加载过程
  • 地理信息系统教程(汤国安老师书)—— 第二章课后习题
  • 掌握提示词工程:让大模型更懂你的需求
  • vue:vue3 watch 属性
  • Nacos Server 3.0.x安装教程
  • JAVA面试汇总(四)JVM(一)
  • 软件包管理-源代码安装
  • GaussDB 数据库架构师修炼(十三)安全管理(4)-数据库审计
  • Win11更新0x80073712错误解决方法
  • 优雅草星云物联网项目私有化定制技术解析:RS485接口与工业通讯协议-优雅草卓伊凡
  • 初识c语言————宏定义和调用
  • SpringSecurity(一)入门
  • 行为型设计模式:对象协作的舞蹈家(上)
  • 车行横洞*到底是什么
  • 原码表示法、反码表示法、移码表示法、补码表示法