123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /*
- * A quick and dirty implementation of the meta object compiler.
- *
- * Worst limitations:
- * - Signals and Slots cannot have arguments;
- * - Parsing is done on lines, not on tokens;
- * - Comments are not handled properly;
- * - Matching is primitive, so certain styles of indentation may fail.
- */
- #include <ctype.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define MAX_LINE_SIZE 1024
- #define MAX_CLASS_NAME 64
- #define MAX_SIGNAL_NAME 64
- #define MAX_SIGNALS_NO 36
- #define MAX_SLOT_NAME 64
- #define MAX_SLOTS_NO 36
- /* Current line number. */
- int lineno;
- /* Current class name. */
- char classname[MAX_CLASS_NAME];
- /* Registered signals. */
- char signals[MAX_SIGNAL_NAME][MAX_SIGNALS_NO];
- /* Registered slots. */
- char slots[MAX_SIGNAL_NAME][MAX_SIGNALS_NO];
- /* Number of registered signals. */
- int signals_no;
- /* Number of registered slots. */
- int slots_no;
- /* Removes whitespaces at the beginning and the end of the string */
- void eat_spaces(char *buf)
- {
- char *p = buf;
- while (isspace(*p)) // remove prefix whitespace
- ++p;
- if (p > buf)
- memmove(buf, p, strlen(p) + 1);
- p = buf;
- while (*p != '\0') // skip to end of string
- ++p;
- while (p > buf && isspace(*(p - 1))) { // remove trailing whitespace
- --p;
- *p = '\0';
- }
- }
- /* Extracts "QPushButton" from the string "class QPushButton : public QWidget {" */
- char *make_classname(char *buf)
- {
- char *p = buf + 5; // "class" already matched
- while (isspace(*p)) // skip whitespace
- ++p;
- buf = p;
- while (isalnum(*p) || *p == '_')
- ++p;
- *p = '\0';
- return buf;
- }
- /* Extracts "clicked()" from the string "void clicked();" */
- char *make_signal(char *buf)
- {
- char *p = buf;
- while (*p != 0 && *p != '(')
- ++p;
- if (*p == '\0')
- return NULL;
- --p;
- while (p > buf && (isalnum(*p) || *p == '_'))
- --p;
- buf = p + 1;
- while (*p != '\0')
- ++p;
- if (*(p - 1) != ';' || *(p - 2) != ')') {
- fprintf(stderr, "minimoc: invalid signal at line %d\n", lineno);
- return NULL;
- }
- *(p - 1) = '\0'; // Remove ending ';'
- return buf;
- }
- int end_of_signals(char *buf)
- {
- return *buf == '}' || !strncmp(buf, "public", 6) || !strncmp(buf, "private", 7)
- || !strncmp(buf, "protected", 9);
- }
- int end_of_slots(char *buf)
- {
- return *buf == '}' || !strncmp(buf, "public", 6) || !strncmp(buf, "private", 7)
- || !strncmp(buf, "protected", 9) || !strcmp(buf, "signals");
- }
- void add_signal(char *signal)
- {
- strcpy(signals[signals_no], signal);
- ++signals_no;
- }
- void add_slot(char *slot)
- {
- strcpy(slots[slots_no], slot);
- ++slots_no;
- }
- void emit_class_decl(FILE *fout, char *inname)
- {
- int i;
- static int header = 0;
- if (!header) {
- fprintf(fout, "// Automatically generated by the mini meta object compiler\n"
- "// from the source file \"%s\"\n"
- "// DO NOT EDIT!\n\n"
- "#include <qobject.h>\n\n"
- "#include \"%s\"\n\n", inname, inname);
- header = 1;
- }
- // className() function
- fprintf(fout, "const char *%s::className() const\n{\n\treturn \"%s\";\n}\n\n",
- classname, classname);
- // initMetaObject() function
- fprintf(fout, "void %s::initMetaObject()\n{\n"
- "\tif (moc_check.wasInitialized())\n"
- "\t\treturn;\n"
- "\tmoc_check.initialize();\n",
- classname);
- for (i = 0; i < signals_no; ++i)
- fprintf(fout, "\tregisterSignal(\"%s\");\n",
- signals[i]);
- for (i = 0; i < slots_no; ++i) {
- char buf[MAX_SLOT_NAME];
- strcpy(buf, slots[i]);
- buf[strlen(slots[i]) - 2] = '\0';
- fprintf(fout, "\tregisterSlot(\"%s\", this, (QMember)&%s::%s);\n",
- slots[i], classname, buf);
- }
- fprintf(fout, "}\n\n");
- // signal functions
- for (i = 0; i < signals_no; ++i) {
- fprintf(fout, "void %s::%s\n{\n",
- classname, signals[i]);
- fprintf(fout, "\tcalledSignal(\"%s\");\n}\n\n",
- signals[i]);
- }
- }
- void process_file(char *inname, char *outname)
- {
- FILE *fin, *fout;
- char buf[MAX_LINE_SIZE];
- int haveqobject = 0;
- int insignals = 0, inslots = 0;
- int havedef = 0;
- if ((fin = fopen(inname, "r")) == NULL) {
- fprintf(stderr, "minimoc: %s: %s\n", inname, strerror(errno));
- exit(1);
- }
- if ((fout = fopen(outname, "w")) == NULL) {
- fprintf(stderr, "minimoc: %s: %s\n", outname, strerror(errno));
- exit(1);
- }
- lineno = 0;
- while (fgets(buf, MAX_LINE_SIZE, fin) != NULL) {
- ++lineno;
- eat_spaces(buf);
- if (strlen(buf) < 1)
- continue;
- if (insignals && !end_of_signals(buf)) {
- char *sig = make_signal(buf);
- if (sig != NULL)
- add_signal(sig);
- } else if (insignals) {
- insignals = 0;
- }
- if (inslots && !end_of_slots(buf)) {
- char *sig = make_signal(buf);
- if (sig != NULL)
- add_slot(sig);
- } else if (inslots) {
- inslots = 0;
- }
- if (!strncmp(buf, "class", 5)) {
- if (havedef)
- emit_class_decl(fout, inname);
- havedef = 0;
- strcpy(classname, make_classname(buf));
- haveqobject = 0;
- insignals = 0;
- inslots = 0;
- signals_no = 0;
- slots_no = 0;
- } else if (!strcmp(buf, "Q_OBJECT")) {
- haveqobject = 1;
- } else if (!strcmp(buf, "signals:")) {
- if (!haveqobject)
- fprintf(stderr, "minimoc: warning: Q_OBJECT not found in class %s\n", classname);
- havedef = 1;
- insignals = 1;
- } else if (!strcmp(buf, "public slots:")
- || !strcmp(buf, "protected slots:")
- || !strcmp(buf, "private slots:")) {
- if (!haveqobject)
- fprintf(stderr, "minimoc: warning: Q_OBJECT not found in class %s\n", classname);
- havedef = 1;
- inslots = 1;
- }
- }
- if (havedef)
- emit_class_decl(fout, inname);
- fclose(fin);
- fclose(fout);
- }
- int main(int argc, char **argv)
- {
- if (argc != 3) {
- fprintf(stderr, "The Mini Meta Object Compiler\n"
- "usage: minimoc <infile> <outfile>\n");
- return 1;
- }
- process_file(argv[1], argv[2]);
- return 0;
- }
|