summaryrefslogtreecommitdiff
path: root/fluid/io/Code_Writer.h
blob: 9d52e0600e9dd24d746dd6adbec26aeaa5f30062 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//
// Fluid C++ Code Writer header for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2025 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file.  If this
// file is missing or damaged, see the license at:
//
//     https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
//     https://www.fltk.org/bugs.php
//

#ifndef FLUID_IO_CODE_WRITER_H
#define FLUID_IO_CODE_WRITER_H

#include "proj/mergeback.h"

#include <FL/fl_attr.h>

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

class Node;

/** Simple string-to-pointer map entry */
struct Fd_Id_Entry {
  char *key;
  void *value;
};

/** Simple string-to-pointer map (unsorted array, linear search) */
struct Fd_Id_Map {
  Fd_Id_Entry *entries;
  int count;
  int capacity;

  Fd_Id_Map() : entries(0), count(0), capacity(0) {}
  ~Fd_Id_Map() { clear(); }
  void clear();
  const char *find_or_insert(const char *key, void *value, void **found_value);
};

/** Simple string set (unsorted array, linear search) */
struct Fd_String_Set {
  char **strings;
  int count;
  int capacity;

  Fd_String_Set() : strings(0), count(0), capacity(0) {}
  ~Fd_String_Set() { clear(); }
  void clear();
  bool contains(const char *s);
  void insert(const char *s);
};

/** Simple pointer set (unsorted array, linear search) */
struct Fd_Pointer_Set {
  void **pointers;
  int count;
  int capacity;

  Fd_Pointer_Set() : pointers(0), count(0), capacity(0) {}
  ~Fd_Pointer_Set() { clear(); }
  void clear();
  bool contains(void *p);
  void insert(void *p);
};

int is_id(char c);

namespace fld {

class Project;

namespace io {

class Code_Writer
{
private:
  /// Link Code_Writer class to the project.
  Project &proj_;

  /// file pointer for the C++ code file
  FILE *code_file = nullptr;
  /// file pointer for the C++ header file
  FILE *header_file = nullptr;

  /// tree of unique but human-readable identifiers
  Fd_Id_Map unique_id_list;
  /// searchable text tree for text that is only written once to the header file
  Fd_String_Set text_in_header;
  /// searchable text tree for text that is only written once to the code file
  Fd_String_Set text_in_code;
  /// searchable tree for pointers that are only written once to the code file
  Fd_Pointer_Set ptr_in_code;

  /// crc32 for blocks of text written to the code file
  unsigned long block_crc_ = 0;
  /// if set, we are at the start of a line and can ignore leading spaces in crc
  bool block_line_start_ = true;
  /// expanding buffer for vsnprintf
  char *block_buffer_ = nullptr;
  /// size of expanding buffer for vsnprintf
  int block_buffer_size_ = 0;

  void crc_add(const void *data, int n=-1);
  int crc_printf(const char *format, ...);
  int crc_vprintf(const char *format, va_list args);
  int crc_puts(const char *text);
  int crc_putc(int c);

public:
  /// current level of source code indentation
  int indentation = 0;
  /// set if we write abbreviated file for the source code previewer
  /// (disables binary data blocks, for example)
  bool write_codeview = false;
  /// 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 variable "o" is used:
  int varused_test = 0;
  /// set to 1 if varused_test found that a variable is actually used
  int varused = 0;

public:
  Code_Writer(Project &proj);
  ~Code_Writer();
  const char* unique_id(void* o, const char*, const char*, const char*);
  /// Increment source code indentation level.
  void indent_more() { indentation++; }
  /// Decrement source code indentation level.
  void indent_less() { indentation--; }
  const char *indent();
  const char *indent(int set);
  const char *indent_plus(int offset);
  int write_h_once(const char *, ...) __fl_attr((__format__ (__printf__, 2, 3)));
  int write_c_once(const char *, ...) __fl_attr((__format__ (__printf__, 2, 3)));
  bool c_contains(void* ptr);
  void write_cstring(const char *,int length);
  void write_cstring(const char *);
  void write_cdata(const char *,int length);
  void vwrite_c(const char* format, va_list args);
  void write_c(const char*, ...) __fl_attr((__format__ (__printf__, 2, 3)));
  void write_cc(const char *, int, const char*, const char*);
  void write_h(const char*, ...) __fl_attr((__format__ (__printf__, 2, 3)));
  void write_hc(const char *, int, const char*, const char*);
  void write_c_indented(const char *textlines, int inIndent, char inTrailwWith);
  Node* write_static(Node* p);
  Node* write_code(Node* p);
  int write_code(const char *cfile, const char *hfile, bool to_codeview=false);
  void write_public(int state); // writes pubic:/private: as needed

  void tag(proj::Mergeback::Tag prev_type, proj::Mergeback::Tag next_type, unsigned short uid);

  static unsigned long block_crc(const void *data, int n=-1, unsigned long in_crc=0, bool *inout_line_start=nullptr);
};

} // namespace io
} // namespace fld

#endif // FLUID_IO_CODE_WRITER_H