/* PZT_complex_text.c, part of PoZeTools version 0.56, december 24, 2019. Copyright (c) 2002-2019 Pieter Suurmond Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. See the accompanying headerfile PZT_complexText.h. */ #include #include #include #include /* For exp(). */ #include "PZT_complex_math.h" #include "PZT_complex_text.h" /*-------------------------------------*/ int cutTrailingZeroesAndDot(char* str) { int i = strlen(str) - 1; /* Don't cut the only one! */ while ((i > 0) & (str[i] == '0')) str[i--]=(char)0; if (str[i] == '.') str[i]=(char)0; else i++; return i; } /*-------------------------------------*/ int simplifyString(char* str) { char c; /* Destrutive! */ char* wr = str; int length = 0; do { c = *str++; while (c && (c <= ' ')) c = *str++; if (c) { length++; if ((c >= 'A') && (c <= 'Z')) c += 32; } *wr++ = c; /* Also terminate. */ } while (c); return length; } /*---------------------------------------------------------------*/ static double readImaginaryPart(char* jf, char* str) { double im; /* Only used by 'readPolarAndCartesian()'. */ if (jf < &str[2]) { /* Accept '+j' and '-j'. */ if (str[0] == '-') /* And '+1j' and '-1j', etc. */ im = -1.0; else im = 1.0; } else im = strtod(str, (char**)NULL); return im; } /*---------------------------------------------------------------------------*/ int readPolarAndCartesian(char* str, complexPolar* p, complexCartesian* c) { int lenm; char k, *found, *jfound, *mfound, *pfound; if (!*str) return 1; /* "" is not the same as zero! */ found = strstr(str, "exp("); if (found) { /*------------------------------------ POLAR: ----------------*/ *found = (char)0; /* Isolate magnitude. */ if (!*str) /* Empty? Nothing? */ p->mag = 1.0; else { p->mag = strtod(str, (char**)NULL); if (p->mag < 0) return -2; /* Negative length! */ } /* (maybe zero length, go on...) */ str = found + 4; /* Isolate angle. */ lenm = strlen(str) - 1; if (str[lenm] != ')') return -3; /* Missing closing bracket. */ str[lenm--] = (char)0; if (lenm < 1) return -4; /* Nothing between the brackets. */ if (str[0] == '-') /* Only first char between brackets may be '-'. */ { p->ang = -1.0; str++; } else { p->ang = 1.0; if (str[0] == '+') str++; } if (!str[0]) return -5; /* Nothing after "(-" or "(+". */ if (strchr(str, '-') || strchr(str, '+')) return -6; found = strstr(str, "pi"); /* Search for "pi". */ if (found) { found[0] = ' '; found[1] = ' '; p->ang *= kPZT_onePi; } jfound = strchr(str, 'j'); /* Search for 'j'. */ if (jfound) jfound[0] = ' '; found = str; while (*found) { if (*found++ != ' ') { p->ang *= strtod(str, (char**)NULL); goto something; } } something: if (!jfound) { p->mag *= exp(p->ang); p->ang = 0; /* Pure real "exp(... pi)" */ } polarToCartesian(p, c); } else { /*---------------------------------------- CARTESIAN: ---------------*/ mfound = strchr(&str[1], '-'); /* Search second '-' or '+'. */ pfound = strchr(&str[1], '+'); /* (&str[1] may be empty.) */ if (mfound && pfound) return 200; /* This should never happen. */ jfound = strchr(str, 'j'); /* Search for 'j'. */ if (jfound) { *jfound = ' '; /* Destroy 'j' (no more ' ').*/ if (mfound == pfound) /* Then they're both NULL. */ { /* Pure imaginary: */ c->re = 0.0; c->im = readImaginaryPart(jfound, str); } else { if (mfound) found = mfound; else found = pfound; if (!found[1]) return 201; /* Nothing after 2nd '+/-'. The */ if (jfound > found) /* latter = im, first = real. */ { k = found[0]; found[0] = (char)0; /* Terminat to read first (re). */ c->re = strtod(str,(char**)NULL); found[0] = k; /* Repair again. */ c->im = readImaginaryPart(jfound, found); } else /* The first = im, latter = re. */ { c->re = strtod(found,(char**)NULL); /* Reading the latter */ k = found[0]; /* (re) needs no termination. */ found[0] = (char)0; /* Terminate to read first (im). */ c->im = readImaginaryPart(jfound, str); found[0] = k; /* Repair again. */ } } } else /* Pure real: */ { c->re = strtod(str,(char**)NULL); c->im = 0.0; } cartesianToPolar(c, p); } return 0; } /*--------------------------------------------------------------------------*/ void writePolar(const complexPolar* p, int decimals, char* str) { char* begin = str, formatStr[8]; double abs_angle; sprintf(formatStr, "%%.%df", decimals); /* 'decimals' may not be 0. */ if (p->mag < kPZT_epsilon) { sprintf(str, "0"); return; } /* We assume p->mag >= 0 !! */ abs_angle = fabs(p->ang); if (fabs(abs_angle - kPZT_onePi) < kPZT_epsilon) { str += sprintf(str, "-"); abs_angle = 0.0; } str += sprintf(str, formatStr, p->mag); while (str[-1] == '0') *--str = (char)0; if (str[-1] == '.') *--str = (char)0; if (abs_angle < kPZT_epsilon) /* Pure positive (or negative) real. */ return; if (!strcmp("1", begin)) /* Skip 1 before exp() */ str = begin; else if (!strcmp("-1", begin)) begin[1] = ' '; else str += sprintf(str, " "); str += sprintf(str, "exp("); begin = str; str += sprintf(str, formatStr, p->ang / kPZT_onePi); while (str[-1] == '0') *--str = (char)0; if (str[-1] == '.') *--str = (char)0; if (!strcmp("1", begin)) /* Skip 1 before PI */ str = begin; else if (!strcmp("-1", begin)) begin[1] = ' '; else str += sprintf(str, " "); str += sprintf(str, "PI j)"); } /*----------------------------------------------------------------------------*/ /* If decimals is negative, we cut all trailing zeros. Argument decimals was an int up to version 0.55. But since the size of int grew... to take care that the sprintf never overflows the format-string buffer, I changed that to a signed char. */ void writeCartesian(const complexCartesian* c, signed char decimals, char* str) { char formatStr[8]; int n; sprintf(formatStr, "%%.%df", abs(decimals)); /* 'decimals' may not be 0. */ if (fabs(c->re) > kPZT_epsilon) { n = sprintf(str, formatStr, c->re); if (decimals < 0) str += cutTrailingZeroesAndDot(str); else str += n; } if (fabs(c->im) > kPZT_epsilon) /* No epsilons here, 0 must be 0.0. */ { if (fabs(c->re) > kPZT_epsilon) { /* str += sprintf(str, " "); */ if (c->im > 0.0) str += sprintf(str, "+"); } n = sprintf(str, formatStr, c->im); if (decimals < 0) { n = cutTrailingZeroesAndDot(str); if (!strcmp(str, "1")) ; else if (!strcmp(str, "-1")) *str++ = '-'; else str += n; } else str += n; sprintf(str, "j"); } else if (c->re == 0.0) sprintf(str, "0"); } /*-------------------------------------------------------*/ int copy_line(char* lineBuff, int max, const char** source) { int result = 0; /* max must be > 0 */ char c; while ((c = **source)) { (*source)++; if (++result < max) { *lineBuff++ = c; if (c == 10) break; } else break; } *lineBuff = 0; return result; }