Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / regex / regex_test_random.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2012 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 /**
19  * @file src/regex/regex_test_random.c
20  * @brief functions for creating random regular expressions and strings
21  * @author Maximilian Szengel
22  */
23 #include "platform.h"
24 #include "regex_test_lib.h"
25 #include "gnunet_crypto_lib.h"
26 #include "regex_internal.h"
27
28
29 /**
30  * Get a (pseudo) random valid literal for building a regular expression.
31  *
32  * @return random valid literal
33  */
34 static char
35 get_random_literal ()
36 {
37   uint32_t ridx;
38
39   ridx =
40       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
41                                 (uint32_t) strlen (ALLOWED_LITERALS));
42
43   return ALLOWED_LITERALS[ridx];
44 }
45
46
47 /**
48  * Generate a (pseudo) random regular expression of length 'rx_length', as well
49  * as a (optional) string that will be matched by the generated regex. The
50  * returned regex needs to be freed.
51  *
52  * @param rx_length length of the random regex.
53  * @param matching_str (optional) pointer to a string that will contain a string
54  *                     that will be matched by the generated regex, if
55  *                     'matching_str' pointer was not NULL. Make sure you
56  *                     allocated at least rx_length+1 bytes for this sting.
57  *
58  * @return NULL if 'rx_length' is 0, a random regex of length 'rx_length', which
59  *         needs to be freed, otherwise.
60  */
61 char *
62 REGEX_TEST_generate_random_regex (size_t rx_length, char *matching_str)
63 {
64   char *rx;
65   char *rx_p;
66   char *matching_strp;
67   unsigned int i;
68   unsigned int char_op_switch;
69   unsigned int last_was_op;
70   int rx_op;
71   char current_char;
72
73   if (0 == rx_length)
74     return NULL;
75
76   if (NULL != matching_str)
77     matching_strp = matching_str;
78   else
79     matching_strp = NULL;
80
81   rx = GNUNET_malloc (rx_length + 1);
82   rx_p = rx;
83   current_char = 0;
84   last_was_op = 1;
85
86   for (i = 0; i < rx_length; i++)
87   {
88     char_op_switch = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
89
90     if (0 == char_op_switch && !last_was_op)
91     {
92       last_was_op = 1;
93       rx_op = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4);
94
95       switch (rx_op)
96       {
97       case 0:
98         current_char = '+';
99         break;
100       case 1:
101         current_char = '*';
102         break;
103       case 2:
104         current_char = '?';
105         break;
106       case 3:
107         if (i < rx_length - 1)  /* '|' cannot be at the end */
108           current_char = '|';
109         else
110           current_char = get_random_literal ();
111         break;
112       }
113     }
114     else
115     {
116       current_char = get_random_literal ();
117       last_was_op = 0;
118     }
119
120     if (NULL != matching_strp &&
121         (current_char != '+' && current_char != '*' && current_char != '?' &&
122          current_char != '|'))
123     {
124       *matching_strp = current_char;
125       matching_strp++;
126     }
127
128     *rx_p = current_char;
129     rx_p++;
130   }
131   *rx_p = '\0';
132   if (NULL != matching_strp)
133     *matching_strp = '\0';
134
135   return rx;
136 }
137
138
139 /**
140  * Generate a random string of maximum length 'max_len' that only contains literals allowed
141  * in a regular expression. The string might be 0 chars long but is garantueed
142  * to be shorter or equal to 'max_len'.
143  *
144  * @param max_len maximum length of the string that should be generated.
145  *
146  * @return random string that needs to be freed.
147  */
148 char *
149 REGEX_TEST_generate_random_string (size_t max_len)
150 {
151   unsigned int i;
152   char *str;
153   size_t len;
154
155   if (1 > max_len)
156     return GNUNET_strdup ("");
157
158   len = (size_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max_len);
159   str = GNUNET_malloc (len + 1);
160
161   for (i = 0; i < len; i++)
162   {
163     str[i] = get_random_literal ();
164   }
165
166   str[i] = '\0';
167
168   return str;
169 }