本文通过实现一个“创建C语言头文件和源文件模板”的dn命令作为例子演示linux中实现带参数的命令过程。
第一步:实现命令源代码:
/**********************************************************
FileName : dn.c
FileFunc : Linux下实现.c和.h文件模板
Version : V0.1
Author : qiuyigui
Date : 2013-03-30
Descp : Linux下实现命令行实用程序
*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void GetLocalTime( char *pOutTime );
unsigned char createfile( unsigned char ucFileFlag,char *pFilename );
void StrToUpper( char *pcStr );
void write_h( FILE *fp ,char *pFileName,char *pAliasName);
void write_c( FILE *fp,char *pFileName );
void GetLocalTime( char *pOutTime )
{
time_t t;
struct tm tm1;
t = time(NULL);
memcpy(&tm1,localtime(&t),sizeof(struct tm));
sprintf(pOutTime,"%04d-%02d-%02d %02d:%02d:%02d",tm1.tm_year+1900,tm1.tm_mon+1,tm1.tm_mday,tm1.tm_hour,tm1.tm_min,tm1.tm_sec);
/*YYYYMMDDHHMMSS(年月日时分秒) */
}
void StrToUpper( char *pcStr )
{
while( '\0'!=*pcStr )
{
if( islower(*pcStr) )
*pcStr -= 32;
++pcStr;
}
}
int main( int argc,char *argv[] )
{
unsigned char ucRetCode = 1;
if( 2==argc )
{
if( 0==memcmp(argv[1],"--help",strlen(argv[1])) )
{
fprintf(stderr,"用法:dn 选项... 文件... \n");
fprintf(stderr,"根据<选项>参数的设置来选择创建指定的<文件>是.h文件还是.c文件。\n");
fprintf(stderr,"\n<选项> <文件> 参数的设置\n");
fprintf(stderr,"-h filename 创建名为filename.h文件\n");
fprintf(stderr,"-c filename 创建名为filename.c文件\n");
fprintf(stderr,"--help 显示此帮助信息并退出\n");
fprintf(stderr,"--version 输出版本信息并退出\n");
fprintf(stderr,"\n如遇到问题,请向 <qiuyigui@126.com> 报告错误。\n");
}
else if( 0==memcmp(argv[1],"--version",strlen(argv[1])) )
{
fprintf(stderr,"create (free code) 1.01\n");
fprintf(stderr,"这是自由软件,相互交流学习可以加入QQ:58114361\n");
fprintf(stderr,"\n");
fprintf(stderr,"由qiuyigui编写\n");
}
else
{
fprintf(stderr,"%s:无效选项\"%s\" \n",argv[0],argv[1]);
fprintf(stderr,"请尝试执行 \"dn --help\" 来获取更多的信息. \n");
}
exit (1);
}
if( 3!=argc )
{
fprintf(stderr,"%s:无效选项 \n",argv[0]);
fprintf(stderr,"请尝试执行 \"dn --help\" 来获取更多的信息. \n");
exit (1);
}
if( '-'==*argv[1])
{
if( 0==memcmp(argv[1],"-h",strlen(argv[1])) )
{
ucRetCode = createfile(0,argv[2]);
}
else if( 0==memcmp(argv[1],"-c",strlen(argv[1])) )
{
ucRetCode = createfile(1,argv[2]);
}
else
{
fprintf(stderr,"%s:无效选项\"%s\" \"%s\" \n",argv[0],argv[1],argv[2]);
fprintf(stderr,"请尝试执行 \"dn --help\" 来获取更多的信息. \n");
exit(1);
}
}
else
{
fprintf(stderr,"%s:无效选项\"%s\" \"%s\" \n",argv[0],argv[1],argv[2]);
fprintf(stderr,"请尝试执行 \"dn --help\" 来获取更多的信息. \n");
exit(1);
}
return ucRetCode;
}
unsigned char createfile(unsigned char ucFileFlag,char *pFilename)
{
unsigned char ucRetCode = 1;
char szFileName[30];
char szAliasName[30];
FILE *fp = NULL;
unsigned int uiI;
if( strlen(pFilename)>27 )
{
fprintf(stderr,"%s:创建文件失败,文件名长度太长!\n",pFilename);
return 1;
}
memset(szFileName,0,sizeof(szFileName));
if( !ucFileFlag )
{
sprintf(szFileName,"%s.h",pFilename);
}
else
{
sprintf(szFileName,"%s.c",pFilename);
}
memset(szAliasName,0,sizeof(szAliasName));
sprintf(szAliasName,"%s",pFilename);
StrToUpper(szAliasName);
fp = fopen(szFileName,"r");
if( NULL!=fp )
{
fclose(fp);
fprintf(stderr,"%s:创建文件失败,你指定的文件名当前目录下已经存在!\n",pFilename);
return 1;
}
fp = NULL;
fp = fopen(szFileName,"a");
if( NULL==fp )
{
fprintf(stderr,"%s:创建文件失败!\n",pFilename);
return 1;
}
if( !ucFileFlag )
{
write_h(fp,szFileName,szAliasName);
}
else
{
write_c(fp,szFileName);
}
fclose(fp);
return 0;
}
void write_h( FILE *fp ,char *pFileName,char *pAliasName )
{
char szTime[30];
memset(szTime,0,sizeof(szTime));
GetLocalTime(szTime);
fprintf(fp,"/*************************************************************\n");
fprintf(fp," FileName : %s \n",pFileName);
fprintf(fp," FileFunc : 定义头文件 \n");
fprintf(fp," Version : V0.1 \n");
fprintf(fp," Author : Sunrier \n");
fprintf(fp," Date : %s \n",szTime);
fprintf(fp," Descp : Linux下头文件 \n");
fprintf(fp,"*************************************************************/\n");
fprintf(fp,"#ifndef __%s_H__\n",pAliasName);
fprintf(fp,"#define __%s_H__\n",pAliasName);
fprintf(fp,"\n");
fprintf(fp,"#ifdef __cplusplus\n");
fprintf(fp,"extern \"C\" {\n");
fprintf(fp,"#endif\n");
fprintf(fp,"\n\n\n\n");
fprintf(fp,"#ifdef __cplusplus\n");
fprintf(fp,"}\n");
fprintf(fp,"#endif\n");
fprintf(fp,"\n");
fprintf(fp,"#endif\n");
}
void write_c( FILE *fp,char *pFileName )
{
char szTime[30];
memset(szTime,0,sizeof(szTime));
GetLocalTime(szTime);
fprintf(fp,"/*************************************************************\n");
fprintf(fp," FileName : %s \n",pFileName);
fprintf(fp," FileFunc : 定义实现文件 \n");
fprintf(fp," Version : V0.1 \n");
fprintf(fp," Author : Sunrier \n");
fprintf(fp," Date : %s \n",szTime);
fprintf(fp," Descp : Linux下实现文件 \n");
fprintf(fp,"*************************************************************/\n");
fprintf(fp,"#include <stdio.h>\n");
fprintf(fp,"\n");
fprintf(fp,"int main(int argc,char *argv[])\n");
fprintf(fp,"{\n");
fprintf(fp,"\n\n");
fprintf(fp," return 0;\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
}
第二步:创建man手册文档:
.\"表示:行首注释 而\":表示在行中的注释
.\":dn命令程序手册页的实例
.TH DN 1 "2013-03-30" "dn 1.01" "User Commands"
.\"DN:表示标题
.\"1:表示此命令出现在手册页的第几部分,范围为1-8的数字,和定义这个文件名小数点后的数字一致
.\""2013-03-30":表示"2013-03-30"显示在整个页的下中
.\""dn 1.01":表示"dn 1.01"显示在整个页的左下
.\""User Commands":表示"User Commands"显示在整个页的上中
.\".TH在文件的开始,主要说明标题
.SH NAME
.\"说明名称
.\".SH从行首开始,靠左边,宽体
\fBdn\fR \- A simple demonstration application creates a file that head file or c file .
.\"-:表示为\-
.SH SYNOPSIS
.\"说明语法格式
.B dn
.\".B:表示宽体,如果本行没有文字,则.B标签的下一行为宽体
\-OPTION... FILE...
.SH DESCRIPTION
.\"说明本命令或程序等的相关描述
This manual page document is from qiuyigui . \fBdn\fR is a common application for create a new file that .c or .h file .
.\"\fB文字\fR:表示将该文字设置成宽体
.\"\fI文字\fR:表示将文字加下划线
.\".:表示为\&.
.SH OPTIONS
.\"说明参数选项设置
It will decide to create a .h file or .c file
.sp
.\".sp:表示空行
.B \-h
It will create a new head file
.sp
.B \-c
It will create a new c file
.sp
.B \-\-help
display this help and exit
.sp
.B \-\-version
output version information and exit
.SH COPYRIGHT
.\":版权声明
\fBdn\fR is Copyright qiuyigui .This program is free software ,you can redistribute it or modify it under the GNU General Public License as published by the free software foundation .
.SH SEE ALSO
.\":其他参考
This program is a template of c and h files to quickly create .
.SH REPORTING BUGS
.\":漏洞说明
.TP 0
.\".TP n:表示TP标签下的第2行开始缩进n个字符(在第1行超过n字符的前提下) n默认值为7
.\".TP 0:表示Report bugs to <qiuyigui@126.com> .这一句缩进0个字符,这句即为了实现换行的作用
There probably are some,but I don't know that what they are yet.
Report bugs to <qiuyigui@gmail.com> .
.SH AUTHOR
.\":文档编写作者
Written by qiuyigui .
.\"看显示创建man手册命令的结果groff -Tascii -man dn.1(注:此时不会创建任务文件,只是看下显示效果)
.\"gzip dn.1 把dn.1压缩成.gz 文件,会创建一个dn.1.gz的文件,而dn.1文件会在gzip执行完后删除
.\"如果想保留原文件可以这样用:gzip -c dn.1 > dn.1.gz
.\"把文件dn.1.gz放到/usr/share/man/man1下就可以完成dn命令的man手册了
.\"当执行man dn后还会在在/var/cache/man/cat1/dn.1.bz2创建一个dn.1.bz2压缩文件
第三步:创建Makefile,内容如下:
#makefile
OBJS = dn
all:$(OBJS)
CFLAGS = -O -w -ansi
#CFLAGS = -O -Wall -ansi
CC = gcc $(CFLAGS)
dn:dn.c
@$(CC) -o $@ $?
@gzip -c dn.1 > dn.1.gz
@mv dn.1.gz /usr/share/man/man1
#gzip压缩成.gz 文件
#gzip不加参数时,默认压缩文件时,不保存原来的文件;
#如gzip create.1 结果只有压缩文件create.1.gz,原文件create.1没有了.
clean:
@ls | grep -v ^makefile$$ | grep -v [.]c$$ | grep -v [.]h$$ | grep -v [.]1$$ | grep -v [.]txt$$ | xargs rm -rf
#makefile
第四步:Make生成dn二进制执行文件
第五步:实例:
root@ubuntu:/opt/work/dn# ./dn --version
create (free code) 1.01
这是自由软件,相互交流学习可以加入QQ:58114361
由qiuyigui编写
把dn文件放入/usr/bin下可以省去前面的"./"