Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
716 | lvd | 1 | #include "std.h" |
2 | |||
3 | #include "resource.h" |
||
4 | |||
5 | #include "emul.h" |
||
6 | #include "vars.h" |
||
7 | #include "debug.h" |
||
8 | #include "dbgpaint.h" |
||
9 | #include "dbglabls.h" |
||
10 | #include "memory.h" |
||
11 | #include "config.h" |
||
12 | #include "util.h" |
||
13 | |||
14 | MON_LABELS mon_labels; |
||
15 | |||
16 | void MON_LABELS::start_watching_labels() |
||
17 | { |
||
18 | addpath(userfile, "?"); |
||
19 | hNewUserLabels = FindFirstChangeNotification(userfile, 0, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE); |
||
20 | addpath(userfile, "user.l"); |
||
21 | } |
||
22 | |||
23 | void MON_LABELS::stop_watching_labels() |
||
24 | { |
||
25 | if (!hNewUserLabels || hNewUserLabels == INVALID_HANDLE_VALUE) return; |
||
26 | CloseHandle(hNewUserLabels); |
||
27 | hNewUserLabels = INVALID_HANDLE_VALUE; |
||
28 | } |
||
29 | |||
30 | void MON_LABELS::notify_user_labels() |
||
31 | { |
||
32 | if (hNewUserLabels == INVALID_HANDLE_VALUE) return; |
||
33 | // load labels at first check |
||
34 | if (hNewUserLabels == NULL) { start_watching_labels(); import_file(); return; } |
||
35 | |||
36 | if (WaitForSingleObject(hNewUserLabels, 0) != WAIT_OBJECT_0) return; |
||
37 | |||
38 | import_file(); |
||
39 | FindNextChangeNotification(hNewUserLabels); |
||
40 | } |
||
41 | |||
42 | unsigned MON_LABELS::add_name(char *name) |
||
43 | { |
||
44 | unsigned len = strlen(name)+1, new_size = names_size + len; |
||
45 | if (new_size > align_by(names_size, 4096)) |
||
46 | names = (char*)realloc(names, align_by(new_size, 4096)); |
||
47 | unsigned result = names_size; |
||
48 | memcpy(names + result, name, len); |
||
49 | names_size = new_size; |
||
50 | return result; |
||
51 | } |
||
52 | |||
53 | void MON_LABELS::clear(unsigned char *start, unsigned size) |
||
54 | { |
||
55 | unsigned dst = 0; |
||
56 | for (unsigned src = 0; src < n_pairs; src++) |
||
57 | if ((unsigned)(pairs[src].address - start) > size) |
||
58 | pairs[dst++] = pairs[src]; |
||
59 | n_pairs = dst; |
||
60 | // pack `names' |
||
61 | char *pnames = names; names = 0; names_size = 0; |
||
62 | for (unsigned l = 0; l < n_pairs; l++) |
||
63 | pairs[l].name_offs = add_name(pnames + pairs[l].name_offs); |
||
64 | free(pnames); |
||
65 | } |
||
66 | |||
67 | int __cdecl labels_sort_func(const void *e1, const void *e2) |
||
68 | { |
||
69 | const MON_LABEL *a = (MON_LABEL*)e1, *b = (MON_LABEL*)e2; |
||
70 | return a->address - b->address; |
||
71 | } |
||
72 | |||
73 | void MON_LABELS::sort() |
||
74 | { |
||
75 | qsort(pairs, n_pairs, sizeof(MON_LABEL), labels_sort_func); |
||
76 | } |
||
77 | |||
78 | void MON_LABELS::add(unsigned char *address, char *name) |
||
79 | { |
||
80 | if (n_pairs >= align_by(n_pairs, 1024)) |
||
81 | pairs = (MON_LABEL*)realloc(pairs, sizeof(MON_LABEL) * align_by(n_pairs+1, 1024)); |
||
82 | pairs[n_pairs].address = address; |
||
83 | pairs[n_pairs].name_offs = add_name(name); |
||
84 | n_pairs++; |
||
85 | } |
||
86 | |||
87 | char *MON_LABELS::find(unsigned char *address) |
||
88 | { |
||
89 | unsigned l = 0, r = n_pairs; |
||
90 | for (;;) { |
||
91 | if (l >= r) return 0; |
||
92 | unsigned m = (l+r)/2; |
||
93 | if (pairs[m].address == address) return names + pairs[m].name_offs; |
||
94 | if (pairs[m].address < address) l = m+1; else r = m; |
||
95 | } |
||
96 | } |
||
97 | |||
98 | unsigned MON_LABELS::load(char *filename, unsigned char *base, unsigned size) |
||
99 | { |
||
100 | FILE *in = fopen(filename, "rt"); |
||
101 | if (!in) |
||
102 | { |
||
103 | errmsg("can't find label file %s", filename); |
||
104 | return 0; |
||
105 | } |
||
106 | |||
107 | clear(base, size); |
||
108 | unsigned l_counter = 0, loaded = 0; char *txt = 0; |
||
109 | int l; //Alone Coder 0.36.7 |
||
110 | while (!feof(in)) { |
||
111 | char line[64]; |
||
112 | if (!fgets(line, sizeof(line), in)) break; |
||
113 | l_counter++; |
||
114 | for (/*int*/ l = strlen(line); l && line[l-1] <= ' '; l--); line[l] = 0; |
||
115 | if (!l) continue; |
||
116 | unsigned val = 0, offset = 0; |
||
117 | if (l >= 6 && line[4] == ' ') |
||
118 | { // адрес без номера банка xxxx label |
||
119 | for (l = 0; l < 4; l++) |
||
120 | { |
||
121 | if (!ishex(line[l])) |
||
122 | goto ll_err; |
||
123 | val = (val * 0x10) + hex(line[l]); |
||
124 | } |
||
125 | txt = line+5; |
||
126 | } |
||
127 | else if (l >= 9 && line[2] == ':' && line[7] == ' ') |
||
128 | { // адрес сномером банка bb:xxxx label |
||
129 | for (l = 0; l < 2; l++) |
||
130 | { |
||
131 | if (!ishex(line[l])) |
||
132 | goto ll_err; |
||
133 | val = (val * 0x10) + hex(line[l]); |
||
134 | } |
||
135 | for (l = 3; l < 7; l++) |
||
136 | { |
||
137 | if (!ishex(line[l])) |
||
138 | goto ll_err; |
||
139 | offset = (offset * 0x10) + hex(line[l]); |
||
140 | } |
||
141 | val = val*PAGE + (offset & (PAGE-1)); |
||
142 | txt = line+8; |
||
143 | } |
||
144 | else |
||
145 | { |
||
146 | ll_err: |
||
147 | color(CONSCLR_ERROR); |
||
148 | printf("error in %s, line %d\n", filename, l_counter); |
||
149 | continue; |
||
150 | } |
||
151 | |||
152 | if (val < size) |
||
153 | { |
||
154 | add(base+val, txt); |
||
155 | loaded++; |
||
156 | } |
||
157 | } |
||
158 | fclose(in); |
||
159 | sort(); |
||
160 | return loaded; |
||
161 | } |
||
162 | |||
163 | unsigned MON_LABELS::alasm_chain_len(unsigned char *page, unsigned offset, unsigned &end) |
||
164 | { |
||
165 | unsigned count = 0; |
||
166 | for (;;) { |
||
167 | if (offset >= 0x3FFC) return 0; |
||
168 | unsigned s1 = page[offset], sz = s1 & 0x3F; |
||
169 | if (!s1 || offset == 0x3E00) { end = offset+1; return count; } |
||
170 | if (sz < 6) return 0; |
||
171 | unsigned char sym = page[offset+sz-1]; |
||
172 | if (sym >= '0' && sym <= '9') return 0; |
||
173 | for (unsigned ptr = 5; ptr < sz; ptr++) |
||
174 | if (!alasm_valid_char[page[offset+ptr]]) return 0; |
||
175 | if (!(s1 & 0xC0)) count++; |
||
176 | offset += sz; |
||
177 | } |
||
178 | } |
||
179 | |||
180 | void MON_LABELS::find_alasm() |
||
181 | { |
||
182 | static const char label_chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$_"; |
||
183 | memset(alasm_valid_char, 0, sizeof alasm_valid_char); |
||
184 | for (const char *lbl = label_chars; *lbl; lbl++) alasm_valid_char[*lbl] = 1; |
||
185 | |||
186 | alasm_found_tables = 0; |
||
187 | for (unsigned page = 0; page < conf.ramsize*1024; page += PAGE) { |
||
188 | for (unsigned offset = 0; offset < PAGE; offset++) { |
||
189 | unsigned end, count = alasm_chain_len(RAM_BASE_M + page, offset, end); |
||
190 | if (count < 2) continue; |
||
191 | alasm_count[alasm_found_tables] = count; |
||
192 | alasm_offset[alasm_found_tables] = page + offset; |
||
193 | offset = end; alasm_found_tables++; |
||
194 | if (alasm_found_tables == MAX_ALASM_LTABLES) return; |
||
195 | } |
||
196 | } |
||
197 | } |
||
198 | |||
199 | |||
200 | void MON_LABELS::import_alasm(unsigned offset, char *caption) |
||
201 | { |
||
202 | clear_ram(); |
||
203 | unsigned char *base = RAM_BASE_M + offset; |
||
204 | for (;;) { // #FE00/FF00/FFFC - end of labels? |
||
205 | unsigned char sz = *base; if (!sz) break; |
||
206 | if (!(sz & 0xC0)) { |
||
207 | char lbl[64]; unsigned ptr = 0; |
||
208 | for (unsigned k = sz; k > 5;) k--, lbl[ptr++] = base[k]; lbl[ptr] = 0; |
||
209 | unsigned val = *(unsigned short*)(base+1); |
||
210 | unsigned char *bs; |
||
211 | switch (val & 0xC000) { |
||
212 | case 0x4000: bs = RAM_BASE_M+5*PAGE; break; |
||
213 | case 0x8000: bs = RAM_BASE_M+2*PAGE; break; |
||
214 | case 0xC000: bs = RAM_BASE_M+0*PAGE; break; |
||
215 | default: bs = 0; |
||
216 | } |
||
217 | if (bs) add(bs+(val & 0x3FFF), lbl); |
||
218 | } |
||
219 | base += (sz & 0x3F); |
||
220 | } |
||
221 | sort(); |
||
222 | } |
||
223 | |||
224 | void MON_LABELS::find_xas() |
||
225 | { |
||
226 | char look_page_6 = 0; |
||
227 | const char *err = "XAS labels not found in bank #06"; |
||
228 | if (conf.mem_model == MM_PENTAGON && conf.ramsize > 128) |
||
229 | err = "XAS labels not found in banks #06,#46", look_page_6 = 1; |
||
230 | xaspage = 0; |
||
231 | if (look_page_6 && RAM_BASE_M[PAGE*14+0x3FFF] == 5 && RAM_BASE_M[PAGE*14+0x1FFF] == 5) xaspage = 0x46; |
||
232 | if (!xaspage && RAM_BASE_M[PAGE*6+0x3FFF] == 5 && RAM_BASE_M[PAGE*6+0x1FFF] == 5) xaspage = 0x06; |
||
233 | if (!xaspage) strcpy(xas_errstr, err); |
||
234 | else sprintf(xas_errstr, "XAS labels from bank #%02X", xaspage); |
||
235 | } |
||
236 | |||
237 | void MON_LABELS::import_xas() |
||
238 | { |
||
239 | if (!xaspage) return; |
||
240 | unsigned base = (xaspage == 0x46)? 0x0E*PAGE : (unsigned)xaspage*PAGE; |
||
241 | |||
242 | clear_ram(); unsigned count = 0; |
||
243 | int i; //Alone Coder 0.36.7 |
||
244 | for (int k = 0; k < 2; k++) { |
||
245 | unsigned char *ptr = RAM_BASE_M + base + (k? 0x3FFD : 0x1FFD); |
||
246 | for (;;) { |
||
247 | if (ptr[2] < 5 || (ptr[2] & 0x80)) break; |
||
248 | char lbl[16]; for (/*int*/ i = 0; i < 7; i++) lbl[i] = ptr[i-7]; |
||
249 | for (i = 7; i && lbl[i-1]==' '; i--); lbl[i] = 0; |
||
250 | unsigned val = *(unsigned short*)ptr; |
||
251 | unsigned char *bs; |
||
252 | switch (val & 0xC000) { |
||
253 | case 0x4000: bs = RAM_BASE_M+5*PAGE; break; |
||
254 | case 0x8000: bs = RAM_BASE_M+2*PAGE; break; |
||
255 | case 0xC000: bs = RAM_BASE_M+0*PAGE; break; |
||
256 | default: bs = 0; |
||
257 | } |
||
258 | if (bs) add(bs+(val & 0x3FFF), lbl), count++; |
||
259 | ptr -= 9; if (ptr < RAM_BASE_M+base+9) break; |
||
260 | } |
||
261 | } |
||
262 | sort(); |
||
263 | char ln[64]; sprintf(ln, "imported %d labels", count); |
||
264 | MessageBox(GetForegroundWindow(), ln, xas_errstr, MB_OK | MB_ICONINFORMATION); |
||
265 | } |
||
266 | |||
267 | void MON_LABELS::import_menu() |
||
268 | { |
||
269 | find_xas(); |
||
270 | find_alasm(); |
||
271 | |||
272 | MENUITEM items[MAX_ALASM_LTABLES+4] = { 0 }; |
||
273 | unsigned menuptr = 0; |
||
274 | |||
275 | items[menuptr].text = xas_errstr; |
||
276 | items[menuptr].flags = xaspage? (MENUITEM::FLAGS)0 : MENUITEM::DISABLED; |
||
277 | menuptr++; |
||
278 | |||
279 | char alasm_text[MAX_ALASM_LTABLES][64]; |
||
280 | if (!alasm_found_tables) { |
||
281 | sprintf(alasm_text[0], "No ALASM labels in whole %dK memory", conf.ramsize); |
||
282 | items[menuptr].text = alasm_text[0]; |
||
283 | items[menuptr].flags = MENUITEM::DISABLED; |
||
284 | menuptr++; |
||
285 | } else { |
||
286 | for (unsigned i = 0; i < alasm_found_tables; i++) { |
||
287 | sprintf(alasm_text[i], "%d ALASM labels in page %d, offset #%04X", alasm_count[i], alasm_offset[i]/PAGE, (alasm_offset[i] & 0x3FFF) | 0xC000); |
||
288 | items[menuptr].text = alasm_text[i]; |
||
289 | items[menuptr].flags = (MENUITEM::FLAGS)0; |
||
290 | menuptr++; |
||
291 | } |
||
292 | } |
||
293 | |||
294 | items[menuptr].text = nil; |
||
295 | items[menuptr].flags = MENUITEM::DISABLED; |
||
296 | menuptr++; |
||
297 | |||
298 | items[menuptr].text = "CANCEL"; |
||
299 | items[menuptr].flags = MENUITEM::CENTER; |
||
300 | menuptr++; |
||
301 | |||
302 | MENUDEF menu = { items, menuptr, "import labels" }; |
||
303 | if (!handle_menu(&menu)) return; |
||
304 | if (menu.pos == 0) import_xas(); |
||
305 | menu.pos--; |
||
306 | if ((unsigned)menu.pos < alasm_found_tables) import_alasm(alasm_offset[menu.pos], alasm_text[menu.pos]); |
||
307 | } |
||
308 | |||
309 | void MON_LABELS::import_file() |
||
310 | { |
||
311 | FILE *ff = fopen(userfile, "rb"); if (!ff) return; fclose(ff); |
||
312 | unsigned count = load(userfile, RAM_BASE_M, conf.ramsize * 1024); |
||
313 | if (!count) return; |
||
314 | char tmp[0x200]; |
||
315 | sprintf(tmp, "loaded %d labels from\r\n%s", count, userfile); |
||
316 | puts(tmp); |
||
317 | //MessageBox(GetForegroundWindow(), tmp, "unreal discovered changes in user labels", MB_OK | MB_ICONINFORMATION);//removed by Alone Coder |
||
318 | } |
||
319 | |||
320 | void load_labels(char *filename, unsigned char *base, unsigned size) |
||
321 | { |
||
322 | mon_labels.load(filename, base, size); |
||
323 | } |
||
324 | |||
325 | char curlabel[64]; unsigned lcount; |
||
326 | |||
327 | void ShowLabels() |
||
328 | { |
||
329 | SetDlgItemText(dlg, IDC_LABEL_TEXT, curlabel); |
||
330 | HWND list = GetDlgItem(dlg, IDC_LABELS); |
||
331 | |||
332 | while (SendMessage(list, LB_GETCOUNT, 0, 0)) |
||
333 | SendMessage(list, LB_DELETESTRING, 0, 0); |
||
334 | |||
335 | unsigned ln = strlen(curlabel); lcount = 0; |
||
336 | char *s; //Alone Coder 0.36.7 |
||
337 | for (unsigned p = 0; p < 4; p++) |
||
338 | { |
||
339 | unsigned char *base = am_r(p*PAGE); |
||
340 | for (unsigned i = 0; i < mon_labels.n_pairs; i++) |
||
341 | { |
||
342 | unsigned char *label = mon_labels.pairs[i].address; |
||
343 | if (label < base || label >= base + PAGE) |
||
344 | continue; |
||
345 | char *name = mon_labels.pairs[i].name_offs + mon_labels.names; |
||
346 | if (ln) |
||
347 | { |
||
348 | // unfortunately, strstr() is case sensitive, use loop |
||
349 | for (/*char * */s = name; *s; s++) |
||
350 | if (!strnicmp(s, curlabel, ln)) break; |
||
351 | if (!*s) continue; |
||
352 | } |
||
353 | char zz[0x400]; |
||
354 | sprintf(zz, "%04X %s", (label - base) + (p * PAGE), name); |
||
355 | SendMessage(list, LB_ADDSTRING, 0, (LPARAM)zz); lcount++; |
||
356 | } |
||
357 | } |
||
358 | SendMessage(list, LB_SETCURSEL, 0, 0); |
||
359 | SetFocus(list); |
||
360 | } |
||
361 | |||
362 | INT_PTR CALLBACK LabelsDlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp) |
||
363 | { |
||
364 | ::dlg = dlg; |
||
365 | if (msg == WM_INITDIALOG) |
||
366 | { |
||
367 | *curlabel = 0; |
||
368 | ShowLabels(); |
||
369 | return 1; |
||
370 | } |
||
371 | |||
372 | if (msg == WM_SYSCOMMAND && (wp & 0xFFF0) == SC_CLOSE) EndDialog(dlg, 0); |
||
373 | |||
374 | if (msg == WM_VKEYTOITEM) |
||
375 | { |
||
376 | unsigned sz = strlen(curlabel); |
||
377 | wp = LOWORD(wp); |
||
378 | if (wp == VK_BACK) { |
||
379 | if (sz) curlabel[sz-1] = 0, ShowLabels(); |
||
380 | else { deadkey: Beep(300, 100); } |
||
381 | } else if ((unsigned)(wp-'0') < 10 || (unsigned)(wp-'A') < 26 || wp == '_') { |
||
382 | if (sz == sizeof(curlabel)-1) goto deadkey; |
||
383 | curlabel[sz] = wp, curlabel[sz+1] = 0, ShowLabels(); |
||
384 | if (!lcount) { curlabel[sz] = 0, ShowLabels(); goto deadkey; } |
||
385 | } else return -1; |
||
386 | return -2; |
||
387 | } |
||
388 | |||
389 | if (msg != WM_COMMAND) return 0; |
||
390 | |||
391 | unsigned id = LOWORD(wp), code = HIWORD(wp); |
||
392 | if (id == IDCANCEL || id == IDOK) EndDialog(dlg, 0); |
||
393 | |||
394 | if (id == IDOK || (id == IDC_LABELS && code == LBN_DBLCLK)) |
||
395 | { |
||
396 | HWND list = GetDlgItem(dlg, IDC_LABELS); |
||
397 | unsigned n = SendMessage(list, LB_GETCURSEL, 0, 0); |
||
398 | if (n >= lcount) return 0; |
||
399 | char zz[0x400]; SendMessage(list, LB_GETTEXT, n, (LPARAM)zz); |
||
400 | unsigned address; sscanf(zz, "%X", &address); |
||
401 | |||
402 | void push_pos(); push_pos(); |
||
403 | CpuMgr.Cpu().trace_curs = CpuMgr.Cpu().trace_top = address; |
||
404 | activedbg = WNDTRACE; |
||
405 | |||
406 | EndDialog(dlg, 1); |
||
407 | return 1; |
||
408 | } |
||
409 | |||
410 | return 0; |
||
411 | } |
||
412 | |||
413 | void mon_show_labels() |
||
414 | { |
||
415 | DialogBox(hIn, MAKEINTRESOURCE(IDD_LABELS), wnd, LabelsDlg); |
||
416 | } |