ARB
AW_xfig.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : AW_xfig.cxx //
4 // Purpose : functions for processing xfig graphics //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "aw_xfig.hxx"
12 #include <aw_device.hxx>
13 #include "aw_msg.hxx"
14 
15 #include <arbdb.h>
16 #include <climits>
17 
18 inline int scaleAndRound(int unscaled, double scaleFactor) {
19  double scaled = double(unscaled)*scaleFactor;
20  return AW_INT(scaled);
21 }
22 
23 inline void setMinMax(int value, int& min, int& max) {
24  if (value<min) min = value;
25  if (value>max) max = value;
26 }
27 
28 class Xfig_Eater {
29  char *buffer;
30  const char *delim;
31 
32  char *p; // last return of strtok
33  bool failed;
34 
35  void nextToken() {
36  if (!failed) {
37  p = strtok(buffer, delim);
38  buffer = NULp;
39  if (!p) failed = true;
40  }
41  }
42 
43 public:
44  Xfig_Eater(char *buffer_, const char *delim_) : buffer(buffer_), delim(delim_) {
45  p = NULp;
46  failed = false;
47  }
48 
49  bool eat_int(int& what) {
50  nextToken();
51  if (failed) return false;
52  what = atoi(p);
53  return true;
54  }
55 
56  bool ignore(unsigned count=1) {
57  while (count-->0) {
58  nextToken();
59  if (failed) return false;
60  }
61  return true;
62  }
63 
64  char *get_rest() {
65  if (failed || !p) return NULp;
66  return p+strlen(p)+1;
67  }
68 };
69 
70 void AW_xfig::calc_scaling(int font_width, int font_height) {
71  double font_x_scale = abs(font_width) / (double) XFIG_DEFAULT_FONT_WIDTH;
72  double font_y_scale = abs(font_height) / (double) XFIG_DEFAULT_FONT_HEIGHT;
73 
74  font_scale = font_x_scale>font_y_scale ? font_x_scale : font_y_scale;
76 }
77 
78 AW_xfig::AW_xfig(int font_width, int font_height) {
79  // creates the same as loading an empty xfig
80  init(font_width, font_height);
81 }
82 
83 AW_xfig::AW_xfig(const char *filename, int font_width, int font_height) {
84  /* Arguments: xfig file, fontsize (>0: abort on error - normal usage!
85  * <0: returns NULp on error)
86  *
87  * Returns: graphical data or NULp or exit!
88  *
89  * Description: load xfig graphical data for construction of windows,
90  */
91  aw_assert(filename && filename[0]);
92  init(font_width, font_height);
93 
94  // ----------------
95 
97  char *ret;
98  char *buffer = ARB_calloc<char>(MAX_XFIG_LENGTH);
99  FILE *file = NULp;
100 
101  if (filename[0]=='/') { // absolute file ?
102  strcpy(buffer, filename);
103  file = fopen(buffer, "r");
104  }
105  else {
106  const char *fileInLib = GB_concat_path_in_ARBLIB("pictures", filename);
107 
108  strcpy(buffer, fileInLib);
109  file = fopen(fileInLib, "r");
110 
111  // Note: before 12/2008 file was also searched in $ARBHOME and current dir
112  }
113 
114  if (!file) {
115  error = GBS_global_string("Can't locate '%s'", filename);
116  }
117  else {
118  char *expanded_filename = strdup(buffer);
119  int lineNumber = 0;
120 
121  ret = fgets(buffer, MAX_XFIG_LENGTH, file); ++lineNumber;
122  if (!ret || strncmp("#FIG", ret, 4)) {
123  error = "Expected XFIG format";
124  }
125  else {
126  enum {
127  XFIG_UNKNOWN,
128  XFIG_OLD_FORMAT, // XFIG 2.1 saves old format
129  XFIG_NEW_FORMAT, // XFIG 3.2 saves new format
130  XFIG_UNSUPPORTED
131 
132  } version = XFIG_UNKNOWN;
133 
134  char *xfig_version = strchr(ret, ' ');
135 
136  if (!xfig_version) {
137  error = "Missing version info";
138  }
139  else {
140  int mainVersion = 0;
141  int subVersion = 0;
142  *xfig_version++ = 0;
143  mainVersion = atoi(xfig_version);
144 
145  char *vers_point = strchr(xfig_version, '.');
146  if (vers_point) {
147  *vers_point++ = 0;
148  subVersion = atoi(vers_point);
149  }
150  else {
151  subVersion = 0; // none
152  }
153 
154  if (mainVersion>3 || (mainVersion==3 && subVersion>2)) {
155  version = XFIG_UNSUPPORTED; // unsupported (maybe only untested)
156  error = "Xfig-format above 3.2 not supported";
157  }
158  else {
159  if (mainVersion==3 && subVersion==2) {
160  version = XFIG_NEW_FORMAT;
161  }
162  else {
163  version = XFIG_OLD_FORMAT;
164  }
165  }
166  }
167  if (!error) {
168  ret = fgets(buffer, MAX_XFIG_LENGTH, file); ++lineNumber;
169  if (!ret) error = "Unexpected end of file";
170  }
171 
172  if (!error) {
174 
175  maxx = maxy = 0;
176  minx = miny = INT_MAX;
177 
178  if (version==XFIG_NEW_FORMAT) { // XFIG 3.2 format
179  // new xfig format has the following changes:
180  //
181  // - header (see just below)
182  // - lines do not end with 9999 9999
183  // - ??? maybe more changes
184 
185 
186  // over-read xfig-header:
187  // Landscape
188  // Center
189  // Metric
190  // A4
191  // 100.00
192  // Single
193  // -2
194 
195  int count;
196  for (count = 0;
197  ret && count<=6;
198  ret=fgets(buffer, MAX_XFIG_LENGTH, file), count++, ++lineNumber)
199  {
200  const char *awaited = NULp;
201  switch (count) {
202  case 0: awaited = "Landscape"; break;
203  case 1: awaited = "Center"; break;
204  case 2: awaited = "Metric"; break;
205  case 3: awaited = "A4"; break;
206  case 4: awaited = ""; break; // accept any magnification (accepted only 100 before)
207  case 5: awaited = "Single"; break;
208  case 6: awaited = "-2"; break;
209  default: aw_assert(0);
210  }
211 
212  if (strncmp(ret, awaited, strlen(awaited))!=0) {
213  error = GBS_global_string("'%s' expected", awaited);
214  }
215  }
216  }
217  }
218 
219  if (!error) {
220  // read resolution
221  int dpi = 80;
222  int default_dpi = 80; // used in old version (before 3.2)
223  if (ret) {
224  char *p = strtok(ret, "\t");
225  if (p) dpi = atoi(p);
226 
227  ret = fgets(buffer, MAX_XFIG_LENGTH, file); ++lineNumber;
228 
229  if (dpi!=default_dpi) dpi_scale = font_scale * (double(default_dpi)/double(dpi));
230  }
231 
232  while (ret) {
233  bool got_nextline = false;
234  char *p;
235  int width = 0;
236  int color = 0;
237  int x, y;
238 
239  if (ret[0]=='2') { // lines
240  int oldx = 0, oldy = 0;
241 
242  {
243  Xfig_Eater args(ret, " \t");
244 
245  bool ok =
246  args.ignore(3) && // ignore '2', type, depth
247  args.eat_int(width) && // width
248  args.eat_int(color); // color
249 
250  if (!ok) break;
251  }
252 
253  while (1) {
254  ret = fgets(buffer, MAX_XFIG_LENGTH, file); ++lineNumber;
255  if (!ret) break;
256  if (ret[0]!='\t') {
257  got_nextline = true;
258  break;
259  }
260 
261  Xfig_Eater args(ret, " \t");
262  bool ok = true;
263  oldx = oldy = INT_MAX;
264 
265  while (ok) {
266  ok = args.eat_int(x) && args.eat_int(y);
267  if (!ok) break;
268 
269  // 9999/9999 is the end of line-points marker in old version
270  if (version==XFIG_OLD_FORMAT && x==9999 && y==9999) break;
271 
272  x = scaleAndRound(x, dpi_scale);
273  y = scaleAndRound(y, dpi_scale);
274 
275  setMinMax(x, minx, maxx);
276  setMinMax(y, miny, maxy);
277 
278  aw_assert(x>=0 && y>=0);
279 
280  if (oldx == INT_MAX && oldy == INT_MAX) {
281  oldx = x;
282  oldy = y;
283  continue;
284  }
285 
286  struct AW_xfig_line *xline = new AW_xfig_line;
287  if (width >= MAX_LINE_WIDTH) width = MAX_LINE_WIDTH - 1;
288  xline->next = line[width];
289  line[width] = xline;
290  xline->x0 = oldx;
291  xline->y0 = oldy;
292  xline->x1 = x;
293  xline->y1 = y;
294  oldx = x;
295  oldy = y;
296  xline->color = color;
297  }
298  }
299 
300  }
301  else if (ret[0]=='4') { // text
302  int align;
303  int fontnr = -1;
304  int fontsize = -1;
305 
306  // old format: 4 align font fontsize depth color ??? angle justi flags width x y text
307  // new format: 4 align color depth ??? font fontsize angle justi flags width x y text
308  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309 
310  Xfig_Eater args(ret, " \t");
311 
312  bool ok =
313  args.ignore(1) && // the '4'
314  args.eat_int(align); // align
315 
316  if (ok) {
317  if (version==XFIG_OLD_FORMAT) {
318  ok =
319  args.eat_int(fontnr) && // font
320  args.eat_int(fontsize) && // fontsize
321  args.ignore(1) && // depth
322  args.eat_int(color) && // color
323  args.ignore(1); // ???
324  }
325  else {
326  aw_assert(version==XFIG_NEW_FORMAT);
327 
328  ok =
329  args.eat_int(color) && // color
330  args.ignore(1) && // depth
331  args.ignore(1) && // ???
332  args.eat_int(fontnr) && // font
333  args.eat_int(fontsize); // fontsize
334  }
335 
336  if (ok) {
337  ok =
338  args.ignore(3) && // angle, justi, flags
339  args.eat_int(width) && // width
340  args.eat_int(x) && // x
341  args.eat_int(y); // y
342 
343  }
344  }
345 
346  if (ok && (p=args.get_rest())) {
347  x = scaleAndRound(x, dpi_scale);
348  y = scaleAndRound(y, dpi_scale);
349 
350  while (*p==' ' || *p=='\t') ++p;
351 
352  char *endf = strchr(p, 1); // search for ASCII-1 (new EOL-marker)
353  char *endf2 = GBS_find_string(p, "\\001", 0); // search for "\001" (Pseudo-ASCII-1)
354  if (endf || endf2) {
355  if (endf) *endf = 0;
356  if (endf2) *endf2 = 0;
357  }
358 
359  if (*p=='$') { // text starts with a '$'
360  // place a button
361  if (strcmp(p, "$$") == 0) {
362  this->centerx = x;
363  this->centery = y;
364  }
365  else {
366  struct AW_xfig_pos *xpos = new AW_xfig_pos;
367 
368  xpos->center = align;
369  xpos->x = x;
370  xpos->y = y;
371 
372  GBS_write_hash(at_pos_hash, p+1, (long)xpos);
373  }
374  }
375  else {
376  struct AW_xfig_text *xtext = new AW_xfig_text;
377  xtext->x = x;
378  xtext->y = y;
379 
380  if (x>maxx) maxx = x;
381  if (y>maxy) maxy = y;
382  if (x<minx) minx = x;
383  if (y<miny) miny = y;
384 
385  xtext->text = strdup(p);
386  xtext->fontsize = fontsize;
387  xtext->color = color;
388  xtext->center = align;
389  xtext->font = fontnr;
390  xtext->next = text;
391  text = xtext;
392  }
393  }
394 
395  }
396 
397  if (!got_nextline) {
398  ret = fgets(buffer, MAX_XFIG_LENGTH, file); ++lineNumber;
399  }
400  }
401 
402  this->size_x = maxx - minx;
403  this->size_y = maxy - miny;
404  }
405  }
406 
407  if (error) { // append file-info to error
408  aw_assert(expanded_filename);
409  error = GBS_global_string("While reading %s:%i:\nError: %s", expanded_filename, lineNumber, error);
410  }
411 
412  free(expanded_filename);
413  fclose(file);
414  }
415 
416  free(buffer);
417 
418  if (error) {
419  error = GBS_global_string("Failed to read XFIG resource (defect installation?)\n"
420  "Reason: %s", error);
421 
422  if (font_width>0 && font_height>0) { // react with fatal exit
423  GBK_terminate(error);
424  }
425 
426  // special case (used by aw_read_xfigfont())
427  aw_message(error);
428  }
429 }
430 
431 static long aw_xfig_hash_free_loop(const char *, long val, void *) {
432  free((void*)val);
433  return 0;
434 }
435 
437  int i;
438 
439  if (at_pos_hash) {
442  }
443  struct AW_xfig_text *xtext;
444  while (text) {
445  xtext = text;
446  text = text->next;
447  delete xtext->text;
448  delete xtext;
449  }
450 
451  struct AW_xfig_line *xline;
452  for (i=0; i<MAX_LINE_WIDTH; i++) {
453  while (line[i]) {
454  xline = line[i];
455  line[i] = xline->next;
456  delete xline;
457  }
458  }
459 }
460 
461 void AW_xfig::print(AW_device *device) {
462  const AW_screen_area& window_size = device->get_area_size();
463  device->clear(-1);
464  struct AW_xfig_text *xtext;
465  for (xtext = text; xtext; xtext=xtext->next) {
466  char *str = xtext->text;
467 
468  if (str[0]) {
469  int x = xtext->x;
470  int y = xtext->y;
471 
472  if (str[1]) {
473  if (str[1] == ':') {
474  if (str[0] == 'Y') {
475  y += (window_size.b - window_size.t)- size_y;
476  str += 2;
477  }
478  else if (str[0] == 'X') {
479  x += (window_size.r - window_size.l)- size_x;
480  str += 2;
481  }
482  }
483  else if (str[2] == ':' && str[0] == 'X' && str[1] == 'Y') {
484  x += (window_size.r - window_size.l)- size_x;
485  y += (window_size.b - window_size.t)- size_y;
486  str += 3;
487  }
488  }
489 
490  device->text(xtext->gc, str, (AW_pos)x, (AW_pos)y, (AW_pos)xtext->center*.5, AW_ALL_DEVICES_UNSCALED);
491  }
492  }
493 
494  struct AW_xfig_line *xline;
495  for (int i=0; i<MAX_LINE_WIDTH; i++) {
496  int line_width = std::max(1, scaleAndRound(i, font_scale));
497  device->set_line_attributes(0, line_width, AW_SOLID);
498  for (xline = line[i]; xline; xline=xline->next) {
499  device->line(0, (AW_pos)xline->x0, (AW_pos)xline->y0, (AW_pos)xline->x1, (AW_pos)xline->y1);
500  }
501  }
502 }
503 
504 void AW_xfig::create_gcs(AW_device *device, int depth) {
505  GB_HASH *gchash;
506  int gc;
507  char fontstring[100];
508  gchash = GBS_create_hash(100, GB_MIND_CASE);
509 
510  struct AW_xfig_text *xtext;
511  gc = 0;
512  device->new_gc(gc); // create at least one gc ( 0 ) for the lines
513  device->set_foreground_color(gc, AW_WINDOW_FG);
514  if (depth<=1) device->set_function(gc, AW_XOR);
515  device->set_line_attributes(gc, 1, AW_SOLID);
516  gc = 1; // create gc for texts
517  for (xtext = text; xtext; xtext=xtext->next) {
518  sprintf(fontstring, "%i-%i", xtext->font, scaleAndRound(xtext->fontsize, font_scale));
519  if (!(xtext->gc = (int)GBS_read_hash(gchash, fontstring))) {
520  device->new_gc(gc);
521  device->set_line_attributes(gc, 1, AW_SOLID);
522  device->set_font(gc, xtext->font, scaleAndRound(xtext->fontsize, font_scale), NULp);
523  device->set_foreground_color(gc, AW_WINDOW_FG);
524  if (depth<=1) device->set_function(gc, AW_XOR);
525  xtext->gc = gc;
526  GBS_write_hash(gchash, fontstring, gc);
527  gc++;
528  }
529  }
530  GBS_free_hash(gchash);
531 }
532 
533 void AW_xfig::add_line(int x1, int y1, int x2, int y2, int width) { // add a line to xfig
534  struct AW_xfig_line *xline = new AW_xfig_line;
535 
536  x1 = scaleAndRound(x1, dpi_scale);
537  x2 = scaleAndRound(x2, dpi_scale);
538  y1 = scaleAndRound(y1, dpi_scale);
539  y2 = scaleAndRound(y2, dpi_scale);
540 
541  setMinMax(x1, minx, maxx);
542  setMinMax(y1, miny, maxy);
543  setMinMax(x2, minx, maxx);
544  setMinMax(y2, miny, maxy);
545 
546  xline->x0 = x1;
547  xline->y0 = y1;
548  xline->x1 = x2;
549  xline->y1 = y2;
550 
551  xline->color = 1;
552 
553  if (width >= MAX_LINE_WIDTH) width = MAX_LINE_WIDTH - 1;
554 
555  xline->next = line[width];
556  line[width] = xline;
557 }
short x0
Definition: aw_xfig.hxx:38
virtual void clear(AW_bitset filteri)
Definition: AW_device.cxx:313
short color
Definition: aw_xfig.hxx:40
const int MAX_XFIG_LENGTH
Definition: aw_xfig.hxx:29
const int MAX_LINE_WIDTH
Definition: aw_xfig.hxx:28
double dpi_scale
Definition: aw_xfig.hxx:91
const AW_screen_area & get_area_size() const
Definition: AW_device.cxx:57
static char * y[maxsp+1]
long GBS_write_hash(GB_HASH *hs, const char *key, long val)
Definition: adhash.cxx:454
void set_line_attributes(int gc, short width, AW_linestyle style)
Definition: AW_device.cxx:465
void set_function(int gc, AW_function function)
Definition: AW_device.cxx:468
short y
Definition: aw_xfig.hxx:58
struct AW_xfig_line * line[MAX_LINE_WIDTH]
Definition: aw_xfig.hxx:81
int size_y
Definition: aw_xfig.hxx:87
int maxx
Definition: aw_xfig.hxx:86
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
AW_xfig(const char *filename, int font_width, int font_height)
Definition: AW_xfig.cxx:83
short fontsize
Definition: aw_xfig.hxx:51
static float fontsize
Definition: arb_a2ps.c:317
void GBS_free_hash(GB_HASH *hs)
Definition: adhash.cxx:538
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
short color
Definition: aw_xfig.hxx:53
GB_CSTR GBS_find_string(GB_CSTR cont, GB_CSTR substr, int match_mode)
Definition: admatch.cxx:103
double font_scale
Definition: aw_xfig.hxx:90
bool ignore(unsigned count=1)
Definition: AW_xfig.cxx:56
double AW_pos
Definition: aw_base.hxx:29
void set_font(int gc, AW_font fontnr, int size, int *found_size)
Definition: AW_device.cxx:458
void set_foreground_color(int gc, AW_color_idx color)
Definition: AW_device.cxx:471
int miny
Definition: aw_xfig.hxx:85
void new_gc(int gc)
Definition: AW_device.cxx:449
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:509
bool eat_int(int &what)
Definition: AW_xfig.cxx:49
~AW_xfig()
Definition: AW_xfig.cxx:436
#define aw_assert(bed)
Definition: aw_position.hxx:29
int size_x
Definition: aw_xfig.hxx:87
char * get_rest()
Definition: AW_xfig.cxx:64
bool line(int gc, const AW::LineVector &Line, AW_bitset filteri=AW_ALL_DEVICES_SCALED)
Definition: aw_device.hxx:430
int centerx
Definition: aw_xfig.hxx:88
static void error(const char *msg)
Definition: mkptypes.cxx:96
struct AW_xfig_line * next
Definition: aw_xfig.hxx:36
AW_font font
Definition: aw_xfig.hxx:50
int center
Definition: aw_xfig.hxx:59
struct AW_xfig_text * text
Definition: aw_xfig.hxx:80
int centery
Definition: aw_xfig.hxx:88
void GBS_hash_do_loop(GB_HASH *hs, gb_hash_loop_type func, void *client_data)
Definition: adhash.cxx:545
int maxy
Definition: aw_xfig.hxx:86
const int XFIG_DEFAULT_FONT_WIDTH
Definition: aw_xfig.hxx:25
void create_gcs(AW_device *device, int screen_depth)
Definition: AW_xfig.cxx:504
int scaleAndRound(int unscaled, double scaleFactor)
Definition: AW_xfig.cxx:18
void setMinMax(int value, int &min, int &max)
Definition: AW_xfig.cxx:23
char * text
Definition: aw_xfig.hxx:49
GB_CSTR GB_concat_path_in_ARBLIB(const char *relative_path_left, const char *anypath_right)
Definition: adsocket.cxx:1159
#define abs(x)
Definition: f2c.h:151
const AW_bitset AW_ALL_DEVICES_UNSCALED
Definition: aw_device.hxx:46
short x1
Definition: aw_xfig.hxx:39
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
Xfig_Eater(char *buffer_, const char *delim_)
Definition: AW_xfig.cxx:44
void add_line(int x1, int y1, int x2, int y2, int width)
Definition: AW_xfig.cxx:533
#define NULp
Definition: cxxforward.h:116
short x
Definition: aw_xfig.hxx:58
short y0
Definition: aw_xfig.hxx:38
void print(AW_device *device)
Definition: AW_xfig.cxx:461
static long aw_xfig_hash_free_loop(const char *, long val, void *)
Definition: AW_xfig.cxx:431
GB_HASH * at_pos_hash
Definition: aw_xfig.hxx:83
#define min(a, b)
Definition: f2c.h:153
int minx
Definition: aw_xfig.hxx:85
bool text(int gc, const SizedCstr &cstr, const AW::Position &pos, AW_pos alignment=0.0, AW_bitset filteri=AW_ALL_DEVICES_UNSCALED)
Definition: aw_device.hxx:440
long GBS_read_hash(const GB_HASH *hs, const char *key)
Definition: adhash.cxx:392
struct AW_xfig_text * next
Definition: aw_xfig.hxx:45
short y1
Definition: aw_xfig.hxx:39
GB_HASH * GBS_create_hash(long estimated_elements, GB_CASE case_sens)
Definition: adhash.cxx:253
const int XFIG_DEFAULT_FONT_HEIGHT
Definition: aw_xfig.hxx:26
#define max(a, b)
Definition: f2c.h:154