Sindbad~EG File Manager
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // access() and gethostname()
#include <math.h>
#include "uthash.h"
#include "ThreeBodyDoc.h"
#include "textwidth.h"
#include "svgGraph3.h"
#include "ode3.h"
void init_docData3(PDOCDATA3 pDocData, char *sessionId, char *param) {
// The param string format is:
// sessionId~pxmin~pxmax~pymin~pymax~border~background
// ~tmax
// ~integrationMethod ("rk4" or "leapfrog")
// ~graphpaper (index, -1 means no graph paper)
// ~numBodies
// ~body1~body2~...~bodyN
// where each body is encoded as:
// mass;R,G,B;radius;x0;y0;p0;q0
pDocData->tmin = 0.0; // without loss of generality
char *saveptr1 = NULL;
// 1st token: sessionId
char *token = strtok_r(param, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing sessionId in param.\n");
return;
}
// Copy sessionId into the structure (ensure no overflow)
strncpy(pDocData->sessionId, token, MAX_SESSIONID);
pDocData->sessionId[MAX_SESSIONID - 1] = '\0';
// 2nd token: pxmin
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing pxmin in param.\n");
return;
}
pDocData->pxmin = atoi(token);
// 3rd token: pxmax
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing pxmax in param.\n");
return;
}
pDocData->pxmax = atoi(token);
// 4th token: pymin
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing pymin in param.\n");
return;
}
pDocData->pymin = atoi(token);
// 5th token: pymax
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing pymax in param.\n");
return;
}
pDocData->pymax = atoi(token);
pDocData->xmin = -4;
pDocData->xmax = 4;
double aspectratio = fabs( (pDocData->pymax - pDocData->pymin)/(double)(pDocData->pxmax-pDocData->pxmin));
double height = (pDocData->xmax - pDocData->xmin) * aspectratio;
pDocData->ymin = - height/2;
pDocData->ymax = height/2;
// 6th token: border
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing border in param.\n");
return;
}
pDocData->border = (unsigned)atoi(token);
// 7th token: background
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing background in param.\n");
return;
}
pDocData->background = (unsigned)atoi(token);
// 8th token: tmax
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing tmax in param.\n");
return;
}
int nfields = sscanf(token,"%lf",&pDocData->tmax);
if(nfields != 1){
fprintf(stderr, "init_docData3: tmax must be a number \n");
return;
}
// 9th token: integrationMethod
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing integration method in param.\n");
return;
}
strncpy(pDocData->integrationMethod,token,32);
// 10th token: graphpaper
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing background in param.\n");
return;
}
pDocData->graphpaper = (unsigned)atoi(token);
// 11th token: number of bodies
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing number of bodies in param.\n");
return;
}
int nbodies = atoi(token);
if (nbodies < 0)
nbodies = 0;
if (nbodies > MAXBODIES)
nbodies = MAXBODIES;
pDocData->nbodies = nbodies;
// Now parse each body's data.
for (int i = 0; i < nbodies; i++) {
token = strtok_r(NULL, "~", &saveptr1);
if (token == NULL) {
fprintf(stderr, "init_docData3: Missing data for body %d.\n", i);
break;
}
// token format: mass;R,G,B;radius;x0;y0;p0;q0
char *saveptr2 = NULL;
// mass
char *part = strtok_r(token, ";", &saveptr2);
if (part == NULL) continue;
pDocData->bodies[i].mass = atof(part);
pDocData->bodies[i].bodynumber = i;
// color in R,G,B
part = strtok_r(NULL, ";", &saveptr2);
if (part == NULL) continue;
int r, g, b;
if (sscanf(part, "%d,%d,%d", &r, &g, &b) != 3) {
fprintf(stderr, "init_docData3: Invalid color for body %d.\n", i);
continue;
}
pDocData->bodies[i].color = RGB(r,g,b);
// radius
part = strtok_r(NULL, ";", &saveptr2);
if (part == NULL) continue;
pDocData->bodies[i].r = atof(part);
// x0
part = strtok_r(NULL, ";", &saveptr2);
if (part == NULL) continue;
pDocData->bodies[i].x0 = atof(part);
// y0
part = strtok_r(NULL, ";", &saveptr2);
if (part == NULL) continue;
pDocData->bodies[i].y0 = atof(part);
// p0
part = strtok_r(NULL, ";", &saveptr2);
if (part == NULL) continue;
pDocData->bodies[i].p0 = atof(part);
// q0
part = strtok_r(NULL, ";", &saveptr2);
if (part == NULL) continue;
pDocData->bodies[i].q0 = atof(part);
}
}
int process_message3(PDOCDATA3 pDocData, char *message, char *param, char *outbuffer, int outbuffersize)
{ memset(outbuffer, 0, outbuffersize);
reset_arrays();
if(!strcmp(message,"newDocument") || !strcmp(message, "saveSVG"))
{ // pDocData has already been initialized
// when the following code finishes, the SVG is in outbuffer,
// ready either to be sent or saved.
computeSolution(pDocData);
rect r;
int err;
r.left = 0;
r.top = 0;
r.bottom = pDocData->pymax;
r.right= pDocData->pxmax;
set_svgDevice(outbuffer,outbuffersize, &r);
svgDevice *theDevice = get_device();
err = sendDocument3(pDocData);
int byteswritten = (int) strlen(theDevice->next);
theDevice->next += byteswritten;
relinquish_device();
return err;
}
return 1;
}
/*___________________________________________________________________*/
int saveAsSVG(char *outbuffer, char *filename, char *errmsg)
// filename is relative to the images directory, where to save the document as an SVG file.
// If filename doesn't end in .svg, add that at the end.
// The caller is supposed to make sure it has either no file extension or .svg,
// is not NULL, and is already trimmmed of beginning or ending whitespace.
// The PHP that sends the "saveAsSVG" message will save the document's data
// to ThreeBodyDatabase.db, so that is not done in the Engine.
// Return 0 for success, 1 for file error; errmsg will hold up to 128 chars.
// This function should not modify outbuffer, which will subsequently be
// sent to the browser for display.
{
char images[256];
int n;
const char *imageDir;
// Detect environment
char hostname[256];
gethostname(hostname, sizeof(hostname));
printf("DEBUG: hostname = [%s]\n", hostname);
// Choose image directory based on host
if (strstr(hostname, "local"))
imageDir = "/Users/beeson/Dropbox/Sites/WebMathXpert/ThreeBodyWeb/images/";
else
imageDir = "/home/beeson/public_html/WebMathXpert/ThreeBodyWeb/images/";
// Build the full path using snprintf.
n = snprintf(images, sizeof(images), "%s%s", imageDir, filename);
if (n < 0 || n >= (int)sizeof(images)) {
snprintf(errmsg, 128, "Filename too long or formatting error");
return 1;
}
// Ensure the resulting filename ends with ".svg"
size_t len = strlen(images);
if (len < 4 || strcmp(images + len - 4, ".svg") != 0) {
if (len + 4 >= sizeof(images)) {
snprintf(errmsg, 128, "Not enough space for .svg extension");
return 1;
}
strcat(images, ".svg");
}
// Check if the file already exists.
if (access(images, F_OK) == 0) {
snprintf(errmsg, 128, "File already exists: %.100s", images);
return 1;
}
// Trim outbuffer to remove extra content after the closing </svg>
char *closeTagPos = strstr(outbuffer, "</svg>");
if (closeTagPos != NULL) {
closeTagPos += strlen("</svg>");
// Calculate new length up to and including the closing </svg>
size_t newLen = closeTagPos - outbuffer;
// Terminate the string at that point.
outbuffer[newLen] = '\0';
}
// replace "mywidth" by " width" and "myheight" by " height"
// so the browser can scale it
char *marker = strstr(outbuffer, "mywidth");
if (marker)
memcpy(marker, " width", 7);
// exactly 7 bytes, no null terminator needed here
marker = strstr(outbuffer, "myheight");
if (marker)
memcpy(marker, " height", 7); //
// Open the file for writing.
FILE *fp = fopen(images, "w");
if (fp == NULL) {
snprintf(errmsg, 128, "Unable to open file: %.100s", images);
return 1;
}
// Write the outbuffer (SVG data) into the file.
if (fputs(outbuffer, fp) == EOF) {
snprintf(errmsg, 128, "Error writing to file: %.100s", images);
fclose(fp);
return 1;
}
fclose(fp);
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists