comparison src/kaigo/Nk/nk.go @ 41:34a474fb83c3

add perori/porori/nk.
author pyon@macmini
date Wed, 04 Mar 2020 23:46:59 +0900
parents
children c58172a59534
comparison
equal deleted inserted replaced
40:c6df3bae683e 41:34a474fb83c3
1 /*
2 nk.go: Nintei Kekka
3
4 Last Change: 2020-01-24 金 09:18:04.
5 */
6
7 package main
8
9 /*
10 #cgo LDFLAGS: -L. -lxdwapi -static
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <io.h>
15 #include <windows.h>
16 #include <xdw_api.h>
17 #include <xdwapian.h>
18
19 #define MAXCOL 1024
20 #define MAXLINE 9999
21 #define BLOCKSZ 128
22
23 int xdwpages(const char* file) {
24 char in_path[_MAX_PATH];
25 _fullpath(in_path, file, _MAX_PATH);
26
27 XDW_DOCUMENT_HANDLE h = NULL; // 文書ハンドルを開く
28 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_READONLY, XDW_AUTH_NODIALOGUE};
29 if (XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode)) {
30 printf("Error: cannot open %s\n", file);
31 return -1;
32 }
33
34 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0, 0, 0}; // 総ページ数を得る
35 XDW_GetDocumentInformation(h, &info);
36 int nPage = info.nPages;
37
38 XDW_CloseDocumentHandle(h, NULL); // 文書ハンドルを閉じる
39
40 return nPage;
41 }
42
43 char* xdw2txt(const char* file) {
44 char in_path[_MAX_PATH];
45 _fullpath(in_path, file, _MAX_PATH);
46
47 XDW_DOCUMENT_HANDLE h = NULL; // 文書ハンドルを開く
48 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_READONLY, XDW_AUTH_NODIALOGUE};
49 if (XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode)) {
50 printf("Error: cannot open %s\n", file);
51 return NULL;
52 }
53
54 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0, 0, 0}; // 総ページ数を得る
55 XDW_GetDocumentInformation(h, &info);
56 int nPage = info.nPages;
57
58 // メイン処理
59 char *lpszvalue, *all_lpszvalue;
60 long datasize[9999];
61 for (int i=1; i<=nPage; i++) {
62 datasize[i] = XDW_GetPageTextToMemory(h, i, NULL, 0, NULL);
63 datasize[0] += datasize[i];
64 }
65 datasize[0] += nPage - 1; // for "\n"
66 all_lpszvalue = (char*)malloc(sizeof(char)*datasize[0]);
67 all_lpszvalue[0] = '\0';
68 for (int i=1; i<=nPage; i++) {
69 if (i<nPage) datasize[i]++; // for "\n"
70 lpszvalue = (char*)malloc(sizeof(char)*(datasize[i]));
71 XDW_GetPageTextToMemory(h, i, lpszvalue, datasize[i], NULL);
72 strcat(all_lpszvalue, lpszvalue);
73 if (i<nPage) strcat(all_lpszvalue, "\n");
74 free(lpszvalue);
75 }
76
77 XDW_CloseDocumentHandle(h, NULL); // 文書ハンドルを閉じる
78 return all_lpszvalue;
79 }
80
81 int xdwpush(const char* file1, const char* file2) {
82 char in_path[_MAX_PATH], add_path[_MAX_PATH];
83 _fullpath(in_path, file1, _MAX_PATH);
84 _fullpath(add_path, file2, _MAX_PATH);
85
86 XDW_DOCUMENT_HANDLE h = NULL;
87 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_UPDATE, XDW_AUTH_NODIALOGUE};
88
89 int api_result = XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode);
90 if (api_result < 0) return api_result;
91
92 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0, 0, 0};
93 XDW_GetDocumentInformation(h, &info);
94 int last_page = info.nPages;
95
96 api_result = XDW_InsertDocument(h, last_page+1, add_path, NULL);
97 if (api_result < 0) api_result;
98
99 XDW_SaveDocument(h, NULL);
100 XDW_CloseDocumentHandle(h, NULL);
101
102 return (api_result >= 0);
103 }
104
105 int xdwaddatn(const char* file, char* atnlist) {
106 char in_path[_MAX_PATH];
107 _fullpath(in_path, file, _MAX_PATH);
108
109 XDW_DOCUMENT_HANDLE h = NULL;
110 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_UPDATE, XDW_AUTH_NODIALOGUE};
111
112 int api_result = XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode);
113 if (api_result < 0) return api_result;
114
115 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0, 0, 0};
116 XDW_GetDocumentInformation(h, &info);
117
118 char *str, *token;
119 char *saveptr1, *saveptr2;
120 int x, y, sz, tr;
121 char *s;
122
123 for (str = atnlist; ; str = NULL) {
124 token = strtok_r(str, ":", &saveptr1);
125 if (token == NULL) break;
126 //printf("%s\n", token);
127
128 // atn.X, atn.Y, atn.Sz, tr, atn.Txt
129 x = atoi(strtok_r(token, ",", &saveptr2));
130 y = atoi(strtok_r(NULL , ",", &saveptr2));
131 sz = atoi(strtok_r(NULL, ",", &saveptr2));
132 tr = atoi(strtok_r(NULL, ",", &saveptr2));
133 s = strtok_r(NULL, ",", &saveptr2);
134 //printf("x=%d y=%d txt=%s sz=%d tr=%d\n", x, y, s, sz, tr);
135
136 for (int i = 0; i < info.nPages; i++ ) {
137 XDW_ANNOTATION_HANDLE annoation;
138 int api_result = XDW_AddAnnotation(h, XDW_AID_TEXT, i + 1, x, y, NULL, &annoation, NULL);
139
140 if (api_result < 0) return api_result;
141
142 api_result = XDW_SetAnnotationAttribute(h, annoation, XDW_ATN_Text, XDW_ATYPE_STRING, s, 0, NULL);
143 api_result = XDW_SetAnnotationAttribute(h, annoation, XDW_ATN_FontSize, XDW_ATYPE_INT, (char*)&sz, 0, NULL);
144
145 if (tr) {
146 int color = XDW_COLOR_NONE;
147 api_result = XDW_SetAnnotationAttribute(h, annoation, XDW_ATN_BackColor, XDW_ATYPE_INT, (char*)&color, 0, NULL);
148 }
149 }
150 }
151
152 XDW_SaveDocument(h, NULL);
153 XDW_CloseDocumentHandle(h, NULL);
154
155 return 0;
156 }
157
158 int xdwsort(const char* file, const char* sorted, const char* order, const char* workdir, const char* prefix) {
159 char buf[MAXCOL];
160
161 // メモリ確保
162 char *sl = (char*)malloc(MAXLINE * sizeof(char) * MAXCOL);
163 if (sl == NULL) return -1;
164
165 int slN = 0;
166 char *p;
167 p = strtok(order, ":");
168 strncpy(&sl[slN * MAXCOL], p, MAXCOL);
169 slN++;
170
171 while (p = strtok(NULL, ":")) {
172 strncpy(&sl[slN * MAXCOL], p, MAXCOL);
173 slN++;
174 }
175
176 //for (int j = 0; j < slN; j++) printf("%d : %s\n", j, &sl[j * MAXCOL]);
177 //return 0;
178
179 // 重み付け = 並び順
180 char in_path[_MAX_PATH];
181 _fullpath(in_path, file, _MAX_PATH);
182
183 XDW_DOCUMENT_HANDLE h = NULL;
184 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_READONLY, XDW_AUTH_NODIALOGUE};
185
186 int api_result = XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode);
187 if (api_result < 0) return api_result;
188
189 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0, 0, 0};
190 XDW_GetDocumentInformation(h, &info);
191 int last_page = info.nPages;
192
193 int *table = (int*)malloc(sizeof(int) * last_page);
194 for (int p = 0; p < last_page; p++) *(table + p) = 9999;
195
196 int index = 0;
197 XDW_FOUND_HANDLE pFoundHandle = NULL;
198 for (int i = 0; i < slN; i++) {
199 for (int p = 0; p < last_page; p++) {
200 if (*(table + p) != 9999) continue;
201
202 api_result = XDW_FindTextInPage(h, p + 1, &sl[i * MAXCOL], NULL, &pFoundHandle, NULL);
203 if (api_result < 0) return api_result;
204
205 if (pFoundHandle != NULL) {
206 *(table + p) = ++index;
207 pFoundHandle = NULL;
208 }
209 }
210 }
211 free(sl);
212
213 for (int p = 0; p < last_page; p++) {
214 if (*(table + p) == 9999) *(table + p) = ++index;
215
216 sprintf(buf, "%s/%s_%04d.xdw", workdir, prefix, *(table + p));
217 _fullpath(in_path, buf, _MAX_PATH);
218
219 api_result = XDW_GetPage(h, p + 1, in_path, NULL);
220 if (api_result < 0) return api_result;
221 }
222 free(table);
223 XDW_CloseDocumentHandle(h, NULL);
224
225 // ブロック処理
226 char *blk_path = (char*)malloc(BLOCKSZ * sizeof(char) * _MAX_PATH);
227 const char **blk_path_addr = (const char**)malloc((last_page / BLOCKSZ + 1) * sizeof(char*) * _MAX_PATH);
228
229 int bn = 0;
230 for (int p = 0, m = 0; p < last_page; p++) {
231 m = p % BLOCKSZ;
232
233 if (m == 0 && p > 0) {
234 sprintf(buf, "%s/%s_b%04d.xdw", workdir, prefix, ++bn);
235 _fullpath(in_path, buf, _MAX_PATH);
236
237 api_result = XDW_MergeXdwFiles(blk_path_addr, BLOCKSZ, in_path, NULL);
238 if (api_result < 0) return api_result;
239 }
240
241 sprintf(buf, "%s/%s_%04d.xdw", workdir, prefix, p + 1);
242 _fullpath(in_path, buf, _MAX_PATH);
243
244 strncpy(&blk_path[m * _MAX_PATH], in_path, _MAX_PATH);
245
246 blk_path_addr[m] = &blk_path[m * _MAX_PATH];
247 }
248
249 sprintf(buf, "%s/%s_b%04d.xdw", workdir, prefix, ++bn);
250 _fullpath(in_path, buf, _MAX_PATH);
251
252 int mod = last_page % BLOCKSZ;
253 if (mod == 0) mod = BLOCKSZ;
254
255 api_result = XDW_MergeXdwFiles(blk_path_addr, mod, in_path, NULL);
256 if (api_result < 0) return api_result;
257
258 for (int b = 0; b < bn; b++) {
259 sprintf(buf, "%s/%s_b%04d.xdw", workdir, prefix, b + 1);
260
261 _fullpath(in_path, buf, _MAX_PATH);
262 strncpy(&blk_path[b * _MAX_PATH], in_path, _MAX_PATH);
263
264 blk_path_addr[b] = &blk_path[b * _MAX_PATH];
265 }
266
267 _fullpath(in_path, sorted, _MAX_PATH);
268
269 api_result = XDW_MergeXdwFiles(blk_path_addr, bn, in_path, NULL);
270 if (api_result < 0) return api_result;
271
272 free(blk_path);
273 free(blk_path_addr);
274
275 return 0;
276 }
277
278 int xdw2pdf(const char* xdwfile, const char* pdffile) {
279 char in_path[_MAX_PATH], out_path[_MAX_PATH];
280 _fullpath(in_path, xdwfile, _MAX_PATH);
281 _fullpath(out_path, pdffile, _MAX_PATH);
282
283 remove(out_path);
284 int api_result = 0;
285
286 XDW_DOCUMENT_HANDLE h = NULL;
287 XDW_OPEN_MODE_EX mode = {sizeof(XDW_OPEN_MODE_EX), XDW_OPEN_READONLY, XDW_AUTH_NODIALOGUE};
288
289 api_result = XDW_OpenDocumentHandle(in_path, &h, (XDW_OPEN_MODE*)&mode);
290 if (api_result < 0) return api_result;
291
292 XDW_DOCUMENT_INFO info = {sizeof(XDW_DOCUMENT_INFO), 0, 0, 0};
293 XDW_GetDocumentInformation(h, &info);
294
295 XDW_IMAGE_OPTION_PDF pdf = {
296 sizeof(XDW_IMAGE_OPTION_PDF),
297 XDW_COMPRESS_MRC_NORMAL,
298 XDW_CONVERT_MRC_OS,
299 info.nPages
300 };
301
302 XDW_IMAGE_OPTION_EX ex = {
303 sizeof(XDW_IMAGE_OPTION_EX),
304 600, // dpi
305 XDW_IMAGE_MONO_HIGHQUALITY,
306 XDW_IMAGE_PDF,
307 &pdf
308 };
309
310 api_result = XDW_ConvertPageToImageFile(h, 1, out_path, (XDW_IMAGE_OPTION*)&ex);
311
312 XDW_SaveDocument(h, NULL);
313 XDW_CloseDocumentHandle(h, NULL);
314
315 return 0;
316 }
317
318 int xdwopt(const char* in, const char* out) {
319 char in_path[_MAX_PATH], out_path[_MAX_PATH];
320 _fullpath(in_path, in, _MAX_PATH);
321 _fullpath(out_path, out, _MAX_PATH);
322
323 int api_result = XDW_OptimizeDocument(in_path, out_path, NULL);
324 return (api_result >= 0);
325 }
326 */
327 import "C"
328
329 import (
330 "bufio"
331 "encoding/json"
332 "fmt"
333 "flag"
334 "io/ioutil"
335 "log"
336 "os"
337 "os/exec"
338 "path/filepath"
339 "regexp"
340 "sort"
341 "strings"
342 "time"
343
344 "golang.org/x/text/encoding/japanese"
345 "golang.org/x/text/transform"
346 )
347
348 var (
349 ver = "0.1"
350
351 flg_hb int
352 flg_time bool
353 flg_log bool
354 flg_debug bool
355 flg_clean bool
356
357 confjson = "nk.json"
358 logfile = "nk.log"
359 hhscsv = "hhsdb.csv"
360 tmpdir string
361 tmpprefix = "nktemp_"
362 inputdir = "input"
363 outputdir = "output"
364 outcsv = "out.csv"
365
366 start time.Time
367
368 hb string // 発番
369 fw, hs, kt = "", "", "kttemp.xdw" // 負担割合証, 被保険者証, 結果通知
370
371 step, totalstep = 1, 13
372 )
373
374 type Annotation struct {
375 X, Y int
376 Sz int
377 Tr bool
378 Txt string
379 }
380
381 type Config struct {
382 Atns []Annotation
383 Kyotaku []string
384 }
385
386 func (c *Config) ProcessTemplate() {
387 today := time.Now().Format("令和 r 年 1 月 2 日")
388 y := time.Now().Year() - 2018
389 if y == 1 {
390 today = strings.ReplaceAll(today, "r", "元")
391 } else {
392 today = strings.ReplaceAll(today, "r", fmt.Sprintf("%d", y))
393 }
394
395 var atns []Annotation
396 for _, atn := range c.Atns {
397 s := atn.Txt
398 if atn.Txt == "date" {
399 s = today
400 }
401 if strings.ContainsAny(atn.Txt, "hb") {
402 s = strings.ReplaceAll(atn.Txt, "hb", hb)
403 }
404 atns = append(atns, Annotation{atn.X, atn.Y, atn.Sz, atn.Tr, s})
405 }
406 c.Atns = atns
407 }
408
409 func (c *Config) KyotakuList() []string {
410 return c.Kyotaku
411 }
412
413 func (c *Config) AnnotationList() (al []string) {
414 for _, atn := range c.Atns {
415 tr := 0
416 if atn.Tr {
417 tr = 1
418 }
419 s := fmt.Sprintf("%d,%d,%d,%d,%s", atn.X, atn.Y, atn.Sz, tr, atn.Txt)
420 al = append(al, s)
421 }
422 return
423 }
424
425 func init() {
426 /* INITIALIZE FLAGS */
427 flag.IntVar(&flg_hb, "b", 0, "set hatsuban")
428 flag.BoolVar(&flg_time, "t", false, "print time")
429 flag.BoolVar(&flg_log, "l", false, "save log")
430 flag.BoolVar(&flg_debug, "d", false, "print data for debug")
431 flag.BoolVar(&flg_clean, "c", false, "clean temporary directory & exit")
432
433 /* CREAN OUTPUT-FILE & TEMP-FILE */
434 if err := os.RemoveAll(outputdir); err != nil {
435 log.Fatal(err)
436 }
437 os.Remove(logfile)
438
439 /* PREPARATE OUTPUT-DIR & TEMP-DIR */
440 if err := os.Mkdir(outputdir, 0755); err != nil {
441 log.Fatal(err)
442 }
443
444 var err error
445 tmpdir, err = ioutil.TempDir(".", tmpprefix)
446 if err != nil {
447 log.Fatal(err)
448 }
449 logfile = filepath.Join(tmpdir, logfile)
450 kt = filepath.Join(tmpdir, kt)
451 }
452
453 func main() {
454 flag.Parse()
455
456 /* CLEAN TEMPORARY DIRECTORY */
457 if flg_clean {
458 files, err := ioutil.ReadDir(".")
459 if err != nil {
460 log.Fatal(err)
461 }
462 for _, file := range files {
463 if strings.HasPrefix(file.Name(), tmpprefix) {
464 if err := os.RemoveAll(file.Name()); err != nil {
465 log.Fatal(err)
466 }
467 }
468 }
469 os.Exit(0)
470 }
471
472 /* PRINT HEADER */
473 fmt.Println("=======================================")
474 fmt.Println(" 被保険者証と結果通知と負担割合証を... ")
475 fmt.Printf(" - nk [ver %s] -\n", ver)
476 fmt.Println("=======================================\n")
477
478 /* USER INPUT */
479 hb = fmt.Sprintf("%d", flg_hb)
480 if flg_hb == 0 {
481 fmt.Print("発番 > ")
482 fmt.Scan(&hb)
483 }
484
485 start = time.Now()
486
487 /* READ CONFIG FROM JSON */
488 print_step("設定読込み")
489 conf, err := read_conf(confjson)
490 if err != nil {
491 log.Fatal(err)
492 }
493 conf.ProcessTemplate()
494 step_start := print_time(start)
495
496 /* CHECK INPUT-FILE */
497 print_step("入力ファイルのチェック")
498 files, err := ioutil.ReadDir(inputdir)
499 if err != nil {
500 log.Fatal(err)
501 }
502
503 var kts []string
504 for _, file := range files {
505 if strings.HasSuffix(file.Name(), ".xdw") {
506 print_debug([]string{file.Name()})
507 switch file.Name()[0:8] {
508 case "KBPV016G":
509 fw = filepath.Join(inputdir, file.Name())
510 case "KBPG316G":
511 hs = filepath.Join(inputdir, file.Name())
512 case "KBPG206G", "KBPG706G":
513 f := filepath.Join(inputdir, file.Name())
514 kts = append(kts, f)
515 }
516 }
517 }
518
519 fmt.Println()
520 fmt.Printf(" 負担割合証ファイル = %s\n", fw)
521 fmt.Printf(" 被保険者証ファイル = %s\n", hs)
522 fmt.Print(" 結果通知ファイル =")
523 for _, f := range kts {
524 fmt.Printf(" %s", f)
525 }
526 fmt.Println()
527 if fw == "" || hs == "" || len(kts) == 0 {
528 fmt.Fprintf(os.Stderr, "Input file is wrong.\n")
529 os.Exit(1)
530 }
531
532 bytes, err := ioutil.ReadFile(hhscsv)
533 if err != nil {
534 log.Fatal(err)
535 }
536 hash_hhs := make(map[string]string) // 被保険者氏名のハッシュ
537 r := strings.NewReader(string(bytes))
538 tr := transform.NewReader(r, japanese.ShiftJIS.NewDecoder())
539 buf := bufio.NewScanner(tr)
540 for buf.Scan() {
541 records := strings.Split(buf.Text(), ",")
542 hash_hhs[records[0]] = records[2]
543 }
544 fmt.Printf(" 被保険者ファイル = %s\n", hhscsv)
545
546 step_start = print_time(step_start)
547
548 /* CONCATNATE INPUT-FILE */
549 print_step("結果通知ファイルの連結")
550 b, err := ioutil.ReadFile(kts[0])
551 if err != nil {
552 log.Fatal(err)
553 }
554 if err = ioutil.WriteFile(kt, b, 0644); err != nil {
555 log.Fatal(err)
556 }
557 if len(kts) > 1 {
558 pp := 0
559 fmt.Println()
560 for _, file := range kts {
561 p, _ := C.xdwpages(C.CString(file))
562 fmt.Printf(" %s\t= %d ページ\n", file, int(p))
563 pp += int(p)
564 }
565 fmt.Printf(" 合計\t= %d ページ\n", pp)
566 for _, file := range kts[1:] {
567 C.xdwpush(C.CString(kt), C.CString(file))
568 }
569 }
570 step_start = print_time(step_start)
571
572 /* MAKE SORT-TABEL */
573 print_step("並び順の決定")
574
575 re_hhs := regexp.MustCompile(`05((2126)|(2159)|(4346))0[1238]\d{8}`)
576 re_kaigo := regexp.MustCompile(`要((介護)|(支援)).`)
577
578 hash_fw := make(map[string]int) // 負担割合証発行者のハッシュ
579 for _, t := range xdw2txt(fw) {
580 hash_fw[re_hhs.FindString(t)]++
581 print_debug([]string{re_hhs.FindString(t)})
582 }
583
584 kyotaku := conf.KyotakuList()
585
586 hash_kaigo := make(map[string]string) // 被保険者証発行者の要介護度のハッシュ
587 hash_kyotaku := make(map[string]string) // 被保険者証発行者の居宅介護支援事業所のハッシュ
588 var sorttable []string
589 for _, t := range xdw2txt(hs) {
590 h := re_hhs.FindString(t)
591 hash_kaigo[h] = re_kaigo.FindString(t)
592 for _, k := range kyotaku {
593 if strings.Contains(t, k) {
594 hash_kyotaku[h] = k
595 }
596 }
597 key := make_sort_key(hash_fw[h], re_kaigo.FindString(t), h)
598 s := fmt.Sprintf("%s#%d:%s:%s#%s", key, hash_fw[h], re_kaigo.FindString(t), hash_kyotaku[h], h)
599 sorttable = append(sorttable, s)
600 }
601 //sort.Sort(sort.Reverse(sort.StringSlice(sorttable)))
602 sort.Sort(sort.StringSlice(sorttable))
603 print_debug(sorttable)
604 step_start = print_time(step_start)
605
606 /* DO SORT */
607 order := ""
608 for _, s := range sorttable {
609 t := strings.Split(s, "#")
610 order += ":" + t[len(t)-1][6:]
611 }
612 order = strings.Replace(order, ":", "", 1)
613
614 print_step("被保険者証並び替え")
615 hs_sorted := filepath.Join(tmpdir, "hs.xdw")
616 C.xdwsort(C.CString(hs), C.CString(hs_sorted), C.CString(order), C.CString(tmpdir), C.CString("hs"))
617 step_start = print_time(step_start)
618
619 print_step("負担割合証並び替え")
620 fw_sorted := filepath.Join(tmpdir, "fw.xdw")
621 C.xdwsort(C.CString(fw), C.CString(fw_sorted), C.CString(order), C.CString(tmpdir), C.CString("fw"))
622 step_start = print_time(step_start)
623
624 print_step("結果通知並び替え")
625 kt_sorted := filepath.Join(tmpdir, "kt.xdw")
626 C.xdwsort(C.CString(kt), C.CString(kt_sorted), C.CString(order), C.CString(tmpdir), C.CString("kt"))
627 step_start = print_time(step_start)
628
629 /* ADD ANNOTATION */
630 print_step("発番印字")
631 al := strings.Join(conf.AnnotationList(), ":")
632 al, _, _ = transform.String(japanese.ShiftJIS.NewEncoder(), al)
633 C.xdwaddatn(C.CString(kt_sorted), C.CString(al))
634 step_start = print_time(step_start)
635
636 /* OPTIMIZE OUTPUT-FILE */
637 print_step("最適化")
638 hs_opt := filepath.Join(outputdir, "hs.xdw")
639 C.xdwopt(C.CString(hs_sorted), C.CString(hs_opt))
640 fw_opt := filepath.Join(outputdir, "fw.xdw")
641 C.xdwopt(C.CString(fw_sorted), C.CString(fw_opt))
642 kt_opt := filepath.Join(outputdir, "kt.xdw")
643 C.xdwopt(C.CString(kt_sorted), C.CString(kt_opt))
644 step_start = print_time(step_start)
645
646 /* OUTPUT CSV */
647 print_step("CSV出力")
648 outcsv = filepath.Join(outputdir, outcsv)
649 fcsv, err := os.OpenFile(outcsv, os.O_RDWR|os.O_CREATE, 0644)
650 if err != nil {
651 log.Fatal(err)
652 }
653 for i, s := range sorttable {
654 t := strings.Split(s, "#")
655 u := strings.ReplaceAll(t[1], ":", ",")
656 u, _, _ = transform.String(japanese.ShiftJIS.NewEncoder(), u)
657 c := t[2][0:6]
658 h := t[2][6:16]
659 n, _, _ := transform.String(japanese.ShiftJIS.NewEncoder(), hash_hhs[h])
660 // seq, city, hno, name, kaigo, fw, kyotaku
661 fmt.Fprintf(fcsv, "%04d,%s,%s,%s,%s\n", i + 1, c, h, n, u)
662 }
663 if err := fcsv.Close(); err != nil {
664 log.Fatal(err)
665 }
666 step_start = print_time(step_start)
667
668 /* PDF */
669 print_step("負担割合証割付PDF作成")
670 fwpdf := filepath.Join(tmpdir, "fw.pdf")
671 C.xdw2pdf(C.CString(fw_opt), C.CString(fwpdf)) // 2min
672 step_start = print_time(step_start)
673
674 print_step("負担割合証PDF割付")
675 fw4pdf := filepath.Join(outputdir, "fw4.pdf")
676 cmd := exec.Command("fw4.exe", fwpdf, fw4pdf, tmpdir)
677 if err := cmd.Run(); err != nil {
678 log.Fatal(err)
679 }
680 step_start = print_time(step_start)
681
682 print_step("終了")
683 step_start = print_time(step_start)
684
685 /* REMOVE TEMP-FILE */
686 if flg_log {
687 logfile2 := filepath.Join(".", strings.Replace(logfile, tmpdir, "", 1))
688 os.Link(logfile, logfile2)
689 }
690
691 if !flg_debug {
692 if err := os.RemoveAll(tmpdir); err != nil {
693 log.Fatal(err)
694 }
695 }
696 }
697
698 func make_sort_key(fw int, kaigo, h string) string {
699 key := fmt.Sprintf("%d:", 9 - fw)
700 if strings.HasPrefix(kaigo, "要支援") {
701 key += "1"
702 }
703 if strings.HasPrefix(kaigo, "要介護") {
704 key += "2"
705 }
706 switch {
707 case strings.HasSuffix(kaigo, "1"):
708 key += "1:"
709 case strings.HasSuffix(kaigo, "2"):
710 key += "2:"
711 case strings.HasSuffix(kaigo, "3"):
712 key += "3:"
713 case strings.HasSuffix(kaigo, "4"):
714 key += "4:"
715 case strings.HasSuffix(kaigo, "5"):
716 key += "5:"
717 default:
718 key += "00:"
719 }
720 return key + h
721 }
722
723 func xdw2txt(file string) (txt []string) {
724 s := C.GoString(C.xdw2txt(C.CString(file)))
725 r := strings.NewReader(s)
726 tr := transform.NewReader(r, japanese.ShiftJIS.NewDecoder())
727 buf := bufio.NewScanner(tr)
728 for buf.Scan() {
729 txt = append(txt, buf.Text())
730 }
731 return;
732 }
733
734 func read_conf(file string) (conf Config, err error) {
735 content, err := ioutil.ReadFile(file)
736 if err != nil {
737 log.Fatal(err)
738 }
739 err = json.Unmarshal(content, &conf)
740 return
741 }
742
743 func print_step(msg string) {
744 s := fmt.Sprintf("\n[%d/%d] %s\n", step, totalstep, msg)
745 step++
746 fmt.Print(s)
747 save_log(s)
748 }
749
750 func print_time(t time.Time) time.Time {
751 now := time.Now()
752 if !flg_time {
753 return now
754 }
755 elapsed := now.Sub(t)
756 total := now.Sub(start)
757 s := fmt.Sprintf("---- Elapsed: %v (total = %v) @ %02d:%02d\n", elapsed, total, now.Hour(), now.Minute())
758 fmt.Print(s)
759 save_log(s)
760 return now
761 }
762
763 func print_debug(msg []string) {
764 if !flg_debug {
765 return
766 }
767 s := ""
768 if len(msg) == 1 {
769 s = fmt.Sprintf("----- %s\n", msg)
770 }
771 for i, s := range msg {
772 s += fmt.Sprintf("%05d %s\n", i, s)
773 }
774 fmt.Print(s)
775 save_log(s)
776 }
777
778 func save_log(logtxt string) error {
779 if !flg_log {
780 return nil
781 }
782 f, err := os.OpenFile(logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
783 if err != nil {
784 return err
785 }
786 if _, err := f.Write([]byte(logtxt)); err != nil {
787 f.Close()
788 return err
789 }
790 if err := f.Close(); err != nil {
791 return err
792 }
793 return nil
794 }
795