util.c revision fbfaf8f3
143f32c10Smrg/* 243f32c10SmrgCopyright (c) 2002-2003 by Juliusz Chroboczek 343f32c10Smrg 443f32c10SmrgPermission is hereby granted, free of charge, to any person obtaining a copy 543f32c10Smrgof this software and associated documentation files (the "Software"), to deal 643f32c10Smrgin the Software without restriction, including without limitation the rights 743f32c10Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell 843f32c10Smrgcopies of the Software, and to permit persons to whom the Software is 943f32c10Smrgfurnished to do so, subject to the following conditions: 1043f32c10Smrg 1143f32c10SmrgThe above copyright notice and this permission notice shall be included in 1243f32c10Smrgall copies or substantial portions of the Software. 1343f32c10Smrg 1443f32c10SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1543f32c10SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1643f32c10SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1743f32c10SmrgAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1843f32c10SmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1943f32c10SmrgOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2043f32c10SmrgTHE SOFTWARE. 2143f32c10Smrg*/ 2243f32c10Smrg/* $XdotOrg: xc/programs/fonttosfnt/util.c,v 1.11 2003/12/19 02:16:36 dawes Exp $ */ 2343f32c10Smrg/* $XFree86: xc/programs/fonttosfnt/util.c,v 1.10 2003/12/19 02:05:39 dawes Exp $ */ 2443f32c10Smrg 2543f32c10Smrg#include <time.h> 2643f32c10Smrg#include <string.h> 2743f32c10Smrg#include <errno.h> 2843f32c10Smrg#include <stdlib.h> 2943f32c10Smrg#ifndef __UNIXOS2__ 3043f32c10Smrg# include <math.h> 3143f32c10Smrg#else 3243f32c10Smrg# include <float.h> 3343f32c10Smrg#endif 3443f32c10Smrg#include <stdarg.h> 3543f32c10Smrg 3643f32c10Smrg#include <ft2build.h> 3743f32c10Smrg#include FT_FREETYPE_H 3843f32c10Smrg#include FT_BDF_H 3943f32c10Smrg#include "X11/Xos.h" 40ea148d1dSmrg#include "X11/Xfuncproto.h" /* for _X_ATTRIBUTE_PRINTF */ 4143f32c10Smrg#include "fonttosfnt.h" 4243f32c10Smrg 4343f32c10Smrg#ifdef NEED_SNPRINTF 4443f32c10Smrg#undef SCOPE 4543f32c10Smrg#define SCOPE static 4643f32c10Smrg#include "snprintf.c" 4743f32c10Smrg#endif 4843f32c10Smrg 4943f32c10Smrg#ifdef __GLIBC__ 5043f32c10Smrg#define HAVE_TIMEGM 5143f32c10Smrg#define HAVE_TM_GMTOFF 5243f32c10Smrg#endif 5343f32c10Smrg 5443f32c10Smrg#ifdef BSD 5543f32c10Smrg#define HAVE_TM_GMTOFF 5643f32c10Smrg#define GMTOFFMEMBER tm_gmtoff 5743f32c10Smrg#endif 5843f32c10Smrg 5943f32c10Smrg#ifdef __SCO__ 6043f32c10Smrg#define HAVE_TM_GMTOFF 6143f32c10Smrg#define GMTOFFMEMBER tm_tzadj 6243f32c10Smrg#endif 6343f32c10Smrg 6443f32c10Smrg/* That's in POSIX */ 6543f32c10Smrg#define HAVE_TZSET 6643f32c10Smrg 6743f32c10Smrg#ifdef NEED_SETENV 6843f32c10Smrgextern int setenv(const char *name, const char *value, int overwrite); 6943f32c10Smrgextern void unsetenv(const char *name); 7043f32c10Smrg#endif 7143f32c10Smrg 7243f32c10Smrgchar* 736ef05171Smrgsprintf_alloc(const char *f, ...) 7443f32c10Smrg{ 7543f32c10Smrg char *s; 7643f32c10Smrg va_list args; 7743f32c10Smrg va_start(args, f); 7843f32c10Smrg s = vsprintf_alloc(f, args); 7943f32c10Smrg va_end(args); 8043f32c10Smrg return s; 8143f32c10Smrg} 8243f32c10Smrg 8343f32c10Smrg#if HAVE_VASPRINTF 84ea148d1dSmrg_X_ATTRIBUTE_PRINTF(1, 0) 8543f32c10Smrgchar* 866ef05171Smrgvsprintf_alloc(const char *f, va_list args) 8743f32c10Smrg{ 8843f32c10Smrg char *r; 8943f32c10Smrg int rc; 9043f32c10Smrg 9143f32c10Smrg rc = vasprintf(&r, f, args); 9243f32c10Smrg if(rc < 0) 9343f32c10Smrg return NULL; 9443f32c10Smrg return r; 9543f32c10Smrg} 9643f32c10Smrg#else 97ea148d1dSmrg_X_ATTRIBUTE_PRINTF(1, 0) 9843f32c10Smrgchar* 996ef05171Smrgvsprintf_alloc(const char *f, va_list args) 10043f32c10Smrg{ 10143f32c10Smrg int n, size = 12; 10243f32c10Smrg char *string; 103fbfaf8f3Smrg#if HAVE_DECL_VA_COPY 10443f32c10Smrg va_list args_copy; 105fbfaf8f3Smrg#endif 10643f32c10Smrg 10743f32c10Smrg while(1) { 10843f32c10Smrg if(size > 4096) 10943f32c10Smrg return NULL; 11043f32c10Smrg string = malloc(size); 11143f32c10Smrg if(!string) 11243f32c10Smrg return NULL; 11343f32c10Smrg 11443f32c10Smrg#if HAVE_DECL_VA_COPY 11543f32c10Smrg va_copy(args_copy, args); 11643f32c10Smrg n = vsnprintf(string, size, f, args_copy); 11743f32c10Smrg#else 11843f32c10Smrg n = vsnprintf(string, size, f, args); 11943f32c10Smrg#endif 12043f32c10Smrg if(n >= 0 && n < size) 12143f32c10Smrg return string; 12243f32c10Smrg else if(n >= size) 12343f32c10Smrg size = n + 1; 12443f32c10Smrg else 12543f32c10Smrg size = size * 3 / 2 + 1; 12643f32c10Smrg free(string); 12743f32c10Smrg } 12843f32c10Smrg /* NOTREACHED */ 12943f32c10Smrg} 13043f32c10Smrg#endif 13143f32c10Smrg 132ea148d1dSmrg/* Build a UTF-16 string from a Latin-1 string. 13343f32c10Smrg Result is not NUL-terminated. */ 13443f32c10Smrgchar * 1356ef05171SmrgmakeUTF16(const char *string) 13643f32c10Smrg{ 13743f32c10Smrg int n = strlen(string); 13843f32c10Smrg char *value = malloc(2 * n); 13943f32c10Smrg if(!value) 14043f32c10Smrg return NULL; 141fbfaf8f3Smrg for(int i = 0; i < n; i++) { 14243f32c10Smrg value[2 * i] = '\0'; 14343f32c10Smrg value[2 * i + 1] = string[i]; 14443f32c10Smrg } 14543f32c10Smrg return value; 14643f32c10Smrg} 14743f32c10Smrg 14843f32c10Smrg/* Like mktime(3), but UTC rather than local time */ 14943f32c10Smrg#if defined(HAVE_TIMEGM) 15043f32c10Smrgstatic time_t 15143f32c10Smrgmktime_gmt(struct tm *tm) 15243f32c10Smrg{ 15343f32c10Smrg return timegm(tm); 15443f32c10Smrg} 15543f32c10Smrg#elif defined(HAVE_TM_GMTOFF) 15643f32c10Smrgstatic time_t 15743f32c10Smrgmktime_gmt(struct tm *tm) 15843f32c10Smrg{ 15943f32c10Smrg time_t t; 16043f32c10Smrg struct tm *ltm; 16143f32c10Smrg 16243f32c10Smrg t = mktime(tm); 16343f32c10Smrg if(t < 0) 16443f32c10Smrg return -1; 16543f32c10Smrg ltm = localtime(&t); 16643f32c10Smrg if(ltm == NULL) 16743f32c10Smrg return -1; 16843f32c10Smrg return t + ltm->GMTOFFMEMBER; 16943f32c10Smrg} 17043f32c10Smrg#elif defined(HAVE_TZSET) 17143f32c10Smrg/* Taken from the Linux timegm(3) man page */ 17243f32c10Smrgstatic time_t 17343f32c10Smrgmktime_gmt(struct tm *tm) 17443f32c10Smrg{ 17543f32c10Smrg time_t t; 17643f32c10Smrg char *tz; 17743f32c10Smrg 17843f32c10Smrg tz = getenv("TZ"); 17943f32c10Smrg setenv("TZ", "", 1); 18043f32c10Smrg tzset(); 18143f32c10Smrg t = mktime(tm); 18243f32c10Smrg if(tz) 18343f32c10Smrg setenv("TZ", tz, 1); 18443f32c10Smrg else 18543f32c10Smrg unsetenv("TZ"); 18643f32c10Smrg tzset(); 18743f32c10Smrg return t; 18843f32c10Smrg} 18943f32c10Smrg#else 19043f32c10Smrg#error no mktime_gmt implementation on this platform 19143f32c10Smrg#endif 19243f32c10Smrg 19343f32c10Smrg/* Return the current time as a signed 64-bit number of seconds since 19443f32c10Smrg midnight, 1 January 1904. This is apparently when the Macintosh 19543f32c10Smrg was designed. */ 19643f32c10Smrgint 19743f32c10SmrgmacTime(int *hi, unsigned *lo) 19843f32c10Smrg{ 19943f32c10Smrg unsigned long diff; /* Not time_t */ 20043f32c10Smrg time_t macEpoch, current; 20143f32c10Smrg struct tm tm; 20243f32c10Smrg tm.tm_sec = 0; 20343f32c10Smrg tm.tm_min = 0; 20443f32c10Smrg tm.tm_hour = 0; 20543f32c10Smrg tm.tm_mday = 1; 20643f32c10Smrg tm.tm_mon = 1; 20743f32c10Smrg tm.tm_year = 4; 20843f32c10Smrg tm.tm_isdst = -1; 20943f32c10Smrg 21043f32c10Smrg macEpoch = mktime_gmt(&tm); 211c813b494Smrg if(macEpoch == -1) return -1; 21243f32c10Smrg 21343f32c10Smrg current = time(NULL); 214c813b494Smrg if(current == -1) 21543f32c10Smrg return -1; 21643f32c10Smrg 21743f32c10Smrg if(current < macEpoch) { 21843f32c10Smrg errno = EINVAL; 21943f32c10Smrg return -1; 22043f32c10Smrg } 22143f32c10Smrg 22243f32c10Smrg diff = current - macEpoch; 22343f32c10Smrg#if INT_MAX == LONG_MAX 22443f32c10Smrg *hi = 0; 22543f32c10Smrg#else 22643f32c10Smrg *hi = diff >> 32; 22743f32c10Smrg#endif 22843f32c10Smrg *lo = diff & 0xFFFFFFFF; 22943f32c10Smrg return 0; 23043f32c10Smrg} 23143f32c10Smrg 23243f32c10Smrgunsigned 23343f32c10SmrgfaceFoundry(FT_Face face) 23443f32c10Smrg{ 23543f32c10Smrg int rc; 23643f32c10Smrg BDF_PropertyRec prop; 23743f32c10Smrg 23843f32c10Smrg rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop); 239ea148d1dSmrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) { 24043f32c10Smrg if(strcasecmp(prop.u.atom, "adobe") == 0) 24143f32c10Smrg return makeName("ADBE"); 24243f32c10Smrg else if(strcasecmp(prop.u.atom, "agfa") == 0) 24343f32c10Smrg return makeName("AGFA"); 24443f32c10Smrg else if(strcasecmp(prop.u.atom, "altsys") == 0) 24543f32c10Smrg return makeName("ALTS"); 24643f32c10Smrg else if(strcasecmp(prop.u.atom, "apple") == 0) 24743f32c10Smrg return makeName("APPL"); 24843f32c10Smrg else if(strcasecmp(prop.u.atom, "arphic") == 0) 24943f32c10Smrg return makeName("ARPH"); 25043f32c10Smrg else if(strcasecmp(prop.u.atom, "alltype") == 0) 25143f32c10Smrg return makeName("ATEC"); 25243f32c10Smrg else if(strcasecmp(prop.u.atom, "b&h") == 0) 25343f32c10Smrg return makeName("B&H "); 25443f32c10Smrg else if(strcasecmp(prop.u.atom, "bitstream") == 0) 25543f32c10Smrg return makeName("BITS"); 25643f32c10Smrg else if(strcasecmp(prop.u.atom, "dynalab") == 0) 25743f32c10Smrg return makeName("DYNA"); 25843f32c10Smrg else if(strcasecmp(prop.u.atom, "ibm") == 0) 25943f32c10Smrg return makeName("IBM "); 26043f32c10Smrg else if(strcasecmp(prop.u.atom, "itc") == 0) 26143f32c10Smrg return makeName("ITC "); 26243f32c10Smrg else if(strcasecmp(prop.u.atom, "interleaf") == 0) 26343f32c10Smrg return makeName("LEAF"); 26443f32c10Smrg else if(strcasecmp(prop.u.atom, "impress") == 0) 26543f32c10Smrg return makeName("IMPR"); 26643f32c10Smrg else if(strcasecmp(prop.u.atom, "larabiefonts") == 0) 26743f32c10Smrg return makeName("LARA"); 26843f32c10Smrg else if(strcasecmp(prop.u.atom, "linotype") == 0) 26943f32c10Smrg return makeName("LINO"); 27043f32c10Smrg else if(strcasecmp(prop.u.atom, "monotype") == 0) 27143f32c10Smrg return makeName("MT "); 27243f32c10Smrg else if(strcasecmp(prop.u.atom, "microsoft") == 0) 27343f32c10Smrg return makeName("MS "); 27443f32c10Smrg else if(strcasecmp(prop.u.atom, "urw") == 0) 27543f32c10Smrg return makeName("URW "); 27643f32c10Smrg else if(strcasecmp(prop.u.atom, "y&y") == 0) 27743f32c10Smrg return makeName("Y&Y "); 278c813b494Smrg else { 279c813b494Smrg char buf[5]; 280c813b494Smrg snprintf(buf, sizeof(buf), "%-4s", prop.u.atom); 281c813b494Smrg return makeName(buf); 282c813b494Smrg } 28343f32c10Smrg } 28443f32c10Smrg /* For now */ 28543f32c10Smrg return makeName("UNKN"); 28643f32c10Smrg} 287ea148d1dSmrg 28843f32c10Smrg 28943f32c10Smrgint 29043f32c10SmrgfaceWeight(FT_Face face) 29143f32c10Smrg{ 29243f32c10Smrg int rc; 29343f32c10Smrg BDF_PropertyRec prop; 29443f32c10Smrg rc = FT_Get_BDF_Property(face, "WEIGHT_NAME", &prop); 295ea148d1dSmrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) { 29643f32c10Smrg if(strcasecmp(prop.u.atom, "thin") == 0) 29743f32c10Smrg return 100; 29843f32c10Smrg else if(strcasecmp(prop.u.atom, "extralight") == 0) 29943f32c10Smrg return 200; 30043f32c10Smrg else if(strcasecmp(prop.u.atom, "light") == 0) 30143f32c10Smrg return 300; 30243f32c10Smrg else if(strcasecmp(prop.u.atom, "medium") == 0) 303c813b494Smrg return 400; 30443f32c10Smrg else if(strcasecmp(prop.u.atom, "semibold") == 0) 30543f32c10Smrg return 600; 30643f32c10Smrg else if(strcasecmp(prop.u.atom, "bold") == 0) 30743f32c10Smrg return 700; 30843f32c10Smrg else if(strcasecmp(prop.u.atom, "extrabold") == 0) 30943f32c10Smrg return 800; 31043f32c10Smrg else if(strcasecmp(prop.u.atom, "black") == 0) 31143f32c10Smrg return 900; 31243f32c10Smrg else 313c813b494Smrg return 400; 31443f32c10Smrg } else 315c813b494Smrg return 400; /* for now */ 31643f32c10Smrg} 31743f32c10Smrg 31843f32c10Smrgint 31943f32c10SmrgfaceWidth(FT_Face face) 32043f32c10Smrg{ 32143f32c10Smrg int rc; 32243f32c10Smrg BDF_PropertyRec prop; 32343f32c10Smrg rc = FT_Get_BDF_Property(face, "SETWIDTH_NAME", &prop); 324ea148d1dSmrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) { 32543f32c10Smrg if(strcasecmp(prop.u.atom, "ultracondensed") == 0) 32643f32c10Smrg return 1; 32743f32c10Smrg else if(strcasecmp(prop.u.atom, "extracondensed") == 0) 32843f32c10Smrg return 2; 32943f32c10Smrg else if(strcasecmp(prop.u.atom, "condensed") == 0) 33043f32c10Smrg return 3; 33143f32c10Smrg else if(strcasecmp(prop.u.atom, "semicondensed") == 0) 33243f32c10Smrg return 4; 33343f32c10Smrg else if(strcasecmp(prop.u.atom, "normal") == 0) 33443f32c10Smrg return 5; 33543f32c10Smrg else if(strcasecmp(prop.u.atom, "semiexpanded") == 0) 33643f32c10Smrg return 6; 33743f32c10Smrg else if(strcasecmp(prop.u.atom, "expanded") == 0) 33843f32c10Smrg return 7; 33943f32c10Smrg else if(strcasecmp(prop.u.atom, "extraexpanded") == 0) 34043f32c10Smrg return 8; 34143f32c10Smrg else if(strcasecmp(prop.u.atom, "ultraexpanded") == 0) 34243f32c10Smrg return 9; 34343f32c10Smrg else 34443f32c10Smrg return 5; 34543f32c10Smrg } else 34643f32c10Smrg return 5; /* for now */ 34743f32c10Smrg} 34843f32c10Smrg 34943f32c10Smrgint 35043f32c10SmrgfaceItalicAngle(FT_Face face) 35143f32c10Smrg{ 35243f32c10Smrg int rc; 35343f32c10Smrg BDF_PropertyRec prop; 35443f32c10Smrg 35543f32c10Smrg rc = FT_Get_BDF_Property(face, "ITALIC_ANGLE", &prop); 35643f32c10Smrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) { 35743f32c10Smrg return (prop.u.integer - 64 * 90) * (TWO_SIXTEENTH / 64); 35843f32c10Smrg } 35943f32c10Smrg 36043f32c10Smrg rc = FT_Get_BDF_Property(face, "SLANT", &prop); 361ea148d1dSmrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) { 36243f32c10Smrg if(strcasecmp(prop.u.atom, "i") == 0 || 36343f32c10Smrg strcasecmp(prop.u.atom, "s") == 0) 36443f32c10Smrg return -30 * TWO_SIXTEENTH; 36543f32c10Smrg else 36643f32c10Smrg return 0; 36743f32c10Smrg } else 36843f32c10Smrg return 0; /* for now */ 36943f32c10Smrg} 37043f32c10Smrg 37143f32c10Smrgint 37243f32c10SmrgfaceFlags(FT_Face face) 37343f32c10Smrg{ 37443f32c10Smrg int flags = 0; 37543f32c10Smrg BDF_PropertyRec prop; 37643f32c10Smrg int rc; 37743f32c10Smrg 37843f32c10Smrg if(faceWeight(face) >= 650) 37943f32c10Smrg flags |= FACE_BOLD; 38043f32c10Smrg rc = FT_Get_BDF_Property(face, "SLANT", &prop); 381ea148d1dSmrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) { 38243f32c10Smrg if(strcasecmp(prop.u.atom, "i") == 0 || 38343f32c10Smrg strcasecmp(prop.u.atom, "s") == 0) 38443f32c10Smrg flags |= FACE_ITALIC; 38543f32c10Smrg } 38643f32c10Smrg return flags; 38743f32c10Smrg} 38843f32c10Smrg 389c813b494Smrgint 390c813b494SmrgfaceIntProp(FT_Face face, const char *name) 391c813b494Smrg{ 392c813b494Smrg int rc; 393c813b494Smrg BDF_PropertyRec prop; 394c813b494Smrg 395c813b494Smrg rc = FT_Get_BDF_Property(face, name, &prop); 396c813b494Smrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) 397c813b494Smrg return prop.u.integer; 398c813b494Smrg else 399c813b494Smrg return UNDEF; 400c813b494Smrg} 401c813b494Smrg 402d2f28e1bSmrgchar * 403d2f28e1bSmrgfaceStringProp(FT_Face face, const char *name) 404d2f28e1bSmrg{ 405d2f28e1bSmrg int rc; 406d2f28e1bSmrg BDF_PropertyRec prop; 407d2f28e1bSmrg char *buf = NULL; 408d2f28e1bSmrg 409d2f28e1bSmrg rc = FT_Get_BDF_Property(face, name, &prop); 410d2f28e1bSmrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 411d2f28e1bSmrg buf = sprintf_alloc("%s", prop.u.atom ? prop.u.atom : ""); 412d2f28e1bSmrg if(buf == NULL) { 413d2f28e1bSmrg perror("sprintf_alloc failed"); 414d2f28e1bSmrg exit(1); 415d2f28e1bSmrg } 416d2f28e1bSmrg } 417d2f28e1bSmrg return buf; 418d2f28e1bSmrg} 419d2f28e1bSmrg 42043f32c10Smrgchar * 42143f32c10SmrgfaceEncoding(FT_Face face) 42243f32c10Smrg{ 42343f32c10Smrg BDF_PropertyRec p1, p2; 42443f32c10Smrg int rc; 42543f32c10Smrg 42643f32c10Smrg rc = FT_Get_BDF_Property(face, "CHARSET_REGISTRY", &p1); 42743f32c10Smrg if(rc != 0 || p1.type != BDF_PROPERTY_TYPE_ATOM) 42843f32c10Smrg return NULL; 42943f32c10Smrg rc = FT_Get_BDF_Property(face, "CHARSET_ENCODING", &p2); 43043f32c10Smrg if(rc != 0 || p2.type != BDF_PROPERTY_TYPE_ATOM) 43143f32c10Smrg return NULL; 432ea148d1dSmrg if(!(p1.u.atom && p2.u.atom)) 433ea148d1dSmrg return NULL; 43443f32c10Smrg 43543f32c10Smrg return sprintf_alloc("%s-%s", p1.u.atom, p2.u.atom); 43643f32c10Smrg} 437ea148d1dSmrg 43843f32c10Smrgint 43943f32c10SmrgdegreesToFraction(int deg, int *num, int *den) 44043f32c10Smrg{ 44143f32c10Smrg double n, d; 44243f32c10Smrg double rad, val; 44343f32c10Smrg 44443f32c10Smrg if(deg <= -(60 * TWO_SIXTEENTH) || deg >= (60 * TWO_SIXTEENTH)) 44543f32c10Smrg goto fail; 44643f32c10Smrg 44743f32c10Smrg rad = (((double)deg) / TWO_SIXTEENTH) / 180.0 * M_PI; 44843f32c10Smrg 44943f32c10Smrg n = sin(-rad); 45043f32c10Smrg d = cos(rad); 45143f32c10Smrg 45243f32c10Smrg if(d < 0.001) 45343f32c10Smrg goto fail; 45443f32c10Smrg 45543f32c10Smrg val = atan2(n, d); 45643f32c10Smrg /* There must be a cleaner way */ 457fbfaf8f3Smrg for(int i = 1; i < 10000; i++) { 45843f32c10Smrg if((int)(d * i) != 0.0 && 45943f32c10Smrg fabs(atan2(ROUND(n * i), ROUND(d * i)) - val) < 0.05) { 46043f32c10Smrg *num = (int)ROUND(n * i); 46143f32c10Smrg *den = (int)ROUND(d * i); 46243f32c10Smrg return 0; 46343f32c10Smrg } 46443f32c10Smrg } 46543f32c10Smrg 46643f32c10Smrg fail: 46743f32c10Smrg *den = 1; 46843f32c10Smrg *num = 0; 46943f32c10Smrg return -1; 47043f32c10Smrg} 47143f32c10Smrg 472