Skip to content

Commit ca43d10

Browse files
authored
Simple command line argument parsing utility in PJLIB (#4013)
1 parent e9a8a69 commit ca43d10

File tree

5 files changed

+214
-0
lines changed

5 files changed

+214
-0
lines changed

pjlib/build/pjlib.vcproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12637,6 +12637,10 @@
1263712637
Name="Header Files"
1263812638
Filter="h;hpp;hxx;hm;inl"
1263912639
>
12640+
<File
12641+
RelativePath="..\include\pj\argparse.h"
12642+
>
12643+
</File>
1264012644
<File
1264112645
RelativePath="..\include\pj\activesock.h"
1264212646
>

pjlib/build/pjlib.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,7 @@
10361036
<ClInclude Include="..\include\pjlib.h" />
10371037
<ClInclude Include="..\include\pj\activesock.h" />
10381038
<ClInclude Include="..\include\pj\addr_resolv.h" />
1039+
<ClInclude Include="..\include\pj\argparse.h" />
10391040
<ClInclude Include="..\include\pj\array.h" />
10401041
<ClInclude Include="..\include\pj\assert.h" />
10411042
<ClInclude Include="..\include\pj\compat\assert.h" />

pjlib/build/pjlib.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,5 +442,8 @@
442442
<ClInclude Include="..\src\pj\ssl_sock_imp_common.h">
443443
<Filter>Header Files</Filter>
444444
</ClInclude>
445+
<ClInclude Include="..\include\pj\argparse.h">
446+
<Filter>Header Files</Filter>
447+
</ClInclude>
445448
</ItemGroup>
446449
</Project>

pjlib/include/pj/argparse.h

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Copyright (C) 2008-2024 Teluu Inc. (http://www.teluu.com)
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 2 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, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+
*/
18+
#ifndef __PJ_ARGPARSE_H__
19+
#define __PJ_ARGPARSE_H__
20+
21+
/**
22+
* @file argparse.h
23+
* @brief Command line argument parser
24+
*/
25+
#include <pj/ctype.h>
26+
#include <pj/errno.h>
27+
#include <pj/string.h>
28+
29+
PJ_BEGIN_DECL
30+
31+
/**
32+
* Define function to display parsing error.
33+
*/
34+
#ifndef PJ_ARGPARSE_ERROR
35+
# include <stdio.h>
36+
# define PJ_ARGPARSE_ERROR(fmt, arg) printf(fmt "\n", arg)
37+
#endif
38+
39+
40+
/**
41+
* @defgroup PJ_ARGPARSE Command line argument parser
42+
* @ingroup PJ_MISC
43+
* @{
44+
*
45+
* This module provides header only utilities to parse command line arguments.
46+
* This is mostly used by PJSIP test and sample apps. Note that there is
47+
* getopt() implementation in PJLIB-UTIL (but it's in PJLIB-UTIL, so it can't
48+
* be used by PJLIB).
49+
*
50+
* Limitations:
51+
* - the utility only supports white space(s) as separator between an option
52+
* and its value. Equal sign is not supported.
53+
* - the utility does not support double dash (--) as separator between options
54+
* and operands. It will keep treating arguments after -- as possible
55+
* options.
56+
*/
57+
58+
/**
59+
* Peek the next possible option from argv. An argument is considered an
60+
* option if it starts with "-".
61+
*
62+
* @param argv The argv, which must be null terminated.
63+
*
64+
* @return next option or NULL.
65+
*/
66+
PJ_INLINE(char*) pj_argparse_peek_next_option(char *const argv[])
67+
{
68+
while (*argv) {
69+
const char *arg = *argv;
70+
if (*arg=='-') {
71+
return *argv;
72+
}
73+
++argv;
74+
}
75+
return NULL;
76+
}
77+
78+
/**
79+
* Check that an option exists, without modifying argv.
80+
*
81+
* @param argv The argv, which must be null terminated.
82+
* @param opt The option to find, e.g. "-h", "--help"
83+
*
84+
* @return PJ_TRUE if the option exists, else PJ_FALSE.
85+
*/
86+
PJ_INLINE(pj_bool_t) pj_argparse_exists(char *const argv[], const char *opt)
87+
{
88+
int i;
89+
for (i=1; argv[i]; ++i) {
90+
if (pj_ansi_strcmp(argv[i], opt)==0)
91+
return PJ_TRUE;
92+
}
93+
return PJ_FALSE;
94+
}
95+
96+
/**
97+
* Check for an option and if it exists remove that option from argc/argv and
98+
* returns PJ_TRUE.
99+
*
100+
* @param argc Pointer to argc.
101+
* @param argv Null terminated argv.
102+
* @param opt The option to find, e.g. "-h", "--help"
103+
*
104+
* @return PJ_TRUE if the option exists, else PJ_FALSE.
105+
*/
106+
PJ_INLINE(pj_bool_t) pj_argparse_get_bool(int *argc, char *argv[],
107+
const char *opt)
108+
{
109+
int i;
110+
for (i=1; argv[i]; ++i) {
111+
if (pj_ansi_strcmp(argv[i], opt)==0) {
112+
pj_memmove(&argv[i], &argv[i+1], ((*argc)-i)*sizeof(char*));
113+
(*argc)--;
114+
return PJ_TRUE;
115+
}
116+
}
117+
return PJ_FALSE;
118+
}
119+
120+
/**
121+
* Check for an option and if it exists get the value and remove both
122+
* the option and the value from argc/argv. Note that the function only
123+
* supports whitespace(s) as separator between option and value (i.e. equal
124+
* sign is not supported, e.g. "--server=127.0.0.1" will not be parsed
125+
* correctly).
126+
*
127+
* @param argc Pointer to argc.
128+
* @param argv Null terminated argv.
129+
* @param opt The option to find, e.g. "-t", "--type"
130+
* @param ptr_value Pointer to receive the value.
131+
*
132+
* @return - PJ_SUCCESS if the option exists and value is found
133+
* or if the option does not exist
134+
* - PJ_EINVAL if the option exits but value is not found
135+
*/
136+
PJ_INLINE(pj_status_t) pj_argparse_get_str(int *argc, char *argv[],
137+
const char *opt, char **ptr_value)
138+
{
139+
int i;
140+
for (i=1; argv[i]; ++i) {
141+
if (pj_ansi_strcmp(argv[i], opt)==0) {
142+
pj_memmove(&argv[i], &argv[i+1], ((*argc)-i)*sizeof(char*));
143+
(*argc)--;
144+
145+
if (argv[i]) {
146+
char *val = argv[i];
147+
pj_memmove(&argv[i], &argv[i+1], ((*argc)-i)*sizeof(char*));
148+
(*argc)--;
149+
*ptr_value = val;
150+
return PJ_SUCCESS;
151+
} else {
152+
PJ_ARGPARSE_ERROR("Error: missing value for %s argument",
153+
opt);
154+
return PJ_EINVAL;
155+
}
156+
}
157+
}
158+
return PJ_SUCCESS;
159+
}
160+
161+
/**
162+
* Check for an option and if it exists, get the integer value and remove both
163+
* the option and the value from argc/argv. Note that the function only
164+
* supports whitespace(s) as separator between option and value (i.e. equal
165+
* sign is not supported, e.g. "--port=80" will not be parsed correctly).
166+
*
167+
* @param opt The option to find, e.g. "-h", "--help"
168+
* @param argc Pointer to argc.
169+
* @param argv Null terminated argv.
170+
* @param ptr_value Pointer to receive the value.
171+
*
172+
* @return - PJ_SUCCESS if the option exists and value is found
173+
* or if the option does not exist
174+
* - PJ_EINVAL if the option exits but value is not found,
175+
* or if the value is not an integer.
176+
*/
177+
PJ_INLINE(pj_status_t) pj_argparse_get_int(int *argc, char *argv[],
178+
const char *opt, int *ptr_value)
179+
{
180+
char *endptr, *sval=NULL;
181+
long val;
182+
pj_status_t status = pj_argparse_get_str(argc, argv, opt, &sval);
183+
if (status!=PJ_SUCCESS || !sval)
184+
return status;
185+
186+
val = strtol(sval, &endptr, 10);
187+
if (*endptr) {
188+
PJ_ARGPARSE_ERROR("Error: invalid value for %s argument",
189+
opt);
190+
return PJ_EINVAL;
191+
}
192+
193+
*ptr_value = (int)val;
194+
return PJ_SUCCESS;
195+
}
196+
197+
/**
198+
* @}
199+
*/
200+
201+
PJ_END_DECL
202+
203+
204+
#endif /* __PJ_ARGPARSE_H__ */
205+

pjlib/include/pjlib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include <pj/activesock.h>
2929
#include <pj/addr_resolv.h>
30+
#include <pj/argparse.h>
3031
#include <pj/array.h>
3132
#include <pj/assert.h>
3233
#include <pj/ctype.h>

0 commit comments

Comments
 (0)