fltk/fluid/code.cxx

317 lines
8.4 KiB
C++

//
// "$Id: code.cxx,v 1.9.2.2 1999/08/05 08:01:39 bill Exp $"
//
// Code output routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-1999 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems to "fltk-bugs@easysw.com".
//
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <FL/Fl.H>
#include "Fl_Type.h"
#include "alignment_panel.h"
static FILE *code_file;
static FILE *header_file;
// return true if c can be in a C identifier. I needed this so
// it is not messed up by locale settings:
int is_id(char c) {
return c>='a' && c<='z' || c>='A' && c<='Z' || c>='0' && c<='9' || c=='_';
}
////////////////////////////////////////////////////////////////
// Generate unique but human-readable identifiers:
struct id {
char* text;
void* object;
id *left, *right;
id (const char* t, void* o) : text(strdup(t)), object(o) {left = right = 0;}
~id();
};
id::~id() {
delete left;
free((void *)text);
delete right;
}
static id* id_root;
const char* unique_id(void* o, const char* type, const char* name, const char* label) {
char buffer[128];
char* q = buffer;
while (*type) *q++ = *type++;
*q++ = '_';
const char* n = name;
if (!n || !*n) n = label;
if (n && *n) {
while (!is_id(*n)) n++;
while (is_id(*n)) *q++ = *n++;
}
*q = 0;
// okay, search the tree and see if the name was already used:
id** p = &id_root;
int which = 0;
while (*p) {
int i = strcmp(buffer, (*p)->text);
if (!i) {
if ((*p)->object == o) return (*p)->text;
// already used, we need to pick a new name:
sprintf(q,"%x",++which);
p = &id_root;
continue;
}
else if (i < 0) p = &((*p)->left);
else p = &((*p)->right);
}
*p = new id(buffer, o);
return (*p)->text;
}
////////////////////////////////////////////////////////////////
// return current indentation:
static const char* spaces = " ";
int indentation;
const char* indent() {
int i = indentation; if (i>16) i = 16;
return spaces+16-i;
}
////////////////////////////////////////////////////////////////
// declarations/include files:
// Each string generated by write_declare is written only once to
// the header file. This is done by keeping a binary tree of all
// the calls so far and not printing it if it is in the tree.
struct included {
char *text;
included *left, *right;
included(const char *t) {
text = strdup(t);
left = right = 0;
}
~included();
};
included::~included() {
delete left;
free((void *)text);
delete right;
}
static included *included_root;
int write_declare(const char *format, ...) {
va_list args;
char buf[1024];
va_start(args, format);
vsprintf(buf, format, args);
va_end(args);
included **p = &included_root;
while (*p) {
int i = strcmp(buf,(*p)->text);
if (!i) return 0;
else if (i < 0) p = &((*p)->left);
else p = &((*p)->right);
}
fprintf(header_file,"%s\n",buf);
*p = new included(buf);
return 1;
}
////////////////////////////////////////////////////////////////
// silly thing to prevent declaring unused variables:
// When this symbol is on, all attempts to write code don't write
// anything, but set a variable if it looks like the varaible "o" is used:
int varused_test;
int varused;
// write an array of C characters (adds a null):
void write_cstring(const char *w, int length) {
if (varused_test) return;
const char *e = w+length;
int linelength = 1;
putc('\"', code_file);
for (; w < e;) {
int c = *w++;
switch (c) {
case '\b': c = 'b'; goto QUOTED;
case '\t': c = 't'; goto QUOTED;
case '\n': c = 'n'; goto QUOTED;
case '\f': c = 'f'; goto QUOTED;
case '\r': c = 'r'; goto QUOTED;
case '\"':
case '\'':
case '\\':
QUOTED:
if (linelength >= 77) {fputs("\\\n",code_file); linelength = 0;}
putc('\\', code_file);
putc(c, code_file);
linelength += 2;
break;
case '?': // prevent trigraphs by writing ?? as ?\?
if (*(w-2) == '?') goto QUOTED;
// else fall through:
default:
if (c >= ' ' && c < 127) {
// a legal ASCII character
if (linelength >= 78) {fputs("\\\n",code_file); linelength = 0;}
putc(c, code_file);
linelength++;
break;
}
// otherwise we must print it as an octal constant:
c &= 255;
if (c < 8) {
if (linelength >= 76) {fputs("\\\n",code_file); linelength = 0;}
fprintf(code_file, "\\%o",c);
linelength += 2;
} else if (c < 64) {
if (linelength >= 75) {fputs("\\\n",code_file); linelength = 0;}
fprintf(code_file, "\\%o",c);
linelength += 3;
} else {
if (linelength >= 74) {fputs("\\\n",code_file); linelength = 0;}
fprintf(code_file, "\\%o",c);
linelength += 4;
}
// We must not put more numbers after it, because some C compilers
// consume them as part of the quoted sequence. Use string constant
// pasting to avoid this:
c = *w;
if (w < e && (c>='0'&&c<='9' || c>='a'&&c<='f' || c>='A'&&c<='F')) {
putc('\"', code_file); linelength++;
if (linelength >= 79) {fputs("\n",code_file); linelength = 0;}
putc('\"', code_file); linelength++;
}
break;
}
}
putc('\"', code_file);
}
// write a C string, quoting characters if necessary:
void write_cstring(const char *w) {write_cstring(w,strlen(w));}
void write_c(const char* format,...) {
if (varused_test) {varused = 1; return;}
va_list args;
va_start(args, format);
vfprintf(code_file, format, args);
va_end(args);
}
void write_h(const char* format,...) {
if (varused_test) return;
va_list args;
va_start(args, format);
vfprintf(header_file, format, args);
va_end(args);
}
#include <FL/filename.H>
int write_number;
// recursively dump code, putting children between the two parts
// of the parent code:
static Fl_Type* write_code(Fl_Type* p) {
p->write_code1();
Fl_Type* q;
for (q = p->next; q && q->level > p->level;) q = write_code(q);
p->write_code2();
return q;
}
int write_code(const char *s, const char *t) {
write_number++;
delete id_root; id_root = 0;
indentation = 0;
if (!s) code_file = stdout;
else {
FILE *f = fopen(s,"w");
if (!f) return 0;
code_file = f;
}
if (!t) header_file = stdout;
else {
FILE *f = fopen(t,"w");
if (!f) {fclose(code_file); return 0;}
header_file = f;
}
const char *hdr = "\
// generated by Fast Light User Interface Designer (fluid) version %.2f\n\n";
fprintf(header_file, hdr, FL_VERSION);
fprintf(code_file, hdr, FL_VERSION);
{char define_name[102];
const char* a = filename_name(t);
char* b = define_name;
if (!isalpha(*a)) {*b++ = '_';}
while (*a) {*b++ = isalnum(*a) ? *a : '_'; a++;}
*b = 0;
fprintf(header_file, "#ifndef %s\n", define_name);
fprintf(header_file, "#define %s\n", define_name);
}
write_declare("#include <FL/Fl.H>");
if (t && include_H_from_C)
write_c("#include \"%s\"\n", filename_name(t));
for (Fl_Type* p = Fl_Type::first; p;) {
// write all static data for this & all children first
p->write_static();
for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next)
q->write_static();
// then write the nested code:
p = write_code(p);
}
delete included_root; included_root = 0;
if (!s) return 1;
int x = fclose(code_file);
code_file = 0;
fprintf(header_file, "#endif\n");
int y = fclose(header_file);
header_file = 0;
return x >= 0 && y >= 0;
}
////////////////////////////////////////////////////////////////
void Fl_Type::write_static() {}
void Fl_Type::write_code1() {
write_h("// Header for %s\n", title());
write_c("// Code for %s\n", title());
}
void Fl_Type::write_code2() {}
//
// End of "$Id: code.cxx,v 1.9.2.2 1999/08/05 08:01:39 bill Exp $".
//