minimoc.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * A quick and dirty implementation of the meta object compiler.
  3. *
  4. * Worst limitations:
  5. * - Signals and Slots cannot have arguments;
  6. * - Parsing is done on lines, not on tokens;
  7. * - Comments are not handled properly;
  8. * - Matching is primitive, so certain styles of indentation may fail.
  9. */
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #define MAX_LINE_SIZE 1024
  16. #define MAX_CLASS_NAME 64
  17. #define MAX_SIGNAL_NAME 64
  18. #define MAX_SIGNALS_NO 36
  19. #define MAX_SLOT_NAME 64
  20. #define MAX_SLOTS_NO 36
  21. /* Current line number. */
  22. int lineno;
  23. /* Current class name. */
  24. char classname[MAX_CLASS_NAME];
  25. /* Registered signals. */
  26. char signals[MAX_SIGNAL_NAME][MAX_SIGNALS_NO];
  27. /* Registered slots. */
  28. char slots[MAX_SIGNAL_NAME][MAX_SIGNALS_NO];
  29. /* Number of registered signals. */
  30. int signals_no;
  31. /* Number of registered slots. */
  32. int slots_no;
  33. /* Removes whitespaces at the beginning and the end of the string */
  34. void eat_spaces(char *buf)
  35. {
  36. char *p = buf;
  37. while (isspace(*p)) // remove prefix whitespace
  38. ++p;
  39. if (p > buf)
  40. memmove(buf, p, strlen(p) + 1);
  41. p = buf;
  42. while (*p != '\0') // skip to end of string
  43. ++p;
  44. while (p > buf && isspace(*(p - 1))) { // remove trailing whitespace
  45. --p;
  46. *p = '\0';
  47. }
  48. }
  49. /* Extracts "QPushButton" from the string "class QPushButton : public QWidget {" */
  50. char *make_classname(char *buf)
  51. {
  52. char *p = buf + 5; // "class" already matched
  53. while (isspace(*p)) // skip whitespace
  54. ++p;
  55. buf = p;
  56. while (isalnum(*p) || *p == '_')
  57. ++p;
  58. *p = '\0';
  59. return buf;
  60. }
  61. /* Extracts "clicked()" from the string "void clicked();" */
  62. char *make_signal(char *buf)
  63. {
  64. char *p = buf;
  65. while (*p != 0 && *p != '(')
  66. ++p;
  67. if (*p == '\0')
  68. return NULL;
  69. --p;
  70. while (p > buf && (isalnum(*p) || *p == '_'))
  71. --p;
  72. buf = p + 1;
  73. while (*p != '\0')
  74. ++p;
  75. if (*(p - 1) != ';' || *(p - 2) != ')') {
  76. fprintf(stderr, "minimoc: invalid signal at line %d\n", lineno);
  77. return NULL;
  78. }
  79. *(p - 1) = '\0'; // Remove ending ';'
  80. return buf;
  81. }
  82. int end_of_signals(char *buf)
  83. {
  84. return *buf == '}' || !strncmp(buf, "public", 6) || !strncmp(buf, "private", 7)
  85. || !strncmp(buf, "protected", 9);
  86. }
  87. int end_of_slots(char *buf)
  88. {
  89. return *buf == '}' || !strncmp(buf, "public", 6) || !strncmp(buf, "private", 7)
  90. || !strncmp(buf, "protected", 9) || !strcmp(buf, "signals");
  91. }
  92. void add_signal(char *signal)
  93. {
  94. strcpy(signals[signals_no], signal);
  95. ++signals_no;
  96. }
  97. void add_slot(char *slot)
  98. {
  99. strcpy(slots[slots_no], slot);
  100. ++slots_no;
  101. }
  102. void emit_class_decl(FILE *fout, char *inname)
  103. {
  104. int i;
  105. static int header = 0;
  106. if (!header) {
  107. fprintf(fout, "// Automatically generated by the mini meta object compiler\n"
  108. "// from the source file \"%s\"\n"
  109. "// DO NOT EDIT!\n\n"
  110. "#include <qobject.h>\n\n"
  111. "#include \"%s\"\n\n", inname, inname);
  112. header = 1;
  113. }
  114. // className() function
  115. fprintf(fout, "const char *%s::className() const\n{\n\treturn \"%s\";\n}\n\n",
  116. classname, classname);
  117. // initMetaObject() function
  118. fprintf(fout, "void %s::initMetaObject()\n{\n"
  119. "\tif (moc_check.wasInitialized())\n"
  120. "\t\treturn;\n"
  121. "\tmoc_check.initialize();\n",
  122. classname);
  123. for (i = 0; i < signals_no; ++i)
  124. fprintf(fout, "\tregisterSignal(\"%s\");\n",
  125. signals[i]);
  126. for (i = 0; i < slots_no; ++i) {
  127. char buf[MAX_SLOT_NAME];
  128. strcpy(buf, slots[i]);
  129. buf[strlen(slots[i]) - 2] = '\0';
  130. fprintf(fout, "\tregisterSlot(\"%s\", this, (QMember)&%s::%s);\n",
  131. slots[i], classname, buf);
  132. }
  133. fprintf(fout, "}\n\n");
  134. // signal functions
  135. for (i = 0; i < signals_no; ++i) {
  136. fprintf(fout, "void %s::%s\n{\n",
  137. classname, signals[i]);
  138. fprintf(fout, "\tcalledSignal(\"%s\");\n}\n\n",
  139. signals[i]);
  140. }
  141. }
  142. void process_file(char *inname, char *outname)
  143. {
  144. FILE *fin, *fout;
  145. char buf[MAX_LINE_SIZE];
  146. int haveqobject = 0;
  147. int insignals = 0, inslots = 0;
  148. int havedef = 0;
  149. if ((fin = fopen(inname, "r")) == NULL) {
  150. fprintf(stderr, "minimoc: %s: %s\n", inname, strerror(errno));
  151. exit(1);
  152. }
  153. if ((fout = fopen(outname, "w")) == NULL) {
  154. fprintf(stderr, "minimoc: %s: %s\n", outname, strerror(errno));
  155. exit(1);
  156. }
  157. lineno = 0;
  158. while (fgets(buf, MAX_LINE_SIZE, fin) != NULL) {
  159. ++lineno;
  160. eat_spaces(buf);
  161. if (strlen(buf) < 1)
  162. continue;
  163. if (insignals && !end_of_signals(buf)) {
  164. char *sig = make_signal(buf);
  165. if (sig != NULL)
  166. add_signal(sig);
  167. } else if (insignals) {
  168. insignals = 0;
  169. }
  170. if (inslots && !end_of_slots(buf)) {
  171. char *sig = make_signal(buf);
  172. if (sig != NULL)
  173. add_slot(sig);
  174. } else if (inslots) {
  175. inslots = 0;
  176. }
  177. if (!strncmp(buf, "class", 5)) {
  178. if (havedef)
  179. emit_class_decl(fout, inname);
  180. havedef = 0;
  181. strcpy(classname, make_classname(buf));
  182. haveqobject = 0;
  183. insignals = 0;
  184. inslots = 0;
  185. signals_no = 0;
  186. slots_no = 0;
  187. } else if (!strcmp(buf, "Q_OBJECT")) {
  188. haveqobject = 1;
  189. } else if (!strcmp(buf, "signals:")) {
  190. if (!haveqobject)
  191. fprintf(stderr, "minimoc: warning: Q_OBJECT not found in class %s\n", classname);
  192. havedef = 1;
  193. insignals = 1;
  194. } else if (!strcmp(buf, "public slots:")
  195. || !strcmp(buf, "protected slots:")
  196. || !strcmp(buf, "private slots:")) {
  197. if (!haveqobject)
  198. fprintf(stderr, "minimoc: warning: Q_OBJECT not found in class %s\n", classname);
  199. havedef = 1;
  200. inslots = 1;
  201. }
  202. }
  203. if (havedef)
  204. emit_class_decl(fout, inname);
  205. fclose(fin);
  206. fclose(fout);
  207. }
  208. int main(int argc, char **argv)
  209. {
  210. if (argc != 3) {
  211. fprintf(stderr, "The Mini Meta Object Compiler\n"
  212. "usage: minimoc <infile> <outfile>\n");
  213. return 1;
  214. }
  215. process_file(argv[1], argv[2]);
  216. return 0;
  217. }