home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1996 February
/
VPR9602A.ISO
/
fwindows
/
tmedt090
/
toold101
/
cwtools.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-19
|
278KB
|
10,107 lines
#include <windows.h>
#include "comwin.h"
/*-----------*/
/* xargs API */
/*-----------*/
char ** FAR PASCAL CreateArgs(char *);
BOOL FAR PASCAL DeleteArgs(char **);
LONG FAR PASCAL cwFprintf(LPSTR, LPSTR, ...);
/*--------------*/
/* 外部変数関係 */
/*--------------*/
BOOL CreateGlobal(void);
BOOL DeleteGlobal(void);
/*----------------*/
/* 内部コマンド群 */
/*----------------*/
int cal_main(int argc, char **argv);
int cat_main(int argc, char **argv);
int chdir_main(int argc, char **argv);
int chmod_main(int argc, char **argv);
int cmp_main(int argc, char **argv);
int cp_main(int argc, char **argv);
int date_main(int argc, char **argv);
int df_main(int argc, char **argv);
int diff_main(int argc, char **argv);
int echo_main(int argc, char **argv);
int expand_main(int argc, char **argv);
int fold_main(int argc, char **argv);
int grep_main(int argc, char **argv);
int head_main(int argc, char **argv);
int join_main(int argc, char **argv);
int ls_main(int argc, char **argv);
int man_main(int argc, char **argv);
int mkdir_main(int argc, char **argv);
int mv_main(int argc, char **argv);
int od_main(int argc, char **argv);
int pwd_main(int argc, char **argv);
int rm_main(int argc, char **argv);
int rmdir_main(int argc, char **argv);
int sort_main(int argc, char **argv);
int split_main(int argc, char **argv);
int tail_main(int argc, char **argv);
int tee_main(int argc, char **argv);
int touch_main(int argc, char **argv);
int tr_main(int argc, char **argv);
int unexpand_main(int argc, char **argv);
int uniq_main(int argc, char **argv);
int wc_main(int argc, char **argv);
int which_main(int argc, char **argv);
/*------------------------------------------*/
/* CallCommand関数 (ワイルドカード展開あり) */
/*------------------------------------------*/
typedef struct CMDTABLE CMDTABLE;
struct CMDTABLE {
char *szCmd;
int (*pfnCmd)(int argc, char **argv);
};
LONG (FAR PASCAL *cwPuts)(LPSTR);
LPSTR (FAR PASCAL *cwGets)(LPSTR);
LONG (FAR PASCAL *cwFputs)(LPSTR, LPSTR);
LPSTR (FAR PASCAL *cwFgets)(LPSTR, LONG, LPSTR);
LONG (FAR PASCAL *cwSystem)(LPSTR);
BOOL (FAR PASCAL *cwCallConsole)(FARPROC FAR *, LPSTR, LPLONG);
LONG (FAR PASCAL *cwGetch)(void);
LONG (FAR PASCAL *cwInkey)(void);
/*----------------------*/
/* コンソール情報構造体 */
/*----------------------*/
CW_S_CONSOLE_INFO gConsoleInfo;
/*--------------------------------------*/
/* 関数へのポインタの配列の先頭アドレス */
/*--------------------------------------*/
FARPROC FAR *glpfnIO;
BOOL FAR PASCAL CallCommand(FARPROC FAR *lpfnIO,
LPSTR lpszCmdLine,
LPLONG lpReturn)
{
char szPath[MAX_PATH];
char *pszFile;
char *pszSpace;
int nRet;
char **wargv;
int wargc;
CMDTABLE *pCT;
static CMDTABLE cmdTable[] = {
{"cal", cal_main},
{"cat", cat_main},
{"chdir", chdir_main},
{"chmod", chmod_main},
{"cmp", cmp_main},
{"cp", cp_main},
{"date", date_main},
{"df", df_main},
{"diff", diff_main},
{"echo", echo_main},
{"expand", expand_main},
{"fold", fold_main},
{"grep", grep_main},
{"head", head_main},
{"join", join_main},
{"ls", ls_main},
{"man", man_main},
{"mkdir", mkdir_main},
{"mv", mv_main},
{"od", od_main},
{"pwd", pwd_main},
{"rm", rm_main},
{"rmdir", rmdir_main},
{"sort", sort_main},
{"split", split_main},
{"tail", tail_main},
{"tee", tee_main},
{"touch", touch_main},
{"tr", tr_main},
{"unexpand", unexpand_main},
{"uniq", uniq_main},
{"wc", wc_main},
{"which", which_main},
{NULL, NULL}
};
/*------------------------------*/
/* 関数へのポインタの配列を保存 */
/*------------------------------*/
glpfnIO = lpfnIO;
switch (*lpReturn) {
case CW_M_CONSOLE_INFO: {
LP_CW_S_CONSOLE_INFO lpci;
/*------------------------------*/
/* コンソール情報をチェックする */
/*------------------------------*/
lpci = (LP_CW_S_CONSOLE_INFO)lpReturn;
switch (lpci->lMode) {
case CW_MODE_GET:
return FALSE;
default:
memcpy(&gConsoleInfo, lpReturn, sizeof(gConsoleInfo));
return TRUE;
}
}
case CW_M_HELP: {
/*-------------------------------*/
/* ヘルプコマンド *lpReturn == 0 */
/*-------------------------------*/
if (*lpszCmdLine == '\0' && *lpReturn == 0) {
static int i = 0;
if (cmdTable[i].szCmd == NULL) {
i = 0;
return FALSE;
}
lstrcpyn(lpszCmdLine, cmdTable[i].szCmd, 80); i++;
return TRUE;
}
}
}
/*---------------------------------------*/
/* コマンド要求のチェック *lReturn == -1 */
/*---------------------------------------*/
if (*lpReturn != CW_M_EXEC) return FALSE;
/*------------------------*/
/* モジュール名を取得する */
/*------------------------*/
lstrcpy(szPath, lpszCmdLine);
pszFile = szPath;
pszSpace = strchr(pszFile, ' ');
if (pszSpace != NULL) *pszSpace = '\0';
/*----------------------------*/
/* サポートコマンドのチェック */
/*----------------------------*/
if (*pszFile == '\0') return FALSE;
for (pCT = cmdTable; pCT->szCmd != NULL &&
lstrcmpi(pCT->szCmd, pszFile) != 0; pCT++);
if (pCT->szCmd == NULL) return FALSE;
/*--------------------------*/
/* 関数ポインタを実体化する */
/*--------------------------*/
(FARPROC)cwPuts = lpfnIO[0];
(FARPROC)cwGets = lpfnIO[1];
(FARPROC)cwFputs = lpfnIO[2];
(FARPROC)cwFgets = lpfnIO[3];
(FARPROC)cwSystem = lpfnIO[4];
(FARPROC)cwCallConsole = lpfnIO[5];
(FARPROC)cwGetch = lpfnIO[6];
(FARPROC)cwInkey = lpfnIO[7];
/*--------------------*/
/* ワイルドカード展開 */
/*--------------------*/
wargv = CreateArgs(lpszCmdLine);
for (wargc = 0; wargv[wargc][0] != '\0'; wargc++);
/*--------------------------------*/
/* アプリケーションのメインを呼ぶ */
/*--------------------------------*/
CreateGlobal();
nRet = pCT->pfnCmd(wargc, wargv);
DeleteGlobal();
/*----------*/
/* 終了処理 */
/*----------*/
DeleteArgs(wargv);
*lpReturn = nRet;
return TRUE;
}
/*--------------*/
/* 各種コマンド */
/*--------------*/
#include <ctype.h>
#include <direct.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/stat.h>
int errno;
/*--------*/
/* マクロ */
/*--------*/
#define gg (*GetGlobal())
#define _puterrmes(s) cwFputs((s), (LPSTR)-1)
#define iskanji(c) IsDBCSLeadByte((BYTE)(c))
#define PD '\\'
#define ESCAPE '^'
#define isoctal(c) (isdigit(c) && (c) < '9')
#define is_octal(c) (isascii(c) && isoctal(c))
#define XBUFSIZ 8192
#define is_alpha(c) (isascii(c) && isalpha(c))
#define is_lower(c) (isascii(c) && islower(c))
#define is_upper(c) (isascii(c) && isupper(c))
#define to_lower(c) (is_upper(c) ? tolower(c) : (c))
#define to_upper(c) (is_lower(c) ? toupper(c) : (c))
#define TBUFSIZ 160
#define GET_DRIVE(c) c - (c >= 'a' ? 'a' - 1 : 'A' - 1)
#define is_digit(c) (isascii(c) && isdigit(c))
#define KSPC 0x8140
#define COLLISTMAX 512
#define is_space(c) (isascii(c) && isspace(c))
#define LINMAX 1024
#define LBUFSIZ 8192
#define RBUFSIZ 32768
#define ctoi(c) ((c) - ((c) <= '9' ? '0' : (c) >= 'a' ? 'a' - 10 : 'A' - 10))
#define is_xdigit(c) (isascii(c) && isxdigit(c))
#define OPT_FORCE 01
#define OPT_BINARY 02
#define OPT_VISUAL 04
#define imax(x, y) ((x) > (y) ? (x) : (y))
#define imin(x, y) ((x) < (y) ? (x) : (y))
#define CBUFSIZ 8192
#define iskanji2(c) (0x40 <= (c) && (c) <= 0xFC && (c) != 0x7F)
#define YES_OR_NO_P yn_p_with_ret /* ←y/nで答えるときリターン要 */
#define True 1
#define MAXLEN 1024
#define BIGBUFSIZ 32767 /* MAX available size in setvbuf() is 32767 */
#define BUFFERSIZE (unsigned int)(8192*4)
#define opt_all 1
#define LINMAX 1024
#define fieldnext(p) fieldtop(fieldend(p))
#define IS_DIRECTORY(x) (x & 0x10)
#define IS_READONLY(x) (x!=(unsigned)-1 && (x & 1))
#define BUFFER_SIZE 1024 /* Maximum length of an input line */
#define BLOCK_SIZE 1024
#define free_buffer(l) free(l->buf),free(l)
#define DIRFCMP
#define IO_SUCCESS 0
#define IO_ERROR 1
#define EOS '\0'
#define TEMPFILE (gg.temfile!=NULL ? gg.temfile : (gg.temfile=difftmpnam()))
#define TRUE 1
#define FALSE 0
#define fileA gg.file[0]
#define fileB gg.file[1]
#define sfileA gg.sfile[0]
#define sfileB gg.sfile[1]
#define lenA gg.len[0]
#define lenB gg.len[1]
#define slenA gg.slen[0]
#define slenB gg.slen[1]
#define CSIZE_INC 50 /* How many to allocate each time we have to */
#define fname argv
#define isstdin(fnm) (fnm[0] == '-' && fnm[1] == EOS)
#define isdelim(c) ((c) == '\\' || (c) == '/' || (c) == ':')
#define true 1
#define false 0
#define DEV_MASK 0x40
#define ARC_MASK 0x20 /* Archive */
#define DIR_MASK 0x10 /* Directory */
#define VOL_MASK 0x08 /* Volume */
#define SYS_MASK 0x04 /* System file */
#define INV_MASK 0x02 /* Invisible */
#define RDO_MASK 0x01 /* Read only */
#define LINMAX 1024
#define L_1ST 400
#define L_INC 200
#define umin(x, y) ((x) < (y) ? (x) : (y))
#define spcpass(p) {while(is_space(*p)) p++;}
#define nonspcpass(p) {while(!is_space(*p)){if(!*p) break; else p++;}}
#define fieldpass(p) fieldcharpass(&p)
#define ncharpass(p, n) {unsigned int _n; \
for(_n = n; _n; _n--){if(!*p) break; p++;}}
#define OCTDUMP 1 /* o */
#define DECDUMP 2 /* d */
#define SGNDECDUMP 4 /* s */
#define HEXDUMP 8 /* x */
#define CHARDUMP 16 /* c */
#define EUCDUMP 32 /* C */
#define SJISDUMP 64 /* S */
#define BYTEDUMP 128 /* b */
#define BITMAPOUT 256 /* m */ /* no h,i,l,f */
#define STRINGOUT 512 /* t */
#define NOADDR 0
#define OCTADDR 1
#define DECADDR 2
#define HEXADDR 3
#define ASCIISTR 0
#define EUCSTR 1
#define SJISSTR 2
#define OBUFSIZ 1024
#define MAXDISPUNIT 2
/* longやdoubleでの表示などを将来付け加えるなら増やす。2^nであること */
#define EUCCONT 1
#define SJISCONT 2
#define issjiskana(c) \
(0xa1 <= (c) && (c) <= 0xdf)
#define issjis1(c) \
(0x81 <= (c) && (c) <= 0x9f || 0xe0 <= (c) && (c) <= 0xfc)
#define issjis2(c) \
(0x40 <= (c) && (c) <= 0xfc && 0x7f != (c))
#define iseuc(c) \
(0xa1 <= (c) && (c) <= 0xfe)
#define isSS2(c) \
(0x8e == (c))
#define PATHNAMELENGTH 1024
/*--------*/
/* 構造体 */
/*--------*/
typedef unsigned long ulong;
typedef unsigned char uchar;
typedef unsigned int uint;
struct charstock {
char *buf;
unsigned int bufsiz;
unsigned int bufpos;
};
struct argchar {
uchar *arg;
int next;
int step;
uint count;
};
struct spinfo {
struct charstock sptabseq;
int pos, tabidx;
};
typedef unsigned long ulong;
typedef struct {
char fno; /* 0 or 1 */
int field;
} outfieldstr;
typedef struct line_buffer {
struct line_buffer *link; /* Link to the next line. */
int len; /* Length of the line. */
char *buf; /* Line. */
} line_buffer;
typedef struct candidate {
int b; /* Line in fileB */
int a; /* Line in fileA */
int link; /* Previous candidate */
} CANDIDATE;
typedef struct line {
unsigned short hash; /* Hash value etc. */
short serial; /* Line number */
} DIFF_LINE;
typedef int bool;
typedef union dosdate {
struct {
struct {
unsigned day:5;
unsigned month:4;
unsigned year:7;
} bh;
struct {
unsigned sec2:5;
unsigned minute:6;
unsigned hour:5;
} bl;
} b;
struct {
unsigned short d;
unsigned short t;
} dt;
} dosdate;
typedef struct diff_file {
struct diff_file *next;
char *name;
int attr;
dosdate date;
off_t size;
} diff_file;
typedef struct dirfile {
struct dirfile *next;
char *fullname;
} dirfile;
typedef struct {
unsigned int numsort : 1;
unsigned int pblankign : 1;
unsigned int mblankign : 1;
unsigned int reverse : 1;
unsigned int foldcase : 1;
/* 以下2つはglobal専用 */
unsigned int usegopt : 1;
unsigned int donormcmp : 1;
} optstr;
typedef struct {
unsigned int beginf, beginc; /* -1を無限大扱いするためunsigned */
unsigned int endf, endc;
optstr opt;
} parmstr;
/* 'u'追加時はEUC1bytekana注意 */ /* 順序変更? */
typedef unsigned char us_char;
typedef unsigned short us_short;
typedef unsigned int us_int;
typedef unsigned long us_long;
struct infile {
FILE *f;
us_long curpos, curline;
};
enum { /* Mode for search */
from_head, /* `+' option */
from_tail, /* `-' option */
tail_reverse /* `+r' or `-r' option */
};
enum { /* Unit of count */
LINE, /* `[+-]l' option */
CHARACTER, /* `[+-]c' option */
BLOCK /* `[+-]b' option */
};
struct bufstr {
us_char *buf;
us_int buflen, pos; /* for undump */
int contmode;
};
struct tagTXTBUF {
us_char *buf;
us_int buflen, pos;
us_long filepos;
int tcontmode; /* boolean */
};
struct tagSORTTMPF {
FILE *f;
char *name;
int dirlen;
};
/*----------*/
/* 外部変数 */
/*----------*/
char ERR_MEMORY[] = "Memory exhausted\n";
char *fmt = "%-15s %7ld %7ld %*ld %5ld%% %7ld %s\n";
char strnul[ ] = "";
char *eofmsg = "cmp: EOF on %s\n";
char *monthname[] = {
NULL,
"January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December",
};
char dofw_title[ ] = " S M Tu W Th F S";
char *dofwkname[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday",
};
char *month_name = "???JanFebMarAprMayJunJulAugSepOctNovDec";
char STRNULL[] = "";
#if 0 /* old grobal variant */
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int width = 80;
int nodisp = 0;
int current_drive, old_drive;
int tabcol = 8;
int tabcols[COLLISTMAX];
int addsp = 0, eofnl = 0, kspc = 0; /* boolean */
int ignf = 0, ignc = 0;
char outlcnt = 0, outdup = 0, outndup = 0;
unsigned int availunit = 1024;
char cmplmnt = 0, delete = 0, supdup = 0, treatz = 0;
char ibinary = 0, obinary = 0;
int cnvtbl[0x100], duptbl[0x100];
char print_line = 0, print_word = 0, print_char = 0;
long total_l = 0L, total_w = 0L, total_c = 0L;
static int found;
static int display_all, msdos_format;
static int error_code = 0;
static char *path_scanned;
extern int tabcol;
int tabcols[COLLISTMAX];
int elimsp = 0, unexpall = 0;
extern int kspc; /* boolean */
int vis = 0, num = 0, Num = 0, itxt = 0, otxt = 0;
int lasteol = 1;
long lineno = 0L;
char readbuf[CBUFSIZ];
int opt_recursive;
int opt_verbose;
int opt_interactive;
int opt_force;
int error_code;
int linesonly = 0, fnmdisp = -1, nocase = 0, fnmonly = 0, lnumdisp = 0,
retonly = 0, reverse = 0, wholematch = 0, wordmatch = 0;
int status = 1, totallcount = 0;
char *bigiobuf;
int opt_backup, opt_preserve, opt_update; /* initially 0 */
static char copybuf[BUFFERSIZE];
char addwidow = 0; /* 0, 1, 2, 3 */
char *emptyfill = "";
int joinfield[2] = {0, 0};
char fieldsep[2] = {'\0', '\0'};
outfieldstr *outlist = NULL;
int outlistlen = 0;
FILE *inf[2];
char *infnm[2];
char linbuf[2][LINMAX];
int force, verbose, interactive, backup, update; /* intially 0 */
static char current_disk;
/* Global variables */
int mode;
int unit;
unsigned tail_lineno;
int seek_block; /* The length of one block when seeking back the file */
char *temfile = NULL;
DIFF_LINE *file[2]; /* Hash/line for total file */
DIFF_LINE *sfile[2]; /* Hash/line after prefix */
int len[2]; /* Actual lines in each file */
int slen[2]; /* Squished lengths */
int prefix; /* Identical lines at start */
int suffix; /* Identical lenes at end */
FILE *infd[2] = {NULL, NULL}; /* Input file identifiers */
FILE *tempfd = NULL; /* Temp for input redirection */
short *class; /* Unsorted line numbers */
int *klist; /* Index of element in clist */
CANDIDATE far *clist; /* Storage pool for candidates */
int clength = 0; /* Number of active candidates */
int csize = CSIZE_INC; /* Current size of storage pool */
int *match; /* Longest subsequence */
long *oldseek; /* Seek position in file A */
short *member; /* Concatenated equiv. classes */
long *newseek; /* Seek position in file B */
char *textb; /* Input from file2 for check */
int eflag = FALSE; /* Edit script requested */
int bflag = FALSE; /* Blank supress requested */
int cflag = FALSE; /* Context printout */
int iflag = FALSE; /* Ignore case requested */
char text[257]; /* Input line from file1 */
diff_file *files = 0;
dirfile *dirs = 0;
char current_directory[PATHNAMELENGTH];
bool a_opt, d_opt, l_opt, s_opt, t_opt, x_opt, C_opt, F_opt, R_opt,
disp_dir;
bool X_opt, S_opt, Sort_by_ext_opt;
int r_opt, c_opt;
int filenum; /* Nide, from inside main() */
parmstr *sortparm; /* フィールド指定とそれへのオプション。
最初の1つはglobal optionだが、field optionへのコピーにも使用 */
int parmcnt = 1;
/* フィールド指定の個数。global optionがあるので最低1つ */
char **lines; /* 各行のデータ */
unsigned int linecnt = 0, linealloc;
/* できるだけオーバーフローを防ぐためunsigned */
char global_sep[2] = {'\0', '\0'};
/* '\0'はスペース扱い。区切り文字のみ2バイト対応。余りは'\0'で埋めること */
char *otfnm = NULL;
struct tagSORTTMPF sorttmpf[2];
int tmpfsw = 0;
int outmode = 0, addrmode = OCTADDR;
int /* boolean */ alldata = 0, endianrev = 0, hexcode = 0, undump = 0;
us_int bytelen = 0, bytelen1 = 0, stringslen = 0, stringskind = ASCIISTR;
us_int fieldw = 0, fieldb = 0, hsepwidth = 2 /* 1or2 */, sepwidth = 1;
char *bigbuf = NULL, *obigbuf = NULL;
struct bufstr usebuf[2];
struct tagTXTBUF txtbuf;
#endif
typedef struct GLOBAL GLOBAL, FAR *LPGLOBAL;
struct GLOBAL {
int opterr;
int optind;
int optopt;
char *optarg;
int width;
int nodisp;
int current_drive;
int old_drive;
int tabcol;
int tabcols[COLLISTMAX];
int addsp;
int eofnl;
int kspc;
int ignf;
int ignc;
char outlcnt;
char outdup;
char outndup;
unsigned int availunit;
char cmplmnt;
char delete;
char supdup;
char treatz;
char ibinary;
char obinary;
int cnvtbl[0x100];
int duptbl[0x100];
char print_line;
char print_word;
char print_char;
long total_l;
long total_w;
long total_c;
int found;
int display_all;
int msdos_format;
int error_code;
char *path_scanned;
int elimsp;
int unexpall;
int vis;
int num;
int Num;
int itxt;
int otxt;
int lasteol;
long lineno;
char readbuf[CBUFSIZ];
int opt_recursive;
int opt_verbose;
int opt_interactive;
int opt_force;
int linesonly;
int fnmdisp;
int nocase;
int fnmonly;
int lnumdisp;
int retonly;
int reverse;
int wholematch;
int wordmatch;
int status;
int totallcount;
char *bigiobuf;
int opt_backup;
int opt_preserve;
int opt_update;
char copybuf[BUFFERSIZE];
char addwidow; /* 0, 1, 2, 3 */
char *emptyfill;
int joinfield[2];
char fieldsep[2];
outfieldstr *outlist;
int outlistlen;
FILE *inf[2];
char *infnm[2];
char linbuf[2][LINMAX];
int force;
int verbose;
int interactive;
int backup;
int update;
char current_disk;
int mode;
int unit;
unsigned tail_lineno;
int seek_block; /* The length of one block when seeking back the file */
char *temfile;
DIFF_LINE *file[2]; /* Hash/line for total file */
DIFF_LINE *sfile[2]; /* Hash/line after prefix */
int len[2]; /* Actual lines in each file */
int slen[2]; /* Squished lengths */
int prefix; /* Identical lines at start */
int suffix; /* Identical lenes at end */
FILE *infd[2]; /* Input file identifiers */
FILE *tempfd; /* Temp for input redirection */
short *class; /* Unsorted line numbers */
int *klist; /* Index of element in clist */
CANDIDATE far *clist; /* Storage pool for candidates */
int clength; /* Number of active candidates */
int csize; /* Current size of storage pool */
int *match; /* Longest subsequence */
long *oldseek; /* Seek position in file A */
short *member; /* Concatenated equiv. classes */
long *newseek; /* Seek position in file B */
char *textb; /* Input from file2 for check */
int eflag; /* Edit script requested */
int bflag; /* Blank supress requested */
int cflag; /* Context printout */
int iflag; /* Ignore case requested */
char text[257]; /* Input line from file1 */
diff_file *files;
dirfile *dirs;
char current_directory[PATHNAMELENGTH];
bool a_opt;
bool d_opt;
bool l_opt;
bool s_opt;
bool t_opt;
bool x_opt;
bool C_opt;
bool F_opt;
bool R_opt;
bool disp_dir;
bool X_opt;
bool S_opt;
bool Sort_by_ext_opt;
int r_opt;
int c_opt;
int filenum; /* Nide, from inside main() */
parmstr *sortparm; /* フィールド指定とそれへのオプション。
最初の1つはglobal optionだが、field optionへのコピーにも使用 */
int parmcnt; /* フィールド指定の個数。global optionがあるので最低1つ */
char **lines; /* 各行のデータ */
unsigned int linecnt;
unsigned int linealloc; /* できるだけオーバーフローを防ぐためunsigned */
char global_sep[2]; /* '\0'はスペース扱い。区切り文字のみ2バイト対応。
余りは'\0'で埋めること */
char *otfnm;
struct tagSORTTMPF sorttmpf[2];
int tmpfsw;
int outmode;
int addrmode;
bool alldata;
bool endianrev;
bool hexcode;
bool undump;
us_int bytelen;
us_int bytelen1;
us_int stringslen;
us_int stringskind;
us_int fieldw;
us_int fieldb;
us_int hsepwidth /* 1or2 */;
us_int sepwidth;
char *bigbuf;
char *obigbuf;
struct bufstr usebuf[2];
struct tagTXTBUF txtbuf;
char s_converted[MAX_PATH];
char s_crtail[3];
char *s_curopt;
int s_pos;
char s_buf[TBUFSIZ];
char s_readbuf[RBUFSIZ];
char *s_readbuf2;
char s_buf2[100];
struct spinfo s_sppresv;
int s_first;
char s_base[PATHNAMELENGTH];
int s_flag;
char *s_buf1_0;
char *s_buf2_0;
char s_name[13];
int s_prev_sp;
char s_tmparg[4];
double s_a;
double s_b;
char *s_passbuf;
int screenwidth;
};
GLOBAL G;
BOOL CreateGlobal(void)
{
memset(&G, 0, sizeof(G));
G.opterr = 1;
G.optind = 1;
G.width = 80;
G.tabcol = 8;
G.availunit = 1024;
G.lasteol = 1;
G.fnmdisp = -1;
G.status = 1;
G.emptyfill = "";
G.csize = CSIZE_INC;
G.parmcnt = 1;
G.addrmode = OCTADDR;
G.stringskind = ASCIISTR;
G.hsepwidth = 2l;
G.sepwidth = 1;
G.s_crtail[1] = '\0';
G.s_first = 1;
G.s_base[0] = 'x';
G.s_flag = -1;
G.s_tmparg[1] = ':';
G.s_tmparg[2] = '.';
G.screenwidth = 80;
return TRUE;
}
LPGLOBAL GetGlobal(void)
{
return &G;
}
BOOL DeleteGlobal(void)
{
return TRUE;
}
#define gg (*GetGlobal())
/*--------------*/
/* プロトタイプ */
/*--------------*/
unsigned char getcurdrv(void);
int getwd(unsigned char drvnm, char *p);
void fold(FILE *f);
int fold_usage(void);
void fhead(FILE *f, int lines);
int head(char *fnm, int lines, int disphead);
int expand(FILE *f); /* returns last pos */
int uniq(int ac, char **av);
void out(char *buf, int cnt);
void df(void);
void trmain(uchar *from, uchar *to);
int wc_usage(void);
int wc(char *fnm, int nmdisp);
void wcout(int flg, unsigned long n);
void wcmain(int fd);
void unexpand(FILE *f);
int s_cmp(char *s, char *t);
int a_cmp(char *s, char *t);
int cmp(char *s, char *t);
int cantopen(char *s);
int do_split(int flag, int linemax, long bytemax, FILE *inf, char *base);
int nextext(char *ext);
int writefail(void);
long caldate(int y, int m, int d);
int bad(void);
int fputs_so(char *s);
void putint(int n);
void putchar_n(int n, int c);
void putday(int n); /* width 2 */
void shortmonth(int m);
void getmonthdays(int year, int month, char *days, char *d_of_w);
int cal(void);
int caly(int year);
int calym(int year, int month);
void calrow(int year, int month, int days, int d_of_w, int row, int eolsup);
void outv(FILE *f);
void outn(FILE *f);
void outb(FILE *f);
void longintout(int w, unsigned long n, char **);
int mod_disp_time(char *newt, char *fmt);
int date_usage(void);
int illdate(void);
int disptime(char *fmt, int y, int m, int d, int h, int mi, int s, int w);
int pempty(void);
int efgrep(char *ptn, char *fnm);
int foundline(char *ptn, char *p);
int cp_usage(void);
int touch_usage(void);
int readtime(char *str, struct utimbuf *utimearg);
void fieldout(char *s1, char *s2, int flag);
int strfieldcmp(char *fb, char *fe, char *p, int n);
int strpartcmp(char *p, int m, char *q, int n);
int mv_usage(void);
int tail_usage(void);
char *difftmpnam(void); /* ad hoc */
int differror(char *format, ...);
int cant(char *filename,
char *what,
int fatalflag);
int isdir(char *fnm); /* on TURBOC, which files are needed to be included? */
void input(int which);
void squish(void);
void sort(DIFF_LINE *vector, int vecsize);
void equiv(void);
void unsort(void);
int subseq(void);
void unravel(int k);
int check(char *fileAname, char *fileBname);
void output(char *fileAname, char *fileBname);
int getline(FILE *fd, char *buffer);
int newcand(int a, int b, int pred);
unsigned search(unsigned low, unsigned high, int b);
int streq(char *s1, char *s2);
void change(int astart, int aend, int bstart, int bend);
void range(int from, int to, int w);
void fetch(long *seekvec,
int start,
int end,
int trueend,
FILE *fd,
char *pfx);
void fputss(char *s, FILE *iop);
void noroom(char *why);
void errorexit(void);
char *fgetss();
unsigned short hash();
char *dircat();
extern char *myalloc(); /* Storage allocator */
extern char *compact(); /* Storage compactor */
extern int getopt();
void readfile(char *fnm);
void linereg(char *s);
void do_sort(void);
void join_output(FILE *f, FILE *midf);
void midproc(void); /* メモリが足りなくなったので中間処理 */
bool add_file_list_sub(char *name,
bool fullname,
unsigned volmask,
bool nomsg,
int intended_as_directory);
void setstdoutbuf(void);
/*--------------*/
/* サブルーチン */
/*--------------*/
/*
* Convert MSDOS format pathname F(as '\xx\yy\zz') to UNIX format pathname
* '/xx/yy/zz'. F is overwritten. Returns F.
*/
char *conv_char(char *s, char cs, char cd)
{
unsigned char *p;
for (p = s; *p != '\0'; p++) {
if (IsDBCSLeadByte(*p) == TRUE) {
p++;
if (*p == '\0') {
break;
}
continue;
}
if (*p == cs) {
*p = cd;
}
}
return s;
}
int conv_char_args(char **argv, char cs, char cd)
{
char **p;
for (p = argv; p[0][0] != '\0'; p++) {
conv_char(*p, cs, cd);
}
return 0;
}
char *conv_to_unix_format(char *s)
{
conv_char(s, '\\', '/');
AnsiLowerBuff(s, lstrlen(s));
return s;
}
char *s_conv_to_unix_format(char *f)
{
return conv_to_unix_format(strcpy(gg.s_converted, f));
}
void _putnomemmes(void) /* Nide */
{
_puterrmes(ERR_MEMORY);
}
int iskanjipos(char *p)
{
return iskanji(*p) && p[1];
}
/*
* Cutoff the redundant path delimiter in the pathname string F. F is
* overwritten. Returns 1 if F ends with '/'(means the path is a directory,
* in UNIX semantics), else returns 0.
*
*/
int regularize_pathname(char *f)
{
char *s, *d;
int r = 0;
conv_char(f, '/', '\\');
/* Ignore the drive specifier */
if(isalpha(f[0]) && f[1] == ':'){
if(f[2] == '\0') {
return 1;
}
f += 2;
}
/* Root are treated specially. */
if(f[0] == PD && f[1] == '\0') {
return 1;
}
for(s = d = f; *s;){
if(iskanjipos(s)){
if(s != d) {
*d++ = *s++, *d++ = *s++;
} else {
s += 2, d += 2;
}
} else {
if(s > f && s[0] == PD && (s[1] == PD || s[1] == '\0')){
/*
* don't convert '//...' -> '/...'. this is
* used as super root file system in the
* future :-).
*
* convert '...//...' -> '.../...', '..../' ->
* '....' .
*/
if(s[1] == '\0') {
r = 1;
}
s++;
} else {
if(s != d) {
*d++ = *s++;
} else {
s++, d++;
}
}
}
}
*d = '\0';
return r;
}
int conv_to_dos_format(char *f)
{
conv_char(f, '/', '\\');
return regularize_pathname(f);
}
/***********************************************************************
getopt.c このgetopt.cはPublic Domainです
***********************************************************************/
void errdisp(char *cmd, char *as)
{
if(gg.opterr){
_puterrmes(cmd), _puterrmes(as),
*gg.s_crtail = gg.optopt, _puterrmes(gg.s_crtail);
}
}
int getopt(int ac, char **av, char *opts)
{
register char *cp;
if(gg.s_curopt == NULL || !*gg.s_curopt){
if(gg.optind >= ac || *(gg.s_curopt = av[gg.optind]) != '-' ||
!gg.s_curopt[1])
return EOF;
if(!strcmp("-", ++gg.s_curopt))
return (gg.optind++, EOF);
}
if(':' == (gg.optopt=*gg.s_curopt++) ||
NULL == (cp=strchr(opts, gg.optopt))){
errdisp(*av, ": unknown option, -");
if(!*gg.s_curopt) gg.optind++;
return '?';
}
if(*++cp == ':'){
gg.optind++;
if(*gg.s_curopt){
gg.optarg = gg.s_curopt;
gg.s_curopt = NULL;
} else {
if(gg.optind >= ac){
errdisp(*av, ": argument missing for -");
return '?';
} else {
gg.optarg = av[gg.optind++];
}
/* now *curopt == '\0' */
}
} else {
gg.optarg = NULL;
if(!*gg.s_curopt) gg.optind++;
}
return gg.optopt;
}
/*-----------*/
/* echo_main */
/*-----------*/
int echo_main(int ac, char **av)
{
int nI;
int nLen;
char *pStr;
nLen = 0;
for (nI = 0; nI < ac; nI++) {
nLen += lstrlen(av[nI]) + 1;
}
pStr = malloc(nLen + 1); nI = 0;
if (pStr == NULL) {
return 0;
}
ac--, av++;
if(!ac) return 0; /* exit 0 */
for(; ac--; av++){
char *p, c;
int i;
for(p = *av; c = *p; p++){
if(c == ESCAPE){
switch(c = *++p){
case 'c': goto nextarg;
case 'n': c = '\n'; break;
case 't': c = '\t'; break;
case 'b': c = '\b'; break;
case 'r': c = '\r'; break;
case 'f': c = '\f'; break;
case 'a': c = 0x7; break;
case 'v': c = 0xb; break;
case 'e': c = '\033'; break;
case '\0': p--, c = ESCAPE; break;
case '0':
c = 0, i = 3;
while(p++, i-- && is_octal(*p)) {
c <<= 3, c |= *p - '0';
}
p--; break;
/* case ESCAPE: break; */
/* default: break; */
}
}
pStr[nI] = c; nI++;
}
pStr[nI] = '\0';
cwFputs(pStr, NULL); nI = 0;
if(ac){
cwFputs(" ", NULL);
} else {
cwFputs("\n", NULL);
}
nextarg:
;
}
free(pStr);
return 0; /* exit 0 */
}
/*------------*/
/* rmdir_main */
/*------------*/
int rmdir_main(int ac, char **av)
{
int error = 0;
if(av++, !--ac){
cwFputs("rmdir DIRECTORY...\n", (LPSTR)-1); return 1;
}
for(; ac; ac--, av++){
if(rmdir(*av)){
conv_to_unix_format(*av), cwFputs(*av, (LPSTR)-1);
cwFputs(errno == ENOENT ?
": Not exist\n" : ": Can't remove\n", (LPSTR)-1);
error = 1;
}
}
return error;
}
/*----------*/
/* tee_main */
/*----------*/
int tee_main(int ac, char **av)
{
char *buf; /* no huge auto array... */
int i, iosize, mode = O_TEXT | O_WRONLY | O_CREAT, *fps;
buf = malloc(XBUFSIZ);
if (buf == NULL) {
return 1;
}
if(av++, ac-- && !strcmp(*av, "-a")){
av++, ac--, mode |= O_APPEND;
}
if(NULL == (fps = malloc(sizeof(int) * (ac + 1)))){
_putnomemmes();
free(buf);
return 1;
} else {
fps[ac] = 1;
}
for(i = 0; i < ac; i++){
if(0 > (fps[i] = open(av[i], mode, S_IWRITE | S_IREAD))){
if(errno == EMFILE) {
_puterrmes("Too many open files");
} else {
_puterrmes(conv_to_unix_format(av[i]));
_puterrmes(": Can't open");
}
_puterrmes("\n");
free(buf);
return 1;
}
}
while(NULL != cwFgets(buf, XBUFSIZ, NULL)){
iosize = lstrlen(buf);
for(i = 0; i < ac; i++){
if(iosize > write(fps[i], buf, iosize)){
_puterrmes(conv_to_unix_format(av[i]));
_puterrmes(": Write failed\n");
}
}
cwFputs(buf, NULL);
}
for (i = 0; i < ac; i++) {
close(fps[i]);
}
free(buf);
return 0;
}
/*----------*/
/* pwd_main */
/*----------*/
/*
usage:
pwd [-dp] [drive[:]]
-d …… ドライブ名のみ表示。
-p …… ディレクトリ名のみ表示。
*/
unsigned char getcurdrv(void)
{
return _getdrive() - 1;
}
int pwd_main(int ac, char **av)
{
int c;
register unsigned char drvnm;
register char *drvarg, drv;
// extern int optind, opterr;
// extern char *optarg;
char p[MAX_PATH];
char szDrv[16];
int nopath = 0, nodrv = 0;
gg.opterr = 0;
while(EOF != (c = getopt(ac, av, "dp"))){
switch(c){
case 'd': nopath = 1; break;
case 'p': nodrv = 1; break;
default:
cwFputs("Usage: pwd [-dp] [drive[:]]\n", (LPSTR)-1);
return 1;
}
}
if(nopath && nodrv){
cwFputs("Equivocal operands --- p and d\n", (LPSTR)-1);
return 1;
}
ac -= gg.optind;
av += gg.optind;
switch(ac){
case 0:
drvnm = 0;
drv = 'a' + getcurdrv();
break;
case 1:
drvarg = *av;
if(!is_alpha(*drvarg) ||
!(!drvarg[1] || drvarg[1] == ':' && !drvarg[2])){
cwFputs("Illegal drive --- ", (LPSTR)-1);
cwFputs(drvarg, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
return 1;
}
drv = to_lower(*drvarg);
drvnm = drv - 'a' + 1;
break;
default:
cwFputs("Too many arguments.\n", (LPSTR)-1);
return 1;
}
if(nopath){
_snprintf(szDrv, sizeof(szDrv), "%c\n", drv);
cwFputs(szDrv, NULL);
} else {
switch(getwd(drvnm, p)){
case 1:
cwFputs("Unavailable drive --- ", (LPSTR)-1);
cwFputs(drvarg, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
return 1;
default:
if(!nodrv){
_snprintf(szDrv, sizeof(szDrv), "%c:", drv);
cwFputs(szDrv, NULL);
}
szDrv[0] = '/'; szDrv[1] = '\0';
cwFputs(szDrv, NULL);
cwFputs(p, NULL);
szDrv[0] = '\n'; szDrv[1] = '\0';
cwFputs(szDrv, NULL);
}
}
return 0;
}
int getwd(unsigned char drvnm, char *p)
{
char *pRet;
pRet = _getdcwd(drvnm, p, MAX_PATH);
if (pRet == NULL) {
return 1;
} else {
memmove(p, p + 3, MAX_PATH-2);
conv_to_unix_format(p);
return 0;
}
}
/*---------*/
/* fold_main */
/*---------*/
int fold_usage(void)
{
cwFputs("Usage: fold [-[w]width] [file...]\n", (LPSTR)-1);
return 1;
}
int fold_main(int ac, char **av)
{
FILE *inf;
ac--, av++;
if(ac && av[0][0] == '-' && av[0][1]){
if(av[0][1] == 'w'){
if(av[0][2]){
gg.width = atoi(*av + 2);
} else {
if(av++, !--ac) {
return fold_usage();
}
gg.width = atoi(*av);
}
} else {
gg.width = atoi(*av + 1);
}
if(0 >= gg.width) {
return fold_usage();
}
ac--, av++;
}
if(!ac){
fold(NULL);
} else {
for(; ac; ac--, av++){
if(av[0][0] == '-' && !av[0][1]){
fold(NULL);
} else {
if(NULL == (inf = fopen(*av, "r"))){
cwFputs(s_conv_to_unix_format(*av), (LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
return 1;
}
fold(inf);
fclose(inf);
}
}
}
return 0;
}
void fold(FILE *f)
{
int c;
char bufi[0x100];
char bufo[0x200];
char *pi;
char *po;
while (TRUE) {
if (f == NULL) {
if (cwFgets(bufi, 0xFF, NULL) == NULL) break;
} else {
if (fgets(bufi, 0xFF, f) == NULL) break;
}
bufi[0xFF] = '\0';
po = bufo;
for (pi = bufi; *pi != '\0'; pi++) {
c = *pi;
if(iskanji(c)){
gg.s_pos += 2;
if(gg.s_pos > gg.width) {
*po++ = '\n';
gg.s_pos = 2;
}
*po++ = c;
pi++;
if (*pi == '\0') {
gg.s_pos--;
return;
}
*po++ = c;
} else if(c == '\b'){
*po++ = c;
gg.s_pos--;
} else if(c == '\n' || c == '\r' || c == '\f'){
*po++ = c;
gg.s_pos = 0;
} else if(c == '\t'){
gg.s_pos = (gg.s_pos + 8) & ~7;
if(gg.s_pos > gg.width) {
*po++ = '\n';
gg.s_pos = 8;
}
*po++ = c;
} else {
if(++gg.s_pos > gg.width) {
*po++ = '\n';
gg.s_pos = 1;
}
*po++ = c;
}
}
*po = '\0';
cwFputs(bufo, NULL);
}
}
/*-------*/
/* mkdir */
/*-------*/
int makedir(char *path)
{
char *x, *last_path_sep;
/*
* No problem if succeeded to mkdir PATH.
*/
if(!mkdir(path))
return 1;
/*
* Suppose PATH is "A/B/C/D", if failed to mkdir PATH itself, then
* try to mkdir "A/B/C", and mkdir "D" under "A/B/C". This process
* can be expressed as recursion.
*/
x = path;
last_path_sep = 0;
/*
* First split PATH into 2 part, for example if PATH = "A/B/C/D",
* split into "A/B/C" and "D". LAST_PATH_SEP holds between the 1st
* and 2nd string.
*/
while(*x){
if(iskanjipos(x))
x += 2;
else {
if(*x == PD)
last_path_sep = x;
x++;
}
}
/*
* Return error if failed to split PATH.
*/
if(last_path_sep == 0)
return 0;
{
char buf[BUFSIZ];
strncpy(buf, path, last_path_sep - path);
buf[last_path_sep - path] = '\0';
/*
* Try to mkdir "A/B/C".
*/
if(!makedir(buf))
return 0;
/*
* and mkdir "D" under "A/B/C".
*/
return !mkdir(path);
/* Instead of: if(mkdir(path)) return 0; else return 1; */
}
}
int mkdir_main(int argc, char **argv)
{
int i;
int error = 0;
int recur = 0; /* Add Nide */
conv_char_args(argv, '/', '\\');
if(argc >= 2 && !strcmp("-p", argv[1])){
argc--, argv++, recur = 1;
} /* Add Nide */
if(argc < 2){
cwFputs("mkdir [-p] DIRECTORY...\n", (LPSTR)-1); /* Changed Nide */
return 1;
}
for(i = 1; i < argc; i++){
conv_to_dos_format(argv[i]);
if(recur ? !makedir(argv[i]) : mkdir(argv[i])){ /* Changed Nide */
cwFputs(s_conv_to_unix_format(argv[i]), (LPSTR)-1);
cwFputs(": Can't make directory\n", (LPSTR)-1);
error = 1;
}
}
return error;
}
/*------------*/
/* chmod_main */
/*------------*/
/* chmod.c
Usage: chmod [[ua]{-,+}owhsa] files...
'+'はその属性を与え、'-'は取り去る
o: 書き込み禁止属性
w: 書き込み許可(oの反対)
h: 隠しファイル属性
s: システムファイル属性
a: アーカイブ属性
*/
char *name_unixnize(unsigned char *s)
{
char *ret = s;
for(; *s; s++){
if(iskanjipos(s)) s++;
else if(*s == '\\') *s = '/';
else if(isascii(*s) && isupper(*s))
*s = tolower(*s);
}
return(ret);
}
int chmod_usage(void)
{
cwFputs("Usage: chmod [-n] [[ua]{-,+}owhsa] files...\n", (LPSTR)-1);
return 1;
}
unsigned getattr(char *s)
/* エラー時には ~0 が返る */
{
return GetFileAttributes(s);
}
int setattr(char *s, unsigned a)
/* 成功時には0 失敗時には-1を返す */
{
return (SetFileAttributes(s, a) == TRUE) ? 0 : -1;
}
#if 0
void expand_control()
{
_dosfind_param = 0x37;
}
#endif
char *modarg(char *s)
{
if(*s == 'u' || *s == 'a') s++;
return (*s == '-' || *s == '+') ? s : NULL;
}
int chmod_main(int ac, char **av)
{
char *p;
int plus, status = 0;
unsigned attr, plusattr = 0, minusattr = 0x18; /* dir&vol bit */
ac--, av++;
if(ac && !strcmp(*av, "-n")){
ac--, av++, gg.nodisp = 1;
}
if(!ac || NULL == modarg(*av)) return chmod_usage();
for(; ac && NULL != (p = modarg(*av)); ac--, av++){
plus = (*p == '+');
for(p++; *p; p++){
switch(*p){
case 'o':
plus ? (plusattr |= 1) : (minusattr |= 1);
break;
case 'h':
plus ? (plusattr |= 2) : (minusattr |= 2);
break;
case 's':
plus ? (plusattr |= 4) : (minusattr |= 4);
break;
case 'a':
plus ? (plusattr |= 32) : (minusattr |= 32);
break;
case 'w':
!plus ? (plusattr |= 1) : (minusattr |= 1);
break;
default:
return chmod_usage();
}
}
}
if(!ac) return chmod_usage();
for(; ac; ac--, av++){
p = name_unixnize(*av);
attr = getattr(p);
attr &= ~minusattr;
attr |= plusattr;
if(-1 == setattr(p, attr)){
cwFputs(p, (LPSTR)-1);
cwFputs(": Can't change\n", (LPSTR)-1);
status = 1;
continue;
}
if(!gg.nodisp){
cwFputs(p, (LPSTR)-1);
cwFputs(":\n", (LPSTR)-1);
}
}
return status;
}
/*----------*/
/* man_main */
/*----------*/
/*
Very very simple man Changed Nide
*/
char *find_man_file(char *dir, char *command)
{
_snprintf(gg.s_buf, sizeof(gg.s_buf), "%s\\%s.doc", dir, command);
if(!access(gg.s_buf, 0)) return gg.s_buf;
_snprintf(gg.s_buf, sizeof(gg.s_buf), "%s\\%s.man", dir, command);
if(!access(gg.s_buf, 0)) return gg.s_buf;
_snprintf(gg.s_buf, sizeof(gg.s_buf), "%s\\%s.1", dir, command);
if(!access(gg.s_buf, 0)) return gg.s_buf;
return 0;
}
int man(char *cmdname)
{
char *path = 0, *manpath;
char *p, *q, buf[TBUFSIZ];
if(NULL == (manpath = getenv("MANPATH")) &&
NULL == (manpath = getenv("MAN"))){
cwFputs("MANPATH not set\n", (LPSTR)-1);
return 1;
}
for(p = manpath; p != NULL;){
_snprintf(buf, sizeof(buf), "%.*s",
NULL != (q = strchr(p, ';')) ? q++ - p : strlen(p), p);
if(*buf && (buf-1)[strlen(buf)] == '\\')
(buf-1)[strlen(buf)] = '\0';
if(path = find_man_file(buf, cmdname)) break;
p = q;
}
if(path == 0){
cwFputs("No entry found for ", (LPSTR)-1);
cwFputs(cmdname, (LPSTR)-1);
cwFputs("\n", (LPSTR)-1);
return 1;
}
{
FILE *fp;
int line;
fp = fopen(path, "r");
for (line = 1; fgets(buf, 0xFF, fp) != NULL; line++) {
buf[0xFF] = '\0';
cwFputs(buf, NULL);
if (line % 24 == 0) {
cwFputs("-- More --", (LPSTR)-1);
cwGetch();
cwFputs("\n", (LPSTR)-1);
}
}
fclose(fp);
}
return 0;
}
int man_main(int argc, char **argv)
{
if(argc < 2){
cwFputs("man COMMANDNAME\n", (LPSTR)-1);
return 1;
}
return man(argv[1]);
}
/*-----------*/
/* head_main */
/*-----------*/
/* head.c tailがあるのにheadがないのは淋しいので。
Usage: head [-行数] [files...]
ファイルの指定を '-' とすると標準入力を読みます。
*/
int head_main(int ac, char **av)
{
int lines = 10;
ac--, av++;
if(ac && av[0][0] == '-' && av[0][1] != '\0'){
lines = atoi(*av + 1);
if(lines <= 0){
cwFputs("Usage: head [-lines] [files...]\n", (LPSTR)-1);
return 1;
}
ac--, av++;
}
switch(ac){
case 0:
fhead(NULL, lines);
break;
case 1:
head(*av, lines, 0);
break;
default:
for(; ac; ac--, av++) head(*av, lines, 1);
break;
}
return 0;
}
void fhead(FILE *f, int lines)
{
char buf[0x100];
int i;
for (i = 0; i < lines; i++) {
if (f == NULL) {
if (cwFgets(buf, 0xFF, NULL) == NULL) break;
} else {
if (fgets(buf, 0xFF, f) == NULL) break;
}
buf[0xFF] = '\0';
cwFputs(buf, NULL);
}
}
int head(char *fnm, int lines, int disphead)
{
FILE *f;
if(fnm[0] == '-' && !fnm[1]){
if(disphead) cwFputs("\n==> stdin <==\n", NULL);
fhead(NULL, lines);
} else {
name_unixnize(fnm);
if(disphead){
cwFputs("\n==> ", NULL), cwFputs(fnm, NULL),
cwFputs(" <==\n", NULL);
}
if(NULL == (f = fopen(fnm, "r"))){
cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
return 1;
}
fhead(f, lines);
fclose(f);
}
return 0;
}
/*------------*/
/* chdir_main */
/*------------*/
/*
* chd: Change directory.
*
* Yasushi Saito (yasushi@is.s.u-tokyo.ac.jp)
*/
void _dos_setdrive(unsigned drive, unsigned *numdrives)
{
char szBuf[0x10];
*numdrives = 26;
_snprintf(szBuf, sizeof(szBuf), "%c:", drive + 'A' - 1);
SetCurrentDirectory(szBuf);
}
int change_directory(char *s)
{
unsigned dd;
regularize_pathname(s);
if(isalpha(*s) && s[1] == ':'){
if(gg.current_drive != GET_DRIVE(*s)){ /* Changed Nide */
_dos_setdrive((gg.current_drive = GET_DRIVE(*s)), &dd);
if(getcurdrv() + 1 != gg.current_drive){
cwFputs("chd: can't change drive\n", (LPSTR)-1);
return -1;
}
}
s += 2;
if(*s == '\0') return 0;
}
return chdir(s);
}
int chdir_main(int argc, char **argv)
{
char *cdpath, *pathp, pathname[BUFSIZ];
int dd;
conv_char_args(argv, '/', '\\');
getcwd(pathname, BUFSIZ);
gg.old_drive = gg.current_drive = GET_DRIVE(*pathname);
if(argc > 2){ /* Too many arguments */
cwFputs("chd: directory ambiguous\n", (LPSTR)-1);
/* Nide, 非ANSIコンパイラの便のために変更した */
return 2;
} else if(argc == 1){ /* No arguments */
char *home;
if(NULL == (home = getenv("HOME"))){
cwPuts(conv_to_unix_format(pathname));
goto OK;
} else if(0 == change_directory(home)){
goto OK;
} else {
goto L_ERROR;
}
}
if(0 == change_directory(argv[1]))
goto OK;
/* Check if string contains path separator */
if(argv[1][0] == '.' || argv[1][0] == PD ||
isalpha(argv[1][0]) && argv[1][1] == ':')
goto L_ERROR;
if((cdpath = getenv("CDPATH")) == NULL)
goto L_ERROR;
while(*cdpath){
pathp = pathname;
while(*cdpath && *cdpath != ';') *pathp++ = *cdpath++;
if(*cdpath == ';') cdpath++;
*pathp = 0;
if(*pathname == PD && !pathname[1] ||
isalpha(*pathname) && pathname[1] == ':' &&
pathname[2] == PD && !pathname[3]){
/* nothing */
} else {
*pathp++ = PD;
} /* あとでregularize_pathname()する */
strcpy(pathp, argv[1]);
if(0 == change_directory(pathname)){
cwPuts(s_conv_to_unix_format(pathname));
goto OK;
}
}
L_ERROR:
cwFputs("chd: no such directory\n", (LPSTR)-1);
/* Nide, 非ANSIコンパイラの便のために変更した */
if(gg.old_drive != gg.current_drive)
_dos_setdrive(gg.old_drive, &dd);
return 1;
OK:
return 0;
}
/*-------------*/
/* expand_main */
/*-------------*/
int expand_usage(void)
{
cwFputs("Usage: expand [-nsk] [-tablist] [file...]\n", (LPSTR)-1);
return 1;
}
int do_opt(char *opt)
{
int tabidx = 0, prevcol = 0;
for(;;){
if(tabidx == COLLISTMAX - 1){
cwFputs("Tabstop list too long\n", (LPSTR)-1);
return 1;
}
gg.tabcols[tabidx] = atoi(opt);
if(prevcol >= gg.tabcols[tabidx]){
cwFputs("Bad tab stop spec\n", (LPSTR)-1);
return 1;
} else {
prevcol = gg.tabcols[tabidx++];
}
while(is_digit(*opt)) opt++;
if(!*opt) break;
if(*opt++ != ',') {
expand_usage();
return 1;
}
}
gg.tabcols[tabidx] = 0;
gg.tabcol = (gg.tabcols[1] ? 0 : gg.tabcols[0]);
return 0;
}
int expand_main(int ac, char **av)
{
FILE *inf;
int pos;
ac--, av++;
while(ac && av[0][0] == '-' && av[0][1]){
char *p;
for(p = *av + 1; *p && !is_digit(*p); p++){
switch(*p){
case 's':
gg.addsp = 1; break;
case 'k':
gg.kspc = 1; break;
case 'n':
gg.eofnl = 1; break;
default:
return expand_usage();
}
}
if(*p) {
if (do_opt(p) != 0) {
return 1;
}
}
ac--, av++;
}
if(!ac){
pos = expand(NULL);
} else {
for(; ac; ac--, av++){
if(av[0][0] == '-' && !av[0][1]){
pos = expand(NULL);
} else {
if(NULL == (inf = fopen(*av, "r"))){
cwFputs(s_conv_to_unix_format(*av), (LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
return 1;
}
pos = expand(inf);
fclose(inf);
}
}
}
if(pos && gg.eofnl) cwFputs("\n", NULL);
return 0;
}
int expand(FILE *f) /* returns last pos */
{
int pos = 0, c, d, tabidx = 0;
char bufi[0x100];
char bufo[0x1000];
char *pi;
char *po;
while (TRUE) {
if (f == NULL) {
if (cwFgets(bufi, 0xFF, NULL) == NULL) break;
} else {
if (fgets(bufi, 0xFF, f) == NULL) break;
}
bufi[0xFF] = '\0';
po = bufo;
for (pi = bufi; *pi != '\0'; pi++) {
c = *pi;
if(iskanji(c)){
if('\0' == (d = *(++pi))){
*po++ = c;
++pos;
pi--;
continue;
}
if(gg.kspc && ((c << 8) | d) == KSPC){
*po++ = ' '; *po++ = ' ';
} else {
*po++ = c; *po++ = d;
}
pos += 2;
} else if(c == '\b'){
*po++ = c;
pos--;
if(tabidx) tabidx--; /* 最高1つ戻せばよい */
} else if(c == '\n' || c == '\r' || c == '\f'){
if(!pos && gg.addsp) {
*po++ = ' ';
}
*po++ = c;
pos = tabidx = 0;
} else if(c == '\t'){
int newpos;
if(gg.tabcol){
newpos = (pos / gg.tabcol + 1) * gg.tabcol;
} else {
for(;; tabidx++){
newpos = gg.tabcols[tabidx];
if(!newpos || pos < newpos) break;
}
if(!newpos) newpos = pos + 1;
}
for(; pos < newpos; pos++) *po++ = ' ';
} else {
*po++ = c;
pos++;
}
}
*po = '\0';
cwFputs(bufo, NULL);
}
return pos;
}
/*-----------*/
/* uniq_main */
/*-----------*/
int uniq_usage(void)
{
cwFputs("Usage: uniq [-cdu] [{+|-}n] [file]\n", (LPSTR)-1);
return 1;
}
int uniq_main(int ac, char **av)
{
char *p;
int optend;
char udopt = 0;
for(optend = 0; av++, --ac; ){
switch(p = *av, *p++){
case '+':
if(!*p) return uniq_usage();
gg.ignc = atoi(p);
break;
case '-':
if(!*p){optend++; break;}
if(isdigit(*p)){
gg.ignf = atoi(p);
break;
}
for(; *p; p++){
switch(*p){
case 'c':
gg.outlcnt = 1; break;
case 'd':
gg.outdup = udopt = 1; break;
case 'u':
gg.outndup = udopt = 1; break;
default:
return uniq_usage();
}
}
break;
default:
optend++; break;
}
if(optend) break;
}
if(!udopt) gg.outdup = gg.outndup = 1;
return uniq(ac, av);
}
int uniq(int ac, char **av)
{
FILE *f = NULL;
int i, dupcnt = 0, len;
char *bufcur, *cmpcur, *bufprv = NULL, *cmpprv = NULL;
char *fnm, sw = 0, linbuf[2][LINMAX];
int ret = 0;
if(ac > 1) {
uniq_usage();
ret = 1;
goto EXIT;
}
if(!ac || **av == '-' && !av[0][1]){
f = NULL, fnm = "(stdin)";
} else if(NULL == (f = fopen(fnm = conv_to_unix_format(*av), "r"))){
cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
ret = 1;
goto EXIT;
}
while(((f == NULL) ? cwFgets(bufcur = linbuf[sw], LINMAX, NULL) :
fgets(bufcur = linbuf[sw], LINMAX, f)) != NULL) {
if(!bufcur[0]){
; /* nothing */
} else if(bufcur[(len = strlen(bufcur)) - 1] != '\n'){
cwFputs(fnm, (LPSTR)-1);
if(len == LINMAX - 1){
cwFputs(": line too long\n", (LPSTR)-1);
ret = 1;
goto EXIT;
} else {
cwFputs(": missing line-feed character "
"added at EOF\n", (LPSTR)-1);
}
} else {
bufcur[len - 1] = '\0';
}
cmpcur = bufcur;
for(i = gg.ignf; i--;){
while(is_space(*cmpcur)) cmpcur++;
while(!is_space(*cmpcur)){
if(!*cmpcur) goto contin;
cmpcur++;
}
}
contin:
for(i = gg.ignc; i--;){
if(!*cmpcur) break;
cmpcur++;
}
if(cmpprv == NULL || strcmp(cmpprv, cmpcur)){
out(bufprv, dupcnt);
dupcnt = 1;
sw ^= 1, cmpprv = cmpcur, bufprv = bufcur;
} else {
dupcnt++;
}
}
out(bufprv, dupcnt);
EXIT:
if (f != NULL) fclose(f);
return ret;
}
void intout(int w, unsigned int n)
{
int num, col;
char *buf;
buf = malloc(w + 1);
if (buf == NULL) {
return;
}
memset(buf, ' ', w);
buf[w] = '\0';
num = n / 10;
for (col = 1; num > 0; col++, num /= 10);
if (col > w) col = w;
_snprintf(buf + w - col, 10, "%d", n);
cwFputs(buf, NULL);
free(buf);
}
void out(char *buf, int cnt)
{
if(buf != NULL && (cnt == 1 ? gg.outndup : gg.outdup)){
if(gg.outlcnt) (intout(4, cnt), cwFputs(" ", NULL));
/* instead of printf("%4d ", cnt); */
cwPuts(buf);
}
}
/*---------*/
/* df_main */
/*---------*/
int df_usage(void)
{
cwFputs("Usage: df [-B]\n", (LPSTR)-1);
return 1;
}
int df_main(int ac, char **av)
{
switch(av++, --ac){
case 0:
break;
case 1:
if(!strcmp(*av, "-B")){ac--, av++, gg.availunit = 1; break;}
default:
return df_usage();
}
df();
return 0;
}
void df(void)
{
char szLogDrives[0x100];
char szOut[0x100];
LPSTR lpLog;
DWORD dwSectorsPerCluster;
DWORD dwBytesPerSector;
DWORD dwFreeClusters;
DWORD dwClusters;
DWORD dwTotal;
DWORD dwUsed;
DWORD dwAvail;
DWORD dwCap;
DWORD dwBytesPerCluster;
UINT uErrorOrg;
_snprintf(szOut, sizeof(szOut), "lastdrive: %c", 'z');
cwFputs(szOut, NULL);
_snprintf(szOut, sizeof(szOut),
(gg.availunit == 1) ? "%25savail" : (LPSTR)"", (LPSTR)"");
cwFputs(szOut, NULL);
_snprintf(szOut, sizeof(szOut),
/* a:/usr/local 0123456 0123456 01-9 --100%-- 0123456 c:\ */
"\nFilesystem Kbytes used %s capacity Cluster Mounted on\n",
(gg.availunit == 1) ? " (bytes)" : "avail");
cwFputs(szOut, NULL);
GetLogicalDriveStrings(0x100, szLogDrives);
uErrorOrg = SetErrorMode(SEM_FAILCRITICALERRORS);
for (lpLog = szLogDrives; *lpLog != '\0'; lpLog += lstrlen(lpLog) + 1) {
if (GetDiskFreeSpace(lpLog,
&dwSectorsPerCluster,
&dwBytesPerSector,
&dwFreeClusters,
&dwClusters) == FALSE) {
continue;
}
dwBytesPerCluster = dwSectorsPerCluster * dwBytesPerSector;
dwTotal = dwClusters * dwBytesPerCluster / 1024;
dwAvail = dwFreeClusters * dwBytesPerCluster / 1024;
dwUsed = dwTotal - dwAvail;
dwCap = dwUsed / (dwTotal / 100);
dwAvail *= 1024 / gg.availunit;
_snprintf(szOut, sizeof(szOut), fmt,
(LPSTR)conv_to_unix_format(lpLog),
dwTotal,
dwUsed,
(gg.availunit == 1) ? 10 : 7,
dwAvail,
dwCap,
dwBytesPerCluster,
(LPSTR)lpLog);
cwFputs(szOut, NULL);
}
SetErrorMode(uErrorOrg);
}
/*---------*/
/* tr_main */
/*---------*/
/* tr [-cds] [string1 [string2]], no wildcards */
int tr_usage(void)
{
cwFputs("Usage: tr [-cdsIOz] [string1 [string2]]\n", (LPSTR)-1);
return 1;
}
int tr_main(int ac, char **av)
{
if(av++, --ac && **av == '-'){
char *p;
for(p = *av + 1; *p; p++){
switch(*p){
case 'c': gg.cmplmnt = 1; break;
case 'd': gg.delete = 1; break;
case 's': gg.supdup = 1; break;
case 'I': gg.ibinary = 1; break;
case 'O': gg.obinary = 1; break;
case 'z': gg.treatz = 1; break;
default: return tr_usage();
}
}
ac--, av++;
}
if(ac > 2) return tr_usage();
trmain(ac ? av[0] : strnul, ac > 1 ? av[1] : strnul);
return 0; /* exit from main() */
}
void init_argchar(struct argchar *p, uchar *s)
{
p -> count = 0;
p -> arg = s;
}
int get1char(uchar **pp)
{
uchar *p;
int c;
c = *(p = *pp);
if(!c) return EOF;
if(c != '\\') {
(*pp)++;
} else if(c = *++p, isoctal(c)){
int i = 3;
c -= '0';
while(p++, --i && isoctal(*p)){
c <<= 3, c |= *p - '0';
}
*pp = p;
} else {
switch(c){
case 'n': c = '\n'; break;
case 't': c = '\t'; break;
case 'b': c = '\b'; break;
case 'r': c = '\r'; break;
case 'f': c = '\f'; break;
case 'v': c = 0xb; break;
case 'a': c = 0x7; break;
case 'e': c = '\033'; break;
}
*pp = ++p;
}
return c;
}
int getargchar(struct argchar *p)
{
int i, j;
uchar *s;
if(p -> count){
p -> count--; /* -1であっても -- しないと… */
i = p -> next;
p -> next += p -> step;
return i;
}
i = *(s = p -> arg);
if(!i) return EOF;
if(i != '['){
i = get1char(&s);
} else { /* non-escaped '[' */
s++;
if(EOF == (i = get1char(&s))) goto Bad;
switch(*s++){
case '-':
if(EOF == (j = get1char(&s))) goto Bad;
if(0 < (j -= i)){
p -> step = 1, p -> count = j;
} else {
p -> step = -1, p -> count = -j;
}
p -> next = i + p -> step;
break;
case '*':
j = 0;
if(*s == '0'){
while(isoctal(*s)) (j <<= 3, j |= *s++ - '0');
} else {
while(isdigit(*s)) (j *= 10, j += *s++ - '0');
} /* numが略された場合もこれでOK */
p -> count = --j; /* 0なら(uint)(-1)==Hugeになる */
p -> step = 0, p -> next = i;
break;
default:
goto Bad;
}
if(*s++ != ']'){
Bad:
cwFputs("Bad string\n", (LPSTR)-1);
return EOF;
}
}
p -> arg = s;
return i;
}
int getargchar_nodup(struct argchar *p)
{
int i;
i = getargchar(p);
if(!p -> step) p -> count = 0;
return i;
}
void getargcharpair(struct argchar *p1, int *ip,
struct argchar *p2, int *jp)
{
*ip = getargchar(p1);
*jp = getargchar(p2);
if(!p1 -> step && !p2 -> step){
p1 -> count > p2 -> count ?
(p1 -> count -= p2 -> count) :
(p2 -> count -= p1 -> count);
}
}
void trmain(uchar *from, uchar *to)
{
struct argchar fromstr, tostr;
int i, j;
if(!gg.cmplmnt){
for(i = 0; i < 0x100; i++) (gg.cnvtbl[i] = i, gg.duptbl[i] = 0);
if(!gg.treatz) gg.cnvtbl[0] = EOF;
init_argchar(&fromstr, from);
if(!gg.delete){
init_argchar(&tostr, to);
while(getargcharpair(&fromstr, &i, &tostr, &j),
EOF != i && (gg.treatz || i) &&
EOF != j && (gg.treatz || j)){
gg.cnvtbl[i] = j;
}
while(EOF != i && (gg.treatz || i)){
gg.cnvtbl[i] = i;
i = getargchar_nodup(&fromstr);
}
} else {
while(EOF != (i = getargchar_nodup(&fromstr)) &&
(gg.treatz || i)){
gg.cnvtbl[i] = EOF;
}
}
} else { /* complement */
for(i = 0; i < 0x100; i++) (gg.cnvtbl[i] = EOF, gg.duptbl[i] = 0);
init_argchar(&fromstr, from);
while(EOF != (i = getargchar_nodup(&fromstr)) &&
(gg.treatz || i)){
gg.cnvtbl[i] = i;
}
if(!gg.delete){
init_argchar(&tostr, to), i = (gg.treatz ? 0 : 1);
while(EOF != (j = getargchar(&tostr)) &&
(gg.treatz || j)){
while(gg.cnvtbl[i] != EOF){
if(++i >= 0x100) goto nomorecnv;
}
gg.cnvtbl[i] = j;
}
for(; i < 0x100; i++){
if(gg.cnvtbl[i] == EOF) gg.cnvtbl[i] = i;
}
}
}
nomorecnv:
init_argchar(&tostr, to);
while(EOF != (j = getargchar_nodup(&tostr)) && (gg.treatz || j)){
gg.duptbl[j] = 1;
}
{
char bufi[0x2000];
char bufo[0x2000];
char *pi;
char *po;
j = EOF;
while (cwFgets(bufi, 0x1FFF, NULL) != NULL) {
bufi[0x1FFF] = '\0';
po = bufo;
for (pi = bufi; *pi != '\0'; pi++) {
i = *pi;
if (EOF != (i = gg.cnvtbl[i])) {
if (gg.supdup && gg.duptbl[i] && j== i) {
continue;
}
*po++ = i;
j = i;
}
}
*po = '\0';
cwFputs(bufo, NULL);
}
}
}
/*-------*/
/* wc_main */
/*-------*/
/* wc [-lwc] [files...] */
int wc_main(int ac, char **av)
{
// extern int optind, opterr;
int c, errstat = 0;
gg.opterr = 0;
while(EOF != (c = getopt(ac, av, "lwc"))){
switch(c){
case 'l':
gg.print_line = 1; break;
case 'w':
gg.print_word = 1; break;
case 'c':
gg.print_char = 1; break;
default:
return wc_usage();
}
}
ac -= gg.optind, av += gg.optind;
if(!gg.print_line && !gg.print_word && !gg.print_char)
gg.print_line = gg.print_word = gg.print_char = 1;
switch(ac){
case 0:
return wc(NULL, 0);
case 1:
return wc(*av, 0);
default:
for(; ac; ac--, av++) errstat |= wc(*av, 1);
wcout(gg.print_line, gg.total_l);
wcout(gg.print_word, gg.total_w);
wcout(gg.print_char, gg.total_c);
/* instead of printf("%7ld ", ...) */
cwPuts("total");
return errstat;
}
}
/* open不能の場合は1 正常終了なら0返す */
int wc(char *fnm, int nmdisp)
{
int fd;
if(fnm == NULL || !strcmp("-", fnm)){
fnm = NULL;
wcmain(-1);
} else {
if(-1 == (fd = open(fnm, O_RDONLY | O_BINARY))){
cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
return 1;
}
wcmain(fd);
close(fd);
}
if(nmdisp) cwFputs(fnm == NULL ?
"(stdin)" : s_conv_to_unix_format(fnm), NULL);
cwFputs("\n", NULL);
return 0;
}
void wcmain(int fd)
{
long file_l = 0L, file_w = 0L, file_c = 0L;
register unsigned char *p;
register unsigned int n;
int word_cont = 0;
while(TRUE) {
if (fd == -1) {
if (cwFgets(gg.s_readbuf, sizeof(gg.s_readbuf) - 1, NULL) == NULL)
break;
n = lstrlen(gg.s_readbuf);
} else {
if ((n = read(fd, gg.s_readbuf, RBUFSIZ)) <= 0) break;
}
file_c += (long)n;
for(p = gg.s_readbuf; n; n--, p++){
if(*p == '\n') file_l++;
if(!word_cont){
if(!is_space(*p)){
word_cont++;
file_w++;
}
} else {
if(is_space(*p)) word_cont = 0;
}
}
}
wcout(gg.print_line, file_l);
wcout(gg.print_word, file_w);
wcout(gg.print_char, file_c);
gg.total_l += file_l;
gg.total_w += file_w;
gg.total_c += file_c;
}
void wcout(int flg, unsigned long n)
{
if (flg) {
char buf[16];
_snprintf(buf, sizeof(buf), "%8ld ", n);
cwFputs(buf, NULL);
}
}
int wc_usage(void)
{
cwFputs("Usage: wc [-lwc] [files...]\n", (LPSTR)-1);
return 1;
}
/*------------*/
/* which_main */
/*------------*/
char *convert(char *s)
{
if(gg.msdos_format)
return s;
return s_conv_to_unix_format(s);
}
void print_found(char *string)
{
cwFputs(convert(string), NULL);
cwFputs("\n", NULL);
gg.found = 1;
}
void which_expand(char *buf, char *path, char *file, char *ext)
{
if(path[strlen(path) - 1] == '\\'){
_snprintf(buf, 1024, "%s%s%s", path, file, ext);
} else {
_snprintf(buf, 1024, "%s\\%s%s", path, file, ext);
}
}
int search_file(char *path, char *file)
{
char buf[1024];
int found_p = 0;
if(strchr(file, '.')){
/* FILE already had the extention. */
which_expand(buf, path, file, "");
if(!access(buf, 0)){
print_found(buf);
found_p = 1;
if(!gg.display_all)
return 1;
}
} else {
which_expand(buf, path, file, ".com");
if(!access(buf, 0)){
print_found(buf);
found_p = 1;
if(!gg.display_all)
return 1;
}
which_expand(buf, path, file, ".exe");
if(!access(buf, 0)){
print_found(buf);
found_p = 1;
if(!gg.display_all)
return 1;
}
which_expand(buf, path, file, ".bat");
if(!access(buf, 0)){
print_found(buf);
found_p = 1;
if(!gg.display_all)
return 1;
}
}
return found_p;
}
void pathscan_start(char *path_variable)
{
gg.path_scanned = path_variable;
}
char *pathscan(void)
{
char *pathend;
if(gg.path_scanned == 0)
return 0;
pathend = strchr(gg.path_scanned, ';');
if(pathend){
strncpy(gg.s_buf2, gg.path_scanned, pathend - gg.path_scanned);
gg.s_buf2[pathend - gg.path_scanned] = '\0';
} else
strcpy(gg.s_buf2, gg.path_scanned);
if(pathend){
gg.path_scanned = pathend + 1;
if(*gg.path_scanned == '\0'){
gg.path_scanned = 0;
}
} else
gg.path_scanned = 0;
return gg.s_buf2;
}
int which_usage(void)
{
cwFputs("which [-am] commandname...\n", (LPSTR)-1);
return 1;
}
void which_a_file(char *commandname, char*pathlist)
{
int found = 0;
if(search_file(".", commandname)){
found = 1;
if(!gg.display_all)
return;
}
pathscan_start(pathlist);
{
char *one_path;
while(one_path = pathscan()){
if(search_file(one_path, commandname)){
found = 1;
if(!gg.display_all)
return;
}
}
}
if(!found){
char *one_path;
gg.error_code = 1;
cwFputs(commandname, NULL); cwFputs(" not found in . ", NULL);
pathscan_start(pathlist);
while(one_path = pathscan()){
cwFputs(convert(one_path), NULL);
cwFputs(" ", NULL);
}
cwFputs("\n", NULL);
}
}
int which_main(int argc, char **argv)
{
char *getenv(), *path;
// extern int optind, opterr;
int option;
int errorcode = 0;
gg.opterr = 0;
path = getenv("PATH");
if(path == 0){
cwFputs("Variable PATH not set\n", (LPSTR)-1);
return 1;
}
while((option = getopt(argc, argv, "am")) != EOF){
switch (option){
case 'a':
gg.display_all = 1;
break;
case 'm':
gg.msdos_format = 1;
break;
default:
return which_usage();
}
}
if(argc == gg.optind)
return which_usage();
while(gg.optind < argc){
which_a_file(argv[gg.optind], path);
gg.optind++;
}
return errorcode;
}
/*---------------*/
/* unexpand_main */
/*---------------*/
int charstockinit(struct charstock *p)
{
if(NULL == (p->buf = malloc(p->bufsiz = 100))){
_putnomemmes();
MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
// exit(1);
}
/* bufposを0にはしない */
return 0;
}
int charstockend(struct charstock *p)
{
if (p->buf != NULL) free(p->buf); p->buf = NULL;
return 0;
}
void stockchar(char c, struct charstock *p) /* 失敗時非0 */
{
unsigned int i;
if((i = p -> bufpos) >= p -> bufsiz){
if(NULL == (p -> buf = realloc(p -> buf, p -> bufsiz += 100))){
_putnomemmes();
MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
// exit(1);
}
}
p -> buf[i] = c;
p -> bufpos = ++i;
}
int unexpand_usage(void)
{
cwFputs("Usage: unexpand [-aks] [-tablist] [file...]\n", (LPSTR)-1);
return 1;
}
int unexpand_do_opt(char *opt)
{
int tabidx = 0, prevcol = 0;
for(;;){
if(tabidx == COLLISTMAX - 1){
cwFputs("Tabstop list too long\n", (LPSTR)-1);
return 1;
}
gg.tabcols[tabidx] = atoi(opt);
if(prevcol >= gg.tabcols[tabidx]){
cwFputs("Bad tab stop spec\n", (LPSTR)-1);
return 1;
} else {
prevcol = gg.tabcols[tabidx++];
}
while(is_digit(*opt)) opt++;
if(!*opt) break;
if(*opt++ != ',') {
unexpand_usage();
return 1;
}
}
gg.tabcols[tabidx] = 0;
gg.tabcol = (gg.tabcols[1] ? 0 : gg.tabcols[0]);
return 0;
}
int unexpand_main(int ac, char **av)
{
FILE *inf;
ac--, av++;
while(ac && av[0][0] == '-' && av[0][1]){
char *p;
for(p = *av + 1; *p && !is_digit(*p); p++){
switch(*p){
case 'k':
gg.kspc = 1; break;
case 's':
gg.elimsp = 1; break;
case 'a':
gg.unexpall = 1; break;
default:
return unexpand_usage();
}
}
if(*p) {
if (unexpand_do_opt(p) != 0) {
return 1;
}
}
ac--, av++;
}
if(!ac){
unexpand(NULL);
} else {
for(; ac; ac--, av++){
if(av[0][0] == '-' && !av[0][1]){
unexpand(NULL);
} else {
if(NULL == (inf = fopen(*av, "r"))){
cwFputs(s_conv_to_unix_format(*av),
(LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
return 1;
}
unexpand(inf);
fclose(inf);
}
}
}
return 0;
}
void outspc(struct spinfo *spdatp, char **ppo)
{
char *p;
int i, pos, tabpos, tabidx, origpos;
stockchar('\0', &spdatp -> sptabseq);
origpos = tabpos = pos = spdatp -> pos, tabidx = spdatp -> tabidx;
p = spdatp -> sptabseq . buf;
do{
if(*p == ' '){
pos++;
if(!gg.unexpall && origpos){
*(*ppo)++ = ' ', tabpos++;
}
continue;
}
/* else *p must be '\t' or '\0' */
if(gg.tabcol){
while((i = (tabpos / gg.tabcol + 1) * gg.tabcol) <= pos){
*(*ppo)++ = (i - tabpos > 1) ? '\t' : ' ';
tabpos = i;
}
if(*p == '\t'){
pos = tabpos = (tabpos / gg.tabcol + 1) * gg.tabcol;
/* previously pos = (tabpos += tabcol); */
*(*ppo)++ = '\t';
} else {
for(; tabpos < pos; tabpos++) *(*ppo)++ = ' ';
}
} else {
while((i = gg.tabcols[tabidx]) > 0 && i <= tabpos)
tabidx++;
/* now i == tabcols[tabidx] and tabcols[tabidx - 1] is
the maximum tabcol <= tabpos */
if(i){
while((i = gg.tabcols[tabidx]) > 0 && i <= pos){
*(*ppo)++ = (i - tabpos > 1) ? '\t' : ' ';
tabpos = i;
tabidx++;
}
/* tabcols[tabidx - 1] is always kept
< current pos (if tabidx > 0) */
}
if(!i){
for(; tabpos < pos; tabpos++) *(*ppo)++ = ' ';
if(*p == '\t'){
*(*ppo)++ = '\t';
pos = ++tabpos;
}
} else {
if(*p == '\t'){
*(*ppo)++ = '\t';
pos = tabpos = i;
} else {
for(; tabpos < pos; tabpos++)
*(*ppo)++ = '\t';
}
}
}
} while(*p++);
spdatp -> sptabseq . bufpos = 0;
spdatp -> pos = pos, spdatp -> tabidx = tabidx;
}
void unexpand(FILE *f)
{
int c, d;
char bufi[0x100];
char bufo[0x100];
char *pi;
char *po;
if(gg.s_first){
charstockinit(&gg.s_sppresv.sptabseq);
gg.s_first = 0;
} /* sptabseq . buf には ' ' か '\t' ばかりが入っていく */
gg.s_sppresv.pos = gg.s_sppresv.tabidx = gg.s_sppresv.sptabseq.bufpos = 0;
while (TRUE) {
if (f == NULL) {
if (cwFgets(bufi, 0xFF, NULL) == NULL) break;
} else {
if (fgets(bufi, 0xFF, f) == NULL) break;
}
bufi[0xFF] = '\0';
po = bufo;
for (pi = bufi; *pi != '\0'; pi++) {
c = *pi;
if(iskanji(c)){
if('\0' == (d = *(++pi))){
outspc(&gg.s_sppresv, &po);
*po++ = c;
pi--;
continue;
}
if(gg.kspc && ((c << 8) | d) == KSPC &&
(gg.unexpall || !gg.s_sppresv.pos)){
stockchar(' ', &gg.s_sppresv.sptabseq);
stockchar(' ', &gg.s_sppresv.sptabseq);
} else {
outspc(&gg.s_sppresv, &po);
*po++ = c; *po++ = d;
gg.s_sppresv.pos += 2;
}
} else if(c == '\b'){
*po++ = c, gg.s_sppresv.pos--;
if(gg.s_sppresv.tabidx)
gg.s_sppresv.tabidx--; /* 最高1つ戻せばよい */
} else if(c == '\n' || c == '\r' || c == '\f'){
if(!gg.elimsp) outspc(&gg.s_sppresv, &po);
*po++ = c;
gg.s_sppresv.pos = gg.s_sppresv.tabidx =
gg.s_sppresv.sptabseq.bufpos = 0;
} else if(c == '\t' || c == ' '){
stockchar((char)c, &gg.s_sppresv . sptabseq);
} else {
outspc(&gg.s_sppresv, &po);
*po++ = c, gg.s_sppresv.pos++;
}
}
*po = '\0';
cwFputs(bufo, NULL);
}
if(!gg.elimsp) outspc(&gg.s_sppresv, &po);
charstockend(&gg.s_sppresv.sptabseq);
}
/*----------*/
/* cmp_main */
/*----------*/
/* exit: 0=same, 1=diff, 2=error */
int cmp_usage(void)
{
cwFputs("Usage: cmp [-ls] file1 file2\n", (LPSTR)-1);
cwFputs("-l : report all differences\n", (LPSTR)-1);
cwFputs("-s : return code only\n", (LPSTR)-1);
return 2;
}
FILE *argfopen(char *s)
{
register FILE *f;
if(*s == '-' && !s[1]){
f = NULL;
} else {
if(NULL == (f = fopen(s, "rb"))){
cwFputs(conv_to_unix_format(s), (LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
return NULL;
}
}
return f;
}
#if 0
void expand_control()
{
_expand_abendcode = 2;
}
#endif
int cmp_main(int ac, char **av)
{
// extern int optind, opterr;
int c;
char all = 0, silent = 0;
gg.opterr = 0;
while(EOF != (c = getopt(ac, av, "ls"))){
switch(c){
case 'l': all = 1; break;
case 's': silent = 1; break;
default: return cmp_usage();
}
}
ac -= gg.optind, av += gg.optind;
if(ac != 2) return cmp_usage();
if(silent) {
return s_cmp(av[0], av[1]);
} else if(all) {
return a_cmp(av[0], av[1]);
} else {
return cmp(av[0], av[1]);
}
}
int s_cmp(char *s, char *t)
{
register FILE *f = argfopen(s), *g = argfopen(t);
register int c;
int status;
if (f == NULL || g == NULL) {
status = 2;
goto end;
}
status = 1;
while(c = getc(f), c == getc(g)) {
if(c == EOF) {
status = 0;
break;
}
}
end:
if (f != NULL) fclose(f);
if (g != NULL) fclose(g);
return status;
}
int a_cmp(char *s, char *t)
{
FILE *f = argfopen(s), *g = argfopen(t);
char status = 0;
long pos = 0;
register int c, d;
char buf[0x100];
if (f == NULL || g == NULL) {
status = 2;
goto end;
}
while(c = getc(f), d = getc(g), pos++, c != EOF && d != EOF){
if(c == d) continue;
status = 1;
sprintf(buf, "%6ld %3o %3o\n", pos, c, d);
cwFputs(buf, NULL);
}
if(d != EOF){
sprintf(buf, eofmsg, s);
cwFputs(buf, NULL);
status = 1;
} else if(c != EOF){
sprintf(buf, eofmsg, t);
cwFputs(buf, NULL);
status = 1;
}
end:
if (f != NULL) fclose(f);
if (g != NULL) fclose(g);
return status;
}
int cmp(char *s, char *t)
{
FILE *f = argfopen(s), *g = argfopen(t);
long pos = 0, line = 1;
register int c, d;
int status;
char buf[0x100];
if (f == NULL || g == NULL) {
status = 2;
goto end;
}
for(; c = getc(f), d = getc(g), pos++, c == d; c == '\n' && line++){
if(c == EOF) {
status = 0;
goto end;
}
}
if(c == EOF){
sprintf(buf, eofmsg, s);
cwFputs(buf, NULL);
} else if(d == EOF){
sprintf(buf, eofmsg, t);
cwFputs(buf, NULL);
} else {
sprintf(buf, "%s %s differ: char %ld, line %ld\n", s, t, pos, line);
cwFputs(buf, NULL);
}
status = 1;
end:
if (f != NULL) fclose(f);
if (g != NULL) fclose(g);
return status;
}
/*------------*/
/* split_main */
/*------------*/
int split_usage(void)
{
cwFputs("split [-fv] [-b[0][x]n[k]] [-lines] file [basename]\n", (LPSTR)-1);
return 1;
}
int chknon0num(char *s)
{
int i = 0;
for(; is_digit(*s); s++){
i *= 10; i += ctoi(*s);
}
return *s ? 0 : i;
}
int chkxknon0lnum(char *s)
{
long l = 0L;
if(*s == '0'){
if(s++, *s == 'x' || *s == 'X') goto hex;
for(; is_octal(*s); s++){
l <<= 3; l += ctoi(*s);
}
} else if(*s == 'x' || *s == 'X'){
hex:
for(s++; is_xdigit(*s); s++){
l <<= 4; l += ctoi(*s);
}
} else {
for(; is_digit(*s); s++){
l *= 10; l += ctoi(*s);
}
}
return *s == 'k' || *s == 'K' ? l << 10 : *s ? 0L : l;
}
int split_main(int ac, char **av)
{
int flag = 0; /* 1:force 2:binary 4:visual */
int linemax = 1000;
long bytemax = 0L;
FILE *inf;
int ret;
ac--, av++;
for(; ac && av[0][0] == '-' && av[0][1]; ac--, av++){
char *p;
for(p = av[0] + 1; *p; p++){
if(0 != chknon0num(p)){
/* flag &= ~OPT_BINARY; */
linemax = chknon0num(p);
break;
} else if(*p == 'b'){
if(0L != chkxknon0lnum(++p)){
flag |= OPT_BINARY;
bytemax = chkxknon0lnum(p);
} else {
return split_usage();
}
break;
} else if(*p == 'f'){
flag |= OPT_FORCE;
} else if(*p == 'v'){
flag |= OPT_VISUAL;
} else {
return split_usage();
}
}
}
switch(ac){
case 0:
inf = NULL; break;
case 2:
if(strlen(av[1]) > PATHNAMELENGTH - 5) {
/* need 5 more spaces to put in ".aaa\0" */
conv_to_unix_format(av[1]);
cwFputs(av[1], (LPSTR)-1);
cwFputs(": basename too long\n", (LPSTR)-1);
return 1;
}
strcpy(gg.s_base, av[1]);
/* through */
case 1:
if(av[0][0] == '-' && !av[0][1]){
inf = NULL;
} else {
if(NULL == (inf = fopen(*av, ((flag & OPT_BINARY) == 0) ?
"r" : "rb"))) {
return cantopen(*av);
}
}
break;
default:
return split_usage();
}
conv_to_unix_format(gg.s_base);
ret = do_split(flag, linemax, bytemax, inf, gg.s_base);
if (inf != NULL) fclose(inf);
return ret;
}
int fexist(char *s)
{
struct stat sbuf;
return(stat(s, &sbuf) == 0);
}
FILE *fopen_nonexchk(int flag, char *n, char *m)
/* nはあらかじめconv_to_unix_formatされているものとする */
{
FILE *retf;
if(!(flag & OPT_FORCE) && fexist(n)){
cwFputs(n, (LPSTR)-1), cwFputs(": exist\n", (LPSTR)-1);
return NULL;
}
if(NULL == (retf = fopen(n, m))) {
cantopen(n);
return NULL;
}
if(flag & OPT_VISUAL){
cwFputs(n, (LPSTR)-1), cwFputs(":\n", (LPSTR)-1);
}
return retf;
}
int do_split(int flag, int linemax, long bytemax, FILE *inf, char *base)
{
int ret = 0;
register FILE *otf = NULL;
char *ext;
int lines = 0;
long bytes = 0L;
if(NULL == gg.s_readbuf2 && NULL == (gg.s_readbuf2 = malloc(RBUFSIZ))){
_putnomemmes();
ret = 1; goto EXIT;
}
ext = base + strlen(base);
strcpy(ext++, ".aaa");
if(flag & OPT_BINARY){
int rdbyte, wrbyte;
if (inf == NULL) {
ret = 1; goto EXIT;
}
for(;;){
rdbyte = (int)imin(bytemax - bytes, (long)RBUFSIZ);
/* RBUFSIZがintだからlongになることはない */
rdbyte = fread(gg.s_readbuf2, 1, rdbyte, inf);
if(rdbyte <= 0) break;
if(NULL == otf){
otf = fopen_nonexchk(flag, base, "wb");
if (otf == NULL ) {
ret = 1; goto EXIT;
}
/* write()だからwbの必要はない…か? */
if (nextext(ext) != 0) {
ret = 1; goto EXIT;
}
}
wrbyte = fwrite(gg.s_readbuf2, 1, rdbyte, otf);
if(wrbyte < rdbyte){ /* wrbyte == -1 を含む */
writefail();
ret = 1; goto EXIT;
}
if(bytemax > (bytes += wrbyte)) continue;
bytes = 0;
if(fclose(otf) == EOF) {
writefail();
ret = 1; goto EXIT;
}
otf = NULL;
}
} else {
while(((inf == NULL) ? cwFgets(gg.s_readbuf2, BUFSIZ, NULL) :
fgets(gg.s_readbuf2, BUFSIZ, inf)) != NULL) {
if(otf == NULL){
otf = fopen_nonexchk(flag, base, "w");
if (otf == NULL ) {
ret = 1; goto EXIT;
}
if (nextext(ext) != 0) {
ret = 1; goto EXIT;
}
}
if(EOF == fputs(gg.s_readbuf2, otf)) {
writefail();
ret = 1; goto EXIT;
}
if(!*gg.s_readbuf2 ||
gg.s_readbuf2[strlen(gg.s_readbuf2 + 1)] != '\n' ||
++lines < linemax) continue;
lines = 0;
if(fclose(otf) == EOF) {
writefail();
ret = 1; goto EXIT;
}
otf = NULL;
}
}
EXIT:
if (otf != NULL) fclose(otf); otf = NULL;
if (gg.s_readbuf2 != NULL) free(gg.s_readbuf2); gg.s_readbuf2 = NULL;
return ret;
}
int nextext(char *ext)
{
int i = 3;
while(i--){
if(++ext[i] <= 'z') return 0;
ext[i] = 'a';
}
cwFputs("Too many output files\n", (LPSTR)-1);
return 1;
}
int cantopen(char *s)
{
conv_to_unix_format(s);
cwFputs(s, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
return 1;
}
int writefail(void)
{
cwFputs("Write failed (disk full?)\n", (LPSTR)-1);
return 1;
}
/*----------*/
/* cal_main */
/*----------*/
#include <time.h>
/* caldate(y1,m1,d1) - caldate(y2,m2,d2) で y1年m1月d1日からy2年m2月d2日までの
日数が計算できる。caldate(y,m,d) % 7 で曜日も求まる(0が日曜、6が土曜)。
1752年9月以前でも大丈夫な版 */
long caldate(int y, int m, int d)
{
long ly;
if(m <= 2)(y--, m += 12);
d += (306 * m + 17) / 10;
if((((ly = y) << 9) | d) < ((1752L << 9) | 291)){
y = 1752, d += 11; /* 1752年9月2日の次は14日 */
}
return ly * 1461 / 4 - y / 100 + y / 400 + d;
}
int bad(void)
{
cwFputs("Bad argument\n", (LPSTR)-1);
return 1;
}
/* output routines */
int fputs_so(char *s)
{
return cwFputs(s, NULL);
}
void putchar_n(int n, int c)
{
char buf[0x101];
int i;
for (i = 0; i < n; i++) {
buf[i % 0x100] = c;
if (i % 0x100 == 0xFF) {
buf[i % 0x100 + 1] = '\0';
cwFputs(buf, NULL);
}
}
buf[i % 0x100] = '\0';
cwFputs(buf, NULL);
}
void putint(int n)
{
char buf[0x10];
sprintf(buf, "%d", n);
cwFputs(buf, NULL);
}
void putday(int n) /* width 2 */
{
char buf[0x8];
sprintf(buf, "%2d", n);
cwFputs(buf, NULL);
}
void shortmonth(int m)
{
char buf[0x8];
strncpy(buf, monthname[m], 3); buf[3] = '\0';
cwFputs(buf, NULL);
}
int cal_main(int ac, char **av)
{
switch(ac){
case 3: /* cal m y */
return calym(atoi(av[2]), atoi(av[1]));
case 2: /* cal y */
return caly(atoi(av[1]));
case 1: /* this month */
return cal();
default:
cwFputs("Usage: cal [[month] year]\n", (LPSTR)-1);
return 1;
}
return 0;
}
void getmonthdays(int year, int month, char *days, char *d_of_w)
{ /* その月の日数とついたちの曜日を求める */
long temp;
temp = caldate(year, month, 1);
*d_of_w = (int)(temp % 7);
if(++month > 12) (year++, month = 1);
*days = (int)(caldate(year, month, 1) - temp);
}
int cal(void)
{
struct tm *dt;
long tt;
time(&tt);
dt = localtime(&tt);
return calym(dt -> tm_year + 1900, dt -> tm_mon + 1);
}
int calym(int year, int month)
{
int i;
unsigned char d_of_w, days;
if(year <= 0 || month < 1 || 12 < month) return bad();
putchar_n(3, ' '); fputs_so(monthname[month]); cwFputs(" ", NULL);
putint(year);
cwFputs("\n", NULL), fputs_so(dofw_title), cwFputs("\n", NULL);
getmonthdays(year, month, &days, &d_of_w);
for(i = 0; i < 6; i++){
calrow(year, month, days, d_of_w, i, 1);
cwFputs("\n", NULL);
}
return 0;
}
int caly(int year)
{
int i, j, k, m;
unsigned char days[3], d_of_w[3];
if(year <= 0) return bad();
fputs_so("\n\n\n\t\t\t\t"), putint(year);
putchar_n(2, '\n');
for(i = 0; i < 4; i++){
for(k = -2; k < 6; k++){
for(j = 0; j < 3; j++){
m = i * 3 + j + 1;
switch(k){
case -2:
putchar_n(9, ' ');
shortmonth(m);
j == 2 ? cwFputs("\n", NULL) :
putchar_n(11, ' ');
break;
case -1:
fputs_so(dofw_title);
getmonthdays(year, m,
&days[j], &d_of_w[j]);
goto common;
default:
calrow(year, m, days[j], d_of_w[j],
k, j == 2);
common:
j == 2 ? cwFputs("\n", NULL) :
putchar_n(3, ' ');
break;
}
}
}
}
putchar_n(3, '\n');
return 0;
}
void calrow(int year, int month, int days, int d_of_w, int row, int eolsup)
{ /* 1752年9月に注意 */
int i, d;
for(i = 0; i < 7; i++){
d = row * 7 + i + 1 - d_of_w;
if(days < d){
if(eolsup) break; else d = 0;
}
if(i) cwFputs(" ", NULL);
if(d < 1){
putchar_n(2, ' ');
} else {
if(year == 1752 && month == 9 && d > 2) d += 11;
putday(d);
}
}
}
/*----------*/
/* cat_main */
/*----------*/
int iskana(int c)
{
if(gg.s_flag < 0) gg.s_flag = iskanji(0x81); /* don't omit this */
return gg.s_flag && ((c &= 0xff), (0xa1 <= c && c <= 0xdf));
}
int cat_usage(void)
{
cwFputs("cat [-vnNtTg] file\n"
"-v : display unprintable characters.\n"
"-n : put linenumbers(reset for each file).\n"
"-N : put linenumbers.\n"
"-t : text mode input/output.\n"
"-T : text mode input.\n",
(LPSTR)-1);
return 1;
}
void cat_out(FILE *f)
{
if(gg.Num == 0){
gg.lineno = 0L;
if(!gg.lasteol){
if(!gg.otxt) cwFputs("\r", NULL);
cwFputs("\n", NULL);
gg.lasteol = 1;
}
}
gg.vis ? outv(f) : gg.num ? outn(f) : outb(f);
}
void outv(FILE *f) /* fはこの関数内で全部読み尽くす */
{
int c, d;
char bufi[0x100], bufo[0x200 + 8];
char *pi, *po;
while (((f == NULL) ? cwFgets(bufi, 0x100, NULL) :
fgets(bufi, 0x100, f)) != NULL) {
bufi[0xFF] = '\0';
po = bufo;
for (pi = bufi; *pi != '\0'; pi++) {
c = *pi;
if(gg.lasteol){
if(gg.num) {
longintout(7, ++gg.lineno, &po);
*po++ = ' ';
}
gg.lasteol = 0;
}
if(c == '\n'){
gg.lasteol = 1;
goto out1b;
} else if(isprint(c) || c == '\t' || iskana(c)){
goto out1b;
} else if(isascii(c)){
goto outctrl;
} else if(iskanji(c)){
pi++; d = *pi;
if(d == '\0'){
goto outmeta;
} else if(!iskanji2(d)){
pi--;
goto outmeta;
} else {
goto out2b;
}
} else {
outmeta:
*po++ = 'M'; *po++ = '-';
c = toascii(c);
if(isprint(c)) goto out1b;
outctrl:
d = toascii('@' + c), c = '^';
out2b:
*po++ = c; c = d;
out1b:
*po++ = c;
if (*pi == '\0') {
break;
}
}
}
*po++ = '\0';
cwFputs(bufo, NULL);
}
}
void outn(FILE *f)
{
char buf[0x100];
char bufline[0x10];
while (((f == NULL) ? cwFgets(buf, 0x100, NULL) :
fgets(buf, 0x100, f)) != NULL) {
if(gg.lasteol){
sprintf(bufline, "%7d ", ++gg.lineno);
cwFputs(bufline, NULL);
gg.lasteol = 0;
}
cwFputs(buf, NULL);
gg.lasteol = (buf[lstrlen(buf) - 1] == '\n');
}
}
void outb(FILE *f)
{
char buf[0x100];
while (((f == NULL) ? cwFgets(buf, 0x100, NULL) :
fgets(buf, 0x100, f)) != NULL) {
cwFputs(buf, NULL);
}
}
void longintout(int w, unsigned long n, char **ppo)
{
int i;
unsigned long m;
memset(*ppo, ' ', w);
for (i = 1, m = n; m > 0; i++, m /= 10);
sprintf(*ppo + w - i, "%d", n);
**ppo += w;
}
int cat_main(int ac, char **av)
{
int c, status = 0;
FILE *f;
// extern int optind, opterr;
// extern char *optarg;
gg.opterr = 0;
while(EOF != (c = getopt(ac, av, "vnNtTg"))){
switch(c){
case 'v':
gg.otxt = gg.vis = 1; break;
case 'n':
gg.num = 1; break;
case 'N':
gg.num = gg.Num = 1; break;
case 't':
gg.otxt = 1; /* through */
case 'T':
gg.itxt = 1; break;
default:
return cat_usage();
}
}
av += gg.optind, ac -= gg.optind;
if(ac){
char *p;
for(; p = *av, ac; ac--, av++){
if(*p == '-' && !p[1]){
cat_out(NULL);
} else {
if(NULL == (f = fopen(p, gg.itxt ? "r" : "rb"))){
cwFputs(conv_to_unix_format(p), (LPSTR)-1);
/* 支障ないはず */
cwFputs(": Can't open\n", (LPSTR)-1);
status = 1;
} else {
cat_out(f);
fclose(f);
}
}
}
} else {
cat_out(NULL);
}
return status;
}
/*-----------*/
/* date_main */
/*-----------*/
/* Usage: cdate [[[[mm]dd]hh]mm[[.ss][yy]] [+format] */
int date_main(int ac, char **av)
{
switch(ac){
case 3:
if (mod_disp_time(av[1], av[2]) != 0) return 1;
break;
case 2:
if(*av[1] != '+'){
if (mod_disp_time(av[1], NULL) != 0) return 1;
} else {
if (mod_disp_time(NULL, av[1]) != 0) return 1;
}
break;
case 1:
if (mod_disp_time(NULL, NULL) != 0) return 1;
break;
default:
return date_usage();
}
return 0;
}
int date_usage(void)
{
cwFputs("Usage: cdate [[[[mm]dd]hh]mm[[.ss][yy]] [+format]\n", (LPSTR)-1);
return 1;
}
#if 0
/* caldate(y1,m1,d1) - caldate(y2,m2,d2) で y1年m1月d1日からy2年m2月d2日までの
日数が計算できる。caldate(y,m,d) % 7 で曜日も求まる(0が日曜、6が土曜)*/
long caldate(int y, int m, int d)
/* 特例: mが13なら翌年1月とみなされる dは0でも大丈夫 */
{
if(m <= 2)(y--, m += 12);
return (long)y * 1461 / 4 - y / 100 + y / 400 +
(306 * m + 17) / 10 + d;
}
#endif
int chkdatearg(char *s, int *l1p, char **dsp, int *l2p)
{
char *p;
for(p = s; *p && *p != '.'; p++) {
if (is_digit(*p) == 0) {
return illdate();
}
}
*l1p = p - s;
if(*p){
for(*dsp = s = ++p; *p; p++) {
if (is_digit(*p) == 0) {
illdate();
}
}
*l2p = p - s;
} else {
*l2p = 0, *dsp = NULL;
}
return 0;
}
// #define ctoi(c) ((c) - '0') /* cが数字文字であるとわかっている時 */
int badfmt(void)
{
cwFputs("Bad format character\n", (LPSTR)-1);
return 1;
}
int illdate(void)
{
cwFputs("Bad conversion\n", (LPSTR)-1);
return 1;
}
int scan2int(char *s) /* s以降2桁が数字のみだとわかっている時 */
{
return ctoi(*s) * 10 + ctoi(s[1]);
}
int mod_disp_time(char *newt, char *fmt)
{
int y, m, d, w, h, mi, s;
SYSTEMTIME st;
GetLocalTime(&st);
y = st.wYear;
m = st.wMonth;
d = st.wDay;
h = st.wHour;
mi = st.wMinute;
s = st.wSecond;
w = st.wDayOfWeek;
if(newt != NULL){
int l1, l2;
long ymd;
char *auxarg;
s = 0;
if (chkdatearg(newt, &l1, &auxarg, &l2) != 0) return 1;
switch(l1){
case 12:
s = scan2int(newt + 8);
/* through */
case 10:
y = -scan2int(newt + l1 - 2);
/* through */
case 8:
m = scan2int(newt), newt += 2;
/* through */
case 6:
d = scan2int(newt), newt += 2;
/* through */
case 4:
h = scan2int(newt), newt += 2;
/* through */
case 2:
mi= scan2int(newt);
break;
default:
return illdate();
}
if(auxarg != NULL){
if(l1 > 8) return illdate();
switch(l2){
case 4:
y = -scan2int(auxarg + 2);
/* through */
case 2:
s = scan2int(auxarg);
break;
default:
return illdate();
}
}
if(y <= 0) st.wYear = y = (y <= -80 ? 1900 : 2000) - y;
w = (int)(ymd = caldate(y, m, d)) % 7;
st.wMonth = m, st.wDay = d, st.wHour = h;
st.wMinute = mi, st.wSecond = s;
if(!(1 <= m && m <= 12 &&
1 <= d && ymd < caldate(y, m + 1, 1) &&
/* caldateの13月特例 */
0 <= h && h < 24 &&
0 <= mi && mi < 60 &&
0 <= s && s < 60)) {
return illdate();
}
SetLocalTime(&st);
}
if (disptime(fmt, y, m, d, h, mi, s, w) != 0) return 1;
cwFputs("\n", NULL);
return 0;
}
void strout(char *s, int n) /* -1にすれば事実上無限大になる */
{
char cStack;
if (n >= 0) {
cStack = s[n]; s[n] = '\0';
}
cwFputs(s, NULL);
if (n >= 0) {
s[n] = cStack;
}
}
void intoutz(int i, int n) /* n>0のこと */
{
char *buf;
int col;
int num;
buf = malloc(n + 1);
if (buf == NULL) {
return;
}
memset(buf, '0', n);
buf[n] = '\0';
num = i / 10;
for (col = 1; num > 0; col++, num /= 10);
if (col > n) col = n;
_snprintf(buf + n - col, n, "%d", i);
cwFputs(buf, NULL);
free(buf);
}
void date_intout(int i, int n) /* n>0のこと */
{
char *buf;
int col;
int num;
buf = malloc(n + 1);
if (buf == NULL) {
return;
}
memset(buf, ' ', n);
buf[n] = '\0';
num = i / 10;
for (col = 1; num > 0; col++, num /= 10);
if (col > n) col = n;
_snprintf(buf + n - col, n, "%d", i);
cwFputs(buf, NULL);
free(buf);
}
void Putchar(char c)
{
char buf[0x2];
buf[0] = c; buf[1] = '\0';
cwFputs(buf, NULL);
}
int disptime(char *fmt, int y, int m, int d, int h, int mi, int s, int w)
/* %はSJISの2バイト目にならないので漢字に特段の配慮は不要 */
{
if(fmt == NULL){
return disptime("+%c", y, m, d, h, mi, s, w);
} else if(*fmt++ != '+'){
return badfmt();
}
for(; *fmt; fmt++){
if(*fmt != '%'){
Putchar(*fmt);
continue;
}
switch(*++fmt){
case '%': Putchar('%'); break;
case 'n': Putchar('\n'); break;
case 't': Putchar('\t'); break;
case 'A': strout(dofwkname[w], -1); break;
case 'B': strout(monthname[m], -1); break;
case 'D': disptime("+%m/%d/%y", y, m, d, 0, 0, 0, 0); break;
case 'H': intoutz(h, 2); break;
case 'I': intoutz((h + 11) % 12 + 1, 2); break;
case 'M': intoutz(mi, 2); break;
case 'S': intoutz(s, 2); break;
case 'T':
case 'X': disptime("+%H:%M:%S", 0, 0, 0, h, mi,s, 0); break;
case 'Y': intoutz(y, 4); break;
case 'a': strout(dofwkname[w], 3); break;
case 'b':
case 'h': strout(monthname[m], 3); break;
case 'c': disptime("+%a %b %e %T %Y", y, m, d, h, mi, s, w); break;
case 'd': intoutz(d, 2); break;
case 'e': date_intout(d, 2); break;
case 'j': intoutz(caldate(y, m, d) - caldate(y, 1, 0), 3); break;
case 'm': intoutz(m, 2); break;
case 'p': cwFputs(h < 12 ? "AM" : "PM", NULL); break;
case 'r': disptime("+%I:%M:%S %p", 0, 0, 0, h, mi,s, 0); break;
case 'w': intoutz(w, 1); break;
case 'x': disptime("+%a %b %e %Y", y, m, d, 0, 0, 0, w); break;
case 'y': intoutz(y % 100, 2); break;
default:
return badfmt();
}
}
return 0;
}
/*---------*/
/* rm_main */
/*---------*/
/**
'rm':UNIX-like file delete utility for MS-DOS machines.
89.03.02 ver 1.0 Yasushi Saito, TAIST.
90.10.03 Some cleanups,
supports '.../' notation.
-i asks y/n for all files.
compiled by Microsoft C compiler ver 5.1
changed to LSI-C ver 3.20
rm [options] file1 file2 .. filen
Remove file1, file2, ..., filen
Options:
-r: Remove all files under directory, if specified file is a directory.
-i: Interactive, i.e., ask yes or no when removing files.
-f: Remove readonly files without query.
-v: Verbose message.
Wildcards can be used to give file or directory name ambiguously.
See 'wild.c' for the wildcard specs.
This program is NOT COPYRIGHTED, used, modified, re-distributed
with no restriction,and no warranty.
*/
/*
* Almost same as sprintf(BUF,"%s\\%s",DIR,F), but perform BUF boundary
* check(BUF must be longer than PATHNAMELENGTH bytes), and if DIR ends with
* PD, then does not add PD between DIR and F, as above sprintf does.
*
*/
int yn_p_with_ret(void)
{
char szbuf[0x100];
cwFgets(szbuf, 0x100, NULL);
return (szbuf[0] == 'y' || szbuf[0] == 'Y');
}
void rm_error(char *s, char *pathname)
{
char szbuf[0x100];
if(gg.opt_force) return;
_snprintf(szbuf, sizeof(szbuf), s, s_conv_to_unix_format(pathname));
cwFputs(szbuf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
gg.error_code = 1;
}
void io_error(char *s, char *pathname)
{
char szbuf[0x100];
_snprintf(szbuf, sizeof(szbuf), s, s_conv_to_unix_format(pathname));
cwFputs(szbuf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
// perror(" ");
if(!gg.opt_force) gg.error_code = 1;
}
/*
* Actually remove PATH. PATH is a normal file (not directory).
*/
void remove_file(char *path)
{
char szbuf[0x100];
if(gg.opt_interactive){
_snprintf(szbuf, sizeof(szbuf),
"remove %s ? ", s_conv_to_unix_format(path));
cwFputs(szbuf, (LPSTR)-1);
if(!YES_OR_NO_P()) return;
}
if(remove(path) < 0){
unsigned attr;
if((attr = getattr(path)) == -1){
rm_error("'%s' does not exist.", path);
return;
}
if(attr & 0x10){
rm_error("'%s' is a directory.", path);
return;
}
if(!gg.opt_force){
_snprintf(szbuf,sizeof(szbuf),"override protection %x for %s ? ",
attr, s_conv_to_unix_format(path));
cwFputs(szbuf, (LPSTR)-1);
if(!YES_OR_NO_P()) return;
}
setattr(path, attr & ~7);
if(remove(path) < 0){
io_error("cannot remove '%s'", s_conv_to_unix_format(path));
return;
}
}
if(gg.opt_verbose){
cwFputs(s_conv_to_unix_format(path), (LPSTR)-1);
cwFputs("\n", (LPSTR)-1);
}
}
/*
* Remove all files under the directory S
*
* Same as performing "DEL S\*.*"(S is the parameter) from commandline. Returns
* immediately with files left untouched if failed to chdir S (hence S need
* not a directory, in which case this procedure performs nothing).
*
* Hidden files and readonly files may not be removed by this procedure, so this
* is used as preprocess for whole-directory remove.
*
*/
void delete_all_using_FCB(char *s)
{
return;
#if 0
char szpath[MAX_PATH];
char szfile[MAX_PATH * 2];
long lfind;
struct _finddata_t ftfind;
UINT uErrorOrg;
uErrorOrg = SetErrorMode(SEM_FAILCRITICALERRORS);
strcpy(szpath, s);
_snprintf(szfile, sizeof(szfile), "%s\\%s", szpath, "*.*");
memset(&ftfind, 0, sizeof(ftfind));
ftfind.attrib = _A_NORMAL | _A_SUBDIR;
lfind = _findfirst(szfile, &ftfind);
if (lfind != -1) {
do {
_snprintf(szfile, sizeof(szfile), "%s\\%s", szpath, ftfind.name);
remove(szfile);
} while (_findnext(lfind, &ftfind) == 0);
_findclose(lfind);
}
SetErrorMode(uErrorOrg);
#endif
}
/*
* Delete the file PATH. Delete recursively if PATH is a directory and
* OPT_RECURSIVE option is True.
*/
void r_remove_file(char *path)
{
char szbuf[0x100];
if(!regularize_pathname(path)){
/* PATH does not end with \ */
if(!gg.opt_recursive){
remove_file(path);
return;
}
} else if(!gg.opt_recursive){
rm_error("%s is a directory.", path);
return;
}
/* Delete directory files. */
{
struct _finddata_t f;
char temp[PATHNAMELENGTH];
long hfind;
/* First, perform BDOS file remove for speedups. */
if(!gg.opt_interactive){
if(gg.opt_verbose) {
_snprintf(szbuf, sizeof(szbuf), "%s/*.*\n",
s_conv_to_unix_format(path));
cwFputs(szbuf, (LPSTR)-1);
}
delete_all_using_FCB(path);
}
/*
* Delete remaining files(hidden files, readonly files) by
* searching each files.
*/
_snprintf(temp, sizeof(temp), "%s\\%s", path, "*.*");
memset(&f, 0, sizeof(f));
f.attrib = 0x37;
hfind = _findfirst(temp, &f);
if(hfind == -1){
/*
* unable to interpret PATH as a directory. treat it
* as a plain file, and remove it
*/
remove_file(path);
return;
}
do {
/*
* If the first character of the filename is '.',
* then the filename must be "." or ".." in MSDOS.
*/
if(*(f.name) != '.'){
_snprintf(temp, sizeof(temp), "%s\\%s", path, f.name);
if(f.attrib & 0x10)
r_remove_file(temp);
else
remove_file(temp);
}
} while(_findnext(hfind, &f) == 0);
_findclose(hfind);
if(gg.opt_interactive){
_snprintf(szbuf, sizeof(szbuf), "remove %s/ ? ",
s_conv_to_unix_format(path));
cwFputs(szbuf, (LPSTR)-1);
if(!YES_OR_NO_P()) return;
}
if(rmdir(path) < 0) io_error("cannot remove directory '%s'", path);
if(gg.opt_verbose) {
_snprintf(szbuf, sizeof(szbuf), "%s/\n",
s_conv_to_unix_format(path));
cwFputs(szbuf, (LPSTR)-1);
}
}
}
int rm_main(int argc, char **argv)
{
int c, i;
int getopt();
// extern int optind, opterr;
// extern char *optarg;
conv_char_args(argv, '/', '\\');
gg.opterr = 0;
while((c = getopt(argc, argv, "rvif")) != EOF){
switch (c){
case 'r':
gg.opt_recursive = True;
break;
case 'v':
gg.opt_verbose = True;
break;
case 'i':
gg.opt_interactive = True;
break;
case 'f':
gg.opt_force = True;
break;
default: /* Add Nide */
goto synerr;
}
}
argc -= gg.optind;
argv += gg.optind;
if(argc < 1){
static char *msgs[] = {
"rm [-rfiv] file1 ... filen\n",
"-r : Recursively remove all files under directory\n",
"-f : Remove readonly files without query\n",
"-i : Query before removing\n",
"-v : Verbose message\n",
};
synerr: /* Add Nide */
for(i = 0; i < sizeof(msgs) / sizeof(*msgs); i++)
cwFputs(msgs[i], (LPSTR)-1);
/* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
return 1;
}
for(i = 0; i < argc; i++){
r_remove_file(argv[i]);
}
return gg.error_code;
}
/*-----------*/
/* grep_main */
/*-----------*/
/* fgrep.c兼egrep.c 「#define fgrep」とすればfgrepになる
ファイルの中から、指定した文字列あるいはパターンを含む行を探す。
Usage: {e,f}grep [-chilLnsvx] 文字列 ファイル名…
{e,f}grep [-chilLnsvx] -e 文字列 ファイル名…
{e,f}grep [-chilLnsvx] -f 探索文字列ファイル ファイル名…
-c 指定した文字列を含むファイルについて、その行数のみを報告。
-h 見つけた行を表示するとき、先頭にそのファイル名を出力しない。
ファイルが1つだけの時のデフォルト。
-i 文字列のうち1バイト英字の大文字小文字を区別せずに探す(fgrepのみ)。
-l 指定した文字列を含むファイルの名前だけを(1回ずつ)表示。
-L 見つけた行を表示するとき、先頭にそのファイル名を出力する。
ファイルが複数のときのデフォルト。
-n 見つけた行を表示するとき、先頭にファイル中での行番号を出力。
-s exit statusのみを返し、何も表示しない。
-v 条件反転。指定した文字列を含まない行のみを探索対象にする。
-w 指定したパターンを単語として含む行のみを探索対象にする(egrepのみ)。
-x 指定した文字列と完全に一致する行のみを探索対象にする。
-e 文字列
単に文字列を指定するのと同じだが、「-」で始まる文字列を
探索する場合に使う。こうしないと探索文字列をオプションと
混同するため。
-f ファイル名
fgrepの場合、指定したファイルの最初の行の文字列を探索対象とする。
egrepの場合、指定したファイルの各行のorを探索対象とする。
-f指定の場合、コマンド行で改めて探索文字列を指定しなくていい。
exit statusは、文字列が見つかったら0、見つからなかったら1、
文法エラーなどそれ以外の事態が起きたら2。
*/
char *strichr(char *s, int c)
{
c = to_lower(c);
for(; *s; s++) if((char)to_lower(*s) == (char)c) return(s);
return(NULL);
}
char *getfpat(char *fnm)
{
char *p = NULL, linbuf[MAXLEN];
int linlen;
FILE *f = NULL;
char *pret = NULL;
name_unixnize(fnm);
if(NULL == (f = fopen(fnm, "r"))){
perror(fnm);
pret = NULL; goto EXIT;
}
if(NULL == fgets(linbuf, MAXLEN, f)){
cwFputs(fnm, (LPSTR)-1), cwFputs(": empty\n", (LPSTR)-1);
pret = NULL; goto EXIT;
}
for(;;){
if(!(linlen = strlen(linbuf))){
cwFputs("Empty pattern found\n", (LPSTR)-1);
pret = NULL; goto EXIT;
}
if('\n' == (linbuf - 1)[linlen]){ /* chop newline */
(linbuf - 1)[linlen] = '\0';
} else if(linlen == MAXLEN - 1){
cwFputs(fnm, (LPSTR)-1);
cwFputs(": pattern too long\n", (LPSTR)-1);
pret = NULL; goto EXIT;
}
if(NULL == (p = strdup(linbuf))){
perror("strdup");
pret = NULL; goto EXIT;
} else break;
}
pret = p;
EXIT:
if (f != NULL) fclose(f);
return pret;
}
int grep_main(int ac, char **av)
{
int c;
// extern int optind, opterr;
// extern char *optarg;
char *ptn = NULL;
char *ptnf = NULL;
int nret = 0;
gg.opterr = 0;
/* options: ef xvi s lc hLn */
while(EOF != (c = getopt(ac, av, "ce:f:hilLnsvwx"))){
switch(c){
case 'c': gg.linesonly = 1; break;
case 'e': ptn = gg.optarg; break;
case 'f':
ptn = ptnf = getfpat(gg.optarg);
if (ptn == NULL) {
nret = 2; goto EXIT;
}
break;
case 'h': gg.fnmdisp = 0; break;
case 'i': gg.nocase = 1; break;
case 'l': gg.fnmonly = 1; break;
case 'L': gg.fnmdisp = 1; break;
case 'n': gg.lnumdisp = 1; break;
case 's': gg.retonly = 1; break;
case 'v': gg.reverse = 1; break;
case 'x': gg.wholematch = 1; break;
default:
cwFputs("Illegal option.\n", (LPSTR)-1);
nret = 2; goto EXIT;
}
}
ac -= gg.optind, av += gg.optind;
if(ptn == NULL){
if(!ac--) {
nret = pempty(); goto EXIT;
}
ptn = *av++;
}
if(!*ptn){
nret = pempty(); goto EXIT;
}
if(!ac){
if(gg.fnmdisp == -1) gg.fnmdisp = 0;
if (efgrep(ptn, "-") != 0) {
nret = gg.status; goto EXIT;
}
} else {
if(gg.fnmdisp == -1) gg.fnmdisp = (ac > 1);
for(; ac; ac--, av++){
name_unixnize(*av);
if (efgrep(ptn, *av) != 0) {
nret = gg.status; goto EXIT;
}
}
}
if(gg.linesonly && !gg.fnmonly){
char buf[0x100];
_snprintf(buf, sizeof(buf), "%d\n", gg.totallcount);
cwFputs(buf, NULL);
}
nret = gg.status;
EXIT:
if (ptnf != NULL) free(ptnf);
return nret;
}
int pempty(void)
{
cwFputs("Pattern empty\n", (LPSTR)-1);
return 2;
}
int efgrep(char *ptn, char *fnm)
{
int nret = 0;
register FILE *f = NULL;
char lbuf[MAXLEN];
register char *linbuf = lbuf;
int linlen, lineno = 0, lcount = 0;
char *dispfnm;
int found;
if(fnm[0] == '-' && !fnm[1]){
fnm = NULL;
dispfnm = "(stdin)";
f = NULL;
} else {
if(NULL == (f = fopen(dispfnm = fnm, "r"))){
perror(fnm);
gg.status = 2;
nret = 0; goto EXIT;
}
}
while(((f == NULL) ? cwFgets(linbuf, MAXLEN, NULL) :
fgets(linbuf, MAXLEN, f)) != NULL){
if(linlen = strlen(linbuf)){ /* chop newline */
if('\n' == (linbuf - 1)[linlen]){
(linbuf - 1)[linlen] = '\0';
} else if(linlen == MAXLEN - 1){
cwFputs(dispfnm, (LPSTR)-1);
cwFputs(": too long line\n", (LPSTR)-1);
gg.status = 2;
nret = 2; goto EXIT;
}
}
++lineno;
found = foundline(ptn, linbuf);
if (found == -1) {
nret = 0; goto EXIT;
} else if (found == 1) {
if(gg.linesonly){
lcount++;
continue;
}
if(gg.fnmonly){
cwFputs(dispfnm, NULL);
cwFputs("\n", NULL);
break;
}
if(gg.fnmdisp){
cwFputs(dispfnm, NULL);
cwFputs(": ", NULL);
}
if(gg.lnumdisp){
char buf[0x100];
_snprintf(buf, sizeof(buf), "%d: ", lineno);
cwFputs(buf, NULL);
}
cwFputs(linbuf, NULL), cwFputs("\n", NULL);
}
}
gg.totallcount += lcount;
/* totallcount is only used if (linesonly && !fnmonly) */
if(gg.linesonly && gg.fnmonly && lcount){
char buf[0x400];
_snprintf(buf, sizeof(buf), "%s: %d\n", dispfnm, lcount);
cwFputs(buf, NULL);
}
EXIT:
if(f != NULL) fclose(f);
return nret;
}
int foundline(char *ptn, char *p)
/* 条件に適合するかどうか(すれば非0) */
{
int found;
/* サーチのアルゴリズムははっきり言って安直です */
int cmplen;
if(gg.wholematch){
found = !(gg.nocase ? stricmp(ptn, p) : strcmp(ptn, p));
} else if(gg.nocase){
cmplen = strlen(ptn) - 1;
found = 0;
while(NULL != (p = strichr(p, *ptn))){
if(!strnicmp(++p, ptn + 1, cmplen)){
found = 1;
break;
}
}
} else {
cmplen = strlen(ptn) - 1;
found = 0;
while(NULL != (p = strchr(p, *ptn))){
if(!strncmp(++p, ptn + 1, cmplen)){
found = 1;
break;
}
}
}
if(gg.reverse) found = !found;
if(found && gg.status == 1){
gg.status = 0;
if(gg.retonly) return -1; //exit(status);
}
return(found);
}
/*---------*/
/* cp_main */
/*---------*/
/**
'cp':UNIX-like file copy utility for MS-DOS machines.
89.02.11 ver 0.0 by Yasushi Saito, TAIST.
89.02.12 ver 0.3
compiled by Microsoft C compiler ver 5.1
compiler changed to LSI-C 3.20
1. cp [options] file1 file2
2. cp [options] file1 file2 .. filen dir
1. copy file1 to file2
2. copy file1 .. filen to dir by its name.
options:
-r: Copy directory to directory recursively.
-i: Interactive,i.e.,query when overwriting on already existing file.
-v: Verbose message.
-a: Copy hidden files also.
Wildcards can be used to give file or directory name ambiguously.
See 'wild.c' for the wildcard specs.
This program is NOT COPYRIGHTED,
used, modified, re-distributed with no restriction,and no warranty.
*/
unsigned get_file_status(char *path)
{
char *p;
/*
* If PATH ends with \, perform no check and return 0x10(DIR)
* immediately. Further check will be done by the caller.
*/
if(regularize_pathname(path))
return 0x10;
p = path + strlen(path) - 1;
/*
* We have to take special care when the filename end with '\.', or
* '\..', or when the filename is "." or ".." or "a:." or "a:..",
* because of MS-DOS's bug.
*/
if(*p == '.'){
if(p == path || /* path=="." */
p[-1] == PD || /* path=="xxxx\." */
p[-1] == ':' && p - 2 == path && isalpha(p[-2]))
return 0x10;
if(p[-1] == '.'){
if(p - 1 == path || /* path==".." *//* Changed Nide */
p[-2] == PD || /* path=="xxxx\.." */
p[-2] == ':' && p - 3 == path && isalpha(p[-3])
/* path=="a:.." */)
return 0x10;
}
}
return GetFileAttributes(path);
}
char *convert_extention(char *original,
char *new_extention,
char *out)
{
char *x;
strcpy(out, original);
x = strrchr(out, '.');
if(x == 0){
strcat(out, ".");
strcat(out, new_extention);
} else {
strcpy(x + 1, new_extention);
}
return out;
}
int rename_as_backup(char *filename)
{
char buf[PATHNAMELENGTH];
convert_extention(filename, "bak", buf);
unlink(buf);
if(rename(filename, buf)){
return 0;
}
return 1;
}
void copy_attribute(char *src, char *dst)
{ /* Add Nide */
long lattr;
lattr = GetFileAttributes(src);
if (lattr == 0xFFFFFFFF) return;
SetFileAttributes(dst, lattr);
}
int getfullpath_drive(char *buf, char *path)
{
char temp[PATHNAMELENGTH];
if(_fullpath(temp, path, sizeof(temp)) == NULL) {
return -1;
}
if(isalpha(temp[0])){
if(buf != NULL) {
strcpy(buf, temp + 2);
}
to_upper(temp[0]);
return temp[0] - 'A' + 1;
} else {
/* network drive, maybe */
if(buf != NULL) {
strcpy(buf, temp);
}
return 0;
}
}
unsigned _dos_getftime(int handle, unsigned *date, unsigned *time)
{
FILETIME ft, ftLocal;
GetFileTime((HANDLE)handle, NULL, NULL, &ft);
FileTimeToLocalFileTime(&ft, &ftLocal);
FileTimeToDosDateTime(&ftLocal, (LPWORD)date, (LPWORD)time);
return 0;
}
unsigned _dos_setftime(int handle, unsigned date, unsigned time)
{
FILETIME ft, ftLocal;
DosDateTimeToFileTime((WORD)date, (WORD)time, &ftLocal);
LocalFileTimeToFileTime(&ftLocal, &ft);
SetFileTime((HANDLE)handle, NULL, NULL, &ft);
return 0;
}
void cp_error(char *s, char *s2)
{
char buf[0x100];
gg.error_code = 1;
_snprintf(buf, sizeof(buf), s, s_conv_to_unix_format(s2));
cwFputs(buf, (LPSTR)-1);
cwFputs("\n", (LPSTR)-1);
}
void cp_io_error(char *s, char *s2)
{
char buf[0x100];
gg.error_code = 1;
_snprintf(buf, sizeof(buf), s, s_conv_to_unix_format(s2));
cwFputs(buf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
// perror(" ");
}
void verbose_out(char *source, char *dest)
{
char buf[0x100];
_snprintf(buf, sizeof(buf), "%s -> ", s_conv_to_unix_format(source));
cwFputs(buf, (LPSTR)-1);
_snprintf(buf, sizeof(buf), "%s\n", s_conv_to_unix_format(dest));
cwFputs(buf, (LPSTR)-1);
}
/*
* Do copying 'source' to 'dest'.
*
*/ /* fdとfile handleを混用しているのはオリジナル時代から。まずいかなあ? Nide*/
int copy_file(char *source, char *dest)
{
int nret = 0;
int fds = -1, fdd = -1;
unsigned n, dest_stat;
struct {unsigned d, t;} src_dt, dest_dt;
char buf[0x100];
if((fds = _lopen(source, OF_READ)) < 0){
cp_io_error("cannot open source '%s'", source);
nret = 0; goto EXIT;
}
_dos_getftime(fds, &src_dt.d, &src_dt.t);
if(gg.opt_update && (fdd = _lopen(dest, OF_READ)) >= 0){
_dos_getftime(fdd, &dest_dt.d, &dest_dt.t);
_lclose(fdd); fdd = -1;
if(src_dt.d<dest_dt.d || src_dt.d==dest_dt.d && src_dt.t<=dest_dt.t){
nret = 0; goto EXIT;
}
}
if(gg.opt_verbose) verbose_out(source, dest);
dest_stat = get_file_status(dest);
if(gg.opt_interactive || gg.opt_backup){
if(dest_stat != (unsigned) -1){
if(gg.opt_backup){
if(gg.opt_verbose){
_snprintf(buf, sizeof(buf), " (backup %s)",
s_conv_to_unix_format(dest));
cwFputs(buf, (LPSTR)-1);
}
if(!rename_as_backup(dest)){
cp_io_error("Can't rename", dest);
goto ask;
} else {
dest_stat = (unsigned)-1;
}
} else {
ask:
_snprintf(buf, sizeof(buf), "file '%s' exists, overwrite? ",
s_conv_to_unix_format(dest));
cwFputs(buf, (LPSTR)-1);
if(!YES_OR_NO_P()){
nret = 0; goto EXIT;
}
}
}
}
if((fdd = _lcreat(dest, 0)) < 0){
cp_io_error("cannot open destination '%s'", dest);
nret = 0; goto EXIT;
}
while((n = _lread(fds, gg.copybuf, BUFFERSIZE)) > 0) {
if(_lwrite(fdd, gg.copybuf, n) != (int)n){
cp_io_error("%s: write error", dest);
_lclose(fdd); fdd = -1;
unlink(dest);
nret = 1; goto EXIT;
}
}
if(gg.opt_preserve){
/* set_modification_time(fds, fdd); */
_dos_setftime(fdd, src_dt.d, src_dt.t);
}
if(gg.opt_preserve || dest_stat == (unsigned) -1) {
copy_attribute(source, dest);
} else {
SetFileAttributes(dest, dest_stat & 0x27);
/* Check: Is this same as UNIX? (Nide) *//* also check usage */
}
EXIT:
if (fds != -1) _lclose(fds);
if (fdd != -1) _lclose(fdd);
return nret;
}
/*
* Copy 'source' to 'dest'. Copy recursively if 'source' is a directlry and
* 'recursive' option is set.
*
*/
int r_copy_file(char *source, char *dest)
{
/* int i; */
int nret = 0;
int lfind = -1;
int dest_status;
/* Strip off last \\ in the filename string */
regularize_pathname(source);
dest_status = regularize_pathname(dest);
/*
* Check if source and destination are same, or source path is the
* part of the destination(recursive copy).
*/
{
char b1[PATHNAMELENGTH], b2[PATHNAMELENGTH];
int c, d;
if(0 <= (c = getfullpath_drive(b1, source)) &&
0 <= (d = getfullpath_drive(b2, dest)) && c == d)
/* Mod Nide */ {
if(!strcmp(b1, b2)){
cp_error("%s: two files seem to be identical.",
b1);
return 0;
} else if(!strncmp(b1, b2, strlen(b1)) &&
((c = b2[strlen(b1)]) == '\0' || c == PD)){
cp_error("%s: recursive copy", source);
return 0;
}
}
}
if(!dest_status){
/* PATH does not end with \ */
if(!gg.opt_recursive){
if (copy_file(source, dest) != 0) {
nret = 1; goto EXIT;
}
return 0;
}
} else {
if(!gg.opt_recursive){
cp_error("'%s' is a directory", dest);
return 0;
}
}
{
char temp[PATHNAMELENGTH], tempd[PATHNAMELENGTH];
struct _finddata_t f;
verbose_out(source, dest);
_snprintf(temp, sizeof(temp), "%s\\%s", source, "*.*");
memset(&f, 0, sizeof(f));
f.attrib = (opt_all != 0) ? 0x37 : 0x35;
lfind = _findfirst(temp, &f);
if (lfind == -1) {
if (copy_file(source, dest) != 0) {
nret = 1; goto EXIT;
}
} else {
do {
mkdir(dest); /* If dest already exists,
* the error will occur in
* 'mkdir', but we ignore it. */
/*
* If the first character of the filename is
* '.', then the filename must be "." or ".."
* in MSDOS.
*/
if(*(f.name) != '.'){
_snprintf(temp, sizeof(temp), "%s\\%s", source, f.name);
_snprintf(tempd, sizeof(tempd), "%s\\%s", dest, f.name);
if(f.attrib & 0x10) {
if (r_copy_file(temp, tempd) != 0) {
nret = 1; goto EXIT;
}
} else {
if (copy_file(temp, tempd) != 0) {
nret = 1; goto EXIT;
}
}
}
} while(_findnext(lfind, &f) == 0);
_findclose(lfind); lfind == -1;
copy_attribute(source, dest);
}
}
EXIT:
if (lfind != -1) _findclose(lfind);
return nret;
}
char *strip_directory_part(char *path)
{
char *b = path;
while(*path){
if(iskanjipos(path))
path++;
else if(*path == PD || *path == ':')
b = path + 1;
path++;
}
return (char *) b;
}
int multifile_copy(int filenum, char **filevec)
{
char buf[PATHNAMELENGTH];
int i;
for(i = 0; i < filenum - 1; i++){
_snprintf(buf, sizeof(buf), "%s\\%s",
filevec[filenum - 1], strip_directory_part(filevec[i]));
if (r_copy_file(filevec[i], buf) != 0) return 1;
}
return 0;
}
int cp_main(int argc, char **argv)
{
int c;
unsigned mode;
// extern int optind, opterr;
// extern char *optarg;
conv_char_args(argv, '/', '\\');
gg.opterr = 0;
gg.opt_recursive = gg.opt_verbose = gg.opt_interactive = FALSE;
while((c = getopt(argc, argv, "rvaibpu")) != EOF){
switch (c){
case 'r':
gg.opt_recursive = TRUE;
break;
case 'v':
gg.opt_verbose = TRUE;
break;
case 'i':
gg.opt_interactive = TRUE;
break;
case 'a':
/* opt_all = TRUE; */
cwFputs("Warning: 'a' option is obsolete\n", (LPSTR)-1);
break;
case 'b':
gg.opt_backup = TRUE;
break;
case 'p':
gg.opt_preserve = TRUE;
break;
/* I use "alias cp cp -p" :-) */
case 'u': /* Nide */
gg.opt_update = TRUE;
break;
default:
return cp_usage();
}
}
argc -= gg.optind;
argv += gg.optind;
if(argc < 2)
return cp_usage();
else {
if(regularize_pathname(argv[argc - 1])) {
if (multifile_copy(argc, argv) != 0) return 1;
} else {
mode = get_file_status(argv[argc - 1]);
if(argc >= 3){
if(mode == (unsigned) (-1) || !(mode & 0x10))
return cp_usage();
if (multifile_copy(argc, argv) != 0) return 1;
} else {/* argc==2 */
/*
* See if the last argument is directory or
* not.
*/
if(mode != (unsigned) (-1) && (mode & 0x10)){
if (multifile_copy(argc, argv) != 0) return 1;
} else {
if (r_copy_file(argv[0], argv[1]) != 0) return 1;
}
}
}
}
return gg.error_code;
}
int cp_usage(void)
/* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
{
static char *msgs[] = {
"1. cp [-rivbpu] file1 ... filen directory\n",
"2. cp [-rivbpu] file1 file2\n",
"-r : copy all files under directory\n",
"-i : ask when overwriting on existing file\n",
/* "-a : copy hidden files also\n", */
"-v : verbose message\n",
"-b : make backup when overwriting on existing file\n",
"-p : preserve file attribute and modification time\n",
"-u : update (copy only newer file)\n",
};
int i;
for(i = 0; i < sizeof(msgs) / sizeof(*msgs); i++)
cwFputs(msgs[i], (LPSTR)-1);
return 2;
}
/*------------*/
/* touch_main */
/*------------*/
/*
touch…ファイルの更新時刻のセット
nide@ics.nara-wu.ac.jpによる新版
usage: touch [-cfd] [mmdd[hhmm[[ss]yy]]] file1 file2…
touch [-cfd] [-t filename] file1 file2…
時刻指定は年月日時分秒の順ではなく、月日時分秒年の順なので注意。
時刻指定がなければ現在の時刻にセット。
-c…ファイルがない場合作成しない。
-t…指定したファイルと同じ更新時刻にする。
-f…更新に失敗したファイルがあっても停止しない。
-d…ディレクトリやボリュームラベルであっても時刻を設定する。
*/
/* ----------------- 以下はUNIXと共用のソースによる旧版 -----------------
usage: touch [-cf] [mmdd[hhmm[[ss]yy]]] file1 file2…
touch [-cf] [-t filename] file1 file2…
*/
#include <sys/utime.h>
int digitonly(char *s)
{
for(; *s; s++) if(!is_digit(*s)) return(0);
return(1);
}
int time_t_to_dosdatetime(time_t *time, LPWORD dos_date, LPWORD dos_time)
{
FILETIME ft;
SYSTEMTIME st;
struct tm *lptm;
lptm = localtime(time);
st.wYear = lptm->tm_year + 1900;
st.wMonth = lptm->tm_mon + 1;
st.wDayOfWeek = lptm->tm_wday;
st.wDay = lptm->tm_mday;
st.wHour = lptm->tm_hour;
st.wMinute = lptm->tm_min;
st.wSecond = lptm->tm_sec;
st.wMilliseconds = 0;
SystemTimeToFileTime(&st, &ft);
FileTimeToDosDateTime(&ft, dos_date, dos_time);
return 0;
}
int dosdatetime_to_time_t(unsigned dos_date, unsigned dos_time, time_t *time)
{
FILETIME ft;
SYSTEMTIME st;
struct tm tm;
DosDateTimeToFileTime((WORD)dos_date, (WORD)dos_time, &ft);
FileTimeToSystemTime(&ft, &st);
tm.tm_year = st.wYear - 1900;
tm.tm_mon = st.wMonth - 1;
tm.tm_wday = st.wDayOfWeek;
tm.tm_mday = st.wDay;
tm.tm_hour = st.wHour;
tm.tm_min = st.wMinute;
tm.tm_sec = st.wSecond;
*time = mktime(&tm);
return 0;
}
int touch_utime(char *filename, struct utimbuf *times)
{
HFILE hFile;
FILETIME ft;
SYSTEMTIME st;
struct tm *lptm;
BOOL fRet;
lptm = gmtime(×->modtime);
st.wYear = lptm->tm_year + 1900;
st.wMonth = lptm->tm_mon + 1;
st.wDayOfWeek = lptm->tm_wday;
st.wDay = lptm->tm_mday;
st.wHour = lptm->tm_hour;
st.wMinute = lptm->tm_min;
st.wSecond = lptm->tm_sec;
st.wMilliseconds = 0;
SystemTimeToFileTime(&st, &ft);
hFile = _lopen(filename, OF_READWRITE);
fRet = SetFileTime((HANDLE)hFile, NULL, NULL, &ft);
_lclose(hFile);
return (fRet == TRUE) ? 0 : -1;
}
int touch_main(int ac, char **av)
{
int c;
// extern int optind, opterr;
// extern char *optarg;
int fmake = 1, force = 0, status = 0, tmpfd;
char *fromfnm = NULL;
struct utimbuf *utimearg, utimestr;
struct stat statstr;
while(EOF != (c = getopt(ac, av, "cft:"))){
switch(c){
case 'f': force = 1; break;
case 'c': fmake = 0; break;
case 't': fromfnm = gg.optarg; break;
default: return touch_usage();
}
}
ac -= gg.optind, av += gg.optind;
if(!ac) return touch_usage();
if(fromfnm != NULL){
utimearg = &utimestr;
if(0 != stat(fromfnm, &statstr)){
cwFputs(name_unixnize(fromfnm), (LPSTR)-1);
cwFputs(": Can't stat\n", (LPSTR)-1);
return 1;
}
utimestr.modtime = statstr.st_mtime;
} else if(/* ac && */ digitonly(*av)){
utimearg = &utimestr;
if (readtime(*av, utimearg) != 0) return 1;
ac--, av++;
if(!ac) return touch_usage();
} else {
/* utimearg = NULL; */
utimearg = &utimestr;
time(&utimestr.modtime);
}
for(; ac; ac--, av++){
if(0 == touch_utime(*av, utimearg)) continue;
name_unixnize(*av);
if(!fmake){
cwFputs(*av, (LPSTR)-1), cwFputs(": Can't touch\n", (LPSTR)-1);
if(!force) {
return 1;
} else {
status = 1;
}
} else if(0 <= (tmpfd = open(*av, O_CREAT | O_EXCL, 0644))){
close(tmpfd);
setattr(*av, 0x20);
touch_utime(*av, utimearg);
} else {
cwFputs(*av, (LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
if(!force) {
return 1;
} else {
status = 1;
}
}
}
return status;
}
int readtime(char *str, struct utimbuf *utimearg) /*str:数字ばかりの文字列*/
{
int y, m = 1, d = 1, h = 0, mn = 0, s = 0;
int yget = 0, l;
ulong datetime;
switch(l = strlen(str)){
case 12: s = ctoi(str[8]) * 10 + ctoi(str[9]); /* through */
case 10: y = ctoi(str[l-2])*10 + ctoi(str[l-1]); yget = 1; /* through */
case 8: mn = ctoi(str[6]) * 10 + ctoi(str[7]);
h = ctoi(str[4]) * 10 + ctoi(str[5]); /* through */
case 4: d = ctoi(str[2]) * 10 + ctoi(str[3]);
m = ctoi(str[0]) * 10 + ctoi(str[1]); /* through */
break;
default:
return illdate();
}
if(!yget){
long ltime;
struct tm *timeptr;
time(<ime);
timeptr = localtime(<ime);
y = timeptr->tm_year;
}
if(y >= 80) y += 1900; else y += 2000;
datetime = caldate(y, m, d);
if(!(1 <= m && m <= 12 &&
1 <= d && (long)datetime <
(m == 12? caldate(y + 1, 1, 1) : caldate(y, m + 1, 1)) &&
0 <= h && h < 24 &&
0 <= mn && mn < 60 &&
0 <= s && s < 60)) return illdate();
datetime -= caldate(1970, 1, 1);
datetime *= 24L * 60L * 60L;
datetime += (ulong)(h - 17) * 3600L + (ulong)mn * 60L + (ulong)s; /*-17 ?*/
datetime += timezone; /* if timezone is not extern long in your
system, you must modify here */
utimearg->modtime = (time_t)datetime;
return 0;
}
int touch_usage(void)
{
cwFputs("Usage: touch [-cf] [mmdd[hhmm[[ss]yy]]] file...\n", (LPSTR)-1);
cwFputs(" touch [-cf] [-t filename] file...\n", (LPSTR)-1);
cwFputs("-c : no create\n", (LPSTR)-1);
cwFputs("-f : no errors\n", (LPSTR)-1);
cwFputs("-t : copy time-stamp from the specified file\n", (LPSTR)-1);
return -1;
}
/*-----------*/
/* join_main */ /* メモリ解放が完全でない */
/*-----------*/
/* -a123 -estr -j[12]m -o x.y x.y... -tc f1 f2 */
int join_usage(void)
{
cwFputs("Usage: join [-a n] [-e string] [-j[1|2] m]\n", (LPSTR)-1);
cwFputs("\t [-o fieldlist] [-t c] file1 file2\n", (LPSTR)-1);
return 1;
}
char *strsave(char *s)
{
char *p;
if(NULL != (p = malloc(strlen(s) + 1))) strcpy(p, s);
return p;
}
int nomem(void)
{
_putnomemmes();
return 1;
}
int outfreg(char *p)
{
gg.outlist = (outfieldstr *)(gg.outlistlen ?
realloc((char *)gg.outlist, (gg.outlistlen+1)*sizeof(outfieldstr)) :
malloc(sizeof(outfieldstr)));
if(NULL == gg.outlist) return nomem();
gg.outlist[gg.outlistlen] . fno = *p - '1';
if(*p != '1' && *p != '2' || *++p != '.' || !*++p) return join_usage();
if(0 > (gg.outlist[gg.outlistlen].field = atoi(p)-1)) return join_usage();
while(isdigit(*p)) p++;
if(*p) return join_usage();
gg.outlistlen++;
return 0;
}
char *readnthfile(int nth)
{
int len;
char *buf;
buf = (gg.inf[nth] == NULL) ? cwFgets(gg.linbuf[nth], LINMAX, NULL) :
fgets(gg.linbuf[nth], LINMAX, gg.inf[nth]);
if (buf != NULL) {
if(!*buf){ /* nothing */
} else if(len = strlen(buf), buf[--len] != '\n'){
cwFputs(gg.infnm[nth], (LPSTR)-1);
if(len == LINMAX - 2){
cwFputs(": line too long\n", (LPSTR)-1);
return (LPSTR)-1;
} else {
cwFputs(": missing line-feed character "
"added at the end of file\n", (LPSTR)-1);
}
} else {
buf[len] = '\0';
}
}
return buf;
}
char *fieldend(char *p)
/* pがフィールド内ならその末尾の直後、さもないとそのままを返す */
{
if(*gg.fieldsep){
for(; *p; iskanjipos(p) ? (p += 2) : p++){
if(*gg.fieldsep == *p &&
(!gg.fieldsep[1] || gg.fieldsep[1] == p[1])) break;
}
} else {
while(*p && !is_space(*p)) p++;
}
return p;
}
char *fieldtop(char *p)
/* pがタブ文字上なら次のフィールドの先頭、さもないとそのままを返す */
{
if(*gg.fieldsep){
if(*gg.fieldsep == *p){
if(gg.fieldsep[1]){
if(gg.fieldsep[1] == p[1]) p += 2;
} else p++;
}
} else {
while(is_space(*p)) p++;
}
return p;
}
char *fieldnth(char *p, int n)
{
if(!*gg.fieldsep) p = fieldtop(p);
while(n--) p = fieldnext(p);
return p;
}
int do_join(char **infnm)
{
int nret = 0;
char *f2b, *f2e, *f2line = NULL, *f1line;
char *f2linenew;
char **f2bufs = NULL; /* f2bufs, f2bufcntはstaticでなくていい? */
char **f2bufsnew;
int f2bufcnt = 0, f2bufused = 0;
char f2eof = 0, f2pushed = 0, f1eof = 0, f1pushed = 0, f1match;
int i;
for(i = 0; i < 2; i++){
if(infnm[i][0] == '-' && !infnm[i][1]){
gg.inf[i] = NULL; infnm[i] = "(stdin)";
} else if(NULL == (gg.inf[i] = fopen(infnm[i], "r"))){
cwFputs(infnm[i], (LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
nret = 1; goto EXIT;
} else {
conv_to_unix_format(infnm[i]);
}
}
/* malloc sizeは適当に決めた。あとでの増加単位も適当 */
if(NULL == (f2bufs = (char **)
malloc(sizeof(char *) * (f2bufcnt = 50)))) {
nret = nomem(); goto EXIT;
}
for(;;){
/* 前に読んだ行の掃除。直前に読んだ行はf2lineにあり */
if(f2bufcnt > 200 &&
f2bufused < 100 && f2bufused * 3 < f2bufcnt){
f2bufsnew = (char **)realloc((char *)f2bufs,
sizeof(char *) * (f2bufcnt = 200));
/* 現f2bufused以上は確保すること */
if(f2bufsnew == NULL) {
nret = nomem(); goto EXIT;
} else {
f2bufsnew = f2bufs;
}
}
while(f2bufused) free(f2bufs[--f2bufused]);
/* f2bufusedは0になる */
while(!f2eof){
if(f2pushed){
f2pushed = 0;
} else {
f2line = readnthfile(1);
if (f2line == (LPSTR)-1) {
nret = 1; goto EXIT;
}
if(NULL == f2line){
f2eof++;
break;
}
}
if(!f2bufused){ /* 一致する一連の行のうち最初 */
f2linenew = strsave(f2line);
if (f2linenew == NULL) {
nret = nomem(); goto EXIT;
} else {
f2line = f2linenew;
}
/* 先にstrsaveしないとf2b, f2eが狂う */
f2bufs[f2bufused++] = f2line;
f2b = fieldnth(f2line, gg.joinfield[1]);
f2e = fieldend(f2b);
} else {
if(strfieldcmp(f2b, f2e, f2line, gg.joinfield[1])){
f2pushed = 1;
/* 今の行をf2lineつまりlinbuf[1]に
残しておく */
break;
} else { /* 一致 */
if(f2bufused >= f2bufcnt){
f2bufsnew = (char **)realloc((char *)f2bufs,
sizeof(char *) *(f2bufcnt += 20));
if(f2bufsnew == NULL) {
nret = nomem(); goto EXIT;
} else {
f2bufs = f2bufsnew;
}
}
if(NULL == (f2bufs[f2bufused++] = strsave(f2line))) {
nret = nomem(); goto EXIT;
}
}
}
}
for(f1match = 0; ;){
if(f1pushed){
f1pushed = 0;
} else if(!f1eof){
f1line = readnthfile(0);
if (f1line == (LPSTR)-1) {
nret = 1; goto EXIT;
}
if(f1line == NULL) {
f1eof++;
}
}
if(f1eof && !f2bufused) {
nret = 0; goto EXIT;
}
i = !f2bufused ? /* 読み尽くした方が大 */ 1 :
f1eof ? -1 :
strfieldcmp(f2b, f2e, f1line, gg.joinfield[0]);
if(i > 0){ /* f2が大。f1側出力 */
if(gg.addwidow & 01) {
fieldout(f1line, "", 1);
}
} else if(i == 0){ /* 同じ。全f2bufsに対し組み合わせを出力 */
f1match = 1;
for(i = 0; i < f2bufused; i++) {
fieldout(f1line, f2bufs[i], 3);
}
} else if(i < 0){ /* f1が大。f2側出力 */
if(!f1match && (gg.addwidow & 02)){
for(i = 0; i < f2bufused; i++) {
fieldout("", f2bufs[i], 2);
}
}
f1pushed = 1;
/* 現在行をf1lineつまりlinbuf[0]に残す */
break;
}
}
}
EXIT:
if (f2bufs != NULL) free(f2bufs);
if (f2line != NULL) free(f2line);
for (i = 0; i < 2; i++) {
if (gg.inf[i] != NULL) fclose(gg.inf[i]); gg.inf[i] = NULL;
}
return nret;
}
void fieldeach(char *p)
{
char *q;
char buf[0x100];
if (p < (q = fieldend(p))) {
_snprintf(buf, sizeof(buf), "%.*s", q - p, p);
cwFputs(buf, NULL);
} else {
cwFputs(gg.emptyfill, NULL);
}
}
void fieldout(char *s1, char *s2, int flag)
{
int curf[2], i, outfirst, f_no, f_field;
char *ftop[2], *ltop[2], *p;
char buf[0x100];
curf[0] = curf[1] = 0;
ltop[0] = ftop[0] = s1, ltop[1] = ftop[1] = s2;
if(!gg.outlistlen){ /* outlistlenが0なら全部出力 */
f_no = (flag & 01) ? 0 : 1;
f_field = gg.joinfield[f_no];
fieldeach(fieldnth(ltop[f_no], f_field));
for(f_no = 0; f_no < 2; f_no++){
f_field = gg.joinfield[f_no];
for(i = 0, p = fieldnth(ltop[f_no], 0); *p;
i++, p = fieldnext(p)){
if(i != f_field){
_snprintf(buf, sizeof(buf), "%.2s",
*gg.fieldsep ? gg.fieldsep : " ");
cwFputs(buf, NULL);
fieldeach(p);
}
}
}
} else {
for(outfirst = 1, i = 0; i < gg.outlistlen; i++){
f_no = gg.outlist[i] . fno;
f_field = gg.outlist[i] . field;
if(curf[f_no] > f_field){
p = fieldnth(ltop[f_no], f_field);
} else {
p = fieldnth(ftop[f_no], f_field - curf[f_no]);
}
outfirst ? outfirst = 0 :
_snprintf(buf, sizeof(buf), "%.2s",
*gg.fieldsep ? gg.fieldsep : " ");
cwFputs(buf, NULL);
fieldeach(ftop[f_no] = p),
curf[f_no] = f_field;
}
}
cwFputs("\n", NULL);
}
int strfieldcmp(char *fb, char *fe, char *p, int n)
{
char *pe;
p = fieldnth(p, n), pe = fieldend(p);
return strpartcmp(fb, fe - fb, p, pe - p);
}
int strpartcmp(char *p, int m, char *q, int n)
{
int result;
if(0 != (result = strncmp(p, q, m < n ? m : n))) return result;
return m - n;
}
int join_main(int ac, char **av)
{
char **origav, *p;
origav = av;
while(++av, --ac){
if('-' != *(p = *av) || !p[1]) break;
if(*++p == '-') {++av, --ac; break;}
switch(*p){
case 'a':
if(!*++p){
if(++av, !--ac) {
return join_usage();
} else {
p = *av;
}
}
if(*p < '1' || '3' < *p || p[1]) return join_usage();
gg.addwidow = *p - '0';
break;
case 'e':
if(!*++p){
if(++av, !--ac) {
return join_usage();
} else {
p = *av;
}
}
gg.emptyfill = p;
break;
case 'j':
if(*++p && (*p < '1' || '2' < *p || p[1])) return join_usage();
if(++av, !--ac) return join_usage();
{
int fi;
if(0 > (fi = atoi(*av) - 1)) return join_usage();
switch(*p){
case '1': gg.joinfield[0] = fi; break;
case '2': gg.joinfield[1] = fi; break;
default:
gg.joinfield[0]= gg.joinfield[1]= fi; break;
}
}
break;
case 'o':
if(*++p || ac == 1 || (++av, --ac, !isdigit(**av))) {
return join_usage(); /* 最低1つないとだめ */
}
for(; ac; ++av, --ac){
if(p = *av, !isdigit(*p)) break;
if (outfreg(p) != 0) return 1;
}
++ac, --av; /* 1つ戻す */
break;
case 't':
if(!*++p){
if(av++, !--ac) return join_usage();
p = *av;
if(!*p) return join_usage();
}
gg.fieldsep[0] = *p;
if(iskanji(*p)) {
gg.fieldsep[1] = *++p;
} else {
gg.fieldsep[1] = '\0';
}
if(p[1]) return join_usage();
break;
default:
return join_usage();
}
}
if(ac != 2) return join_usage();
return do_join(av);
}
/*---------*/
/* mv_main */
/*---------*/
/**
'mv':UNIX-like file move utility for MS-DOS machines.
89.03.29 ver 0.0 by Yasushi Saito, TAIST.
90.04.02 ver 1.0 Directory->directory move.
90.10.12 Bug removed in '-f'.
Now mv can move the file if destination is readonly.
compiled by Microsoft C compiler ver 5.1
compiler changed to LSI-C 3.20
1. mv [-fvi] file1 file2
2. mv [-fvi] file1 file2 .. filen dir
1. move file1 to file2
2. move file1 .. filen to dir by its name.
options:
-i: Interactive. Ask when overwriting on already existing files.
-f: Force.
-v: Verbose message.
Wildcards can be used to give file or directory name ambiguously.
See 'wild.c' for the wildcard specs.
This program is in public domain.
Used, modified, re-distributed with no restriction,and no warranty.
*/
/*
* Error reporting.
*/
void mv_error(char *s, char *s2)
{
char buf[0x100];
if(gg.force) return;
_snprintf(buf, sizeof(buf), s, s_conv_to_unix_format(s2));
cwFputs(buf, (LPSTR)-1);
cwFputs("\n", (LPSTR)-1);
gg.error_code = 1;
}
/*
* Move SOURCE to DEST.
*/ /* fdとfile handleを混用しているのはオリジナル時代から。まずいかなあ? Nide*/
int move_file(char *source, char *dest)
{
int nret;
int fds = -1, fdd = -1; /* File descriptor for each file. */
char disks, diskd; /* Device name for each file */
unsigned modes, moded; /* File attribute for each file */
struct {unsigned d, t;} dates, dated;
/* File time for each file */
unsigned n; /* Counter when copying */
char buf[0x100];
long lfind = -1;
modes = get_file_status(source);
moded = get_file_status(dest);
/*
* Check the attribute of each file and do pre-processing.
*
*/
if(modes == (unsigned) -1){
mv_error("%s does not exist.", source);
nret = 0; goto EXIT;
}
/* Check if two files are the same */
{
char b1[PATHNAMELENGTH], b2[PATHNAMELENGTH];
int c, d;
if(0 <= (c = getfullpath_drive(b1, source)) &&
0 <= (d = getfullpath_drive(b2, dest)) && c == d)
/* Mod Nide */ {
if(!strcmp(b1, b2)){
mv_error("%s: two files seem to be identical.", b1);
nret = 0; goto EXIT;
} else if(!strncmp(b1, b2, strlen(b1)) &&
(!(c = b2[strlen(b1)]) || c == '/' || c == '\\')){
mv_error("%s: recursive move", source);
nret = 0; goto EXIT;
}
}
}
if(IS_DIRECTORY(modes)){
/* move directory */
struct _finddata_t f;
unsigned char s[PATHNAMELENGTH], ss[PATHNAMELENGTH],
dd[PATHNAMELENGTH];
if(gg.verbose) verbose_out(source, dest);
if(moded != (unsigned) -1){
/*
* Do not move when destination directory already
* exists
*/
mv_error("destination '%s':"
" cannot move directory to existent file.", dest);
nret = 0; goto EXIT;
}
if(mkdir(dest)){
/* Failed on making destination directory */
mv_error("cannot make directory '%s'", dest);
nret = 0; goto EXIT;
}
/*
* Read the filenames contained in the source directory and
* recursively move each files.
*/
_snprintf(s, sizeof(s), "%s\\%s", source, "*.*");
memset(&f, 0, sizeof(f));
f.attrib = 0x16;
lfind = _findfirst(s, &f);
if (lfind == -1) {
mv_error("can't read directory %s", source);
nret = 0; goto EXIT;
}
do {
if(f.name[0] != '.'){
_snprintf(ss, sizeof(ss), "%s\\%s", source, f.name);
_snprintf(dd, sizeof(dd), "%s\\%s", dest, f.name);
if (move_file(ss, dd) != 0) {
nret = 1; goto EXIT;
}
}
} while(_findnext(lfind, &f) == 0);
_findclose(lfind); lfind = -1;
copy_attribute(source, dest); /* Add Nide, dir attr copy */
if(rmdir(source)) {
mv_error("can't delete directory %s", source);
}
nret = 0; goto EXIT;
}
if((fds = _lopen(source, OF_READ)) < 0){
io_error("cannot open source '%s'", source);
nret = 0; goto EXIT;
}
_dos_getftime(fds, &dates.d, &dates.t);
if(gg.update && (fdd = _lopen(dest, OF_READ)) >= 0){
_dos_getftime(fdd, &dated.d, &dated.t);
_lclose(fdd); fdd = -1;
if(dates.d < dated.d || dates.d == dated.d && dates.t <= dated.t){
nret = 0; goto EXIT;
}
}
if(gg.verbose) verbose_out(source, dest);
if(IS_READONLY(modes)){
if(gg.interactive || !gg.force){
_snprintf(buf, sizeof(buf),"'%s' readonly, move? ", source);
cwFputs(buf, (LPSTR)-1);
if(!YES_OR_NO_P()) {
nret = 0; goto EXIT;
}
}
setattr(source, modes & ~7);
}
if(IS_READONLY(moded)){
if(gg.interactive || !gg.force){
_snprintf(buf, sizeof(buf), "'%s' readonly, move? ", dest);
cwFputs(buf, (LPSTR)-1);
if(!YES_OR_NO_P()) {
nret = 0; goto EXIT;
}
}
setattr(dest, moded & ~7); /* Nide, modes -> moded */
}
/*
* Check if we only have to change the 'link' of the file, or we have
* to copy the contents to the destination and unlink the source.
*/
disks = getfullpath_drive(NULL, source);
diskd = getfullpath_drive(NULL, dest);
/* now fds is opened */
if(disks >= 0 && disks == diskd){
_lclose(fds); fds = -1;
/*
* We only have to change the 'link' of files if two files
* are on the save device
*/
if(moded != (unsigned) -1){
if(gg.backup){
if(gg.verbose) {
_snprintf(buf, sizeof(buf), " (backup %s)\n",
s_conv_to_unix_format(dest));
cwFputs(buf, (LPSTR)-1);
}
if(!rename_as_backup(dest))
goto ask;
} else {/* Changed Nide */
if(gg.interactive){
ask:
_snprintf(buf, sizeof(buf), "'%s' exists, move? ",
dest);
cwFputs(buf, (LPSTR)-1);
if(!YES_OR_NO_P()) {
nret = 0; goto EXIT;
}
}
if(remove(dest)){
io_error("cannot delete '%s'", dest);
nret = 0; goto EXIT;
}
}
}
if(rename(source, dest)) {
io_error("could not move '%s'", source);
}
setattr(dest, modes); /* Add Nide; copy attribute */
} else {
/*
* Copy, and unlink , when two files are on different
* devices.
*/
if(moded != (unsigned) -1){
if(gg.backup){
if(gg.verbose) {
_snprintf(buf, sizeof(buf), " (backup %s)\n",
s_conv_to_unix_format(dest));
cwFputs(buf, (LPSTR)-1);
}
if(!rename_as_backup(dest))
goto ask2;
} else if(gg.interactive){
ask2:
_snprintf(buf, sizeof(buf), "'%s' exists, move? ", dest);
cwFputs(buf, (LPSTR)-1);
if(!YES_OR_NO_P()){
nret = 0; goto EXIT;
}
}
}
/* In previous versions fds is opened here
if((fds = _lopen(source, OF_READ)) < 0){
io_error("cannot open source '%s'", source);
nret = 0; goto EXIT;
} */
if((fdd = _lcreat(dest, 0)) < 0){
io_error("cannot open destination '%s'", dest);
nret = 0; goto EXIT;
}
while((n = _lread(fds, gg.copybuf, BUFFERSIZE)) > 0) {
if(_lwrite(fdd, gg.copybuf, n) != n){
io_error("'%s': write error", dest);
goto error;
}
}
if(n < 0){
io_error("'%s': read error", source);
error:
_lclose(fdd);
unlink(dest);
nret = 1; goto EXIT;
}
_dos_setftime(fdd, dates.d, dates.t);
/* set_modification_time(fds, fdd); */
setattr(dest, modes); /* Add Nide; copy attribute */
if (fds != -1) {
_lclose(fds); fds = -1;
}
if(remove(source)) {
io_error("can't delete '%s'", source);
}
}
EXIT:
if (fds != -1) _lclose(fds);
if (fdd != -1) _lclose(fdd);
if (lfind != -1) _findclose(lfind);
return nret;
}
int multifile_move(int filenum, char **filevec)
{
char buf[PATHNAMELENGTH];
int i;
for(i = 0; i < filenum - 1; i++){
_snprintf(buf, sizeof(buf), "%s\\%s", filevec[filenum - 1],
strip_directory_part(filevec[i]));
if (move_file(filevec[i], buf) != 0) return 1;
}
return 0;
}
int ends_with_pathdelimiter_p(char *f)
{
int r = 0;
if(isalpha(f[0]) && f[1] == ':'){
if(f[2] == '\0')
return 1;
f += 2;
}
while(*f){
if(iskanjipos(f))
f += 2;
else {
if(f[1] == '\0' && *f == PD)
r = 1;
f++;
}
}
return r;
}
int mv_main(int argc, char **argv)
{
int c;
unsigned mode;
// extern int optind, opterr;
// extern char *optarg;
conv_char_args(argv, '/', '\\');
gg.opterr = 0;
{
char cwd[128];
getcwd(cwd, 128);
gg.current_disk = toupper(*cwd);
}
gg.force = gg.verbose = gg.interactive = gg.backup = FALSE;
while((c = getopt(argc, argv, "fvibu")) != EOF){
switch (c){
case 'f':
gg.force = TRUE;
break;
case 'v':
gg.verbose = TRUE;
break;
case 'i':
gg.interactive = TRUE;
break;
case 'b':
gg.backup = TRUE;
break;
case 'u':
gg.update = TRUE;
break;
default:
return mv_usage();
}
}
argc -= gg.optind;
argv += gg.optind;
if(argc < 2) {
return mv_usage();
} else {
mode = get_file_status(argv[argc - 1]);
if(argc >= 3){
if(mode == (unsigned) (-1) || !(mode & 0x10)) {
return mv_usage();
}
if (multifile_move(argc, argv) != 0) {
return 1;
}
} else { /* argc==2 */
/* See if the last argument is directory or not. */
if(ends_with_pathdelimiter_p(argv[argc - 1])) {
if (multifile_move(argc, argv) != 0) {
return 1;
}
} else if(mode != (unsigned) (-1) && (mode & 0x10)){
/* 2nd pathname is found to be a directory */
if (multifile_move(argc, argv) != 0) {
return 1;
}
} else {
/* file -> file */
if (move_file(argv[0], argv[1]) != 0) {
return 1;
}
}
}
}
return gg.error_code;
}
int mv_usage(void)
/* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
{
static char *msgs[] = {
"1. mv [-fivbu] file1 ... filen directory\n",
"2. mv [-fivbu] file1 file2\n",
"-f : force readonly files to be moved\n",
"-i : query for each move\n",
"-v : verbose message\n",
"-b : make backup of files being removed\n",
"-u : update (move only newer files)\n",
};
int i;
for(i = 0; i < sizeof(msgs) / sizeof(*msgs); i++)
cwFputs(msgs[i], (LPSTR)-1);
return 3;
}
/*-----------*/
/* tail_main */
/*-----------*/
/*
* TAIL: Get the tail of the file.
* by Yasushi Saito(yasushi@is.s.u-tokyo.ac.jp).
*
*
* April 8, 1989.
*
* Support -l,-c,-h option April 11, 1989.
* Support -r,-b option April 13, 1989.
*/
int tail_error(void)
{
perror("tail");
return 1;
}
int fputs_with_check(char *buf, FILE *fp)
{
if (fp == NULL) {
cwFputs(buf, NULL);
return 0;
}
if(EOF == fputs(buf, fp)){ /* Changed Nide */
cwFputs("tail : write error", (LPSTR)-1);
return 1;
}
return 0;
}
int fgets_with_check(char *buf, int len, FILE *fp)
{
int nret;
if (fp == NULL) {
nret = (int)cwFgets(buf, len, NULL);
} else {
nret = (int)fgets(buf, len, fp);
}
if(nret == 0) {
return 0;
}
if(buf[0] == 'Z' - '@') {
return 0;
}
return nret;
}
void xfseek(FILE *fp, long n, int origin)
{
if(fseek(fp, n, origin))
tail_error();
}
void *xmalloc(unsigned n)
{
register void *m;
if((m = malloc(n)) == 0){
cwFputs("tail:Memory full", (LPSTR)-1);
return NULL;
}
return m;
}
char *xstrdup(char *s)
{
register char *m;
if((m = strdup(s)) == 0){
cwFputs("tail:Memory full", (LPSTR)-1);
return NULL;
}
return m;
}
line_buffer *allocate_buffer(char *buf, int size)
{
register line_buffer *l;
l = xmalloc(sizeof(line_buffer));
l->buf = xmalloc(size + 1);
memcpy(l->buf, buf, size);
l->buf[size] = '\0';
return l;
}
/*
* Count multibyte characters as one, and count 0d0a as one character(EOL)
*/
int string_length(char *s, int size)
{
int n = 0;
while(size > 0){
if(iskanjipos(s)){
s += 2;
size -= 2;
} else if(s[0] == 0x0d && s[1] == 0x0a){
s += 2;
size -= 2;
} else {
s++;
size--;
}
n++;
}
return n;
}
/*
* -##c option Sequential device.
*/
void sequential_find_tail_character(FILE *fp)
{
struct char_buf {
unsigned char h, l;
};
struct char_buf *base, *bottom, *current;
char buf[BUFFER_SIZE], *bufp;
unsigned i;
/* Allocate and initialize buffer. */
current = base = xmalloc(sizeof(struct char_buf) * gg.tail_lineno);
bottom = base + gg.tail_lineno;
for(i = 0; i < gg.tail_lineno; i++)
base[i].h = base[i].l = 0;
/* Read all. */
while(fgets_with_check(buf, BUFFER_SIZE, fp)){
for(bufp = buf; *bufp; bufp++){
if(gg.unit == CHARACTER){
if(iskanjipos(bufp))
current->h = *(bufp++);
else
current->h = 0;
}
current->l = *bufp;
current++;
if(current >= bottom)
current = base;
}
}
/* Printout. */
for(i = 0; i < gg.tail_lineno; i++){
char buf[2];
if(current->h) {
buf[0] = current->h;
buf[1] = '\0';
cwFputs(buf, NULL);
}
if(current->l) {
buf[0] = current->l;
buf[1] = '\0';
cwFputs(buf, NULL);
}
current++;
if(current >= bottom)
current = base;
}
free(base);
}
/*
* -##l or -##r(number specified) option. Sequential device.
*
*/
void sequential_find_tail_line(FILE *fp)
{
char **base, **current, **bottom;
unsigned i;
char buf[BUFFER_SIZE];
/* Allocate and initialize buffer. */
base = current = (char **) xmalloc(sizeof(char *) * gg.tail_lineno);
for(i = 0; i < gg.tail_lineno; i++)
base[i] = 0;
bottom = base + gg.tail_lineno;
/* Read files till the end. */
while(fgets_with_check(buf, BUFFER_SIZE, fp)){
if(*current)
free(*current);
*current = xstrdup(buf);
current++;
if(current >= bottom)
current = base;
}
/* Printout. */
if(gg.mode == tail_reverse){
current--;
for(i = 0; i < gg.tail_lineno; i++){
if(current < base)
current = bottom - 1;
if(*current){
fputs_with_check(*current, NULL);
free(*current);
}
current--;
}
} else {
for(i = 0; i < gg.tail_lineno; i++){
if(*current){
fputs_with_check(*current, NULL);
free(*current);
}
current++;
if(current >= bottom)
current = base;
}
}
free(base);
}
/*
* +##l or +##c options with sequential or block device. Or, +##b with
* sequential device.
*/
void find_head(FILE *fp)
{
char buf[BUFFER_SIZE];
unsigned i;
/* Skip the input to the designated place. */
if(gg.unit == LINE){
for(i = 0; i < gg.tail_lineno; i++)
if(!fgets_with_check(buf, BUFFER_SIZE, fp))
return;
} else {
int c;
for(i = 0; i < gg.tail_lineno; i++){
if((c = getc(fp)) == EOF)
return;
if(gg.unit == CHARACTER && iskanji(c) && (getc(fp) == EOF))
return;
}
}
/* Printout */
while(fgets_with_check(buf, BUFFER_SIZE, fp))
fputs_with_check(buf, NULL);
}
/*
* -##l or -##c option. Block device.
*/
int random_find_tail(FILE *fp)
{
unsigned line; /* Line number (in case of -l), character
* count (in case of -c) */
long file_size; /* Size of the file */
long position; /* Current file pointer FILESIZE >= POSITION
* always. */
/**
The algorithm:
We utilize 2 buffers and use one as a main buffer,
and another to hold an unprocessed portion
(junk string before the first beginning-of-line character).
Their roles are switched at each block-seek.
1. Goto the file end.(file_size is set here and
not modified later.)
2. Seek back SEEK_BLOCK bytes.
3. Read SEEK_BLOCK bytes into READ_BUFFER.
4. Skip the junk string before the first BOL.
(they processed at the next repetition)
5. Add the UNPROCESSED region at the last of READ_BUFFER.
6. Count the lines(or characters) of the READ_BUFFER,
and construct the TOP list.
7. Switch READ_BUFFER and UNPROCESSED.
8. Repeat 2,..,7 until enough lines(or characters) are read.
9. Discard the lines(characters) read excess.
10. Printout.
*/
line_buffer *top, *last,/* Hold the top and last of the current block
* list */
*list_head; /* Global content list */
boolean reached_top; /* Is FP reached the beginning? */
char *read_buffer, *unprocessed;
char *read_buffer_end;/* points to the end of READ_BUFFER */
unsigned unprocessed_size;
char *x;
/*
* Set to binary mode, to synchronize the fread() and fseek()
* operation.
*/
/* fsetbin(fp); *//* Del Nide (done by caller) */
/* Set file pointer at the last */
xfseek(fp, 0L, SEEK_END);
file_size = position = ftell(fp);
line = 0;
list_head = 0;
if(gg.s_buf1_0 == 0){
gg.s_buf1_0 = xmalloc(gg.seek_block * 2);
gg.s_buf2_0 = xmalloc(gg.seek_block * 2);
}
read_buffer = gg.s_buf1_0;
unprocessed = gg.s_buf2_0;
unprocessed_size = 0;
do {
/*
* Seek back one block. REACHED_TOP is set TRUE if the
* current file pointer is at the file top.
*/
if(position - gg.seek_block <= 0){
int size;
xfseek(fp, 0L, SEEK_SET);
reached_top = TRUE;
size = fread(read_buffer, 1, gg.seek_block, fp);
/*
* Copy back the unprocessed portion of the previous
* block
*/
memcpy(read_buffer + size, unprocessed, unprocessed_size);
read_buffer_end = read_buffer + size + unprocessed_size;
x = read_buffer;
position = 0;
} else {
int size;
/* char *s; */
xfseek(fp, -(long) gg.seek_block, SEEK_CUR);
position = ftell(fp);
/* Skip garbages before the first EOL */
size = fread(read_buffer, 1, gg.seek_block, fp);
xfseek(fp, (long) position, SEEK_SET);
memcpy(read_buffer + size, unprocessed, unprocessed_size);
read_buffer_end = read_buffer + size + unprocessed_size;
for(x = read_buffer; *x != '\n' && x < read_buffer_end; x++);
if(x >= read_buffer_end){
cwFputs("Too long input line\n", (LPSTR)-1);
return 1;
}
/*
* Now, X holds the first beginning-of-line.
*/
x++;
unprocessed_size = x - read_buffer;
reached_top = FALSE;
}
/*
* Count the lines contained in READ_BUFFER and addto the TOP
* list line-by-line.
*/
top = 0;
while(x < read_buffer_end){
char *lineend = x;
int size;
/* Look for the line end. */
while(*lineend != '\r' && *lineend != '\n'){
if(lineend >= read_buffer_end){
/*
* fputs("Incomplete last line\n",
* stderr);
*/
lineend--;
break;
}
lineend++;
}
if(*lineend == '\r' && lineend[1] == '\n'){
lineend++;
}
size = lineend - x + 1;
if(top == 0)
top = last = allocate_buffer(x, size);
else {
last->link = allocate_buffer(x, size);
last = last->link;
}
last->link = 0;
x = lineend + 1;
if(gg.unit == LINE)
line++;
else { /* unit==CHARACTER */
last->len = string_length(last->buf, size);
line += last->len;
}
}
/*
* Update the global content list. TOP is inserted at the
* head of the LIST_HEAD.
*/
{
if(list_head == 0)
list_head = top;
else {
last->link = list_head;
list_head = top;
}
}
/*
* Switch READ_BUFFER and UNPROCESSED
*/
{
void *temp = read_buffer;
read_buffer = unprocessed;
unprocessed = temp;
}
/*
* Repeat the loop until enough lines are read, or the file
* reached its top.
*/
} while(!reached_top && line < gg.tail_lineno);
/*
* Discard the lines that was read excess.
*/
if(gg.unit == LINE)
while(line > gg.tail_lineno){
line_buffer *temp;
temp = top;
top = top->link;
free_buffer(temp);
line--;
}
else if(gg.unit == CHARACTER){
/* int n; */
while(line > gg.tail_lineno){
line_buffer *temp;
temp = top;
line -= temp->len;
if(line < gg.tail_lineno){
int i;
char *s = temp->buf;
for(i = 0; i < (int)(temp->len-(gg.tail_lineno-line)); i++){
if(iskanjipos(s) || s[0] == 0x0d && s[1] == 0x0a)
s++;
s++;
}
temp->buf = s;
} else
top = top->link;
free_buffer(temp);
}
}
/*
* Printout.
*/
while(top){
line_buffer *temp;
int length;
temp = top;
/*
* We shouldn't use fputs(or other stream I/O routines) here
* since they will (1) convert EOLs to DOS format (2) they
* will return error if they encountered ^Z. Instead use
* write.
*/
length = strlen(top->buf);
if(write(1, top->buf, length) < 0){
perror("tail-write");
return 1;
}
top = top->link;
free_buffer(temp);
}
return 0;
}
/*
* -r option(with no numeric parameter). Sequential device.
*
*/
void sequential_reverse_print(FILE *fp)
{
line_buffer *top, *temp;
char buf[BUFFER_SIZE];
top = 0;
while(fgets_with_check(buf, BUFFER_SIZE, fp)){
temp = allocate_buffer(buf, strlen(buf));
temp->link = top;
top = temp;
}
while(top){
fputs_with_check(top->buf, NULL);
temp = top;
top = top->link;
free_buffer(temp);
}
}
/*
* -##r option. Block device.
*
*/
void block_reverse_print(FILE *fp)
{
unsigned line;
/* int c; */
long flast_bottom, current_top, position;
line_buffer *list_head, *top, *last, *temp;
int already_top;
char buf[BUFFER_SIZE];
/* Set file pointer at the last */
xfseek(fp, 0L, SEEK_END);
current_top = position = ftell(fp);
list_head = 0;
line = 0;
do {
top = last = 0;
if(current_top - gg.seek_block < 0){
xfseek(fp, 0L, SEEK_SET);
already_top = 1;
} else {
xfseek(fp, -(gg.seek_block + position - current_top), SEEK_CUR);
/* Skip garbages before the first EOL */
fgets_with_check(buf, BUFFER_SIZE, fp);
already_top = 0;
}
flast_bottom = current_top;
current_top = ftell(fp);
while(fgets_with_check(buf, BUFFER_SIZE, fp)){
if(top == 0){
top = last = allocate_buffer(buf, strlen(buf));
} else {
last->link = allocate_buffer(buf, strlen(buf));
last = last->link;
}
last->link = 0;
line++;
if((position = ftell(fp)) >= flast_bottom)
break;
}
while(line > gg.tail_lineno){
temp = top;
top = top->link;
free_buffer(temp);
line--;
}
/* (setq top (nreverse top)) */
list_head = top;
last = 0;
while(top->link){
temp = top->link;
top->link = last;
last = top;
top = temp;
}
top->link = last;
/* Printout top */
while(top){
temp = top;
fputs_with_check(top->buf, NULL);
top = top->link;
free_buffer(temp);
}
} while(!already_top && line < gg.tail_lineno);
}
/*
* -##b option. Block device.
*
*/
void block_find_tail(FILE *fp)
{
long fsize, position;
char buf[BUFFER_SIZE];
position = (long)gg.tail_lineno;
xfseek(fp, 0L, SEEK_END);
fsize = ftell(fp);
if(fsize < position)
position = fsize;
xfseek(fp, -position, SEEK_END);
while(fgets_with_check(buf, BUFFER_SIZE, fp))
fputs_with_check(buf, NULL);
}
/*
* +##b option. Block device.
*/
void block_find_head(FILE *fp)
{
long fsize, position;
char buf[BUFFER_SIZE];
position = (long)gg.tail_lineno;
xfseek(fp, 0L, SEEK_END);
fsize = ftell(fp);
if(fsize < position)
return;
xfseek(fp, position, SEEK_SET);
while(fgets_with_check(buf, BUFFER_SIZE, fp))
fputs_with_check(buf, NULL);
}
/*
* Toplevel dispatcher.
*
*/
int tail(FILE *fp)
{
boolean is_sequential = 1; // (fp == NULL);
/* Nide, to avoid "enum type mismatch" */
if(gg.mode == tail_reverse){
if(!is_sequential) {
block_reverse_print(fp);
} else if(gg.tail_lineno == (unsigned) -1) {
sequential_reverse_print(fp);
} else {
sequential_find_tail_line(fp);
}
} else if(gg.mode == from_tail){
if(!is_sequential){
if(gg.unit != BLOCK){ /* Changed Nide */
if (random_find_tail(fp) != 0) return 1;
} else
block_find_tail(fp);
} else {
if(gg.unit == LINE)
sequential_find_tail_line(fp);
else
sequential_find_tail_character(fp);
}
} else { /* mode==from_head */
if(gg.unit == BLOCK && !is_sequential)
block_find_head(fp);
else
find_head(fp);
}
return 0;
}
int tail_main(int argc, char **argv)
{ /* Changed Nide */
int nret = 0;
FILE *fp = NULL;
int /* c, */ i;
char *s;
boolean print_filename;
int noheader_opt = 0;
gg.tail_lineno = (unsigned)-1;/*tail_lineno==-1はtail_lineno未確定を示す */
gg.mode = from_tail;
gg.unit = LINE;
print_filename = FALSE;
for(i = 1; i < argc; i++){
s = argv[i];
if(*s == '-'){
if(!s[1])
break; /* "-"を、stdinを表す引数と解釈 */
} else if(*s == '+')
gg.mode = from_head;
else
break;
s++;
if(*s >= '0' && *s <= '9')
gg.tail_lineno = atoi(s);
/* tail_lineno == 0 である場合などは
この次のチェックでひっかかるから
大丈夫) */
while(*s >= '0' && *s <= '9')
s++;
while(*s){
switch (*s){ /* `tail_lineno' is checked later */
case 'b':
gg.unit = BLOCK;
break;
case 'c':
gg.unit = CHARACTER;
break;
case 'l':
gg.unit = LINE;
break;
case 'h':
noheader_opt = 1;
break;
case 'r':
gg.mode = tail_reverse;
break;
default:
return tail_usage();
}
s++;
}
}
if(gg.mode == tail_reverse)
gg.unit = LINE;
switch (gg.unit){
case LINE:
if(gg.mode != tail_reverse && gg.tail_lineno == (unsigned) -1)
gg.tail_lineno = 10;
gg.seek_block = 2048L;
break;
case BLOCK:
if(gg.tail_lineno == (unsigned) -1)
gg.tail_lineno = BLOCK_SIZE;
else
gg.tail_lineno *= BLOCK_SIZE;
break;
case CHARACTER:
if(gg.tail_lineno == (unsigned) -1)
gg.tail_lineno = 10;
gg.seek_block = (gg.tail_lineno / BUFFER_SIZE + 2) * BUFFER_SIZE;
break;
}
if(i + 2 <= argc && !noheader_opt) {
print_filename = TRUE;
}
if(i == argc) {
tail(NULL);
} else {
while(i < argc){
fp = (strcmp("-", argv[i]) ? fopen(argv[i], "r") : NULL);
if(fp == 0) return tail_error();
if(print_filename){
cwFputs("<<<", NULL);
cwFputs(strcmp(argv[i], "-") ? argv[i] : "(stdin)", NULL);
cwFputs(">>>\n", NULL);
}
if (tail(fp) != 0) {
nret = 1; goto EXIT;
}
if (fp != NULL) {
fclose(fp); fp == NULL;
}
i++;
}
}
EXIT:
if (fp != NULL) fclose(fp);
return 0;
}
int tail_usage(void)
{
cwFputs("tail [-+][#][blcrh] [file...]\n", (LPSTR)-1);
return -1;
}
/*-----------*/
/* diff_main */
/*-----------*/
/*
diff.c - public domain context diff program
if you want to use this command as 'diff file dir', define DIRFCMP
on VOS3, define VOS3
on MSDOS, define MSDOS ('MSDOS', 'unix' infer 'DIRFCMP')
with MSC, define MSC and link ssetargv.obj
on VOS3, stdout is re-opened with RECFM(VB),LRECL(255).
*/
/* by Nide */
/*
* Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
*/
#include <process.h>
void unlink_tmp(void) /* on MSDOS, must close TEMPFILE first */
{
if(gg.tempfd != NULL){
fclose(gg.tempfd);
}
}
/*
* Diff main program
*/
int diff_main(int argc, char **argv)
{
int nret = 0;
register int i;
register char *ap;
// char *fname[2];
char flg = 0;
while (argc > 1 && *(ap = argv[1]) == '-' && *++ap != EOS) {
while (*ap != EOS) {
switch ((*ap++)) {
case 'b':
gg.bflag++;
break;
case 'c':
if (*ap > '0' && *ap <= '9')
gg.cflag = *ap++ - '0';
else
gg.cflag = 3;
break;
case 'e':
gg.eflag++;
break;
case 'i':
gg.iflag++;
break;
default: {
char buf[80];
_snprintf(buf, sizeof(buf),
"Warning, bad option '%c'\n", ap[-1]);
cwFputs(buf, (LPSTR)-1);
}
}
}
argc--;
argv++;
}
if (argc != 3) {
nret = differror("Usage: diff [-bcei] file1 file2");
goto EXIT;
}
if (gg.cflag && gg.eflag) {
cwFputs("Warning, -c and -e are incompatible, -c supressed.\n",
(LPSTR)-1);
gg.cflag = FALSE;
}
argv++;
for (i = 0; i <= 1; i++) conv_to_unix_format(argv[i]);
for (i = 0; i <= 1; i++) fname[i] = argv[i];
if(isstdin(fname[0]) && isstdin(fname[1])) {
nret = differror("Can't diff two things both on standard input.");
goto EXIT;
}
for (i = 0; i <= 1; i++) {
if (isstdin(fname[i])){
gg.infd[i] = NULL;
if ((gg.tempfd = fopen(TEMPFILE, "w")) == NULL) {
nret = cant(TEMPFILE, "work", 1);
goto EXIT;
}
} else {
if(!flg && isdir(fname[i])){
if(i == 0 && isdir(fname[!i])){
nret = differror("Can't diff two directories. X-(");
goto EXIT;
} else {
flg++;
}
if(isstdin(fname[!i])){
nret = differror("Can't diff directory and stdin.");
goto EXIT;
}
fname[i] = dircat(fname[i], fname[!i]);
}
gg.infd[i] = fopen(fname[i], "r");
if (gg.infd[i] == NULL) {
nret = cant(fname[i], "input", 2); /* Fatal error */
goto EXIT;
}
}
}
if (gg.infd[0] == NULL && gg.infd[1] == NULL) {
cant(fname[0], "input", 0); /* not return */
nret = cant(fname[1], "input", 1);
goto EXIT;
}
/*
* Read input, building hash tables.
*/
input(0);
input(1);
squish();
sort(sfileA, slenA);
sort(sfileB, slenB);
/*
* Build equivalence classes.
*/
gg.member = (short *) fileB;
equiv();
gg.member = (short *) compact((char *)gg.member,(slenB+2)*sizeof(int),
"squeezing member vector");
/*
* Reorder equivalence classes into array class[]
*/
gg.class = (short *) fileA;
unsort();
gg.class = (short *) compact((char *)gg.class, (slenA + 2) * sizeof(int),
"compacting class vector");
/*
* Find longest subsequences
*/
gg.klist = (int *) myalloc((slenA + 2) * sizeof(int), "klist");
gg.clist = (CANDIDATE *)myalloc(gg.csize * sizeof(CANDIDATE), "clist");
i = subseq();
free((char *)gg.member);
free((char *)gg.class);
gg.match = (int *) myalloc((lenA + 2) * sizeof(int), "match");
unravel(gg.klist[i]);
free((char *) gg.clist);
free((char *) gg.klist);
/*
* Check for fortuitous matches and output differences
*/
gg.oldseek = (long *) myalloc((lenA + 2) * sizeof(*gg.oldseek), "oldseek");
gg.newseek = (long *) myalloc((lenB + 2) * sizeof(*gg.newseek), "newseek");
gg.textb = myalloc(sizeof(gg.text), "textbuffer");
if (check(fname[0], fname[1])) {
cwFputs("Spurious match, output is not optimal\n", (LPSTR)-1);
}
output(fname[0], fname[1]);
EXIT:
if (gg.infd[0] != NULL) gg.infd[0] = 0;
gg.infd[0] = NULL;
if (gg.infd[1] != NULL) gg.infd[1] = 0;
gg.infd[1] = NULL;
unlink_tmp();
return nret;
}
/*
* Read the file, building hash table
*/
void input(int which)
/* 0 or 1 to redefine infd[] */
{
register DIFF_LINE *lentry;
register int linect = 0;
FILE *fd;
#define LSIZE_INC 200 /* # of line entries to alloc at once */
int lsize = LSIZE_INC;
lentry = (DIFF_LINE *) myalloc(sizeof(DIFF_LINE) * (lsize + 3), "line");
fd = gg.infd[which];
while (!getline(fd, gg.text)) {
if (++linect >= lsize) {
lsize += 200;
lentry = (DIFF_LINE *) compact((char *) lentry,
(lsize + 3) * sizeof(DIFF_LINE),
"extending line vector");
}
lentry[linect].hash = hash(gg.text);
}
/*
* If input was from stdin ("-" command), finish off the temp file.
*/
if (fd == NULL) {
gg.tempfd = gg.infd[which] = freopen(TEMPFILE, "r", gg.tempfd);
}
/*
* If we wanted to be stingy with memory, we could realloc lentry down to
* its exact size (+3 for some odd reason) here. No need?
*/
gg.len[which] = linect;
gg.file[which] = lentry;
}
/*
* Look for initial and trailing sequences that have identical hash values.
* Don't bother building them into the candidate vector.
*/
void squish(void)
{
register int i;
register DIFF_LINE *ap;
register DIFF_LINE *bp;
int j;
int k;
/*
* prefix -> first line (from start) that doesn't hash identically
*/
i = 0;
ap = &fileA[1];
bp = &fileB[1];
while (i < lenA && i < lenB && ap->hash == bp->hash) {
i++;
ap++;
bp++;
}
gg.prefix = i;
/*
* suffix -> first line (from end) that doesn't hash identically
*/
j = lenA - i;
k = lenB - i;
ap = &fileA[lenA];
bp = &fileB[lenB];
i = 0;
while (i < j && i < k && ap->hash == bp->hash) {
i++;
ap--;
bp--;
}
gg.suffix = i;
/*
* Tuck the counts away
*/
for (k = 0; k <= 1; k++) {
gg.sfile[k] = gg.file[k] + gg.prefix;
j = gg.slen[k] = gg.len[k] - gg.prefix - gg.suffix;
for (i = 0, ap = gg.sfile[k]; i <= gg.slen[k]; i++, ap++) {
ap->serial = i;
}
}
}
/*
* Sort hash entries
*/
void sort(DIFF_LINE *vector, int vecsize)
/* What to sort */
/* How many to sort */
{
register int j;
register DIFF_LINE *aim;
register DIFF_LINE *ai;
int mid;
int k;
DIFF_LINE work;
for (j = 1; j <= vecsize; j *= 2);
mid = (j - 1);
while ((mid /= 2) != 0) {
k = vecsize - mid;
for (j = 1; j <= k; j++) {
for (ai = &vector[j]; ai > vector; ai -= mid) {
aim = &ai[mid];
if (aim < ai)
break; /* ?? Why ?? */
if (aim->hash > ai->hash ||
aim->hash == ai->hash &&
aim->serial > ai->serial)
break;
work.hash = ai->hash;
ai->hash = aim->hash;
aim->hash = work.hash;
work.serial = ai->serial;
ai->serial = aim->serial;
aim->serial = work.serial;
}
}
}
}
/*
* Build equivalence class vector
*/
void equiv(void)
{
register DIFF_LINE *ap;
union {
DIFF_LINE *bp;
short *mp;
} r;
register int j;
DIFF_LINE *atop;
j = 1;
ap = &sfileA[1];
r.bp = &sfileB[1];
atop = &sfileA[slenA];
while (ap <= atop && j <= slenB) {
if (ap->hash < r.bp->hash) {
ap->hash = 0;
ap++;
} else if (ap->hash == r.bp->hash) {
ap->hash = j;
ap++;
} else {
r.bp++;
j++;
}
}
while (ap <= atop) {
ap->hash = 0;
ap++;
}
sfileB[slenB + 1].hash = 0;
ap = &sfileB[0];
atop = &sfileB[slenB];
r.mp = &gg.member[0];
while (++ap <= atop) {
r.mp++;
*r.mp = -(ap->serial);
while (ap[1].hash == ap->hash) {
ap++;
r.mp++;
*r.mp = ap->serial;
}
}
r.mp[1] = -1;
}
/*
* Build class vector
*/
void unsort(void)
{
register int *temp;
register int *tp;
union {
DIFF_LINE *ap;
short *cp;
} u;
DIFF_LINE *evec;
short *eclass;
temp = (int *) myalloc((slenA + 1) * sizeof(int), "unsort scratch");
u.ap = &sfileA[1];
evec = &sfileA[slenA];
while (u.ap <= evec) {
temp[u.ap->serial] = u.ap->hash;
u.ap++;
}
/*
* Copy into class vector and free work space
*/
u.cp = &gg.class[1];
eclass = &gg.class[slenA];
tp = &temp[1];
while (u.cp <= eclass)
*u.cp++ = *tp++;
free((char *) temp);
}
/*
* Generate maximum common subsequence chain in clist[]
*/
int subseq(void)
{
int a;
register unsigned ktop;
register int b;
register int s;
unsigned r;
int i;
int cand;
gg.klist[0] = newcand(0, 0, -1);
gg.klist[1] = newcand(slenA + 1, slenB + 1, -1);
ktop = 1; /* -> guard entry */
for (a = 1; a <= slenA; a++) {
/*
* For each non-zero element in fileA ...
*/
if ((i = gg.class[a]) == 0)
continue;
cand = gg.klist[0]; /* No candidate now */
r = 0; /* Current r-candidate */
do {
/*
* Perform the merge algorithm
*/
if ((b = gg.member[i]) < 0)
b = -b;
if ((s = search(r, ktop, b)) != 0) {
if (gg.clist[gg.klist[s]].b > b) {
gg.klist[r] = cand;
r = s;
cand = newcand(a, b, gg.klist[s - 1]);
}
if (s >= (int)ktop) {
gg.klist[ktop + 1] = gg.klist[ktop];
ktop++;
break;
}
}
} while (gg.member[++i] > 0);
gg.klist[r] = cand;
}
return (ktop - 1); /* Last entry found */
}
int newcand(int a, int b, int pred)
// int a; /* Line in fileA */
// int b; /* Line in fileB */
// int pred; /* Link to predecessor, index in cand[] */
{
register CANDIDATE far *new;
gg.clength++;
if (++gg.clength >= gg.csize) {
gg.csize += CSIZE_INC;
gg.clist = (CANDIDATE *) compact((char *) gg.clist,
gg.csize * sizeof(CANDIDATE),
"extending clist");
}
new = &gg.clist[gg.clength - 1];
new->a = a;
new->b = b;
new->link = pred;
return (gg.clength - 1);
}
/*
* Search klist[low..top] (inclusive) for b. If klist[low]->b >= b,
* return zero. Else return s such that klist[s-1]->b < b and
* klist[s]->b >= b. Note that the algorithm presupposes the two
* preset "fence" elements, (0, 0) and (slenA, slenB).
*/
unsigned search(unsigned low, unsigned high, int b)
{
register int temp;
register unsigned mid;
if (gg.clist[gg.klist[low]].b >= b)
return (0);
while ((mid = (low + high) / 2) > low) {
if ((temp = gg.clist[gg.klist[mid]].b) > b)
high = mid;
else if (temp < b)
low = mid;
else {
return (mid);
}
}
return (mid + 1);
}
void unravel(int k)
{
register int i;
register CANDIDATE far *cp;
int first_trailer;
int difference;
first_trailer = lenA - gg.suffix;
difference = lenB - lenA;
for (i = 0; i <= lenA; i++) {
gg.match[i] = (i <= gg.prefix) ? i
: (i > first_trailer) ? i + difference
: 0;
}
while (k != -1) {
cp = &gg.clist[k];
gg.match[cp->a + gg.prefix] = cp->b + gg.prefix;
k = cp->link;
}
}
/*
* Check for hash matches (jackpots) and collect random access indices to
* the two files.
*
* It should be possible to avoid doing most of the ftell's by noticing
* that we are not doing a context diff and noticing that if a line
* compares equal to the other file, we will not ever need to know its
* file position. FIXME.
*/
int check(char *fileAname, char *fileBname)
{
register int a; /* Current line in file A */
register int b; /* Current line in file B */
int jackpot;
/*
* The VAX C ftell() returns the address of the CURRENT record, not the
* next one (as in DECUS C or, effectively, other C's). Hence, the values
* are "off by one" in the array. OFFSET compensates for this.
*/
#define OFFSET 0
b = 1;
rewind(gg.infd[0]);
rewind(gg.infd[1]);
/*
* See above; these would be over-written on VMS anyway.
*/
gg.oldseek[0] = ftell(gg.infd[0]);
gg.newseek[0] = ftell(gg.infd[1]);
jackpot = 0;
for (a = 1; a <= lenA; a++) {
if (gg.match[a] == 0) {
/* Unique line in A */
gg.oldseek[a + OFFSET] = ftell(gg.infd[0]);
getline(gg.infd[0], gg.text);
continue;
}
while (b < gg.match[a]) {
/* Skip over unique lines in B */
gg.newseek[b + OFFSET] = ftell(gg.infd[1]);
getline(gg.infd[1], gg.textb);
b++;
}
/*
* Compare the two, supposedly matching, lines. Unless we are going
* to print these lines, don't bother to remember where they are. We
* only print matching lines if a context diff is happening, or if a
* jackpot occurs.
*/
if (gg.cflag) {
gg.oldseek[a + OFFSET] = ftell(gg.infd[0]);
gg.newseek[b + OFFSET] = ftell(gg.infd[1]);
}
getline(gg.infd[0], gg.text);
getline(gg.infd[1], gg.textb);
if (!streq(gg.text, gg.textb)) {
char buf[80];
_snprintf(buf, sizeof(buf), "Spurious match:\n");
cwFputs(buf, (LPSTR)-1);
_snprintf(buf, sizeof(buf), "line %d in %s, \"%s\"\n",
a, fileAname, gg.text);
cwFputs(buf, (LPSTR)-1);
_snprintf(buf, sizeof(buf), "line %d in %s, \"%s\"\n",
b, fileBname, gg.textb);
cwFputs(buf, (LPSTR)-1);
gg.match[a] = 0;
jackpot++;
}
b++;
}
for (; b <= lenB; b++) {
gg.newseek[b + OFFSET] = ftell(gg.infd[1]);
getline(gg.infd[1], gg.textb);
}
/*
* The logical converse to the code up above, for NON-VMS systems, to
* store away an fseek() pointer at the beginning of the file. For VMS,
* we need one at EOF...
*/
return (jackpot);
}
void output(char *fileAname, char *fileBname)
{
register int astart;
register int aend = 0;
int bstart;
register int bend;
rewind(gg.infd[0]);
rewind(gg.infd[1]);
gg.match[0] = 0;
gg.match[lenA + 1] = lenB + 1;
if (!gg.eflag) {
if (gg.cflag) {
/*
* Should include ctime style dates after the file names, but
* this would be non-trivial on OSK. Perhaps there should be a
* special case for stdin.
*/
char buf[80];
_snprintf(buf, sizeof(buf), "*** %s\n--- %s\n",
fileAname, fileBname);
cwFputs(buf, NULL);
}
/*
* Normal printout
*/
for (astart = 1; astart <= lenA; astart = aend + 1) {
/*
* New subsequence, skip over matching stuff
*/
while (astart <= lenA
&& gg.match[astart] == (gg.match[astart - 1] + 1))
astart++;
/*
* Found a difference, setup range and print it
*/
bstart = gg.match[astart - 1] + 1;
aend = astart - 1;
while (aend < lenA && gg.match[aend + 1] == 0)
aend++;
bend = gg.match[aend + 1] - 1;
gg.match[aend] = bend;
change(astart, aend, bstart, bend);
}
} else {
/*
* Edit script output -- differences are output "backwards" for the
* benefit of a line-oriented editor.
*/
for (aend = lenA; aend >= 1; aend = astart - 1) {
while (aend >= 1
&& gg.match[aend] == (gg.match[aend + 1] - 1)
&& gg.match[aend] != 0)
aend--;
bend = gg.match[aend + 1] - 1;
astart = aend + 1;
while (astart > 1 && gg.match[astart - 1] == 0)
astart--;
bstart = gg.match[astart - 1] + 1;
gg.match[astart] = bstart;
change(astart, aend, bstart, bend);
}
}
if (lenA == 0)
change(1, 0, 1, lenB);
}
/*
* Output a change entry: fileA[astart..aend] changed to fileB[bstart..bend]
*/
void change(int astart, int aend, int bstart, int bend)
{
char c;
/*
* This catches a "dummy" last entry
*/
if (astart > aend && bstart > bend)
return;
c = (astart > aend) ? 'a' : (bstart > bend) ? 'd' : 'c';
if (gg.cflag)
cwFputs("**************\n*** ", NULL);
if (c == 'a' && !gg.cflag)
range(astart - 1, astart - 1, 0); /* Addition: just print one
* odd # */
else
range(astart, aend, 0); /* Print both, if different */
if (!gg.cflag) {
char buf[2];
buf[0] = c;
buf[1] = '\0';
cwFputs(buf, NULL);
if (!gg.eflag) {
if (c == 'd')
range(bstart - 1, bstart - 1, 1);
/* Deletion: just print * one odd # */
else
range(bstart, bend, 1);
/* Print both, if different */
}
}
cwFputs("\n", NULL);
if ((!gg.eflag && c != 'a') || gg.cflag) {
fetch(gg.oldseek, astart, aend, lenA, gg.infd[0],
gg.cflag ? (c == 'd' ? "- " : "! ") : "< ");
if (gg.cflag) {
cwFputs("--- ", NULL);
range(bstart, bend, 1);
cwFputs(" -----\n", NULL);
} else if (astart <= aend && bstart <= bend)
cwFputs("---\n", NULL);
}
fetch(gg.newseek, bstart, bend, lenB, gg.infd[1],
gg.cflag ? (c == 'a' ? "+ " : "! ") : (gg.eflag ? "" : "> "));
if (gg.eflag && bstart <= bend)
cwFputs(".\n", NULL);
}
/*
* Print a range
*/
void range(int from, int to, int w)
{
char buf[80];
if (gg.cflag) {
if ((from -= gg.cflag) <= 0)
from = 1;
if ((to += gg.cflag) > gg.len[w])
to = gg.len[w];
}
if (to > from) {
_snprintf(buf, sizeof(buf), "%d,%d", from, to); cwFputs(buf, NULL);
} else if (to < from) {
_snprintf(buf, sizeof(buf), "%d,%d", to, from); cwFputs(buf, NULL);
} else {
_snprintf(buf, sizeof(buf), "%d", from); cwFputs(buf, NULL);
}
}
/*
* Print the appropriate text
*/
void fetch(long *seekvec,
int start,
int end,
int trueend,
FILE *fd,
char *pfx)
{
register int i;
register int first;
register int last;
if (gg.cflag) {
if ((first = start - gg.cflag) <= 0)
first = 1;
if ((last = end + gg.cflag) > trueend)
last = trueend;
} else {
first = start;
last = end;
}
/* added by Nide */
if (first == last + 1) { /* do nothing */
} else
/* added by Nide end */
if (fseek(fd, seekvec[first], 0) != 0) {
char buf[80];
_snprintf(buf, sizeof(buf),
"?Can't read line %d at %08lx (hex) in file%c\n",
start, seekvec[first],
(fd == gg.infd[0]) ? 'A' : 'B');
cwFputs(buf, NULL);
} else {
for (i = first; i <= last; i++) {
if (fgetss(gg.text, sizeof(gg.text), fd) == NULL) {
char buf[80];
_snprintf(buf, sizeof(buf), "** Unexpected end of file\n");
cwFputs(buf, NULL);
break;
}
cwFputs((gg.cflag && (i < start || i > end)) ? " " : pfx,
NULL);
cwFputs(gg.text, NULL);
cwFputs("\n", NULL);
}
}
}
/*
* Input routine, read one line to buffer[], return TRUE on eof, else FALSE.
* The terminating newline is always removed. If "-b" was given, trailing
* whitespace (blanks and tabs) are removed and strings of blanks and
* tabs are replaced by a single blank. Getline() does all hacking for
* redirected input files.
*/
int getline(FILE *fd, char *buffer)
{
register char *top;
register char *fromp;
register char c;
if (fgetss(buffer, sizeof(gg.text), fd) == NULL) {
*buffer = EOS;
return (TRUE);
}
if (fd == NULL)
fputss(buffer, gg.tempfd);
if (gg.bflag || gg.iflag) {
top = buffer;
fromp = buffer;
while ((c = *fromp++) != EOS) {
if (gg.bflag && (c == ' ' || c == '\t')) {
c = ' ';
while (*fromp == ' ' || *fromp == '\t')
fromp++;
}
if (gg.iflag)
c = tolower(c);
*top++ = c;
}
if (gg.bflag && top[-1] == ' ')
top--;
*top = EOS;
}
return (FALSE);
}
unsigned short crc16a[] = {
0000000, 0140301, 0140601, 0000500,
0141401, 0001700, 0001200, 0141101,
0143001, 0003300, 0003600, 0143501,
0002400, 0142701, 0142201, 0002100,
};
unsigned short crc16b[] = {
0000000, 0146001, 0154001, 0012000,
0170001, 0036000, 0024000, 0162001,
0120001, 0066000, 0074000, 0132001,
0050000, 0116001, 0104001, 0043000,
};
/*
* Return the CRC16 hash code for the buffer
* Algorithm from Stu Wecker (Digital memo 130-959-002-00).
*/
unsigned short hash(char *buffer)
{
register unsigned short crc;
register char *tp;
register short temp;
crc = 0;
for (tp = buffer; *tp != EOS;) {
temp = *tp++ ^ crc; /* XOR crc with new char */
crc = (crc >> 8)
^ crc16a[(temp & 0017)]
^ crc16b[(temp & 0360) >> 4];
}
return ((crc == 0) ? (unsigned short) 1 : crc);
}
/*
* Allocate or crash.
*/
char *myalloc(unsigned amount, char *why)
{
register char *pointer;
if ((pointer = malloc((unsigned) amount)) == NULL) {
noroom(why);
return NULL;
}
return (pointer);
}
/*
* Reallocate pointer, compacting storage
*
* The "compacting storage" part is probably not relevant any more.
* There used to be horrid code here that malloc'd one byte and freed
* it at magic times, to cause garbage collection of the freespace
* or something. It's safely gone now, you didn't have to see it.
* -- John Gilmore, Nebula Consultants, Sept 26, 1986
*/
char *compact(char *pointer, unsigned new_amount, char *why)
{
register char *new_pointer;
if ((new_pointer = realloc(pointer, (unsigned) new_amount)) == NULL) {
noroom(why);
return NULL;
}
return (new_pointer);
}
void noroom(char *why)
{
char buf[80];
_snprintf(buf, sizeof(buf), "?DIFF-F-out of room when %s\n", why);
cwFputs(buf, (LPSTR)-1);
MessageBox(NULL, "IO_ERROR", "cwtools.dll", MB_OK);
// exit(IO_ERROR);
}
/*
* Can't open file message
*/
int cant(char *filename,
char *what,
int fatalflag)
{
char buf[80];
_snprintf(buf, sizeof(buf),
"Can't open %s file \"%s\": ", what, filename);
cwFputs(buf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
// perror("");
if (fatalflag) {
return fatalflag;
}
return 0;
}
/*
* TRUE if strings are identical
*/
int streq(char *s1, char *s2)
{
while (*s1++ == *s2) {
if (*s2++ == EOS)
return (TRUE);
}
return (FALSE);
}
/*
* Error message before retiring.
*/
/* VARARGS */
int differror(char *format, ...)
{
char buf[0x100];
va_list argptr;
va_start(argptr, format);
_vsnprintf(buf, sizeof(buf), format, argptr);
cwFputs(buf, (LPSTR)-1);
va_end(argptr);
cwFputs("\n", (LPSTR)-1);
return 1;
}
/*
* Like fput() except that it puts a newline at the end of the line.
*/
void fputss(char *s, FILE *iop)
{
if (iop == NULL) {
cwPuts(s);
} else {
fputs(s, iop);
putc('\n', iop);
}
}
/*
* Fgetss() is like fgets() except that the terminating newline
* is removed.
*/
char *fgetss(char *s, int n, FILE *iop)
{
register char *cs;
if (((iop == NULL) ? cwFgets(s, n, NULL) : fgets(s, n, iop)) == NULL)
return ((char *) NULL);
cs = s + strlen(s) - 1;
if (*cs == '\n')
*cs = '\0';
return (s);
}
/* From here, added by Nide */
int isdir(char *fnm) /* on TURBOC, which files are needed to be included? */
{
struct stat statbuf;
char *p, *q, *r;
for(p = q = NULL, r = fnm; *r;
p = q, q = r, r += (iskanjipos(r) ? 2 : 1));
if(q == NULL || isdelim(*q) ||
*q == '.' && (p == NULL || isdelim(*p) || *p == '.')) return(1);
return(stat(fnm, &statbuf) == 0 && (statbuf . st_mode & S_IFDIR));
}
char *difftmpnam(void) /* ad hoc */
{
char *p;
sprintf(gg.s_name, "dtmp%04x.$$$", (short)getpid());
if(NULL == (p = getenv("TMP")) &&
NULL == (p = getenv("TEMP"))) return(gg.s_name);
return(dircat(p, gg.s_name));
}
char *basefname(char *fnm)
{
char *p, *q;
for(p = NULL, q = fnm; *q; q += (iskanjipos(q) ? 2 : 1)){
if(isdelim(*q)) p = q;
}
return(p == NULL ? fnm : ++p);
}
char *dircat(char *dir, char *fnm)
{
char *buf, *p, *q;
fnm = basefname(fnm);
if(NULL == (buf = malloc(strlen(dir) + 1 + strlen(fnm) + 1))){
cwFputs("diff: Memory not enough.\n", NULL);
return NULL;
}
for(p = NULL, q = dir; *q; p = q, q += (iskanjipos(q) ? 2 : 1));
sprintf(buf, (p == NULL || !isdelim(*p)) ? "%s/%s" : "%s%s",
dir, fnm);
return(buf);
}
/*---------*/
/* ls_main */
/*---------*/
/**
* UNIX like ls (originally for Human68k)
*
* Public domain: written by Kaoru Maeda, March, 1989.
* Modified for MS-DOS by Yasushi Saito, April, 1989.
*
* Modified by Yasushi Saito(Oct 5 1989) 'ls -ld' works good.
*/
int ls_usage(void)
/* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
{
cwFputs("Usage: ls [-RadCxBXlrtFsU1c] <files>...\n\
-R : recursive directory search\n\
-a : print hidden files, _* files\n\
-d : do not look inside directory\n\
-C : vertical sort\n\
-x : horizontal sort\n\
-B : sort by filesize\n\
-X : sort by extention\n\
-l : long output\n\
-r : reverse sort\n\
-t : sort by file timestamp\n\
-F : display file type\n\
-s : display file size\n\
-U : no sorting\n\
-1 : 1 file per line\n\
-c : color output\n", (LPSTR)-1);
return 2;
}
/*
* Allocate one space for dirfile.
*
*/
dirfile *allocate_dir(char *name)
{
dirfile *p;
p = xmalloc(sizeof(dirfile));
p->fullname = xstrdup(name);
return p;
}
/*
* Push the directory-chain to the directory stack.
*
*/
void link_dir_chain(dirfile *top, dirfile *last)
{
last->next = gg.dirs;
gg.dirs = top;
}
/*
* Push one directory to the directory stack.
*/
void add_dir_list(char *name)
{
dirfile *p;
p = allocate_dir(name);
link_dir_chain(p, p);
}
/*
* Add one file to the output file chain.
*
*/
void add_file_list(char *name, bool fullname, unsigned volmask)
{
int intended_as_directory;
register bool c = false;
if(intended_as_directory = regularize_pathname(name)) {
volmask &= ~VOL_MASK;
}
/* Add Nide */
if((volmask & VOL_MASK) && (volmask & ~VOL_MASK)){
if(c = add_file_list_sub(name, fullname, VOL_MASK,
true, intended_as_directory))
gg.filenum++;
volmask &= ~VOL_MASK;
}
add_file_list_sub(name, fullname, volmask, c, intended_as_directory);
}
void say_noex(char *s, int dirmode)
{
cwFputs(s_conv_to_unix_format(s), (LPSTR)-1);
if(dirmode) cwFputs("/", (LPSTR)-1);
cwFputs(" not exist.\n", (LPSTR)-1);
}
long _xfindfirst(char *p, struct _finddata_t *f)
{
return _findfirst(p, f);
}
int can_cd_there(char *s)
{
return SetCurrentDirectory(s);
}
bool add_file_list_sub(char *name,
bool fullname,
unsigned volmask,
bool nomsg,
int intended_as_directory)
/* separated from add_file_list() by Nide; これが呼ばれるとき、volmaskの
第3ビットとそれ以外が同時に立つことはない(ようにすること) */
{
struct _finddata_t fb;
long lfind;
diff_file *p, *q, *r;
int c;
char *rs;
/* Get file status */
memset(&fb, 0, sizeof(fb));
fb.attrib = volmask;
lfind = _xfindfirst(name, &fb);
if(lfind != -1){
_findclose(lfind);
} else { /* Changed Nide */
/*
* Failed to read the NAME as normal file. is it a special
* file:-), or root??. Check it here.
*/
/* char buf[128]; */
/* volmask check add Nide */
if(volmask & VOL_MASK){
/* 小文字まじりの変なvolume label対応。ああめんどくさ */
char tmp[10];
if(is_alpha(*name) && name[1] == ':'){
strncpy(tmp, name, 2);
strcpy(tmp+2, "*.*");
} else {
strcpy(tmp, "*.*");
}
memset(&fb, 0, sizeof(fb));
fb.attrib = VOL_MASK;
lfind = _findfirst(tmp, &fb);
if (lfind != -1) {
goto notexist;
} else {
_findclose(lfind);
}
if(stricmp(fb.name, strip_directory_part(name))) {
goto notexist;
}
/* そうでない場合、変ではあるがvolume labelがある */
} else if(can_cd_there(name)){
fb.attrib = DIR_MASK;
strcpy(fb.name, strip_directory_part(name));
fb.size = 0;
dosdatetime_to_time_t(0x21, 0, &fb.time_write);
} else {
notexist:
if(!nomsg) {
say_noex(name, 0);
}
return false;
}
}
/*
* Ignore the plain file, which is intended to be a directory
* file(i.e. ends with '\').
*
* By this, LS will return error if the pathname is specified as
* '\etc\passwd\', even if the plain file '\etc\passwd' exists.
*/
if(!(fb.attrib & DIR_MASK) && intended_as_directory){
if(!nomsg) {
say_noex(name, 1);
}
return false;
}
if(fullname && !gg.d_opt && (fb.attrib & DIR_MASK)){
add_dir_list(name);
return true;
}
p = xmalloc(sizeof(diff_file));
rs = strip_directory_part(name);
if(*gg.current_directory == 0){
/* Set current directory */
strncpy(gg.current_directory, name, rs - name);
gg.current_directory[rs - name] = 0;
}
if(fullname /* && (rs != name) */ ) {
rs = name;
}
conv_to_unix_format(p->name = xstrdup(rs)); /* Nide */
p->attr = fb.attrib;
time_t_to_dosdatetime(&fb.time_write, &p->date.dt.d, &p->date.dt.t);
p->size = fb.size;
/* Insert the file into the proper position */
for(r = NULL, q = gg.files; q; r = q, q = q->next){
if(gg.t_opt){
unsigned short pd, qd;
pd = p->date.dt.d, qd = q->date.dt.d;
if(qd > pd) c = 1;
else if(qd < pd) c = -1;
else {
pd = p->date.dt.t, qd = q->date.dt.t;
if(qd > pd) c = 1;
else if(qd < pd) c = -1;
else goto name_comparison;
}
} else if(gg.X_opt){
off_t ps, qs;
ps = p->size, qs = q->size;
if(qs > ps) c = 1;
else if(qs < ps) c = -1;
else goto name_comparison;
} else if(gg.S_opt){
c = 1;
} else if(gg.Sort_by_ext_opt){
char *pdot = strchr(p->name, '.');
char *qdot = strchr(q->name, '.');
char n = 0;
if(pdot == NULL) pdot = &n;
if(qdot == NULL) qdot = &n;
if(!(c = strcmp(pdot, qdot))) goto name_comparison;
} else {
name_comparison:
c = strcmp(p->name, q->name);
if(!c) c = (q->attr & VOL_MASK) - (p->attr & VOL_MASK);
/* Add Nide,
同名のvolume labelとfileが存在する場合に備えて */
if(!c){
free(p->name);
free(p);
return false; /* false Ok? */
}
}
if(gg.r_opt) c = -c;
if(c < 0) break;
}
if(r) {
r->next = p;
} else {
gg.files = p;
}
p->next = q;
return true;
}
int executable_p(diff_file *p)
{
register char *cp;
if(p->attr & DIR_MASK) return true;
if(p->attr & (VOL_MASK | DEV_MASK)) return false;
cp = p->name, cp += strlen(cp) - 4;
return (cp >= p->name && *cp++ == '.' &&
(!stricmp(cp, "bat") || !stricmp(cp, "exe") ||
!stricmp(cp, "com")));
}
int F_char(diff_file *p)
{
if(gg.F_opt){
if(p->attr & DIR_MASK) return '/';
if(executable_p(p)) return '*';
}
return '\0'; /* Nide */
}
void nameout(diff_file *p)
{ /* Add Nide */
int attr = p->attr, color;
char *name = p->name, *ext;
char buf[0x100];
if(gg.c_opt && 0 != (color = (
attr & VOL_MASK ? 37 :
attr & DEV_MASK ? 34 :
attr & DIR_MASK ? 36 :
attr & (SYS_MASK | INV_MASK) ? 35 :
name <= (ext = name + strlen(name) - 4) && *ext++ == '.' ? (
!stricmp(ext, "bak") || !stricmp(ext, "old") ? 31 :
!stricmp(ext, "bat") ? 33 :
!stricmp(ext, "exe") || !stricmp(ext, "com") ? 32 :
!stricmp(ext, "sys") || !stricmp(ext, "drv") ? 35 : 0
) : 0))){
_snprintf(buf, sizeof(buf), "\033[%dm", color); cwFputs(buf, NULL);
if(attr & VOL_MASK) cwFputs("\033[7m", NULL); /* yueno@titech */
}
cwFputs(s_conv_to_unix_format(name), NULL);
if(gg.c_opt && color) cwFputs("\033[m", NULL);
}
void print_short(diff_file *p, int col)
{ /* Changed Nide */
int F_ch;
char buf[0x100];
if(!p){
gg.s_prev_sp = 0;
cwFputs("\n", NULL);
return;
}
_snprintf(buf, sizeof(buf), "%*s", gg.s_prev_sp, ""); cwFputs(buf, NULL);
if(gg.s_opt) {
_snprintf(buf, sizeof(buf),
"%4ld ", (p->size + BLOCK_SIZE - 1) / BLOCK_SIZE);
cwFputs(buf, NULL);
}
nameout(p);
if(!gg.x_opt && !gg.C_opt){
if('\0' != (F_ch = F_char(p)))
putchar(F_ch);
gg.s_prev_sp = 0;
return;
} else {
gg.s_prev_sp = col - strlen(p->name) - (gg.s_opt ? 5 : 0) -
('\0' != (F_ch = F_char(p)) ? (putchar(F_ch), 1) : 0);
}
}
void multi_output(void)
{
register diff_file *p, *q;
int maxlen, nfil, ncol, wcol, nrow;
if(!gg.files) return;
maxlen = nfil = 0;
for(p = gg.files; p; p = p->next){
register int l = strlen(p->name);
if(l > maxlen) maxlen = l;
nfil++;
}
if(gg.s_opt) maxlen += 5;
wcol = (maxlen + 9) & ~7;
ncol = gg.screenwidth / wcol;
nrow = (nfil - 1) / ncol + 1;
if(gg.x_opt){ /* Changed Nide、行末に余分な空白を付けないよう */
int j = 0;
for(p = gg.files; p; q = p->next, free(p), p = q){
print_short(p, wcol);
if(++j == ncol){
print_short(NULL, 0);
j = 0;
}
free(p->name);
}
if(nfil % ncol) print_short(NULL, 0);
} else { /* -C option */
/* Changed Nide、行末に余分な空白を付けないよう */
int i, j, k;
for(i = nrow; i--;){
p = gg.files;
for(k = nrow - i; --k;)
if(p) p = p->next;
for(j = 0; j < ncol; j++){
if(p && (i || nfil % ncol == 0 ||
j < nfil % ncol))
print_short(p, wcol);
for(k = nrow - 1; k--;)
if(p) p = p->next;
if(nfil % ncol == 0 || j < nfil % ncol)
if(p) p = p->next;
}
print_short(NULL, 0);
}
for(p = gg.files; p; q = p->next, free(p), p = q)
free(p->name);
/* Nide, avoid "q used before set" */
}
}
void one_output(void)
{
diff_file *p, *q;
for(p = gg.files; p; q = p->next, free(p), p = q){
print_short(p, 0);
cwFputs("\n", NULL);
free(p->name);
/* Nide, avoid "q used before set" */
}
}
void short_output(void)
{
if(gg.C_opt || gg.x_opt) multi_output(); else one_output();
}
void long_output(void)
{
diff_file *p, *q;
unsigned int month;
char buf[0x100];
for(p = gg.files; p; q = p->next, free(p), p = q){
/* Nide, to avold "q may used before set" */
char mode[8];
if(gg.s_opt){
_snprintf(buf, sizeof(buf), "%4ld ",
(p->size + BLOCK_SIZE - 1) / BLOCK_SIZE);
cwFputs(buf, NULL);
} /* Add Nide */
mode[0] = p->attr & DEV_MASK ? 'c' :
p->attr & DIR_MASK ? 'd' :
p->attr & VOL_MASK ? 'v' : '-';
mode[1] = p->attr & ARC_MASK ? 'a' : '-';
mode[2] = p->attr & SYS_MASK ? 's' : '-';
mode[3] = p->attr & INV_MASK ? 'h' : '-';
mode[4] = 'r';
mode[5] = p->attr & RDO_MASK ? '-' : 'w';
mode[6] = executable_p(p) ? 'x' : '-';
mode[7] = F_char(p);
/* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
if((month = p->date.b.bh.month) > 12) {
month = 0;
}
_snprintf(buf, sizeof(buf),
"%.7s %7ld %.3s %2d %4d %02d:%02d ",
mode, p->size, month_name + month * 3,
p->date.b.bh.day,
p->date.b.bh.year + 1980,
(p->date.dt.t / 0x0800) & 0x1F,
(p->date.dt.t / 0x0020) & 0x3F);
cwFputs(buf, NULL);
nameout(p);
_snprintf(buf, sizeof(buf), "%.1s\n", mode + 7); cwFputs(buf, NULL);
free(p->name);
}
}
void output_files(void)
{
dirfile *top, *last;
diff_file *f;
char *fn, *strip;
if(!gg.d_opt && gg.R_opt){
top = last = 0;
fn = gg.current_directory + strlen(gg.current_directory);
for(f = gg.files; f; f = f->next){
if(f->attr & DIR_MASK){
strip = strip_directory_part(f->name);
if(*strip != '.'){
strcpy(fn, strip);
if(top == 0)
top = last = allocate_dir(
gg.current_directory);
else {
last->next = allocate_dir(
gg.current_directory);
last = last->next;
}
}
}
}
if(top)
link_dir_chain(top, last);
}
if(gg.l_opt)
long_output();
else
short_output();
gg.files = NULL;
*gg.current_directory = 0;
}
void output_dirs(void)
{
dirfile *p;
char buf[PATHNAMELENGTH], *cp;
struct _finddata_t fb;
long lfind;
while((p = gg.dirs)){
gg.dirs = p->next;
if(gg.disp_dir){
/* Nide,
非ANSIコンパイラの便のために文字列連接をやめた */
char buf[0x100];
_snprintf(buf, sizeof(buf),
"\n%s:\n", s_conv_to_unix_format(p->fullname));
cwFputs(buf, NULL);
}
cp = p->fullname + strlen(p->fullname) - 1;
{
char *dl = "";
if((cp > p->fullname && iskanjipos((cp - 1))) ||
(cp >= p->fullname && *cp != PD && *cp != ':'))
dl = "\\";
sprintf(buf, "%s%s", p->fullname, dl);
}
cp = buf + strlen(buf);
strcpy(cp, "*.*");
memset(&fb, 0, sizeof(fb));
fb.attrib = (gg.a_opt != 0) ? 0x3F : 0x30;
lfind = _findfirst(buf, &fb);
if (lfind == -1) {
continue;
} /* Changed Nide */
do {
if(!gg.a_opt && (fb.name[0] == '.' || fb.name[0] == '_'))
continue;
strcpy(cp, fb.name);
add_file_list(buf, false,
(fb.attrib & VOL_MASK) ? VOL_MASK :
gg.a_opt ? 0x37 : 0x30); /* Changed Nide */
} while(_findnext(lfind, &fb) == 0);
_findclose(lfind);
output_files();
free(p->fullname);
free(p);
}
}
bool process_options(int c)
{
switch (c){
case 'R':
gg.R_opt = true; /* list directory recursively */
gg.disp_dir = true;
gg.d_opt = 0;
break;
case 'a':
gg.a_opt = true;
break; /* list all files */
case 'd':
gg.d_opt = true; /* list directory itself */
gg.R_opt = 0;
gg.disp_dir = 0;
break;
case 'C':
gg.C_opt = true;
gg.x_opt = 0; /* multicolumn output */
break;
case 'x':
gg.x_opt = true;
gg.C_opt = 0; /* multicolumn across */
break;
case 'B': /* sort by file size */
gg.X_opt = true;
gg.t_opt = gg.S_opt = false;
break;
case 'l':
gg.l_opt = true;
break; /* long listing */
case 'r':
gg.r_opt = !gg.r_opt;
break; /* reverse sort */
case 't':
gg.t_opt = true;
gg.X_opt = gg.S_opt = false;
break; /* use timestamp to sort */
case 'F':
gg.F_opt = true;
break; /* list with / and * */
case 's': /* append file size in KB. */
gg.s_opt = true;
break; /* output block size */
case '1':
gg.C_opt = 0; /* no multicolumn */
gg.x_opt = 0;
break;
case 'U': /* no sort */
gg.S_opt = true;
gg.t_opt = gg.X_opt = false;
break;
case 'X': /* sort by extention */
gg.Sort_by_ext_opt = true;
break;
case 'c': /* Add Nide */
if(gg.c_opt > 0){
if(gg.c_opt < 3)
gg.c_opt++;
} else {
if(gg.c_opt-- > -3)
gg.c_opt--;
}
break;
default:
return false;
}
return true;
}
int ls_main(int argc, char **argv)
{
// extern int opterr;
// extern char **expand_wildcards();
// extern void discard_wildcard();
int c /* , i */ ; /* filenum is changed to be extern */
char *opt;
gConsoleInfo.lMode = CW_MODE_GET;
if (cwCallConsole(glpfnIO, "", (LPLONG)&gConsoleInfo) == TRUE) {
gg.screenwidth=min(max(8,gConsoleInfo.lColumns),gConsoleInfo.lBufMax);
}
conv_char_args(argv, '/', '\\');
gg.opterr = 0;
gg.c_opt = -1;
gg.C_opt = true;
*gg.current_directory = 0;
/*
* Process option string from LSOPTIONS and from the command line.
*/
if((opt = getenv("LSOPTIONS"))){
while(*opt){
process_options(*opt);
opt++;
}
}
while((c = getopt(argc, argv, "RadCxlrtBFs1UXc")) != EOF) {
if(process_options(c) != true) {
return ls_usage();
}
}
gg.c_opt = (gg.c_opt < -1 || gg.c_opt > 2);
gg.filenum = 0;
if(gg.optind == argc) {
add_file_list(".", true, gg.a_opt ? 0x37 : 0x30);
/* Changed Nide. In this case we must ignore volume label */
} else {
argv += gg.optind;
/* この後、オリジナルでは引数を後ろから処理してた。なぜだ? */
while((*argv)[0] != '\0'){
char *onearg; /* int len; */
onearg = *argv;
if(isalpha(*onearg) && onearg[1] == ':' && onearg[2] == '\0'){
gg.s_tmparg[0] = *onearg;
onearg = gg.s_tmparg;
}
add_file_list(onearg, true, !gg.a_opt ? 0x30 :
(*onearg && '.' == onearg[strlen(onearg)-1]) ?
0x37 : 0x3F);
/*
* Changed Nide (so that 'ls -a /volname' works).
* '.' is not SJIS 2nd byte.
*/
gg.filenum++;
argv++;
}
}
if(gg.filenum > 1) {
gg.disp_dir = true;
}
output_files();
output_dirs();
return 0; /* return from main() */
}
/*-----------*/
/* sort_main */
/*-----------*/
int rmstmp_exit(int code)
{
int i;
for(i = 0; i < 2; i++){
if(gg.sorttmpf[i].f != NULL){
fclose(gg.sorttmpf[i].f);
unlink(gg.sorttmpf[i].name);
}
}
return code;
}
void userintr(int dummy)
{
cwFputs("sort: User interrupt\n", (LPSTR)-1);
rmstmp_exit(1);
}
int sort_usage(void)
{
cwFputs("Usage: sort [-brnf] [-t c] [-o outfile]\n", (LPSTR)-1),
cwFputs("\t [+n1[.m1][brnf] [-n2[.m2][b]] ...] [files...]\n", (LPSTR)-1);
return 1;
}
void sort_nomem(void)
{
_putnomemmes(), rmstmp_exit(1);
}
void nodisk(void)
{
cwFputs("output error (maybe disk full) while outputting or "
"making temporal file\n", (LPSTR)-1), rmstmp_exit(1);
}
int addfieldparm(char *p)
{
char pm;
if('+' == (pm = *p++)){
if(NULL == (gg.sortparm = (parmstr *)(realloc((char *)gg.sortparm,
sizeof(parmstr) * (gg.parmcnt + 1))))){
sort_nomem();
}
memcpy((char *)&(gg.sortparm[gg.parmcnt]),
(char *)&(gg.sortparm[0]), sizeof(parmstr));
/* global optionのbeginf・c, endf・cは0 0 -1 0のはず */
if(!isdigit(*p)) return sort_usage();
gg.sortparm[gg.parmcnt].beginf = atoi(p);
/* should be a-to-uint? */
while(isdigit(*p)) p++;
if(*p == '.'){
p++; if(!isdigit(*p)) return sort_usage();
gg.sortparm[gg.parmcnt].beginc = atoi(p);
while(isdigit(*p)) p++;
} else gg.sortparm[gg.parmcnt].beginc = 0;
if(*p && gg.sortparm[gg.parmcnt].opt.usegopt){
memset((char *)&gg.sortparm[gg.parmcnt] . opt, 0,
sizeof(optstr));
}
for(; *p; p++){
switch(*p){
case 'b':
gg.sortparm[gg.parmcnt].opt.pblankign = 1; break;
case 'f':
gg.sortparm[gg.parmcnt].opt.foldcase = 1; break;
case 'n':
gg.sortparm[gg.parmcnt].opt.numsort = 1; break;
case 'r':
gg.sortparm[gg.parmcnt].opt.reverse = 1; break;
default:
return sort_usage();
}
}
} else {
gg.parmcnt--;
if(!isdigit(*p)) return sort_usage();
gg.sortparm[gg.parmcnt].endf = atoi(p);
while(isdigit(*p)) p++;
if(*p == '.'){
p++; if(!isdigit(*p)) return sort_usage();
gg.sortparm[gg.parmcnt].endc = atoi(p);
while(isdigit(*p)) p++;
} else gg.sortparm[gg.parmcnt].endc = 0;
if(*p && gg.sortparm[gg.parmcnt].opt.usegopt){
memset((char *)&gg.sortparm[gg.parmcnt].opt,0,
sizeof(optstr));
}
for(; *p; p++){
switch(*p){
case 'b':
gg.sortparm[gg.parmcnt].opt.mblankign = 1; break;
/* あとは+の時と一緒 */
case 'f':
gg.sortparm[gg.parmcnt].opt.foldcase = 1; break;
case 'n':
gg.sortparm[gg.parmcnt].opt.numsort = 1; break;
case 'r':
gg.sortparm[gg.parmcnt].opt.reverse = 1; break;
default:
return sort_usage();
}
}
}
gg.parmcnt++;
}
void makestmpbase(void)
/* メモリがなくなってから一時ファイルを作るのだから、そのための
領域をあらかじめ取っておく */
{
char *tmpdir, *p, yobi[5]/* "a:\\." */;
int i;
FILE *opntest;
if(NULL == (tmpdir = getenv("TMP")) &&
NULL == (tmpdir = getenv("TEMP"))){
tmpdir = ".";
} else
if(*tmpdir == '\\' && !tmpdir[1] ||
is_alpha(*tmpdir) && tmpdir[1] == ':' &&
(!tmpdir[2] || tmpdir[2] == '\\' && !tmpdir[3])){
/* "\\" "a:\\" "a:" の場合 */
strcpy(yobi, tmpdir);
strcat(tmpdir = yobi, ".");
} else {
for(p = tmpdir; *p; ){
if(*p == '\\' && !p[1]){
*p = '\0';
break;
}
if(iskanjipos(p)) p++;
p++;
}
}
p = malloc(strlen(tmpdir) + 5); /* "\\nul" */
if(p == NULL) sort_nomem();
strcpy(p, tmpdir), strcat(p, "\\nul"), opntest = fopen(p, "r");
if(opntest == NULL) tmpdir = "."; else fclose(opntest);
free(p);
for(i = 0; i < 2; i++){
gg.sorttmpf[i].dirlen = strlen(tmpdir);
gg.sorttmpf[i].name = malloc(gg.sorttmpf[i] . dirlen + 14);
/* 14 for "\\xxxxxxxx.xxx\0" */
if(NULL == gg.sorttmpf[i].name) sort_nomem();
strcpy(gg.sorttmpf[i].name, tmpdir);
gg.sorttmpf[i].f = NULL;
}
}
#include <signal.h>
int sort_main(int ac, char **av)
{
int nret = 0;
FILE *otf = NULL;
char *p;
char optend = 0; /* bool */
makestmpbase(); /* signal設定や全rmstmp_exitより前にやること */
signal(SIGINT, userintr);
if(NULL == (gg.sortparm=(parmstr *)malloc(sizeof(parmstr)))) sort_nomem();
memset(gg.sortparm, 0, sizeof(parmstr));
gg.sortparm->beginf = gg.sortparm->beginc = gg.sortparm->endc = 0;
gg.sortparm -> endf = (unsigned int)-1;
gg.sortparm->opt.usegopt = 1;
while(++av, --ac){
p = *av;
switch(*p){
case '+':
if (addfieldparm(p) != 0) {
nret = 1; goto EXIT;
}
if(ac == 1 || av[1][0] != '-' || !isdigit(av[1][1]))
break;
++av, --ac;
if (addfieldparm(*av) != 0) {
nret = 1; goto EXIT;
}
break;
case '-':
if(!p[1]){optend++; break;}
while(*++p){
switch(*p){
case 't':
if(!*++p){
if(av++, !--ac) {
nret = sort_usage(); goto EXIT;
}
p = *av;
if(!*p) {
nret = sort_usage(); goto EXIT;
}
}
gg.global_sep[0] = *p;
if(iskanji(*p))
gg.global_sep[1] = *++p;
else
gg.global_sep[1] = '\0';
if(p[1]) {
nret = sort_usage(); goto EXIT;
}
break;
case 'o':
if(!*++p){
if(av++, !--ac) {
nret = sort_usage(); goto EXIT;
}
p = *av;
}
gg.otfnm = p;
p = "?";
break;
case 'f':
gg.sortparm->opt.donormcmp =
gg.sortparm->opt.foldcase = 1; break;
case 'n':
gg.sortparm->opt.donormcmp =
gg.sortparm->opt.numsort = 1; break;
case 'b':
gg.sortparm->opt.donormcmp =
gg.sortparm->opt.pblankign =
gg.sortparm->opt.mblankign = 1; break;
case 'r':
gg.sortparm->opt.reverse = 1; break;
default:
nret = sort_usage(); goto EXIT;
}
}
break;
default:
optend++; break;
}
if(optend) break;
}
if(gg.parmcnt > 1) gg.sortparm->opt.donormcmp = 1;
/* field optionが1つでもあれば後で行全体の通常比較
(その場合global optionを適用しての行全体の比較はしない)
field optionなくても-bや-nの場合は行全体の通常比較がいる
-rだけの場合などは改めて行全体の通常比較をする必要なし */
if(NULL == (gg.lines = (char **)malloc(
(gg.linealloc = L_1ST) * sizeof(char *)))) sort_nomem();
if(!ac){
readfile(NULL);
} else for(; ac; ac--, av++){
if(**av == '-' && !av[0][1]){
readfile(NULL);
} else {
readfile(*av);
}
}
do_sort();
if(NULL != gg.otfnm){
name_unixnize(gg.otfnm);
if(NULL == (otf = fopen(gg.otfnm, "w"))){
cwFputs(gg.otfnm, (LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
rmstmp_exit(1);
}
} else {
otf = NULL;
}
join_output(otf, gg.sorttmpf[!gg.tmpfsw] . f);
EXIT:
if (otf != NULL) fclose(otf);
if (gg.lines != NULL) free(gg.lines);
gg.lines = NULL;
rmstmp_exit(0);
return 0;
}
void readfile(char *fnm)
{
int len;
FILE *inf;
char linbuf[LINMAX];
if(fnm == NULL){
inf = NULL, fnm = "(stdin)";
} else {
name_unixnize(fnm);
if(NULL == (inf = fopen(fnm, "r"))){
cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
}
}
while(((inf == NULL) ? cwFgets(linbuf, LINMAX, NULL) :
fgets(linbuf, LINMAX, inf)) != NULL){
if(!*linbuf){ /* nothing */
;
} else if(linbuf[(len = strlen(linbuf)) - 1] != '\n'){
cwFputs(fnm, (LPSTR)-1);
if(len == LINMAX - 1){
cwFputs(": line too long\n", (LPSTR)-1);
rmstmp_exit(1);
} else {
cwFputs(": missing line-feed character "
"added at the end of file\n", (LPSTR)-1);
}
} else {
linbuf[len - 1] = '\0';
}
linereg(linbuf);
}
if(inf != NULL) fclose(inf);
}
/* 1行の内容を保存。将来的にはフィールドの位置情報もあわせて保存 */
void linereg(char *s)
{
char **tmplines;
if(gg.linecnt >= gg.linealloc){
gg.linealloc += L_INC;
if(gg.linealloc * sizeof(char *) / sizeof(char *) != gg.linealloc ||
/* reallocだと失敗時に元の内容が保証されない */
NULL == (tmplines = (char **)malloc(
gg.linealloc * sizeof(char *)))){
midproc();
} else {
memcpy((char *)tmplines, (char *)gg.lines,
gg.linecnt * sizeof(char *));
free((char *)gg.lines);
gg.lines = tmplines;
}
}
if(NULL == (gg.lines[gg.linecnt] = strsave(s))){
midproc(); /* linecntは0になる */
if(NULL == (gg.lines[0] = strsave(s))) sort_nomem();
}
gg.linecnt++;
}
/* macros to move pointer */
void fieldcharpass(char **pp)
{
char *p;
p = *pp;
if(*gg.global_sep){
for(;; iskanjipos(p) ? (p += 2) : p++){
if(!*p){
*pp = p; return;
}
if(*p != *gg.global_sep) continue;
if(!gg.global_sep[1]){
*pp = ++p; return;
} else {
if(p[1] != gg.global_sep[1]) continue;
*pp = p + 2; return;
}
}
} else {
spcpass(p); nonspcpass(p);
}
*pp = p;
}
int compare(const char **pp, const char **qp)
{
char *p, *pe, *q, *qe;
int i;
unsigned int minf, u;
int rsl = 0;
int strnicmp(), strncmp(), stricmp(), strcmp();
/* parmcntが1なら0だけ、1より大なら1~parmcnt-1を見る */
for(i = (gg.parmcnt > 1); i < gg.parmcnt; i++){
p = *pp, q = *qp;
minf = umin(gg.sortparm[i].beginf, gg.sortparm[i].endf);
for(u = minf; u; u--){
fieldpass(p); fieldpass(q);
}
pe = p, qe = q;
/* if endf is -1, pe and qe are not used */
for(u = gg.sortparm[i].beginf-minf; u; u--){
fieldpass(p); fieldpass(q);
}
if(gg.sortparm[i].opt.pblankign){
spcpass(p); spcpass(q);
}
ncharpass(p, gg.sortparm[i].beginc);
ncharpass(q, gg.sortparm[i].beginc);
if(gg.sortparm[i].opt.numsort){ /* endf, endc are not used */
gg.s_a = atof(p); gg.s_b = atof(q);
/* atofは常に空白を飛ばす */
rsl = (gg.s_a < gg.s_b ? -1 : gg.s_a > gg.s_b ? 1 : 0);
} else if((unsigned int)-1 != (u = gg.sortparm[i].endf)){
unsigned int plen, qlen;
for(u -= minf; u; u--){
fieldpass(pe); fieldpass(qe);
}
if(gg.sortparm[i].opt.mblankign){
spcpass(pe); spcpass(qe);
}
ncharpass(pe, gg.sortparm[i].endc);
ncharpass(qe, gg.sortparm[i].endc);
plen = pe - p; if(plen < 0) plen = 0;
qlen = qe - q; if(qlen < 0) qlen = 0;
rsl = (gg.sortparm[i].opt.foldcase ?
strnicmp : strncmp)(p, q, umin(plen, qlen));
if(rsl == 0) rsl = plen - qlen;
} else {
rsl = (gg.sortparm[i].opt.foldcase ? stricmp : strcmp)
(p, q);
}
if(rsl){
return gg.sortparm[i].opt.reverse ? -rsl : rsl;
}
}
/* 勝負が付かなければ行全体を普通に比較 */
if(gg.sortparm->opt.donormcmp){
rsl = strcmp(*pp, *qp);
return gg.sortparm->opt.reverse ? -rsl : rsl;
}
return 0;
}
void do_sort(void)
{
qsort((char *)gg.lines, gg.linecnt, sizeof(char *), compare);
}
FILE *dtmpfile(char *dir) /* dirも書き換わる */
{
char *s;
s = _mktemp(dir);
return (s == NULL) ? NULL : fopen(dir, "w+b");
}
void midproc(void) /* メモリが足りなくなったので中間処理 */
{
unsigned int i;
int (*thndl)(int);
do_sort();
thndl = (int (*)(int))signal(SIGINT, SIG_IGN);
if(NULL ==
(gg.sorttmpf[gg.tmpfsw].f = dtmpfile(gg.sorttmpf[gg.tmpfsw].name))){
cwFputs("Can't open tmpfile\n", (LPSTR)-1), rmstmp_exit(1);
}
signal(SIGINT, (void (*)(int))thndl);
join_output(gg.sorttmpf[gg.tmpfsw].f, gg.sorttmpf[!gg.tmpfsw].f);
thndl = (int (*)(int))signal(SIGINT, SIG_IGN);
rewind(gg.sorttmpf[gg.tmpfsw].f);
gg.tmpfsw ^= 1;
if(gg.sorttmpf[gg.tmpfsw].f != NULL){
fclose(gg.sorttmpf[gg.tmpfsw].f);
gg.sorttmpf[gg.tmpfsw].f = NULL;
unlink(gg.sorttmpf[gg.tmpfsw].name);
gg.sorttmpf[gg.tmpfsw].name[gg.sorttmpf[gg.tmpfsw].dirlen] = '\0';
}
signal(SIGINT, (void (*)(int))thndl);
for(i = 0; i < gg.linecnt; i++) free(gg.lines[i]);
free(gg.lines);
if(NULL == (gg.lines = (char **)malloc(
(gg.linealloc = L_1ST) * sizeof(char *)))) sort_nomem();
gg.linecnt = 0;
}
void join_output(FILE *f, FILE *midf)
{
unsigned int i = 0;
char lbuf[LINMAX], *linbuf;
linbuf = lbuf;
if (midf != NULL) {
while(fgets(linbuf, LINMAX, midf) != NULL) {
linbuf[strlen(linbuf) - 1] = '\0';
for(; i < gg.linecnt && compare(&gg.lines[i], &linbuf) < 0; i++){
(f == NULL) ? cwFputs(gg.lines[i], NULL) : fputs(gg.lines[i], f);
if (((f == NULL) ? cwFputs("\n",NULL):fputs("\n",f)) < 0) {
nodisk();
}
}
(f == NULL) ? cwFputs(gg.lines[i], NULL) : fputs(gg.lines[i], f);
if (((f == NULL) ? cwFputs("\n",NULL):fputs("\n",f)) < 0) {
nodisk();
}
}
}
for(; i < gg.linecnt; i++){
(f == NULL) ? cwFputs(gg.lines[i], NULL) : fputs(gg.lines[i], f);
if (((f == NULL) ? cwFputs("\n",NULL):fputs("\n",f)) < 0) {
nodisk();
}
}
if (f != NULL) {
if(fflush(f) == EOF || ferror(f)) nodisk();
}
}
/* future plan:
フィールドをいちいち探さぬよう比較まわりを作り替え
tmpfile()関係を後で作り替える(その場合intrまわりの世話も)
文字列save関係も作り替えるか
*/
/*---------*/
/* od_main */
/*---------*/
int od_usage(void)
{
cwFputs("Usage: od [-bcdosxvCSmrnXp] [-wn] [-Wn] [-tn[CS]] [file] ",
(LPSTR)-1);
cwFputs("[[+][0x]offset[.][b]]\n", (LPSTR)-1);
return 1;
}
void equivocal(char *s)
{
cwFputs("Equivocal operand: ", (LPSTR)-1);
cwFputs(s, (LPSTR)-1);
}
void nobuf(void)
{
cwFputs("Can't set I/O buffer\n", (LPSTR)-1);
MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
exit(2);
}
FILE *fopen_chk(char *n, char *m)
/* nが"-"ならmを見ずにstdinを返す。fcloseの扱いなどに注意のこと */
{
FILE *f;
if(*n == '-' && !n[1]) return NULL;
if(NULL == (f = fopen(n, m))){
cwFputs(s_conv_to_unix_format(n), (LPSTR)-1);
cwFputs(": Can't open\n", (LPSTR)-1);
return NULL;
}
return f;
}
//#define LBUFSIZ 1024
long setoffset(FILE *f, char *offset)
/* offset指定の文字列を読んで、fの内容を指定された分だけ読み捨て、
大域変数addrmodeを設定してから戻る */
{
us_int offsetmode = OCTADDR;
int in_blks_shft = 0;
us_long pass = 0, passrest;
us_int rsize;
char *strpbrk(), *p;
if(gg.s_passbuf == NULL && NULL == (gg.s_passbuf = malloc(LBUFSIZ))) {
_putnomemmes();
MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
exit(2);
}
offset++; /* when called, *offset is always '+' */
if(!strncmp(offset, "0x", 2) || *offset == 'x'){
offsetmode = HEXADDR;
*offset++ == '0' && offset++;
}
if(NULL != strchr(offset, '.')){ /* 10進指定の方が優先 */
offsetmode = DECADDR;
}
/* ここまででoffsetmodeの設定は終わり。
グローバル変数addrmodeを変更しておく */
if(gg.addrmode != NOADDR) gg.addrmode = offsetmode;
if(offsetmode != HEXADDR && NULL != (p = strpbrk(offset, "bB"))){
in_blks_shft = (*p == 'b' ? 9 : 10);
}
sscanf(offset,
offsetmode == DECADDR ? "%lu" :
offsetmode == HEXADDR ? "%lx" : "%lo", &pass);
pass <<= in_blks_shft;
if(gg.undump){
if(pass){
cwFputs("Warning: non-0 offset with -u option\n", (LPSTR)-1);
}
return 0L;
}
passrest = pass;
if (f != NULL) {
while(passrest > 0){
rsize = (passrest > (us_long)LBUFSIZ) ?
LBUFSIZ : (us_int)passrest;
if(rsize > fread(gg.s_passbuf, 1, rsize, f)){
cwFputs("EOF\n", (LPSTR)-1);
}
passrest -= (us_long)rsize;
}
} else {
while (passrest > 0) {
char *p;
p = cwFgets(gg.s_passbuf, LBUFSIZ, NULL);
rsize = (p != NULL) ? lstrlen(p) : 0;
passrest -= rsize;
}
}
return pass;
}
char *malloc_chk_z(us_int i)
{
char *s;
if(NULL == (s = malloc(i))){
_putnomemmes();
MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
exit(2);
/* od exits with code 2 when error... */
}
memset(s, 0, i);
return s;
}
void addpos(us_long *l, us_int d)
{
*l += d;
switch(gg.addrmode){
case HEXADDR:
*l &= 0xfffffffL; break;
case DECADDR:
*l %= 10000000L; break;
case OCTADDR:
*l &= 07777777L; break;
}
}
void putspcs(int i)
{
char *buf;
buf = malloc(i + 1); if (buf == NULL) return;
memset(buf, ' ', i);
buf[i] = '\0';
cwFputs(buf, NULL);
free(buf);
}
us_char special_char_disp(us_char c)
{ /* ctrl chrのみ。SJISの2バイト目と重複したりはしない */
switch(c){
case '\n':
return 'n';
case '\t':
return 't';
case '\b':
return 'b';
case '\r':
return 'r';
case '\f':
return 'f';
case 0xb:
return 'v';
case 0x7:
return 'a';
case '\033':
return 'e';
}
return 0;
}
#define is_print(c) (isascii(c) && isprint(c))
void byteout(us_char c) /* uses fieldb */
{
char buf[0x100];
if(is_print(c)){
_snprintf(buf, sizeof(buf), "%*s%c", gg.fieldb-1, STRNULL, c);
cwFputs(buf, NULL);
} else {
us_char d;
d = (c ? special_char_disp(c) : '0');
if(d){
_snprintf(buf, sizeof(buf), "%*s\\%c", gg.fieldb-2, STRNULL, d);
cwFputs(buf, NULL);
} else {
if (gg.hexcode) {
_snprintf(buf,sizeof(buf), "%*s%02x", gg.fieldb-2, STRNULL, c);
cwFputs(buf, NULL);
} else {
_snprintf(buf,sizeof(buf), "%*s%03o", gg.fieldb-3, STRNULL, c);
cwFputs(buf, NULL);
}
}
}
}
#define ADDRNGOT 0
#define ADDRGOT 1
#define ADDRSTAR 2
#define ADDREOF 3
void odaddr(us_long curpos, int *flgp, int crmode)
{
char buf[0x100];
if(gg.addrmode == NOADDR) return;
/* NOADDRの時は何も出力しない */
if(*flgp){
cwFputs("\t", NULL); putspcs(gg.hsepwidth - 1);
} else {
char *p;
(*flgp)++;
switch(gg.addrmode){
case OCTADDR:
p = "%07lo"; break;
case HEXADDR:
p = "%07lx"; break;
default: /* case DECADDR: */
p = "%07lu"; break;
}
_snprintf(buf, sizeof(buf), p, curpos);
cwFputs(buf, NULL);
if(crmode) {
cwFputs("\n", NULL);
} else {
putspcs(gg.hsepwidth);
}
}
}
void putnl(void);
void od_oct(struct infile *inf, int *addrout,
us_char *begin, us_char *end)
{
us_char *ptr;
us_short outs;
char buf[0x100];
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
outs = *(us_short *)ptr;
if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
_snprintf(buf, sizeof(buf), "%*s%06o", gg.fieldw - 6, STRNULL, outs);
cwFputs(buf, NULL);
if((ptr += sizeof(short)) < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
}
void od_dec(struct infile *inf, int *addrout,
us_char *begin, us_char *end)
{
us_char *ptr;
us_short outs;
char buf[0x100];
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
outs = *(us_short *)ptr;
if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
_snprintf(buf, sizeof(buf), "%*s%05u", gg.fieldw - 5, STRNULL, outs);
cwFputs(buf, NULL);
if((ptr += sizeof(short)) < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
}
void od_sgndec(struct infile *inf, int *addrout,
us_char *begin, us_char *end)
{
us_char *ptr;
us_short outs;
char buf[0x100];
/* -32768とかに対処するのが面倒なので完全にはSysV odをまねない */
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
outs = *(us_short *)ptr;
if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
_snprintf(buf,sizeof(buf),"%*s%6d", gg.fieldw-6, STRNULL, (short)outs);
cwFputs(buf, NULL);
if((ptr += sizeof(short)) < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
}
void od_hex(struct infile *inf, int *addrout,
us_char *begin, us_char *end)
{
us_char *ptr;
us_short outs;
char buf[0x100];
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
outs = *(us_short *)ptr;
if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
_snprintf(buf, sizeof(buf), "%*s%04x", gg.fieldw-4, STRNULL, outs);
cwFputs(buf, NULL);
if((ptr += sizeof(short)) < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
}
void od_char(struct infile *inf, int *addrout,
us_char *begin, us_char *end)
{
us_char *ptr;
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
byteout(*ptr);
if(++ptr < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
}
void od_euc(struct infile *inf, int *addrout,
us_char *begin, us_char *end, int sw)
{
us_char *ptr;
int cont = gg.usebuf[sw].contmode & EUCCONT;
char buf[0x100];
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
if(cont){
_snprintf(buf, sizeof(buf), "%*s", gg.fieldb, "**");
cwFputs(buf, NULL);
cont = 0;
} else if(!iseuc(*ptr) && !isSS2(*ptr)){
byteout(*ptr);
} else {
int next;
if(ptr + 1 < end){
next = ptr[1]; /* ptr: us_char* */
} else {
next = getc(inf -> f);
if(next != EOF) ungetc(next, inf -> f);
/* EOFならungetcはしない。システムに
よっては入力ファイルが端末の場合、
EOFの後さらに読もうとすると次の
入力待ちで止まってしまうものも… */
}
if(!iseuc(next)){
byteout(*ptr);
} else {
_snprintf(buf, sizeof(buf), "%*s%c%c",
gg.fieldb - (isSS2(*ptr) ? 1 : 2),
STRNULL, *ptr, next);
cwFputs(buf, NULL);
cont = EUCCONT;
}
}
if(++ptr < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
sw ^= 1;
gg.usebuf[sw].contmode &= ~EUCCONT, gg.usebuf[sw].contmode |= cont;
}
void od_sjis(struct infile *inf, int *addrout,
us_char *begin, us_char *end, int sw)
{
us_char *ptr;
int cont = gg.usebuf[sw].contmode & SJISCONT;
char buf[0x100];
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
if(cont){
_snprintf(buf, sizeof(buf), "%*s", gg.fieldb, "**");
cwFputs(buf, NULL);
cont = 0;
} else
if(!issjis1(*ptr)){
if(issjiskana(*ptr)){
_snprintf(buf,sizeof(buf),"%*s%c", gg.fieldb-1, STRNULL, *ptr);
cwFputs(buf, NULL);
} else {
byteout(*ptr);
}
} else {
int next;
us_short dmy;
if(ptr + 1 < end){
next = ptr[1]; /* ptr: us_char* */
} else {
next = getc(inf -> f);
if(next != EOF) ungetc(next, inf -> f);
/* od_eucの場合と同様の事項に注意 */
}
if(!issjis2(next) ||
(dmy = next | (*ptr << 8),
0x8540 <= dmy && dmy <= 0x869e)){
/* NECの2バイト半角文字は排除 */
byteout(*ptr);
} else {
_snprintf(buf, sizeof(buf), "%*s%c%c", gg.fieldb-2, STRNULL,
*ptr, next);
cwFputs(buf, NULL);
cont = SJISCONT;
}
}
if(++ptr < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
sw ^= 1;
gg.usebuf[sw].contmode &= ~SJISCONT, gg.usebuf[sw].contmode |= cont;
}
void od_byte(struct infile *inf, int *addrout,
us_char *begin, us_char *end)
{
us_char *ptr;
char buf[0x100];
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
if (gg.hexcode) {
_snprintf(buf, sizeof(buf), "%*s%02x", gg.fieldb-2, STRNULL, *ptr);
cwFputs(buf, NULL);
} else {
_snprintf(buf, sizeof(buf), "%*s%03o", gg.fieldb-3, STRNULL, *ptr);
cwFputs(buf, NULL);
}
if(++ptr < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
}
void od_bm(struct infile *inf, int *addrout,
us_char *begin, us_char *end)
{
us_char *ptr;
odaddr(inf -> curpos, addrout, 0);
for(ptr = begin; ;){
int i;
char b = *ptr;
putspcs(gg.fieldb - 8);
for(i = 0; i < 8; i++, b <<= 1){
putchar(b & 0x80 ? '#' : '-');
}
if(++ptr < end){
putspcs(gg.sepwidth);
} else {
putnl(); break;
}
}
}
void od_str(struct infile *inf, us_char *begin, us_char *end)
{
us_char *ptr, c;
us_int txtlen;
void odstrout();
int txtchrwidth, next;
txtlen = gg.txtbuf.pos;
ptr = begin;
if(gg.txtbuf.tcontmode) (ptr++, gg.txtbuf.tcontmode = 0);
for(;;){
c = *ptr;
if(is_print(c) || special_char_disp(c) ||
gg.stringskind == SJISSTR && issjiskana(c)){
txtchrwidth = 1;
} else
if(gg.stringskind == EUCSTR && (iseuc(c) || isSS2(c)) ||
gg.stringskind == SJISSTR && issjis1(c)){
int tcont; /* boolean */
tcont = (ptr + 1 >= end);
if(!tcont){
next = ptr[1]; /* ptr: us_char* */
} else {
next = getc(inf -> f);
if(next != EOF) ungetc(next, inf -> f);
/* od_eucの場合と同様の事項に注意 */
}
if(gg.stringskind == EUCSTR ? iseuc(next) : issjis2(next)){
txtchrwidth = 2;
gg.txtbuf.tcontmode = tcont;
} else {
txtchrwidth = 0;
}
} else {
txtchrwidth = 0;
}
if(txtchrwidth){
if(!txtlen){
gg.txtbuf.filepos = inf -> curpos;
addpos(&gg.txtbuf.filepos, ptr - begin);
}
if(txtlen + txtchrwidth > gg.txtbuf.buflen){
gg.txtbuf.buf = (us_char *)realloc(
(void *)gg.txtbuf.buf,
gg.txtbuf.buflen = txtlen + 100);
if(gg.txtbuf.buf == NULL){
_putnomemmes();
MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
exit(2);
/* exit code 2 when error */
}
}
gg.txtbuf.buf[txtlen++] = c;
if(txtchrwidth > 1){
gg.txtbuf.buf[txtlen++] = next;
ptr++;
}
} else {
if(txtlen >= gg.stringslen){
odstrout(gg.txtbuf.filepos,
gg.txtbuf.buf, txtlen);
}
txtlen = 0;
}
if(++ptr >= end) break;
}
gg.txtbuf.pos = txtlen;
}
void odstrout(us_long filepos, us_char *buf, us_int n)
{ /* 今のところ漢字について考慮の必要はなし */
us_char c, d;
us_int dummy = 0;
char *bufo;
char *po;
odaddr(filepos, &dummy, 0);
bufo = malloc(2 * n + 1); if (bufo == NULL) return;
po = bufo;
for(; n; n--, buf++){
d = special_char_disp(c = *buf);
if (d) {
*po++ = '\\'; *po++ = d;
} else {
*po++ = c;
}
}
*po++ = '\n'; *po = '\0';
cwFputs(bufo, NULL);
free(bufo);
}
void odsub(struct infile *inf, int sw, us_int len)
{
us_char *begin, *end;
int addrout = 0;
if(!len){
if(gg.outmode & ~STRINGOUT)
odaddr(inf -> curpos, &addrout, 1);
return;
}
end = (begin = gg.usebuf[sw].buf) + len;
/* lenは少なくとも1 */ /* バイト順序はシステム依存 */
if(gg.outmode & OCTDUMP){
od_oct(inf, &addrout, begin, end);
}
if(gg.outmode & DECDUMP){
od_dec(inf, &addrout, begin, end);
}
if(gg.outmode & SGNDECDUMP){
od_sgndec(inf, &addrout, begin, end);
}
if(gg.outmode & HEXDUMP){
od_hex(inf, &addrout, begin, end);
}
if(gg.outmode & CHARDUMP){
od_char(inf, &addrout, begin, end);
}
if(gg.outmode & EUCDUMP){
od_euc(inf, &addrout, begin, end, sw);
}
if(gg.outmode & SJISDUMP){
od_sjis(inf, &addrout, begin, end, sw);
}
if(gg.outmode & BYTEDUMP){
od_byte(inf, &addrout, begin, end);
}
if(gg.outmode & BITMAPOUT){
od_bm(inf, &addrout, begin, end);
}
if(gg.outmode & STRINGOUT){
od_str(inf, begin, end); /* &addroutは不要 */
}
}
void write_err(void);
void putnl(void)
{
cwFputs("\n", NULL);
}
void write_err(void)
{
cwFputs("Write error\n", (LPSTR)-1), exit(2);
}
us_int fread_pad(char *p, us_int len, FILE *f)
/* 最大lenバイト読み、残りを0で埋める */
{
us_int r;
if(feof(f)) return 0;
if(len > (r = fread(p, 1, len, f))) memset(p + r, 0, len - r);
return r;
}
int chksame(FILE *f, struct bufstr *ubuf0, struct bufstr *ubuf1, us_int n)
{
int c;
if(!n || memcmp(ubuf0 -> buf, ubuf1 -> buf, n) ||
ubuf0 -> contmode != ubuf1 -> contmode) return 0;
if(ubuf0 -> contmode){
if(EOF != (c = getc(f))) ungetc(c, f);
return ubuf0 -> buf[0] == c;
} else return 1;
}
void od(struct infile *inf)
{
us_char *p;
us_int n, bufsw;
if (inf->f == NULL) {
cwFputs("now can't support stdin\n", (LPSTR)-1);
return;
}
if(gg.bytelen != gg.bytelen1){
n = fread_pad(p = gg.usebuf[0].buf, gg.bytelen1, inf->f);
odsub(inf, 0, n);
if(!n) return;
addpos(&inf -> curpos, n);
memset(p, 0, /* これはbytelen1 > bytelenの場合のみ意味あり */
(gg.bytelen1 + MAXDISPUNIT - 1) & ~(MAXDISPUNIT - 1));
}
n = fread_pad(p = gg.usebuf[1].buf, gg.bytelen, inf->f);
odsub(inf, 1, n);
if(!n) return;
addpos(&inf -> curpos, n);
for(bufsw = 1;;){
n = fread_pad(p = gg.usebuf[bufsw ^= 1].buf, gg.bytelen, inf -> f);
if(!gg.alldata && chksame(inf->f, &gg.usebuf[0], &gg.usebuf[1], n)){
if(gg.outmode & ~STRINGOUT) (putchar('*'), putchar('\n'));
do {
addpos(&inf -> curpos, n);
n = fread_pad(p, gg.bytelen, inf -> f);
} while(chksame(inf -> f, &gg.usebuf[0], &gg.usebuf[1], n));
}
odsub(inf, bufsw, n);
if(!n) return;
addpos(&inf -> curpos, n);
}
}
void fbufset(FILE *f)
{
if (f == NULL) {
return;
}
/* bigbufは大きさBIGBUFSIZのバッファかあるいはNULL */
if(gg.bigbuf != NULL && 0 != setvbuf(f, gg.bigbuf, _IOFBF, BIGBUFSIZ)){
nobuf();
} /* fbufset()は一度しか呼ばれないので他のファイルとバッファを
取り合ったりすることはない */
}
int od_main(int ac, char **av)
{
int nret = 0;
int i, c;
// extern int optind, opterr;
// extern char *optarg;
struct infile inf;
inf.f = NULL;
gg.opterr = 0;
#define asrtmax(v, n) (((int)(v) < (int)(n)) && ((int)(v) = (int)(n)))
while(EOF != (c = getopt(ac, av, "bcdosxw:vW:CSmt:rnXpu"))){
switch(c){
case 'b': gg.outmode |= BYTEDUMP; /* 後でfieldb調節 */ break;
case 'c': gg.outmode |= CHARDUMP; /* 後でfieldb調節 */ break;
case 'd': gg.outmode |= DECDUMP; asrtmax(gg.fieldw, 5); break;
case 'o': gg.outmode |= OCTDUMP; asrtmax(gg.fieldw, 6); break;
case 's': gg.outmode |= SGNDECDUMP; asrtmax(gg.fieldw, 6); break;
case 'x': gg.outmode |= HEXDUMP; asrtmax(gg.fieldw, 4); break;
case 'w': gg.bytelen = atoi(gg.optarg); break;
case 'v': gg.alldata = 1; break;
/* 以下は拡張 */
case 'W': gg.bytelen1 = atoi(gg.optarg); break;
case 'C': gg.outmode |= EUCDUMP; /* 後でfieldb調節 */ break;
case 'S': gg.outmode |= SJISDUMP; /* 後でfieldb調節 */ break;
case 'm': gg.outmode |= BITMAPOUT; asrtmax(gg.fieldb, 8); break;
case 't': gg.outmode |= STRINGOUT; gg.stringslen = atoi(gg.optarg);
{char *p; for(p = gg.optarg; isdigit(*p); p++);
gg.stringskind = *p == 'S' ? SJISSTR :
*p == 'C' ? EUCSTR : ASCIISTR;}
case 'r': gg.endianrev = 1; break;
case 'n': gg.addrmode = NOADDR; break;
case 'X': gg.hexcode = 1; break;
case 'p': gg.sepwidth = 0; break;
/* \ntbrfave also treated as text */
default: nret = od_usage(); goto EXIT;
}
}
/* オプションの調整 */
if(gg.stringslen && gg.undump){
equivocal("-u and -t\n");
nret = 1; goto EXIT;
}
if(!gg.outmode) (gg.outmode = OCTDUMP, gg.fieldw = 6);
if(gg.outmode & (BYTEDUMP | CHARDUMP | SJISDUMP | EUCDUMP))
asrtmax(gg.fieldb, gg.hexcode ? 2 : 3);
if(gg.addrmode == NOADDR){ /* -nを指定したら-vも連動 */
gg.alldata = 1;
}
if(!gg.bytelen) gg.bytelen = 16;
if(!gg.bytelen1) gg.bytelen1 = gg.bytelen;
/* bytelen1が未設定(0)のままならbytelenと同じにする */
/* 幅の調整 */
if(!gg.sepwidth) gg.sepwidth = 1;
/* この後gg.sepwidthは変わりうるのでそれまでに */
if(gg.fieldw && gg.fieldb){
if(gg.fieldw & 1){
if(gg.fieldb * 2 < gg.fieldw){
gg.sepwidth = 1;
gg.fieldb = gg.fieldw >> 1;
} else gg.fieldw = gg.fieldb * 2 + gg.sepwidth;;
} else {
if(!gg.sepwidth){
if(gg.fieldb * 2 < gg.fieldw) gg.fieldb = gg.fieldw >> 1;
else gg.fieldw = gg.fieldb * 2;
} else {
if(gg.fieldb * 2 < gg.fieldw){
gg.fieldb = gg.fieldw / 2 - 1;
gg.sepwidth = 2;
} else gg.fieldw = gg.fieldb * 2 + 1;
}
}
}
/* バッファの用意 */
gg.usebuf[0].buflen =
((gg.bytelen>gg.bytelen1?gg.bytelen:gg.bytelen1)+MAXDISPUNIT - 1) &
~(MAXDISPUNIT - 1);
gg.usebuf[1].buflen = (gg.bytelen + MAXDISPUNIT - 1) & ~(MAXDISPUNIT - 1);
for(i = 0; i < 2; i++){
gg.usebuf[i].buf = (us_char *)malloc_chk_z(gg.usebuf[i].buflen);
gg.usebuf[i].pos = gg.usebuf[i].contmode = 0;
}
gg.bigbuf = malloc(BIGBUFSIZ); /* NULLならsetvbufしない */
setstdoutbuf();
gg.txtbuf.buf = (us_char *)malloc_chk_z(gg.txtbuf.buflen = 100);
gg.txtbuf.tcontmode = gg.txtbuf.pos = 0;
ac -= gg.optind, av += gg.optind;
inf.curline = 0L;
switch(ac){
case 0:
fbufset(inf.f = NULL);
inf . curpos = 0L;
od(&inf); break;
case 1:
if(**av == '+'){
fbufset(inf.f = NULL);
inf.curpos = setoffset(NULL, *av);
addpos(&inf.curpos, 0);
od(&inf);
} else {
fbufset(inf.f = fopen_chk(*av, "r"));
inf.curpos = 0L;
od(&inf);
}
break;
case 2:
if(av[1][0] != '+') {
nret = od_usage(); goto EXIT;
}
fbufset(inf.f = fopen_chk(*av, "r"));
inf.curpos = setoffset(inf.f, av[1]);
addpos(&inf.curpos, 0);
od(&inf);
break;
default:
nret = od_usage(); goto EXIT;
}
if((gg.outmode & STRINGOUT) && gg.txtbuf.pos >= gg.stringslen){
/* strings未出力分掃き出し */
odstrout(gg.txtbuf.filepos, gg.txtbuf.buf, gg.txtbuf.pos);
}
EXIT:
if (inf.f != NULL) fclose(inf.f);
return 0;
}
void setstdoutbuf(void)
{
int i;
i = (isatty(1) ? OBUFSIZ : BIGBUFSIZ);
if(NULL != (gg.obigbuf = malloc(i))){
if(0 != setvbuf(stdout, gg.obigbuf, _IOFBF, i)) nobuf();
}
}