MINOR: config: Support a range to specify processes in "cpu-map" parameter

Now, you can define processes concerned by a cpu-map line using a range. For
instance, the following line binds the first 32 processes on CPUs 0 to 3:

  cpu-map 1-32 0-3
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 4940b33..8305515 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -657,20 +657,21 @@
   with superuser privileges. It is important to ensure that <jail_dir> is both
   empty and unwritable to anyone.
 
-cpu-map <"all"|"odd"|"even"|process_num> <cpu-set>...
+cpu-map <"all"|"odd"|"even"|process_num[-process_num]> <cpu-set>...
   On Linux 2.6 and above, it is possible to bind a process to a specific CPU
   set. This means that the process will never run on other CPUs. The "cpu-map"
   directive specifies CPU sets for process sets. The first argument is the
   process number to bind. This process must have a number between 1 and 32 or
   64, depending on the machine's word size, and any process IDs above nbproc
-  are ignored. It is possible to specify all processes at once using "all",
-  only odd numbers using "odd" or even numbers using "even", just like with the
-  "bind-process" directive. The second and forthcoming arguments are CPU sets.
-  Each CPU set is either a unique number between 0 and 31 or 63 or a range with
-  two such numbers delimited by a dash ('-'). Multiple CPU numbers or ranges
-  may be specified, and the processes will be allowed to bind to all of them.
-  Obviously, multiple "cpu-map" directives may be specified. Each "cpu-map"
-  directive will replace the previous ones when they overlap.
+  are ignored. It is possible to specify a range with two such number delimited
+  by a dash ('-'). It also is possible to specify all processes at once using
+  "all", only odd numbers using "odd" or even numbers using "even", just like
+  with the "bind-process" directive. The second and forthcoming arguments are
+  CPU sets.  Each CPU set is either a unique number between 0 and 31 or 63 or a
+  range with two such numbers delimited by a dash ('-'). Multiple CPU numbers
+  or ranges may be specified, and the processes will be allowed to bind to all
+  of them.  Obviously, multiple "cpu-map" directives may be specified. Each
+  "cpu-map" directive will replace the previous ones when they overlap.
 
 crt-base <dir>
   Assigns a default directory to fetch SSL certificates from when a relative
diff --git a/src/cfgparse.c b/src/cfgparse.c
index bf8139c..794148c 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -589,8 +589,9 @@
 }
 
 /* Parse a string representing a process number or a set of processes. It must
- * be "all", "odd", "even" or a number between 1 and <LONGBITS>. It returns a
- * mask where bits are set for corresponding processes or 0 if an error occured.
+ * be "all", "odd", "even", a number between 1 and <LONGBITS> or a range with
+ * two such numbers delimited by a dash ('-'). It returns a mask where bits are
+ * set for corresponding processes or 0 if an error occured.
  *
  * Note: this function can also be used to parse a thread number or a set of
  * threads.
@@ -606,10 +607,29 @@
 	else if (strcmp(arg, "even") == 0)
 		proc = (~0UL/3UL) << 1; /* 0xAAA...AAA */
 	else {
-		proc = atol(arg);
-		if (proc >= 1 && proc <= LONGBITS)
-			proc = 1UL << (proc - 1);
+		char *dash;
+		unsigned int low, high;
+
+		if (!isdigit((int)*arg))
+			goto end;
+
+		low = high = str2uic(arg);
+		if ((dash = strchr(arg, '-')) != NULL)
+			high = str2uic(dash + 1);
+		if (high < low) {
+			unsigned int swap = low;
+			low  = high;
+			high = swap;
+		}
+
+		if (low < 1 || low >= LONGBITS || high >= LONGBITS)
+			goto end;
+
+		for (;low <= high; low++)
+			proc |= 1UL << (low-1);
 	}
+
+  end:
 	return proc;
 }
 
@@ -1676,15 +1696,24 @@
 		unsigned long proc, cpus;
 		int i;
 
-		proc = parse_process_number(args[1]);
-		if (!proc || !*args[2]) {
-			Alert("parsing [%s:%d]: %s expects a process number "
-			      " ('all', 'odd', 'even', or a number from 1 to %d), "
+		if (!*args[1] || !*args[2]) {
+			Alert("parsing [%s:%d] : %s expects a process number "
+			      " ('all', 'odd', 'even', a number from 1 to %d or a range), "
 			      " followed by a list of CPU ranges with numbers from 0 to %d.\n",
 			      file, linenum, args[0], LONGBITS, LONGBITS - 1);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
+
+		proc = parse_process_number(args[1]);
+		if (!proc) {
+			Alert("parsing [%s:%d] : %s : '%s' is not a valid PROC number "
+			      " ('all', 'odd', 'even', a number from 1 to %d or a range).\n",
+			      file, linenum, args[0], args[1], LONGBITS);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
 		if (parse_cpu_set((const char **)args+2, &cpus, &errmsg)) {
 			Alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
 			err_code |= ERR_ALERT | ERR_FATAL;