繁体   English   中英

打印 man 内容作为 C 程序的帮助提示

[英]Print man contents as help prompt of a C program

我计划使用pandoc从 markdown 为一个非常小的 C 程序生成man文件。

我不想重复自己并在程序的源代码中键入帮助提示command [ -h | --help ] )。

问题

问:我能否在 C 程序的编译时永久包含文件中的 man 内容?
或者
问: C中有没有办法将安装的手册页的内容打印到标准输出?


[WIP] 解决方案

根据@KamilCuk 的回答,这就是我正在做的事情:

在终端:

file command.1
# OUTPUT --> command.1: troff or preprocessor input, ASCII text

xxd -i command.1 > command.hex

然后在main.c

#include "command.hex"
printf("%s", command_1);

几乎正是我想要的,除了

  1. 我需要在打印之前解析十六进制的 troff。 或在十六进制之前解析。 我不确定该做什么/如何做。
    • 不,我不想打电话给man和 pipe output。
  2. 我更喜欢使用库 + 宏来生成十六进制,但我不确定它是如何完成的。

澄清

我所说的帮助提示是什么意思:

  • git 的git --help打印到标准输出
  • 不是git --help 分支的git --help branch ,它为 git-branch 打开了 man

但是,也请分享后者。 这不是我想要的:我的手册很短; 但如果不是我所寻求的那种,我会很高兴学习另一种选择。


我注意到的注意事项:

  1. 手册页并不总是安装到同一位置
  2. 某些系统中可能未安装手册页; 或者可能没有man程序

我可以在编译时永久包含文件中的 man 内容吗?

您可以在编译时包含任何文件的任何内容。 最简单的是使用xxd -i并编译 output。

C 中有没有办法打印安装的手册页的内容?

您可以从man -k troff output

您可以通过沿MANPAGER=cat man替换寻呼机从man获取 output 。

在 C 中: setenv("MANPAGER", "cat"); execp("man", (char*[]){"man", "something", 0}); setenv("MANPAGER", "cat"); execp("man", (char*[]){"man", "something", 0}); 或者只是system("MANPAGER=cat man some_command")

手册页并不总是安装到同一位置

并且系统管理员可以使用/etc/man_db.conf来配置man命令的行为。

某些系统中可能未安装手册页; 或者可能没有 man 程序

因此,此类系统的用户似乎并不关心手册页,因此支持此类情况毫无意义。

我相信您的意图是从您的程序中呈现一个手册页,其中您保存了 static troff 输入并希望使用man来显示它。 您可以将输入保存到文件中,保存并将文件名传递给man - man 将解析 troff 并渲染它。 或者您可以使用通常的pipe()+fork()+exec()并从一个进程将 troff 数据传递给 stdin 到man - - -将使man从 stdin 读取 troff 输入。

C 中有没有办法将安装的手册页的内容打印到标准输出?

您可以使用 pipe stream 来调用man命令。 Function popen就是您要找的。 更多信息在这里

这是一个fgets()解决方案,但您可能需要小心,以防您想阅读更多字符。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *fp = NULL;
    char buffer[1000];

    fp  = popen("man man","r");

    if (fp == NULL)
    {
       /* error running the command */
       exit(EXIT_FAILURE);
    }


    while (fgets(buffer,sizeof(buffer),fp))
    {
        puts(buffer);
    }

    fclose(fp);    

    return 0;
}

getline()解决方案,以防您不知道要读取多少字节。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *fp = NULL;
    char *buffer = NULL;
    size_t len = 0U;
    ssize_t nread = 0;

    fp  = popen("man man","r");

    if (fp == NULL)
    {
       /* error running the command */
       exit(EXIT_FAILURE);
    }

    /* getline will set errno uppon failure, you might want to check that too */

    while ((nread = getline(&buffer,&len,fp)) != -1)
    {
       buffer[nread] = 0; /* NULL terminate your buffer */
       puts(buffer);
    }
    
    free(buffer);
    fclose(fp);

    return 0;
}

更多关于getline()的信息

man程序是用 C 编写的,并且是开源的。 它比您想象的要复杂,因为它处理终端(及其宽度)。 另请参见termios(3)tty(4) 请注意ANSI 转义码ncurses库。 考虑到在 2021 年UTF-8 到处都在使用,并且一些man页可能包含§°字符。 还要注意国际化和本地化问题,请参阅locale(7) 在法国,很多 Linux 系统都安装了法语man页。

因此,您可以获得man-db package 的源代码,研究它,并将其合并到您的程序中。

我的观点是这样做是愚蠢的。

您可以改为阅读Advanced Linux Programming ,研究各种syscalls(2) ,并使用fork(2)execve(2)waitpid(2)运行现有安装/usr/bin/man程序(可以测试其存在在 C 代码中使用test(1)access(2)stat(2) ;但如果它不存在,您的execve(2)将失败...)

关于--help的显示,您可以使用(如果允许)GNU libc 程序参数解析工具,并从现有自由软件程序的源代码中获取灵感,例如GNU coreutils

当然,您的构建基础架构(例如,如果您使用GNU make构建软件,您的Makefile )可以运行程序来共享数据和文本描述。 您可以(如果允许)在构建时使用开源工具生成一些 C 代码(例如#include d stuff),例如GNU m4GNU gawkGPP等。

还可以从git的源代码中获取灵感。 它是开源的(对你有用):你可以下载它的源代码并学习它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM