Subversion Repositories Kolibri OS

Rev

Rev 9764 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/ksys.h>
  5. #include <clayer/boxlib.h>
  6. #include <conio.h>
  7. #include <math.h>
  8.  
  9. #include "func.h"
  10. #include "parser.h"
  11.  
  12. #define nullptr 0
  13.  
  14. enum BUTTONS {
  15.         BTN_QUIT = 1,
  16.         BTN_EDIT = 5
  17. };
  18.  
  19. const char STR_PROGRAM_TITLENAME[] = "Graph";
  20. const char empty_text[] = "No function loaded. Type file name and press Enter. ";
  21. const char er_file_not_found[] = "Couldn't open file.";
  22. const char er_wrong_syntax[] = "Syntax error in file: at line %d, at byte %d.";
  23. const char er_invalid_graph_size[] = "Invalid graph size (look at passed x1,x2,y1,y2 graph's border coords).";
  24. const char str_filename[] = "Filename:";
  25. const char str_editfile[] = "Edit";
  26. const char f_str[] = ". Function y=";
  27. const char STR_ERR_CONSOLEINIT[] = "Unable to initialize console.";
  28. const char STR_MSG_HELP_USAGE[] = "Usage: %s [OPTION] [FILENAME]...\n";
  29. const char* STR_MSG_HELP[] = {
  30.         "Draws a graph by calculating mathematical function or using list of points.\n\n",
  31.  
  32.         "\t--help\t\tdisplay this help and exit\n\n",
  33.  
  34.         "You can provide path to file if you want it to be opened immediately.\n",
  35. };
  36.  
  37. // íà÷àëüíûå ðàçìåðû
  38. #define WND_W 600
  39. #define WND_H 470
  40.  
  41. #define LIGHTGREEN 0xff0000
  42. #define WHITE 0xffffff
  43. #define BLACK 0x0
  44. #define LIGHTBLUE 0x0000ff
  45. #define LIGHTRED 0xff0000
  46.  
  47. // font colors
  48. #define BIGFONTCOLOR BLACK
  49. #define SMALLFONTCOLOR BLACK
  50.  
  51. #define THREE 3.0
  52. // minimum space: 3 pixels
  53.  
  54. #define BIG_HEIGHT 4.0
  55. #define SMALL_HEIGHT 2.0
  56. #define TEXT_X 15.0
  57. // numeric format for output
  58. #define FORMAT "%.2f%c"
  59. // format for two coords
  60. #define FORMAT_COORD "(%.2f, %.2f)%c"
  61.  
  62. int SysColor = 0;
  63. double grx1, gry1, grx2, gry2;
  64.  
  65. #define FUNCTS_MAXLEN_INITIAL 1
  66. void** functs; // Array of addresses, first byte of struct always should describe its type
  67. unsigned int functs_maxlen = 0;
  68. unsigned int functs_count = 0;
  69.  
  70. #define FUNCTS_PTYPE 0
  71. #define PFUNCT_POINTS_MAXLEN_INITIAL 16
  72. typedef struct {
  73.         char type;
  74.         double* points;
  75.         unsigned int points_maxlen;
  76.         unsigned int points_count;
  77. } PFunct;
  78.  
  79. #define FUNCTS_ETYPE 1
  80. typedef struct {
  81.         char type;
  82.         char* expr;
  83. } EFunct;
  84.  
  85. char edit_path[256];
  86. edit_box mybox = { 200, 92, WND_H-16-32, 0xffffff, 0x94AECE, 0, 0x808080, 0x10000000,
  87.                                         sizeof(edit_path)-1, (void*)&edit_path, 0, 0, 0 };
  88.  
  89. int full_head_size;
  90. char* full_head;
  91.  
  92. char* lasterror_text = nullptr;
  93. int lasterror_color;
  94.  
  95. // constructor of TCoord
  96. TCoord coord(double x, double y) {
  97.         TCoord r;
  98.         r.x = x;
  99.         r.y = y;
  100.         return r;
  101. }
  102.  
  103. // move and scale mathematical coords to fit screen coords
  104. TCoord mat2Graf(TCoord c, TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) {
  105.         TCoord r;
  106.   if (c.x > mMax.x)
  107.     c.x = mMax.x;
  108.   if (c.x < mMin.x)
  109.     c.x = mMin.x;
  110.   if (c.y > mMax.y)
  111.     c.y = mMax.y;
  112.   if (c.y < mMin.y)
  113.     c.y = mMin.y;
  114.   r.x = (scrMax.x - scrMin.x) / (mMax.x - mMin.x) * (c.x - mMin.x) + scrMin.x;
  115.   r.y = (scrMax.y - scrMin.y) / (mMax.y - mMin.y) * (mMax.y - c.y) + scrMin.y;
  116.  
  117.   return r;
  118. }
  119.  
  120. //just for rounding...
  121. void DrawLine(double xs, double ys, double xe, double ye, ksys_color_t color) {
  122.         _ksys_draw_line(roundi(xs), roundi(ys), roundi(xe), roundi(ye), color);
  123. }
  124. void DrawText(const char* text, double x, double y, uint32_t len, ksys_color_t color) {
  125.         _ksys_draw_text(text, roundi(x), roundi(y), len, color);
  126. }
  127.  
  128. double delta_getoptsize(int n) {
  129.         return pow(2, n % 3) * pow(10, n / 3);
  130. }
  131. //Returns res: delta_getoptsize(res) <= size < delta_getoptsize(res+1)
  132. int delta_getn(double size) {
  133.         int res = floor(log10(size) * 3);
  134.         double t = delta_getoptsize(res + 1);
  135.         if (t < size || isequal(t, size)) ++res;
  136.         return res;
  137. }
  138.  
  139. // huge function to draw all the stuff except the function itself
  140. void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) {
  141.   TCoord cZero = {0.0,0.0}, gMin, gMax, gZero, step;
  142.   TCoord from, to;
  143.   double i = 0.0;
  144.   char buf[30]="";
  145.   int strlentemp;
  146.  
  147.   double deltaBigX = delta_getoptsize(delta_getn(mMax.x - mMin.x)) / 20;
  148.   double deltaBigY = delta_getoptsize(delta_getn(mMax.y - mMin.y)) / 20;
  149.   double deltaSmallX = deltaBigX / 5;
  150.   double deltaSmallY = deltaBigY / 5;
  151.  
  152. // scr means Screen(bounding rect)
  153. // m   means Mathematical
  154. // g   means Graphic(real screen position)
  155.  
  156.   gMin = mat2Graf(mMin, scrMin, scrMax, mMin, mMax);
  157.   gMax = mat2Graf(mMax, scrMin, scrMax, mMin, mMax);
  158.   gZero = mat2Graf(cZero, scrMin, scrMax, mMin, mMax);
  159.  
  160.   SysColor = BLACK;
  161.  
  162.   DrawLine(gMin.x, gZero.y ,gMax.x, gZero.y, SysColor); // osy X
  163.   DrawLine(gZero.x, gMin.y, gZero.x, gMax.y, SysColor); // osy Y
  164.  
  165.   // bounding rect
  166.   DrawLine(gMin.x, gMin.y, gMax.x, gMin.y, SysColor);
  167.   DrawLine(gMin.x, gMax.y, gMax.x, gMax.y, SysColor);
  168.   DrawLine(gMin.x, gMin.y, gMin.x, gMax.y, SysColor);
  169.   DrawLine(gMax.x, gMin.y, gMax.x, gMax.y, SysColor);
  170.  
  171.   // coords of the rect : lower left
  172.   sprintf(buf, FORMAT_COORD, grx1, gry1, '\0');
  173.   //_ksys_debug_puts(buf);
  174.   strlentemp = strlen(buf);
  175.   DrawText(buf, gMin.x, gMin.y + textheight(buf, strlentemp), strlentemp, SysColor);
  176.   // upper left
  177.   sprintf(buf, FORMAT_COORD, grx1, gry2, '\0');
  178.   strlentemp = strlen(buf);
  179.   DrawText(buf, gMin.x, gMax.y - textheight(buf, strlentemp), strlentemp, SysColor);
  180.   // lower right
  181.   sprintf(buf, FORMAT_COORD, grx2, gry1, '\0');
  182.   strlentemp = strlen(buf);
  183.   DrawText(buf, gMax.x - textwidth(buf, strlentemp), gMin.y + textheight(buf, strlentemp), strlentemp, SysColor);
  184.   // upper right
  185.   sprintf(buf, FORMAT_COORD, grx2, gry2, '\0');
  186.   strlentemp = strlen(buf);
  187.   DrawText(buf, gMax.x - textwidth(buf, strlentemp), gMax.y - textheight(buf, strlentemp), strlentemp, SysColor);
  188.  
  189.   //_ksys_debug_puts("some lines painted\n");
  190.  
  191.  
  192.   step.x = (mMax.x - mMin.x) / (scrMax.x - scrMin.x);
  193.   step.y = (mMax.y - mMin.y) / (scrMax.y - scrMin.y);
  194.  
  195.         //roundi values
  196.         double xmin = round(mMin.x / deltaBigX) * deltaBigX;
  197.         double ymin = round(mMin.y / deltaBigY) * deltaBigY;
  198.  
  199.   // (0,0)
  200.  
  201.   if ((grx1 * grx2 <= 0.0) && (gry1 * gry2 <= 0.0))
  202.   {
  203.           from.x=0.0;
  204.           from.y=0.0;
  205.           from = mat2Graf(from, scrMin, scrMax, mMin, mMax);
  206.           SysColor = BLACK;
  207.           sprintf(buf, FORMAT, 0.0, '\0');
  208.           strlentemp = strlen(buf);
  209.           DrawText(buf, from.x - textwidth(buf, strlentemp), from.y + textheight(buf, strlentemp), strlentemp, SysColor);
  210.   }
  211.  
  212.  
  213.   // big marks on X
  214.   //settextstyle(0, 0, 1);
  215.   if (deltaBigX / step.x > THREE) {
  216.     for (i = xmin; i <= mMax.x; i += deltaBigX) {
  217.           if (i != 0.0) {
  218.                   from.x = i;
  219.                   to.x = from.x;
  220.                   from.y = -BIG_HEIGHT * step.y;
  221.                   to.y = BIG_HEIGHT * step.y;
  222.                   from = mat2Graf(from, scrMin, scrMax, mMin, mMax);
  223.                   to = mat2Graf(to, scrMin, scrMax, mMin, mMax);
  224.                   SysColor = BLACK;
  225.                   DrawLine(from.x, from.y, to.x, to.y, SysColor);
  226.                   // write number
  227.                   sprintf(buf, FORMAT, i, '\0');
  228.                   strlentemp = strlen(buf);
  229.                   // if it fits in the GAP, then write it
  230.                   if (from.y > scrMin.y && (deltaBigX > (textwidth(buf, strlentemp) + 1.0) * step.x)) {
  231.                            SysColor = BIGFONTCOLOR;
  232.                            DrawText(buf, from.x - textwidth(buf, strlentemp) / 2.0, to.y - textheight(buf, strlentemp), strlentemp, SysColor);
  233.                   }
  234.           }
  235.     }
  236.   }
  237.  
  238.   // big marks on Y
  239.   if (deltaBigY / step.y > THREE) {
  240.     for (i = ymin; i <= mMax.y; i += deltaBigY) {
  241.           if (i != 0.0) {
  242.                   from.y = i;
  243.                   to.y = from.y;
  244.                   from.x = -BIG_HEIGHT * step.x;
  245.                   to.x = BIG_HEIGHT * step.x;
  246.                   from = mat2Graf(from, scrMin, scrMax, mMin, mMax);
  247.                   to = mat2Graf(to, scrMin, scrMax, mMin, mMax);
  248.                   SysColor = BLACK;
  249.                   DrawLine(from.x, from.y, to.x, to.y, SysColor);
  250.                   sprintf(buf, FORMAT, i, '\0');
  251.                   strlentemp = strlen(buf);
  252.                   if (from.x > scrMin.x && (deltaBigY > textheight(buf, strlentemp) * step.y)) {
  253.                            SysColor = BIGFONTCOLOR;
  254.                          DrawText(buf, from.x + TEXT_X, to.y - textheight(buf, strlentemp) / 2.0, strlentemp, SysColor);
  255.                   }
  256.           }
  257.     }
  258.   }
  259.  
  260.         double xmin2 = round(mMin.x / deltaSmallX) * deltaSmallX;
  261.         double ymin2 = round(mMin.y / deltaSmallY) * deltaSmallY;
  262.  
  263.   if (deltaSmallX / step.x > THREE) {
  264.     int j = roundi((-xmin + xmin2) / deltaSmallX);
  265.     for (i = xmin2; i <= mMax.x; i += deltaSmallX, j++) {
  266.       if (j % 10 == 0) {
  267.       // we need to skip every tenth mark, to avoid overwriting big marks
  268.                 j = 0;
  269.                 continue;
  270.       }
  271.       from.x = i;
  272.       to.x = from.x;
  273.       from.y = -SMALL_HEIGHT * step.y;
  274.       to.y = SMALL_HEIGHT * step.y;
  275.       from = mat2Graf(from, scrMin, scrMax, mMin, mMax);
  276.           to = mat2Graf(to, scrMin, scrMax, mMin, mMax);
  277.       SysColor = BLACK;
  278.       DrawLine(from.x, from.y, to.x, to.y, SysColor);
  279.       sprintf(buf, FORMAT, i, '\0');
  280.           strlentemp = strlen(buf);
  281.       if (from.y > scrMin.y && (deltaSmallX > textwidth(buf, strlentemp) * step.x)) {
  282.                 SysColor = SMALLFONTCOLOR;
  283.                 DrawText(buf, from.x - textwidth(buf, strlentemp) / 2.0, to.y - textheight(buf, strlentemp), strlentemp, SysColor);
  284.       }
  285.  
  286.  
  287.     }
  288.  
  289.   }
  290.  
  291.   // finally small marks on Y
  292.   if (deltaSmallY / step.y > THREE) {
  293.     //_ksys_debug_puts("really small marks y painted\n");
  294.     int j = roundi((-ymin + ymin2) / deltaSmallY);
  295.     for (i = ymin2; i <= mMax.y; i += deltaSmallY, j++) {
  296.       if (j % 10 == 0) {
  297.       // we need to skip every tenth, to avoid overwriting
  298.                 j = 0;
  299.                 continue;
  300.       }
  301.       from.y = i;
  302.       to.y = from.y;
  303.       from.x = -SMALL_HEIGHT * step.x;
  304.       to.x = SMALL_HEIGHT * step.x;
  305.       from = mat2Graf(from, scrMin, scrMax, mMin, mMax);
  306.       to = mat2Graf(to, scrMin, scrMax, mMin, mMax);
  307.       SysColor = BLACK;
  308.       DrawLine(from.x, from.y, to.x, to.y, SysColor);
  309.       sprintf(buf, FORMAT, i, '\0');
  310.           strlentemp = strlen(buf);
  311.       if (from.x > scrMin.x && (deltaSmallY > textheight(buf, strlentemp) * step.y)) {
  312.         SysColor = SMALLFONTCOLOR;
  313.         DrawText(buf, from.x + TEXT_X, from.y - textheight(buf, strlentemp) / 2.0, strlentemp, SysColor);
  314.       }
  315.     }
  316.   }
  317.  
  318. }
  319.  
  320. // returns idx: a[idx] <= x element; -1 can be returned
  321. int binsearchRB_xInPoints(double* a, int a_size, double x) {
  322.         int L = -1;
  323.         int R = a_size;
  324.         while (R - L > 1) {
  325.                 int M = (R + L) / 2;
  326.                 if (a[2*M] <= x) // 2*M because in points array there are 2 coords: x and y
  327.                         L = M;
  328.                 else
  329.                         R = M;
  330.         }
  331.         return L;
  332. }
  333.  
  334. int calcFunct_idx;
  335.  
  336. int calcFunct(double x, double* res) {
  337.         if (*(char*)functs[calcFunct_idx] == FUNCTS_ETYPE) {
  338.                 set_exp(((EFunct*)functs[calcFunct_idx])->expr, x);
  339.                 get_exp(res); // ïàðñèòü äëÿ êàæäîãî çíà÷åíèÿ õ? äà ÿ ñ óìà ñîøåë.
  340.                 return 0;
  341.         }
  342.  
  343.         PFunct* pf = functs[calcFunct_idx];
  344.  
  345.         if (x <= pf->points[0]) {
  346.                 return 1; // Or it better return something??
  347.                 //*res = pf->points[1];
  348.         }
  349.         if (x >= pf->points[(pf->points_count - 1) * 2]) {
  350.                 return 1; // Or it better return something??
  351.                 //*res = pf->points[(pf->points_count - 1) * 2 + 1];
  352.         }
  353.  
  354.         int i = binsearchRB_xInPoints(pf->points, pf->points_count, x);
  355.         *res = (x - pf->points[2 * i]) / (pf->points[2 * (i + 1)] - pf->points[2 * i])
  356.                 * (pf->points[2 * (i + 1) + 1] - pf->points[2 * i + 1]) + pf->points[2 * i + 1];
  357.         return 0;
  358. }
  359.  
  360. void drawFunction(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax, int color) {
  361.   SysColor = color;
  362.   TCoord p, p0 = {0.0, 0.0}, step;
  363.   step.x = (mMax.x - mMin.x) / (scrMax.x - scrMin.x);
  364.   int firstPoint = 1;
  365.   double y;
  366.   for (double x = mMin.x; x < mMax.x; x += step.x) { // function is defined here and gets in the range
  367.     if (!calcFunct(x, &y)) { // óñëîâèå, ÷òî ôóíêöèÿ ïðàâèëüíî âû÷èñëåíà
  368.       if (y > mMin.y && y < mMax.y) {
  369.         p = mat2Graf(coord(x, y), scrMin, scrMax, mMin, mMax);
  370.                 // if it's our first point, only remember its coords
  371.                 // otherwise, draw a line from prev to current
  372.         if (firstPoint == 0) {
  373.           DrawLine(p0.x, p0.y, p.x, p.y, SysColor);
  374.         } else firstPoint = 0;
  375.         p0 = p;
  376.       } else {// too big/small
  377.               firstPoint = 1;
  378.       }
  379.     } else { // no value
  380.        firstPoint = 1;
  381.     }
  382.   }
  383. }
  384.  
  385. int pointsCompare(const void* a, const void* b) {
  386.         const double aval = *(const double*)a; // first element of a
  387.         const double bval = *(const double*)b; // first element of b
  388.         if (isequal(aval, bval)) return 0;
  389.         if (aval < bval) return -1;
  390.         return 1;
  391. }
  392.  
  393. void freeMemoryForGraphs() {
  394.         if (functs_count) {
  395.                 for (int i = 0; i < functs_count; ++i) {
  396.                         switch (*(char*)functs[i]) {
  397.                                 case FUNCTS_PTYPE:
  398.                                         free(((PFunct*)functs[i])->points);
  399.                                         break;
  400.                                 case FUNCTS_ETYPE:
  401.                                         free(((EFunct*)functs[i])->expr);
  402.                                         break;
  403.                         }
  404.                         free(functs[i]);
  405.                 }
  406.                 free(functs);
  407.                 functs = nullptr;
  408.                 functs_maxlen = 0;
  409.                 functs_count = 0;
  410.         }
  411. }
  412.  
  413. void functsSizeChecker() {
  414.         if (functs_maxlen <= functs_count + 1) {
  415.                 if (!functs_maxlen) {
  416.                         functs_maxlen = FUNCTS_MAXLEN_INITIAL;
  417.                         functs = (void**)malloc(sizeof(void*) * functs_maxlen);
  418.                 } else {
  419.                         functs_maxlen *= 2;
  420.                         functs = (void**)realloc(functs, sizeof(void*) * functs_maxlen);
  421.                 }
  422.                 if (!functs) exit(3);
  423.         }
  424. }
  425.  
  426. // èòîãîâàÿ âåðñèÿ ÷èòàëêè òåêñòîâûõ ôàéëîâ
  427. // NOTICE for devs: full_head must be resetted after fail of this function (on 0 ret. code)
  428. int load_points3() {
  429.         freeMemoryForGraphs();
  430.  
  431.         // get file size
  432.         ksys_bdfe_t bdfe;
  433.         int rr = _ksys_file_get_info(edit_path, &bdfe);
  434.         if (rr) {
  435.                 if (lasterror_text) free(lasterror_text);
  436.                 lasterror_text = (char*)malloc(sizeof(er_file_not_found));
  437.                 if (!lasterror_text) exit(3);
  438.                 strcpy(lasterror_text, er_file_not_found);
  439.                 lasterror_color = 0x90000000;
  440.                 return 0;
  441.         }
  442.         unsigned int filesize = bdfe.size;
  443.  
  444.         char* HugeBuf = (char*)malloc(filesize + 1); // ðàçáèðàåì êàê ñòðîêó, îòñþäà òåðìèíàòîð '\0'
  445.         if (!HugeBuf) exit(3);
  446.         unsigned int countRead;
  447.         rr = _ksys_file_read_file(edit_path, 0, filesize, HugeBuf, &countRead);
  448.         if (countRead != filesize) exit(4); // in case if something corrupted
  449.         HugeBuf[filesize] = '\0';
  450.  
  451.         int lineNum = 1;
  452.         int lineStartIdx = 0;
  453.         int borderNextCoord = 0;
  454.         int funct_status = 0; // 0 - empty, 1 - points (can be filled), 2 - expr. (definitely finished)
  455.         int i = 0;
  456.         while (i < filesize) {
  457.                 if (isalpha(HugeBuf[i])) {
  458.                         if (HugeBuf[i] == '\n') {
  459.                                 ++lineNum;
  460.                                 lineStartIdx = i + 1;
  461.                         }
  462.                         ++i;
  463.                         continue;
  464.                 }
  465.  
  466.                 if (HugeBuf[i] == ';') {
  467.                         if (funct_status) {
  468.                                 ++functs_count;
  469.                                 funct_status = 0;
  470.                         }
  471.                         ++i;
  472.                         continue;
  473.                 }
  474.  
  475.                 if (borderNextCoord == 4 && HugeBuf[i] == '=' && !funct_status) {
  476.                         functsSizeChecker();
  477.                         funct_status = 2;
  478.                         functs[functs_count] = malloc(sizeof(EFunct));
  479.                         if (!functs[functs_count]) exit(3);
  480.                         *(char*)functs[functs_count] = FUNCTS_ETYPE;
  481.  
  482.                         EFunct* ef = functs[functs_count];
  483.                         int efunct_len;
  484.                         for (efunct_len = 0; HugeBuf[i + 1 + efunct_len] != ';' && HugeBuf[i + 1 + efunct_len] != '\0'; ++efunct_len) {}
  485.                         ef->expr = (char*)malloc(efunct_len+1);
  486.                         if (!ef->expr) exit(3);
  487.                         strncpy(ef->expr, HugeBuf + i + 1, efunct_len);
  488.                         ef->expr[efunct_len] = '\0';
  489.                         i += efunct_len + 1;
  490.                         continue;
  491.                 }
  492.  
  493.                 int j;
  494.                 double d = convert(HugeBuf + i, &j);
  495.                 if (d == ERROR) {
  496.                         sprintf(debuf, er_wrong_syntax, lineNum, i-lineStartIdx+1);
  497.                         if (lasterror_text) free(lasterror_text);
  498.                         lasterror_text = (char*)malloc(strlen(debuf)+1);
  499.                         if (!lasterror_text) exit(3);
  500.                         strcpy(lasterror_text, debuf);
  501.                         lasterror_color = 0x90FF0000;
  502.                         free(HugeBuf);
  503.                         freeMemoryForGraphs();
  504.                         return 0;
  505.                 }
  506.                 if (d == ERROR_END) {
  507.                         _ksys_debug_puts("[");
  508.                         _ksys_debug_puts(STR_PROGRAM_TITLENAME);
  509.                         _ksys_debug_puts("] EOF reached.\n");
  510.                         break;
  511.                 }
  512.                 i += j;
  513.  
  514.                 if (borderNextCoord < 4) {
  515.                         switch (borderNextCoord) {
  516.                                 case 0:
  517.                                         grx1 = d;
  518.                                         break;
  519.                                 case 1:
  520.                                         grx2 = d;
  521.                                         break;
  522.                                 case 2:
  523.                                         gry1 = d;
  524.                                         break;
  525.                                 case 3:
  526.                                         gry2 = d;
  527.                                         if (grx1 > grx2 || isequal(grx1, grx2) || gry1 > gry2 || isequal(gry1, gry2)) {
  528.                                                 if (lasterror_text) free(lasterror_text);
  529.                                                 lasterror_text = (char*)malloc(sizeof(er_invalid_graph_size));
  530.                                                 if (!lasterror_text) exit(3);
  531.                                                 strcpy(lasterror_text, er_invalid_graph_size);
  532.                                                 lasterror_color = 0x90FF0000;
  533.                                                 free(HugeBuf);
  534.                                                 return 0;
  535.                                         }
  536.                                         break;
  537.                         }
  538.                         ++borderNextCoord;
  539.                 } else {
  540.                         if (!funct_status) {
  541.                                 functsSizeChecker();
  542.                                 funct_status = 1;
  543.                                 functs[functs_count] = malloc(sizeof(PFunct));
  544.                                 if (!functs[functs_count]) exit(3);
  545.                                 *(char*)functs[functs_count] = FUNCTS_PTYPE;
  546.                                 ((PFunct*)functs[functs_count])->points = nullptr;
  547.                                 ((PFunct*)functs[functs_count])->points_maxlen = 0;
  548.                                 ((PFunct*)functs[functs_count])->points_count = 0;
  549.                         }
  550.  
  551.                         PFunct* pf = functs[functs_count];
  552.                         if (pf->points_maxlen <= pf->points_count + 1) {
  553.                                 if (!pf->points_maxlen) {
  554.                                         pf->points_maxlen = PFUNCT_POINTS_MAXLEN_INITIAL;
  555.                                         pf->points = (double*)malloc(sizeof(double) * pf->points_maxlen);
  556.                                 } else {
  557.                                         pf->points_maxlen *= 2;
  558.                                         pf->points = (double*)realloc(pf->points, sizeof(double) * pf->points_maxlen);
  559.                                 }
  560.                                 if (!pf->points) exit(3);
  561.                         }
  562.                         pf->points[pf->points_count++] = d;
  563.                 }
  564.         }
  565.         free(HugeBuf);
  566.         if (funct_status) ++functs_count;
  567.  
  568.         for (int f_idx = 0; f_idx < functs_count; ++f_idx) {
  569.                 if (*(char*)functs[f_idx] != FUNCTS_PTYPE) continue;
  570.                 PFunct* pf = functs[f_idx];
  571.                 pf->points_count /= 2;
  572.                 qsort(pf->points, pf->points_count, sizeof(double)*2, pointsCompare);
  573.         }
  574.  
  575.         int full_head_new_size = sizeof(STR_PROGRAM_TITLENAME)-1 + 3 + strlen(edit_path) + 1; // 3 = strlen(" - ")
  576.         if (functs_count == 1) {
  577.                 if (*(char*)functs[0] == FUNCTS_PTYPE) {
  578.                         sprintf(debuf, ". Number of points: %u.", ((PFunct*)functs[0])->points_count);
  579.                         full_head_new_size += strlen(debuf);
  580.                 } else
  581.                         full_head_new_size += sizeof(f_str)-1 + strlen(((EFunct*)functs[0])->expr);
  582.         } else {
  583.                 sprintf(debuf, ". Functions loaded: %u.", functs_count);
  584.                 full_head_new_size += strlen(debuf);
  585.         }
  586.  
  587.         if (full_head_new_size > full_head_size) {
  588.                 free(full_head);
  589.                 full_head_size = full_head_new_size;
  590.                 full_head = (char*)malloc(full_head_size);
  591.                 if (!full_head) exit(3);
  592.         }
  593.         char* full_head_addr = full_head;
  594.         strcpy(full_head_addr, STR_PROGRAM_TITLENAME);
  595.         full_head_addr += sizeof(STR_PROGRAM_TITLENAME)-1;
  596.         strcpy(full_head_addr, " - ");
  597.         full_head_addr += 3; // 3 = strlen(" - ")
  598.         strcpy(full_head_addr, edit_path);
  599.         full_head_addr += strlen(edit_path);
  600.         if (functs_count == 1) {
  601.                 if (*(char*)functs[0] == FUNCTS_PTYPE)
  602.                         strcpy(full_head_addr, debuf);
  603.                 else {
  604.                         strcpy(full_head_addr, f_str);
  605.                         full_head_addr += sizeof(f_str)-1;
  606.                         strcpy(full_head_addr, ((EFunct*)functs[0])->expr);
  607.                 }
  608.         } else {
  609.                 strcpy(full_head_addr, debuf);
  610.         }
  611.  
  612.         if (lasterror_text) {
  613.                 free(lasterror_text);
  614.                 lasterror_text = nullptr;
  615.         }
  616.         return 1;
  617. }
  618.  
  619. void draw_window() {
  620.         _ksys_start_draw();
  621.         _ksys_create_window(100, 80, WND_W, WND_H, full_head, 0xFFFFFF, 0x33);
  622.         _ksys_end_draw();
  623.  
  624.         ksys_thread_t info;
  625.         _ksys_thread_info(&info, 0xFFFFFFFF);
  626.         int cWidth = info.winx_size - 9;
  627.         int cHeight = info.winy_size - _ksys_get_skin_height() - 4;
  628.  
  629.         mybox.top = cHeight - 50;
  630.         mybox.width = cWidth - mybox.left - 80;
  631.  
  632.         if (info.window_state & 0x04) return; //draw nothing if window is rolled-up
  633.  
  634.         if (!functs_count) {
  635.                 _ksys_draw_text(empty_text, (cWidth - 8 * strlen(empty_text)) / 2, cHeight / 2 - 25, sizeof(empty_text)-1, 0x90000000);
  636.         } else {
  637.                 TCoord scrMin = coord(10, 20),
  638.                        scrMax = coord(cWidth - 20, cHeight - 70),
  639.                        mMin = coord(grx1, gry1),
  640.                        mMax = coord(grx2, gry2);
  641.                 drawAxis(scrMin, scrMax, mMin, mMax);
  642.                 for (calcFunct_idx = 0; calcFunct_idx < functs_count; ++calcFunct_idx)
  643.                         drawFunction(scrMin, scrMax, mMin, mMax, 0x00ff0000);
  644.         }
  645.  
  646.         _ksys_draw_text((char*)str_filename, 15, mybox.top + 4, strlen(str_filename), 0x90000000);
  647.  
  648.         edit_box_draw(&mybox);
  649.  
  650.         _ksys_define_button(cWidth - 70, mybox.top, 50, 21, BTN_EDIT, 0xc0c0c0);
  651.         _ksys_draw_text((char*)str_editfile, cWidth - 60, mybox.top + 4, 0, 0x90000000);
  652.  
  653.         if (lasterror_text) {
  654.                 _ksys_draw_bar(10, 10, 200, 20, 0xFFFFFF); // ôîí äëÿ ñîîáùåíèé îá îøèáêàõ
  655.                 _ksys_draw_text(lasterror_text, 10, 10, strlen(lasterror_text), lasterror_color);
  656.         }
  657. }
  658.  
  659. void consoleInit() {
  660.         if (con_init()) { // Init fail
  661.                 _ksys_debug_puts("[");
  662.                 _ksys_debug_puts(STR_PROGRAM_TITLENAME);
  663.                 _ksys_debug_puts("] ");
  664.                 _ksys_debug_puts(STR_ERR_CONSOLEINIT);
  665.                 _ksys_debug_puts("\n");
  666.                 exit(2);
  667.         }
  668.         (*con_set_title)(STR_PROGRAM_TITLENAME);
  669. }
  670.  
  671. void consoleExit() {
  672.         (*con_exit)(0);
  673. }
  674.  
  675. int main(int argc, char** argv) {
  676.         full_head_size = sizeof(STR_PROGRAM_TITLENAME); // also with '\0'
  677.         full_head = (char*)malloc(full_head_size);
  678.         if (!full_head) return 3;
  679.         strcpy(full_head, STR_PROGRAM_TITLENAME);
  680.  
  681.         if (argc == 2) {
  682.                 if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
  683.                         consoleInit();
  684.                         printf(STR_MSG_HELP_USAGE, argv[0]);
  685.                         for (int j = 0; j < sizeof(STR_MSG_HELP)/sizeof(STR_MSG_HELP[0]); ++j) puts(STR_MSG_HELP[j]);
  686.                         consoleExit();
  687.                         return 0;
  688.                 } else {
  689.                         strcpy(edit_path, argv[1]);
  690.                         mybox.size = mybox.pos = strlen(edit_path);
  691.                         load_points3();
  692.                 }
  693.         } else if (argc > 2) {
  694.                 consoleInit();
  695.                 printf(STR_MSG_HELP_USAGE, argv[0]);
  696.                 consoleExit();
  697.                 return 1;
  698.         }
  699.  
  700.         _ksys_set_event_mask(0xC0000027);
  701.         int event;
  702.         while (1) {
  703.                 edit_box_mouse(&mybox);
  704.                 event = _ksys_get_event();
  705.                 switch (event) {
  706.                         case KSYS_EVENT_REDRAW:
  707.                                 draw_window();
  708.                                 break;
  709.                         case KSYS_EVENT_KEY: {
  710.                                 ksys_oskey_t kc = _ksys_get_key();
  711.                                 switch (kc.code) {
  712.                                         case 0x0D: {
  713.                                                 int res = load_points3();
  714.                                                 if (!res) strcpy(full_head, STR_PROGRAM_TITLENAME);
  715.                                                 draw_window();
  716.                                                 break;
  717.                                         }
  718.                                         default:
  719.                                                 edit_box_key_safe(&mybox, kc);
  720.                                 }
  721.                                 break;
  722.                         }
  723.                         case KSYS_EVENT_BUTTON: {
  724.                                 // button pressed; we have only one button, close
  725.                                 uint32_t button = _ksys_get_button();
  726.                                 if (button == BTN_QUIT)
  727.                                         _ksys_exit();
  728.                                 else if (button == BTN_EDIT)
  729.                                         _ksys_exec("/sys/develop/cedit", edit_path);
  730.                         }
  731.                 }
  732.         }
  733.         return 0;
  734. }
  735.