85506ef39f562915b2baee106e03e8a69fb16f08
[alexxy/gromacs.git] / src / programs / view / fgrid.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2013, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2017,2018,2019, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "fgrid.h"
40
41 #include <cctype>
42 #include <cstdio>
43 #include <cstdlib>
44 #include <cstring>
45
46 #include "gromacs/utility/cstringutil.h"
47 #include "gromacs/utility/futil.h"
48 #include "gromacs/utility/smalloc.h"
49
50 static const char* type[] = { "button", "radiobuttons", "groupbox", "checkbox",
51                               "pixmap", "statictext",   "edittext", "defbutton" };
52
53 static void ReadDlgError(const char* infile, eDLGERR err, const char* s, const char* file, int line)
54 {
55     std::fprintf(stderr, "Error: ");
56     switch (err)
57     {
58         case eNOVALS: std::fprintf(stderr, "Not enough values for %s", s); break;
59         case eGRIDEXP: std::fprintf(stderr, "'grid' expected instead of %s", s); break;
60         case eACCOEXP: std::fprintf(stderr, "'{' expected instead of %s", s); break;
61         case eACCCEXP: std::fprintf(stderr, "'}' expected instead of %s", s); break;
62         case eGRPEXP: std::fprintf(stderr, "'group' expected instead of %s", s); break;
63         case eITEMEXP: std::fprintf(stderr, "item expected instead of %s", s); break;
64         case eSAMEPOINT: std::fprintf(stderr, "grid point for %s already in use", s); break;
65         case eTOOWIDE: std::fprintf(stderr, "grid too wide for %s", s); break;
66         case eTOOHIGH: std::fprintf(stderr, "grid too high for %s", s); break;
67         case eQUOTE: std::fprintf(stderr, "quote expected instead of %s", s); break;
68         default: std::fprintf(stderr, "????"); break;
69     }
70     std::fprintf(stderr, " in file %s\n", infile);
71     std::fprintf(stderr, "source file: %s, line: %d\n", file, line);
72     std::exit(1);
73 }
74
75 #define ReadDlgErr(in, er, es) ReadDlgError(in, er, es, __FILE__, __LINE__)
76
77 static void ReadAccOpen(const char* infile, FILE* in)
78 {
79     char buf[STRLEN];
80     int  result;
81
82     result = std::fscanf(in, "%4s", buf);
83     if ((1 != result) || std::strcmp(buf, "{") != 0)
84     {
85         ReadDlgErr(infile, eACCOEXP, buf);
86     }
87 }
88
89 static void ReadAccClose(const char* infile, FILE* in)
90 {
91     char buf[STRLEN];
92     int  result;
93
94     result = std::fscanf(in, "%4s", buf);
95     if ((1 != result) || std::strcmp(buf, "}") != 0)
96     {
97         ReadDlgErr(infile, eACCCEXP, buf);
98     }
99 }
100
101 void ReadQuoteString(const char* infile, FILE* in, char* buf)
102 {
103     char c[2];
104     int  i = 0;
105
106     /* Read until first quote */
107     while ((c[0] = std::fgetc(in)) != '"')
108     {
109         if (!std::isspace(c[0]))
110         {
111             c[1] = '\0';
112             ReadDlgErr(infile, eQUOTE, c);
113         }
114     }
115     /* Read until second quote */
116     while ((c[0] = std::fgetc(in)) != '"')
117     {
118         buf[i++] = c[0];
119     }
120     buf[i] = '\0';
121 }
122
123 static void ReadQuoteStringOrAccClose(FILE* in, char* buf)
124 {
125     char c;
126     int  i = 0;
127
128     /* Read until first quote */
129     do
130     {
131         c = std::fgetc(in);
132         if (c == '}')
133         {
134             buf[0] = c;
135             buf[1] = '\0';
136             return;
137         }
138     } while (c != '"');
139
140     /* Read until second quote */
141     while ((c = std::fgetc(in)) != '"')
142     {
143         buf[i++] = c;
144     }
145     buf[i] = '\0';
146 }
147
148 static bool bNotAccClose(const char* buf)
149 {
150     return (std::strcmp(buf, "}") != 0);
151 }
152
153 static t_fitem* NewFItem(void)
154 {
155     t_fitem* fitem;
156
157     snew(fitem, 1);
158     fitem->nname = 0;
159     fitem->name  = nullptr;
160     fitem->set   = nullptr;
161     fitem->get   = nullptr;
162     fitem->def   = nullptr;
163     fitem->help  = nullptr;
164
165     return fitem;
166 }
167
168 static t_fsimple* NewFSimple(void)
169 {
170     t_fsimple* fsimple;
171
172     snew(fsimple, 1);
173
174     return fsimple;
175 }
176
177 static void AddFItemName(t_fitem* fitem, char* name)
178 {
179     srenew(fitem->name, ++fitem->nname);
180     fitem->name[fitem->nname - 1] = gmx_strdup(name);
181 }
182
183 static t_fgroup* NewFGroup(void)
184 {
185     t_fgroup* fgroup;
186
187     snew(fgroup, 1);
188     fgroup->name   = nullptr;
189     fgroup->nfitem = 0;
190     fgroup->fitem  = nullptr;
191
192     return fgroup;
193 }
194
195 static void AddFGroupFItem(t_fgroup* fgroup, t_fitem* fitem)
196 {
197     srenew(fgroup->fitem, ++fgroup->nfitem);
198     fgroup->fitem[fgroup->nfitem - 1] = fitem;
199 }
200
201 static t_fgroup* AddFGridFGroup(t_fgrid* fgrid)
202 {
203     srenew(fgrid->fgroup, ++fgrid->nfgroup);
204     fgrid->fgroup[fgrid->nfgroup - 1] = NewFGroup();
205     return fgrid->fgroup[fgrid->nfgroup - 1];
206 }
207
208 static t_fsimple* AddFGridFSimple(t_fgrid* fgrid)
209 {
210     srenew(fgrid->fsimple, ++fgrid->nfsimple);
211     fgrid->fsimple[fgrid->nfsimple - 1] = NewFSimple();
212     return fgrid->fsimple[fgrid->nfsimple - 1];
213 }
214
215 static t_fgrid* NewFGrid(void)
216 {
217     t_fgrid* fgrid;
218
219     snew(fgrid, 1);
220     fgrid->w        = 0;
221     fgrid->h        = 0;
222     fgrid->nfgroup  = 0;
223     fgrid->fgroup   = nullptr;
224     fgrid->nfsimple = 0;
225     fgrid->fsimple  = nullptr;
226
227     return fgrid;
228 }
229
230 static void DoneFItem(t_fitem* fitem)
231 {
232     int i;
233
234     for (i = 0; (i < fitem->nname); i++)
235     {
236         sfree(fitem->name[i]);
237     }
238     sfree(fitem->name);
239     sfree(fitem->set);
240     sfree(fitem->get);
241     sfree(fitem->def);
242     sfree(fitem->help);
243 }
244
245 static void DoneFGroup(t_fgroup* fgroup)
246 {
247     int i;
248
249     sfree(fgroup->name);
250     for (i = 0; (i < fgroup->nfitem); i++)
251     {
252         DoneFItem(fgroup->fitem[i]);
253     }
254     sfree(fgroup->fitem);
255 }
256
257 static void DoneFSimple(t_fsimple* fsimple)
258 {
259     DoneFItem(fsimple->fitem);
260     sfree(fsimple->fitem);
261 }
262
263 void DoneFGrid(t_fgrid* fgrid)
264 {
265     int i;
266
267     for (i = 0; (i < fgrid->nfgroup); i++)
268     {
269         DoneFGroup(fgrid->fgroup[i]);
270     }
271     sfree(fgrid->fgroup);
272     for (i = 0; (i < fgrid->nfsimple); i++)
273     {
274         DoneFSimple(fgrid->fsimple[i]);
275     }
276     sfree(fgrid->fsimple);
277 }
278
279 static t_fitem* ScanFItem(const char* infile, FILE* in, char* buf)
280 {
281     char     set[STRLEN], get[STRLEN], help[STRLEN], def[STRLEN];
282     int      edlg;
283     t_fitem* fitem;
284
285     fitem = NewFItem();
286
287     for (edlg = 0; (edlg < edlgNR + 1); edlg++)
288     {
289         if (std::strcmp(buf, type[edlg]) == 0)
290         {
291             break;
292         }
293     }
294     if (edlg == edlgNR)
295     {
296         /* Special case */
297         edlg        = edlgBN;
298         fitem->bDef = true;
299     }
300     if (edlg == edlgNR + 1)
301     {
302         ReadDlgErr(infile, eITEMEXP, buf);
303     }
304
305     fitem->edlg = (edlgitem)edlg;
306     switch (edlg)
307     {
308         case edlgBN:
309         case edlgCB:
310         case edlgET:
311             ReadQuoteString(infile, in, buf);
312             AddFItemName(fitem, buf);
313             break;
314         case edlgST:
315         case edlgRB:
316             ReadAccOpen(infile, in);
317             ReadQuoteStringOrAccClose(in, buf);
318             while (bNotAccClose(buf))
319             {
320                 AddFItemName(fitem, buf);
321                 ReadQuoteStringOrAccClose(in, buf);
322             }
323             break;
324         case edlgPM:
325         case edlgGB: ReadDlgErr(infile, eITEMEXP, type[edlg]); break;
326         default: break;
327     }
328     ReadQuoteString(infile, in, set);
329     ReadQuoteString(infile, in, get);
330     ReadQuoteString(infile, in, def);
331     ReadQuoteString(infile, in, help);
332     fitem->set  = gmx_strdup(set);
333     fitem->get  = gmx_strdup(get);
334     fitem->def  = gmx_strdup(def);
335     fitem->help = gmx_strdup(help);
336
337     return fitem;
338 }
339
340 t_fgrid* FGridFromFile(const char* infile)
341 {
342     char buf[STRLEN];
343     int  result;
344
345     t_fgrid*   fgrid;
346     t_fgroup*  fgroup;
347     t_fsimple* fsimple;
348     int        gridx, gridy;
349
350     gmx::FilePtr inGuard = gmx::openLibraryFile(infile);
351     FILE*        in      = inGuard.get();
352     result               = std::fscanf(in, "%6s", buf);
353     if ((1 != result) || std::strcmp(buf, "grid") != 0)
354     {
355         ReadDlgErr(infile, eGRIDEXP, buf);
356     }
357     fgrid = NewFGrid();
358     if ((fscanf(in, "%5d%5d", &gridx, &gridy)) != 2)
359     {
360         ReadDlgErr(infile, eNOVALS, "grid w,h");
361     }
362     fgrid->w = gridx;
363     fgrid->h = gridy;
364     ReadAccOpen(infile, in);
365     result = std::fscanf(in, "%15s", buf);
366     while ((1 == result) && bNotAccClose(buf))
367     {
368         if (strcmp(buf, "group") == 0)
369         {
370             fgroup = AddFGridFGroup(fgrid);
371             ReadQuoteString(infile, in, buf);
372             fgroup->name = gmx_strdup(buf);
373             if ((fscanf(in, "%5d%5d%5d%5d", &fgroup->x, &fgroup->y, &fgroup->w, &fgroup->h)) != 4)
374             {
375                 ReadDlgErr(infile, eNOVALS, "group x,y,w,h");
376             }
377             if (fgroup->x + fgroup->w > gridx)
378             {
379                 ReadDlgErr(infile, eTOOWIDE, buf);
380             }
381             if (fgroup->y + fgroup->h > gridy)
382             {
383                 ReadDlgErr(infile, eTOOHIGH, buf);
384             }
385             ReadAccOpen(infile, in);
386             result = std::fscanf(in, "%15s", buf);
387             while ((1 == result) && bNotAccClose(buf))
388             {
389                 AddFGroupFItem(fgroup, ScanFItem(infile, in, buf));
390                 result = std::fscanf(in, "%15s", buf);
391             }
392         }
393         else if (strcmp(buf, "simple") == 0)
394         {
395             fsimple = AddFGridFSimple(fgrid);
396             if ((fscanf(in, "%5d%5d%5d%5d", &fsimple->x, &fsimple->y, &fsimple->w, &fsimple->h)) != 4)
397             {
398                 ReadDlgErr(infile, eNOVALS, "simple x,y,w,h");
399             }
400             if (fsimple->x + fsimple->w > gridx)
401             {
402                 ReadDlgErr(infile, eTOOWIDE, "simple");
403             }
404             if (fsimple->y + fsimple->h > gridy)
405             {
406                 ReadDlgErr(infile, eTOOHIGH, "simple");
407             }
408             ReadAccOpen(infile, in);
409             result = std::fscanf(in, "%15s", buf);
410             if (1 == result)
411             {
412                 fsimple->fitem = ScanFItem(infile, in, buf);
413                 ReadAccClose(infile, in);
414             }
415         }
416         if (1 == result)
417         {
418             result = std::fscanf(in, "%15s", buf);
419         }
420     }
421     /* Since we always read one variable at a time the result from
422      * fscanf should always be 1.
423      */
424     if (1 != result)
425     {
426         ReadDlgErr(infile, eNOVALS, "fgrid");
427     }
428
429     return fgrid;
430 }
431
432 static void DumpFItem(t_fitem* fitem)
433 {
434     int i;
435
436     std::printf("  type: %s, set: '%s', get: '%s', def: '%s', help: '%s'\n  {", type[fitem->edlg],
437                 fitem->set, fitem->get, fitem->def, fitem->help);
438     for (i = 0; (i < fitem->nname); i++)
439     {
440         std::printf("  '%s'", fitem->name[i]);
441     }
442     std::printf("  }\n");
443 }
444
445 static void DumpFSimple(t_fsimple* fsimple)
446 {
447     std::printf("Simple %dx%d at %d,%d\n", fsimple->w, fsimple->h, fsimple->x, fsimple->y);
448     DumpFItem(fsimple->fitem);
449 }
450
451 static void DumpFGroup(t_fgroup* fgroup)
452 {
453     int i;
454
455     std::printf("Group %dx%d at %d,%d\n", fgroup->w, fgroup->h, fgroup->x, fgroup->y);
456     for (i = 0; (i < fgroup->nfitem); i++)
457     {
458         DumpFItem(fgroup->fitem[i]);
459     }
460 }
461
462 void DumpFGrid(t_fgrid* fgrid)
463 {
464     int i;
465
466     std::printf("Grid %dx%d\n", fgrid->w, fgrid->h);
467     for (i = 0; (i < fgrid->nfgroup); i++)
468     {
469         DumpFGroup(fgrid->fgroup[i]);
470     }
471     for (i = 0; (i < fgrid->nfsimple); i++)
472     {
473         DumpFSimple(fgrid->fsimple[i]);
474     }
475 }