1 /* This is a _simple_ program to lookup a hostname via. gethostbyname().
2  *
3  * This shows how easy it is to use custom format specifiers, to make your code
4  * easier to write and maintain.
5  *
6  * This file is more commented than normal code, so as to make it easy to follow
7  * while knowning almost nothing about Vstr or Linux IO programming.
8  */
9 #define EX_UTILS_NO_USE_INPUT 1
10 #define EX_UTILS_NO_USE_OPEN 1
11 
12 #include "ex_utils.h"
13 
14 #include <sys/socket.h>
15 #include <netdb.h>
16 
17 
main(int argc,char * argv[])18 int main(int argc, char *argv[])
19 {
20   Vstr_base *s1 = ex_init(NULL); /* init the library, and create a string */
21   struct hostent *hp = NULL; /* data from the resolver library */
22 
23   /* setup the pre-written custom format specifier for IPv4 addresses,
24    */
25   vstr_cntl_conf(s1->conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$');
26   vstr_sc_fmt_add_ipv4_ptr(s1->conf, "{IPv4:%p}");
27 
28 
29   if (argc != 2) /* if a hostname isn't given output an message to stderr */
30   {
31     size_t pos = 0;
32     size_t len = 0;
33 
34     /* add another format specifier for printing Vstr strings */
35     vstr_sc_fmt_add_vstr(s1->conf, "{Vstr:%p%zu%zu%u}");
36 
37     /* find the program name ...
38      * putting it at the begining of the Vstr string */
39     vstr_add_cstr_ptr(s1, 0, argc ? argv[0] : "lookup_ip");
40     vstr_sc_basename(s1, 1, s1->len, &pos, &len);
41 
42     /* add a format line to the Vstr string, including the program name
43      * which is at the begining of this Vstr string itself */
44     len = vstr_add_fmt(s1, s1->len, " %s ${Vstr:%p%zu%zu%u} %s\n",
45                        "Format:",
46                        s1, pos, len, 0,
47                        "<hostname>");
48 
49     vstr_del(s1, 1, s1->len - len); /* delete the original program name */
50 
51     io_put_all(s1, STDERR_FILENO);
52 
53     exit (EXIT_FAILURE);
54   }
55 
56 
57   sethostent(1);
58   /* call libc to lookup the hostname */
59   hp = gethostbyname(argv[1]);
60 
61 
62   /* just print the relevant data.... Note that nothing complicated needs to
63    * be done to print the IPv4 address, the custom formatter takes care of
64    * it */
65   if (!hp)
66     vstr_add_fmt(s1, 0, " Error retrieving hostname '%s': %s.\n",
67                  argv[1], hstrerror(h_errno));
68   else if (hp->h_addrtype == AF_INET)
69     vstr_add_fmt(s1, 0, " The hostname '%s' has an "
70                  "IPv4 address of \"${IPv4:%p}\".\n", hp->h_name,
71                  hp->h_addr_list[0]);
72   else
73     vstr_add_fmt(s1, 0, " The hostname '%s' has an address type that "
74                  "isn't an IPv4 address.\n",
75                  hp->h_name);
76 
77 
78   /* Cleanup... */
79   io_put_all(s1, STDOUT_FILENO);
80 
81   exit (ex_exit(s1, NULL));
82 }
83