1 /*
2   Purpose : Parse user input
3   Author  : Ky-Anh Huynh
4   Date    : 2017 Sep 19th
5   License : MIT
6 */
7 
8 module plotbar.utils;
9 
10 void parse_argument(string[] args, out uint min_percent)
11 in {
12   assert(args.length > 0, "Input args must contain a program name.");
13 }
14 out {
15   assert(min_percent < 100, "Mininum percent must less than 100.");
16 }
17 do {
18   import std.conv;
19   import std.exception;
20   import std.getopt;
21   import std.stdio;
22   import core.stdc.stdlib: exit;
23   import std.format;
24 
25   try {
26     auto helpInformation = getopt(args,
27       "m",  "Minimum percent to display (0 -> 99)", &min_percent,
28       std.getopt.config.stopOnFirstNonOption
29     );
30 
31     if (helpInformation.helpWanted) {
32       defaultGetoptPrinter("dzplotbar - Draw 2-d barchart.", helpInformation.options);
33       exit(0);
34     }
35 
36   }
37   catch (GetOptException exc) {
38     // Stop processing at the first unknown argument
39   }
40   catch (Exception exc) {
41     throw new Exception(format(":: Error: %s", exc.msg));
42   }
43 
44   if (min_percent >= 100) {
45     throw new Exception(":: Error: min percent must be less than 100.");
46   }
47 }
48 
49 unittest {
50   import std.exception;
51 
52   uint min_percent = 0;
53   parse_argument(["foo"], min_percent);
54   assert(min_percent == 0);
55   assertThrown(parse_argument(["foo", "-m", "-1"], min_percent), "Negative percent should throw an exception.");
56   assertThrown(parse_argument(["foo", "-m", "100"], min_percent), "Percent >= 100 should raise an error.");
57 
58   parse_argument(["foo", "-n", "10", "-m", "10"], min_percent);
59   assert(min_percent == 10, "min percent is parsed");
60 
61   parse_argument(["foo", "-m", "10", "-m", "11", "-n", "10"], min_percent);
62   assert(min_percent == 11, "min percent is 11");
63 }
64 
65 void read_key_value(ref double[string] plotdata, in string line) {
66   import std.string : strip, split;
67   import std.array: join;
68   import std.math;
69   import std.stdio;
70   import std.format: formattedRead;
71 
72   auto line_st = line.strip();
73   auto line_st2 = line_st;
74   try {
75     string key;
76     double value;
77     if (line_st.length) {
78       auto line_st_ = line_st.split.join(' ');
79       line_st_.formattedRead!"%s %f"(key, value);
80       if (key.length && !isNaN(value) && value >= 0) {
81         plotdata[key] = value + plotdata.get(key, 0);
82       }
83       else {
84         debug(2) stderr.writefln(":: Line discarded: %s", line_st2);
85       }
86     }
87   }
88   catch (Exception exc) {
89     debug(2) stderr.writefln(":: Line ignored: %s", line_st2);
90   }
91 }
92 
93 unittest {
94   double[string] result;
95 
96   result.read_key_value("");
97   assert(result is null);
98 
99   result.read_key_value("a 1");
100   result.read_key_value("b x");
101   assert(result.length && result["a"] == 1, "Can parse key = a from space delimiter input.");
102   assert("b" !in result, "Invalid value should not be included.");
103 
104   result.read_key_value("c\t1");
105   assert(result.length && result["c"] == 1, "Can parse key = c from tab delimiter input.");
106 }