Mercurial > mercurial > hgweb_golang.cgi
comparison src/kaigo/superFC/fcgo.go @ 65:0369656be06c default tip
many changes.
author | pyon@macmini |
---|---|
date | Fri, 20 May 2022 06:30:34 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
64:ad5c30ee5cf1 | 65:0369656be06c |
---|---|
1 /* | |
2 fcgo.go: Fucho de Go | |
3 | |
4 Last Change: 2021-06-14 月 16:14:04. | |
5 */ | |
6 package main | |
7 | |
8 /* | |
9 #cgo LDFLAGS: -L. -lxdwapi -static | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <string.h> | |
13 #include <io.h> | |
14 #include <windows.h> | |
15 #include <xdw_api.h> | |
16 #include <xdwapian.h> | |
17 | |
18 #define MAXLINE 12000 | |
19 #define BLOCKSZ 128 | |
20 | |
21 void xdw2txt(const char* xdwfile, const char* txtfile) { | |
22 char in_path[_MAX_PATH]; | |
23 _fullpath(in_path, xdwfile, _MAX_PATH); | |
24 | |
25 XDW_DOCUMENT_HANDLE h = NULL; | |
26 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_READONLY, XDW_AUTH_NODIALOGUE}; | |
27 if (XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode)) { | |
28 printf("XDW Error: cannot open %s\n", xdwfile); | |
29 return; | |
30 } | |
31 | |
32 int api_result = XDW_GetFullText(h, txtfile, NULL); | |
33 if (api_result < 0) { | |
34 printf("Error: cannot write text\n"); | |
35 return; | |
36 } | |
37 XDW_CloseDocumentHandle(h, NULL); | |
38 } | |
39 | |
40 void xdwsplit1(const char* xdwfile) { | |
41 char in_path[_MAX_PATH]; | |
42 _fullpath(in_path, xdwfile, _MAX_PATH); | |
43 | |
44 XDW_DOCUMENT_HANDLE h = NULL; | |
45 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_READONLY, XDW_AUTH_NODIALOGUE}; | |
46 if (XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode)) { | |
47 printf("Error: cannot open %s\n", xdwfile); | |
48 return; | |
49 } | |
50 | |
51 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0, 0, 0}; | |
52 XDW_GetDocumentInformation(h, &info); | |
53 int nPage = info.nPages; | |
54 | |
55 char buf[_MAX_PATH]; | |
56 for (int i = 1; i <= nPage; i++) { | |
57 sprintf(buf, "fctmp_%05d.xdw", i); | |
58 _fullpath(in_path, buf, _MAX_PATH); | |
59 | |
60 int api_result = XDW_GetPage(h, i, in_path, NULL); | |
61 if (api_result < 0) { | |
62 printf("XDW Error: cannot get page\n"); | |
63 return; | |
64 } | |
65 } | |
66 XDW_CloseDocumentHandle(h, NULL); | |
67 } | |
68 | |
69 void xdwmerge(const char* list, const char* output) { | |
70 | |
71 FILE *fp; | |
72 if ((fp = fopen(list, "r")) == NULL) { | |
73 fprintf(stderr, "can't open file [%s]\n", list); | |
74 exit(1); | |
75 } | |
76 | |
77 char *all_path = (char*)malloc(MAXLINE * sizeof(char) * _MAX_PATH); | |
78 if (all_path == NULL) { | |
79 fprintf(stderr, "can't allocate memory\n"); | |
80 exit(1); | |
81 } | |
82 | |
83 int n = 0; | |
84 char *q; | |
85 char buf[_MAX_PATH]; | |
86 | |
87 while (fgets(buf, sizeof buf, fp)) { | |
88 if ((q = strchr(buf, '\n')) != NULL) { | |
89 *q = '\0'; | |
90 } | |
91 _fullpath(buf, buf, _MAX_PATH); | |
92 strncpy(&all_path[n * _MAX_PATH], buf, _MAX_PATH); | |
93 n++; | |
94 } | |
95 fclose(fp); | |
96 | |
97 char *blk_path = (char*)malloc(BLOCKSZ * sizeof(char) * _MAX_PATH); | |
98 const char **blk_path_addr = (const char**)malloc((n / BLOCKSZ + 1) * sizeof(char*) * _MAX_PATH); | |
99 if (blk_path == NULL || blk_path_addr == NULL) { | |
100 fprintf(stderr, "can't allocate memory\n"); | |
101 exit(1); | |
102 } | |
103 | |
104 // process by block | |
105 int api_result; | |
106 int bn = 0; | |
107 for (int p = 0, m = 0; p < n; p++) { | |
108 m = p % BLOCKSZ; | |
109 if (m == 0 && p > 0) { | |
110 sprintf(buf, "fctmp_b%04d.xdw", ++bn); | |
111 _fullpath(buf, buf, _MAX_PATH); | |
112 api_result = XDW_MergeXdwFiles(blk_path_addr, BLOCKSZ, buf, NULL); | |
113 if (api_result < 0) { | |
114 fprintf(stderr, "can't merge [1] (p = %d, m = %d)\n", p, m); | |
115 exit(1); | |
116 } | |
117 } | |
118 strncpy(&blk_path[m * _MAX_PATH], &all_path[p * _MAX_PATH], _MAX_PATH); | |
119 blk_path_addr[m] = &blk_path[m * _MAX_PATH]; | |
120 } | |
121 | |
122 sprintf(buf, "fctmp_b%04d.xdw", ++bn); | |
123 _fullpath(buf, buf, _MAX_PATH); | |
124 int mod = n % BLOCKSZ; | |
125 if (mod == 0) mod = BLOCKSZ; | |
126 api_result = XDW_MergeXdwFiles(blk_path_addr, mod, buf, NULL); | |
127 if (api_result < 0) { | |
128 fprintf(stderr, "can't merge [2]\n"); | |
129 exit(1); | |
130 } | |
131 | |
132 // merge blocks | |
133 for (int b = 0; b < bn; b++) { | |
134 sprintf(buf, "fctmp_b%04d.xdw", b + 1); | |
135 _fullpath(buf, buf, _MAX_PATH); | |
136 strncpy(&blk_path[b * _MAX_PATH], buf, _MAX_PATH); | |
137 blk_path_addr[b] = &blk_path[b * _MAX_PATH]; | |
138 } | |
139 _fullpath(buf, output, _MAX_PATH ); | |
140 api_result = XDW_MergeXdwFiles(blk_path_addr, bn, buf, NULL); | |
141 if (api_result < 0) { | |
142 fprintf(stderr, "can't merge [3]\n"); | |
143 exit(1); | |
144 } | |
145 | |
146 free(all_path); | |
147 free(blk_path); | |
148 free(blk_path_addr); | |
149 } | |
150 | |
151 int xdwaddannotation(XDW_DOCUMENT_HANDLE h, int page, int x, int y, char* string, int* sz, int tr) | |
152 { | |
153 XDW_ANNOTATION_HANDLE annoation; | |
154 int api_result = XDW_AddAnnotation(h, XDW_AID_TEXT, page, x, y, NULL, &annoation, NULL); | |
155 if (api_result < 0) { | |
156 fprintf(stderr, "can't make annotation\n"); | |
157 return -1; | |
158 } | |
159 | |
160 api_result = XDW_SetAnnotationAttribute(h, annoation, XDW_ATN_Text, XDW_ATYPE_STRING, string, 0, NULL); | |
161 api_result = XDW_SetAnnotationAttribute(h, annoation, XDW_ATN_FontSize, XDW_ATYPE_INT, (char*)(sz), 0, NULL); | |
162 if (tr) { | |
163 int color = XDW_COLOR_NONE; | |
164 api_result = XDW_SetAnnotationAttribute(h, annoation, XDW_ATN_BackColor, XDW_ATYPE_INT, (char*)(&color), 0, NULL); | |
165 } | |
166 return 0; | |
167 } | |
168 | |
169 void xdwaddpage(const char* file, int sp) { | |
170 XDW_DOCUMENT_HANDLE h = NULL; | |
171 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_UPDATE, XDW_AUTH_NODIALOGUE}; | |
172 int api_result = XDW_OpenDocumentHandle(file, &h, (XDW_OPEN_MODE*)&mode); | |
173 if (api_result < 0) { | |
174 fprintf(stderr, "can't open file\n"); | |
175 exit(1); | |
176 } | |
177 | |
178 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0}; | |
179 XDW_GetDocumentInformation(h, &info); | |
180 int last_page = info.nPages; | |
181 | |
182 int sz = 80; | |
183 int tr = 1; | |
184 char pagenum[12]; | |
185 | |
186 for (int p = 0; p < last_page; p++) { | |
187 sprintf(pagenum, "%05d-%05d", p + sp, last_page); | |
188 api_result = xdwaddannotation(h, p + 1, 1769, 5658, pagenum, &sz, tr); | |
189 api_result = xdwaddannotation(h, p + 1, 18297, 28326, pagenum, &sz, tr); | |
190 if (api_result < 0) break; | |
191 } | |
192 | |
193 if (api_result >= 0) api_result = XDW_SaveDocument(h, NULL); | |
194 | |
195 XDW_CloseDocumentHandle(h, NULL); | |
196 } | |
197 | |
198 | |
199 */ | |
200 import "C" | |
201 | |
202 import ( | |
203 "encoding/csv" | |
204 "flag" | |
205 "fmt" | |
206 "io" | |
207 "log" | |
208 "os" | |
209 "regexp" | |
210 "strings" | |
211 "time" | |
212 | |
213 "golang.org/x/text/encoding/japanese" | |
214 "golang.org/x/text/transform" | |
215 ) | |
216 | |
217 type Data struct { | |
218 Hno string | |
219 Page string | |
220 } | |
221 | |
222 func (d *Data) ToCsv() string { | |
223 s := []string{d.Hno, d.Page} | |
224 return strings.Join(s, ",") | |
225 } | |
226 | |
227 var ( | |
228 ver = "0.1" | |
229 | |
230 clean bool | |
231 skip bool | |
232 debug bool | |
233 xdwfile string | |
234 | |
235 txtfile = "fctmp_txt.txt" | |
236 infofile = "fctmp_info.csv" | |
237 orderfile = "sort.list" // input | |
238 pagefile = "fctmp_page.txt" | |
239 output = "output.xdw" | |
240 ) | |
241 | |
242 func init() { | |
243 /* INITIALIZE FLAGS */ | |
244 flag.BoolVar(&clean, "c", false, "clean temporary files & exit") | |
245 flag.BoolVar(&skip, "e", false, "use existed files") | |
246 flag.BoolVar(&debug, "d", false, "debug mode") | |
247 flag.StringVar(&xdwfile, "i", "fc.xdw", "target xdw file") | |
248 } | |
249 | |
250 func main() { | |
251 flag.Parse() | |
252 | |
253 /* PRINT HEADER */ | |
254 fmt.Println("===================================================") | |
255 fmt.Println(" 普徴のみならず納通なら被保番でソートできるかも... ") | |
256 fmt.Printf(" - fcgo [ver %s] -\n", ver) | |
257 fmt.Println("===================================================\n") | |
258 print_time("now") | |
259 fmt.Println("[0] start ...") | |
260 | |
261 /* CLEAN TEMPORARY DIRECTORY */ | |
262 os.Remove(output) | |
263 if !skip { | |
264 clean_full() | |
265 } | |
266 if clean { | |
267 os.Exit(0) | |
268 } | |
269 print_time("check done") | |
270 | |
271 fmt.Println("[1] extract ...") | |
272 if !skip { | |
273 C.xdw2txt(C.CString(xdwfile), C.CString(txtfile)) | |
274 } | |
275 print_time("extract done.") | |
276 | |
277 c := make(chan int) | |
278 fmt.Println("[2] split ... (run background)") | |
279 go func() { | |
280 if !skip { | |
281 C.xdwsplit1(C.CString(xdwfile)) | |
282 } | |
283 print_time("split done.") | |
284 c <- 1 | |
285 }() | |
286 | |
287 fmt.Println("[3] analize ...") | |
288 data_hash, err := analize(txtfile, infofile) | |
289 if err != nil { | |
290 log.Fatal(err) | |
291 } | |
292 print_time("analize done.") | |
293 debug_print(debug, fmt.Sprintf("len = %d", len(data_hash))) | |
294 | |
295 fmt.Println("[4] read order ...") | |
296 h_order, n, err := read_order(orderfile) | |
297 if err != nil { | |
298 log.Fatal(err) | |
299 } | |
300 print_time("read order done.") | |
301 debug_print(debug, fmt.Sprintf("len = %d / %d", len(h_order), n)) | |
302 | |
303 fmt.Println("[5] make_list ...") | |
304 n, err = make_list(h_order, data_hash, pagefile) | |
305 if err != nil { | |
306 log.Fatal(err) | |
307 } | |
308 print_time("make list done.") | |
309 debug_print(debug, fmt.Sprintf("order = %d", n)) | |
310 | |
311 <-c | |
312 | |
313 fmt.Println("[6] merge ...") | |
314 clean_mini() | |
315 C.xdwmerge(C.CString(pagefile), C.CString(output)) | |
316 print_time("merge done.") | |
317 clean_mini() | |
318 | |
319 fmt.Println("[7] page ...") | |
320 C.xdwaddpage(C.CString(output), C.int(1)) | |
321 print_time("page done.") | |
322 | |
323 if !debug { | |
324 fmt.Println("[8] clean ...") | |
325 clean_full() | |
326 print_time("clean done.") | |
327 } | |
328 } | |
329 | |
330 func analize(txtfile, infofile string) (map[string]Data, error) { | |
331 hash := make(map[string]Data) | |
332 | |
333 c, err := os.ReadFile(txtfile) | |
334 if err != nil { | |
335 return hash, err | |
336 } | |
337 r := strings.NewReader(string(c)) | |
338 tr := transform.NewReader(r, japanese.ShiftJIS.NewDecoder()) | |
339 b, err := io.ReadAll(tr) | |
340 if err != nil { | |
341 return hash, err | |
342 } | |
343 | |
344 regHno := regexp.MustCompile(`0[1238]0[0-9]{7}`) | |
345 | |
346 var csv string | |
347 | |
348 buf := strings.Split(string(b), "期別保険料額") | |
349 for p, v := range buf[:len(buf)-1] { | |
350 s := zen2han(v) | |
351 hno := regHno.FindString(s) | |
352 page := fmt.Sprintf("%05d", p + 1) | |
353 | |
354 data := Data { | |
355 Hno: hno, | |
356 Page: page, | |
357 } | |
358 hash[hno] = data | |
359 | |
360 csv += data.ToCsv() + "\n" | |
361 } | |
362 | |
363 if err := os.WriteFile(infofile, []byte(csv), 0644); err != nil { | |
364 return hash, err | |
365 } | |
366 return hash, nil; | |
367 } | |
368 | |
369 func zen2han(s string) (string) { | |
370 s = strings.ReplaceAll(s, "0", "0") | |
371 s = strings.ReplaceAll(s, "1", "1") | |
372 s = strings.ReplaceAll(s, "2", "2") | |
373 s = strings.ReplaceAll(s, "3", "3") | |
374 s = strings.ReplaceAll(s, "4", "4") | |
375 s = strings.ReplaceAll(s, "5", "5") | |
376 s = strings.ReplaceAll(s, "6", "6") | |
377 s = strings.ReplaceAll(s, "7", "7") | |
378 s = strings.ReplaceAll(s, "8", "8") | |
379 return strings.ReplaceAll(s, "9", "9") | |
380 } | |
381 | |
382 func read_order(csvfile string) ([]string, int, error) { | |
383 var order []string | |
384 | |
385 c, err := os.ReadFile(csvfile) | |
386 if err != nil { | |
387 return order, -1, err | |
388 } | |
389 r := strings.NewReader(string(c)) | |
390 tr := transform.NewReader(r, japanese.ShiftJIS.NewDecoder()) | |
391 b, err := io.ReadAll(tr) | |
392 if err != nil { | |
393 return order, -1, err | |
394 } | |
395 | |
396 n := 0 | |
397 cr := csv.NewReader(strings.NewReader(string(b))) | |
398 for { | |
399 record, err := cr.Read() | |
400 if err == io.EOF { | |
401 break | |
402 } | |
403 if err != nil { | |
404 return order, n, err | |
405 } | |
406 | |
407 s := zen2han(record[0]) | |
408 if strings.HasPrefix(s, "0") { | |
409 order = append(order, s) | |
410 } | |
411 n++ | |
412 } | |
413 return order, n, nil | |
414 } | |
415 | |
416 func make_list(h_order []string, hash map[string]Data, pagefile string) (int, error) { | |
417 var n int | |
418 var list []string | |
419 done := make(map[string]bool) | |
420 | |
421 for _, h := range h_order { | |
422 if _, ok := done[h]; !ok { | |
423 if data, ok := hash[h]; ok { | |
424 list = append(list, data.Page) | |
425 done[h] = true | |
426 n++ | |
427 } | |
428 } | |
429 } | |
430 | |
431 if err := write_pagefile(pagefile, list); err != nil { | |
432 return n, err | |
433 } | |
434 return n, nil | |
435 } | |
436 | |
437 func write_pagefile(file string, list []string) error { | |
438 f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE, 0755) | |
439 if err != nil { | |
440 return err | |
441 } | |
442 for _, p := range list { | |
443 fmt.Fprintf(f, "fctmp_%s.xdw\n", p) | |
444 } | |
445 if err := f.Close(); err != nil { | |
446 return err | |
447 } | |
448 return nil | |
449 } | |
450 | |
451 func print_time(msg string) { | |
452 now := time.Now() | |
453 fmt.Printf("\t%v # %s\n", now, msg) | |
454 } | |
455 | |
456 func debug_print(debug bool, msg string) { | |
457 if debug { | |
458 fmt.Printf("\t%s\n", msg) | |
459 } | |
460 } | |
461 | |
462 func clean_full() error { | |
463 return clean_file("fctmp_") | |
464 } | |
465 | |
466 func clean_mini() error { | |
467 return clean_file("fctmp_b") | |
468 } | |
469 | |
470 func clean_file(prefix string) error { | |
471 files, err := os.ReadDir(".") | |
472 if err != nil { | |
473 return err | |
474 } | |
475 | |
476 for _, file := range files { | |
477 if strings.HasPrefix(file.Name(), prefix) { | |
478 os.Remove(file.Name()) | |
479 continue | |
480 } | |
481 } | |
482 return err | |
483 } | |
484 |