/* * variable.c 変数管理 * * Copyright (C) 1997-1998 Masaki Chikama (Wren) * 1998- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* $Id: variable.c,v 1.15 2002/09/18 13:16:22 chikama Exp $ */ #include #include #include #include "portab.h" #include "utfsjis.h" #include "variable.h" #include "xsystem35.h" // For some reasons, System3.9's initial system page size is 65537. #define SYSVAR_MAX 65537 #define STRVAR_MAX 5000 #define SYSVARLONG_MAX 128 #define PAGE_MAX 256 typedef struct { int *pointvar; int page; int offset; } VariableAttributes; /* システム変数 */ int sysVar[SYSVAR_MAX]; /* 配列変数の情報 */ static VariableAttributes attributes[SYSVAR_MAX]; /* 配列本体 */ struct VarPage varPage[PAGE_MAX]; /* 64bit変数 */ double longVar[SYSVARLONG_MAX]; /* 文字列変数 */ static char **strVar; static int strvar_cnt; const char *v_name(int var) { if (var < nact->ain.varnum) return nact->ain.var[var]; static char buf[10]; sprintf(buf, "VAR%d", var); return buf; } static char *advance(const char *s, int n) { while (*s && n > 0) { s = advance_char(s, nact->encoding); n--; } return (char *)s; } int *v_ref_indexed(int var, int index, struct VarRef *ref) { VariableAttributes *attr = &attributes[var]; int page = attr->page; if (page == 0) { if (index < 0) index = 0; // If VAR_n is not an array variable, VAR_n[i] points to VAR_(n+i). index += var; if (ref) { ref->var = var; ref->page = page; ref->index = index; } if (index >= SYSVAR_MAX) return NULL; return sysVar + index; } if (index < 0) // Implicit array access index = *attr->pointvar; index += attr->offset; if (ref) { ref->var = var; ref->page = page; ref->index = index; } if (index >= varPage[page].size) return NULL; return varPage[page].value + index; } // DC command bool v_allocatePage(int page, int size, bool saveflag) { if (page < 0 || page >= PAGE_MAX) { return false; } if (size <= 0 || size > 65536) { return false; } if (page != 0) { void *buf = varPage[page].value; if (buf != NULL) buf = realloc(buf, size * sizeof(int)); else buf = calloc(size, sizeof(int)); if (!buf) NOMEMERR(); varPage[page].value = buf; } varPage[page].size = size; varPage[page].saveflag = saveflag; return true; } // DS command bool v_bindArray(int datavar, int *pointvar, int offset, int page) { if (datavar < 0 || datavar >= SYSVAR_MAX) { return false; } if (page <= 0 || page >= PAGE_MAX) { return false; } if (offset < 0 || offset >= varPage[page].size) { return false; } attributes[datavar].pointvar = pointvar; attributes[datavar].page = page; attributes[datavar].offset = offset; return true; } // DR command bool v_unbindArray(int datavar) { attributes[datavar].page = 0; return true; } // DI command void v_getPageStatus(int page, int *in_use, int *size) { if (page == 0) { *in_use = false; *size = 1; // why... } else if (page >= PAGE_MAX) { *in_use = false; *size = 0; } else { *in_use = varPage[page].value != NULL; *size = varPage[page].size & 0xffff; } } /* 文字列変数の再初期化 */ void svar_init(int max_index) { for (int i = max_index + 1; i < strvar_cnt; i++) { if (strVar[i]) free(strVar[i]); } strVar = realloc(strVar, (max_index + 1) * sizeof(char *)); if (strVar == NULL) { NOMEMERR(); } for (int i = strvar_cnt; i <= max_index; i++) strVar[i] = NULL; strvar_cnt = max_index + 1; } int svar_maxindex(void) { return strvar_cnt - 1; } /* 変数の初期化 */ void v_init(void) { varPage[0].value = sysVar; varPage[0].size = SYSVAR_MAX; varPage[0].saveflag = true; svar_init(STRVAR_MAX - 1); } void v_reset(void) { memset(sysVar, 0, sizeof(sysVar)); memset(attributes, 0, sizeof(attributes)); memset(longVar, 0, sizeof(longVar)); for (int i = 1; i < PAGE_MAX; i++) { if (varPage[i].value) free(varPage[i].value); } memset(varPage, 0, sizeof(varPage)); for (int i = 0; i < strvar_cnt; i++) { if (strVar[i]) { free(strVar[i]); strVar[i] = NULL; } } v_init(); } /* 文字変数への代入 */ void svar_set(int no, const char *str) { if ((unsigned)no >= strvar_cnt) { WARNING("string index out of range: %d", no); return; } if (strVar[no]) free(strVar[no]); strVar[no] = strdup(str); } void svar_copy(int dstno, int dstpos, int srcno, int srcpos, int len) { if ((unsigned)dstno >= strvar_cnt) { WARNING("string index out of range: %d", dstno); return; } if (!strVar[dstno]) strVar[dstno] = strdup(""); char *buf = NULL; const char *src; if (srcno == dstno) src = buf = strdup(strVar[srcno]); else src = svar_get(srcno); dstpos = advance(strVar[dstno], dstpos) - strVar[dstno]; // #chars -> #bytes src = advance(src, srcpos); len = advance(src, len) - src; // #chars -> #bytes strVar[dstno] = realloc(strVar[dstno], dstpos + len + 1); strncpy(strVar[dstno] + dstpos, src, len); strVar[dstno][dstpos + len] = '\0'; if (buf) free(buf); } /* 文字変数への接続 */ void svar_append(int no, const char *str) { if ((unsigned)no >= strvar_cnt) { WARNING("string index out of range: %d", no); return; } if (!strVar[no]) { strVar[no] = strdup(str); return; } int len1 = strlen(strVar[no]); int len2 = strlen(str); strVar[no] = realloc(strVar[no], len1 + len2 + 1); strcpy(strVar[no] + len1, str); } /* 文字変数の長さ */ size_t svar_length(int no) { const char *s = svar_get(no); int c = 0; while (*s) { s = advance_char(s, nact->encoding); c++; } return c; } /* Width of a string (2 for full-width characters, 1 for half-width) */ int svar_width(int no) { return strlen(svar_get(no)); } /* 文字変数そのもの */ const char *svar_get(int no) { if ((unsigned)no >= strvar_cnt) { WARNING("string index out of range: %d", no); return ""; } return strVar[no] ? strVar[no] : ""; } int svar_find(int no, int start, const char *str) { if ((unsigned)no >= strvar_cnt) { WARNING("string index out of range: %d", no); return -1; } if (!*str) return 0; if (!strVar[no]) return -1; const char *p = advance(strVar[no], start); const char *found = strstr(p, str); if (!found) return -1; int n = 0; while (p < found) { p = advance_char(p, nact->encoding); n++; } return n; } void svar_fromVars(int no, const int *vars) { if ((unsigned)no >= strvar_cnt) { WARNING("string index out of range: %d", no); return; } int len = 0; for (const int *c = vars; *c; c++) len += (*c < 256) ? 1 : 2; if (strVar[no]) free(strVar[no]); char *p = strVar[no] = malloc(len + 1); for (const int *v = vars; *v; v++) { if (*v < 256) { *p++ = *v; } else { *p++ = *v & 0xff; *p++ = *v >> 8; } } *p = '\0'; } int svar_toVars(int no, int *vars) { if ((unsigned)no >= strvar_cnt) { WARNING("string index out of range: %d", no); return 0; } if (!strVar[no]) { *vars = 0; return 1; } int count = 0; for (const char *p = strVar[no]; *p; p++, count++) { vars[count] = *p & 0xff; if (CHECKSJIS1BYTE(*p) && *(p + 1)) vars[count] |= (*++p & 0xff) << 8; } vars[count++] = 0; return count; } int svar_getCharType(int no, int pos) { const char *p = svar_get(no); for (; *p && pos > 0; pos--) p += CHECKSJIS1BYTE(*p) ? 2 : 1; if (!*p) return 0; return CHECKSJIS1BYTE(*p) ? 2 : 1; } void svar_replaceAll(int no, int pattern, int replacement) { const char *pat = svar_get(pattern); if (!*pat) return; const char *repl = svar_get(replacement); if ((unsigned)no >= strvar_cnt) { WARNING("string index out of range: %d", no); return; } if (!strVar[no]) return; char *src = strVar[no]; strVar[no] = NULL; char *start = src, *found;; while ((found = strstr(start, pat))) { char bak = *found; *found = '\0'; svar_append(no, start); *found = bak; svar_append(no, repl); start = found + strlen(pat); } svar_append(no, start); free(src); }