myRecipeFile Ingredient Measure Conversion and "Normalization"

I wrote this demonstration program to flesh out some ideas I had
about "normalization" of the odd ingredient amounts that can result
from resizing a recipe, or from converting recipe amounts from one
scale to another.

The demonstration program takes commandline options to specify
the measurement unit (it's "dimension", it's specific "scale" and
"unit", and it's amount), and (optionally) a new "scale" to convert
the measurement to. The program outputs the (optionally, converted)
amount in it's "normalized" form.

As the target application uses a database to hold measurement scale
information and relations, this program does as well. In this case,
two tables (the "measure" table, and the "conversion" table) provide
the necessary data for the conversion/normalization process.

To compile:
  make
which will build the "normalize" executable. You will need the
Mysql C Connector library installed to complete linkage step.

To build the tables, etc
1) allocate a mysql user under which the db queries will run
2) create a mysql database under which the db tables will live
3) create and load the two tables and their contents:
	CREATE TABLE `measure` (
	  `measure_id` smallint(5) unsigned NOT NULL,
	  `measure_dimension` enum('Count','Weight','Volume') NOT NULL,
	  `measure_scale` enum('Metric','Imperial','US','Other') NOT NULL,
	  `measure_unit` varchar(15) NOT NULL,
	  `measure_abbr` varchar(6) DEFAULT NULL,
	  PRIMARY KEY (`measure_id`)
	) ENGINE=InnoDB DEFAULT CHARSET=ascii COMMENT='Holds values for preset measurement units';

	LOCK TABLES `measure` WRITE;
	INSERT INTO `measure` VALUES (1,'Weight','Metric','Gram','g');
	INSERT INTO `measure` VALUES (2,'Weight','Metric','Kilogram','kg');
	INSERT INTO `measure` VALUES (3,'Volume','Metric','Millilitre','ml');
	INSERT INTO `measure` VALUES (4,'Volume','Metric','Litre','l');
	INSERT INTO `measure` VALUES (5,'Weight','Imperial','Ounce','oz');
	INSERT INTO `measure` VALUES (6,'Weight','Imperial','Pound','lb');
	INSERT INTO `measure` VALUES (7,'Volume','Imperial','Pinch','pn');
	INSERT INTO `measure` VALUES (8,'Volume','Imperial','Teaspoon','tsp');
	INSERT INTO `measure` VALUES (9,'Volume','Imperial','Tablespoon','tbsp');
	INSERT INTO `measure` VALUES (10,'Volume','Imperial','Fluid Ounce','fl oz');
	INSERT INTO `measure` VALUES (11,'Volume','Imperial','Cup','c');
	INSERT INTO `measure` VALUES (12,'Volume','Imperial','Pint','pt');
	INSERT INTO `measure` VALUES (13,'Volume','Imperial','Quart','qt');
	INSERT INTO `measure` VALUES (14,'Volume','Imperial','Gallon','gal');
	INSERT INTO `measure` VALUES (15,'Weight','US','Ounce','oz');
	INSERT INTO `measure` VALUES (16,'Weight','US','Pound','lb');
	INSERT INTO `measure` VALUES (17,'Volume','US','Pinch','pn');
	INSERT INTO `measure` VALUES (18,'Volume','US','Teaspoon','tsp');
	INSERT INTO `measure` VALUES (19,'Volume','US','Tablespoon','tbsp');
	INSERT INTO `measure` VALUES (20,'Volume','US','Fluid Ounce','fl oz');
	INSERT INTO `measure` VALUES (21,'Volume','US','Cup','c');
	INSERT INTO `measure` VALUES (22,'Volume','US','Pint','pt');
	INSERT INTO `measure` VALUES (23,'Volume','US','Quart','qt');
	INSERT INTO `measure` VALUES (24,'Volume','US','Gallon','gal');
	UNLOCK TABLES;

	CREATE TABLE `conversion` (
	  `conv_f_measure` smallint(5) unsigned NOT NULL,
	  `conv_t_measure` smallint(5) unsigned NOT NULL,
	  `conv_factor` double NOT NULL,
	  PRIMARY KEY (`conv_f_measure`,`conv_t_measure`),
	  KEY `conv_t_measure` (`conv_t_measure`),
	  CONSTRAINT `conversion_ibfk_1` FOREIGN KEY (`conv_f_measure`) REFERENCES `measure` (`measure_id`),
	  CONSTRAINT `conversion_ibfk_2` FOREIGN KEY (`conv_t_measure`) REFERENCES `measure` (`measure_id`)
	) ENGINE=InnoDB DEFAULT CHARSET=ascii COMMENT='Convert one unit of measure to another';

	LOCK TABLES `conversion` WRITE;
	INSERT INTO `conversion` VALUES (2,1,1000);
	INSERT INTO `conversion` VALUES (3,7,1.3514905027);
	INSERT INTO `conversion` VALUES (3,17,1.6230730897);
	INSERT INTO `conversion` VALUES (4,3,1000);
	INSERT INTO `conversion` VALUES (5,1,28.349523125);
	INSERT INTO `conversion` VALUES (6,5,16);
	INSERT INTO `conversion` VALUES (7,17,1.2009504226);
	INSERT INTO `conversion` VALUES (8,7,8);
	INSERT INTO `conversion` VALUES (9,8,3);
	INSERT INTO `conversion` VALUES (10,11,0.1);
	INSERT INTO `conversion` VALUES (11,9,16);
	INSERT INTO `conversion` VALUES (12,11,2);
	INSERT INTO `conversion` VALUES (13,12,2);
	INSERT INTO `conversion` VALUES (14,13,4);
	INSERT INTO `conversion` VALUES (15,1,28.349523125);
	INSERT INTO `conversion` VALUES (15,5,1);
	INSERT INTO `conversion` VALUES (16,15,16);
	INSERT INTO `conversion` VALUES (18,17,8);
	INSERT INTO `conversion` VALUES (19,18,3);
	INSERT INTO `conversion` VALUES (20,21,0.125);
	INSERT INTO `conversion` VALUES (21,19,16);
	INSERT INTO `conversion` VALUES (22,21,2);
	INSERT INTO `conversion` VALUES (23,22,2);
	INSERT INTO `conversion` VALUES (24,23,4);
	UNLOCK TABLES;
4) authorize the selected user for SELECT access to the two tables


To invoke, see the "usage" message.
   $ ./normalize
   Usage: normalize [-h dbm_host] [-d database] -u user -p password dimension amount scale unit [to_scale]
   $

where:	-h dbm_host	specifies the networking hostname of the dbms system
			optional, defaults to "localhost"
	-d database	speficies the dbms database name
			optional, defaults to "myRecipeFile"
	-u user		specifies the dbms username qualified for SELECT access on the database,
	-p password	specifies the dbms password for the specified dbms username
	dimension	specifies the normalization/conversion dimension ("Volume" or "Weight")
	amount		specifies, in decimal form, the normalization/conversion original amount
	scale		specifies the normalization/conversion original measurement scale
			currently, only "Imperial", "US", and "Metric" are supported by the database
	unit		specifies the normalization/conversion original measurement unit-of-measure
			must be a unit-of-measure appropriate to the scale selected
	to_scale	specifies the conversion target measurement scale (optional, invokes conversion)
			currently, only "Imperial", "US", and "Metric" are supported by the database
For example:

	$ ./normalize -u myusername -p mypassword Weight 12.345 Imperial Pound Metric
	12.345000       Imperial Pound converts to
	   5.000        Metric Kilogram
	  600.000       Metric Gram

	$ ./normalize -u myusername -p mypassword Volume 6.3456 US Tablespoon Imperial
	6.345600        US Tablespoon converts to
	   5.000        Imperial Tablespoon
	   7.000        Imperial Pinch

	$ ./normalize -u myusername -p mypassword Volume 6.3456 US Tablespoon         
	6.345600        US Tablespoon normalizes to
	   6.000        US Tablespoon
	   1.000        US Teaspoon

	$

Copyright Lew Pitcher (lew.pitcher@digitalfreehold.ca) 2026-07-22
