math.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #include "TeX.h"
  2. int TeX_isTeX(char* expr)
  3. {
  4. while(*expr)
  5. {
  6. if(*expr == '\\')
  7. {
  8. expr++;
  9. if(!strncmp(expr,"frac",4)) return 1;
  10. else if(!strncmp(expr,"sum", 3)) return 1;
  11. else if(!strncmp(expr,"sqrt",4)) return 1;
  12. else if(!strncmp(expr,"vec", 3)) return 1;
  13. }
  14. expr++;
  15. }
  16. return 0;
  17. }
  18. void TeX_sizeComplex(char *expr, int *width, int *height, int *line)
  19. {
  20. /*
  21. ** This functions returns the size in pixels of any complex expression.
  22. ** Calls TeX_sizeSimple() and can be called by it.
  23. ** Does not handle maximum call level. Therefore, the call stack is supposed unlimited. Any call to TeX_sizeComplex()
  24. ** needs at least one level of subsequent calls to TeX_sizeSimple().
  25. */
  26. int w=0, h=0, l=0; // These variables will contain the final properties of the expression.
  27. int tw, th, tl; // These variables store temporary data needed for comparison between elements.
  28. char *next; // This pointer will parse the expression with expr.
  29. char *element; // This pointer will contain dynamically-allocated temporary data -- the text of an element.
  30. while(*expr)
  31. {
  32. // Getting copied data of the next element in the pointer element.
  33. next = TeX_getElement(expr);
  34. element = TeX_extract(expr,next);
  35. // Getting the properties of the found element and adapting existant properties for the expression.
  36. TeX_sizeSimple(element,&tw,&th,&tl);
  37. w += tw+1;
  38. if(th>h) h=th;
  39. if(tl>l) l=tl;
  40. // Freeing the allocated memory and preparing the next iteration.
  41. free(element);
  42. expr = next;
  43. }
  44. // A pixel of spacing was added for each element, but the last one didn't need one.
  45. w -= 1;
  46. if(width) *width = w;
  47. if(height) *height = h;
  48. if(line) *line = l;
  49. }
  50. void TeX_sizeSimple(char *element, int *width, int *height, int *line)
  51. {
  52. /*
  53. ** This function returns the size of any simple TeX element, based on its parameters. Detects if the parameter is plain
  54. ** text, command or any complex expression.
  55. ** Any call to TeX_sizeSimple() needs at least one level of subsequent calls to TeX_sizeComplex() if the element is a
  56. ** command that has at least one parameter.
  57. ** Otherwise, TeX_sizeSimple() will return a fixed size without calling any subroutine.
  58. */
  59. int w=0, h=0, l=0; // These variables will contain the properties of the element.
  60. int *tw, *th, *tl; // These variables store temporary data needed for comparison between parameters.
  61. char *name; // This pointer will save the value of element to know which command was used.
  62. char *next; // This pointer will parse the element to find the parameters.
  63. char *parameter; // This pointer will contain dynamically-allocated temporary data -- a parameter.
  64. int param; // Contains the number of parameters the command use. Not used if element is plain text.
  65. int i, x; // An incremental loop counter, and just a stupid variable.
  66. // Testing if the element is only plain text.
  67. if(*element != '\\')
  68. {
  69. if(width) *width = (Txt_Width(TEX_FONT)+1)*strlen(element)-1;
  70. if(height) *height = Txt_Height(TEX_FONT);
  71. if(line) *line = Txt_Height(TEX_FONT)>>1;
  72. return;
  73. }
  74. // Otherwise, the element is obviously a command.
  75. name = element+1;
  76. param = TeX_getParamNumber(element+1);
  77. while(*element != '{') element++;
  78. // Allocating memory to store the properties of parameters.
  79. tw = calloc(TEX_MAXP,4);
  80. th = calloc(TEX_MAXP,4);
  81. tl = calloc(TEX_MAXP,4);
  82. // Processing each parameter.
  83. for(i=0;i<param;i++)
  84. {
  85. // Getting the next parameter of the detected command.
  86. next = TeX_getParameter(element);
  87. parameter = TeX_extract(element+1,next);
  88. // Getting the size of the parameter.
  89. TeX_sizeComplex(parameter,tw+i,th+i,tl+i);
  90. // Freeing the temporary data and preparing the next iteration.
  91. free(parameter);
  92. element = next+1;
  93. }
  94. // Debugging data.
  95. // debug("\n** data for simple expression \"%s\":\n",name-1);
  96. // for(i=0;i<param;i++) debug("** tw[%d]=%d, th[%d]=%d, tl[%d]=%d\n",i,tw[i],i,th[i],i,tl[i]);
  97. // Determining the properties of the command using the properties of the parameters.
  98. if(!strncmp(name,"frac",4)) w=(tw[0]>tw[1]?tw[0]:tw[1])+2, h=th[0]+th[1]+3, l=th[0]+1;
  99. else if(!strncmp(name,"sum", 3)) x=(tw[0]>tw[1]?tw[0]:tw[1]), w=(x>8?x:8), h=th[0]+th[1]+11, l=th[0]+4;
  100. else if(!strncmp(name,"sqrt",4)) w=tw[0]+6, h=th[0]+3, l=tl[0]+2;
  101. else if(!strncmp(name,"vec", 3)) w=tw[0], h=th[0]+4, l=tl[0]+4;
  102. else w=-1, h=-1, l=-1;
  103. if(width) *width = w;
  104. if(height) *height = h;
  105. if(line) *line = l;
  106. // Freeing the allocated data.
  107. free(tw);
  108. free(th);
  109. free(tl);
  110. }
  111. char *TeX_getElement(char *expr)
  112. {
  113. /*
  114. ** This function returns a pointer to the end of the first element pointed to by expr. If *expr is '\\', the element is
  115. ** considered as a command and TeX_getElement() returns a pointer to the character just after the '}' closing the command.
  116. ** In any other cases, the element is supposed to be plain text and TeX_getElement() returns a pointer to the first '\\'
  117. ** opening a command.
  118. */
  119. char *next = expr;
  120. // Looking for any '\\' as first character.
  121. if(*expr=='\\')
  122. {
  123. // Getting the number of parameters for the detected command.
  124. const int param = TeX_getParamNumber(expr+1);
  125. int c,i;
  126. // Determining the end of each parameter based on sublevel elements.
  127. for(i=0,c=0;i<param;i++)
  128. {
  129. while(*next)
  130. {
  131. if(*next=='{') c++;
  132. if(*next=='}') c--;
  133. if(*next=='}' && !c) break;
  134. next++;
  135. }
  136. next++;
  137. }
  138. }
  139. // If element is plain text, the next element is the first command found.
  140. else while(*next!='\\' && *next) next++;
  141. return next;
  142. }
  143. char *TeX_getParameter(char *com)
  144. {
  145. /*
  146. ** This function returns a pointer to the end of the first parameter foud at com. It follows a simple parameter : the
  147. ** parameters begins with the first '{' and ends at the '}' which is at level 0, to handle subcommands in parameters.
  148. */
  149. char *end; // Will be returned. Contains the address of the closing '}'.
  150. int c=0;
  151. // Positioning com on the first '{' (spaces handling).
  152. while(*com != '{') com++;
  153. end = com;
  154. while(*end)
  155. {
  156. if(*end=='{') c++;
  157. if(*end=='}') c--;
  158. if(*end=='}' && !c) break;
  159. end++;
  160. }
  161. return end;
  162. }
  163. char *TeX_extract(char *begin, char *end)
  164. {
  165. /*
  166. ** This function returns a pointer to a dynamically-allocated memory block the contains the copied data found between the
  167. ** pointers got as arguments.
  168. ** Returns NULL if any error occur.
  169. */
  170. char *data; // Will be allocated.
  171. int length = end-begin; // Length of data to be copied.
  172. int i; // Incremental loop counter.
  173. // Allocating data to store a copy of the memory block.
  174. data = calloc(length+1,1);
  175. if(!data) return NULL;
  176. // Copying the memory block and returning the resulting pointer.
  177. for(i=0;i<length;i++) *(data+i) = *(begin+i);
  178. *(data+length) = 0;
  179. return data;
  180. }
  181. int TeX_getParamNumber(char *expr)
  182. {
  183. /*
  184. ** This function returns the number of parameters used by a defined command given as only parameter.
  185. ** Returns 0 if the command is unknown.
  186. */
  187. // Constant 2-parameters commands.
  188. if(!strncmp(expr,"frac",4)) return 2;
  189. if(!strncmp(expr,"sum", 3)) return 2;
  190. // Constant 1-parameter commands.
  191. if(!strncmp(expr,"sqrt",4)) return 1;
  192. if(!strncmp(expr,"vec", 3)) return 1;
  193. // Other commands that don't use any parameter.
  194. return 0;
  195. }
  196. void TeX_drawComplex(char *expr, int x, int y)
  197. {
  198. /*
  199. ** This function draws the complex expression expr at point (x;y) on the screen. The is the mainly used function of the
  200. ** program.
  201. */
  202. int w; // These variable will contain the width of the element being drawn.
  203. int baseline; // This integer will contain the baseline of the whole expression.
  204. char *next; // This pointer will parse the expression with expr.
  205. char *element; // This pointer will contain dynamically-allocated temporary data -- the text of an element.
  206. TeX_sizeComplex(expr,NULL,NULL,&baseline);
  207. while(*expr)
  208. {
  209. // Getting copied data of the next element in the pointer element.
  210. next = TeX_getElement(expr);
  211. element = TeX_extract(expr,next);
  212. // Getting the properties of the found element and drawing it.
  213. TeX_sizeSimple(element,&w,NULL,NULL);
  214. TeX_drawSimple(element,x,baseline+y);
  215. // Freeing the allocated memory and preparing the next iteration.
  216. free(element);
  217. expr = next;
  218. x += w+1;
  219. }
  220. // A pixel of spacing was added for each element, but the last one didn't need one.
  221. w -= 1;
  222. }
  223. void TeX_drawSimple(char *element, int x, int l)
  224. {
  225. /*
  226. ** This function draw the simple element at the given position on the screen, defined by the baseline.
  227. */
  228. #define setPixel(x,y,v) setPixel(x,y,v,Txt_VRAM)
  229. extern char *Txt_VRAM; // Needed for using setPixel().
  230. char *name = element+1; // Saving the element address before changing.
  231. char *next; // This pointer will parse the element to find the parameters.
  232. char **parameters; // This pointer will contain the parameters.
  233. int *tw, *th, *tl; // These variables store temporary data needed for comparison between parameters.
  234. int w,h,b; // Contain the properties of the element.
  235. int param; // Contains the number of parameters of the detected command.
  236. int i,j; // Incremental loop counters.
  237. TeX_sizeSimple(element,&w,&h,&b);
  238. debug("Baseline of \"%s\" is %d.\n",element,b);
  239. // Cheking if the element is plain text.
  240. if(*element != '\\')
  241. {
  242. Txt_Text(element,x,l-b,TEX_FONT,TEX_MODE);
  243. return;
  244. }
  245. // Otherwise, the element is obviously a command.
  246. name = element+1;
  247. param = TeX_getParamNumber(element+1);
  248. while(*element != '{') element++;
  249. // Allocating memory to store the properties of parameters.
  250. tw = calloc(TEX_MAXP,4);
  251. th = calloc(TEX_MAXP,4);
  252. tl = calloc(TEX_MAXP,4);
  253. parameters = calloc(TEX_MAXP,sizeof(char *));
  254. // Processing each parameter.
  255. for(i=0;i<param;i++)
  256. {
  257. // Getting the next parameter of the detected command.
  258. next = TeX_getParameter(element);
  259. parameters[i] = TeX_extract(element+1,next);
  260. // Getting the size of the parameter.
  261. TeX_sizeComplex(parameters[i],tw+i,th+i,tl+i);
  262. // Preparing the next iteration.
  263. element = next+1;
  264. }
  265. // Drawing the element depending on the detected command.
  266. if(!strncmp(name,"frac",4))
  267. {
  268. for(j=0;j<w;j++) setPixel(x+j,l,1);
  269. TeX_drawComplex(parameters[0],x+(w>>1)-(tw[0]>>1),l-th[0]-1);
  270. TeX_drawComplex(parameters[1],x+(w>>1)-(tw[1]>>1),l+2);
  271. }
  272. else if(!strncmp(name,"sum",3))
  273. {
  274. for(j=0;j<8;j++) setPixel(x+(w>>1)+j-4,l-4,1), setPixel(x+(w>>1)+j-4,l+4,1);
  275. for(j=1;j<4;j++) setPixel(x+(w>>1)-j,l-j,1), setPixel(x+(w>>1)-j,l+j,1);
  276. setPixel(x+(w>>1),l,1);
  277. setPixel(x+(w>>1)+3,l-3,1);
  278. setPixel(x+(w>>1)+3,l+3,1);
  279. TeX_drawComplex(parameters[0],x+(w>>1)-(tw[0]>>1),l+6);
  280. TeX_drawComplex(parameters[1],x+(w>>1)-(tw[1]>>1),l-5-th[1]);
  281. }
  282. else if(!strncmp(name,"sqrt",4))
  283. {
  284. for(j=0;j<h;j++) setPixel(x+2,l-tl[0]-2+j,1);
  285. setPixel(x+1,l-tl[0]+h-4,1);
  286. setPixel(x,l-tl[0]+h-5,1);
  287. for(j=2;j<w;j++) setPixel(x+j,l-tl[0]-2,1);
  288. setPixel(x+w-1,l-tl[0]-1,1);
  289. setPixel(x+w-1,l-tl[0],1);
  290. TeX_drawComplex(parameters[0],x+4,l-tl[0]);
  291. }
  292. else if(!strncmp(name,"vec",3))
  293. {
  294. for(j=0;j<w;j++) setPixel(x+j,l-tl[0]-3,1); j-=2;
  295. setPixel(x+j,l-tl[0]-4,1);
  296. setPixel(x+j,l-tl[0]-2,1);
  297. TeX_drawComplex(parameters[0],x,l-tl[0]);
  298. }
  299. else setPixel(x,l-b,1);
  300. // Finally freeing the allocated data.
  301. free(tw);
  302. free(th);
  303. free(tl);
  304. for(i=0;i<param;i++) free(parameters[i]);
  305. free(parameters);
  306. }