/* vi:ts=4:sw=4 * * VIM - Vi IMitation Japanese extension * * Code Contributions By: Atsushi Nakamura ann@mrit.mei.co.jp */ #include "vim.h" #include "globals.h" #include "proto.h" #include "param.h" #include "ops.h" #ifdef JP #include "jp.h" #include "jptab.h" # ifdef sony # define sjis2euc sjis_to_euc # endif #endif static int jisx0201rto0208(); #ifdef GENERAL # undef free #endif #if defined(UNIX) && !defined(GENERAL) #include "signal.h" /* * handle core dump by some bugs. */ static void core_handler(dummy) int dummy; { static void abend_handler(); abend_handler(TRUE); } static void hup_handler(dummy) int dummy; { static void abend_handler(); abend_handler(FALSE); } static void abend_handler(core) int core; { char *text; settmode(0); stoptermcap(); flushbuf(); stopscript(); /* remove autoscript file */ #ifdef JPFEP fep_freqsave(); #endif signal(SIGQUIT, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGSEGV, SIG_DFL); #ifdef SIGILL signal(SIGILL, SIG_DFL); #endif #ifdef SIGBUS signal(SIGBUS, SIG_DFL); #endif #ifdef SIGLOST signal(SIGLOST, SIG_DFL); #endif #ifdef SIGPWR signal(SIGPWR, SIG_DFL); #endif #ifdef JP printf("\n%s is killed by some bugs....\n", JpVersion); #else printf("\n%s is killed by some bugs....\n", Version); #endif text = modname(Filename, ".sav"); if (writeit(text, NULL, (linenr_t)1, line_count, FALSE, FALSE, TRUE)) printf("\nThe current text is saved into %s.\n", text); else printf("\nI couldn't save the current text.\n"); if (core) kill(getpid(), SIGQUIT); else kill(getpid(), SIGKILL); } static void core_init() { signal(SIGQUIT, core_handler); signal(SIGHUP, hup_handler); signal(SIGTERM, hup_handler); signal(SIGSEGV, core_handler); #ifdef SIGILL signal(SIGILL, core_handler); #endif #ifdef SIGBUS signal(SIGBUS, core_handler); #endif #ifdef SIGLOST signal(SIGLOST, hup_handler); #endif #ifdef SIGPWR signal(SIGPWR, hup_handler); #endif } #endif /* UNIX && !GENERAL */ #ifdef JP #ifndef GENERAL void jp_init() { JP_FCODE = JP_NEW; #if defined(UNIX) && !defined(GENERAL) core_init(); #endif } #endif /* !GENERAL */ /* * convert EUC letter into suitable letter. */ void kanjito(k1, k2, code) u_char *k1, *k2; char code; { u_char c1, c2; switch(code) { case JP_NJIS: case JP_JIS: *k1 &= 0x7f; *k2 &= 0x7f; return; case JP_SJIS: c1 = *k1 & 0x7f; c2 = *k2 & 0x7f; *k1 = (((int)c1 - 1) >> 1) + ((c1 <= 0x5e) ? 0x71 : 0xb1); *k2 = c2 + ((c1 & 1) ? ((c2 < 0x60) ? 0x1f : 0x20) : 0x7e); return; default: return; } } /* * return kanji shift-in string */ char * kanjiin(code) char code; { switch(code) { case JP_NJIS: return "\033$B"; case JP_JIS: return "\033$@"; default: return ""; } } /* * return kanji shift-out string */ char * kanjiout(code) char code; { switch(code) { case JP_NJIS: return "\033(B"; case JP_JIS: return "\033(J"; default: return ""; } } /* * convert buffer to EUC code */ static int jis, euc, njis, sjis; static int knj_asc; static int jis0201r; #define IsJIS0201r(c) ((u_char)(c) >= 0xa0 && (u_char)(c) <= 0xdf) void reset_jcount() { jis = euc = njis = sjis = knj_asc = jis0201r = 0; } #if defined(JPFEP) || defined(FEPCTRL) char* guess_jiauto(ji, th) char* ji; int th; { if (!th) return ji; if (knj_asc > th) return isupper(*ji) ? "J": "j"; if (knj_asc < - th) return isupper(*ji) ? "A": "a"; return ji; } #endif char judge_jcode(code) char code; { if (code == JP_ANY || code == JP_SANY) { char judge; if (!jis && !euc && !njis && !sjis) judge = JP_NONE; else if (njis) judge = JP_NJIS; else if (jis) judge = JP_JIS; else if (euc >= sjis) judge = JP_EUC; else judge = JP_SJIS; return judge; } else return code; } int num_jis0201r() { return jis0201r; } static void sjis2euc(ptr) char *ptr; { int i, j; i = (u_char) *ptr; j = (u_char) *(ptr + 1); i = (i * 2) - ((i <= 0x9f)? 0xe1 : 0x161); if (j < 0x9f) j -= ((j > 0x7f) ? 0x20 : 0x1f); else { i ++; j -= 0x7e; } *ptr++ = i | 0x80; *ptr = j | 0x80; } #define CHARSET_ASCII FALSE /* or JISX0201 Left hand set */ #define CHARSET_JISX0208 1 #define CHARSET_JISX0201R 2 int /* return the length of dst */ kanjiconvsfrom(ptr, ptrlen, dst, dstlen, tail, code, charsetp) char *ptr; int ptrlen; char *dst; int dstlen; char *tail; char code; int *charsetp; { char *top, *dtop; u_char c; #ifndef GENERAL int firstchar = FALSE; #endif int charset; charset = charsetp ? *charsetp : CHARSET_ASCII; top = ptr; dtop = dst; if (tail) tail[0] = NUL; switch(code) { case JP_NONE: while(ptrlen) { c = *ptr; if (!IsKanji(c) || (c & 0x60)) { /* if not Function key */ c &= 0x7f; if (*ptr > ' ') knj_asc --; } ptr ++; *dst ++ = c; ptrlen --; if (dst - dtop >= dstlen) return -1; } return dst - dtop; case JP_EUC: while(ptrlen) { if (dst - dtop >= dstlen) return -1; ptrlen --; if (IsKanji(c = *dst ++ = *ptr ++)) { if (! (c & 0x60)) /* if Function key */ continue; if (c == 0xff) /* if NT Function key */ continue; if (IsKanji(*ptr)) { /* JIS0208 char. */ knj_asc ++; *dst ++ = *ptr ++; ptrlen --; continue; } if (tail && ptrlen == 0) { /* not completed */ tail[0] = c; tail[1] = NUL; dst --; continue; } else { /* Illegal char */ *(dst - 1) &= 0x7f; continue; } } else if (c > ' ') /* ASCII char */ knj_asc --; } return dst - dtop; case JP_SJIS: while(ptrlen) { if (dst - dtop >= dstlen) return -1; ptrlen --; c = *dst ++ = *ptr ++; if (IsKanji(c)) { if (IsJIS0201r(c)) { /* JIS X 0201R 8bit encoding */ char c1; if (jisx0201rto0208(c, ptrlen ? *ptr : NUL, dst - 1, &c1)) { /* 2 characters -> double byte character. */ * dst++ = c1; ptr ++; ptrlen --; } else if (c1) /* 1 character -> double byte character. */ * dst++ = c1; /* else 1 character -> single byte character. */ jis0201r ++; continue; } if (ptrlen == 0) { /* not completed */ if (tail) { tail[0] = c; tail[1] = NUL; dst --; } else *(dst - 1) &= 0x7f; continue; } if (c == 0xff) /* if NT Function key */ continue; else { /* SJIS character */ * dst++ = * ptr++; ptrlen --; knj_asc ++; sjis2euc(dst - 2); continue; } } else if (c > ' ') knj_asc --; } return dst - dtop; case JP_NJIS: case JP_JIS: case JP_ANY: case JP_SANY: while(ptrlen) { if (dst - dtop >= dstlen) return -1; ptrlen --; c = *dst ++ = *ptr ++; if (IsKanji(c)) { #ifndef GENERAL /* check Function key */ if (!p_jse && code != JP_SJIS && code != JP_SANY) { if (!(c & 0x60)) continue; } else { if (firstchar ++ && !(c & 0x60) && !*ptr) continue; } if (c == 0xff) /* if NT Function key */ continue; #endif if (ptrlen == 0) { /* not completed */ if (tail) { tail[0] = c; tail[1] = NUL; dst --; } else *(dst - 1) &= 0x7f; continue; } if ( (code == JP_SANY || code == JP_NJIS || code == JP_JIS) && IsJIS0201r(c)) { /* JIS X 0201R 8bit encoding */ char c1; if (jisx0201rto0208(c, ptrlen ? *ptr : NUL, dst - 1, &c1)) { /* 2 characters -> double byte character. */ * dst++ = c1; ptr ++; ptrlen --; } else if (c1) /* 1 character -> double byte character. */ * dst++ = c1; /* else 1 character -> single byte character. */ jis0201r ++; continue; } * dst++ = * ptr++; switch(code) { case JP_SANY: if (c < 0xa0 || c >= 0xe0) { sjis ++; sjis2euc(dst - 2); } else euc ++; goto s_or_e; case JP_ANY: if (c < 0xa0) { sjis ++; sjis2euc(dst - 2); } else euc ++; s_or_e: ptrlen --; knj_asc ++; break; default: dst --; ptr --; *(dst - 1) &= 0x7f; } continue; } if (c == ESC) { dst --; if (ptrlen == 0) { if (tail) { tail[0] = c; tail[1] = NUL; } else dst++; continue; } if (*ptr == '(') { ptrlen --; ptr ++; if (ptrlen == 0) { if (tail) { tail[0] = c; tail[1] = '('; tail[2] = NUL; } else { dst ++; * dst++ = '('; } continue; } if (*ptr == 'I') { /* JIS X 0201R ISO2022 encoding */ charset = CHARSET_JISX0201R; ptr ++; ptrlen --; continue; } else if (*ptr == 'J' || *ptr == 'H' || *ptr == 'B' || code == JP_ANY) /* ASCII/JIS In */ { charset = CHARSET_ASCII; ptr ++; ptrlen --; continue; } else { dst ++; * dst++ = '('; continue; } } if (*ptr == '$') { ptrlen --; ptr ++; if (ptrlen == 0) { if (tail) { tail[0] = c; tail[1] = '$'; tail[2] = NUL; } else { dst ++; * dst++ = '$'; } continue; } if (*ptr == '@' || *ptr == 'B' || code == JP_ANY) /* Kanji In */ { if (*ptr == '@') jis++; else if (*ptr == 'B') njis++; charset = CHARSET_JISX0208; ptrlen --; ptr ++; continue; } else { dst ++; * dst ++ = '$'; continue; } } else dst++; } switch(charset) { case CHARSET_ASCII: if (c > ' ') knj_asc --; break; case CHARSET_JISX0201R: if (IsJIS0201r(c | 0x80)) { /* This code is not examined. ann */ char c0, c1; c0 = ptrlen ? *ptr : NUL; if (! IsJIS0201r(c0 | 0x80)) c0 |= 0x80; if (jisx0201rto0208(c | 0x80, c0, dst - 1, &c1)) { /* 2 characters -> double byte character. */ * dst++ = c1; ptr ++; ptrlen --; } else if (c1) /* 1 character -> double byte character. */ * dst++ = c1; /* else 1 character -> single byte character. */ jis0201r ++; } else if (c == NUL || c =='\n' || c == '\r') charset = CHARSET_ASCII; break; default: /* CHARSET_JISX0208 */ if (ptrlen == 0) { if (tail) { tail[0] = c; tail[1] = NUL; dst --; } } else if (c > ' ' && *ptr > ' ') { ptrlen --; *(dst - 1) |= 0x80; * dst++ = * ptr++ | 0x80; knj_asc ++; } else if (c == NUL || c == '\n' || c == '\r') charset = CHARSET_ASCII; } } if (charsetp) *charsetp = charset; return dst - dtop; } return dst - dtop; } /* * convert buffer from EUC code */ #ifdef GENERAL # define alloc_line(x) malloc(x) #endif #ifndef GENERAL void kanjiconvto(lnum, lend, code) linenr_t lnum, lend; char code; { char *ptr, *new; for(; lnum <= lend; ++lnum) { ptr = nr2ptr(lnum); new = kanjiconvsto(ptr, code); if (new != ptr) free_line(replaceline(lnum, new)); } } #endif /* !GENERAL */ char * kanjiconvsto(ptr, code) char *ptr; char code; { char *top, *ptr2; char *kin, *kout, *cp; int kanji, nshift, nchar; top = ptr; switch(code) { case JP_EUC: return top; case JP_NONE: top = ptr2 = alloc_line(strlen(ptr)); while(*ptr) *ptr2 ++ = *ptr ++ & ~0x80; *ptr2 = NUL; return top; case JP_SJIS: top = ptr2 = alloc_line(strlen(ptr)); while(*ptr) if (IsKanji(*ptr2++ = *ptr++)) { *ptr2 ++ = *ptr ++; kanjito(ptr2 - 2, ptr2 - 1, code); } *ptr2 = NUL; return top; case JP_NJIS: case JP_JIS: case JP_ANY: kin = kanjiin(code); kout = kanjiout(code); kanji = 0; for(nshift = 0; *ptr; ptr++) { if (kanji != (*ptr & 0x80)) { nshift++; kanji ^= 0x80; } } if (kanji) nshift++; nchar = ptr - top; if (!nshift) return top; ptr = top; top = ptr2 = alloc_line(nchar + nshift * 3); kanji = 0; while(*ptr) { if (kanji != (*ptr & 0x80)) { if (kanji) for(cp = kout; *cp;) *ptr2++ = *cp++; else for(cp = kin; *cp;) *ptr2++ = *cp++; kanji ^= 0x80; } *ptr2++ = (*ptr++ & 0x7f); } if (kanji) for(cp = kout; *cp;) *ptr2++ = *cp++; *ptr2 = 0; return top; } return top; } #ifndef GENERAL void kanji_align() { int col; char *line; line = nr2ptr(Curpos.lnum); for(col = 0; col < Curpos.col; line++, col++) if (IsKanji(*line)) { line ++; col ++; } Curpos.col = col; } #endif /* !GENERAL */ /* * Japanese Character class; * Make sure this routine is consistent with search.c:cls(). * * for Japanese * 3 - alphabet, digits * 4 - japanese hiragana * 5 - japanese katakana * 6 - symbols * 7 - other multi-char letter */ int jpcls(c, k) char c, k; { if (c == ' ' || c == '\t' || c == NUL) return 0; if (IsKanji(c)) { int ret; return (ret = jptab[c & 0x7f].cls1) == JPC_KIGOU ? jptab[k & 0x7f].cls2 : ret; } #ifdef GENERAL # ifdef __STDC__ if (isalnum(c) || c == '_') # else if (isalpha(c) || isdigit(c) || c == '_') # endif #else if (isidchar(c)) #endif return 1; return -1; } /* * isjppunc(c, k) returns whether a kanji character ck necessary KINSOKU * processing or not. */ int isjppunc(c, k, type) char c, k; int type; { k &= 0x7f; switch(jptab[(int)c & 0x7f].cls1) { case JPC_KIGOU: return type ? jptab[(int)k].punccsym : jptab[(int)k].puncosym; case JPC_HIRA: case JPC_KATA: return type ? jptab[(int)k].puncckana : FALSE; default: return FALSE; } } /* * isaspunc(c, type) returns whether an ascii character ck necessary KINSOKU * processing or not. */ int isaspunc(c, type) char c; int type; { return(type ? jptab[(int)c].punccasc: jptab[(int)c].puncoasc); } /* * isjsend(*cp) returns whether a JIS character *cp separates * sentences or not. */ int isjsend(cp) u_char *cp; { return *cp == (0x80 | '!') && jptab[*(cp + 1) & 0x7f].stcend; } /* * jptocase(&c, &k, tocase) * modify c & k to case tocase * tocase == UPPER : to upper * tocase == LOWER : to lower * tocase == others : swap case */ void jptocase(cp, kp, tocase) u_char *cp, *kp; int tocase; { u_char k; k = *kp & 0x7f; switch(jptab[*cp & 0x7f].cls1) { case JPC_ALNUM: if (tocase != LOWER && islower(k)) *kp = TO_UPPER(k) | 0x80; if (tocase != UPPER && isupper(k)) *kp = TO_LOWER(k) | 0x80; return; case JPC_KIGOU: if ( (tocase != LOWER && jptab[k].scase == JLOS) || (tocase != UPPER && jptab[k].scase == JUPS) ) *kp = jptab[k].swap; return; case JPC_KATA: if (tocase != -1) *cp = JP1_HIRA | 0x80; return; case JPC_HIRA: if (tocase != 1) *cp = JP1_KATA | 0x80; return; default: return; } } /* * JIS X 0201 Right hand set(hankaku kana) <-> JIS X 0208(zenkaku) * */ static int jisx0201rto0208(src0, src1, dst0, dst1) char src0, src1, *dst0, *dst1; { u_char c, y; u_char *x0201p, z; int conv; c = (u_char) src0; x0201p = (u_char*)jisx0201r + 2 * (c - 0xa0); if (! IsKanji(y = *x0201p)) { *dst0 = y; *dst1 = NUL; return 0; } z = *(x0201p + 1); conv = FALSE; if ((u_char)src1 == 0xdf && /* maru */ (c >= 0xca && c <= 0xce)) /* ha - ho */ { z += 2; conv = TRUE; } else if ((u_char)src1 == 0xde) /* dakuten */ { conv = TRUE; if ( (c >= 0xb6 && c <= 0xc4) /* ka - to */ || (c >= 0xca && c <= 0xce) ) /* ha - ho */ z ++; else if (c == 0xb3) /* u -> vu*/ z = 0xf4; else conv = FALSE; } *dst0 = y; *dst1 = z; return conv ? 1 : 0; } #endif /* JP */ #ifdef GENERAL /* * The following codes are copied from alloc.c for jcat.c and jfold.c */ # ifdef BSD_UNIX char * bsdmemset(ptr, c, size) char *ptr; int c; long size; { register char *p = ptr; while (size-- > 0) *p++ = c; return ptr; } # endif # ifdef MEMMOVE /* * Version of memmove that handles overlapping source and destination. * For systems that don't have a function that is guaranteed to do that (SYSV). */ void * memmove(desti, source, len) void *source, *desti; #ifdef __sgi size_t len; #else int len; #endif { char *src = (char *)source; char *dst = (char *)desti; if (dst > src && dst < src + len) /* overlap, copy backwards */ { src +=len; dst +=len; while (len--) *--dst = *--src; } else /* copy forwards */ while (len--) *dst++ = *src++; return desti; } # endif #endif