diff --git a/channels/chan_oss.c b/channels/chan_oss.c
index 94c114f9673f2563a4b33a300ddb3eefa672cd5c..14e6cdcceff535ec4eb3f812a806bfcca6043982 100644
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -177,34 +177,6 @@ END_CONFIG
 
  */
 
-/*
- * Helper macros to parse config arguments. They will go in a common
- * header file if their usage is globally accepted. In the meantime,
- * we define them here. Typical usage is as below.
- * Remember to open a block right before M_START (as it declares
- * some variables) and use the M_* macros WITHOUT A SEMICOLON:
- *
- *	{
- *		M_START(v->name, v->value) 
- *
- *		M_BOOL("dothis", x->flag1)
- *		M_STR("name", x->somestring)
- *		M_F("bar", some_c_code)
- *		M_END(some_final_statement)
- *		... other code in the block
- *	}
- *
- * XXX NOTE these macros should NOT be replicated in other parts of asterisk. 
- * Likely we will come up with a better way of doing config file parsing.
- */
-#define M_START(var, val) \
-        const char *__s = var; const char *__val = val;
-#define M_END(x)   x;
-#define M_F(tag, f)			if (!strcasecmp((__s), tag)) { f; } else
-#define M_BOOL(tag, dst)	M_F(tag, (dst) = ast_true(__val) )
-#define M_UINT(tag, dst)	M_F(tag, (dst) = strtoul(__val, NULL, 0) )
-#define M_STR(tag, dst)		M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
-
 /*
  * The following parameters are used in the driver:
  *
@@ -1559,7 +1531,7 @@ static void store_callerid(struct chan_oss_pvt *o, const char *s)
 
 static void store_config_core(struct chan_oss_pvt *o, const char *var, const char *value)
 {
-	M_START(var, value);
+	CV_START(var, value);
 
 	/* handle jb conf */
 	if (!ast_jb_read_conf(&global_jbconf, (char *)var,(char *) value))
@@ -1567,22 +1539,22 @@ static void store_config_core(struct chan_oss_pvt *o, const char *var, const cha
 
 	if (!console_video_config(&o->env, var, value))
 		return;
-	M_BOOL("autoanswer", o->autoanswer)
-	M_BOOL("autohangup", o->autohangup)
-	M_BOOL("overridecontext", o->overridecontext)
-	M_STR("device", o->device)
-	M_UINT("frags", o->frags)
-	M_UINT("debug", oss_debug)
-	M_UINT("queuesize", o->queuesize)
-	M_STR("context", o->ctx)
-	M_STR("language", o->language)
-	M_STR("mohinterpret", o->mohinterpret)
-	M_STR("extension", o->ext)
-	M_F("mixer", store_mixer(o, value))
-	M_F("callerid", store_callerid(o, value))  
-	M_F("boost", store_boost(o, value))
-
-	M_END(/* */);
+	CV_BOOL("autoanswer", o->autoanswer);
+	CV_BOOL("autohangup", o->autohangup);
+	CV_BOOL("overridecontext", o->overridecontext);
+	CV_STR("device", o->device);
+	CV_UINT("frags", o->frags);
+	CV_UINT("debug", oss_debug);
+	CV_UINT("queuesize", o->queuesize);
+	CV_STR("context", o->ctx);
+	CV_STR("language", o->language);
+	CV_STR("mohinterpret", o->mohinterpret);
+	CV_STR("extension", o->ext);
+	CV_F("mixer", store_mixer(o, value));
+	CV_F("callerid", store_callerid(o, value))  ;
+	CV_F("boost", store_boost(o, value));
+
+	CV_END;
 }
 
 /*!
diff --git a/channels/chan_usbradio.c b/channels/chan_usbradio.c
index 8a1d7517ed9bba6fef4ded3a1c82c6055fd27e99..55a6600c6f639938b71a540dd5e93afcee27b9e1 100644
--- a/channels/chan_usbradio.c
+++ b/channels/chan_usbradio.c
@@ -202,34 +202,6 @@ END_CONFIG
 
  */
 
-/*! \brief
- * Helper macros to parse config arguments. They will go in a common
- * header file if their usage is globally accepted. In the meantime,
- * we define them here. Typical usage is as below.
- * Remember to open a block right before M_START (as it declares
- * some variables) and use the M_* macros WITHOUT A SEMICOLON:
- *
- *	{
- *		M_START(v->name, v->value) 
- *
- *		M_BOOL("dothis", x->flag1)
- *		M_STR("name", x->somestring)
- *		M_F("bar", some_c_code)
- *		M_END(some_final_statement)
- *		... other code in the block
- *	}
- *
- * XXX NOTE these macros should NOT be replicated in other parts of asterisk. 
- * Likely we will come up with a better way of doing config file parsing.
- */
-#define M_START(var, val) \
-        const char *__s = var; const char *__val = val;
-#define M_END(x)   x;
-#define M_F(tag, f)			if (!strcasecmp((__s), tag)) { f; } else
-#define M_BOOL(tag, dst)	M_F(tag, (dst) = ast_true(__val) )
-#define M_UINT(tag, dst)	M_F(tag, (dst) = strtoul(__val, NULL, 0) )
-#define M_STR(tag, dst)		M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
-
 /*!
  * The following parameters are used in the driver:
  *
@@ -2414,45 +2386,35 @@ static struct chan_usbradio_pvt *store_config(struct ast_config *cfg, char *ctg)
 	o->spkrmax = amixer_max(o->devicenum, MIXER_PARAM_SPKR_PLAYBACK_VOL);
 	/* fill other fields from configuration */
 	for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
-		M_START(v->name, v->value);
 
 		/* handle jb conf */
 		if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
 			continue;
-
-#if	0
-			M_BOOL("autoanswer", o->autoanswer)
-			M_BOOL("autohangup", o->autohangup)
-			M_BOOL("overridecontext", o->overridecontext)
-			M_STR("context", o->ctx)
-			M_STR("language", o->language)
-			M_STR("mohinterpret", o->mohinterpret)
-			M_STR("extension", o->ext)
-			M_F("callerid", store_callerid(o, v->value))
-#endif
-			M_UINT("frags", o->frags)
-			M_UINT("queuesize", o->queuesize)
-			M_UINT("devicenum", o->devicenum)
-			M_UINT("debug", usbradio_debug)
-			M_BOOL("rxcpusaver", o->rxcpusaver)
-			M_BOOL("txcpusaver", o->txcpusaver)
-			M_BOOL("invertptt", o->invertptt)
-			M_F("rxdemod", store_rxdemod(o, v->value))
-			M_BOOL("txprelim", o->txprelim);
-			M_F("txmixa", store_txmixa(o, v->value))
-			M_F("txmixb", store_txmixb(o, v->value))
-			M_F("carrierfrom", store_rxcdtype(o, v->value))
-			M_F("rxsdtype", store_rxsdtype(o, v->value))
-			M_F("rxctcssfreq", store_rxctcssfreq(o, v->value))
-			M_F("txctcssfreq", store_txctcssfreq(o, v->value))
-			M_F("rxgain", store_rxgain(o, v->value))
- 			M_BOOL("rxboostset", o->rxboostset)
-			M_UINT("rxctcssrelax", o->rxctcssrelax)
-			M_F("txtoctype", store_txtoctype(o, v->value))
-			M_UINT("hdwtype", o->hdwtype)
-			M_UINT("duplex", o->radioduplex)
-			M_END(;
-			);
+		CV_START(v->name, v->value);
+
+		CV_UINT("frags", o->frags);
+		CV_UINT("queuesize", o->queuesize);
+		CV_UINT("devicenum", o->devicenum);
+		CV_UINT("debug", usbradio_debug);
+		CV_BOOL("rxcpusaver", o->rxcpusaver);
+		CV_BOOL("txcpusaver", o->txcpusaver);
+		CV_BOOL("invertptt", o->invertptt);
+		CV_F("rxdemod", store_rxdemod(o, v->value));
+		CV_BOOL("txprelim", o->txprelim);;
+		CV_F("txmixa", store_txmixa(o, v->value));
+		CV_F("txmixb", store_txmixb(o, v->value));
+		CV_F("carrierfrom", store_rxcdtype(o, v->value));
+		CV_F("rxsdtype", store_rxsdtype(o, v->value));
+		CV_F("rxctcssfreq", store_rxctcssfreq(o, v->value));
+		CV_F("txctcssfreq", store_txctcssfreq(o, v->value));
+		CV_F("rxgain", store_rxgain(o, v->value));
+		CV_BOOL("rxboostset", o->rxboostset);
+		CV_UINT("rxctcssrelax", o->rxctcssrelax);
+		CV_F("txtoctype", store_txtoctype(o, v->value));
+		CV_UINT("hdwtype", o->hdwtype);
+		CV_UINT("duplex", o->radioduplex);
+
+		CV_END;
 	}
 	
 	cfg1 = ast_config_load(config1, config_flags);
@@ -2468,16 +2430,15 @@ static struct chan_usbradio_pvt *store_config(struct ast_config *cfg, char *ctg)
 	} else  {
 		for (v = ast_variable_browse(cfg1, ctg); v; v = v->next) {
 	
-			M_START(v->name, v->value);
-			M_UINT("rxmixerset", o->rxmixerset)
-			M_UINT("txmixaset", o->txmixaset)
-			M_UINT("txmixbset", o->txmixbset)
-			M_F("rxvoiceadj", store_rxvoiceadj(o, v->value))
-			M_F("rxctcssadj", store_rxctcssadj(o, v->value))
-			M_UINT("txctcssadj", o->txctcssadj);
-			M_UINT("rxsquelchadj", o->rxsquelchadj)
-			M_END(;
-			);
+			CV_START(v->name, v->value);
+			CV_UINT("rxmixerset", o->rxmixerset);
+			CV_UINT("txmixaset", o->txmixaset);
+			CV_UINT("txmixbset", o->txmixbset);
+			CV_F("rxvoiceadj", store_rxvoiceadj(o, v->value));
+			CV_F("rxctcssadj", store_rxctcssadj(o, v->value));
+			CV_UINT("txctcssadj", o->txctcssadj);
+			CV_UINT("rxsquelchadj", o->rxsquelchadj);
+			CV_END;
 		}
 		ast_config_destroy(cfg1);
 	}
diff --git a/channels/console_video.c b/channels/console_video.c
index b7a828e9058fd0bd248306fae49bf969d12a5829..d59d3bb77142d3a9701a432dd49b3b86f9e18c73 100644
--- a/channels/console_video.c
+++ b/channels/console_video.c
@@ -2987,18 +2987,6 @@ no_sdl:
 		cleanup_sdl(env);
 }
 
-/* see chan_oss.c for these macros */
-#ifndef M_START
-#define _UNDO_M_START
-#define M_START(var, val) \
-        const char *__s = var; const char *__val = val;
-#define M_END(x)		x;
-#define M_F(tag, f)		if (!strcasecmp((__s), tag)) { f; } else
-#define M_BOOL(tag, dst)        M_F(tag, (dst) = ast_true(__val) )
-#define M_UINT(tag, dst)        M_F(tag, (dst) = strtoul(__val, NULL, 0) )
-#define M_STR(tag, dst)         M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
-#endif
-
 /*
  * Parse a geometry string, accepting also common names for the formats.
  * Trick: if we have a leading > or < and a numeric geometry,
@@ -3245,7 +3233,6 @@ static int console_video_config(struct video_desc **penv,
 	const char *var, const char *val)
 {
 	struct video_desc *env;
-	M_START(var, val);
 
 	if (penv == NULL) {
 		ast_log(LOG_WARNING, "bad argument penv=NULL\n");
@@ -3267,31 +3254,25 @@ static int console_video_config(struct video_desc **penv,
 		env->out.sendvideo = 1;
 		env->out.qmin = 3;
 	}
-        M_STR("videodevice", env->out.videodevice)
-        M_BOOL("sendvideo", env->out.sendvideo)
-        M_F("video_size", video_geom(&env->out.enc_in, val))
-        M_F("camera_size", video_geom(&env->out.loc_src, val))
-        M_F("local_size", video_geom(&env->out.loc_dpy, val))
-        M_F("remote_size", video_geom(&env->in.rem_dpy, val))
-        M_STR("keypad", env->keypad_file)
-        M_F("keypad_entry", keypad_cfg_read(&env->gui, val))
-        M_STR("keypad_mask", env->keypad_mask)
-	M_STR("keypad_font", env->keypad_font)
-        M_UINT("fps", env->out.fps)
-        M_UINT("bitrate", env->out.bitrate)
-        M_UINT("qmin", env->out.qmin)
-	M_STR("videocodec", env->codec_name)
-	M_END(return 1;)	/* the 'nothing found' case */
+	CV_START(var, val);
+        CV_STR("videodevice", env->out.videodevice);
+        CV_BOOL("sendvideo", env->out.sendvideo);
+        CV_F("video_size", video_geom(&env->out.enc_in, val));
+        CV_F("camera_size", video_geom(&env->out.loc_src, val));
+        CV_F("local_size", video_geom(&env->out.loc_dpy, val));
+        CV_F("remote_size", video_geom(&env->in.rem_dpy, val));
+        CV_STR("keypad", env->keypad_file);
+        CV_F("keypad_entry", keypad_cfg_read(&env->gui, val));
+        CV_STR("keypad_mask", env->keypad_mask);
+	CV_STR("keypad_font", env->keypad_font);
+        CV_UINT("fps", env->out.fps);
+        CV_UINT("bitrate", env->out.bitrate);
+        CV_UINT("qmin", env->out.qmin);
+	CV_STR("videocodec", env->codec_name);
+	return 1;	/* nothing found */
+
+	CV_END;		/* the 'nothing found' case */
 	return 0;		/* found something */
 }
-#ifdef _UNDO_M_START
-#undef M_START
-#undef M_END
-#undef M_F
-#undef M_BOOL
-#undef M_UINT
-#undef M_STR
-#undef _UNDO_M_START
-#endif
 
 #endif	/* video support */
diff --git a/include/asterisk/config.h b/include/asterisk/config.h
index ebc71fb8a91789b71565c5e1f106c2a0df415eff..7a2d10135e908cb3dea54fbd6dbda56cc68dd5fa 100644
--- a/include/asterisk/config.h
+++ b/include/asterisk/config.h
@@ -271,6 +271,7 @@ int ast_variable_update(struct ast_category *category, const char *variable,
 int config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator);
 
 struct ast_config *ast_config_internal_load(const char *configfile, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl_file);
+
 /*! \brief Support code to parse config file arguments
  *
  * The function ast_parse_arg() provides a generic interface to parse
@@ -358,6 +359,45 @@ enum ast_parse_flags {
 int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
         void *result, ...);
 
+/*
+ * Parsing config file options in C is slightly annoying because we cannot use
+ * string in a switch() statement, yet we need a similar behaviour, with many
+ * branches and a break on a matching one.
+ * The following somehow simplifies the job: we create a block using
+ * the 	CV_START and CV_END macros, and then within the block we can run
+ * actions such as "if (condition) { body; break; }"
+ * Additional macros are present to run simple functions (e.g. ast_copy_string)
+ * or to pass arguments to ast_parse_arg()
+ *
+ * As an example:
+
+	CV_START(v->name, v->value);	// start the block
+	CV_STR("foo", x_foo);		// static string
+	CV_DSTR("bar", y_bar);		// malloc'ed string
+	CV_F("bar", ...);		// call a generic function
+	CV_END;				// end the block
+ */
+
+/*! \brief the macro to open a block for variable parsing */
+#define CV_START(__in_var, __in_val) 		\
+	do {					\
+		const char *__var = __in_var;	\
+		const char *__val = __in_val;
+
+/*! \brief close a variable parsing block */
+#define	CV_END			} while (0)
+
+/*! \brief call a generic function if the name matches. */
+#define	CV_F(__pattern, __body)	if (!strcasecmp((__var), __pattern)) { __body; break; }
+
+/*! \brief helper macros to assign the value to a BOOL, UINT, static string and
+ * dynamic string
+ */
+#define	CV_BOOL(__x, __dst)	CV_F(__x, (__dst) = ast_true(__val) )
+#define CV_UINT(__x, __dst)	CV_F(__x, (__dst) = strtoul(__val, NULL, 0) )
+#define CV_STR(__x, __dst)	CV_F(__x, ast_copy_string(__dst, __val, sizeof(__dst)))
+#define CV_DSTR(__x, __dst)	CV_F(__x, if (__dst) ast_free(__dst); __dst = ast_strdup(__val))
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif