/*
libparted - a library for manipulating disk partitions
Copyright (C) 2005, 2007, 2009-2010 Free Software Foundation, Inc.
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file unit.c */
/**
* \addtogroup PedUnit
*
* \brief The PedUnit module provides a standard mechanism for describing
* and parsing locations within devices in human-friendly plain text.
*
* Internally, libparted uses PedSector (which is typedef'ed to be long long
* end of partitions. However, sector numbers are often long and unintuitive.
* For example, my extended partition starts at sector 208845. PedUnit allows
* this location to be represented in more intutitive ways, including "106Mb",
* "0Gb" and "0%", as well as "208845s". PedUnit aims to provide facilities
* to provide a consistent system for describing device locations all
* throughout libparted.
*
* PedUnit provides two basic services: converting a PedSector into a text
* representation, and parsing a text representation into a PedSector.
* PedUnit currently supports these units:
*
* sectors, bytes, kilobytes, megabytes, gigabytes, terabytes, compact,
* cylinder and percent.
*
* PedUnit has a global variable that contains the default unit for all
* conversions.
*
* @{
*/
#include <config.h>
#include <ctype.h>
#include <stdio.h>
#include <float.h>
#if ENABLE_NLS
# include <libintl.h>
#else
#endif /* ENABLE_NLS */
static const char* unit_names[] = {
"s",
"B",
"kB",
"MB",
"GB",
"TB",
"compact",
"cyl",
"chs",
"%",
"kiB",
"MiB",
"GiB",
"TiB"
};
/**
* \brief Set the default \p unit used by subsequent calls to the PedUnit API.
*
* In particular, this affects how locations inside error messages
* (exceptions) are displayed.
*/
void
{
default_unit = unit;
}
/**
* \brief Get the current default unit.
*/
{
return default_unit;
}
/**
* Get the byte size of a given \p unit.
*/
long long
{
switch (unit) {
case PED_UNIT_BYTE: return 1;
case PED_UNIT_KILOBYTE: return PED_KILOBYTE_SIZE;
case PED_UNIT_MEGABYTE: return PED_MEGABYTE_SIZE;
case PED_UNIT_GIGABYTE: return PED_GIGABYTE_SIZE;
case PED_UNIT_TERABYTE: return PED_TERABYTE_SIZE;
case PED_UNIT_KIBIBYTE: return PED_KIBIBYTE_SIZE;
case PED_UNIT_MEBIBYTE: return PED_MEBIBYTE_SIZE;
case PED_UNIT_GIBIBYTE: return PED_GIBIBYTE_SIZE;
case PED_UNIT_TEBIBYTE: return PED_TEBIBYTE_SIZE;
case PED_UNIT_PERCENT:
case PED_UNIT_COMPACT:
_("Cannot get unit size for special unit "
"'COMPACT'."));
return 0;
}
/* never reached */
PED_ASSERT(0, return 0);
return 0;
}
/**
* Get a textual (non-internationalized) representation of a \p unit.
*
* For example, the textual representation of PED_UNIT_SECTOR is "s".
*/
const char*
{
return unit_names[unit];
}
/**
* Get a unit based on its textual representation: \p unit_name.
*
* For example, ped_unit_get_by_name("Mb") returns PED_UNIT_MEGABYTE.
*/
{
return unit;
}
return -1;
}
static char*
{
char *result;
if (!result)
return NULL;
return result;
}
/**
* \brief Get a string that describes the location of the \p byte on
* device \p dev.
*
* The string is described with the desired \p unit.
* The returned string must be freed with free().
*/
char*
{
double d, w;
int p;
/* CHS has a special comma-separated format. */
if (unit == PED_UNIT_CHS) {
return ped_strdup (buf);
}
/* Cylinders, sectors and bytes should be rounded down... */
if (unit == PED_UNIT_CYLINDER
|| unit == PED_UNIT_SECTOR
|| unit == PED_UNIT_BYTE) {
return ped_strdup (buf);
}
if (unit == PED_UNIT_COMPACT) {
else
}
/* IEEE754 says that 100.5 has to be rounded to 100 (by printf) */
/* but 101.5 has to be rounded to 102... so we multiply by 1+E. */
/* This just divide by 2 the natural IEEE754 extended precision */
/* and won't cause any trouble before 1000 TB */
* (1. + DBL_EPSILON);
w = d + ( (d < 10. ) ? 0.005 :
(d < 100.) ? 0.05 :
0.5 );
p = (w < 10. ) ? 2 :
(w < 100.) ? 1 :
0 ;
#ifdef __BEOS__
#else
#endif
return ped_strdup (buf);
}
/**
* \brief Get a string that describes the location of the \p byte on
* device \p dev.
*
* The string is described with the default unit, which is set
* by ped_unit_set_default().
* The returned string must be freed with free().
*/
char*
{
}
/**
* \brief Get a string that describes the location \p sector on device \p dev.
*
* The string is described with the desired \p unit.
* The returned string must be freed with free().
*/
char*
{
}
/**
* \brief Get a string that describes the location \p sector on device \p dev.
*
* The string is described with the default unit, which is set
* by ped_unit_set_default().
* The returned string must be freed with free().
*/
char*
{
}
/**
* If \p str contains a valid description of a location on \p dev,
* then \p *sector is modified to describe the location and a geometry
* is created in \p *range describing a 2 units large area centered on
* \p *sector. If the \p range as described here would be partially outside
* the device \p dev, the geometry returned is the intersection between the
* former and the whole device geometry. If no units are specified, then the
* default unit is assumed.
*
* \return \c 1 if \p str is a valid location description, \c 0 otherwise
*/
int
PedGeometry** range)
{
}
/* Inefficiently removes all spaces from a string, in-place. */
static void
{
int i;
for (i = 0; str[i] != 0; i++) {
int j;
for (j = i + 1; str[j] != 0; j++)
}
}
}
/* Find non-number suffix. Eg: find_suffix("32Mb") returns a pointer to
* "Mb". */
static char*
{
str++;
return (char *) str;
}
static void
{
int i = 0;
for (i = 0; str[i]; i++) {
str[i] = ' ';
}
}
static int
{
int punct_count = 0;
int i = 0;
for (i = 0; str[i]; i++)
return punct_count == 2;
}
static int
PedGeometry** range)
{
if (!copy)
return 0;
strip_string (copy);
remove_punct (copy);
_("\"%s\" has invalid syntax for locations."),
copy);
goto error_free_copy;
}
_("The maximum head value is %d."),
goto error_free_copy;
}
_("The maximum sector value is %d."),
goto error_free_copy;
}
_("The location %s is outside of the "
"device %s."),
goto error_free_copy;
}
if (range)
*sector = 0;
if (range)
return 0;
}
static PedSector
{
if (sector < 0)
return 0;
return sector;
}
static PedGeometry*
{
return NULL;
}
static PedUnit
{
case 'k': return PED_UNIT_KIBIBYTE;
case 'm': return PED_UNIT_MEBIBYTE;
case 'g': return PED_UNIT_GIBIBYTE;
case 't': return PED_UNIT_TEBIBYTE;
}
case 's': return PED_UNIT_SECTOR;
case 'b': return PED_UNIT_BYTE;
case 'k': return PED_UNIT_KILOBYTE;
case 'm': return PED_UNIT_MEGABYTE;
case 'g': return PED_UNIT_GIGABYTE;
case 't': return PED_UNIT_TERABYTE;
case 'c': return PED_UNIT_CYLINDER;
case '%': return PED_UNIT_PERCENT;
}
}
if (suggested_unit == PED_UNIT_COMPACT) {
if (default_unit == PED_UNIT_COMPACT)
return PED_UNIT_MEGABYTE;
else
return default_unit;
}
return suggested_unit;
}
/**
* If \p str contains a valid description of a location on \p dev, then
* \p *sector is modified to describe the location and a geometry is created
* in \p *range describing a 2 units large area centered on \p *sector. If the
* \p range as described here would be partially outside the device \p dev, the
* geometry returned is the intersection between the former and the whole
* device geometry. If no units are specified, then the default unit is
* assumed.
*
* \throws PED_EXCEPTION_ERROR if \p str contains invalid description of a
* location
* \throws PED_EXCEPTION_ERROR if location described by \p str
* is outside of the device \p dev->path
*
* \return \c 1 if \p str is a valid location description, \c 0 otherwise.
*/
int
{
char* copy;
char* suffix;
double num;
long long unit_size;
if (!copy)
goto error;
strip_string (copy);
suffix[0] = 0;
_("Invalid number."));
goto error_free_copy;
}
if (radius < 0)
radius = 0;
/* negative numbers count from the end */
if (copy[0] == '-')
if (range) {
if (!*range) {
_("The location %s is outside of the "
"device %s."),
goto error_free_copy;
}
}
return 1;
*sector = 0;
if (range)
return 0;
}
/** @} */