1

Compare commits

..

10 Commits

Author SHA1 Message Date
6991ccf249 Add license 2023-03-13 19:27:39 -07:00
Alexei Yatskov
fc2ac3e03c
Merge pull request #2 from eqyiel/patch-1
fix: make build work on macos
2022-07-14 15:31:41 -07:00
bc00845361 Move to foosoft.net 2022-07-03 20:50:39 -07:00
Ruben Maher
3be10cb389
fix: make build work on macos
Otherwise the build will fail with errors like `ld: symbol(s) not found for architecture x86_64`
2022-04-24 07:34:14 +09:00
2b31c3d779 Fixes for windows 2021-01-10 17:03:06 -08:00
cdd6f9e1a9 Path changes for windows 2021-01-10 16:28:16 -08:00
7c4b1f8c8b Windows fixes 2021-01-10 11:51:14 -08:00
4e432fa545 Fix incorrect text read call 2021-01-09 22:36:57 -08:00
8924b11aa8 Update output 2021-01-09 22:05:14 -08:00
a93f029d43 Format error messages 2021-01-09 20:49:12 -08:00
8 changed files with 272 additions and 34 deletions

18
LICENSE Normal file
View File

@ -0,0 +1,18 @@
Copyright 2020-2023 Alex Yatskov
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

6
README.md Normal file
View File

@ -0,0 +1,6 @@
<!-- +++
GitHub = "zero-epwing-go"
Layout = "page"
+++ -->
# Zero-EPWING-Go

View File

@ -31,6 +31,12 @@
#include "error.h" #include "error.h"
#include "build-post.h" #include "build-post.h"
#ifdef WIN32
#include <direct.h>
#endif
#ifndef WIN32
/* /*
* Canonicalize `path_name' (UNIX version). * Canonicalize `path_name' (UNIX version).
* Convert a path name to an absolute path. * Convert a path name to an absolute path.
@ -74,6 +80,104 @@ eb_canonicalize_path_name(char *path_name)
return EB_SUCCESS; return EB_SUCCESS;
} }
#else /* WIN32 */
/*
* Canonicalize `path_name' (DOS version).
* Convert a path name to an absolute path with drive letter unless
* that is an UNC path.
*
* Original version by KSK Jan/30/1998.
* Current version by Motoyuki Kasahara.
*/
EB_Error_Code
eb_canonicalize_path_name(char *path_name)
{
char cwd[EB_MAX_PATH_LENGTH + 1];
char temporary_path_name[EB_MAX_PATH_LENGTH + 1];
char *slash;
char *last_backslash;
/*
* Replace `/' with `\\'.
*/
slash = path_name;
for (;;) {
slash = strchr(slash, '/');
if (slash == NULL)
break;
*slash++ = '\\';
}
if (*path_name == '\\' && *(path_name + 1) == '\\') {
/*
* `path_name' is UNC path. Nothing to be done.
*/
} else if (ASCII_ISALPHA(*path_name) && *(path_name + 1) == ':') {
/*
* `path_name' has a drive letter.
* Nothing to be done if it is an absolute path.
*/
if (*(path_name + 2) != '\\') {
/*
* `path_name' is a relative path.
* Covert the path name to an absolute path.
*/
if (_getdcwd(ASCII_TOUPPER(*path_name) - 'A' + 1, cwd,
EB_MAX_PATH_LENGTH + 1) == NULL) {
return EB_ERR_FAIL_GETCWD;
}
if (EB_MAX_PATH_LENGTH < strlen(cwd) + 1 + strlen(path_name + 2))
return EB_ERR_TOO_LONG_FILE_NAME;
sprintf(temporary_path_name, "%s\\%s", cwd, path_name + 2);
strcpy(path_name, temporary_path_name);
}
} else if (*path_name == '\\') {
/*
* `path_name' has no drive letter and is an absolute path.
* Add a drive letter to the path name.
*/
if (getcwd(cwd, EB_MAX_PATH_LENGTH + 1) == NULL)
return EB_ERR_FAIL_GETCWD;
cwd[1] = '\0';
if (EB_MAX_PATH_LENGTH < strlen(cwd) + 1 + strlen(path_name))
return EB_ERR_TOO_LONG_FILE_NAME;
sprintf(temporary_path_name, "%s:%s", cwd, path_name);
strcpy(path_name, temporary_path_name);
} else {
/*
* `path_name' has no drive letter and is a relative path.
* Add a drive letter and convert it to an absolute path.
*/
if (getcwd(cwd, EB_MAX_PATH_LENGTH + 1) == NULL)
return EB_ERR_FAIL_GETCWD;
if (EB_MAX_PATH_LENGTH < strlen(cwd) + 1 + strlen(path_name))
return EB_ERR_TOO_LONG_FILE_NAME;
sprintf(temporary_path_name, "%s\\%s", cwd, path_name);
strcpy(path_name, temporary_path_name);
}
/*
* Now `path_name' is `X:\...' or `\\...'.
* Unless it is "X:\", eliminate `\' in the tail of the path name.
*/
last_backslash = strrchr(path_name, '\\');
if (ASCII_ISALPHA(*path_name)) {
if (last_backslash != path_name + 2 && *(last_backslash + 1) == '\0')
*last_backslash = '\0';
} else {
if (last_backslash != path_name + 1 && *(last_backslash + 1) == '\0')
*last_backslash = '\0';
}
return EB_SUCCESS;
}
#endif /* WIN32 */
/* /*
* Canonicalize file name. * Canonicalize file name.
@ -175,7 +279,11 @@ eb_fix_path_name_suffix(char *path_name, const char *suffix)
char *dot; char *dot;
char *semicolon; char *semicolon;
#ifndef WIN32
base_name = strrchr(path_name, '/'); base_name = strrchr(path_name, '/');
#else
base_name = strrchr(path_name, '\\');
#endif
if (base_name == NULL) if (base_name == NULL)
base_name = path_name; base_name = path_name;
else else
@ -378,10 +486,17 @@ void
eb_compose_path_name(const char *path_name, const char *file_name, eb_compose_path_name(const char *path_name, const char *file_name,
char *composed_path_name) char *composed_path_name)
{ {
#ifndef WIN32
if (strcmp(path_name, "/") == 0) if (strcmp(path_name, "/") == 0)
sprintf(composed_path_name, "%s%s", path_name, file_name); sprintf(composed_path_name, "%s%s", path_name, file_name);
else else
sprintf(composed_path_name, "%s/%s", path_name, file_name); sprintf(composed_path_name, "%s/%s", path_name, file_name);
#else
if (ASCII_ISALPHA(*path_name) && strcmp(path_name + 1, ":\\") == 0)
sprintf(composed_path_name, "%s%s", path_name, file_name);
else
sprintf(composed_path_name, "%s\\%s", path_name, file_name);
#endif
} }
@ -394,6 +509,7 @@ void
eb_compose_path_name2(const char *path_name, const char *sub_directory_name, eb_compose_path_name2(const char *path_name, const char *sub_directory_name,
const char *file_name, char *composed_path_name) const char *file_name, char *composed_path_name)
{ {
#ifndef WIN32
if (strcmp(path_name, "/") == 0) { if (strcmp(path_name, "/") == 0) {
sprintf(composed_path_name, "%s%s/%s", sprintf(composed_path_name, "%s%s/%s",
path_name, sub_directory_name, file_name); path_name, sub_directory_name, file_name);
@ -401,6 +517,16 @@ eb_compose_path_name2(const char *path_name, const char *sub_directory_name,
sprintf(composed_path_name, "%s/%s/%s", sprintf(composed_path_name, "%s/%s/%s",
path_name, sub_directory_name, file_name); path_name, sub_directory_name, file_name);
} }
#else
if (ASCII_ISALPHA(*path_name)
&& strcmp(path_name + 1, ":\\") == 0) {
sprintf(composed_path_name, "%s%s\\%s",
path_name, sub_directory_name, file_name);
} else {
sprintf(composed_path_name, "%s\\%s\\%s",
path_name, sub_directory_name, file_name);
}
#endif
} }
@ -414,6 +540,7 @@ eb_compose_path_name3(const char *path_name, const char *sub_directory_name,
const char *sub2_directory_name, const char *file_name, const char *sub2_directory_name, const char *file_name,
char *composed_path_name) char *composed_path_name)
{ {
#ifndef WIN32
if (strcmp(path_name, "/") == 0) { if (strcmp(path_name, "/") == 0) {
sprintf(composed_path_name, "%s%s/%s/%s", sprintf(composed_path_name, "%s%s/%s/%s",
path_name, sub_directory_name, sub2_directory_name, file_name); path_name, sub_directory_name, sub2_directory_name, file_name);
@ -421,6 +548,16 @@ eb_compose_path_name3(const char *path_name, const char *sub_directory_name,
sprintf(composed_path_name, "%s/%s/%s/%s", sprintf(composed_path_name, "%s/%s/%s/%s",
path_name, sub_directory_name, sub2_directory_name, file_name); path_name, sub_directory_name, sub2_directory_name, file_name);
} }
#else
if (ASCII_ISALPHA(*path_name)
&& strcmp(path_name + 1, ":\\") == 0) {
sprintf(composed_path_name, "%s%s\\%s\\%s",
path_name, sub_directory_name, sub2_directory_name, file_name);
} else {
sprintf(composed_path_name, "%s\\%s\\%s\\%s",
path_name, sub_directory_name, sub2_directory_name, file_name);
}
#endif
} }
@ -590,7 +727,11 @@ eb_path_name_zio_code(const char *path_name, Zio_Code default_zio_code,
const char *base_name; const char *base_name;
const char *dot; const char *dot;
#ifndef WIN32
base_name = strrchr(path_name, '/'); base_name = strrchr(path_name, '/');
#else
base_name = strrchr(path_name, '\\');
#endif
if (base_name != NULL) if (base_name != NULL)
base_name++; base_name++;
else else

6
go.mod
View File

@ -1,5 +1,5 @@
module github.com/FooSoft/zero-epwing-go module foosoft.net/projects/zero-epwing-go
go 1.15 go 1.18
require golang.org/x/text v0.3.4 require golang.org/x/text v0.3.7

6
go.sum
View File

@ -1,4 +1,2 @@
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -29,12 +29,17 @@
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <sys/socket.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
#include "linebuf.h" #include "linebuf.h"
/* /*

View File

@ -1,25 +1,89 @@
package main package main
import ( import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log" "log"
"os" "os"
zig "github.com/FooSoft/zero-epwing-go" zig "foosoft.net/projects/zero-epwing-go"
) )
type Entry struct {
Heading string `json:"heading"`
Text string `json:"text"`
}
type Subbook struct {
Title string `json:"title"`
Copyright string `json:"copyrignt"`
Entries []Entry `json:"entries"`
}
type Book struct {
DiscCode string `json:"discCode"`
CharCode string `json:"charCode"`
Subbooks []Subbook `json:"subbooks"`
}
func outputBook(bookSrc *zig.Book, path string, pretty bool) error {
bookDst := Book{DiscCode: bookSrc.DiscCode, CharCode: bookSrc.CharCode}
for _, subbookSrc := range bookSrc.Subbooks {
subbookDst := Subbook{Title: subbookSrc.Title, Copyright: subbookSrc.Copyright}
for _, entrySrc := range subbookSrc.Entries {
entryDst := Entry{entrySrc.Heading, entrySrc.Text}
subbookDst.Entries = append(subbookDst.Entries, entryDst)
}
bookDst.Subbooks = append(bookDst.Subbooks, subbookDst)
}
var (
data []byte
err error
)
if pretty {
data, err = json.MarshalIndent(bookDst, "", "\t")
} else {
data, err = json.Marshal(bookDst)
}
if err != nil {
return err
}
return ioutil.WriteFile(path, data, 0644)
}
func main() { func main() {
book, err := zig.Load(os.Args[1]) var (
entriesPath = flag.String("entries-path", "", "output path for dictionary entries")
entriesPretty = flag.Bool("entries-pretty", false, "pretty-print dictionary entries")
)
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: zero-epwing [options] path\n")
fmt.Fprintf(os.Stderr, "Parameters:\n")
flag.PrintDefaults()
}
flag.Parse()
args := flag.Args()
if len(args) != 1 {
flag.Usage()
os.Exit(2)
}
book, err := zig.Load(args[0])
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
fp, err := os.Create(os.Args[2]) if err := outputBook(book, *entriesPath, *entriesPretty); err != nil {
defer fp.Close() log.Fatal(err)
for _, subbook := range book.Subbooks {
for _, entry := range subbook.Entries {
fp.WriteString(entry.Heading)
fp.WriteString("\n")
}
} }
} }

38
zig.go
View File

@ -10,7 +10,9 @@ import (
) )
/* /*
#cgo LDFLAGS: -lz #cgo linux LDFLAGS: -lz
#cgo darwin LDFLAGS: -lz
#cgo windows LDFLAGS: -lz -lws2_32
#include "zig.h" #include "zig.h"
*/ */
import "C" import "C"
@ -34,6 +36,10 @@ func hookCallback(book *C.EB_Book, appendix *C.EB_Appendix, container *C.void, h
return C.EB_SUCCESS return C.EB_SUCCESS
} }
func formatError(code C.EB_Error_Code) string {
return C.GoString(C.eb_error_string(code))
}
type blockType int type blockType int
const ( const (
@ -67,10 +73,10 @@ type Context struct {
func (c *Context) initialize() error { func (c *Context) initialize() error {
if errEb := C.eb_initialize_library(); errEb != C.EB_SUCCESS { if errEb := C.eb_initialize_library(); errEb != C.EB_SUCCESS {
return fmt.Errorf("eb_initialize_library failed with code %d", errEb) return fmt.Errorf("eb_initialize_library failed with code: %s", formatError(errEb))
} }
c.book = (*C.EB_Book)(C.calloc(1, C.size_t(unsafe.Sizeof(C.EB_Book{}))+8)) c.book = (*C.EB_Book)(C.calloc(1, C.size_t(unsafe.Sizeof(C.EB_Book{}))))
C.eb_initialize_book(c.book) C.eb_initialize_book(c.book)
c.hookset = (*C.EB_Hookset)(C.calloc(1, C.size_t(unsafe.Sizeof(C.EB_Hookset{})))) c.hookset = (*C.EB_Hookset)(C.calloc(1, C.size_t(unsafe.Sizeof(C.EB_Hookset{}))))
@ -104,7 +110,7 @@ func (c *Context) installHooks() error {
for _, hookCode := range hookCodes { for _, hookCode := range hookCodes {
if errEb := C.installHook(c.hookset, hookCode); errEb != C.EB_SUCCESS { if errEb := C.installHook(c.hookset, hookCode); errEb != C.EB_SUCCESS {
return fmt.Errorf("eb_set_hook failed with code %d", errEb) return fmt.Errorf("eb_set_hook failed with code: %s", formatError(errEb))
} }
} }
@ -115,7 +121,7 @@ func (c *Context) loadInternal(path string) (*Book, error) {
pathC := C.CString(path) pathC := C.CString(path)
defer C.free(unsafe.Pointer(pathC)) defer C.free(unsafe.Pointer(pathC))
if errEb := C.eb_bind(c.book, pathC); errEb != C.EB_SUCCESS { if errEb := C.eb_bind(c.book, pathC); errEb != C.EB_SUCCESS {
return nil, fmt.Errorf("eb_bind failed with code %d", errEb) return nil, fmt.Errorf("eb_bind failed with code: %s", formatError(errEb))
} }
var ( var (
@ -141,7 +147,7 @@ func (c *Context) loadInternal(path string) (*Book, error) {
func (c *Context) loadCharCode() (string, error) { func (c *Context) loadCharCode() (string, error) {
var charCode C.EB_Character_Code var charCode C.EB_Character_Code
if errEb := C.eb_character_code(c.book, &charCode); errEb != C.EB_SUCCESS { if errEb := C.eb_character_code(c.book, &charCode); errEb != C.EB_SUCCESS {
return "", fmt.Errorf("eb_character_code failed with code %d", errEb) return "", fmt.Errorf("eb_character_code failed with code: %s", formatError(errEb))
} }
switch charCode { switch charCode {
@ -159,7 +165,7 @@ func (c *Context) loadCharCode() (string, error) {
func (c *Context) loadDiscCode() (string, error) { func (c *Context) loadDiscCode() (string, error) {
var discCode C.EB_Disc_Code var discCode C.EB_Disc_Code
if errEb := C.eb_disc_type(c.book, &discCode); errEb != C.EB_SUCCESS { if errEb := C.eb_disc_type(c.book, &discCode); errEb != C.EB_SUCCESS {
return "", fmt.Errorf("eb_disc_type failed with code %d", errEb) return "", fmt.Errorf("eb_disc_type failed with code: %s", formatError(errEb))
} }
switch discCode { switch discCode {
@ -179,7 +185,7 @@ func (c *Context) loadSubbooks() ([]BookSubbook, error) {
) )
if errEb := C.eb_subbook_list(c.book, &subbookCodes[0], &subbookCount); errEb != C.EB_SUCCESS { if errEb := C.eb_subbook_list(c.book, &subbookCodes[0], &subbookCount); errEb != C.EB_SUCCESS {
return nil, fmt.Errorf("eb_subbook_list failed with code %d", errEb) return nil, fmt.Errorf("eb_subbook_list failed with code: %s", formatError(errEb))
} }
var subbooks []BookSubbook var subbooks []BookSubbook
@ -197,7 +203,7 @@ func (c *Context) loadSubbooks() ([]BookSubbook, error) {
func (c *Context) loadSubbook(subbookCode C.EB_Subbook_Code) (*BookSubbook, error) { func (c *Context) loadSubbook(subbookCode C.EB_Subbook_Code) (*BookSubbook, error) {
if errEb := C.eb_set_subbook(c.book, subbookCode); errEb != C.EB_SUCCESS { if errEb := C.eb_set_subbook(c.book, subbookCode); errEb != C.EB_SUCCESS {
return nil, fmt.Errorf("eb_set_subbook failed with code %d", errEb) return nil, fmt.Errorf("eb_set_subbook failed with code: %s", formatError(errEb))
} }
var ( var (
@ -255,7 +261,7 @@ func (c *Context) loadEntries(blocksSeen map[uint32]bool) ([]BookEntry, error) {
) )
if errEb := C.eb_hit_list(c.book, (C.int)(len(hits)), &hits[0], &hitCount); errEb != C.EB_SUCCESS { if errEb := C.eb_hit_list(c.book, (C.int)(len(hits)), &hits[0], &hitCount); errEb != C.EB_SUCCESS {
return nil, fmt.Errorf("eb_hit_list failed with code %d", errEb) return nil, fmt.Errorf("eb_hit_list failed with code: %s", formatError(errEb))
} }
for _, hit := range hits[:hitCount] { for _, hit := range hits[:hitCount] {
@ -268,7 +274,7 @@ func (c *Context) loadEntries(blocksSeen map[uint32]bool) ([]BookEntry, error) {
return nil, err return nil, err
} }
if entry.Text, err = c.loadContent(hit.text, blockTypeHeading); err != nil { if entry.Text, err = c.loadContent(hit.text, blockTypeText); err != nil {
return nil, err return nil, err
} }
@ -292,7 +298,7 @@ func (c *Context) loadEntries(blocksSeen map[uint32]bool) ([]BookEntry, error) {
func (c *Context) loadTitle() (string, error) { func (c *Context) loadTitle() (string, error) {
var data [C.EB_MAX_TITLE_LENGTH + 1]C.char var data [C.EB_MAX_TITLE_LENGTH + 1]C.char
if errEb := C.eb_subbook_title(c.book, &data[0]); errEb != C.EB_SUCCESS { if errEb := C.eb_subbook_title(c.book, &data[0]); errEb != C.EB_SUCCESS {
return "", fmt.Errorf("eb_subbook_title failed with code %d", errEb) return "", fmt.Errorf("eb_subbook_title failed with code: %s", formatError(errEb))
} }
return c.decoder.String(C.GoString(&data[0])) return c.decoder.String(C.GoString(&data[0]))
@ -305,7 +311,7 @@ func (c *Context) loadCopyright() (string, error) {
var position C.EB_Position var position C.EB_Position
if errEb := C.eb_copyright(c.book, &position); errEb != C.EB_SUCCESS { if errEb := C.eb_copyright(c.book, &position); errEb != C.EB_SUCCESS {
return "", fmt.Errorf("eb_copyright failed with code %d", errEb) return "", fmt.Errorf("eb_copyright failed with code: %s", formatError(errEb))
} }
return c.loadContent(position, blockTypeText) return c.loadContent(position, blockTypeText)
@ -320,17 +326,17 @@ func (c *Context) loadContent(position C.EB_Position, blockType blockType) (stri
) )
if errEb := C.eb_seek_text(c.book, &position); errEb != C.EB_SUCCESS { if errEb := C.eb_seek_text(c.book, &position); errEb != C.EB_SUCCESS {
return "", fmt.Errorf("eb_seek_text failed with code %d", errEb) return "", fmt.Errorf("eb_seek_text failed with code: %s", formatError(errEb))
} }
switch blockType { switch blockType {
case blockTypeHeading: case blockTypeHeading:
if errEb := C.eb_read_heading(c.book, nil, c.hookset, nil, dataSize, data, &dataUsed); errEb != C.EB_SUCCESS { if errEb := C.eb_read_heading(c.book, nil, c.hookset, nil, dataSize, data, &dataUsed); errEb != C.EB_SUCCESS {
return "", fmt.Errorf("eb_read_heading failed with code %d", errEb) return "", fmt.Errorf("eb_read_heading failed with code: %s", formatError(errEb))
} }
case blockTypeText: case blockTypeText:
if errEb := C.eb_read_text(c.book, nil, c.hookset, nil, dataSize, data, &dataUsed); errEb != C.EB_SUCCESS { if errEb := C.eb_read_text(c.book, nil, c.hookset, nil, dataSize, data, &dataUsed); errEb != C.EB_SUCCESS {
return "", fmt.Errorf("eb_read_text failed with code %d", errEb) return "", fmt.Errorf("eb_read_text failed with code: %s", formatError(errEb))
} }
default: default:
panic("invalid block type") panic("invalid block type")