home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1996 February / VPR9602A.ISO / fwindows / archive / tmedt090.lzh / TOOLD101.LZH / CWTOOLS.C < prev    next >
C/C++ Source or Header  |  1995-11-20  |  278KB  |  10,107 lines

  1. #include <windows.h>
  2. #include "comwin.h"
  3.  
  4. /*-----------*/
  5. /* xargs API */
  6. /*-----------*/
  7. char ** FAR PASCAL CreateArgs(char *);
  8. BOOL    FAR PASCAL DeleteArgs(char **);
  9.  
  10. LONG FAR PASCAL cwFprintf(LPSTR, LPSTR, ...);
  11.  
  12. /*--------------*/
  13. /* 外部変数関係 */
  14. /*--------------*/
  15. BOOL CreateGlobal(void);
  16. BOOL DeleteGlobal(void);
  17.  
  18. /*----------------*/
  19. /* 内部コマンド群 */
  20. /*----------------*/
  21. int cal_main(int argc, char **argv);
  22. int cat_main(int argc, char **argv);
  23. int chdir_main(int argc, char **argv);
  24. int chmod_main(int argc, char **argv);
  25. int cmp_main(int argc, char **argv);
  26. int cp_main(int argc, char **argv);
  27. int date_main(int argc, char **argv);
  28. int df_main(int argc, char **argv);
  29. int diff_main(int argc, char **argv);
  30. int echo_main(int argc, char **argv);
  31. int expand_main(int argc, char **argv);
  32. int fold_main(int argc, char **argv);
  33. int grep_main(int argc, char **argv);
  34. int head_main(int argc, char **argv);
  35. int join_main(int argc, char **argv);
  36. int ls_main(int argc, char **argv);
  37. int man_main(int argc, char **argv);
  38. int mkdir_main(int argc, char **argv);
  39. int mv_main(int argc, char **argv);
  40. int od_main(int argc, char **argv);
  41. int pwd_main(int argc, char **argv);
  42. int rm_main(int argc, char **argv);
  43. int rmdir_main(int argc, char **argv);
  44. int sort_main(int argc, char **argv);
  45. int split_main(int argc, char **argv);
  46. int tail_main(int argc, char **argv);
  47. int tee_main(int argc, char **argv);
  48. int touch_main(int argc, char **argv);
  49. int tr_main(int argc, char **argv);
  50. int unexpand_main(int argc, char **argv);
  51. int uniq_main(int argc, char **argv);
  52. int wc_main(int argc, char **argv);
  53. int which_main(int argc, char **argv);
  54.  
  55. /*------------------------------------------*/
  56. /* CallCommand関数 (ワイルドカード展開あり) */
  57. /*------------------------------------------*/
  58.  
  59. typedef struct CMDTABLE CMDTABLE;
  60. struct CMDTABLE {
  61.     char *szCmd;
  62.     int (*pfnCmd)(int argc, char **argv);
  63. };
  64.  
  65. LONG  (FAR PASCAL *cwPuts)(LPSTR);
  66. LPSTR (FAR PASCAL *cwGets)(LPSTR);
  67. LONG  (FAR PASCAL *cwFputs)(LPSTR, LPSTR);
  68. LPSTR (FAR PASCAL *cwFgets)(LPSTR, LONG, LPSTR);
  69. LONG  (FAR PASCAL *cwSystem)(LPSTR);
  70. BOOL  (FAR PASCAL *cwCallConsole)(FARPROC FAR *, LPSTR, LPLONG);
  71. LONG  (FAR PASCAL *cwGetch)(void);
  72. LONG  (FAR PASCAL *cwInkey)(void);
  73.  
  74. /*----------------------*/
  75. /* コンソール情報構造体 */
  76. /*----------------------*/
  77. CW_S_CONSOLE_INFO gConsoleInfo;
  78.  
  79. /*--------------------------------------*/
  80. /* 関数へのポインタの配列の先頭アドレス */
  81. /*--------------------------------------*/
  82. FARPROC FAR *glpfnIO;
  83.  
  84. BOOL FAR PASCAL CallCommand(FARPROC FAR *lpfnIO,
  85.                             LPSTR lpszCmdLine,
  86.                             LPLONG lpReturn)
  87. {
  88.     char szPath[MAX_PATH];
  89.     char *pszFile;
  90.     char *pszSpace;
  91.     int nRet;
  92.     char **wargv;
  93.     int wargc;
  94.     CMDTABLE *pCT;
  95.     static CMDTABLE cmdTable[] = {
  96.         {"cal",      cal_main},
  97.         {"cat",      cat_main},
  98.         {"chdir",    chdir_main},
  99.         {"chmod",    chmod_main},
  100.         {"cmp",      cmp_main},
  101.         {"cp",       cp_main},
  102.         {"date",     date_main},
  103.         {"df",       df_main},
  104.         {"diff",     diff_main},
  105.         {"echo",     echo_main},
  106.         {"expand",   expand_main},
  107.         {"fold",     fold_main},
  108.         {"grep",     grep_main},
  109.         {"head",     head_main},
  110.         {"join",     join_main},
  111.         {"ls",       ls_main},
  112.         {"man",      man_main},
  113.         {"mkdir",    mkdir_main},
  114.         {"mv",       mv_main},
  115.         {"od",       od_main},
  116.         {"pwd",      pwd_main},
  117.         {"rm",       rm_main},
  118.         {"rmdir",    rmdir_main},
  119.         {"sort",     sort_main},
  120.         {"split",    split_main},
  121.         {"tail",     tail_main},
  122.         {"tee",      tee_main},
  123.         {"touch",    touch_main},
  124.         {"tr",       tr_main},
  125.         {"unexpand", unexpand_main},
  126.         {"uniq",     uniq_main},
  127.         {"wc",       wc_main},
  128.         {"which",    which_main},
  129.         {NULL, NULL}
  130.     };
  131.  
  132.     /*------------------------------*/
  133.     /* 関数へのポインタの配列を保存 */
  134.     /*------------------------------*/
  135.     glpfnIO = lpfnIO;
  136.  
  137.     switch (*lpReturn) {
  138.         case CW_M_CONSOLE_INFO: {
  139.             LP_CW_S_CONSOLE_INFO lpci;
  140.  
  141.             /*------------------------------*/
  142.             /* コンソール情報をチェックする */
  143.             /*------------------------------*/
  144.             lpci = (LP_CW_S_CONSOLE_INFO)lpReturn;
  145.             switch (lpci->lMode) {
  146.                 case CW_MODE_GET:
  147.                     return FALSE;
  148.                 default:
  149.                     memcpy(&gConsoleInfo, lpReturn, sizeof(gConsoleInfo));
  150.                     return TRUE;
  151.             }
  152.         }
  153.         case CW_M_HELP: {
  154.             /*-------------------------------*/
  155.             /* ヘルプコマンド *lpReturn == 0 */
  156.             /*-------------------------------*/
  157.             if (*lpszCmdLine == '\0' && *lpReturn == 0) {
  158.                 static int i = 0;
  159.                 if (cmdTable[i].szCmd == NULL) {
  160.                     i = 0;
  161.                     return FALSE;
  162.                 }
  163.                 lstrcpyn(lpszCmdLine, cmdTable[i].szCmd, 80); i++;
  164.                 return TRUE;
  165.             }
  166.         }
  167.     }
  168.  
  169.     /*---------------------------------------*/
  170.     /* コマンド要求のチェック *lReturn == -1 */
  171.     /*---------------------------------------*/
  172.     if (*lpReturn != CW_M_EXEC) return FALSE;
  173.  
  174.     /*------------------------*/
  175.     /* モジュール名を取得する */
  176.     /*------------------------*/
  177.     lstrcpy(szPath, lpszCmdLine);
  178.     pszFile = szPath;
  179.     pszSpace = strchr(pszFile, ' ');
  180.     if (pszSpace != NULL) *pszSpace = '\0';
  181.  
  182.     /*----------------------------*/
  183.     /* サポートコマンドのチェック */
  184.     /*----------------------------*/
  185.     if (*pszFile == '\0') return FALSE;
  186.     for (pCT = cmdTable; pCT->szCmd != NULL &&
  187.                          lstrcmpi(pCT->szCmd, pszFile) != 0; pCT++);
  188.     if (pCT->szCmd == NULL) return FALSE;
  189.  
  190.     /*--------------------------*/
  191.     /* 関数ポインタを実体化する */
  192.     /*--------------------------*/
  193.     (FARPROC)cwPuts        = lpfnIO[0];
  194.     (FARPROC)cwGets        = lpfnIO[1];
  195.     (FARPROC)cwFputs       = lpfnIO[2];
  196.     (FARPROC)cwFgets       = lpfnIO[3];
  197.     (FARPROC)cwSystem      = lpfnIO[4];
  198.     (FARPROC)cwCallConsole = lpfnIO[5];
  199.     (FARPROC)cwGetch       = lpfnIO[6];
  200.     (FARPROC)cwInkey       = lpfnIO[7];
  201.  
  202.     /*--------------------*/
  203.     /* ワイルドカード展開 */
  204.     /*--------------------*/
  205.     wargv = CreateArgs(lpszCmdLine);
  206.     for (wargc = 0; wargv[wargc][0] != '\0'; wargc++);
  207.  
  208.     /*--------------------------------*/
  209.     /* アプリケーションのメインを呼ぶ */
  210.     /*--------------------------------*/
  211.     CreateGlobal();
  212.     nRet = pCT->pfnCmd(wargc, wargv);
  213.     DeleteGlobal();
  214.  
  215.     /*----------*/
  216.     /* 終了処理 */
  217.     /*----------*/
  218.     DeleteArgs(wargv);
  219.  
  220.     *lpReturn = nRet;
  221.     return TRUE;
  222. }
  223.  
  224. /*--------------*/
  225. /* 各種コマンド */
  226. /*--------------*/
  227. #include <ctype.h>
  228. #include <direct.h>
  229. #include <errno.h>
  230. #include <fcntl.h>
  231. #include <io.h>
  232. #include <stdio.h>
  233. #include <stdarg.h>
  234. #include <sys/stat.h>
  235.  
  236. int errno;
  237.  
  238. /*--------*/
  239. /* マクロ */
  240. /*--------*/
  241.  
  242. #define gg (*GetGlobal())
  243.  
  244. #define _puterrmes(s) cwFputs((s), (LPSTR)-1)
  245. #define iskanji(c) IsDBCSLeadByte((BYTE)(c))
  246. #define PD '\\'
  247. #define ESCAPE '^'
  248. #define isoctal(c) (isdigit(c) && (c) < '9')
  249. #define is_octal(c) (isascii(c) && isoctal(c))
  250. #define XBUFSIZ 8192
  251. #define is_alpha(c) (isascii(c) && isalpha(c))
  252. #define is_lower(c) (isascii(c) && islower(c))
  253. #define is_upper(c) (isascii(c) && isupper(c))
  254. #define to_lower(c) (is_upper(c) ? tolower(c) : (c))
  255. #define to_upper(c) (is_lower(c) ? toupper(c) : (c))
  256. #define TBUFSIZ 160
  257. #define GET_DRIVE(c) c - (c >= 'a' ? 'a' - 1 : 'A' - 1)
  258. #define is_digit(c) (isascii(c) && isdigit(c))
  259. #define KSPC 0x8140
  260. #define COLLISTMAX 512
  261. #define is_space(c) (isascii(c) && isspace(c))
  262. #define LINMAX 1024
  263. #define LBUFSIZ 8192
  264. #define RBUFSIZ 32768
  265. #define ctoi(c) ((c) - ((c) <= '9' ? '0' : (c) >= 'a' ? 'a' - 10 : 'A' - 10))
  266. #define is_xdigit(c) (isascii(c) && isxdigit(c))
  267. #define OPT_FORCE   01
  268. #define OPT_BINARY  02
  269. #define OPT_VISUAL  04
  270. #define imax(x, y) ((x) > (y) ? (x) : (y))
  271. #define imin(x, y) ((x) < (y) ? (x) : (y))
  272. #define CBUFSIZ 8192
  273. #define iskanji2(c) (0x40 <= (c) && (c) <= 0xFC && (c) != 0x7F)
  274. #define YES_OR_NO_P yn_p_with_ret   /* ←y/nで答えるときリターン要 */
  275. #define True 1
  276. #define MAXLEN 1024
  277. #define BIGBUFSIZ 32767 /* MAX available size in setvbuf() is 32767 */
  278. #define BUFFERSIZE (unsigned int)(8192*4)
  279. #define opt_all 1
  280. #define LINMAX  1024
  281. #define fieldnext(p) fieldtop(fieldend(p))
  282. #define IS_DIRECTORY(x) (x & 0x10)
  283. #define IS_READONLY(x) (x!=(unsigned)-1 && (x & 1))
  284. #define BUFFER_SIZE 1024    /* Maximum length of an input line */
  285. #define BLOCK_SIZE 1024
  286. #define free_buffer(l) free(l->buf),free(l)
  287. #define DIRFCMP
  288. #define IO_SUCCESS  0
  289. #define IO_ERROR  1
  290. #define  EOS    '\0'
  291. #define TEMPFILE  (gg.temfile!=NULL ? gg.temfile : (gg.temfile=difftmpnam()))
  292. #define  TRUE   1
  293. #define  FALSE  0
  294. #define  fileA  gg.file[0]
  295. #define  fileB  gg.file[1]
  296. #define  sfileA  gg.sfile[0]
  297. #define  sfileB  gg.sfile[1]
  298. #define  lenA  gg.len[0]
  299. #define  lenB  gg.len[1]
  300. #define  slenA  gg.slen[0]
  301. #define  slenB  gg.slen[1]
  302. #define CSIZE_INC 50    /* How many to allocate each time we have to */
  303. #define fname argv
  304. #define isstdin(fnm) (fnm[0] == '-' && fnm[1] == EOS)
  305. #define isdelim(c) ((c) == '\\' || (c) == '/' || (c) == ':')
  306. #define true    1
  307. #define false   0
  308. #define DEV_MASK 0x40
  309. #define ARC_MASK 0x20       /* Archive */
  310. #define DIR_MASK 0x10       /* Directory */
  311. #define VOL_MASK 0x08       /* Volume */
  312. #define SYS_MASK 0x04       /* System file */
  313. #define INV_MASK 0x02       /* Invisible */
  314. #define RDO_MASK 0x01       /* Read only */
  315. #define LINMAX  1024
  316. #define L_1ST   400
  317. #define L_INC   200
  318. #define umin(x, y) ((x) < (y) ? (x) : (y))
  319. #define spcpass(p) {while(is_space(*p)) p++;}
  320. #define nonspcpass(p) {while(!is_space(*p)){if(!*p) break; else p++;}}
  321. #define fieldpass(p) fieldcharpass(&p)
  322. #define ncharpass(p, n) {unsigned int _n; \
  323.     for(_n = n; _n; _n--){if(!*p) break; p++;}}
  324. #define OCTDUMP     1   /* o */
  325. #define DECDUMP     2   /* d */
  326. #define SGNDECDUMP  4   /* s */
  327. #define HEXDUMP     8   /* x */
  328. #define CHARDUMP    16  /* c */
  329. #define EUCDUMP     32  /* C */
  330. #define SJISDUMP    64  /* S */
  331. #define BYTEDUMP    128 /* b */
  332. #define BITMAPOUT   256 /* m */ /* no h,i,l,f */
  333. #define STRINGOUT   512 /* t */
  334. #define NOADDR      0
  335. #define OCTADDR     1
  336. #define DECADDR     2
  337. #define HEXADDR     3
  338. #define ASCIISTR    0
  339. #define EUCSTR      1
  340. #define SJISSTR     2
  341. #define OBUFSIZ     1024
  342. #define MAXDISPUNIT 2
  343.  /* longやdoubleでの表示などを将来付け加えるなら増やす。2^nであること */
  344. #define EUCCONT  1
  345. #define SJISCONT 2
  346. #define issjiskana(c) \
  347.     (0xa1 <= (c) && (c) <= 0xdf)
  348. #define issjis1(c) \
  349.     (0x81 <= (c) && (c) <= 0x9f || 0xe0 <= (c) && (c) <= 0xfc)
  350. #define issjis2(c) \
  351.     (0x40 <= (c) && (c) <= 0xfc && 0x7f != (c))
  352. #define iseuc(c) \
  353.     (0xa1 <= (c) && (c) <= 0xfe)
  354. #define isSS2(c) \
  355.     (0x8e == (c))
  356. #define PATHNAMELENGTH 1024
  357.  
  358.  
  359. /*--------*/
  360. /* 構造体 */
  361. /*--------*/
  362. typedef unsigned long   ulong;
  363. typedef unsigned char   uchar;
  364. typedef unsigned int    uint;
  365.  
  366. struct charstock {
  367.     char *buf;
  368.     unsigned int bufsiz;
  369.     unsigned int bufpos;
  370. };
  371.  
  372. struct argchar {
  373.     uchar *arg;
  374.     int next;
  375.     int step;
  376.     uint count;
  377. };
  378.  
  379. struct spinfo {
  380.     struct charstock sptabseq;
  381.     int pos, tabidx;
  382. };
  383.  
  384. typedef unsigned long   ulong;
  385.  
  386. typedef struct {
  387.     char    fno; /* 0 or 1 */
  388.     int field;
  389. } outfieldstr;
  390.  
  391. typedef struct line_buffer {
  392.     struct line_buffer *link;   /* Link to the next line. */
  393.     int     len;        /* Length of the line. */
  394.     char   *buf;        /* Line. */
  395. }       line_buffer;
  396.  
  397. typedef struct candidate {
  398.     int     b;          /* Line in fileB     */
  399.     int     a;          /* Line in fileA     */
  400.     int     link;       /* Previous candidate    */
  401. } CANDIDATE;
  402.  
  403. typedef struct line {
  404.     unsigned short  hash;       /* Hash value etc.   */
  405.     short       serial;     /* Line number        */
  406. } DIFF_LINE;
  407.  
  408. typedef int bool;
  409.  
  410. typedef union dosdate {
  411.     struct {
  412.         struct {
  413.             unsigned day:5;
  414.             unsigned month:4;
  415.             unsigned year:7;
  416.         } bh;
  417.         struct {
  418.             unsigned sec2:5;
  419.             unsigned minute:6;
  420.             unsigned hour:5;
  421.         } bl;
  422.     } b;
  423.     struct {
  424.         unsigned short d;
  425.         unsigned short t;
  426.     } dt;
  427. } dosdate;
  428.  
  429. typedef struct diff_file {
  430.     struct  diff_file    *next;
  431.     char    *name;
  432.     int attr;
  433.     dosdate date;
  434.     off_t   size;
  435. } diff_file;
  436.  
  437. typedef struct dirfile {
  438.     struct  dirfile *next;
  439.     char    *fullname;
  440. } dirfile;
  441.  
  442. typedef struct {
  443.     unsigned int    numsort : 1;
  444.     unsigned int    pblankign : 1;
  445.     unsigned int    mblankign : 1;
  446.     unsigned int    reverse : 1;
  447.     unsigned int    foldcase : 1;
  448.      /* 以下2つはglobal専用 */
  449.     unsigned int    usegopt : 1;
  450.     unsigned int    donormcmp : 1;
  451. } optstr;
  452.  
  453. typedef struct {
  454.     unsigned int    beginf, beginc; /* -1を無限大扱いするためunsigned */
  455.     unsigned int    endf, endc;
  456.     optstr  opt;
  457. } parmstr;
  458.  
  459.  /* 'u'追加時はEUC1bytekana注意 */ /* 順序変更? */
  460. typedef unsigned char   us_char;
  461. typedef unsigned short  us_short;
  462. typedef unsigned int    us_int;
  463. typedef unsigned long   us_long;
  464.  
  465. struct  infile {
  466.     FILE    *f;
  467.     us_long curpos, curline;
  468. };
  469.  
  470. enum {              /* Mode for search */
  471.     from_head,      /* `+' option */
  472.     from_tail,      /* `-' option */
  473.     tail_reverse    /* `+r' or `-r' option */
  474. };
  475.  
  476. enum {              /* Unit of count */
  477.     LINE,           /* `[+-]l' option */
  478.     CHARACTER,      /* `[+-]c' option */
  479.     BLOCK           /* `[+-]b' option */
  480. };
  481.  
  482. struct bufstr {
  483.     us_char *buf;
  484.     us_int  buflen, pos; /* for undump */
  485.     int contmode;
  486. };
  487.  
  488. struct tagTXTBUF {
  489.     us_char *buf;
  490.     us_int  buflen, pos;
  491.     us_long filepos;
  492.     int tcontmode; /* boolean */
  493. };
  494.  
  495. struct tagSORTTMPF {
  496.     FILE    *f;
  497.     char    *name;
  498.     int dirlen;
  499. };
  500.  
  501. /*----------*/
  502. /* 外部変数 */
  503. /*----------*/
  504. char ERR_MEMORY[] = "Memory exhausted\n";
  505. char    *fmt = "%-15s %7ld %7ld %*ld %5ld%%   %7ld  %s\n";
  506. char strnul[ ] = "";
  507. char    *eofmsg = "cmp: EOF on %s\n";
  508. char    *monthname[] = {
  509.     NULL,
  510.     "January",  "February", "March",
  511.     "April",    "May",      "June",
  512.     "July",     "August",   "September",
  513.     "October",  "November", "December",
  514. };
  515. char    dofw_title[ ] = " S  M Tu  W Th  F  S";
  516. char    *dofwkname[] = {
  517.     "Sunday",   "Monday",   "Tuesday",  "Wednesday",
  518.     "Thursday", "Friday",   "Saturday",
  519. };
  520. char    *month_name = "???JanFebMarAprMayJunJulAugSepOctNovDec";
  521. char    STRNULL[] = "";
  522.  
  523. #if 0 /* old grobal variant */
  524. int opterr = 1;
  525. int optind = 1;
  526. int optopt;
  527. char *optarg;
  528. int width = 80;
  529. int nodisp = 0;
  530. int current_drive, old_drive;
  531. int tabcol = 8;
  532. int tabcols[COLLISTMAX];
  533. int addsp = 0, eofnl = 0, kspc = 0; /* boolean */
  534. int ignf = 0, ignc = 0; 
  535. char outlcnt = 0, outdup = 0, outndup = 0;
  536. unsigned int availunit = 1024;
  537. char cmplmnt = 0, delete = 0, supdup = 0, treatz = 0;
  538. char ibinary = 0, obinary = 0;
  539. int  cnvtbl[0x100], duptbl[0x100];
  540. char    print_line = 0, print_word = 0, print_char = 0;
  541. long    total_l = 0L, total_w = 0L, total_c = 0L;
  542. static int found;
  543. static int display_all, msdos_format;
  544. static int error_code = 0;
  545. static char *path_scanned;
  546. extern int tabcol;
  547. int tabcols[COLLISTMAX];
  548. int elimsp = 0, unexpall = 0;
  549. extern int kspc; /* boolean */
  550. int vis = 0, num = 0, Num = 0, itxt = 0, otxt = 0;
  551. int lasteol = 1;
  552. long    lineno = 0L;
  553. char    readbuf[CBUFSIZ];
  554. int opt_recursive;
  555. int opt_verbose;
  556. int opt_interactive;
  557. int opt_force;
  558. int error_code;
  559. int linesonly = 0, fnmdisp = -1, nocase = 0, fnmonly = 0, lnumdisp = 0,
  560.     retonly = 0, reverse = 0, wholematch = 0, wordmatch = 0;
  561. int status = 1, totallcount = 0;
  562. char    *bigiobuf;
  563. int opt_backup, opt_preserve, opt_update; /* initially 0 */
  564. static char copybuf[BUFFERSIZE];
  565. char    addwidow = 0; /* 0, 1, 2, 3 */
  566. char    *emptyfill = "";
  567. int joinfield[2] = {0, 0};
  568. char    fieldsep[2] = {'\0', '\0'};
  569. outfieldstr *outlist = NULL;
  570. int outlistlen = 0;
  571. FILE    *inf[2];
  572. char    *infnm[2];
  573. char    linbuf[2][LINMAX];
  574. int force, verbose, interactive, backup, update; /* intially 0 */
  575. static char current_disk;
  576. /* Global variables */
  577. int mode;
  578. int unit;
  579. unsigned tail_lineno;
  580. int     seek_block; /* The length of one block when seeking back the file */
  581. char    *temfile = NULL;
  582. DIFF_LINE           *file[2];        /* Hash/line for total file  */
  583. DIFF_LINE           *sfile[2];       /* Hash/line after prefix  */
  584. int     len[2];         /* Actual lines in each file  */
  585. int     slen[2];        /* Squished lengths  */
  586. int     prefix;         /* Identical lines at start  */
  587. int     suffix;         /* Identical lenes at end  */
  588. FILE           *infd[2] = {NULL, NULL}; /* Input file identifiers  */
  589. FILE           *tempfd = NULL;      /* Temp for input redirection  */
  590. short          *class;          /* Unsorted line numbers  */
  591. int        *klist;          /* Index of element in clist  */
  592. CANDIDATE far  *clist;          /* Storage pool for candidates  */
  593. int     clength = 0;    /* Number of active candidates  */
  594. int     csize = CSIZE_INC;  /* Current size of storage pool */
  595. int        *match;          /* Longest subsequence       */
  596. long           *oldseek;        /* Seek position in file A  */
  597. short          *member;         /* Concatenated equiv. classes  */
  598. long           *newseek;        /* Seek position in file B  */
  599. char           *textb;          /* Input from file2 for check  */
  600. int     eflag = FALSE;  /* Edit script requested  */
  601. int     bflag = FALSE;  /* Blank supress requested  */
  602. int     cflag = FALSE;  /* Context printout  */
  603. int     iflag = FALSE;  /* Ignore case requested  */
  604. char        text[257];      /* Input line from file1  */
  605. diff_file    *files = 0;
  606. dirfile *dirs = 0;
  607. char    current_directory[PATHNAMELENGTH];
  608. bool    a_opt, d_opt, l_opt, s_opt, t_opt, x_opt, C_opt, F_opt, R_opt,
  609.     disp_dir;
  610. bool    X_opt, S_opt, Sort_by_ext_opt;
  611. int r_opt, c_opt;
  612. int filenum;        /* Nide, from inside main() */
  613. parmstr *sortparm; /* フィールド指定とそれへのオプション。
  614.   最初の1つはglobal optionだが、field optionへのコピーにも使用 */
  615. int parmcnt = 1;
  616.   /* フィールド指定の個数。global optionがあるので最低1つ */
  617.  
  618. char    **lines; /* 各行のデータ */
  619. unsigned int    linecnt = 0, linealloc;
  620.  /* できるだけオーバーフローを防ぐためunsigned */
  621.  
  622. char    global_sep[2] = {'\0', '\0'};
  623.  /* '\0'はスペース扱い。区切り文字のみ2バイト対応。余りは'\0'で埋めること */
  624. char    *otfnm = NULL;
  625.  
  626. struct tagSORTTMPF sorttmpf[2];
  627. int tmpfsw = 0;
  628. int outmode = 0, addrmode = OCTADDR;
  629. int /* boolean */ alldata = 0, endianrev = 0, hexcode = 0, undump = 0;
  630. us_int  bytelen = 0, bytelen1 = 0, stringslen = 0, stringskind = ASCIISTR;
  631. us_int  fieldw = 0, fieldb = 0, hsepwidth = 2 /* 1or2 */, sepwidth = 1;
  632.  
  633. char    *bigbuf = NULL, *obigbuf = NULL;
  634. struct bufstr usebuf[2];
  635. struct tagTXTBUF txtbuf;
  636. #endif
  637.  
  638. typedef struct GLOBAL GLOBAL, FAR *LPGLOBAL;
  639. struct GLOBAL {
  640.     int opterr;
  641.     int optind;
  642.     int optopt;
  643.     char *optarg;
  644.     int width;
  645.     int nodisp;
  646.     int current_drive;
  647.     int old_drive;
  648.     int tabcol;
  649.     int tabcols[COLLISTMAX];
  650.     int addsp;
  651.     int eofnl;
  652.     int kspc;
  653.     int ignf;
  654.     int ignc; 
  655.     char outlcnt;
  656.     char outdup;
  657.     char outndup;
  658.     unsigned int availunit;
  659.     char cmplmnt;
  660.     char delete;
  661.     char supdup;
  662.     char treatz;
  663.     char ibinary;
  664.     char obinary;
  665.     int cnvtbl[0x100];
  666.     int duptbl[0x100];
  667.     char print_line;
  668.     char print_word;
  669.     char print_char;
  670.     long total_l;
  671.     long total_w;
  672.     long total_c;
  673.     int found;
  674.     int display_all;
  675.     int msdos_format;
  676.     int error_code;
  677.     char *path_scanned;
  678.     int elimsp;
  679.     int unexpall;
  680.     int vis;
  681.     int num;
  682.     int Num;
  683.     int itxt;
  684.     int otxt;
  685.     int lasteol;
  686.     long lineno;
  687.     char readbuf[CBUFSIZ];
  688.     int opt_recursive;
  689.     int opt_verbose;
  690.     int opt_interactive;
  691.     int opt_force;
  692.     int linesonly;
  693.     int fnmdisp;
  694.     int nocase;
  695.     int fnmonly;
  696.     int lnumdisp;
  697.     int retonly;
  698.     int reverse;
  699.     int wholematch;
  700.     int wordmatch;
  701.     int status;
  702.     int totallcount;
  703.     char *bigiobuf;
  704.     int opt_backup;
  705.     int opt_preserve;
  706.     int opt_update;
  707.     char copybuf[BUFFERSIZE];
  708.     char addwidow; /* 0, 1, 2, 3 */
  709.     char *emptyfill;
  710.     int joinfield[2];
  711.     char fieldsep[2];
  712.     outfieldstr *outlist;
  713.     int outlistlen;
  714.     FILE *inf[2];
  715.     char *infnm[2];
  716.     char linbuf[2][LINMAX];
  717.     int force;
  718.     int verbose;
  719.     int interactive;
  720.     int backup;
  721.     int update;
  722.     char current_disk;
  723.     int mode;
  724.     int unit;
  725.     unsigned tail_lineno;
  726.     int seek_block; /* The length of one block when seeking back the file */
  727.     char *temfile;
  728.     DIFF_LINE *file[2];        /* Hash/line for total file  */
  729.     DIFF_LINE *sfile[2];       /* Hash/line after prefix  */
  730.     int len[2];         /* Actual lines in each file  */
  731.     int slen[2];        /* Squished lengths  */
  732.     int prefix;         /* Identical lines at start  */
  733.     int suffix;         /* Identical lenes at end  */
  734.     FILE *infd[2]; /* Input file identifiers  */
  735.     FILE *tempfd;      /* Temp for input redirection  */
  736.     short *class;          /* Unsorted line numbers  */
  737.     int *klist;          /* Index of element in clist  */
  738.     CANDIDATE far  *clist;          /* Storage pool for candidates  */
  739.     int clength;    /* Number of active candidates  */
  740.     int csize;  /* Current size of storage pool */
  741.     int *match;          /* Longest subsequence       */
  742.     long *oldseek;        /* Seek position in file A  */
  743.     short *member;         /* Concatenated equiv. classes  */
  744.     long *newseek;        /* Seek position in file B  */
  745.     char *textb;          /* Input from file2 for check  */
  746.     int eflag;  /* Edit script requested  */
  747.     int bflag;  /* Blank supress requested  */
  748.     int cflag;  /* Context printout  */
  749.     int iflag;  /* Ignore case requested  */
  750.     char  text[257];      /* Input line from file1  */
  751.     diff_file *files;
  752.     dirfile *dirs;
  753.     char current_directory[PATHNAMELENGTH];
  754.     bool a_opt;
  755.     bool d_opt;
  756.     bool l_opt;
  757.     bool s_opt;
  758.     bool t_opt;
  759.     bool x_opt;
  760.     bool C_opt;
  761.     bool F_opt;
  762.     bool R_opt;
  763.     bool disp_dir;
  764.     bool X_opt;
  765.     bool S_opt;
  766.     bool Sort_by_ext_opt;
  767.     int r_opt;
  768.     int c_opt;
  769.     int filenum;        /* Nide, from inside main() */
  770.     parmstr *sortparm; /* フィールド指定とそれへのオプション。
  771.             最初の1つはglobal optionだが、field optionへのコピーにも使用 */
  772.     int parmcnt; /* フィールド指定の個数。global optionがあるので最低1つ */
  773.     char **lines; /* 各行のデータ */
  774.     unsigned int linecnt;
  775.     unsigned int linealloc; /* できるだけオーバーフローを防ぐためunsigned */
  776.     char global_sep[2]; /* '\0'はスペース扱い。区切り文字のみ2バイト対応。
  777.                            余りは'\0'で埋めること */
  778.     char *otfnm;
  779.     struct tagSORTTMPF sorttmpf[2];
  780.     int tmpfsw;
  781.     int outmode;
  782.     int addrmode;
  783.     bool alldata;
  784.     bool endianrev;
  785.     bool hexcode;
  786.     bool undump;
  787.     us_int bytelen;
  788.     us_int bytelen1;
  789.     us_int stringslen;
  790.     us_int stringskind;
  791.     us_int fieldw;
  792.     us_int fieldb;
  793.     us_int hsepwidth /* 1or2 */;
  794.     us_int sepwidth;
  795.     char *bigbuf;
  796.     char *obigbuf;
  797.     struct bufstr usebuf[2];
  798.     struct tagTXTBUF txtbuf;
  799.     char s_converted[MAX_PATH];
  800.     char s_crtail[3];
  801.     char *s_curopt;
  802.     int s_pos;
  803.     char s_buf[TBUFSIZ];
  804.     char s_readbuf[RBUFSIZ];
  805.     char *s_readbuf2;
  806.     char s_buf2[100];
  807.     struct spinfo s_sppresv;
  808.     int s_first;
  809.     char s_base[PATHNAMELENGTH];
  810.     int s_flag;
  811.     char *s_buf1_0;
  812.     char *s_buf2_0;
  813.     char s_name[13];
  814.     int s_prev_sp;
  815.     char s_tmparg[4];
  816.     double s_a;
  817.     double s_b;
  818.     char *s_passbuf;
  819.     int screenwidth;
  820. };
  821.  
  822. GLOBAL G;
  823.  
  824. BOOL CreateGlobal(void)
  825. {
  826.     memset(&G, 0, sizeof(G));
  827.     G.opterr = 1;
  828.     G.optind = 1;
  829.     G.width = 80;
  830.     G.tabcol = 8;
  831.     G.availunit = 1024;
  832.     G.lasteol = 1;
  833.     G.fnmdisp = -1;
  834.     G.status = 1;
  835.     G.emptyfill = "";
  836.     G.csize = CSIZE_INC;
  837.     G.parmcnt = 1;
  838.     G.addrmode = OCTADDR;
  839.     G.stringskind = ASCIISTR;
  840.     G.hsepwidth = 2l;
  841.     G.sepwidth = 1;
  842.     G.s_crtail[1] = '\0';
  843.     G.s_first = 1;
  844.     G.s_base[0] = 'x';
  845.     G.s_flag = -1;
  846.     G.s_tmparg[1] = ':';
  847.     G.s_tmparg[2] = '.';
  848.     G.screenwidth = 80;
  849.  
  850.     return TRUE;
  851. }
  852.  
  853. LPGLOBAL GetGlobal(void)
  854. {
  855.     return &G;
  856. }
  857.  
  858. BOOL DeleteGlobal(void)
  859. {
  860.     return TRUE;
  861. }
  862.  
  863. #define gg (*GetGlobal())
  864.  
  865. /*--------------*/
  866. /* プロトタイプ */
  867. /*--------------*/
  868. unsigned char getcurdrv(void);
  869. int getwd(unsigned char drvnm, char *p);
  870. void fold(FILE *f);
  871. int fold_usage(void);
  872. void fhead(FILE *f, int lines);
  873. int head(char *fnm, int lines, int disphead);
  874. int expand(FILE *f); /* returns last pos */
  875. int uniq(int ac, char **av);
  876. void out(char *buf, int cnt);
  877. void df(void);
  878. void trmain(uchar *from, uchar *to);
  879. int wc_usage(void);
  880. int wc(char *fnm, int nmdisp);
  881. void wcout(int flg, unsigned long n);
  882. void wcmain(int fd);
  883. void unexpand(FILE *f);
  884. int s_cmp(char *s, char *t);
  885. int a_cmp(char *s, char *t);
  886. int cmp(char *s, char *t);
  887. int cantopen(char *s);
  888. int do_split(int flag, int linemax, long bytemax, FILE *inf, char *base);
  889. int nextext(char *ext);
  890. int writefail(void);
  891. long caldate(int y, int m, int d);
  892. int  bad(void);
  893. int  fputs_so(char *s);
  894. void putint(int n);
  895. void putchar_n(int n, int c);
  896. void putday(int n); /* width 2 */
  897. void shortmonth(int m);
  898. void getmonthdays(int year, int month, char *days, char *d_of_w);
  899. int  cal(void);
  900. int  caly(int year);
  901. int  calym(int year, int month);
  902. void calrow(int year, int month, int days, int d_of_w, int row, int eolsup);
  903. void outv(FILE *f); 
  904. void outn(FILE *f);
  905. void outb(FILE *f);
  906. void longintout(int w, unsigned long n, char **);
  907. int mod_disp_time(char *newt, char *fmt);
  908. int date_usage(void);
  909. int illdate(void);
  910. int disptime(char *fmt, int y, int m, int d, int h, int mi, int s, int w);
  911. int pempty(void);
  912. int efgrep(char *ptn, char *fnm);
  913. int foundline(char *ptn, char *p);
  914. int cp_usage(void);
  915. int touch_usage(void);
  916. int readtime(char *str, struct utimbuf *utimearg);
  917. void fieldout(char *s1, char *s2, int flag);
  918. int strfieldcmp(char *fb, char *fe, char *p, int n);
  919. int strpartcmp(char *p, int m, char *q, int n);
  920. int mv_usage(void);
  921. int tail_usage(void);
  922. char *difftmpnam(void); /* ad hoc */
  923. int differror(char *format, ...);
  924. int cant(char *filename,
  925.           char *what,
  926.           int fatalflag);
  927. int isdir(char *fnm); /* on TURBOC, which files are needed to be included? */
  928. void input(int which);
  929. void squish(void);
  930. void sort(DIFF_LINE *vector, int vecsize);
  931. void equiv(void);
  932. void unsort(void);
  933. int subseq(void);
  934. void unravel(int k);
  935. int check(char *fileAname, char *fileBname);
  936. void output(char *fileAname, char *fileBname);
  937. int getline(FILE *fd, char *buffer);
  938. int newcand(int a, int b, int pred);
  939. unsigned search(unsigned low, unsigned high, int b);
  940. int streq(char *s1, char *s2);
  941. void change(int astart, int aend, int bstart, int bend);
  942. void range(int from, int to, int w);
  943. void fetch(long *seekvec,
  944.            int start,
  945.            int end,
  946.            int trueend,
  947.            FILE *fd,
  948.            char *pfx);
  949. void fputss(char *s, FILE *iop);
  950. void noroom(char *why);
  951. void errorexit(void);
  952. char        *fgetss();
  953. unsigned short  hash();
  954. char        *dircat();
  955. extern  char    *myalloc();     /* Storage allocator     */
  956. extern  char    *compact();     /* Storage compactor     */
  957. extern int getopt();
  958. void readfile(char *fnm);
  959. void linereg(char *s);
  960. void do_sort(void);
  961. void join_output(FILE *f, FILE *midf);
  962. void midproc(void); /* メモリが足りなくなったので中間処理 */
  963. bool add_file_list_sub(char *name, 
  964.                        bool fullname,
  965.                        unsigned volmask,
  966.                        bool nomsg,
  967.                        int intended_as_directory);
  968. void setstdoutbuf(void);
  969.  
  970. /*--------------*/
  971. /* サブルーチン */
  972. /*--------------*/
  973.  
  974. /*
  975.  * Convert MSDOS format pathname F(as '\xx\yy\zz') to UNIX format pathname
  976.  * '/xx/yy/zz'. F is overwritten. Returns F.
  977.  */
  978. char *conv_char(char *s, char cs, char cd)
  979. {
  980.     unsigned char *p;
  981.  
  982.     for (p = s; *p != '\0'; p++) {
  983.         if (IsDBCSLeadByte(*p) == TRUE) {
  984.             p++;
  985.             if (*p == '\0') {
  986.                 break;
  987.             }
  988.             continue;
  989.         }
  990.         if (*p == cs) {
  991.             *p = cd;
  992.         }
  993.      }
  994.      return s;
  995. }
  996.  
  997. int conv_char_args(char **argv, char cs, char cd)
  998. {
  999.     char **p;
  1000.  
  1001.     for (p = argv; p[0][0] != '\0'; p++) {
  1002.         conv_char(*p, cs, cd);
  1003.     }
  1004.     return 0;
  1005. }
  1006.  
  1007. char *conv_to_unix_format(char *s)
  1008. {
  1009.     conv_char(s, '\\', '/');
  1010.     AnsiLowerBuff(s, lstrlen(s));
  1011.     return s;
  1012. }
  1013.  
  1014. char *s_conv_to_unix_format(char *f)
  1015. {
  1016.     return conv_to_unix_format(strcpy(gg.s_converted, f));
  1017. }
  1018.  
  1019. void _putnomemmes(void) /* Nide */
  1020. {
  1021.     _puterrmes(ERR_MEMORY);
  1022. }
  1023.  
  1024. int iskanjipos(char *p)
  1025. {
  1026.     return iskanji(*p) && p[1];
  1027. }
  1028.  
  1029. /*
  1030.  * Cutoff the redundant path delimiter in the pathname string F. F is
  1031.  * overwritten. Returns 1 if F ends with '/'(means the path is a directory,
  1032.  * in UNIX semantics), else returns 0.
  1033.  * 
  1034.  */
  1035. int regularize_pathname(char *f)
  1036. {
  1037.     char   *s, *d;
  1038.     int r = 0;
  1039.  
  1040.     conv_char(f, '/', '\\');
  1041.  
  1042.     /* Ignore the drive specifier */
  1043.     if(isalpha(f[0]) && f[1] == ':'){
  1044.         if(f[2] == '\0') {
  1045.             return 1;
  1046.         }
  1047.         f += 2;
  1048.     }
  1049.     /* Root are treated specially. */
  1050.     if(f[0] == PD && f[1] == '\0') {
  1051.         return 1;
  1052.     }
  1053.     for(s = d = f; *s;){
  1054.         if(iskanjipos(s)){
  1055.             if(s != d) {
  1056.                 *d++ = *s++, *d++ = *s++;
  1057.             } else {
  1058.                 s += 2, d += 2;
  1059.             }
  1060.         } else {
  1061.             if(s > f && s[0] == PD && (s[1] == PD || s[1] == '\0')){
  1062.                 /*
  1063.                  * don't convert '//...' -> '/...'. this is
  1064.                  * used as super root file system in the
  1065.                  * future :-).
  1066.                  * 
  1067.                  * convert '...//...' -> '.../...', '..../' ->
  1068.                  * '....' .
  1069.                  */
  1070.                 if(s[1] == '\0') {
  1071.                     r = 1;
  1072.                 }
  1073.                 s++;
  1074.             } else {
  1075.                 if(s != d) {
  1076.                     *d++ = *s++;
  1077.                 } else {
  1078.                     s++, d++;
  1079.                 }
  1080.             }
  1081.         }
  1082.     }
  1083.     *d = '\0';
  1084.     return r;
  1085. }
  1086.  
  1087. int conv_to_dos_format(char *f)
  1088. {
  1089.     conv_char(f, '/', '\\');
  1090.     return regularize_pathname(f);
  1091. }
  1092. /***********************************************************************
  1093.         getopt.c  このgetopt.cはPublic Domainです
  1094. ***********************************************************************/
  1095.  
  1096. void errdisp(char *cmd, char *as)
  1097. {
  1098.     if(gg.opterr){
  1099.         _puterrmes(cmd), _puterrmes(as),
  1100.         *gg.s_crtail = gg.optopt, _puterrmes(gg.s_crtail);
  1101.     }
  1102. }
  1103.  
  1104. int getopt(int ac, char **av, char *opts)
  1105. {
  1106.     register char *cp;
  1107.  
  1108.     if(gg.s_curopt == NULL || !*gg.s_curopt){
  1109.         if(gg.optind >= ac || *(gg.s_curopt = av[gg.optind]) != '-' ||
  1110.                 !gg.s_curopt[1])
  1111.             return EOF;
  1112.         if(!strcmp("-", ++gg.s_curopt))
  1113.             return (gg.optind++, EOF);
  1114.     }
  1115.     if(':' == (gg.optopt=*gg.s_curopt++) ||
  1116.             NULL == (cp=strchr(opts, gg.optopt))){
  1117.         errdisp(*av, ": unknown option, -");
  1118.         if(!*gg.s_curopt) gg.optind++;
  1119.         return '?';
  1120.     }
  1121.     if(*++cp == ':'){
  1122.         gg.optind++;
  1123.         if(*gg.s_curopt){
  1124.             gg.optarg = gg.s_curopt;
  1125.             gg.s_curopt = NULL;
  1126.         } else {
  1127.             if(gg.optind >= ac){
  1128.                 errdisp(*av, ": argument missing for -");
  1129.                 return '?';
  1130.             } else {
  1131.                 gg.optarg = av[gg.optind++];
  1132.             }
  1133.              /* now *curopt == '\0' */
  1134.         }
  1135.     } else {
  1136.         gg.optarg = NULL;
  1137.         if(!*gg.s_curopt) gg.optind++;
  1138.     }
  1139.     return gg.optopt;
  1140. }
  1141.  
  1142. /*-----------*/
  1143. /* echo_main */
  1144. /*-----------*/
  1145.  
  1146. int echo_main(int ac, char **av)
  1147. {
  1148.     int nI;
  1149.     int nLen;
  1150.     char *pStr;
  1151.  
  1152.     nLen = 0;
  1153.     for (nI = 0; nI < ac; nI++) {
  1154.         nLen += lstrlen(av[nI]) + 1;
  1155.     }
  1156.     pStr = malloc(nLen + 1); nI = 0;
  1157.     if (pStr == NULL) {
  1158.         return 0;
  1159.     }
  1160.  
  1161.     ac--, av++;
  1162.  
  1163.     if(!ac) return 0; /* exit 0 */
  1164.     for(; ac--; av++){
  1165.         char *p, c;
  1166.         int i;
  1167.  
  1168.         for(p = *av; c = *p; p++){
  1169.             if(c == ESCAPE){
  1170.                 switch(c = *++p){
  1171.                     case 'c': goto nextarg;
  1172.                     case 'n': c = '\n'; break;
  1173.                     case 't': c = '\t'; break;
  1174.                     case 'b': c = '\b'; break;
  1175.                     case 'r': c = '\r'; break;
  1176.                     case 'f': c = '\f'; break;
  1177.                     case 'a': c = 0x7; break;
  1178.                     case 'v': c = 0xb; break;
  1179.                     case 'e': c = '\033'; break;
  1180.                     case '\0': p--, c = ESCAPE; break;
  1181.                     case '0':
  1182.                         c = 0, i = 3;
  1183.                         while(p++, i-- && is_octal(*p)) {
  1184.                              c <<= 3, c |= *p - '0';
  1185.                         }
  1186.                         p--; break;
  1187.                         /* case ESCAPE: break; */
  1188.                         /* default: break; */
  1189.                 }
  1190.             }
  1191.             pStr[nI] = c; nI++;
  1192.         }
  1193.         pStr[nI] = '\0';
  1194.         cwFputs(pStr, NULL); nI = 0;
  1195.         if(ac){
  1196.             cwFputs(" ", NULL);
  1197.         } else {
  1198.             cwFputs("\n", NULL);
  1199.         }
  1200.     nextarg:
  1201.         ;
  1202.     }
  1203.     free(pStr);
  1204.     return 0; /* exit 0 */
  1205. }
  1206.  
  1207. /*------------*/
  1208. /* rmdir_main */
  1209. /*------------*/
  1210. int rmdir_main(int ac, char **av)
  1211. {
  1212.     int error = 0;
  1213.  
  1214.     if(av++, !--ac){
  1215.         cwFputs("rmdir DIRECTORY...\n", (LPSTR)-1); return 1;
  1216.     }
  1217.     for(; ac; ac--, av++){
  1218.     if(rmdir(*av)){
  1219.         conv_to_unix_format(*av), cwFputs(*av, (LPSTR)-1);
  1220.         cwFputs(errno == ENOENT ? 
  1221.               ": Not exist\n" : ": Can't remove\n", (LPSTR)-1);
  1222.              error = 1;
  1223.         }
  1224.     }
  1225.     return  error;
  1226. }
  1227.  
  1228. /*----------*/
  1229. /* tee_main */
  1230. /*----------*/
  1231.  
  1232. int tee_main(int ac, char **av)
  1233. {
  1234.     char *buf; /* no huge auto array... */
  1235.     int i, iosize, mode = O_TEXT | O_WRONLY | O_CREAT, *fps;
  1236.  
  1237.     buf = malloc(XBUFSIZ);
  1238.     if (buf == NULL) {
  1239.         return 1;
  1240.     }
  1241.  
  1242.     if(av++, ac-- && !strcmp(*av, "-a")){
  1243.         av++, ac--, mode |= O_APPEND;
  1244.     }
  1245.     if(NULL == (fps = malloc(sizeof(int) * (ac + 1)))){
  1246.         _putnomemmes();
  1247.         free(buf);
  1248.         return 1;
  1249.     } else {
  1250.         fps[ac] = 1;
  1251.     }
  1252.     for(i = 0; i < ac; i++){
  1253.         if(0 > (fps[i] = open(av[i], mode, S_IWRITE | S_IREAD))){
  1254.             if(errno == EMFILE) {
  1255.                  _puterrmes("Too many open files");
  1256.             } else {
  1257.                 _puterrmes(conv_to_unix_format(av[i]));
  1258.                 _puterrmes(": Can't open");
  1259.             }
  1260.             _puterrmes("\n");
  1261.             free(buf);
  1262.             return 1;
  1263.         }
  1264.     }
  1265.     while(NULL != cwFgets(buf, XBUFSIZ, NULL)){
  1266.         iosize = lstrlen(buf);
  1267.         for(i = 0; i < ac; i++){
  1268.             if(iosize > write(fps[i], buf, iosize)){
  1269.                 _puterrmes(conv_to_unix_format(av[i]));
  1270.                 _puterrmes(": Write failed\n");
  1271.             }
  1272.         }
  1273.         cwFputs(buf, NULL);
  1274.     }
  1275.     for (i = 0; i < ac; i++) {
  1276.         close(fps[i]);
  1277.     }
  1278.     free(buf);
  1279.     return 0;
  1280. }
  1281.  
  1282. /*----------*/
  1283. /* pwd_main */
  1284. /*----------*/
  1285.  
  1286. /*
  1287.   usage:
  1288.     pwd [-dp] [drive[:]]
  1289.  
  1290.     -d …… ドライブ名のみ表示。
  1291.     -p …… ディレクトリ名のみ表示。
  1292. */
  1293.  
  1294. unsigned char getcurdrv(void)
  1295. {
  1296.     return _getdrive() - 1;
  1297. }
  1298.  
  1299. int pwd_main(int ac, char **av)
  1300. {
  1301.     int c;
  1302.     register unsigned char drvnm;
  1303.     register char *drvarg, drv;
  1304. //  extern int optind, opterr;
  1305. //  extern char *optarg;
  1306.     char p[MAX_PATH];
  1307.     char szDrv[16];
  1308.  
  1309.     int nopath = 0, nodrv = 0;
  1310.  
  1311.     gg.opterr = 0;
  1312.     while(EOF != (c = getopt(ac, av, "dp"))){
  1313.         switch(c){
  1314.             case 'd': nopath = 1; break;
  1315.             case 'p': nodrv = 1; break;
  1316.             default:
  1317.                 cwFputs("Usage: pwd [-dp] [drive[:]]\n", (LPSTR)-1);
  1318.                 return 1;
  1319.         }
  1320.     }
  1321.     if(nopath && nodrv){
  1322.         cwFputs("Equivocal operands --- p and d\n", (LPSTR)-1);
  1323.         return 1;
  1324.     }
  1325.  
  1326.     ac -= gg.optind;
  1327.     av += gg.optind;
  1328.  
  1329.     switch(ac){
  1330.         case 0:
  1331.             drvnm = 0;
  1332.             drv = 'a' + getcurdrv();
  1333.             break;
  1334.         case 1:
  1335.             drvarg = *av;
  1336.             if(!is_alpha(*drvarg) ||
  1337.                     !(!drvarg[1] || drvarg[1] == ':' && !drvarg[2])){
  1338.                 cwFputs("Illegal drive --- ", (LPSTR)-1);
  1339.                 cwFputs(drvarg, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
  1340.                 return 1;
  1341.             }
  1342.             drv = to_lower(*drvarg);
  1343.             drvnm = drv - 'a' + 1;
  1344.             break;
  1345.         default:
  1346.             cwFputs("Too many arguments.\n", (LPSTR)-1);
  1347.             return 1;
  1348.     }
  1349.  
  1350.     if(nopath){
  1351.         _snprintf(szDrv, sizeof(szDrv), "%c\n", drv);
  1352.         cwFputs(szDrv, NULL);
  1353.     } else {
  1354.         switch(getwd(drvnm, p)){
  1355.             case 1:
  1356.                 cwFputs("Unavailable drive --- ", (LPSTR)-1);
  1357.                 cwFputs(drvarg, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
  1358.                 return 1;
  1359.             default:
  1360.                 if(!nodrv){
  1361.                     _snprintf(szDrv, sizeof(szDrv), "%c:", drv);
  1362.                     cwFputs(szDrv, NULL);
  1363.                 } 
  1364.                 szDrv[0] = '/'; szDrv[1] = '\0';
  1365.                 cwFputs(szDrv, NULL);
  1366.                 cwFputs(p, NULL);
  1367.                 szDrv[0] = '\n'; szDrv[1] = '\0';
  1368.                 cwFputs(szDrv, NULL);
  1369.         }
  1370.     }
  1371.     return 0;
  1372. }
  1373.  
  1374. int getwd(unsigned char drvnm, char *p)
  1375. {
  1376.     char *pRet;
  1377.     pRet = _getdcwd(drvnm, p, MAX_PATH);
  1378.     if (pRet == NULL) {
  1379.         return 1;
  1380.     } else {
  1381.         memmove(p, p + 3, MAX_PATH-2);
  1382.         conv_to_unix_format(p);
  1383.         return 0;
  1384.     }
  1385. }
  1386.  
  1387. /*---------*/
  1388. /* fold_main */
  1389. /*---------*/
  1390.  
  1391. int fold_usage(void)
  1392. {
  1393.     cwFputs("Usage: fold [-[w]width] [file...]\n", (LPSTR)-1);
  1394.     return 1;
  1395. }
  1396.  
  1397. int fold_main(int ac, char **av)
  1398. {
  1399.     FILE *inf;
  1400.  
  1401.     ac--, av++;
  1402.     if(ac && av[0][0] == '-' && av[0][1]){
  1403.         if(av[0][1] == 'w'){
  1404.             if(av[0][2]){
  1405.                 gg.width = atoi(*av + 2);
  1406.             } else {
  1407.                 if(av++, !--ac) {
  1408.                     return fold_usage();
  1409.                 }
  1410.                 gg.width = atoi(*av);
  1411.             }
  1412.         } else {
  1413.             gg.width = atoi(*av + 1);
  1414.         }
  1415.         if(0 >= gg.width) {
  1416.             return fold_usage();
  1417.         }
  1418.         ac--, av++;
  1419.     }
  1420.     if(!ac){
  1421.         fold(NULL);
  1422.     } else {
  1423.         for(; ac; ac--, av++){
  1424.             if(av[0][0] == '-' && !av[0][1]){
  1425.                 fold(NULL);
  1426.             } else {
  1427.                 if(NULL == (inf = fopen(*av, "r"))){
  1428.                     cwFputs(s_conv_to_unix_format(*av), (LPSTR)-1);
  1429.                     cwFputs(": Can't open\n", (LPSTR)-1);
  1430.                     return 1;
  1431.                 }
  1432.                 fold(inf);
  1433.                 fclose(inf);
  1434.             }
  1435.         }
  1436.     }
  1437.     return 0;
  1438. }
  1439.  
  1440. void fold(FILE *f)
  1441. {
  1442.     int c;
  1443.     char bufi[0x100];
  1444.     char bufo[0x200];
  1445.     char *pi;
  1446.     char *po;
  1447.  
  1448.     while (TRUE) {
  1449.         if (f == NULL) {
  1450.             if (cwFgets(bufi, 0xFF, NULL) == NULL) break;
  1451.         } else {
  1452.             if (fgets(bufi, 0xFF, f) == NULL) break;
  1453.         }
  1454.         bufi[0xFF] = '\0';
  1455.         po = bufo;
  1456.         for (pi = bufi; *pi != '\0'; pi++) {
  1457.             c = *pi;
  1458.             if(iskanji(c)){
  1459.                 gg.s_pos += 2;
  1460.                 if(gg.s_pos > gg.width) {
  1461.                     *po++ = '\n';
  1462.                     gg.s_pos = 2;
  1463.                 }
  1464.                 *po++ = c;
  1465.                 pi++;
  1466.                 if (*pi == '\0') {
  1467.                     gg.s_pos--;
  1468.                     return;
  1469.                 }
  1470.                 *po++ = c;
  1471.             } else if(c == '\b'){
  1472.                 *po++ = c;
  1473.                 gg.s_pos--;
  1474.             } else if(c == '\n' || c == '\r' || c == '\f'){
  1475.                 *po++ = c;
  1476.                 gg.s_pos = 0;
  1477.             } else if(c == '\t'){
  1478.                 gg.s_pos = (gg.s_pos + 8) & ~7;
  1479.                 if(gg.s_pos > gg.width) {
  1480.                     *po++ = '\n';
  1481.                     gg.s_pos = 8;
  1482.                 }
  1483.                 *po++ = c;
  1484.             } else {
  1485.                 if(++gg.s_pos > gg.width) {
  1486.                     *po++ = '\n';
  1487.                     gg.s_pos = 1;
  1488.                 }
  1489.                 *po++ = c;
  1490.             }
  1491.         }
  1492.         *po = '\0';
  1493.         cwFputs(bufo, NULL);
  1494.     }
  1495. }
  1496.  
  1497. /*-------*/
  1498. /* mkdir */
  1499. /*-------*/
  1500. int makedir(char *path)
  1501. {
  1502.     char   *x, *last_path_sep;
  1503.     /*
  1504.      * No problem if succeeded to mkdir PATH.
  1505.      */
  1506.  
  1507.     if(!mkdir(path))
  1508.         return 1;
  1509.  
  1510.     /*
  1511.      * Suppose PATH is "A/B/C/D", if failed to mkdir PATH itself, then
  1512.      * try to mkdir "A/B/C", and mkdir "D" under "A/B/C". This process
  1513.      * can be expressed as recursion.
  1514.      */
  1515.     x = path;
  1516.     last_path_sep = 0;
  1517.  
  1518.     /*
  1519.      * First split PATH into 2 part, for example if PATH = "A/B/C/D",
  1520.      * split into "A/B/C" and "D". LAST_PATH_SEP holds between the 1st
  1521.      * and 2nd string.
  1522.      */
  1523.     while(*x){
  1524.         if(iskanjipos(x))
  1525.             x += 2;
  1526.         else {
  1527.             if(*x == PD)
  1528.                 last_path_sep = x;
  1529.             x++;
  1530.         }
  1531.     }
  1532.     /*
  1533.      * Return error if failed to split PATH.
  1534.      */
  1535.     if(last_path_sep == 0)
  1536.         return 0;
  1537.  
  1538.     {
  1539.         char buf[BUFSIZ];
  1540.         strncpy(buf, path, last_path_sep - path);
  1541.         buf[last_path_sep - path] = '\0';
  1542.         /*
  1543.          * Try to mkdir "A/B/C".
  1544.          */
  1545.         if(!makedir(buf))
  1546.             return 0;
  1547.         /*
  1548.          * and mkdir "D" under "A/B/C".
  1549.          */
  1550.         return !mkdir(path);
  1551.         /* Instead of: if(mkdir(path)) return 0; else return 1; */
  1552.     }
  1553. }
  1554.  
  1555. int mkdir_main(int argc, char **argv)
  1556. {
  1557.     int i;
  1558.     int error = 0;
  1559.     int recur = 0;  /* Add Nide */
  1560.  
  1561.     conv_char_args(argv, '/', '\\');
  1562.  
  1563.     if(argc >= 2 && !strcmp("-p", argv[1])){
  1564.         argc--, argv++, recur = 1;
  1565.     } /* Add Nide */
  1566.     if(argc < 2){
  1567.         cwFputs("mkdir [-p] DIRECTORY...\n", (LPSTR)-1); /* Changed Nide */
  1568.         return 1;
  1569.     }
  1570.     for(i = 1; i < argc; i++){
  1571.         conv_to_dos_format(argv[i]);
  1572.         if(recur ? !makedir(argv[i]) : mkdir(argv[i])){ /* Changed Nide */
  1573.             cwFputs(s_conv_to_unix_format(argv[i]), (LPSTR)-1);
  1574.             cwFputs(": Can't make directory\n", (LPSTR)-1);
  1575.             error = 1;
  1576.         }
  1577.     }
  1578.     return error;
  1579. }
  1580.  
  1581. /*------------*/
  1582. /* chmod_main */
  1583. /*------------*/
  1584.  /* chmod.c
  1585.  
  1586.     Usage: chmod [[ua]{-,+}owhsa] files...
  1587.     '+'はその属性を与え、'-'は取り去る
  1588.     o: 書き込み禁止属性
  1589.     w: 書き込み許可(oの反対)
  1590.     h: 隠しファイル属性
  1591.     s: システムファイル属性
  1592.     a: アーカイブ属性
  1593.  */
  1594.  
  1595. char *name_unixnize(unsigned char *s)
  1596. {
  1597.     char *ret = s;
  1598.  
  1599.     for(; *s; s++){
  1600.         if(iskanjipos(s)) s++;
  1601.         else if(*s == '\\') *s = '/';
  1602.         else if(isascii(*s) && isupper(*s))
  1603.             *s = tolower(*s);
  1604.     }
  1605.     return(ret);
  1606. }
  1607.  
  1608. int chmod_usage(void)
  1609. {
  1610.     cwFputs("Usage: chmod [-n] [[ua]{-,+}owhsa] files...\n", (LPSTR)-1);
  1611.     return 1;
  1612. }
  1613.  
  1614. unsigned getattr(char *s)
  1615. /* エラー時には ~0 が返る */
  1616. {
  1617.     return GetFileAttributes(s);
  1618. }
  1619.  
  1620. int setattr(char *s, unsigned a)
  1621. /* 成功時には0 失敗時には-1を返す */
  1622. {
  1623.     return (SetFileAttributes(s, a) == TRUE) ? 0 : -1;
  1624. }
  1625.  
  1626. #if 0
  1627. void    expand_control()
  1628. {
  1629.     _dosfind_param = 0x37;
  1630. }
  1631. #endif
  1632.  
  1633. char *modarg(char *s)
  1634. {
  1635.     if(*s == 'u' || *s == 'a') s++;
  1636.     return (*s == '-' || *s == '+') ? s : NULL;
  1637. }
  1638.  
  1639. int chmod_main(int ac, char **av)
  1640. {
  1641.     char *p;
  1642.     int plus, status = 0;
  1643.     unsigned attr, plusattr = 0, minusattr = 0x18; /* dir&vol bit */
  1644.  
  1645.     ac--, av++;
  1646.     if(ac && !strcmp(*av, "-n")){
  1647.         ac--, av++, gg.nodisp = 1;
  1648.     }
  1649.     if(!ac || NULL == modarg(*av)) return chmod_usage();
  1650.     for(; ac && NULL != (p = modarg(*av)); ac--, av++){
  1651.         plus = (*p == '+');
  1652.         for(p++; *p; p++){
  1653.             switch(*p){
  1654.             case 'o':
  1655.                 plus ? (plusattr |= 1) : (minusattr |= 1);
  1656.                 break;
  1657.             case 'h':
  1658.                 plus ? (plusattr |= 2) : (minusattr |= 2);
  1659.                 break;
  1660.             case 's':
  1661.                 plus ? (plusattr |= 4) : (minusattr |= 4);
  1662.                 break;
  1663.             case 'a':
  1664.                 plus ? (plusattr |= 32) : (minusattr |= 32);
  1665.                 break;
  1666.             case 'w':
  1667.                 !plus ? (plusattr |= 1) : (minusattr |= 1);
  1668.                 break;
  1669.             default:
  1670.                 return chmod_usage();
  1671.             }
  1672.         }
  1673.     }
  1674.     if(!ac) return chmod_usage();
  1675.  
  1676.  
  1677.     for(; ac; ac--, av++){
  1678.         p = name_unixnize(*av);
  1679.         attr = getattr(p);
  1680.         attr &= ~minusattr;
  1681.         attr |= plusattr;
  1682.         if(-1 == setattr(p, attr)){
  1683.             cwFputs(p, (LPSTR)-1);
  1684.             cwFputs(": Can't change\n", (LPSTR)-1);
  1685.             status = 1;
  1686.             continue;
  1687.         }
  1688.         if(!gg.nodisp){
  1689.             cwFputs(p, (LPSTR)-1);
  1690.             cwFputs(":\n", (LPSTR)-1);
  1691.         }
  1692.     }
  1693.     return status;
  1694. }
  1695.  
  1696. /*----------*/
  1697. /* man_main */
  1698. /*----------*/
  1699. /*
  1700.     Very very simple man        Changed Nide
  1701. */
  1702.  
  1703. char *find_man_file(char *dir, char *command)
  1704. {
  1705.     _snprintf(gg.s_buf, sizeof(gg.s_buf), "%s\\%s.doc", dir, command);
  1706.     if(!access(gg.s_buf, 0)) return gg.s_buf;
  1707.     _snprintf(gg.s_buf, sizeof(gg.s_buf), "%s\\%s.man", dir, command);
  1708.     if(!access(gg.s_buf, 0)) return gg.s_buf;
  1709.     _snprintf(gg.s_buf, sizeof(gg.s_buf), "%s\\%s.1", dir, command);
  1710.     if(!access(gg.s_buf, 0)) return gg.s_buf;
  1711.     return 0;
  1712. }
  1713.  
  1714. int man(char *cmdname)
  1715. {
  1716.     char *path = 0, *manpath;
  1717.     char *p, *q, buf[TBUFSIZ];
  1718.  
  1719.     if(NULL == (manpath = getenv("MANPATH")) &&
  1720.        NULL == (manpath = getenv("MAN"))){
  1721.         cwFputs("MANPATH not set\n", (LPSTR)-1);
  1722.         return 1;
  1723.     }
  1724.     for(p = manpath; p != NULL;){
  1725.         _snprintf(buf, sizeof(buf), "%.*s",
  1726.             NULL != (q = strchr(p, ';')) ? q++ - p : strlen(p), p);
  1727.         if(*buf && (buf-1)[strlen(buf)] == '\\')
  1728.             (buf-1)[strlen(buf)] = '\0';
  1729.         if(path = find_man_file(buf, cmdname)) break;
  1730.         p = q;
  1731.     }
  1732.     if(path == 0){
  1733.         cwFputs("No entry found for ", (LPSTR)-1);
  1734.         cwFputs(cmdname, (LPSTR)-1);
  1735.         cwFputs("\n", (LPSTR)-1);
  1736.         return 1;
  1737.     }
  1738.  
  1739.     {
  1740.         FILE *fp;
  1741.         int line;
  1742.  
  1743.         fp = fopen(path, "r");
  1744.         for (line = 1; fgets(buf, 0xFF, fp) != NULL; line++) {
  1745.             buf[0xFF] = '\0';
  1746.             cwFputs(buf, NULL);
  1747.             if (line % 24 == 0) {
  1748.                 cwFputs("-- More --", (LPSTR)-1);
  1749.                 cwGetch();
  1750.                 cwFputs("\n", (LPSTR)-1);
  1751.             }
  1752.         }
  1753.         fclose(fp);
  1754.     }
  1755.     return 0;
  1756. }
  1757.  
  1758. int man_main(int argc, char **argv)
  1759. {
  1760.     if(argc < 2){
  1761.         cwFputs("man COMMANDNAME\n", (LPSTR)-1);
  1762.         return 1;
  1763.     }
  1764.     return man(argv[1]);
  1765. }
  1766.  
  1767. /*-----------*/
  1768. /* head_main */
  1769. /*-----------*/
  1770.  /* head.c  tailがあるのにheadがないのは淋しいので。
  1771.  
  1772.     Usage: head [-行数] [files...]
  1773.       ファイルの指定を '-' とすると標準入力を読みます。
  1774.  */
  1775.  
  1776. int head_main(int ac, char **av)
  1777. {
  1778.     int lines = 10;
  1779.  
  1780.     ac--, av++;
  1781.     if(ac && av[0][0] == '-' && av[0][1] != '\0'){
  1782.         lines = atoi(*av + 1);
  1783.         if(lines <= 0){
  1784.             cwFputs("Usage: head [-lines] [files...]\n", (LPSTR)-1);
  1785.             return 1;
  1786.         }
  1787.         ac--, av++;
  1788.     }
  1789.  
  1790.     switch(ac){
  1791.     case 0:
  1792.         fhead(NULL, lines);
  1793.         break;
  1794.     case 1:
  1795.         head(*av, lines, 0);
  1796.         break;
  1797.     default:
  1798.         for(; ac; ac--, av++) head(*av, lines, 1);
  1799.         break;
  1800.     }
  1801.     return 0;
  1802. }
  1803.  
  1804. void fhead(FILE *f, int lines)
  1805. {
  1806.     char buf[0x100];
  1807.     int i;
  1808.  
  1809.     for (i = 0; i < lines; i++) {
  1810.         if (f == NULL) {
  1811.             if (cwFgets(buf, 0xFF, NULL) == NULL) break;
  1812.         } else {
  1813.             if (fgets(buf, 0xFF, f) == NULL) break;
  1814.         }
  1815.         buf[0xFF] = '\0';
  1816.         cwFputs(buf, NULL);
  1817.     }
  1818. }
  1819.  
  1820. int head(char *fnm, int lines, int disphead)
  1821. {
  1822.     FILE *f;
  1823.  
  1824.     if(fnm[0] == '-' && !fnm[1]){
  1825.         if(disphead) cwFputs("\n==> stdin <==\n", NULL);
  1826.         fhead(NULL, lines);
  1827.     } else {
  1828.         name_unixnize(fnm);
  1829.         if(disphead){
  1830.             cwFputs("\n==> ", NULL), cwFputs(fnm, NULL),
  1831.             cwFputs(" <==\n", NULL);
  1832.         }
  1833.         if(NULL == (f = fopen(fnm, "r"))){
  1834.             cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
  1835.             return 1;
  1836.         }
  1837.         fhead(f, lines);
  1838.         fclose(f);
  1839.     }
  1840.     return 0;
  1841. }
  1842.  
  1843. /*------------*/
  1844. /* chdir_main */
  1845. /*------------*/
  1846. /*
  1847.  * chd: Change directory.
  1848.  * 
  1849.  * Yasushi Saito (yasushi@is.s.u-tokyo.ac.jp)
  1850.  */
  1851.  
  1852.  
  1853. void _dos_setdrive(unsigned drive, unsigned *numdrives)
  1854. {
  1855.     char szBuf[0x10];
  1856.  
  1857.     *numdrives = 26;
  1858.     _snprintf(szBuf, sizeof(szBuf), "%c:", drive + 'A' - 1);
  1859.     SetCurrentDirectory(szBuf);
  1860. }
  1861.  
  1862. int change_directory(char *s)
  1863. {
  1864.     unsigned dd;
  1865.  
  1866.     regularize_pathname(s);
  1867.     if(isalpha(*s) && s[1] == ':'){
  1868.         if(gg.current_drive != GET_DRIVE(*s)){ /* Changed Nide */
  1869.             _dos_setdrive((gg.current_drive = GET_DRIVE(*s)), &dd);
  1870.             if(getcurdrv() + 1 != gg.current_drive){
  1871.             cwFputs("chd: can't change drive\n", (LPSTR)-1);
  1872.                 return -1;
  1873.             }
  1874.         }
  1875.         s += 2;
  1876.         if(*s == '\0') return 0;
  1877.     }
  1878.     return chdir(s);
  1879. }
  1880.  
  1881. int chdir_main(int argc, char **argv)
  1882. {
  1883.     char *cdpath, *pathp, pathname[BUFSIZ];
  1884.     int dd;
  1885.  
  1886.     conv_char_args(argv, '/', '\\');
  1887.  
  1888.     getcwd(pathname, BUFSIZ);
  1889.     gg.old_drive = gg.current_drive = GET_DRIVE(*pathname);
  1890.  
  1891.     if(argc > 2){    /* Too many arguments */
  1892.         cwFputs("chd: directory ambiguous\n", (LPSTR)-1);
  1893.         /* Nide, 非ANSIコンパイラの便のために変更した */
  1894.         return 2;
  1895.     } else if(argc == 1){ /* No arguments */
  1896.         char   *home;
  1897.  
  1898.         if(NULL == (home = getenv("HOME"))){
  1899.             cwPuts(conv_to_unix_format(pathname));
  1900.             goto OK;
  1901.         } else if(0 == change_directory(home)){
  1902.             goto OK;
  1903.         } else {
  1904.             goto L_ERROR;
  1905.         }
  1906.     }
  1907.  
  1908.     if(0 == change_directory(argv[1]))
  1909.         goto OK;
  1910.  
  1911.     /* Check if string contains path separator */
  1912.     if(argv[1][0] == '.' || argv[1][0] == PD ||
  1913.         isalpha(argv[1][0]) && argv[1][1] == ':')
  1914.         goto L_ERROR;
  1915.  
  1916.     if((cdpath = getenv("CDPATH")) == NULL)
  1917.         goto L_ERROR;
  1918.  
  1919.     while(*cdpath){
  1920.         pathp = pathname;
  1921.         while(*cdpath && *cdpath != ';') *pathp++ = *cdpath++;
  1922.         if(*cdpath == ';') cdpath++;
  1923.         *pathp = 0;
  1924.         if(*pathname == PD && !pathname[1] ||
  1925.                 isalpha(*pathname) && pathname[1] == ':' &&
  1926.                 pathname[2] == PD && !pathname[3]){
  1927.             /* nothing */
  1928.         } else {
  1929.             *pathp++ = PD;
  1930.         } /* あとでregularize_pathname()する */
  1931.         strcpy(pathp, argv[1]);
  1932.         if(0 == change_directory(pathname)){
  1933.             cwPuts(s_conv_to_unix_format(pathname));
  1934.             goto OK;
  1935.         }
  1936.     }
  1937.  
  1938. L_ERROR:
  1939.     cwFputs("chd: no such directory\n", (LPSTR)-1);
  1940.     /* Nide, 非ANSIコンパイラの便のために変更した */
  1941.     if(gg.old_drive != gg.current_drive)
  1942.         _dos_setdrive(gg.old_drive, &dd);
  1943.     return 1;
  1944. OK:
  1945.     return 0;
  1946. }
  1947.  
  1948. /*-------------*/
  1949. /* expand_main */
  1950. /*-------------*/
  1951.  
  1952. int expand_usage(void)
  1953. {
  1954.     cwFputs("Usage: expand [-nsk] [-tablist] [file...]\n", (LPSTR)-1);
  1955.     return 1;
  1956. }
  1957.  
  1958. int do_opt(char *opt)
  1959. {
  1960.     int tabidx = 0, prevcol = 0;
  1961.  
  1962.     for(;;){
  1963.         if(tabidx == COLLISTMAX - 1){
  1964.             cwFputs("Tabstop list too long\n", (LPSTR)-1);
  1965.             return 1;
  1966.         }
  1967.         gg.tabcols[tabidx] = atoi(opt);
  1968.         if(prevcol >= gg.tabcols[tabidx]){
  1969.             cwFputs("Bad tab stop spec\n", (LPSTR)-1);
  1970.             return 1;
  1971.         } else {
  1972.             prevcol = gg.tabcols[tabidx++];
  1973.         }
  1974.         while(is_digit(*opt)) opt++;
  1975.         if(!*opt) break;
  1976.         if(*opt++ != ',') {
  1977.             expand_usage();
  1978.             return 1;
  1979.         }
  1980.     }
  1981.     gg.tabcols[tabidx] = 0;
  1982.     gg.tabcol = (gg.tabcols[1] ? 0 : gg.tabcols[0]);
  1983.     return 0;
  1984. }
  1985.  
  1986. int expand_main(int ac, char **av)
  1987. {
  1988.     FILE *inf;
  1989.     int pos;
  1990.  
  1991.     ac--, av++;
  1992.     while(ac && av[0][0] == '-' && av[0][1]){
  1993.         char *p;
  1994.  
  1995.         for(p = *av + 1; *p && !is_digit(*p); p++){
  1996.             switch(*p){
  1997.                 case 's':
  1998.                 gg.addsp = 1; break;
  1999.             case 'k':
  2000.                 gg.kspc = 1; break;
  2001.             case 'n':
  2002.                 gg.eofnl = 1; break;
  2003.             default:
  2004.                 return expand_usage();
  2005.             }
  2006.         }
  2007.         if(*p) {
  2008.             if (do_opt(p) != 0) {
  2009.                 return 1;
  2010.             }
  2011.         }
  2012.         ac--, av++;
  2013.     }
  2014.     if(!ac){
  2015.         pos = expand(NULL);
  2016.     } else {
  2017.         for(; ac; ac--, av++){
  2018.             if(av[0][0] == '-' && !av[0][1]){
  2019.                 pos = expand(NULL);
  2020.             } else {
  2021.                 if(NULL == (inf = fopen(*av, "r"))){
  2022.                     cwFputs(s_conv_to_unix_format(*av), (LPSTR)-1);
  2023.                     cwFputs(": Can't open\n", (LPSTR)-1);
  2024.                     return 1;
  2025.                 }
  2026.                 pos = expand(inf);
  2027.                 fclose(inf);
  2028.             }
  2029.         }
  2030.     }
  2031.     if(pos && gg.eofnl) cwFputs("\n", NULL);
  2032.     return 0;
  2033. }
  2034.  
  2035. int expand(FILE *f) /* returns last pos */
  2036. {
  2037.     int pos = 0, c, d, tabidx = 0;
  2038.     char bufi[0x100];
  2039.     char bufo[0x1000];
  2040.     char *pi;
  2041.     char *po;
  2042.  
  2043.     while (TRUE) {
  2044.         if (f == NULL) {
  2045.             if (cwFgets(bufi, 0xFF, NULL) == NULL) break;
  2046.         } else {
  2047.             if (fgets(bufi, 0xFF, f) == NULL) break;
  2048.         }
  2049.         bufi[0xFF] = '\0';
  2050.         po = bufo;
  2051.         for (pi = bufi; *pi != '\0'; pi++) {
  2052.             c = *pi;
  2053.             if(iskanji(c)){
  2054.                 if('\0' == (d = *(++pi))){
  2055.                     *po++ = c;
  2056.                     ++pos;
  2057.                     pi--;
  2058.                     continue;
  2059.                 }
  2060.                 if(gg.kspc && ((c << 8) | d) == KSPC){
  2061.                     *po++ = ' '; *po++ = ' ';
  2062.                 } else {
  2063.                     *po++ = c; *po++ = d;
  2064.                 }
  2065.                 pos += 2;
  2066.             } else if(c == '\b'){
  2067.                 *po++ = c;
  2068.                 pos--;
  2069.                 if(tabidx) tabidx--; /* 最高1つ戻せばよい */
  2070.             } else if(c == '\n' || c == '\r' || c == '\f'){
  2071.                 if(!pos && gg.addsp) {
  2072.                     *po++ = ' ';
  2073.                 }
  2074.                 *po++ = c;
  2075.                 pos = tabidx = 0;
  2076.             } else if(c == '\t'){
  2077.                 int newpos;
  2078.  
  2079.                 if(gg.tabcol){
  2080.                     newpos = (pos / gg.tabcol + 1) * gg.tabcol;
  2081.                 } else {
  2082.                     for(;; tabidx++){
  2083.                         newpos = gg.tabcols[tabidx];
  2084.                         if(!newpos || pos < newpos) break;
  2085.                     }
  2086.                     if(!newpos) newpos = pos + 1;
  2087.                 }
  2088.                 for(; pos < newpos; pos++) *po++ = ' ';
  2089.             } else {
  2090.                 *po++ = c;
  2091.                 pos++;
  2092.             }
  2093.         }
  2094.         *po = '\0';
  2095.         cwFputs(bufo, NULL);
  2096.     }
  2097.     return pos;
  2098. }
  2099.  
  2100. /*-----------*/
  2101. /* uniq_main */
  2102. /*-----------*/
  2103.  
  2104. int uniq_usage(void)
  2105. {
  2106.     cwFputs("Usage: uniq [-cdu] [{+|-}n] [file]\n", (LPSTR)-1);
  2107.     return 1;
  2108. }
  2109.  
  2110. int uniq_main(int ac, char **av)
  2111. {
  2112.     char *p;
  2113.     int optend;
  2114.     char udopt = 0;
  2115.  
  2116.     for(optend = 0; av++, --ac; ){
  2117.         switch(p = *av, *p++){
  2118.         case '+':
  2119.             if(!*p) return uniq_usage();
  2120.             gg.ignc = atoi(p);
  2121.             break;
  2122.         case '-':
  2123.             if(!*p){optend++; break;}
  2124.             if(isdigit(*p)){
  2125.                 gg.ignf = atoi(p);
  2126.                 break;
  2127.             }
  2128.             for(; *p; p++){
  2129.                 switch(*p){
  2130.                 case 'c':
  2131.                     gg.outlcnt = 1; break;
  2132.                 case 'd':
  2133.                     gg.outdup = udopt = 1; break;
  2134.                 case 'u':
  2135.                     gg.outndup = udopt = 1; break;
  2136.                 default:
  2137.                     return uniq_usage();
  2138.                 }
  2139.             }
  2140.             break;
  2141.         default:
  2142.             optend++; break;
  2143.         }
  2144.         if(optend) break;
  2145.     }
  2146.     if(!udopt) gg.outdup = gg.outndup = 1;
  2147.  
  2148.     return uniq(ac, av);
  2149. }
  2150.  
  2151. int uniq(int ac, char **av)
  2152. {
  2153.     FILE *f = NULL;
  2154.     int i, dupcnt = 0, len;
  2155.     char *bufcur, *cmpcur, *bufprv = NULL, *cmpprv = NULL;
  2156.     char *fnm, sw = 0, linbuf[2][LINMAX];
  2157.     int ret = 0;
  2158.  
  2159.     if(ac > 1) {
  2160.         uniq_usage();
  2161.         ret = 1;
  2162.         goto EXIT;
  2163.     }
  2164.     if(!ac || **av == '-' && !av[0][1]){
  2165.         f = NULL, fnm = "(stdin)";
  2166.     } else if(NULL == (f = fopen(fnm = conv_to_unix_format(*av), "r"))){
  2167.         cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
  2168.         ret = 1;
  2169.         goto EXIT;
  2170.     }
  2171.  
  2172.     while(((f == NULL) ? cwFgets(bufcur = linbuf[sw], LINMAX, NULL) :
  2173.                          fgets(bufcur = linbuf[sw], LINMAX, f)) != NULL) {
  2174.         if(!bufcur[0]){
  2175.             ; /* nothing */
  2176.         } else if(bufcur[(len = strlen(bufcur)) - 1] != '\n'){
  2177.             cwFputs(fnm, (LPSTR)-1);
  2178.             if(len == LINMAX - 1){
  2179.                 cwFputs(": line too long\n", (LPSTR)-1);
  2180.                 ret = 1;
  2181.                 goto EXIT;
  2182.             } else {
  2183.                 cwFputs(": missing line-feed character "
  2184.                       "added at EOF\n", (LPSTR)-1);
  2185.             }
  2186.         } else {
  2187.             bufcur[len - 1] = '\0';
  2188.         }
  2189.  
  2190.         cmpcur = bufcur;
  2191.         for(i = gg.ignf; i--;){
  2192.             while(is_space(*cmpcur)) cmpcur++;
  2193.             while(!is_space(*cmpcur)){
  2194.                 if(!*cmpcur) goto contin;
  2195.                 cmpcur++;
  2196.             }
  2197.         }
  2198. contin:
  2199.         for(i = gg.ignc; i--;){
  2200.             if(!*cmpcur) break;
  2201.             cmpcur++;
  2202.         }
  2203.  
  2204.         if(cmpprv == NULL || strcmp(cmpprv, cmpcur)){
  2205.             out(bufprv, dupcnt);
  2206.             dupcnt = 1;
  2207.             sw ^= 1, cmpprv = cmpcur, bufprv = bufcur;
  2208.         } else {
  2209.             dupcnt++;
  2210.         }
  2211.     }
  2212.     out(bufprv, dupcnt);
  2213. EXIT:
  2214.     if (f != NULL) fclose(f);
  2215.     return ret;
  2216. }
  2217.  
  2218. void intout(int w, unsigned int n)
  2219. {
  2220.     int num, col;
  2221.     char *buf;
  2222.  
  2223.     buf = malloc(w + 1);
  2224.     if (buf == NULL) {
  2225.         return;
  2226.     }
  2227.     memset(buf, ' ', w);
  2228.     buf[w] = '\0';
  2229.     num = n / 10;
  2230.     for (col = 1; num > 0; col++, num /= 10);
  2231.     if (col > w) col = w;
  2232.     _snprintf(buf + w - col, 10, "%d", n);
  2233.     cwFputs(buf, NULL);
  2234.     free(buf);
  2235. }
  2236.  
  2237. void out(char *buf, int cnt)
  2238. {
  2239.     if(buf != NULL && (cnt == 1 ? gg.outndup : gg.outdup)){
  2240.         if(gg.outlcnt) (intout(4, cnt), cwFputs(" ", NULL));
  2241.         /* instead of printf("%4d ", cnt); */
  2242.         cwPuts(buf);
  2243.     }
  2244. }
  2245.  
  2246. /*---------*/
  2247. /* df_main */
  2248. /*---------*/
  2249.  
  2250. int df_usage(void)
  2251. {
  2252.     cwFputs("Usage: df [-B]\n", (LPSTR)-1);
  2253.     return 1;
  2254. }
  2255.  
  2256. int df_main(int ac, char **av)
  2257. {
  2258.     switch(av++, --ac){
  2259.     case 0:
  2260.         break;
  2261.     case 1:
  2262.         if(!strcmp(*av, "-B")){ac--, av++, gg.availunit = 1; break;}
  2263.     default:
  2264.         return df_usage();
  2265.     }
  2266.     df();
  2267.     return 0;
  2268. }
  2269.  
  2270. void df(void)
  2271. {
  2272.     char szLogDrives[0x100];
  2273.     char szOut[0x100];
  2274.     LPSTR lpLog;
  2275.     DWORD dwSectorsPerCluster;
  2276.     DWORD dwBytesPerSector;
  2277.     DWORD dwFreeClusters;
  2278.     DWORD dwClusters;
  2279.     DWORD dwTotal;
  2280.     DWORD dwUsed;
  2281.     DWORD dwAvail;
  2282.     DWORD dwCap;
  2283.     DWORD dwBytesPerCluster;
  2284.     UINT  uErrorOrg;
  2285.  
  2286.     _snprintf(szOut, sizeof(szOut), "lastdrive: %c", 'z');
  2287.     cwFputs(szOut, NULL);
  2288.     _snprintf(szOut, sizeof(szOut),
  2289.               (gg.availunit == 1) ? "%25savail" : (LPSTR)"", (LPSTR)"");
  2290.     cwFputs(szOut, NULL);
  2291.     _snprintf(szOut, sizeof(szOut),
  2292.     /*  a:/usr/local    0123456 0123456 01-9 --100%-- 0123456  c:\ */
  2293.      "\nFilesystem       Kbytes    used   %s capacity Cluster  Mounted on\n",
  2294.              (gg.availunit == 1) ? " (bytes)" : "avail");
  2295.     cwFputs(szOut, NULL);
  2296.  
  2297.     GetLogicalDriveStrings(0x100, szLogDrives);
  2298.     uErrorOrg = SetErrorMode(SEM_FAILCRITICALERRORS);
  2299.     for (lpLog = szLogDrives; *lpLog != '\0'; lpLog += lstrlen(lpLog) + 1) {
  2300.         if (GetDiskFreeSpace(lpLog,
  2301.                              &dwSectorsPerCluster,
  2302.                              &dwBytesPerSector,
  2303.                              &dwFreeClusters,
  2304.                              &dwClusters) == FALSE) {
  2305.             continue;
  2306.         }
  2307.         dwBytesPerCluster = dwSectorsPerCluster * dwBytesPerSector;
  2308.         dwTotal           = dwClusters     * dwBytesPerCluster / 1024;
  2309.         dwAvail           = dwFreeClusters * dwBytesPerCluster / 1024;
  2310.         dwUsed            = dwTotal - dwAvail;
  2311.         dwCap             = dwUsed / (dwTotal / 100);
  2312.         dwAvail          *= 1024 / gg.availunit;
  2313.  
  2314.         _snprintf(szOut, sizeof(szOut), fmt,
  2315.                 (LPSTR)conv_to_unix_format(lpLog),
  2316.                 dwTotal,
  2317.                 dwUsed,
  2318.                 (gg.availunit == 1) ? 10 : 7,
  2319.                 dwAvail,
  2320.                 dwCap,
  2321.                 dwBytesPerCluster,
  2322.                 (LPSTR)lpLog);
  2323.         cwFputs(szOut, NULL);
  2324.     }
  2325.     SetErrorMode(uErrorOrg);
  2326. }
  2327.  
  2328. /*---------*/
  2329. /* tr_main */
  2330. /*---------*/
  2331.  
  2332. /* tr [-cds] [string1 [string2]], no wildcards */
  2333.  
  2334. int tr_usage(void)
  2335. {
  2336.     cwFputs("Usage: tr [-cdsIOz] [string1 [string2]]\n", (LPSTR)-1);
  2337.     return 1;
  2338. }
  2339.  
  2340. int tr_main(int ac, char **av)
  2341. {
  2342.     if(av++, --ac && **av == '-'){
  2343.         char *p;
  2344.  
  2345.         for(p = *av + 1; *p; p++){
  2346.             switch(*p){
  2347.             case 'c': gg.cmplmnt = 1; break;
  2348.             case 'd': gg.delete = 1; break;
  2349.             case 's': gg.supdup = 1; break;
  2350.             case 'I': gg.ibinary = 1; break;
  2351.             case 'O': gg.obinary = 1; break;
  2352.             case 'z': gg.treatz = 1; break;
  2353.             default: return tr_usage();
  2354.             }
  2355.         }
  2356.         ac--, av++;
  2357.     }
  2358.     if(ac > 2) return tr_usage();
  2359.     trmain(ac ? av[0] : strnul, ac > 1 ? av[1] : strnul);
  2360.     return 0; /* exit from main() */
  2361. }
  2362.  
  2363.  
  2364. void init_argchar(struct argchar *p, uchar *s)
  2365. {
  2366.     p -> count = 0;
  2367.     p -> arg = s;
  2368. }
  2369.  
  2370. int get1char(uchar **pp)
  2371. {
  2372.     uchar *p;
  2373.     int c;
  2374.  
  2375.     c = *(p = *pp);
  2376.     if(!c) return EOF;
  2377.  
  2378.     if(c != '\\') {
  2379.         (*pp)++;
  2380.     } else if(c = *++p, isoctal(c)){
  2381.         int i = 3;
  2382.  
  2383.         c -= '0';
  2384.         while(p++, --i && isoctal(*p)){
  2385.             c <<= 3, c |= *p - '0';
  2386.         }
  2387.         *pp = p;
  2388.     } else {
  2389.         switch(c){
  2390.         case 'n': c = '\n'; break;
  2391.         case 't': c = '\t'; break;
  2392.         case 'b': c = '\b'; break;
  2393.         case 'r': c = '\r'; break;
  2394.         case 'f': c = '\f'; break;
  2395.         case 'v': c = 0xb; break;
  2396.         case 'a': c = 0x7; break;
  2397.         case 'e': c = '\033'; break;
  2398.         }
  2399.         *pp = ++p;
  2400.     }
  2401.     return c;
  2402. }
  2403.  
  2404. int getargchar(struct argchar *p)
  2405. {
  2406.     int i, j;
  2407.     uchar *s;
  2408.  
  2409.     if(p -> count){
  2410.         p -> count--; /* -1であっても -- しないと… */
  2411.         i = p -> next;
  2412.         p -> next += p -> step;
  2413.         return i;
  2414.     }
  2415.     i = *(s = p -> arg);
  2416.     if(!i) return EOF;
  2417.  
  2418.     if(i != '['){
  2419.         i = get1char(&s);
  2420.     } else { /* non-escaped '[' */
  2421.         s++;
  2422.         if(EOF == (i = get1char(&s))) goto Bad;
  2423.         switch(*s++){
  2424.         case '-':
  2425.             if(EOF == (j = get1char(&s))) goto Bad;
  2426.             if(0 < (j -= i)){
  2427.                 p -> step = 1, p -> count = j;
  2428.             } else {
  2429.                 p -> step = -1, p -> count = -j;
  2430.             }
  2431.             p -> next = i + p -> step;
  2432.             break;
  2433.         case '*':
  2434.             j = 0;
  2435.             if(*s == '0'){
  2436.                 while(isoctal(*s)) (j <<= 3, j |= *s++ - '0');
  2437.             } else {
  2438.                 while(isdigit(*s)) (j *= 10, j += *s++ - '0');
  2439.             } /* numが略された場合もこれでOK */
  2440.             p -> count = --j; /* 0なら(uint)(-1)==Hugeになる */
  2441.             p -> step = 0, p -> next = i;
  2442.             break;
  2443.         default:
  2444.             goto Bad;
  2445.         }
  2446.         if(*s++ != ']'){
  2447.         Bad:
  2448.             cwFputs("Bad string\n", (LPSTR)-1);
  2449.             return EOF;
  2450.         }
  2451.     }
  2452.  
  2453.     p -> arg = s;
  2454.     return i;
  2455. }
  2456.  
  2457. int getargchar_nodup(struct argchar *p)
  2458. {
  2459.     int i;
  2460.  
  2461.     i = getargchar(p);
  2462.     if(!p -> step) p -> count = 0;
  2463.     return i;
  2464. }
  2465.  
  2466. void getargcharpair(struct argchar *p1, int *ip,
  2467.                     struct argchar *p2, int *jp)
  2468. {
  2469.     *ip = getargchar(p1);
  2470.     *jp = getargchar(p2);
  2471.     if(!p1 -> step && !p2 -> step){
  2472.         p1 -> count > p2 -> count ?
  2473.             (p1 -> count -= p2 -> count) :
  2474.             (p2 -> count -= p1 -> count);
  2475.     }
  2476. }
  2477.  
  2478. void trmain(uchar *from, uchar *to)
  2479. {
  2480.     struct argchar fromstr, tostr;
  2481.     int i, j;
  2482.  
  2483.     if(!gg.cmplmnt){
  2484.         for(i = 0; i < 0x100; i++) (gg.cnvtbl[i] = i, gg.duptbl[i] = 0);
  2485.         if(!gg.treatz) gg.cnvtbl[0] = EOF;
  2486.         init_argchar(&fromstr, from);
  2487.         if(!gg.delete){
  2488.             init_argchar(&tostr, to);
  2489.             while(getargcharpair(&fromstr, &i, &tostr, &j),
  2490.                   EOF != i && (gg.treatz || i) &&
  2491.                   EOF != j && (gg.treatz || j)){
  2492.                 gg.cnvtbl[i] = j;
  2493.             }
  2494.             while(EOF != i && (gg.treatz || i)){
  2495.                 gg.cnvtbl[i] = i;
  2496.                 i = getargchar_nodup(&fromstr);
  2497.             }
  2498.         } else {
  2499.             while(EOF != (i = getargchar_nodup(&fromstr)) &&
  2500.                     (gg.treatz || i)){
  2501.                 gg.cnvtbl[i] = EOF;
  2502.             }
  2503.         }
  2504.     } else { /* complement */
  2505.         for(i = 0; i < 0x100; i++) (gg.cnvtbl[i] = EOF, gg.duptbl[i] = 0);
  2506.         init_argchar(&fromstr, from);
  2507.         while(EOF != (i = getargchar_nodup(&fromstr)) &&
  2508.                  (gg.treatz || i)){
  2509.             gg.cnvtbl[i] = i;
  2510.         }
  2511.         if(!gg.delete){
  2512.             init_argchar(&tostr, to), i = (gg.treatz ? 0 : 1);
  2513.             while(EOF != (j = getargchar(&tostr)) &&
  2514.                     (gg.treatz || j)){
  2515.                 while(gg.cnvtbl[i] != EOF){
  2516.                     if(++i >= 0x100) goto nomorecnv;
  2517.                 }
  2518.                 gg.cnvtbl[i] = j;
  2519.             }
  2520.             for(; i < 0x100; i++){
  2521.                 if(gg.cnvtbl[i] == EOF) gg.cnvtbl[i] = i;
  2522.             }
  2523.         }
  2524.     }
  2525. nomorecnv:
  2526.     init_argchar(&tostr, to);
  2527.     while(EOF != (j = getargchar_nodup(&tostr)) && (gg.treatz || j)){
  2528.         gg.duptbl[j] = 1;
  2529.     }
  2530.  
  2531.     {
  2532.         char bufi[0x2000];
  2533.         char bufo[0x2000];
  2534.         char *pi;
  2535.         char *po;
  2536.  
  2537.         j = EOF;
  2538.         while (cwFgets(bufi, 0x1FFF, NULL) != NULL) {
  2539.             bufi[0x1FFF] = '\0';
  2540.             po = bufo;
  2541.             for (pi = bufi; *pi != '\0'; pi++) {
  2542.                 i = *pi;
  2543.                 if (EOF != (i = gg.cnvtbl[i])) {
  2544.                     if (gg.supdup && gg.duptbl[i] && j== i) {
  2545.                         continue;
  2546.                     }
  2547.                     *po++ = i;
  2548.                     j = i;
  2549.                 }
  2550.             }
  2551.             *po = '\0';
  2552.             cwFputs(bufo, NULL);
  2553.         }
  2554.     }
  2555. }
  2556.  
  2557. /*-------*/
  2558. /* wc_main */
  2559. /*-------*/
  2560. /* wc [-lwc] [files...] */
  2561.  
  2562.  
  2563. int wc_main(int ac, char **av)
  2564. {
  2565. //  extern int optind, opterr;
  2566.     int c, errstat = 0;
  2567.  
  2568.     gg.opterr = 0;
  2569.  
  2570.     while(EOF != (c = getopt(ac, av, "lwc"))){
  2571.         switch(c){
  2572.         case 'l':
  2573.             gg.print_line = 1; break;
  2574.         case 'w':
  2575.             gg.print_word = 1; break;
  2576.         case 'c':
  2577.             gg.print_char = 1; break;
  2578.         default:
  2579.             return wc_usage();
  2580.         }
  2581.     }
  2582.     ac -= gg.optind, av += gg.optind;
  2583.     if(!gg.print_line && !gg.print_word && !gg.print_char)
  2584.         gg.print_line = gg.print_word = gg.print_char = 1;
  2585.  
  2586.     switch(ac){
  2587.     case 0:
  2588.         return wc(NULL, 0);
  2589.     case 1:
  2590.         return wc(*av, 0);
  2591.     default:
  2592.         for(; ac; ac--, av++) errstat |= wc(*av, 1);
  2593.         wcout(gg.print_line, gg.total_l);
  2594.         wcout(gg.print_word, gg.total_w);
  2595.         wcout(gg.print_char, gg.total_c);
  2596.          /* instead of printf("%7ld ", ...) */
  2597.         cwPuts("total");
  2598.         return errstat;
  2599.     }
  2600. }
  2601.  
  2602.  /* open不能の場合は1 正常終了なら0返す */
  2603. int wc(char *fnm, int nmdisp)
  2604. {
  2605.     int fd;
  2606.  
  2607.     if(fnm == NULL || !strcmp("-", fnm)){
  2608.         fnm = NULL;
  2609.         wcmain(-1);
  2610.     } else {
  2611.         if(-1 == (fd = open(fnm, O_RDONLY | O_BINARY))){
  2612.             cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
  2613.             return 1;
  2614.         }
  2615.         wcmain(fd);
  2616.         close(fd);
  2617.     }
  2618.     if(nmdisp) cwFputs(fnm == NULL ?
  2619.         "(stdin)" : s_conv_to_unix_format(fnm), NULL);
  2620.     cwFputs("\n", NULL);
  2621.     return 0;
  2622. }
  2623.  
  2624. void wcmain(int fd)
  2625. {
  2626.     long file_l = 0L, file_w = 0L, file_c = 0L;
  2627.     register unsigned char *p;
  2628.     register unsigned int n;
  2629.     int word_cont = 0;
  2630.  
  2631.     while(TRUE) {
  2632.         if (fd == -1) {
  2633.             if (cwFgets(gg.s_readbuf, sizeof(gg.s_readbuf) - 1, NULL) == NULL)
  2634.                 break;
  2635.             n = lstrlen(gg.s_readbuf);
  2636.         } else {
  2637.             if ((n = read(fd, gg.s_readbuf, RBUFSIZ)) <= 0) break;
  2638.         }
  2639.         file_c += (long)n;
  2640.         for(p = gg.s_readbuf; n; n--, p++){
  2641.             if(*p == '\n') file_l++;
  2642.             if(!word_cont){
  2643.                 if(!is_space(*p)){
  2644.                     word_cont++;
  2645.                     file_w++;
  2646.                 }
  2647.             } else {
  2648.                 if(is_space(*p)) word_cont = 0;
  2649.             }
  2650.         }
  2651.     }
  2652.     wcout(gg.print_line, file_l);
  2653.     wcout(gg.print_word, file_w);
  2654.     wcout(gg.print_char, file_c);
  2655.     gg.total_l += file_l;
  2656.     gg.total_w += file_w;
  2657.     gg.total_c += file_c;
  2658. }
  2659.  
  2660. void wcout(int flg, unsigned long n)
  2661. {
  2662.     if (flg) {
  2663.         char buf[16];
  2664.         _snprintf(buf, sizeof(buf), "%8ld ", n);
  2665.         cwFputs(buf, NULL);
  2666.     }
  2667. }
  2668.  
  2669. int wc_usage(void)
  2670. {
  2671.     cwFputs("Usage: wc [-lwc] [files...]\n", (LPSTR)-1);
  2672.     return 1;
  2673. }
  2674.  
  2675. /*------------*/
  2676. /* which_main */
  2677. /*------------*/
  2678.  
  2679. char *convert(char *s)
  2680. {
  2681.     if(gg.msdos_format)
  2682.         return s;
  2683.     return s_conv_to_unix_format(s);
  2684. }
  2685.  
  2686. void print_found(char *string)
  2687. {
  2688.     cwFputs(convert(string), NULL);
  2689.     cwFputs("\n", NULL);
  2690.     gg.found = 1;
  2691. }
  2692.  
  2693. void which_expand(char *buf, char *path, char *file, char *ext)
  2694. {
  2695.     if(path[strlen(path) - 1] == '\\'){
  2696.         _snprintf(buf, 1024, "%s%s%s", path, file, ext);
  2697.     } else {
  2698.         _snprintf(buf, 1024, "%s\\%s%s", path, file, ext);
  2699.     }
  2700. }
  2701.  
  2702. int search_file(char *path, char *file)
  2703. {
  2704.     char buf[1024];
  2705.     int found_p = 0;
  2706.     if(strchr(file, '.')){
  2707.         /* FILE already had the extention. */
  2708.         which_expand(buf, path, file, "");
  2709.         if(!access(buf, 0)){
  2710.             print_found(buf);
  2711.             found_p = 1;
  2712.             if(!gg.display_all)
  2713.                 return 1;
  2714.         }
  2715.     } else {
  2716.         which_expand(buf, path, file, ".com");
  2717.         if(!access(buf, 0)){
  2718.             print_found(buf);
  2719.             found_p = 1;
  2720.             if(!gg.display_all)
  2721.                 return 1;
  2722.         }
  2723.         which_expand(buf, path, file, ".exe");
  2724.         if(!access(buf, 0)){
  2725.             print_found(buf);
  2726.             found_p = 1;
  2727.             if(!gg.display_all)
  2728.                 return 1;
  2729.         }
  2730.         which_expand(buf, path, file, ".bat");
  2731.         if(!access(buf, 0)){
  2732.             print_found(buf);
  2733.             found_p = 1;
  2734.             if(!gg.display_all)
  2735.                 return 1;
  2736.         }
  2737.     }
  2738.     return found_p;
  2739. }
  2740.  
  2741. void pathscan_start(char *path_variable)
  2742. {
  2743.     gg.path_scanned = path_variable;
  2744. }
  2745.  
  2746. char *pathscan(void)
  2747. {
  2748.     char   *pathend;
  2749.     if(gg.path_scanned == 0)
  2750.         return 0;
  2751.     pathend = strchr(gg.path_scanned, ';');
  2752.     if(pathend){
  2753.         strncpy(gg.s_buf2, gg.path_scanned, pathend - gg.path_scanned);
  2754.         gg.s_buf2[pathend - gg.path_scanned] = '\0';
  2755.     } else
  2756.         strcpy(gg.s_buf2, gg.path_scanned);
  2757.     if(pathend){
  2758.         gg.path_scanned = pathend + 1;
  2759.         if(*gg.path_scanned == '\0'){
  2760.             gg.path_scanned = 0;
  2761.         }
  2762.     } else
  2763.         gg.path_scanned = 0;
  2764.     return gg.s_buf2;
  2765. }
  2766.  
  2767. int which_usage(void)
  2768. {
  2769.     cwFputs("which [-am] commandname...\n", (LPSTR)-1);
  2770.     return 1;
  2771. }
  2772.  
  2773. void which_a_file(char *commandname, char*pathlist)
  2774. {
  2775.     int found = 0;
  2776.     if(search_file(".", commandname)){
  2777.         found = 1;
  2778.         if(!gg.display_all)
  2779.             return;
  2780.     }
  2781.     pathscan_start(pathlist);
  2782.     {
  2783.         char   *one_path;
  2784.         while(one_path = pathscan()){
  2785.             if(search_file(one_path, commandname)){
  2786.                 found = 1;
  2787.                 if(!gg.display_all)
  2788.                     return;
  2789.             }
  2790.         }
  2791.     }
  2792.     if(!found){
  2793.         char   *one_path;
  2794.         gg.error_code = 1;
  2795.         cwFputs(commandname, NULL); cwFputs(" not found in . ", NULL);
  2796.         pathscan_start(pathlist);
  2797.         while(one_path = pathscan()){
  2798.             cwFputs(convert(one_path), NULL);
  2799.             cwFputs(" ", NULL);
  2800.         }
  2801.         cwFputs("\n", NULL);
  2802.     }
  2803. }
  2804.  
  2805. int which_main(int argc, char **argv)
  2806. {
  2807.     char   *getenv(), *path;
  2808. //  extern int optind, opterr;
  2809.     int option;
  2810.     int errorcode = 0;
  2811.  
  2812.     gg.opterr = 0;
  2813.  
  2814.     path = getenv("PATH");
  2815.     if(path == 0){
  2816.         cwFputs("Variable PATH not set\n", (LPSTR)-1);
  2817.         return 1;
  2818.     }
  2819.     while((option = getopt(argc, argv, "am")) != EOF){
  2820.         switch (option){
  2821.         case 'a':
  2822.             gg.display_all = 1;
  2823.             break;
  2824.         case 'm':
  2825.             gg.msdos_format = 1;
  2826.             break;
  2827.         default:
  2828.             return which_usage();
  2829.         }
  2830.     }
  2831.     if(argc == gg.optind)
  2832.         return which_usage();
  2833.     while(gg.optind < argc){
  2834.         which_a_file(argv[gg.optind], path);
  2835.         gg.optind++;
  2836.     }
  2837.     return errorcode;
  2838. }
  2839.  
  2840. /*---------------*/
  2841. /* unexpand_main */
  2842. /*---------------*/
  2843.  
  2844. int charstockinit(struct charstock *p)
  2845. {
  2846.     if(NULL == (p->buf = malloc(p->bufsiz = 100))){
  2847.          _putnomemmes();
  2848.          MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
  2849. //       exit(1);
  2850.     }
  2851.      /* bufposを0にはしない */
  2852.     return 0;
  2853. }
  2854.  
  2855. int charstockend(struct charstock *p)
  2856. {
  2857.     if (p->buf != NULL) free(p->buf); p->buf = NULL;
  2858.     return 0;
  2859. }
  2860.  
  2861. void stockchar(char c, struct charstock *p) /* 失敗時非0 */
  2862. {
  2863.     unsigned int i;
  2864.  
  2865.     if((i = p -> bufpos) >= p -> bufsiz){
  2866.         if(NULL == (p -> buf = realloc(p -> buf, p -> bufsiz += 100))){
  2867.             _putnomemmes();
  2868.             MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
  2869. //          exit(1);
  2870.         }
  2871.     }
  2872.     p -> buf[i] = c;
  2873.     p -> bufpos = ++i;
  2874. }
  2875.  
  2876. int unexpand_usage(void)
  2877. {
  2878.     cwFputs("Usage: unexpand [-aks] [-tablist] [file...]\n", (LPSTR)-1);
  2879.     return 1;
  2880. }
  2881.  
  2882. int unexpand_do_opt(char *opt)
  2883. {
  2884.     int tabidx = 0, prevcol = 0;
  2885.  
  2886.     for(;;){
  2887.         if(tabidx == COLLISTMAX - 1){
  2888.             cwFputs("Tabstop list too long\n", (LPSTR)-1);
  2889.             return 1;
  2890.         }
  2891.         gg.tabcols[tabidx] = atoi(opt);
  2892.         if(prevcol >= gg.tabcols[tabidx]){
  2893.             cwFputs("Bad tab stop spec\n", (LPSTR)-1);
  2894.             return 1;
  2895.         } else {
  2896.             prevcol = gg.tabcols[tabidx++];
  2897.         }
  2898.         while(is_digit(*opt)) opt++;
  2899.         if(!*opt) break;
  2900.         if(*opt++ != ',') {
  2901.             unexpand_usage();
  2902.             return 1;
  2903.         }
  2904.     }
  2905.     gg.tabcols[tabidx] = 0;
  2906.     gg.tabcol = (gg.tabcols[1] ? 0 : gg.tabcols[0]);
  2907.     return 0;
  2908. }
  2909.  
  2910. int unexpand_main(int ac, char **av)
  2911. {
  2912.     FILE *inf;
  2913.  
  2914.     ac--, av++;
  2915.     while(ac && av[0][0] == '-' && av[0][1]){
  2916.         char *p;
  2917.  
  2918.         for(p = *av + 1; *p && !is_digit(*p); p++){
  2919.             switch(*p){
  2920.             case 'k':
  2921.                 gg.kspc = 1; break;
  2922.             case 's':
  2923.                 gg.elimsp = 1; break;
  2924.             case 'a':
  2925.                 gg.unexpall = 1; break;
  2926.             default:
  2927.                 return unexpand_usage();
  2928.             }
  2929.         }
  2930.         if(*p) {
  2931.             if (unexpand_do_opt(p) != 0) {
  2932.                 return 1;
  2933.             }
  2934.         }
  2935.         ac--, av++;
  2936.     }
  2937.     if(!ac){
  2938.         unexpand(NULL);
  2939.     } else {
  2940.         for(; ac; ac--, av++){
  2941.             if(av[0][0] == '-' && !av[0][1]){
  2942.                 unexpand(NULL);
  2943.             } else {
  2944.                 if(NULL == (inf = fopen(*av, "r"))){
  2945.                     cwFputs(s_conv_to_unix_format(*av),
  2946.                           (LPSTR)-1);
  2947.                     cwFputs(": Can't open\n", (LPSTR)-1);
  2948.                     return 1;
  2949.                 }
  2950.                 unexpand(inf);
  2951.                 fclose(inf);
  2952.             }
  2953.         }
  2954.     }
  2955.     return 0;
  2956. }
  2957.  
  2958. void outspc(struct spinfo *spdatp, char **ppo)
  2959. {
  2960.     char *p;
  2961.     int i, pos, tabpos, tabidx, origpos;
  2962.  
  2963.     stockchar('\0', &spdatp -> sptabseq);
  2964.     origpos = tabpos = pos = spdatp -> pos, tabidx = spdatp -> tabidx;
  2965.     p = spdatp -> sptabseq . buf;
  2966.     do{
  2967.         if(*p == ' '){
  2968.             pos++;
  2969.             if(!gg.unexpall && origpos){
  2970.                 *(*ppo)++ = ' ', tabpos++;
  2971.             }
  2972.             continue;
  2973.         }
  2974.  
  2975.          /* else *p must be '\t' or '\0' */
  2976.         if(gg.tabcol){
  2977.             while((i = (tabpos / gg.tabcol + 1) * gg.tabcol) <= pos){
  2978.                 *(*ppo)++ = (i - tabpos > 1) ? '\t' : ' ';
  2979.                 tabpos = i;
  2980.             }
  2981.  
  2982.             if(*p == '\t'){
  2983.                 pos = tabpos = (tabpos / gg.tabcol + 1) * gg.tabcol;
  2984.                 /* previously pos = (tabpos += tabcol); */
  2985.                 *(*ppo)++ = '\t';
  2986.             } else {
  2987.                 for(; tabpos < pos; tabpos++) *(*ppo)++ = ' ';
  2988.             }
  2989.         } else {
  2990.             while((i = gg.tabcols[tabidx]) > 0 && i <= tabpos)
  2991.                 tabidx++;
  2992.              /* now i == tabcols[tabidx] and tabcols[tabidx - 1] is
  2993.                 the maximum tabcol <= tabpos */
  2994.             if(i){
  2995.                 while((i = gg.tabcols[tabidx]) > 0 && i <= pos){
  2996.                     *(*ppo)++ = (i - tabpos > 1) ? '\t' : ' ';
  2997.                     tabpos = i;
  2998.                     tabidx++;
  2999.                 }
  3000.                  /* tabcols[tabidx - 1] is always kept
  3001.                     < current pos (if tabidx > 0) */
  3002.             }
  3003.  
  3004.             if(!i){
  3005.                 for(; tabpos < pos; tabpos++) *(*ppo)++ = ' ';
  3006.                 if(*p == '\t'){
  3007.                     *(*ppo)++ = '\t';
  3008.                     pos = ++tabpos;
  3009.                 }
  3010.             } else {
  3011.                 if(*p == '\t'){
  3012.                     *(*ppo)++ = '\t';
  3013.                     pos = tabpos = i;
  3014.                 } else {
  3015.                     for(; tabpos < pos; tabpos++)
  3016.                         *(*ppo)++ = '\t';
  3017.                 }
  3018.             }
  3019.         }
  3020.     } while(*p++);
  3021.     spdatp -> sptabseq . bufpos = 0;
  3022.     spdatp -> pos = pos, spdatp -> tabidx = tabidx;
  3023. }
  3024.  
  3025. void unexpand(FILE *f)
  3026. {
  3027.     int c, d;
  3028.     char bufi[0x100];
  3029.     char bufo[0x100];
  3030.     char *pi;
  3031.     char *po;
  3032.  
  3033.     if(gg.s_first){
  3034.         charstockinit(&gg.s_sppresv.sptabseq);
  3035.         gg.s_first = 0;
  3036.     } /* sptabseq . buf には ' ' か '\t' ばかりが入っていく */
  3037.     gg.s_sppresv.pos = gg.s_sppresv.tabidx = gg.s_sppresv.sptabseq.bufpos = 0;
  3038.  
  3039.     while (TRUE) {
  3040.         if (f == NULL) {
  3041.             if (cwFgets(bufi, 0xFF, NULL) == NULL) break;
  3042.         } else {
  3043.             if (fgets(bufi, 0xFF, f) == NULL) break;
  3044.         }
  3045.         bufi[0xFF] = '\0';
  3046.         po = bufo;
  3047.         for (pi = bufi; *pi != '\0'; pi++) {
  3048.             c = *pi;
  3049.             if(iskanji(c)){
  3050.                 if('\0' == (d = *(++pi))){
  3051.                     outspc(&gg.s_sppresv, &po);
  3052.                     *po++ = c;
  3053.                     pi--;
  3054.                     continue;
  3055.                 }
  3056.                 if(gg.kspc && ((c << 8) | d) == KSPC &&
  3057.                        (gg.unexpall || !gg.s_sppresv.pos)){
  3058.                     stockchar(' ', &gg.s_sppresv.sptabseq);
  3059.                     stockchar(' ', &gg.s_sppresv.sptabseq);
  3060.                 } else {
  3061.                     outspc(&gg.s_sppresv, &po);
  3062.                     *po++ = c; *po++ = d;
  3063.                     gg.s_sppresv.pos += 2;
  3064.                 }
  3065.             } else if(c == '\b'){
  3066.                 *po++ = c, gg.s_sppresv.pos--;
  3067.                 if(gg.s_sppresv.tabidx)
  3068.                     gg.s_sppresv.tabidx--; /* 最高1つ戻せばよい */
  3069.             } else if(c == '\n' || c == '\r' || c == '\f'){
  3070.                 if(!gg.elimsp) outspc(&gg.s_sppresv, &po);
  3071.                 *po++ = c;
  3072.                 gg.s_sppresv.pos = gg.s_sppresv.tabidx =
  3073.                     gg.s_sppresv.sptabseq.bufpos = 0;
  3074.             } else if(c == '\t' || c == ' '){
  3075.                 stockchar((char)c, &gg.s_sppresv . sptabseq);
  3076.             } else {
  3077.                 outspc(&gg.s_sppresv, &po);
  3078.                 *po++ = c, gg.s_sppresv.pos++;
  3079.             }
  3080.         }
  3081.         *po = '\0';
  3082.         cwFputs(bufo, NULL);
  3083.     }
  3084.  
  3085.     if(!gg.elimsp) outspc(&gg.s_sppresv, &po);
  3086.     charstockend(&gg.s_sppresv.sptabseq);
  3087. }
  3088.  
  3089. /*----------*/
  3090. /* cmp_main */
  3091. /*----------*/
  3092.  /* exit: 0=same, 1=diff, 2=error */
  3093.  
  3094. int cmp_usage(void)
  3095. {
  3096.     cwFputs("Usage: cmp [-ls] file1 file2\n", (LPSTR)-1);
  3097.     cwFputs("-l : report all differences\n", (LPSTR)-1);
  3098.     cwFputs("-s : return code only\n", (LPSTR)-1);
  3099.     return 2;
  3100. }
  3101.  
  3102. FILE *argfopen(char *s)
  3103. {
  3104.     register FILE   *f;
  3105.  
  3106.     if(*s == '-' && !s[1]){
  3107.         f = NULL;
  3108.     } else {
  3109.         if(NULL == (f = fopen(s, "rb"))){
  3110.             cwFputs(conv_to_unix_format(s), (LPSTR)-1);
  3111.             cwFputs(": Can't open\n", (LPSTR)-1);
  3112.             return NULL;
  3113.         }
  3114.     }
  3115.     return f;
  3116. }
  3117.  
  3118. #if 0
  3119. void    expand_control()
  3120. {
  3121.     _expand_abendcode = 2;
  3122. }
  3123. #endif
  3124.  
  3125. int cmp_main(int ac, char **av)
  3126. {
  3127. //  extern  int optind, opterr;
  3128.     int c;
  3129.     char    all = 0, silent = 0;
  3130.  
  3131.     gg.opterr = 0;
  3132.  
  3133.     while(EOF != (c = getopt(ac, av, "ls"))){
  3134.         switch(c){
  3135.         case 'l': all = 1; break;
  3136.         case 's': silent = 1; break;
  3137.         default:  return cmp_usage();
  3138.         }
  3139.     }
  3140.  
  3141.     ac -= gg.optind, av += gg.optind;
  3142.     if(ac != 2) return cmp_usage();
  3143.  
  3144.     if(silent) {
  3145.         return s_cmp(av[0], av[1]);
  3146.     } else if(all) {
  3147.         return a_cmp(av[0], av[1]);
  3148.     } else {
  3149.         return cmp(av[0], av[1]);
  3150.     }
  3151. }
  3152.  
  3153. int s_cmp(char *s, char *t)
  3154. {
  3155.     register FILE   *f = argfopen(s), *g = argfopen(t);
  3156.     register int c;
  3157.     int status;
  3158.  
  3159.     if (f == NULL || g == NULL) {
  3160.         status = 2;
  3161.         goto end;
  3162.     }
  3163.     status = 1;
  3164.     while(c = getc(f), c == getc(g)) {
  3165.         if(c == EOF) {
  3166.              status = 0;
  3167.              break;
  3168.         }
  3169.     }
  3170. end:
  3171.     if (f != NULL) fclose(f);
  3172.     if (g != NULL) fclose(g);
  3173.     return status;
  3174. }
  3175.  
  3176. int a_cmp(char *s, char *t)
  3177. {
  3178.     FILE    *f = argfopen(s), *g = argfopen(t);
  3179.     char    status = 0;
  3180.     long    pos = 0;
  3181.     register int    c, d;
  3182.     char    buf[0x100];
  3183.  
  3184.     if (f == NULL || g == NULL) {
  3185.         status = 2;
  3186.         goto end;
  3187.     }
  3188.  
  3189.     while(c = getc(f), d = getc(g), pos++, c != EOF && d != EOF){
  3190.         if(c == d) continue;
  3191.         status = 1;
  3192.         sprintf(buf, "%6ld %3o %3o\n", pos, c, d);
  3193.         cwFputs(buf, NULL);
  3194.     }
  3195.     if(d != EOF){
  3196.         sprintf(buf, eofmsg, s);
  3197.         cwFputs(buf, NULL);
  3198.         status = 1;
  3199.     } else if(c != EOF){
  3200.         sprintf(buf, eofmsg, t);
  3201.         cwFputs(buf, NULL);
  3202.         status = 1;
  3203.     }
  3204. end:
  3205.     if (f != NULL) fclose(f);
  3206.     if (g != NULL) fclose(g);
  3207.     return status;
  3208. }
  3209.  
  3210. int cmp(char *s, char *t)
  3211. {
  3212.     FILE    *f = argfopen(s), *g = argfopen(t);
  3213.     long    pos = 0, line = 1;
  3214.     register int    c, d;
  3215.     int status;
  3216.     char buf[0x100];
  3217.  
  3218.     if (f == NULL || g == NULL) {
  3219.         status = 2;
  3220.         goto end;
  3221.     }
  3222.  
  3223.     for(; c = getc(f), d = getc(g), pos++, c == d; c == '\n' && line++){
  3224.         if(c == EOF) {
  3225.             status = 0;
  3226.             goto end;
  3227.         }
  3228.     }
  3229.     if(c == EOF){
  3230.         sprintf(buf, eofmsg, s);
  3231.         cwFputs(buf, NULL);
  3232.     } else if(d == EOF){
  3233.         sprintf(buf, eofmsg, t);
  3234.         cwFputs(buf, NULL);
  3235.     } else {
  3236.         sprintf(buf, "%s %s differ: char %ld, line %ld\n", s, t, pos, line);
  3237.         cwFputs(buf, NULL);
  3238.     }
  3239.     status = 1;
  3240. end:
  3241.     if (f != NULL) fclose(f);
  3242.     if (g != NULL) fclose(g);
  3243.     return status;
  3244. }
  3245.  
  3246. /*------------*/
  3247. /* split_main */
  3248. /*------------*/
  3249.  
  3250. int split_usage(void)
  3251. {
  3252.     cwFputs("split [-fv] [-b[0][x]n[k]] [-lines] file [basename]\n", (LPSTR)-1);
  3253.     return 1;
  3254. }
  3255.  
  3256. int chknon0num(char *s)
  3257. {
  3258.     int i = 0;
  3259.  
  3260.     for(; is_digit(*s); s++){
  3261.         i *= 10; i += ctoi(*s);
  3262.     }
  3263.     return *s ? 0 : i;
  3264. }
  3265.  
  3266. int chkxknon0lnum(char *s)
  3267. {
  3268.     long    l = 0L;
  3269.  
  3270.     if(*s == '0'){
  3271.         if(s++, *s == 'x' || *s == 'X') goto hex;
  3272.         for(; is_octal(*s); s++){
  3273.             l <<= 3; l += ctoi(*s);
  3274.         }
  3275.     } else if(*s == 'x' || *s == 'X'){
  3276.     hex:
  3277.         for(s++; is_xdigit(*s); s++){
  3278.             l <<= 4; l += ctoi(*s);
  3279.         }
  3280.     } else {
  3281.         for(; is_digit(*s); s++){
  3282.             l *= 10; l += ctoi(*s);
  3283.         }
  3284.     }
  3285.     return *s == 'k' || *s == 'K' ? l << 10 : *s ? 0L : l;
  3286. }
  3287.  
  3288. int split_main(int ac, char **av)
  3289. {
  3290.     int flag = 0; /* 1:force 2:binary 4:visual */
  3291.     int linemax = 1000;
  3292.     long    bytemax = 0L;
  3293.     FILE    *inf;
  3294.     int ret;
  3295.  
  3296.     ac--, av++;
  3297.     for(; ac && av[0][0] == '-' && av[0][1]; ac--, av++){
  3298.         char    *p;
  3299.  
  3300.         for(p = av[0] + 1; *p; p++){
  3301.             if(0 != chknon0num(p)){
  3302.                 /* flag &= ~OPT_BINARY; */
  3303.                 linemax = chknon0num(p);
  3304.                 break;
  3305.             } else if(*p == 'b'){
  3306.                 if(0L != chkxknon0lnum(++p)){
  3307.                     flag |= OPT_BINARY;
  3308.                     bytemax = chkxknon0lnum(p);
  3309.                 } else {
  3310.                     return split_usage();
  3311.                 }
  3312.                 break;
  3313.             } else if(*p == 'f'){
  3314.                 flag |= OPT_FORCE;
  3315.             } else if(*p == 'v'){
  3316.                 flag |= OPT_VISUAL;
  3317.             } else {
  3318.                 return split_usage();
  3319.             }
  3320.         }
  3321.     }
  3322.     switch(ac){
  3323.     case 0:
  3324.         inf = NULL; break;
  3325.     case 2:
  3326.         if(strlen(av[1]) > PATHNAMELENGTH - 5) {
  3327.          /* need 5 more spaces to put in ".aaa\0" */
  3328.             conv_to_unix_format(av[1]);
  3329.             cwFputs(av[1], (LPSTR)-1);
  3330.             cwFputs(": basename too long\n", (LPSTR)-1);
  3331.             return 1;
  3332.         }
  3333.         strcpy(gg.s_base, av[1]);
  3334.         /* through */
  3335.     case 1:
  3336.         if(av[0][0] == '-' && !av[0][1]){
  3337.             inf = NULL;
  3338.         } else {
  3339.             if(NULL == (inf = fopen(*av, ((flag & OPT_BINARY) == 0) ?
  3340.                                          "r" : "rb"))) {
  3341.                 return cantopen(*av);
  3342.             }
  3343.         }
  3344.         break;
  3345.     default:
  3346.         return split_usage();
  3347.     }
  3348.  
  3349.     conv_to_unix_format(gg.s_base);
  3350.     ret = do_split(flag, linemax, bytemax, inf, gg.s_base);
  3351.     if (inf != NULL) fclose(inf);
  3352.     return ret;
  3353. }
  3354.  
  3355. int fexist(char *s)
  3356. {
  3357.     struct  stat    sbuf;
  3358.  
  3359.     return(stat(s, &sbuf) == 0);
  3360. }
  3361.  
  3362. FILE    *fopen_nonexchk(int flag, char *n, char *m)
  3363.  /* nはあらかじめconv_to_unix_formatされているものとする */
  3364. {
  3365.     FILE    *retf;
  3366.  
  3367.     if(!(flag & OPT_FORCE) && fexist(n)){
  3368.         cwFputs(n, (LPSTR)-1), cwFputs(": exist\n", (LPSTR)-1);
  3369.         return NULL;
  3370.     }
  3371.     if(NULL == (retf = fopen(n, m))) {
  3372.         cantopen(n);
  3373.         return NULL;
  3374.     }
  3375.     if(flag & OPT_VISUAL){
  3376.         cwFputs(n, (LPSTR)-1), cwFputs(":\n", (LPSTR)-1);
  3377.     }
  3378.     return retf;
  3379. }
  3380.  
  3381. int do_split(int flag, int linemax, long bytemax, FILE *inf, char *base)
  3382. {
  3383.     int ret = 0;
  3384.     register FILE *otf = NULL;
  3385.     char    *ext;
  3386.     int lines = 0;
  3387.     long    bytes = 0L;
  3388.  
  3389.     if(NULL == gg.s_readbuf2 && NULL == (gg.s_readbuf2 = malloc(RBUFSIZ))){
  3390.         _putnomemmes();
  3391.         ret = 1; goto EXIT;
  3392.     }
  3393.  
  3394.     ext = base + strlen(base);
  3395.     strcpy(ext++, ".aaa");
  3396.  
  3397.     if(flag & OPT_BINARY){
  3398.         int rdbyte, wrbyte;
  3399.  
  3400.         if (inf == NULL) {
  3401.             ret = 1; goto EXIT;
  3402.         }
  3403.         for(;;){
  3404.             rdbyte = (int)imin(bytemax - bytes, (long)RBUFSIZ);
  3405.              /* RBUFSIZがintだからlongになることはない */
  3406.             rdbyte = fread(gg.s_readbuf2, 1, rdbyte, inf);
  3407.             if(rdbyte <= 0) break;
  3408.  
  3409.             if(NULL == otf){
  3410.                 otf = fopen_nonexchk(flag, base, "wb");
  3411.                 if (otf == NULL ) {
  3412.                     ret = 1; goto EXIT;
  3413.                 }
  3414.                  /* write()だからwbの必要はない…か? */
  3415.                 if (nextext(ext) != 0) {
  3416.                     ret = 1; goto EXIT;
  3417.                 }
  3418.             }
  3419.             wrbyte = fwrite(gg.s_readbuf2, 1, rdbyte, otf);
  3420.             if(wrbyte < rdbyte){ /* wrbyte == -1 を含む */
  3421.                 writefail();
  3422.                 ret = 1; goto EXIT;
  3423.             }
  3424.             if(bytemax > (bytes += wrbyte)) continue;
  3425.  
  3426.             bytes = 0;
  3427.             if(fclose(otf) == EOF) {
  3428.                 writefail();
  3429.                 ret = 1; goto EXIT;
  3430.             }
  3431.             otf = NULL;
  3432.         }
  3433.     } else {
  3434.         while(((inf == NULL) ? cwFgets(gg.s_readbuf2, BUFSIZ, NULL) :
  3435.                                fgets(gg.s_readbuf2, BUFSIZ, inf)) != NULL) {
  3436.             if(otf == NULL){
  3437.                 otf = fopen_nonexchk(flag, base, "w");
  3438.                 if (otf == NULL ) {
  3439.                     ret = 1; goto EXIT;
  3440.                 }
  3441.                 if (nextext(ext) != 0) {
  3442.                     ret = 1; goto EXIT;
  3443.                 }
  3444.             }
  3445.             if(EOF == fputs(gg.s_readbuf2, otf)) {
  3446.                 writefail();
  3447.                 ret = 1; goto EXIT;
  3448.             }
  3449.             if(!*gg.s_readbuf2 ||
  3450.                     gg.s_readbuf2[strlen(gg.s_readbuf2 + 1)] != '\n' ||
  3451.                ++lines < linemax) continue;
  3452.  
  3453.             lines = 0;
  3454.             if(fclose(otf) == EOF) {
  3455.                 writefail();
  3456.                 ret = 1; goto EXIT;
  3457.             }
  3458.             otf = NULL;
  3459.         }
  3460.     }
  3461. EXIT:
  3462.     if (otf != NULL) fclose(otf); otf = NULL;
  3463.     if (gg.s_readbuf2 != NULL) free(gg.s_readbuf2); gg.s_readbuf2 = NULL;
  3464.     return ret;
  3465. }
  3466.  
  3467. int nextext(char *ext)
  3468. {
  3469.     int i = 3;
  3470.  
  3471.     while(i--){
  3472.         if(++ext[i] <= 'z') return 0;
  3473.         ext[i] = 'a';
  3474.     }
  3475.     cwFputs("Too many output files\n", (LPSTR)-1);
  3476.     return 1;
  3477. }
  3478.  
  3479. int cantopen(char *s)
  3480. {
  3481.     conv_to_unix_format(s);
  3482.     cwFputs(s, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
  3483.     return 1;
  3484. }
  3485.  
  3486. int writefail(void)
  3487. {
  3488.     cwFputs("Write failed (disk full?)\n", (LPSTR)-1);
  3489.     return 1;
  3490. }
  3491.  
  3492. /*----------*/
  3493. /* cal_main */
  3494. /*----------*/
  3495. #include <time.h>
  3496.  
  3497.  
  3498. /* caldate(y1,m1,d1) - caldate(y2,m2,d2) で y1年m1月d1日からy2年m2月d2日までの
  3499.    日数が計算できる。caldate(y,m,d) % 7 で曜日も求まる(0が日曜、6が土曜)。
  3500.    1752年9月以前でも大丈夫な版 */
  3501. long    caldate(int y, int m, int d)
  3502. {
  3503.     long    ly;
  3504.  
  3505.     if(m <= 2)(y--, m += 12);
  3506.     d += (306 * m + 17) / 10;
  3507.     if((((ly = y) << 9) | d) < ((1752L << 9) | 291)){
  3508.         y = 1752, d += 11; /* 1752年9月2日の次は14日 */
  3509.     }
  3510.     return ly * 1461 / 4 - y / 100 + y / 400 + d;
  3511. }
  3512.  
  3513.  
  3514. int bad(void)
  3515. {
  3516.     cwFputs("Bad argument\n", (LPSTR)-1);
  3517.     return 1;
  3518. }
  3519.  
  3520.  /* output routines */
  3521. int fputs_so(char *s)
  3522. {
  3523.     return cwFputs(s, NULL);
  3524. }
  3525.  
  3526. void putchar_n(int n, int c)
  3527. {
  3528.     char buf[0x101];
  3529.     int i;
  3530.  
  3531.     for (i = 0; i < n; i++) {
  3532.         buf[i % 0x100] = c;
  3533.         if (i % 0x100 == 0xFF) {
  3534.             buf[i % 0x100 + 1] = '\0';
  3535.             cwFputs(buf, NULL);
  3536.         }
  3537.     }
  3538.     buf[i % 0x100] = '\0';
  3539.     cwFputs(buf, NULL);
  3540. }
  3541.  
  3542. void putint(int n)
  3543. {
  3544.     char buf[0x10];
  3545.  
  3546.     sprintf(buf, "%d", n);
  3547.     cwFputs(buf, NULL);
  3548. }
  3549.  
  3550. void putday(int n) /* width 2 */
  3551. {
  3552.     char buf[0x8];
  3553.  
  3554.     sprintf(buf, "%2d", n);
  3555.     cwFputs(buf, NULL);
  3556. }
  3557.  
  3558. void shortmonth(int m)
  3559. {
  3560.     char buf[0x8];
  3561.  
  3562.     strncpy(buf, monthname[m], 3); buf[3] = '\0';
  3563.     cwFputs(buf, NULL);
  3564. }
  3565.  
  3566. int cal_main(int ac, char **av)
  3567. {
  3568.     switch(ac){
  3569.     case 3: /* cal m y */
  3570.         return calym(atoi(av[2]), atoi(av[1]));
  3571.     case 2: /* cal y */
  3572.         return caly(atoi(av[1]));
  3573.     case 1: /* this month */
  3574.         return cal();
  3575.     default:
  3576.         cwFputs("Usage: cal [[month] year]\n", (LPSTR)-1);
  3577.         return 1;
  3578.     }
  3579.     return 0;
  3580. }
  3581.  
  3582. void getmonthdays(int year, int month, char *days, char *d_of_w)
  3583. { /* その月の日数とついたちの曜日を求める */
  3584.     long    temp;
  3585.  
  3586.     temp = caldate(year, month, 1);
  3587.     *d_of_w = (int)(temp % 7);
  3588.     if(++month > 12) (year++, month = 1);
  3589.     *days = (int)(caldate(year, month, 1) - temp);
  3590. }
  3591.  
  3592. int cal(void)
  3593. {
  3594.     struct  tm  *dt;
  3595.     long    tt;
  3596.  
  3597.     time(&tt);
  3598.     dt = localtime(&tt);
  3599.     return calym(dt -> tm_year + 1900, dt -> tm_mon + 1);
  3600. }
  3601.  
  3602. int calym(int year, int month)
  3603. {
  3604.     int i;
  3605.     unsigned char d_of_w, days;
  3606.  
  3607.     if(year <= 0 || month < 1 || 12 < month) return bad();
  3608.  
  3609.     putchar_n(3, ' '); fputs_so(monthname[month]); cwFputs(" ", NULL);
  3610.     putint(year);
  3611.     cwFputs("\n", NULL), fputs_so(dofw_title), cwFputs("\n", NULL);
  3612.  
  3613.     getmonthdays(year, month, &days, &d_of_w);
  3614.     for(i = 0; i < 6; i++){
  3615.         calrow(year, month, days, d_of_w, i, 1);
  3616.         cwFputs("\n", NULL);
  3617.     }
  3618.     return 0;
  3619. }
  3620.  
  3621. int caly(int year)
  3622. {
  3623.     int i, j, k, m;
  3624.     unsigned char days[3], d_of_w[3];
  3625.  
  3626.     if(year <= 0) return bad();
  3627.     fputs_so("\n\n\n\t\t\t\t"), putint(year);
  3628.     putchar_n(2, '\n');
  3629.     for(i = 0; i < 4; i++){
  3630.         for(k = -2; k < 6; k++){
  3631.             for(j = 0; j < 3; j++){
  3632.                 m = i * 3 + j + 1;
  3633.                 switch(k){
  3634.                 case -2:
  3635.                     putchar_n(9, ' ');
  3636.                     shortmonth(m);
  3637.                     j == 2 ? cwFputs("\n", NULL) :
  3638.                          putchar_n(11, ' ');
  3639.                     break;
  3640.                 case -1:
  3641.                     fputs_so(dofw_title);
  3642.                     getmonthdays(year, m,
  3643.                         &days[j], &d_of_w[j]);
  3644.                     goto common;
  3645.                 default:
  3646.                     calrow(year, m, days[j], d_of_w[j],
  3647.                         k, j == 2);
  3648.                 common:
  3649.                     j == 2 ? cwFputs("\n", NULL) :
  3650.                          putchar_n(3, ' ');
  3651.                     break;
  3652.                 }
  3653.             }
  3654.         }
  3655.     }
  3656.     putchar_n(3, '\n');
  3657.     return 0;
  3658. }
  3659.  
  3660. void calrow(int year, int month, int days, int d_of_w, int row, int eolsup)
  3661. { /* 1752年9月に注意 */
  3662.     int i, d;
  3663.  
  3664.     for(i = 0; i < 7; i++){
  3665.         d = row * 7 + i + 1 - d_of_w;
  3666.         if(days < d){
  3667.             if(eolsup) break; else d = 0;
  3668.         }
  3669.  
  3670.         if(i) cwFputs(" ", NULL);
  3671.         if(d < 1){
  3672.             putchar_n(2, ' ');
  3673.         } else {
  3674.             if(year == 1752 && month == 9 && d > 2) d += 11;
  3675.             putday(d);
  3676.         }
  3677.     }
  3678. }
  3679.  
  3680. /*----------*/
  3681. /* cat_main */
  3682. /*----------*/
  3683.  
  3684. int iskana(int c)
  3685. {
  3686.     if(gg.s_flag < 0) gg.s_flag = iskanji(0x81); /* don't omit this */
  3687.     return gg.s_flag && ((c &= 0xff), (0xa1 <= c && c <= 0xdf));
  3688. }
  3689.  
  3690. int cat_usage(void)
  3691. {
  3692.     cwFputs("cat [-vnNtTg] file\n"
  3693.           "-v : display unprintable characters.\n"
  3694.           "-n : put linenumbers(reset for each file).\n"
  3695.           "-N : put linenumbers.\n"
  3696.           "-t : text mode input/output.\n"
  3697.           "-T : text mode input.\n",
  3698.           (LPSTR)-1);
  3699.     return 1;
  3700. }
  3701.  
  3702. void cat_out(FILE *f)
  3703. {
  3704.     if(gg.Num == 0){
  3705.         gg.lineno = 0L;
  3706.         if(!gg.lasteol){
  3707.             if(!gg.otxt) cwFputs("\r", NULL);
  3708.             cwFputs("\n", NULL);
  3709.             gg.lasteol = 1;
  3710.         }
  3711.     }
  3712.     gg.vis ? outv(f) : gg.num ? outn(f) : outb(f);
  3713. }
  3714.  
  3715. void outv(FILE *f) /* fはこの関数内で全部読み尽くす */
  3716. {
  3717.     int c, d;
  3718.     char bufi[0x100], bufo[0x200 + 8];
  3719.     char *pi, *po;
  3720.  
  3721.     while (((f == NULL) ? cwFgets(bufi, 0x100, NULL) :
  3722.                           fgets(bufi, 0x100, f)) != NULL) {
  3723.         bufi[0xFF] = '\0';
  3724.         po = bufo;
  3725.         for (pi = bufi; *pi != '\0'; pi++) {
  3726.             c = *pi;
  3727.             if(gg.lasteol){
  3728.                 if(gg.num) {
  3729.                     longintout(7, ++gg.lineno, &po);
  3730.                     *po++ = ' ';
  3731.                 }
  3732.                 gg.lasteol = 0;
  3733.             }
  3734.             if(c == '\n'){
  3735.                 gg.lasteol = 1;
  3736.                 goto out1b;
  3737.             } else if(isprint(c) || c == '\t' || iskana(c)){
  3738.                 goto out1b;
  3739.             } else if(isascii(c)){
  3740.                 goto outctrl;
  3741.             } else if(iskanji(c)){
  3742.                 pi++; d = *pi;
  3743.                 if(d == '\0'){
  3744.                     goto outmeta;
  3745.                 } else if(!iskanji2(d)){
  3746.                     pi--;
  3747.                     goto outmeta;
  3748.                 } else {
  3749.                     goto out2b;
  3750.                 }
  3751.             } else {
  3752. outmeta:
  3753.                 *po++ = 'M'; *po++ = '-';
  3754.                 c = toascii(c);
  3755.                 if(isprint(c)) goto out1b;
  3756. outctrl:
  3757.                 d = toascii('@' + c), c = '^';
  3758. out2b:
  3759.                 *po++ = c; c = d;
  3760. out1b:
  3761.                 *po++ = c;
  3762.                 if (*pi == '\0') {
  3763.                     break;
  3764.                 }
  3765.             }
  3766.         }
  3767.         *po++ = '\0';
  3768.         cwFputs(bufo, NULL);
  3769.     }
  3770. }
  3771.  
  3772. void outn(FILE *f)
  3773. {
  3774.     char buf[0x100];
  3775.     char bufline[0x10];
  3776.  
  3777.     while (((f == NULL) ? cwFgets(buf, 0x100, NULL) :
  3778.                           fgets(buf, 0x100, f)) != NULL) {
  3779.         if(gg.lasteol){
  3780.             sprintf(bufline, "%7d ", ++gg.lineno);
  3781.             cwFputs(bufline, NULL);
  3782.             gg.lasteol = 0;
  3783.         }
  3784.         cwFputs(buf, NULL);
  3785.         gg.lasteol = (buf[lstrlen(buf) - 1] == '\n');
  3786.     }
  3787. }
  3788.  
  3789. void outb(FILE *f)
  3790. {
  3791.     char buf[0x100];
  3792.  
  3793.     while (((f == NULL) ? cwFgets(buf, 0x100, NULL) :
  3794.                           fgets(buf, 0x100, f)) != NULL) {
  3795.         cwFputs(buf, NULL);
  3796.     }
  3797. }
  3798.  
  3799. void longintout(int w, unsigned long n, char **ppo)
  3800. {
  3801.     int i;
  3802.     unsigned long m;
  3803.  
  3804.     memset(*ppo, ' ', w);
  3805.     for (i = 1, m = n; m > 0; i++, m /= 10);
  3806.     sprintf(*ppo + w - i, "%d", n);
  3807.     **ppo += w;
  3808. }
  3809.  
  3810. int cat_main(int ac, char **av)
  3811. {
  3812.     int c, status = 0;
  3813.     FILE    *f;
  3814. //  extern  int optind, opterr;
  3815. //  extern  char    *optarg;
  3816.  
  3817.     gg.opterr = 0;
  3818.  
  3819.     while(EOF != (c = getopt(ac, av, "vnNtTg"))){
  3820.         switch(c){
  3821.         case 'v':
  3822.             gg.otxt = gg.vis = 1; break;
  3823.         case 'n':
  3824.             gg.num = 1; break;
  3825.         case 'N':
  3826.             gg.num = gg.Num = 1; break;
  3827.         case 't':
  3828.             gg.otxt = 1; /* through */
  3829.         case 'T':
  3830.             gg.itxt = 1; break;
  3831.         default:
  3832.             return cat_usage();
  3833.         }
  3834.     }
  3835.     av += gg.optind, ac -= gg.optind;
  3836.  
  3837.     if(ac){
  3838.         char    *p;
  3839.  
  3840.         for(; p = *av, ac; ac--, av++){
  3841.             if(*p == '-' && !p[1]){
  3842.                 cat_out(NULL);
  3843.             } else {
  3844.                 if(NULL == (f = fopen(p, gg.itxt ? "r" : "rb"))){
  3845.                     cwFputs(conv_to_unix_format(p), (LPSTR)-1);
  3846.                      /* 支障ないはず */
  3847.                     cwFputs(": Can't open\n", (LPSTR)-1);
  3848.                     status = 1;
  3849.                 } else {
  3850.                     cat_out(f);
  3851.                     fclose(f);
  3852.                 }
  3853.             }
  3854.         }
  3855.     } else {
  3856.         cat_out(NULL);
  3857.     }
  3858.     return status;
  3859. }
  3860.  
  3861. /*-----------*/
  3862. /* date_main */
  3863. /*-----------*/
  3864. /* Usage: cdate [[[[mm]dd]hh]mm[[.ss][yy]] [+format] */
  3865.  
  3866.  
  3867. int date_main(int ac, char **av)
  3868. {
  3869.     switch(ac){
  3870.     case 3:
  3871.         if (mod_disp_time(av[1], av[2]) != 0) return 1;
  3872.         break;
  3873.     case 2:
  3874.         if(*av[1] != '+'){
  3875.             if (mod_disp_time(av[1], NULL) != 0) return 1;
  3876.         } else {
  3877.             if (mod_disp_time(NULL, av[1]) != 0) return 1;
  3878.         }
  3879.         break;
  3880.     case 1:
  3881.         if (mod_disp_time(NULL, NULL) != 0) return 1;
  3882.         break;
  3883.     default:
  3884.         return date_usage();
  3885.     }
  3886.     return 0;
  3887. }
  3888.  
  3889. int date_usage(void)
  3890. {
  3891.     cwFputs("Usage: cdate [[[[mm]dd]hh]mm[[.ss][yy]] [+format]\n", (LPSTR)-1);
  3892.     return 1;
  3893. }
  3894.  
  3895. #if 0
  3896. /* caldate(y1,m1,d1) - caldate(y2,m2,d2) で y1年m1月d1日からy2年m2月d2日までの
  3897.    日数が計算できる。caldate(y,m,d) % 7 で曜日も求まる(0が日曜、6が土曜)*/
  3898. long    caldate(int y, int m, int d)
  3899.  /* 特例: mが13なら翌年1月とみなされる dは0でも大丈夫 */
  3900. {
  3901.     if(m <= 2)(y--, m += 12);
  3902.     return (long)y * 1461 / 4 - y / 100 + y / 400 +
  3903.            (306 * m + 17) / 10 + d;
  3904. }
  3905. #endif
  3906.  
  3907. int chkdatearg(char *s, int *l1p, char **dsp, int *l2p)
  3908. {
  3909.     char    *p;
  3910.  
  3911.     for(p = s; *p && *p != '.'; p++) {
  3912.         if (is_digit(*p) == 0) {
  3913.             return illdate();
  3914.         }
  3915.     }
  3916.     *l1p = p - s;
  3917.     if(*p){
  3918.         for(*dsp = s = ++p; *p; p++) {
  3919.             if (is_digit(*p) == 0) {
  3920.                 illdate();
  3921.             }
  3922.         }
  3923.         *l2p = p - s;
  3924.     } else {
  3925.         *l2p = 0, *dsp = NULL;
  3926.     }
  3927.     return 0;
  3928. }
  3929.  
  3930. // #define ctoi(c) ((c) - '0') /* cが数字文字であるとわかっている時 */
  3931.  
  3932. int badfmt(void)
  3933. {
  3934.     cwFputs("Bad format character\n", (LPSTR)-1);
  3935.     return 1;
  3936. }
  3937.  
  3938. int illdate(void)
  3939. {
  3940.     cwFputs("Bad conversion\n", (LPSTR)-1);
  3941.     return 1;
  3942. }
  3943.  
  3944. int scan2int(char *s) /* s以降2桁が数字のみだとわかっている時 */
  3945. {
  3946.     return ctoi(*s) * 10 + ctoi(s[1]);
  3947. }
  3948.  
  3949. int mod_disp_time(char *newt, char *fmt)
  3950. {
  3951.     int y, m, d, w, h, mi, s;
  3952.     SYSTEMTIME st;
  3953.  
  3954.     GetLocalTime(&st);
  3955.  
  3956.     y  = st.wYear;
  3957.     m  = st.wMonth;
  3958.     d  = st.wDay;
  3959.     h  = st.wHour;
  3960.     mi = st.wMinute;
  3961.     s  = st.wSecond;
  3962.     w  = st.wDayOfWeek;
  3963.  
  3964.     if(newt != NULL){
  3965.         int l1, l2;
  3966.         long    ymd;
  3967.         char    *auxarg;
  3968.  
  3969.         s = 0;
  3970.         if (chkdatearg(newt, &l1, &auxarg, &l2) != 0) return 1;
  3971.         switch(l1){
  3972.         case 12:
  3973.             s = scan2int(newt + 8);
  3974.             /* through */
  3975.         case 10:
  3976.             y = -scan2int(newt + l1 - 2);
  3977.             /* through */
  3978.         case 8:
  3979.             m = scan2int(newt), newt += 2;
  3980.             /* through */
  3981.         case 6:
  3982.             d = scan2int(newt), newt += 2;
  3983.             /* through */
  3984.         case 4:
  3985.             h = scan2int(newt), newt += 2;
  3986.             /* through */
  3987.         case 2:
  3988.             mi= scan2int(newt);
  3989.             break;
  3990.         default:
  3991.             return illdate();
  3992.         }
  3993.  
  3994.         if(auxarg != NULL){
  3995.             if(l1 > 8) return illdate();
  3996.  
  3997.             switch(l2){
  3998.             case 4:
  3999.                 y = -scan2int(auxarg + 2);
  4000.                 /* through */
  4001.             case 2:
  4002.                 s = scan2int(auxarg);
  4003.                 break;
  4004.             default:
  4005.                 return illdate();
  4006.             }
  4007.         }
  4008.  
  4009.         if(y <= 0) st.wYear = y = (y <= -80 ? 1900 : 2000) - y;
  4010.         w = (int)(ymd = caldate(y, m, d)) % 7;
  4011.         st.wMonth = m, st.wDay = d, st.wHour = h;
  4012.         st.wMinute = mi, st.wSecond = s;
  4013.  
  4014.         if(!(1 <= m && m <= 12 &&
  4015.              1 <= d && ymd < caldate(y, m + 1, 1) &&
  4016.                     /* caldateの13月特例 */
  4017.              0 <= h && h < 24 &&
  4018.              0 <= mi && mi < 60 &&
  4019.              0 <= s && s < 60)) {
  4020.             return illdate();
  4021.         }
  4022.         SetLocalTime(&st);
  4023.     }
  4024.  
  4025.     if (disptime(fmt, y, m, d, h, mi, s, w) != 0) return 1;
  4026.     cwFputs("\n", NULL);
  4027.     return 0;
  4028. }
  4029.  
  4030. void strout(char *s, int n) /* -1にすれば事実上無限大になる */
  4031. {
  4032.     char cStack;
  4033.  
  4034.     if (n >= 0) {
  4035.         cStack = s[n]; s[n] = '\0';
  4036.     }
  4037.     cwFputs(s, NULL);
  4038.     if (n >= 0) {
  4039.         s[n] = cStack;
  4040.     }
  4041. }
  4042.  
  4043. void intoutz(int i, int n) /* n>0のこと */
  4044. {
  4045.     char *buf;
  4046.     int col;
  4047.     int num;
  4048.  
  4049.     buf = malloc(n + 1);
  4050.     if (buf == NULL) {
  4051.         return;
  4052.     }
  4053.     memset(buf, '0', n);
  4054.     buf[n] = '\0';
  4055.     num = i / 10;
  4056.     for (col = 1; num > 0; col++, num /= 10);
  4057.     if (col > n) col = n;
  4058.     _snprintf(buf + n - col, n, "%d", i);
  4059.     cwFputs(buf, NULL);
  4060.     free(buf);
  4061. }
  4062.  
  4063. void date_intout(int i, int n) /* n>0のこと */
  4064. {
  4065.     char *buf;
  4066.     int col;
  4067.     int num;
  4068.  
  4069.     buf = malloc(n + 1);
  4070.     if (buf == NULL) {
  4071.         return;
  4072.     }
  4073.     memset(buf, ' ', n);
  4074.     buf[n] = '\0';
  4075.     num = i / 10;
  4076.     for (col = 1; num > 0; col++, num /= 10);
  4077.     if (col > n) col = n;
  4078.     _snprintf(buf + n - col, n, "%d", i);
  4079.     cwFputs(buf, NULL);
  4080.     free(buf);
  4081. }
  4082.  
  4083. void Putchar(char c)
  4084. {
  4085.     char buf[0x2];
  4086.  
  4087.     buf[0] = c; buf[1] = '\0';
  4088.     cwFputs(buf, NULL);
  4089. }
  4090.  
  4091. int disptime(char *fmt, int y, int m, int d, int h, int mi, int s, int w)
  4092. /* %はSJISの2バイト目にならないので漢字に特段の配慮は不要 */
  4093. {
  4094.     if(fmt == NULL){
  4095.         return disptime("+%c", y, m, d, h, mi, s, w);
  4096.     } else if(*fmt++ != '+'){
  4097.         return badfmt();
  4098.     }
  4099.  
  4100.     for(; *fmt; fmt++){
  4101.         if(*fmt != '%'){
  4102.             Putchar(*fmt);
  4103.             continue;
  4104.         }
  4105.         switch(*++fmt){
  4106.         case '%': Putchar('%'); break;
  4107.         case 'n': Putchar('\n'); break;
  4108.         case 't': Putchar('\t'); break;
  4109.         case 'A': strout(dofwkname[w], -1); break;
  4110.         case 'B': strout(monthname[m], -1); break;
  4111.         case 'D': disptime("+%m/%d/%y", y, m, d, 0, 0, 0, 0); break;
  4112.         case 'H': intoutz(h, 2); break;
  4113.         case 'I': intoutz((h + 11) % 12 + 1, 2); break;
  4114.         case 'M': intoutz(mi, 2); break;
  4115.         case 'S': intoutz(s, 2); break;
  4116.         case 'T':
  4117.         case 'X': disptime("+%H:%M:%S", 0, 0, 0, h, mi,s, 0); break;
  4118.         case 'Y': intoutz(y, 4); break;
  4119.         case 'a': strout(dofwkname[w], 3); break;
  4120.         case 'b':
  4121.         case 'h': strout(monthname[m], 3); break;
  4122.         case 'c': disptime("+%a %b %e %T %Y", y, m, d, h, mi, s, w); break;
  4123.         case 'd': intoutz(d, 2); break;
  4124.         case 'e': date_intout(d, 2); break;
  4125.         case 'j': intoutz(caldate(y, m, d) - caldate(y, 1, 0), 3); break;
  4126.         case 'm': intoutz(m, 2); break;
  4127.         case 'p': cwFputs(h < 12 ? "AM" : "PM", NULL); break;
  4128.         case 'r': disptime("+%I:%M:%S %p", 0, 0, 0, h, mi,s, 0); break;
  4129.         case 'w': intoutz(w, 1); break;
  4130.         case 'x': disptime("+%a %b %e %Y", y, m, d, 0, 0, 0, w); break;
  4131.         case 'y': intoutz(y % 100, 2); break;
  4132.         default:
  4133.             return badfmt();
  4134.         }
  4135.     }
  4136.     return 0;
  4137. }
  4138.  
  4139. /*---------*/
  4140. /* rm_main */
  4141. /*---------*/
  4142. /**
  4143.  
  4144.  
  4145.     'rm':UNIX-like file delete utility for MS-DOS machines.
  4146.  
  4147.     89.03.02    ver 1.0     Yasushi Saito, TAIST.
  4148.     90.10.03            Some cleanups,
  4149.                     supports '.../' notation.
  4150.                     -i asks y/n for all files.
  4151.  
  4152.                 compiled by Microsoft C compiler ver 5.1
  4153.                 changed to LSI-C ver 3.20
  4154.  
  4155.  
  4156.     rm [options] file1 file2 .. filen
  4157.  
  4158.     Remove file1, file2, ..., filen
  4159.  
  4160.     Options:
  4161.     -r: Remove all files under directory, if specified file is a directory.
  4162.     -i: Interactive, i.e., ask yes or no when removing files.
  4163.     -f: Remove readonly files without query.
  4164.     -v: Verbose message.
  4165.  
  4166.     Wildcards can be used to give file or directory name ambiguously.
  4167.     See 'wild.c' for the wildcard specs.
  4168.  
  4169.     This program is NOT COPYRIGHTED, used, modified, re-distributed
  4170.          with no restriction,and no warranty.
  4171.  
  4172. */
  4173.  
  4174. /*
  4175.  * Almost same as sprintf(BUF,"%s\\%s",DIR,F), but perform BUF boundary
  4176.  * check(BUF must be longer than PATHNAMELENGTH bytes), and if DIR ends with
  4177.  * PD, then does not add PD between DIR and F, as above sprintf does.
  4178.  * 
  4179.  */
  4180.  
  4181. int yn_p_with_ret(void)
  4182. {
  4183.     char szbuf[0x100];
  4184.  
  4185.     cwFgets(szbuf, 0x100, NULL);
  4186.     return (szbuf[0] == 'y' || szbuf[0] == 'Y');
  4187. }
  4188.  
  4189. void rm_error(char *s, char *pathname)
  4190. {
  4191.     char szbuf[0x100];
  4192.  
  4193.     if(gg.opt_force) return;
  4194.     _snprintf(szbuf, sizeof(szbuf), s, s_conv_to_unix_format(pathname));
  4195.     cwFputs(szbuf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
  4196.     gg.error_code = 1;
  4197. }
  4198.  
  4199. void io_error(char *s, char *pathname)
  4200. {
  4201.     char szbuf[0x100];
  4202.  
  4203.     _snprintf(szbuf, sizeof(szbuf), s, s_conv_to_unix_format(pathname));
  4204.     cwFputs(szbuf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
  4205. //  perror(" ");
  4206.     if(!gg.opt_force) gg.error_code = 1;
  4207. }
  4208.  
  4209. /*
  4210.  * Actually remove PATH. PATH is a normal file (not directory).
  4211.  */
  4212. void remove_file(char *path)
  4213. {
  4214.     char szbuf[0x100];
  4215.  
  4216.     if(gg.opt_interactive){
  4217.         _snprintf(szbuf, sizeof(szbuf),
  4218.                   "remove %s ? ", s_conv_to_unix_format(path));
  4219.         cwFputs(szbuf, (LPSTR)-1);
  4220.         if(!YES_OR_NO_P()) return;
  4221.     }
  4222.  
  4223.     if(remove(path) < 0){
  4224.         unsigned attr;
  4225.         if((attr = getattr(path)) == -1){
  4226.             rm_error("'%s' does not exist.", path);
  4227.             return;
  4228.         }
  4229.         if(attr & 0x10){
  4230.             rm_error("'%s' is a directory.", path);
  4231.             return;
  4232.         }
  4233.         if(!gg.opt_force){
  4234.             _snprintf(szbuf,sizeof(szbuf),"override protection %x for %s ? ",
  4235.                 attr, s_conv_to_unix_format(path));
  4236.             cwFputs(szbuf, (LPSTR)-1);
  4237.             if(!YES_OR_NO_P()) return;
  4238.         }
  4239.         setattr(path, attr & ~7);
  4240.         if(remove(path) < 0){
  4241.             io_error("cannot remove '%s'", s_conv_to_unix_format(path));
  4242.             return;
  4243.         }
  4244.     }
  4245.     if(gg.opt_verbose){
  4246.         cwFputs(s_conv_to_unix_format(path), (LPSTR)-1);
  4247.         cwFputs("\n", (LPSTR)-1);
  4248.     }
  4249. }
  4250.  
  4251. /*
  4252.  * Remove all files under the directory S
  4253.  * 
  4254.  * Same as performing "DEL S\*.*"(S is the parameter) from commandline. Returns
  4255.  * immediately with files left untouched if failed to chdir S (hence S need
  4256.  * not a directory, in which case this procedure performs nothing).
  4257.  * 
  4258.  * Hidden files and readonly files may not be removed by this procedure, so this
  4259.  * is used as preprocess for whole-directory remove.
  4260.  * 
  4261.  */
  4262. void delete_all_using_FCB(char *s)
  4263. {
  4264.     return;
  4265.  
  4266. #if 0
  4267.     char szpath[MAX_PATH];
  4268.     char szfile[MAX_PATH * 2];
  4269.     long lfind;
  4270.     struct _finddata_t ftfind;
  4271.     UINT uErrorOrg;
  4272.  
  4273.     uErrorOrg = SetErrorMode(SEM_FAILCRITICALERRORS);
  4274.     strcpy(szpath, s);
  4275.     _snprintf(szfile, sizeof(szfile), "%s\\%s", szpath, "*.*");
  4276.     memset(&ftfind, 0, sizeof(ftfind));
  4277.     ftfind.attrib = _A_NORMAL | _A_SUBDIR;
  4278.     lfind = _findfirst(szfile, &ftfind);
  4279.     if (lfind != -1) {
  4280.         do {
  4281.             _snprintf(szfile, sizeof(szfile), "%s\\%s", szpath, ftfind.name);
  4282.             remove(szfile);
  4283.         } while (_findnext(lfind, &ftfind) == 0);
  4284.         _findclose(lfind);
  4285.     }
  4286.     SetErrorMode(uErrorOrg);
  4287. #endif
  4288. }
  4289.  
  4290. /*
  4291.  * Delete the file PATH. Delete recursively if PATH is a directory and
  4292.  * OPT_RECURSIVE option is True.
  4293.  */
  4294. void r_remove_file(char *path)
  4295. {
  4296.     char szbuf[0x100];
  4297.  
  4298.     if(!regularize_pathname(path)){
  4299.         /* PATH does not end with \ */
  4300.  
  4301.         if(!gg.opt_recursive){
  4302.             remove_file(path);
  4303.             return;
  4304.         }
  4305.     } else if(!gg.opt_recursive){
  4306.         rm_error("%s is a directory.", path);
  4307.         return;
  4308.     }
  4309.     /* Delete directory files. */
  4310.     {
  4311.         struct _finddata_t f;
  4312.         char    temp[PATHNAMELENGTH];
  4313.         long hfind;
  4314.  
  4315.         /* First, perform BDOS file remove for speedups. */
  4316.         if(!gg.opt_interactive){
  4317.             if(gg.opt_verbose) {
  4318.                 _snprintf(szbuf, sizeof(szbuf), "%s/*.*\n",
  4319.                           s_conv_to_unix_format(path));
  4320.                 cwFputs(szbuf, (LPSTR)-1);
  4321.             }
  4322.             delete_all_using_FCB(path);
  4323.         }
  4324.         /*
  4325.          * Delete remaining files(hidden files, readonly files) by
  4326.          * searching each files.
  4327.          */
  4328.         _snprintf(temp, sizeof(temp), "%s\\%s", path, "*.*");
  4329.         memset(&f, 0, sizeof(f));
  4330.         f.attrib = 0x37;
  4331.         hfind = _findfirst(temp, &f);
  4332.         if(hfind == -1){
  4333.             /*
  4334.              * unable to interpret PATH as a directory. treat it
  4335.              * as a plain file, and remove it
  4336.              */
  4337.             remove_file(path);
  4338.             return;
  4339.         }
  4340.         do {
  4341.             /*
  4342.              * If the first character of the filename is '.',
  4343.              * then the filename must be "." or ".." in MSDOS.
  4344.              */
  4345.             if(*(f.name) != '.'){
  4346.                 _snprintf(temp, sizeof(temp), "%s\\%s", path, f.name);
  4347.                 if(f.attrib & 0x10)
  4348.                     r_remove_file(temp);
  4349.                 else
  4350.                     remove_file(temp);
  4351.             }
  4352.         } while(_findnext(hfind, &f) == 0);
  4353.         _findclose(hfind);
  4354.         if(gg.opt_interactive){
  4355.             _snprintf(szbuf, sizeof(szbuf), "remove %s/ ? ",
  4356.                 s_conv_to_unix_format(path));
  4357.             cwFputs(szbuf, (LPSTR)-1);
  4358.             if(!YES_OR_NO_P()) return;
  4359.         }
  4360.         if(rmdir(path) < 0) io_error("cannot remove directory '%s'", path);
  4361.         if(gg.opt_verbose) {
  4362.             _snprintf(szbuf, sizeof(szbuf), "%s/\n",
  4363.                     s_conv_to_unix_format(path));
  4364.             cwFputs(szbuf, (LPSTR)-1);
  4365.         }
  4366.     }
  4367. }
  4368.  
  4369. int rm_main(int argc, char **argv)
  4370. {
  4371.     int c, i;
  4372.     int getopt();
  4373. //  extern  int optind, opterr;
  4374. //  extern  char    *optarg;
  4375.  
  4376.     conv_char_args(argv, '/', '\\');
  4377.  
  4378.     gg.opterr = 0;
  4379.  
  4380.     while((c = getopt(argc, argv, "rvif")) != EOF){
  4381.         switch (c){
  4382.         case 'r':
  4383.             gg.opt_recursive = True;
  4384.             break;
  4385.         case 'v':
  4386.             gg.opt_verbose = True;
  4387.             break;
  4388.         case 'i':
  4389.             gg.opt_interactive = True;
  4390.             break;
  4391.         case 'f':
  4392.             gg.opt_force = True;
  4393.             break;
  4394.         default:    /* Add Nide */
  4395.             goto synerr;
  4396.         }
  4397.     }
  4398.     argc -= gg.optind;
  4399.     argv += gg.optind;
  4400.  
  4401.     if(argc < 1){
  4402.         static char *msgs[] = {
  4403.             "rm [-rfiv] file1 ... filen\n",
  4404.             "-r : Recursively remove all files under directory\n",
  4405.             "-f : Remove readonly files without query\n",
  4406.             "-i : Query before removing\n",
  4407.             "-v : Verbose message\n",
  4408.         };
  4409.  
  4410. synerr:         /* Add Nide */
  4411.         for(i = 0; i < sizeof(msgs) / sizeof(*msgs); i++)
  4412.             cwFputs(msgs[i], (LPSTR)-1);
  4413.         /* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
  4414.         return 1;
  4415.     }
  4416.     for(i = 0; i < argc; i++){
  4417.         r_remove_file(argv[i]);
  4418.     }
  4419.     return gg.error_code;
  4420. }
  4421.  
  4422. /*-----------*/
  4423. /* grep_main */
  4424. /*-----------*/
  4425. /* fgrep.c兼egrep.c    「#define fgrep」とすればfgrepになる
  4426.     ファイルの中から、指定した文字列あるいはパターンを含む行を探す。
  4427.  
  4428.     Usage: {e,f}grep [-chilLnsvx] 文字列 ファイル名…
  4429.            {e,f}grep [-chilLnsvx] -e 文字列 ファイル名…
  4430.            {e,f}grep [-chilLnsvx] -f 探索文字列ファイル ファイル名…
  4431.       -c  指定した文字列を含むファイルについて、その行数のみを報告。
  4432.       -h  見つけた行を表示するとき、先頭にそのファイル名を出力しない。
  4433.           ファイルが1つだけの時のデフォルト。
  4434.       -i  文字列のうち1バイト英字の大文字小文字を区別せずに探す(fgrepのみ)。
  4435.       -l  指定した文字列を含むファイルの名前だけを(1回ずつ)表示。
  4436.       -L  見つけた行を表示するとき、先頭にそのファイル名を出力する。
  4437.           ファイルが複数のときのデフォルト。
  4438.       -n  見つけた行を表示するとき、先頭にファイル中での行番号を出力。
  4439.       -s  exit statusのみを返し、何も表示しない。
  4440.       -v  条件反転。指定した文字列を含まない行のみを探索対象にする。
  4441.       -w  指定したパターンを単語として含む行のみを探索対象にする(egrepのみ)。
  4442.       -x  指定した文字列と完全に一致する行のみを探索対象にする。
  4443.  
  4444.       -e 文字列
  4445.           単に文字列を指定するのと同じだが、「-」で始まる文字列を
  4446.           探索する場合に使う。こうしないと探索文字列をオプションと
  4447.           混同するため。
  4448.       -f ファイル名
  4449.           fgrepの場合、指定したファイルの最初の行の文字列を探索対象とする。
  4450.           egrepの場合、指定したファイルの各行のorを探索対象とする。
  4451.           -f指定の場合、コマンド行で改めて探索文字列を指定しなくていい。
  4452.  
  4453.     exit statusは、文字列が見つかったら0、見つからなかったら1、
  4454.     文法エラーなどそれ以外の事態が起きたら2。
  4455.  */
  4456.  
  4457.  
  4458. char    *strichr(char *s, int c)
  4459. {
  4460.     c = to_lower(c);
  4461.     for(; *s; s++) if((char)to_lower(*s) == (char)c) return(s);
  4462.     return(NULL);
  4463. }
  4464.  
  4465. char    *getfpat(char *fnm)
  4466. {
  4467.     char    *p = NULL, linbuf[MAXLEN];
  4468.     int linlen;
  4469.     FILE    *f = NULL;
  4470.     char    *pret = NULL;
  4471.  
  4472.     name_unixnize(fnm);
  4473.     if(NULL == (f = fopen(fnm, "r"))){
  4474.         perror(fnm);
  4475.         pret = NULL; goto EXIT;
  4476.     }
  4477.  
  4478.     if(NULL == fgets(linbuf, MAXLEN, f)){
  4479.         cwFputs(fnm, (LPSTR)-1), cwFputs(": empty\n", (LPSTR)-1);
  4480.         pret = NULL; goto EXIT;
  4481.     }
  4482.     for(;;){
  4483.         if(!(linlen = strlen(linbuf))){
  4484.             cwFputs("Empty pattern found\n", (LPSTR)-1);
  4485.             pret = NULL; goto EXIT;
  4486.         }
  4487.         if('\n' == (linbuf - 1)[linlen]){ /* chop newline */
  4488.             (linbuf - 1)[linlen] = '\0';
  4489.         } else if(linlen == MAXLEN - 1){
  4490.             cwFputs(fnm, (LPSTR)-1);
  4491.             cwFputs(": pattern too long\n", (LPSTR)-1);
  4492.             pret = NULL; goto EXIT;
  4493.         }
  4494.         if(NULL == (p = strdup(linbuf))){
  4495.             perror("strdup");
  4496.             pret = NULL; goto EXIT;
  4497.         } else break;
  4498.     }
  4499.     pret = p;
  4500. EXIT:
  4501.     if (f != NULL) fclose(f);
  4502.     return pret;
  4503. }
  4504.  
  4505. int grep_main(int ac, char **av)
  4506. {
  4507.     int c;
  4508. //  extern  int optind, opterr;
  4509. //  extern  char    *optarg;
  4510.     char    *ptn = NULL;
  4511.     char    *ptnf = NULL;
  4512.     int nret = 0;
  4513.  
  4514.     gg.opterr = 0;
  4515.  
  4516.      /* options: ef xvi s lc hLn */
  4517.     while(EOF != (c = getopt(ac, av, "ce:f:hilLnsvwx"))){
  4518.         switch(c){
  4519.         case 'c': gg.linesonly = 1; break;
  4520.         case 'e': ptn = gg.optarg; break;
  4521.         case 'f':
  4522.             ptn = ptnf = getfpat(gg.optarg);
  4523.             if (ptn == NULL) {
  4524.                 nret = 2; goto EXIT;
  4525.             }
  4526.             break;
  4527.         case 'h': gg.fnmdisp = 0; break;
  4528.         case 'i': gg.nocase = 1; break;
  4529.         case 'l': gg.fnmonly = 1; break;
  4530.         case 'L': gg.fnmdisp = 1; break;
  4531.         case 'n': gg.lnumdisp = 1; break;
  4532.         case 's': gg.retonly = 1; break;
  4533.         case 'v': gg.reverse = 1; break;
  4534.         case 'x': gg.wholematch = 1; break;
  4535.         default:
  4536.             cwFputs("Illegal option.\n", (LPSTR)-1);
  4537.             nret = 2; goto EXIT;
  4538.         }
  4539.     }
  4540.  
  4541.     ac -= gg.optind, av += gg.optind;
  4542.     if(ptn == NULL){
  4543.         if(!ac--) {
  4544.             nret = pempty(); goto EXIT;
  4545.         }
  4546.         ptn = *av++;
  4547.     }
  4548.     if(!*ptn){
  4549.         nret = pempty(); goto EXIT;
  4550.     }
  4551.  
  4552.     if(!ac){
  4553.         if(gg.fnmdisp == -1) gg.fnmdisp = 0;
  4554.         if (efgrep(ptn, "-") != 0) {
  4555.             nret = gg.status; goto EXIT;
  4556.         }
  4557.     } else {
  4558.         if(gg.fnmdisp == -1) gg.fnmdisp = (ac > 1);
  4559.         for(; ac; ac--, av++){
  4560.             name_unixnize(*av);
  4561.             if (efgrep(ptn, *av) != 0) {
  4562.                 nret = gg.status; goto EXIT;
  4563.             }
  4564.         }
  4565.     }
  4566.     if(gg.linesonly && !gg.fnmonly){
  4567.         char buf[0x100];
  4568.         _snprintf(buf, sizeof(buf), "%d\n", gg.totallcount);
  4569.         cwFputs(buf, NULL);
  4570.     }
  4571.     nret = gg.status;
  4572. EXIT:
  4573.     if (ptnf != NULL) free(ptnf);
  4574.     return nret;
  4575. }
  4576.  
  4577. int pempty(void)
  4578. {
  4579.     cwFputs("Pattern empty\n", (LPSTR)-1);
  4580.     return 2;
  4581. }
  4582.  
  4583. int efgrep(char *ptn, char *fnm)
  4584. {
  4585.     int nret = 0;
  4586.     register FILE   *f = NULL;
  4587.     char    lbuf[MAXLEN];
  4588.     register char   *linbuf = lbuf;
  4589.     int linlen, lineno = 0, lcount = 0;
  4590.     char    *dispfnm;
  4591.     int found;
  4592.  
  4593.     if(fnm[0] == '-' && !fnm[1]){
  4594.         fnm = NULL;
  4595.         dispfnm = "(stdin)";
  4596.         f = NULL;
  4597.     } else {
  4598.         if(NULL == (f = fopen(dispfnm = fnm, "r"))){
  4599.             perror(fnm);
  4600.             gg.status = 2;
  4601.             nret = 0; goto EXIT;
  4602.         }
  4603.     }
  4604.     while(((f == NULL) ? cwFgets(linbuf, MAXLEN, NULL) :
  4605.                          fgets(linbuf, MAXLEN, f)) != NULL){
  4606.         if(linlen = strlen(linbuf)){ /* chop newline */
  4607.             if('\n' == (linbuf - 1)[linlen]){
  4608.                 (linbuf - 1)[linlen] = '\0';
  4609.             } else if(linlen == MAXLEN - 1){
  4610.                 cwFputs(dispfnm, (LPSTR)-1);
  4611.                 cwFputs(": too long line\n", (LPSTR)-1);
  4612.                 gg.status = 2;
  4613.                 nret = 2; goto EXIT;
  4614.             }
  4615.         }
  4616.  
  4617.         ++lineno;
  4618.  
  4619.         found = foundline(ptn, linbuf);
  4620.         if (found == -1) {
  4621.             nret = 0; goto EXIT;
  4622.         } else if (found == 1) {
  4623.             if(gg.linesonly){
  4624.                 lcount++;
  4625.                 continue;
  4626.             }
  4627.             if(gg.fnmonly){
  4628.                 cwFputs(dispfnm, NULL);
  4629.                 cwFputs("\n", NULL);
  4630.                 break;
  4631.             }
  4632.  
  4633.             if(gg.fnmdisp){
  4634.                 cwFputs(dispfnm, NULL);
  4635.                 cwFputs(": ", NULL);
  4636.             }
  4637.             if(gg.lnumdisp){
  4638.                 char buf[0x100];
  4639.                 _snprintf(buf, sizeof(buf), "%d: ", lineno);
  4640.                 cwFputs(buf, NULL);
  4641.             }
  4642.             cwFputs(linbuf, NULL), cwFputs("\n", NULL);
  4643.         }
  4644.     }
  4645.  
  4646.     gg.totallcount += lcount;
  4647.      /* totallcount is only used if (linesonly && !fnmonly) */
  4648.     if(gg.linesonly && gg.fnmonly && lcount){
  4649.         char buf[0x400];
  4650.         _snprintf(buf, sizeof(buf), "%s: %d\n", dispfnm, lcount);
  4651.         cwFputs(buf, NULL);
  4652.     }
  4653. EXIT:
  4654.     if(f != NULL) fclose(f);
  4655.     return nret;
  4656. }
  4657.  
  4658. int foundline(char *ptn, char *p)
  4659. /* 条件に適合するかどうか(すれば非0) */
  4660. {
  4661.     int found;
  4662.  
  4663.   /* サーチのアルゴリズムははっきり言って安直です */
  4664.     int cmplen;
  4665.  
  4666.     if(gg.wholematch){
  4667.         found = !(gg.nocase ? stricmp(ptn, p) : strcmp(ptn, p));
  4668.     } else if(gg.nocase){
  4669.         cmplen = strlen(ptn) - 1;
  4670.         found = 0;
  4671.         while(NULL != (p = strichr(p, *ptn))){
  4672.             if(!strnicmp(++p, ptn + 1, cmplen)){
  4673.                 found = 1;
  4674.                 break;
  4675.             }
  4676.         }
  4677.     } else {
  4678.         cmplen = strlen(ptn) - 1;
  4679.         found = 0;
  4680.         while(NULL != (p = strchr(p, *ptn))){
  4681.             if(!strncmp(++p, ptn + 1, cmplen)){
  4682.                 found = 1;
  4683.                 break;
  4684.             }
  4685.         }
  4686.     }
  4687.     if(gg.reverse) found = !found;
  4688.     if(found && gg.status == 1){
  4689.         gg.status = 0;
  4690.         if(gg.retonly) return -1; //exit(status);
  4691.     }
  4692.     return(found);
  4693. }
  4694.  
  4695. /*---------*/
  4696. /* cp_main */
  4697. /*---------*/
  4698. /**
  4699.       'cp':UNIX-like file copy utility for MS-DOS machines.
  4700.  
  4701.       89.02.11 ver 0.0    by Yasushi Saito, TAIST.
  4702.       89.02.12 ver 0.3
  4703.       compiled by Microsoft C compiler ver 5.1
  4704.       compiler changed to LSI-C 3.20
  4705.  
  4706.       1. cp [options] file1 file2
  4707.       2. cp [options] file1 file2 .. filen dir
  4708.  
  4709.       1.      copy file1 to file2
  4710.       2.      copy file1 .. filen to dir by its name.
  4711.  
  4712.       options:
  4713.       -r: Copy directory to directory recursively.
  4714.       -i: Interactive,i.e.,query when overwriting on already existing file.
  4715.       -v: Verbose message.
  4716.       -a: Copy hidden files also.
  4717.  
  4718.       Wildcards can be used to give file or directory name ambiguously.
  4719.       See 'wild.c' for the wildcard specs.
  4720.  
  4721.       This program is NOT COPYRIGHTED,
  4722.       used, modified, re-distributed with no restriction,and no warranty.
  4723. */
  4724.  
  4725.  
  4726. unsigned get_file_status(char *path)
  4727. {
  4728.     char *p;
  4729.  
  4730.     /*
  4731.      * If PATH ends with \, perform no check and return 0x10(DIR)
  4732.      * immediately. Further check will be done by the caller.
  4733.      */
  4734.     if(regularize_pathname(path))
  4735.         return 0x10;
  4736.  
  4737.     p = path + strlen(path) - 1;
  4738.     /*
  4739.      * We have to take special care when the filename end with '\.', or
  4740.      * '\..', or when the filename is "." or ".." or "a:." or "a:..",
  4741.      * because of MS-DOS's bug.
  4742.      */
  4743.     if(*p == '.'){
  4744.         if(p == path ||     /* path=="." */
  4745.            p[-1] == PD ||   /* path=="xxxx\." */
  4746.            p[-1] == ':' && p - 2 == path && isalpha(p[-2]))
  4747.                return 0x10;
  4748.         if(p[-1] == '.'){
  4749.             if(p - 1 == path || /* path==".." *//* Changed Nide */
  4750.                p[-2] == PD ||   /* path=="xxxx\.." */
  4751.                p[-2] == ':' && p - 3 == path && isalpha(p[-3])
  4752.                     /* path=="a:.." */)
  4753.                return 0x10;
  4754.         }
  4755.     }
  4756.     return GetFileAttributes(path);
  4757. }
  4758.  
  4759. char *convert_extention(char *original,
  4760.                         char *new_extention,
  4761.                         char *out)
  4762. {
  4763.     char   *x;
  4764.  
  4765.     strcpy(out, original);
  4766.     x = strrchr(out, '.');
  4767.     if(x == 0){
  4768.         strcat(out, ".");
  4769.         strcat(out, new_extention);
  4770.     } else {
  4771.         strcpy(x + 1, new_extention);
  4772.     }
  4773.     return out;
  4774. }
  4775.  
  4776. int rename_as_backup(char *filename)
  4777. {
  4778.     char buf[PATHNAMELENGTH];
  4779.     convert_extention(filename, "bak", buf);
  4780.     unlink(buf);
  4781.     if(rename(filename, buf)){
  4782.         return 0;
  4783.     }
  4784.     return 1;
  4785. }
  4786.  
  4787. void copy_attribute(char *src, char *dst)
  4788. {    /* Add Nide */
  4789.     long lattr;
  4790.  
  4791.     lattr = GetFileAttributes(src);
  4792.     if (lattr == 0xFFFFFFFF) return;
  4793.     SetFileAttributes(dst, lattr);
  4794. }
  4795.  
  4796. int getfullpath_drive(char *buf, char *path)
  4797. {
  4798.     char temp[PATHNAMELENGTH];
  4799.  
  4800.     if(_fullpath(temp, path, sizeof(temp)) == NULL) {
  4801.         return -1;
  4802.     }
  4803.     if(isalpha(temp[0])){
  4804.         if(buf != NULL) {
  4805.             strcpy(buf, temp + 2);
  4806.         }
  4807.         to_upper(temp[0]);
  4808.         return temp[0] - 'A' + 1;
  4809.     } else {
  4810.         /* network drive, maybe */
  4811.         if(buf != NULL) {
  4812.             strcpy(buf, temp);
  4813.         }
  4814.         return 0;
  4815.     }
  4816. }
  4817.  
  4818. unsigned _dos_getftime(int handle, unsigned *date, unsigned *time)
  4819. {
  4820.     FILETIME ft, ftLocal;
  4821.  
  4822.     GetFileTime((HANDLE)handle, NULL, NULL, &ft);
  4823.     FileTimeToLocalFileTime(&ft, &ftLocal);
  4824.     FileTimeToDosDateTime(&ftLocal, (LPWORD)date, (LPWORD)time);
  4825.     return 0;
  4826. }
  4827.  
  4828. unsigned _dos_setftime(int handle, unsigned date, unsigned time)
  4829. {
  4830.     FILETIME ft, ftLocal;
  4831.  
  4832.     DosDateTimeToFileTime((WORD)date, (WORD)time, &ftLocal);
  4833.     LocalFileTimeToFileTime(&ftLocal, &ft);
  4834.     SetFileTime((HANDLE)handle, NULL, NULL, &ft);
  4835.     return 0;
  4836. }
  4837.  
  4838. void cp_error(char *s, char *s2)
  4839. {
  4840.     char buf[0x100];
  4841.  
  4842.     gg.error_code = 1;
  4843.  
  4844.     _snprintf(buf, sizeof(buf), s, s_conv_to_unix_format(s2));
  4845.     cwFputs(buf, (LPSTR)-1);
  4846.     cwFputs("\n", (LPSTR)-1);
  4847. }
  4848.  
  4849. void cp_io_error(char *s, char *s2)
  4850. {
  4851.     char buf[0x100];
  4852.  
  4853.     gg.error_code = 1;
  4854.  
  4855.     _snprintf(buf, sizeof(buf), s, s_conv_to_unix_format(s2));
  4856.     cwFputs(buf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
  4857. //  perror(" ");
  4858. }
  4859.  
  4860.  
  4861. void verbose_out(char *source, char *dest)
  4862. {
  4863.     char buf[0x100];
  4864.  
  4865.     _snprintf(buf, sizeof(buf), "%s -> ", s_conv_to_unix_format(source));
  4866.     cwFputs(buf, (LPSTR)-1);
  4867.     _snprintf(buf, sizeof(buf), "%s\n", s_conv_to_unix_format(dest));
  4868.     cwFputs(buf, (LPSTR)-1);
  4869. }
  4870.  
  4871. /*
  4872.  * Do copying 'source' to 'dest'.
  4873.  * 
  4874.  */ /* fdとfile handleを混用しているのはオリジナル時代から。まずいかなあ? Nide*/
  4875. int copy_file(char *source, char *dest)
  4876. {
  4877.     int nret = 0;
  4878.     int fds = -1, fdd = -1;
  4879.     unsigned n, dest_stat;
  4880.     struct {unsigned d, t;} src_dt, dest_dt;
  4881.     char buf[0x100];
  4882.  
  4883.     if((fds = _lopen(source, OF_READ)) < 0){
  4884.         cp_io_error("cannot open source '%s'", source);
  4885.         nret = 0; goto EXIT;
  4886.     }
  4887.     _dos_getftime(fds, &src_dt.d, &src_dt.t);
  4888.     if(gg.opt_update && (fdd = _lopen(dest, OF_READ)) >= 0){
  4889.         _dos_getftime(fdd, &dest_dt.d, &dest_dt.t);
  4890.         _lclose(fdd); fdd = -1;
  4891.         if(src_dt.d<dest_dt.d || src_dt.d==dest_dt.d && src_dt.t<=dest_dt.t){
  4892.             nret = 0; goto EXIT;
  4893.         }
  4894.     }
  4895.     if(gg.opt_verbose) verbose_out(source, dest);
  4896.  
  4897.     dest_stat = get_file_status(dest);
  4898.     if(gg.opt_interactive || gg.opt_backup){
  4899.         if(dest_stat != (unsigned) -1){
  4900.             if(gg.opt_backup){
  4901.                 if(gg.opt_verbose){
  4902.                     _snprintf(buf, sizeof(buf), "    (backup %s)",
  4903.                                    s_conv_to_unix_format(dest));
  4904.                     cwFputs(buf, (LPSTR)-1);
  4905.                 }
  4906.                 if(!rename_as_backup(dest)){
  4907.                     cp_io_error("Can't rename", dest);
  4908.                     goto ask;
  4909.                 } else {
  4910.                     dest_stat = (unsigned)-1;
  4911.                 }
  4912.             } else {
  4913.             ask:
  4914.                 _snprintf(buf, sizeof(buf), "file '%s' exists, overwrite? ",
  4915.                                              s_conv_to_unix_format(dest));
  4916.                 cwFputs(buf, (LPSTR)-1);
  4917.                 if(!YES_OR_NO_P()){
  4918.                     nret = 0; goto EXIT;
  4919.                 }
  4920.             }
  4921.         }
  4922.     }
  4923.     if((fdd = _lcreat(dest, 0)) < 0){
  4924.         cp_io_error("cannot open destination '%s'", dest);
  4925.         nret = 0; goto EXIT;
  4926.     }
  4927.     while((n = _lread(fds, gg.copybuf, BUFFERSIZE)) > 0) {
  4928.         if(_lwrite(fdd, gg.copybuf, n) != (int)n){
  4929.             cp_io_error("%s: write error", dest);
  4930.             _lclose(fdd); fdd = -1;
  4931.             unlink(dest);
  4932.             nret = 1; goto EXIT;
  4933.         }
  4934.     }
  4935.     if(gg.opt_preserve){
  4936.         /* set_modification_time(fds, fdd); */
  4937.         _dos_setftime(fdd, src_dt.d, src_dt.t);
  4938.     }
  4939.     if(gg.opt_preserve || dest_stat == (unsigned) -1) {
  4940.         copy_attribute(source, dest);
  4941.     } else {
  4942.         SetFileAttributes(dest, dest_stat & 0x27);
  4943.     /* Check: Is this same as UNIX? (Nide) *//* also check usage */
  4944.     }
  4945. EXIT:
  4946.     if (fds != -1) _lclose(fds);
  4947.     if (fdd != -1) _lclose(fdd);
  4948.     return nret;
  4949. }
  4950.  
  4951. /*
  4952.  * Copy 'source' to 'dest'. Copy recursively if 'source' is a directlry and
  4953.  * 'recursive' option is set.
  4954.  * 
  4955.  */
  4956. int r_copy_file(char *source, char *dest)
  4957. {
  4958.     /* int i; */
  4959.     int nret = 0;
  4960.     int lfind = -1;
  4961.     int dest_status;
  4962.     /* Strip off last \\ in the filename string */
  4963.     regularize_pathname(source);
  4964.     dest_status = regularize_pathname(dest);
  4965.  
  4966.     /*
  4967.      * Check if source and destination are same, or source path is the
  4968.      * part of the destination(recursive copy).
  4969.      */
  4970.     {
  4971.         char    b1[PATHNAMELENGTH], b2[PATHNAMELENGTH];
  4972.         int c, d;
  4973.         if(0 <= (c = getfullpath_drive(b1, source)) &&
  4974.            0 <= (d = getfullpath_drive(b2, dest)) && c == d)
  4975.              /* Mod Nide */ {
  4976.             if(!strcmp(b1, b2)){
  4977.                 cp_error("%s: two files seem to be identical.",
  4978.                      b1);
  4979.                 return 0;
  4980.             } else if(!strncmp(b1, b2, strlen(b1)) &&
  4981.                   ((c = b2[strlen(b1)]) == '\0' || c == PD)){
  4982.                 cp_error("%s: recursive copy", source);
  4983.                 return 0;
  4984.             }
  4985.         }
  4986.     }
  4987.  
  4988.     if(!dest_status){
  4989.         /* PATH does not end with \ */
  4990.         if(!gg.opt_recursive){
  4991.             if (copy_file(source, dest) != 0) {
  4992.                 nret = 1; goto EXIT;
  4993.             }
  4994.             return 0;
  4995.         }
  4996.     } else {
  4997.         if(!gg.opt_recursive){
  4998.             cp_error("'%s' is a directory", dest);
  4999.             return 0;
  5000.         }
  5001.     }
  5002.  
  5003.     {
  5004.         char    temp[PATHNAMELENGTH], tempd[PATHNAMELENGTH];
  5005.         struct  _finddata_t f;
  5006.  
  5007.         verbose_out(source, dest);
  5008.  
  5009.         _snprintf(temp, sizeof(temp), "%s\\%s", source, "*.*");
  5010.         memset(&f, 0, sizeof(f));
  5011.         f.attrib = (opt_all != 0) ? 0x37 : 0x35;
  5012.         lfind = _findfirst(temp, &f);
  5013.         if (lfind == -1) {
  5014.             if (copy_file(source, dest) != 0) {
  5015.                 nret = 1; goto EXIT;
  5016.             }
  5017.         } else {
  5018.             do {
  5019.                 mkdir(dest);    /* If dest already exists,
  5020.                          * the error will occur in
  5021.                          * 'mkdir', but we ignore it. */
  5022.                 /*
  5023.                  * If the first character of the filename is
  5024.                  * '.', then the filename must be "." or ".."
  5025.                  * in MSDOS.
  5026.                  */
  5027.                 if(*(f.name) != '.'){
  5028.                     _snprintf(temp, sizeof(temp), "%s\\%s", source, f.name);
  5029.                     _snprintf(tempd, sizeof(tempd), "%s\\%s", dest, f.name);
  5030.                     if(f.attrib & 0x10) {
  5031.                         if (r_copy_file(temp, tempd) != 0) {
  5032.                             nret = 1; goto EXIT;
  5033.                         }
  5034.                     } else {
  5035.                         if (copy_file(temp, tempd) != 0) {
  5036.                             nret = 1; goto EXIT;
  5037.                         }
  5038.                     }
  5039.                 }
  5040.             } while(_findnext(lfind, &f) == 0);
  5041.             _findclose(lfind); lfind == -1;
  5042.             copy_attribute(source, dest);
  5043.         }
  5044.     }
  5045. EXIT:
  5046.     if (lfind != -1) _findclose(lfind);
  5047.     return nret;
  5048. }
  5049.  
  5050. char *strip_directory_part(char *path)
  5051. {
  5052.     char *b = path;
  5053.     while(*path){
  5054.         if(iskanjipos(path))
  5055.             path++;
  5056.         else if(*path == PD || *path == ':')
  5057.             b = path + 1;
  5058.             path++;
  5059.     }
  5060.     return (char *) b;
  5061. }
  5062.  
  5063. int multifile_copy(int filenum, char **filevec)
  5064. {
  5065.     char    buf[PATHNAMELENGTH];
  5066.     int i;
  5067.     for(i = 0; i < filenum - 1; i++){
  5068.         _snprintf(buf, sizeof(buf), "%s\\%s",
  5069.                   filevec[filenum - 1], strip_directory_part(filevec[i]));
  5070.         if (r_copy_file(filevec[i], buf) != 0) return 1;
  5071.     }
  5072.     return 0;
  5073. }
  5074.  
  5075. int cp_main(int argc, char **argv)
  5076. {
  5077.     int c;
  5078.     unsigned mode;
  5079. //  extern int optind, opterr;
  5080. //  extern char *optarg;
  5081.  
  5082.     conv_char_args(argv, '/', '\\');
  5083.  
  5084.     gg.opterr = 0;
  5085.  
  5086.     gg.opt_recursive = gg.opt_verbose = gg.opt_interactive = FALSE;
  5087.     while((c = getopt(argc, argv, "rvaibpu")) != EOF){
  5088.         switch (c){
  5089.         case 'r':
  5090.             gg.opt_recursive = TRUE;
  5091.             break;
  5092.         case 'v':
  5093.             gg.opt_verbose = TRUE;
  5094.             break;
  5095.         case 'i':
  5096.             gg.opt_interactive = TRUE;
  5097.             break;
  5098.         case 'a':
  5099.             /* opt_all = TRUE; */
  5100.             cwFputs("Warning: 'a' option is obsolete\n", (LPSTR)-1);
  5101.             break;
  5102.         case 'b':
  5103.             gg.opt_backup = TRUE;
  5104.             break;
  5105.         case 'p':
  5106.             gg.opt_preserve = TRUE;
  5107.             break;
  5108.             /* I use "alias cp cp -p" :-) */
  5109.         case 'u': /* Nide */
  5110.             gg.opt_update = TRUE;
  5111.             break;
  5112.         default:
  5113.             return cp_usage();
  5114.         }
  5115.     }
  5116.  
  5117.     argc -= gg.optind;
  5118.     argv += gg.optind;
  5119.  
  5120.     if(argc < 2)
  5121.         return cp_usage();
  5122.     else {
  5123.         if(regularize_pathname(argv[argc - 1])) {
  5124.             if (multifile_copy(argc, argv) != 0) return 1;
  5125.         } else {
  5126.             mode = get_file_status(argv[argc - 1]);
  5127.             if(argc >= 3){
  5128.                 if(mode == (unsigned) (-1) || !(mode & 0x10))
  5129.                     return cp_usage();
  5130.                 if (multifile_copy(argc, argv) != 0) return 1;
  5131.             } else {/* argc==2 */
  5132.                 /*
  5133.                  * See if the last argument is directory or
  5134.                  * not.
  5135.                  */
  5136.                 if(mode != (unsigned) (-1) && (mode & 0x10)){
  5137.                     if (multifile_copy(argc, argv) != 0) return 1;
  5138.                 } else {
  5139.                     if (r_copy_file(argv[0], argv[1]) != 0) return 1;
  5140.                 }
  5141.             }
  5142.         }
  5143.     }
  5144.     return gg.error_code;
  5145. }
  5146.  
  5147. int cp_usage(void)
  5148.  /* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
  5149. {               
  5150.     static char *msgs[] = {
  5151.         "1. cp [-rivbpu] file1 ... filen directory\n",
  5152.         "2. cp [-rivbpu] file1 file2\n",
  5153.         "-r : copy all files under directory\n",
  5154.         "-i : ask when overwriting on existing file\n",
  5155.          /* "-a : copy hidden files also\n", */
  5156.         "-v : verbose message\n",
  5157.         "-b : make backup when overwriting on existing file\n",
  5158.         "-p : preserve file attribute and modification time\n",
  5159.         "-u : update (copy only newer file)\n",
  5160.     };
  5161.     int i;
  5162.  
  5163.     for(i = 0; i < sizeof(msgs) / sizeof(*msgs); i++)
  5164.         cwFputs(msgs[i], (LPSTR)-1);
  5165.     return 2;
  5166. }
  5167.  
  5168. /*------------*/
  5169. /* touch_main */
  5170. /*------------*/
  5171. /*
  5172.     touch…ファイルの更新時刻のセット
  5173.                 nide@ics.nara-wu.ac.jpによる新版
  5174.  
  5175.     usage: touch [-cfd] [mmdd[hhmm[[ss]yy]]] file1 file2…
  5176.            touch [-cfd] [-t filename] file1 file2…
  5177.  
  5178.     時刻指定は年月日時分秒の順ではなく、月日時分秒年の順なので注意。
  5179.     時刻指定がなければ現在の時刻にセット。
  5180.     -c…ファイルがない場合作成しない。
  5181.     -t…指定したファイルと同じ更新時刻にする。
  5182.     -f…更新に失敗したファイルがあっても停止しない。
  5183.     -d…ディレクトリやボリュームラベルであっても時刻を設定する。
  5184. */
  5185.  
  5186. /* ----------------- 以下はUNIXと共用のソースによる旧版 -----------------
  5187.     usage: touch [-cf] [mmdd[hhmm[[ss]yy]]] file1 file2…
  5188.            touch [-cf] [-t filename] file1 file2…
  5189. */
  5190. #include <sys/utime.h>
  5191.  
  5192.  
  5193. int digitonly(char *s)
  5194. {
  5195.     for(; *s; s++) if(!is_digit(*s)) return(0);
  5196.     return(1);
  5197. }
  5198.  
  5199. int time_t_to_dosdatetime(time_t *time, LPWORD dos_date, LPWORD dos_time)
  5200. {
  5201.     FILETIME ft;
  5202.     SYSTEMTIME st;
  5203.     struct tm *lptm;
  5204.  
  5205.     lptm = localtime(time);
  5206.     st.wYear         = lptm->tm_year + 1900;
  5207.     st.wMonth        = lptm->tm_mon + 1;
  5208.     st.wDayOfWeek    = lptm->tm_wday;
  5209.     st.wDay          = lptm->tm_mday;
  5210.     st.wHour         = lptm->tm_hour;
  5211.     st.wMinute       = lptm->tm_min;
  5212.     st.wSecond       = lptm->tm_sec;
  5213.     st.wMilliseconds = 0;
  5214.  
  5215.     SystemTimeToFileTime(&st, &ft);
  5216.     FileTimeToDosDateTime(&ft, dos_date, dos_time);
  5217.     return 0;
  5218. }
  5219.  
  5220. int dosdatetime_to_time_t(unsigned dos_date, unsigned dos_time, time_t *time)
  5221. {
  5222.     FILETIME ft;
  5223.     SYSTEMTIME st;
  5224.     struct tm tm;
  5225.  
  5226.     DosDateTimeToFileTime((WORD)dos_date, (WORD)dos_time, &ft);
  5227.     FileTimeToSystemTime(&ft, &st);
  5228.  
  5229.     tm.tm_year = st.wYear - 1900;
  5230.     tm.tm_mon = st.wMonth - 1;
  5231.     tm.tm_wday = st.wDayOfWeek;
  5232.     tm.tm_mday = st.wDay;
  5233.     tm.tm_hour = st.wHour;
  5234.     tm.tm_min = st.wMinute;
  5235.     tm.tm_sec = st.wSecond;
  5236.  
  5237.     *time = mktime(&tm);
  5238.     return 0;
  5239. }
  5240.  
  5241. int touch_utime(char *filename, struct utimbuf *times)
  5242. {
  5243.     HFILE hFile;
  5244.     FILETIME ft;
  5245.     SYSTEMTIME st;
  5246.     struct tm *lptm;
  5247.     BOOL fRet;
  5248.  
  5249.     lptm = gmtime(×->modtime);
  5250.     st.wYear         = lptm->tm_year + 1900;
  5251.     st.wMonth        = lptm->tm_mon + 1;
  5252.     st.wDayOfWeek    = lptm->tm_wday;
  5253.     st.wDay          = lptm->tm_mday;
  5254.     st.wHour         = lptm->tm_hour;
  5255.     st.wMinute       = lptm->tm_min;
  5256.     st.wSecond       = lptm->tm_sec;
  5257.     st.wMilliseconds = 0;
  5258.  
  5259.     SystemTimeToFileTime(&st, &ft);
  5260.  
  5261.     hFile = _lopen(filename, OF_READWRITE);
  5262.     fRet = SetFileTime((HANDLE)hFile, NULL, NULL, &ft);
  5263.     _lclose(hFile);
  5264.  
  5265.     return (fRet == TRUE) ? 0 : -1;
  5266. }
  5267.  
  5268. int touch_main(int ac, char **av)
  5269. {
  5270.     int c;
  5271. //  extern  int optind, opterr;
  5272. //  extern  char    *optarg;
  5273.  
  5274.     int fmake = 1, force = 0, status = 0, tmpfd;
  5275.     char    *fromfnm = NULL;
  5276.     struct  utimbuf *utimearg, utimestr;
  5277.     struct  stat    statstr;
  5278.  
  5279.     while(EOF != (c = getopt(ac, av, "cft:"))){
  5280.         switch(c){
  5281.         case 'f': force = 1; break;
  5282.         case 'c': fmake = 0; break;
  5283.         case 't': fromfnm = gg.optarg; break;
  5284.         default: return touch_usage();
  5285.         }
  5286.     }
  5287.     ac -= gg.optind, av += gg.optind;
  5288.     if(!ac) return touch_usage();
  5289.  
  5290.     if(fromfnm != NULL){
  5291.         utimearg = &utimestr;
  5292.         if(0 != stat(fromfnm, &statstr)){
  5293.             cwFputs(name_unixnize(fromfnm), (LPSTR)-1);
  5294.             cwFputs(": Can't stat\n", (LPSTR)-1);
  5295.             return 1;
  5296.         }
  5297.         utimestr.modtime = statstr.st_mtime;
  5298.     } else if(/* ac && */ digitonly(*av)){
  5299.         utimearg = &utimestr;
  5300.         if (readtime(*av, utimearg) != 0) return 1;
  5301.         ac--, av++;
  5302.         if(!ac) return touch_usage();
  5303.     } else {
  5304.         /* utimearg = NULL; */
  5305.         utimearg = &utimestr;
  5306.         time(&utimestr.modtime);
  5307.     }
  5308.  
  5309.     for(; ac; ac--, av++){
  5310.         if(0 == touch_utime(*av, utimearg)) continue;
  5311.  
  5312.         name_unixnize(*av);
  5313.  
  5314.         if(!fmake){
  5315.             cwFputs(*av, (LPSTR)-1), cwFputs(": Can't touch\n", (LPSTR)-1);
  5316.             if(!force) {
  5317.                 return 1;
  5318.             } else {
  5319.                 status = 1;
  5320.             }
  5321.         } else if(0 <= (tmpfd = open(*av, O_CREAT | O_EXCL, 0644))){
  5322.             close(tmpfd);
  5323.             setattr(*av, 0x20);
  5324.             touch_utime(*av, utimearg);
  5325.         } else {
  5326.             cwFputs(*av, (LPSTR)-1);
  5327.             cwFputs(": Can't open\n", (LPSTR)-1);
  5328.             if(!force) {
  5329.                 return 1;
  5330.             } else {
  5331.                 status = 1;
  5332.             }
  5333.         }
  5334.     }
  5335.  
  5336.     return status;
  5337. }
  5338.  
  5339.  
  5340. int readtime(char *str, struct utimbuf *utimearg) /*str:数字ばかりの文字列*/
  5341. {
  5342.     int y, m = 1, d = 1, h = 0, mn = 0, s = 0;
  5343.     int yget = 0, l;
  5344.     ulong   datetime;
  5345.  
  5346.     switch(l = strlen(str)){
  5347.     case 12: s = ctoi(str[8]) * 10 + ctoi(str[9]); /* through */
  5348.     case 10: y = ctoi(str[l-2])*10 + ctoi(str[l-1]); yget = 1; /* through */
  5349.     case 8: mn = ctoi(str[6]) * 10 + ctoi(str[7]);
  5350.          h = ctoi(str[4]) * 10 + ctoi(str[5]); /* through */
  5351.     case 4:  d = ctoi(str[2]) * 10 + ctoi(str[3]);
  5352.          m = ctoi(str[0]) * 10 + ctoi(str[1]); /* through */
  5353.          break;
  5354.     default:
  5355.         return illdate();
  5356.     }
  5357.     if(!yget){
  5358.         long    ltime;
  5359.         struct  tm  *timeptr;
  5360.  
  5361.         time(<ime);
  5362.         timeptr = localtime(<ime);
  5363.         y = timeptr->tm_year;
  5364.     }
  5365.     if(y >= 80) y += 1900; else y += 2000;
  5366.     datetime = caldate(y, m, d);
  5367.     if(!(1 <= m && m <= 12 &&
  5368.          1 <= d && (long)datetime <
  5369.             (m == 12? caldate(y + 1, 1, 1) : caldate(y, m + 1, 1)) &&
  5370.          0 <= h && h < 24 &&
  5371.          0 <= mn && mn < 60 &&
  5372.          0 <= s && s < 60)) return illdate();
  5373.  
  5374.     datetime -= caldate(1970, 1, 1);
  5375.     datetime *= 24L * 60L * 60L;
  5376.     datetime += (ulong)(h - 17) * 3600L + (ulong)mn * 60L + (ulong)s; /*-17 ?*/
  5377.     datetime += timezone; /* if timezone is not extern long in your
  5378.       system, you must modify here */
  5379.     utimearg->modtime = (time_t)datetime;
  5380.     return 0;
  5381. }
  5382.  
  5383. int touch_usage(void)
  5384. {
  5385.     cwFputs("Usage: touch [-cf] [mmdd[hhmm[[ss]yy]]] file...\n", (LPSTR)-1);
  5386.     cwFputs("       touch [-cf] [-t filename] file...\n", (LPSTR)-1);
  5387.     cwFputs("-c : no create\n", (LPSTR)-1);
  5388.     cwFputs("-f : no errors\n", (LPSTR)-1);
  5389.     cwFputs("-t : copy time-stamp from the specified file\n", (LPSTR)-1);
  5390.     return -1;
  5391. }
  5392.  
  5393. /*-----------*/
  5394. /* join_main */ /* メモリ解放が完全でない */
  5395. /*-----------*/
  5396. /* -a123 -estr -j[12]m -o x.y x.y... -tc f1 f2  */
  5397.  
  5398. int join_usage(void)
  5399. {
  5400.     cwFputs("Usage: join [-a n] [-e string] [-j[1|2] m]\n", (LPSTR)-1);
  5401.     cwFputs("\t    [-o fieldlist] [-t c] file1 file2\n", (LPSTR)-1);
  5402.     return 1;
  5403. }
  5404.  
  5405. char *strsave(char *s)
  5406. {
  5407.     char    *p;
  5408.  
  5409.     if(NULL != (p = malloc(strlen(s) + 1))) strcpy(p, s);
  5410.     return p;
  5411. }
  5412.  
  5413. int nomem(void)
  5414. {
  5415.     _putnomemmes();
  5416.     return 1;
  5417. }
  5418.  
  5419. int outfreg(char *p)
  5420. {
  5421.     gg.outlist = (outfieldstr *)(gg.outlistlen ?
  5422.         realloc((char *)gg.outlist, (gg.outlistlen+1)*sizeof(outfieldstr)) :
  5423.         malloc(sizeof(outfieldstr)));
  5424.     if(NULL == gg.outlist) return nomem();
  5425.  
  5426.     gg.outlist[gg.outlistlen] . fno = *p - '1';
  5427.     if(*p != '1' && *p != '2' || *++p != '.' || !*++p) return join_usage();
  5428.     if(0 > (gg.outlist[gg.outlistlen].field = atoi(p)-1)) return join_usage();
  5429.     while(isdigit(*p)) p++;
  5430.     if(*p) return join_usage();
  5431.  
  5432.     gg.outlistlen++;
  5433.     return 0;
  5434. }
  5435.  
  5436. char *readnthfile(int nth)
  5437. {
  5438.     int len;
  5439.     char    *buf;
  5440.  
  5441.     buf = (gg.inf[nth] == NULL) ? cwFgets(gg.linbuf[nth], LINMAX, NULL) :
  5442.                                   fgets(gg.linbuf[nth], LINMAX, gg.inf[nth]);
  5443.     if (buf != NULL) {
  5444.         if(!*buf){ /* nothing */
  5445.         } else if(len = strlen(buf), buf[--len] != '\n'){
  5446.             cwFputs(gg.infnm[nth], (LPSTR)-1);
  5447.             if(len == LINMAX - 2){
  5448.                 cwFputs(": line too long\n", (LPSTR)-1);
  5449.                 return (LPSTR)-1;
  5450.             } else {
  5451.                 cwFputs(": missing line-feed character "
  5452.                       "added at the end of file\n", (LPSTR)-1);
  5453.             }
  5454.         } else {
  5455.             buf[len] = '\0';
  5456.         }
  5457.     }
  5458.     return buf;
  5459. }
  5460.  
  5461. char *fieldend(char *p)
  5462.  /* pがフィールド内ならその末尾の直後、さもないとそのままを返す */
  5463. {
  5464.     if(*gg.fieldsep){
  5465.         for(; *p; iskanjipos(p) ? (p += 2) : p++){
  5466.             if(*gg.fieldsep == *p &&
  5467.                (!gg.fieldsep[1] || gg.fieldsep[1] == p[1])) break;
  5468.         }
  5469.     } else {
  5470.         while(*p && !is_space(*p)) p++;
  5471.     }
  5472.     return p;
  5473. }
  5474.  
  5475. char *fieldtop(char *p)
  5476.  /* pがタブ文字上なら次のフィールドの先頭、さもないとそのままを返す */
  5477. {
  5478.     if(*gg.fieldsep){
  5479.         if(*gg.fieldsep == *p){
  5480.             if(gg.fieldsep[1]){
  5481.                 if(gg.fieldsep[1] == p[1]) p += 2;
  5482.             } else p++;
  5483.         }
  5484.     } else {
  5485.         while(is_space(*p)) p++;
  5486.     }
  5487.     return p;
  5488. }
  5489.  
  5490. char *fieldnth(char *p, int n)
  5491. {
  5492.     if(!*gg.fieldsep) p = fieldtop(p);
  5493.     while(n--) p = fieldnext(p);
  5494.     return p;
  5495. }
  5496.  
  5497. int do_join(char **infnm)
  5498. {
  5499.     int nret = 0;
  5500.     char    *f2b, *f2e, *f2line = NULL, *f1line;
  5501.     char    *f2linenew;
  5502.     char    **f2bufs = NULL; /* f2bufs, f2bufcntはstaticでなくていい? */
  5503.     char    **f2bufsnew;
  5504.     int f2bufcnt = 0, f2bufused = 0;
  5505.     char    f2eof = 0, f2pushed = 0, f1eof = 0, f1pushed = 0, f1match;
  5506.     int i;
  5507.  
  5508.     for(i = 0; i < 2; i++){
  5509.         if(infnm[i][0] == '-' && !infnm[i][1]){
  5510.             gg.inf[i] = NULL; infnm[i] = "(stdin)";
  5511.         } else if(NULL == (gg.inf[i] = fopen(infnm[i], "r"))){
  5512.             cwFputs(infnm[i], (LPSTR)-1);
  5513.             cwFputs(": Can't open\n", (LPSTR)-1);
  5514.             nret = 1; goto EXIT;
  5515.         } else {
  5516.             conv_to_unix_format(infnm[i]);
  5517.         }
  5518.     }
  5519.  
  5520.     /* malloc sizeは適当に決めた。あとでの増加単位も適当 */
  5521.     if(NULL == (f2bufs = (char **)
  5522.             malloc(sizeof(char *) * (f2bufcnt = 50)))) {
  5523.         nret = nomem(); goto EXIT;
  5524.     }
  5525.     for(;;){
  5526.          /* 前に読んだ行の掃除。直前に読んだ行はf2lineにあり */
  5527.         if(f2bufcnt > 200 &&
  5528.            f2bufused < 100 && f2bufused * 3 < f2bufcnt){
  5529.             f2bufsnew = (char **)realloc((char *)f2bufs,
  5530.                         sizeof(char *) * (f2bufcnt = 200));
  5531.              /* 現f2bufused以上は確保すること */
  5532.             if(f2bufsnew == NULL) {
  5533.                 nret = nomem(); goto EXIT;
  5534.             } else {
  5535.                 f2bufsnew = f2bufs;
  5536.             }
  5537.         }
  5538.         while(f2bufused) free(f2bufs[--f2bufused]);
  5539.          /* f2bufusedは0になる */
  5540.  
  5541.         while(!f2eof){
  5542.             if(f2pushed){
  5543.                 f2pushed = 0;
  5544.             } else {
  5545.                 f2line = readnthfile(1);
  5546.                 if (f2line == (LPSTR)-1) {
  5547.                     nret = 1; goto EXIT;
  5548.                 }
  5549.                 if(NULL == f2line){
  5550.                     f2eof++;
  5551.                     break;
  5552.                 }
  5553.             }
  5554.  
  5555.             if(!f2bufused){ /* 一致する一連の行のうち最初 */
  5556.                 f2linenew = strsave(f2line);
  5557.                 if (f2linenew == NULL) {
  5558.                     nret = nomem(); goto EXIT;
  5559.                 } else {
  5560.                     f2line = f2linenew;
  5561.                 }
  5562.                  /* 先にstrsaveしないとf2b, f2eが狂う */
  5563.                 f2bufs[f2bufused++] = f2line;
  5564.                 f2b = fieldnth(f2line, gg.joinfield[1]);
  5565.                 f2e = fieldend(f2b);
  5566.             } else {
  5567.                 if(strfieldcmp(f2b, f2e, f2line, gg.joinfield[1])){
  5568.                     f2pushed = 1;
  5569.                      /* 今の行をf2lineつまりlinbuf[1]に
  5570.                         残しておく */
  5571.                     break;
  5572.                 } else { /* 一致 */
  5573.                     if(f2bufused >= f2bufcnt){
  5574.                         f2bufsnew = (char **)realloc((char *)f2bufs, 
  5575.                                           sizeof(char *) *(f2bufcnt += 20));
  5576.                         if(f2bufsnew == NULL) {
  5577.                             nret = nomem(); goto EXIT;
  5578.                         } else {
  5579.                             f2bufs = f2bufsnew;
  5580.                         }
  5581.                     }
  5582.                     if(NULL == (f2bufs[f2bufused++] = strsave(f2line))) {
  5583.                         nret = nomem(); goto EXIT;
  5584.                     }
  5585.                 }
  5586.             }
  5587.         }
  5588.  
  5589.         for(f1match = 0; ;){
  5590.             if(f1pushed){
  5591.                 f1pushed = 0;
  5592.             } else if(!f1eof){
  5593.                 f1line = readnthfile(0);
  5594.                 if (f1line == (LPSTR)-1) {
  5595.                     nret = 1; goto EXIT;
  5596.                 }
  5597.                 if(f1line == NULL) {
  5598.                     f1eof++;
  5599.                 }
  5600.             }
  5601.             if(f1eof && !f2bufused) {
  5602.                 nret = 0; goto EXIT;
  5603.             }
  5604.             i = !f2bufused ? /* 読み尽くした方が大 */ 1 :
  5605.                 f1eof ? -1 :
  5606.                 strfieldcmp(f2b, f2e, f1line, gg.joinfield[0]);
  5607.  
  5608.             if(i > 0){ /* f2が大。f1側出力 */
  5609.                 if(gg.addwidow & 01) {
  5610.                     fieldout(f1line, "", 1);
  5611.                 }
  5612.             } else if(i == 0){ /* 同じ。全f2bufsに対し組み合わせを出力 */
  5613.                 f1match = 1;
  5614.                 for(i = 0; i < f2bufused; i++) {
  5615.                     fieldout(f1line, f2bufs[i], 3);
  5616.                 }
  5617.             } else if(i < 0){ /* f1が大。f2側出力 */
  5618.                 if(!f1match && (gg.addwidow & 02)){
  5619.                     for(i = 0; i < f2bufused; i++) {
  5620.                         fieldout("", f2bufs[i], 2);
  5621.                     }
  5622.                 }
  5623.                 f1pushed = 1;
  5624.                  /* 現在行をf1lineつまりlinbuf[0]に残す */
  5625.                 break;
  5626.             }
  5627.         }
  5628.     }
  5629. EXIT:
  5630.     if (f2bufs != NULL) free(f2bufs);
  5631.     if (f2line != NULL) free(f2line);
  5632.     for (i = 0; i < 2; i++) {
  5633.         if (gg.inf[i] != NULL) fclose(gg.inf[i]); gg.inf[i] = NULL;
  5634.     }
  5635.     return nret;
  5636. }
  5637.  
  5638. void fieldeach(char *p)
  5639. {
  5640.     char    *q;
  5641.     char buf[0x100];
  5642.  
  5643.     if (p < (q = fieldend(p))) {
  5644.         _snprintf(buf, sizeof(buf), "%.*s", q - p, p);
  5645.         cwFputs(buf, NULL);
  5646.     } else {
  5647.         cwFputs(gg.emptyfill, NULL);
  5648.     }
  5649. }
  5650.  
  5651. void fieldout(char *s1, char *s2, int flag)
  5652. {
  5653.     int curf[2], i, outfirst, f_no, f_field;
  5654.     char    *ftop[2], *ltop[2], *p;
  5655.     char buf[0x100];
  5656.  
  5657.     curf[0] = curf[1] = 0;
  5658.     ltop[0] = ftop[0] = s1, ltop[1] = ftop[1] = s2;
  5659.  
  5660.     if(!gg.outlistlen){ /* outlistlenが0なら全部出力 */
  5661.         f_no = (flag & 01) ? 0 : 1;
  5662.         f_field = gg.joinfield[f_no];
  5663.         fieldeach(fieldnth(ltop[f_no], f_field));
  5664.         for(f_no = 0; f_no < 2; f_no++){
  5665.             f_field = gg.joinfield[f_no];
  5666.             for(i = 0, p = fieldnth(ltop[f_no], 0); *p;
  5667.                 i++, p = fieldnext(p)){
  5668.                 if(i != f_field){
  5669.                     _snprintf(buf, sizeof(buf), "%.2s",
  5670.                               *gg.fieldsep ? gg.fieldsep : " ");
  5671.                     cwFputs(buf, NULL);
  5672.                     fieldeach(p);
  5673.                 }
  5674.             }
  5675.         }
  5676.     } else {
  5677.         for(outfirst = 1, i = 0; i < gg.outlistlen; i++){
  5678.             f_no = gg.outlist[i] . fno;
  5679.             f_field = gg.outlist[i] . field;
  5680.             if(curf[f_no] > f_field){
  5681.                 p = fieldnth(ltop[f_no], f_field);
  5682.             } else {
  5683.                 p = fieldnth(ftop[f_no], f_field - curf[f_no]);
  5684.             }
  5685.             outfirst ? outfirst = 0 :
  5686.                _snprintf(buf, sizeof(buf), "%.2s",
  5687.                          *gg.fieldsep ? gg.fieldsep : " ");
  5688.             cwFputs(buf, NULL);
  5689.  
  5690.             fieldeach(ftop[f_no] = p), 
  5691.             curf[f_no] = f_field;
  5692.         }
  5693.     }
  5694.     cwFputs("\n", NULL);
  5695. }
  5696.  
  5697. int strfieldcmp(char *fb, char *fe, char *p, int n)
  5698. {
  5699.     char    *pe;
  5700.  
  5701.     p = fieldnth(p, n), pe = fieldend(p);
  5702.     return strpartcmp(fb, fe - fb, p, pe - p);
  5703. }
  5704.  
  5705. int strpartcmp(char *p, int m, char *q, int n)
  5706. {
  5707.     int result;
  5708.  
  5709.     if(0 != (result = strncmp(p, q, m < n ? m : n))) return result;
  5710.     return m - n;
  5711. }
  5712.  
  5713. int join_main(int ac, char **av)
  5714. {
  5715.     char    **origav, *p;
  5716.  
  5717.     origav = av;
  5718.     while(++av, --ac){
  5719.         if('-' != *(p = *av) || !p[1]) break;
  5720.         if(*++p == '-') {++av, --ac; break;}
  5721.         switch(*p){
  5722.         case 'a':
  5723.             if(!*++p){
  5724.                 if(++av, !--ac) {
  5725.                     return join_usage();
  5726.                 } else {
  5727.                     p = *av;
  5728.                 }
  5729.             }
  5730.             if(*p < '1' || '3' < *p || p[1]) return join_usage();
  5731.             gg.addwidow = *p - '0';
  5732.             break;
  5733.         case 'e':
  5734.             if(!*++p){
  5735.                 if(++av, !--ac) {
  5736.                     return join_usage();
  5737.                 } else {
  5738.                     p = *av;
  5739.                 }
  5740.             }
  5741.             gg.emptyfill = p;
  5742.             break;
  5743.         case 'j':
  5744.             if(*++p && (*p < '1' || '2' < *p || p[1])) return join_usage();
  5745.             if(++av, !--ac) return join_usage();
  5746.             {
  5747.                 int fi;
  5748.  
  5749.                 if(0 > (fi = atoi(*av) - 1)) return join_usage();
  5750.                 switch(*p){
  5751.                 case '1': gg.joinfield[0] = fi; break;
  5752.                 case '2': gg.joinfield[1] = fi; break;
  5753.                 default:
  5754.                     gg.joinfield[0]= gg.joinfield[1]= fi; break;
  5755.                 }
  5756.             }
  5757.             break;
  5758.         case 'o':
  5759.             if(*++p || ac == 1 || (++av, --ac, !isdigit(**av))) {
  5760.                 return join_usage(); /* 最低1つないとだめ */
  5761.             }
  5762.             for(; ac; ++av, --ac){
  5763.                 if(p = *av, !isdigit(*p)) break;
  5764.                 if (outfreg(p) != 0) return 1;
  5765.             }
  5766.             ++ac, --av; /* 1つ戻す */
  5767.             break;
  5768.         case 't':
  5769.             if(!*++p){
  5770.                 if(av++, !--ac) return join_usage();
  5771.                 p = *av;
  5772.                 if(!*p) return join_usage();
  5773.             }
  5774.             gg.fieldsep[0] = *p;
  5775.             if(iskanji(*p)) {
  5776.                 gg.fieldsep[1] = *++p;
  5777.             } else {
  5778.                 gg.fieldsep[1] = '\0';
  5779.             }
  5780.             if(p[1]) return join_usage();
  5781.             break;
  5782.         default:
  5783.             return join_usage();
  5784.         }
  5785.     }
  5786.     if(ac != 2) return join_usage();
  5787.     return do_join(av);
  5788. }
  5789.  
  5790. /*---------*/
  5791. /* mv_main */
  5792. /*---------*/
  5793. /**
  5794.       'mv':UNIX-like file move utility for MS-DOS machines.
  5795.  
  5796.       89.03.29 ver 0.0    by Yasushi Saito, TAIST.
  5797.       90.04.02 ver 1.0    Directory->directory move.
  5798.       90.10.12        Bug removed in '-f'.
  5799.  
  5800.       Now mv can move the file if destination is readonly.
  5801.  
  5802.       compiled by Microsoft C compiler ver 5.1
  5803.       compiler changed to LSI-C 3.20
  5804.  
  5805.       1. mv [-fvi] file1 file2
  5806.       2. mv [-fvi] file1 file2 .. filen dir
  5807.  
  5808.       1.      move file1 to file2
  5809.       2.      move file1 .. filen to dir by its name.
  5810.  
  5811.       options:
  5812.       -i: Interactive. Ask when overwriting on already existing files.
  5813.       -f: Force.
  5814.       -v: Verbose message.
  5815.  
  5816.       Wildcards can be used to give file or directory name ambiguously.
  5817.       See 'wild.c' for the wildcard specs.
  5818.  
  5819.       This program is in public domain.
  5820.       Used, modified, re-distributed with no restriction,and no warranty.
  5821. */
  5822.  
  5823.  
  5824. /*
  5825.  * Error reporting.
  5826.  */
  5827.  
  5828. void mv_error(char *s, char *s2)
  5829. {
  5830.     char buf[0x100];
  5831.  
  5832.     if(gg.force) return;
  5833.     _snprintf(buf, sizeof(buf), s, s_conv_to_unix_format(s2));
  5834.     cwFputs(buf, (LPSTR)-1);
  5835.     cwFputs("\n", (LPSTR)-1);
  5836.     gg.error_code = 1;
  5837. }
  5838.  
  5839.  
  5840. /*
  5841.  * Move SOURCE to DEST.
  5842.  */ /* fdとfile handleを混用しているのはオリジナル時代から。まずいかなあ? Nide*/
  5843. int move_file(char *source, char *dest)
  5844. {
  5845.     int nret;
  5846.     int fds = -1, fdd = -1;   /* File descriptor for each file. */
  5847.     char    disks, diskd;   /* Device name for each file */
  5848.     unsigned modes, moded;  /* File attribute for each file */
  5849.     struct {unsigned d, t;} dates, dated;
  5850.                 /* File time for each file */
  5851.     unsigned n;     /* Counter when copying */
  5852.     char buf[0x100];
  5853.     long lfind = -1;
  5854.  
  5855.     modes = get_file_status(source);
  5856.     moded = get_file_status(dest);
  5857.  
  5858.     /*
  5859.      * Check the attribute of each file and do pre-processing.
  5860.      * 
  5861.      */
  5862.     if(modes == (unsigned) -1){
  5863.         mv_error("%s does not exist.", source);
  5864.         nret = 0; goto EXIT;
  5865.     }
  5866.     /* Check if two files are the same */
  5867.     {
  5868.         char    b1[PATHNAMELENGTH], b2[PATHNAMELENGTH];
  5869.         int c, d;
  5870.  
  5871.         if(0 <= (c = getfullpath_drive(b1, source)) &&
  5872.            0 <= (d = getfullpath_drive(b2, dest)) && c == d)
  5873.              /* Mod Nide */ {
  5874.             if(!strcmp(b1, b2)){
  5875.                 mv_error("%s: two files seem to be identical.", b1);
  5876.                 nret = 0; goto EXIT;
  5877.             } else if(!strncmp(b1, b2, strlen(b1)) &&
  5878.                       (!(c = b2[strlen(b1)]) || c == '/' || c == '\\')){
  5879.                 mv_error("%s: recursive move", source);
  5880.                 nret = 0; goto EXIT;
  5881.             }
  5882.         }
  5883.     }
  5884.  
  5885.     if(IS_DIRECTORY(modes)){
  5886.         /* move directory */
  5887.         struct _finddata_t f;
  5888.         unsigned char s[PATHNAMELENGTH], ss[PATHNAMELENGTH],
  5889.                   dd[PATHNAMELENGTH];
  5890.  
  5891.         if(gg.verbose) verbose_out(source, dest);
  5892.         if(moded != (unsigned) -1){
  5893.             /*
  5894.              * Do not move when destination directory already
  5895.              * exists
  5896.              */
  5897.             mv_error("destination '%s':"
  5898.                      " cannot move directory to existent file.", dest);
  5899.             nret = 0; goto EXIT;
  5900.         }
  5901.         if(mkdir(dest)){
  5902.             /* Failed on making destination directory */
  5903.             mv_error("cannot make directory '%s'", dest);
  5904.             nret = 0; goto EXIT;
  5905.         }
  5906.         /*
  5907.          * Read the filenames contained in the source directory and
  5908.          * recursively move each files.
  5909.          */
  5910.         _snprintf(s, sizeof(s), "%s\\%s", source, "*.*");
  5911.         memset(&f, 0, sizeof(f));
  5912.         f.attrib = 0x16;
  5913.         lfind = _findfirst(s, &f);
  5914.         if (lfind == -1) {
  5915.             mv_error("can't read directory %s", source);
  5916.             nret = 0; goto EXIT;
  5917.         }
  5918.         do {
  5919.             if(f.name[0] != '.'){
  5920.                 _snprintf(ss, sizeof(ss), "%s\\%s", source, f.name);
  5921.                 _snprintf(dd, sizeof(dd), "%s\\%s", dest,   f.name);
  5922.                 if (move_file(ss, dd) != 0) {
  5923.                     nret = 1; goto EXIT;
  5924.                 }
  5925.             }
  5926.         } while(_findnext(lfind, &f) == 0);
  5927.         _findclose(lfind); lfind = -1;
  5928.         copy_attribute(source, dest);   /* Add Nide, dir attr copy */
  5929.         if(rmdir(source)) {
  5930.             mv_error("can't delete directory %s", source);
  5931.         }
  5932.         nret = 0; goto EXIT;
  5933.     }
  5934.  
  5935.     if((fds = _lopen(source, OF_READ)) < 0){
  5936.         io_error("cannot open source '%s'", source);
  5937.         nret = 0; goto EXIT;
  5938.     }
  5939.     _dos_getftime(fds, &dates.d, &dates.t);
  5940.     if(gg.update && (fdd = _lopen(dest, OF_READ)) >= 0){
  5941.         _dos_getftime(fdd, &dated.d, &dated.t);
  5942.         _lclose(fdd); fdd = -1;
  5943.         if(dates.d < dated.d || dates.d == dated.d && dates.t <= dated.t){
  5944.             nret = 0; goto EXIT;
  5945.         }
  5946.     }
  5947.     if(gg.verbose) verbose_out(source, dest);
  5948.  
  5949.     if(IS_READONLY(modes)){
  5950.         if(gg.interactive || !gg.force){
  5951.             _snprintf(buf, sizeof(buf),"'%s' readonly, move? ", source);
  5952.             cwFputs(buf, (LPSTR)-1);
  5953.             if(!YES_OR_NO_P()) {
  5954.                 nret = 0; goto EXIT;
  5955.             }
  5956.         }
  5957.         setattr(source, modes & ~7);
  5958.     }
  5959.     if(IS_READONLY(moded)){
  5960.         if(gg.interactive || !gg.force){
  5961.             _snprintf(buf, sizeof(buf), "'%s' readonly, move? ", dest);
  5962.             cwFputs(buf, (LPSTR)-1);
  5963.             if(!YES_OR_NO_P()) {
  5964.                 nret = 0; goto EXIT;
  5965.             }
  5966.         }
  5967.         setattr(dest, moded & ~7); /* Nide, modes -> moded */
  5968.     }
  5969.     /*
  5970.      * Check if we only have to change the 'link' of the file, or we have
  5971.      * to copy the contents to the destination and unlink the source.
  5972.      */
  5973.     disks = getfullpath_drive(NULL, source);
  5974.     diskd = getfullpath_drive(NULL, dest);
  5975.  
  5976.      /* now fds is opened */
  5977.     if(disks >= 0 && disks == diskd){
  5978.         _lclose(fds); fds = -1;
  5979.         /*
  5980.          * We only have to change the 'link' of files if two files
  5981.          * are on the save device
  5982.          */
  5983.         if(moded != (unsigned) -1){
  5984.             if(gg.backup){
  5985.                 if(gg.verbose) {
  5986.                     _snprintf(buf, sizeof(buf), "    (backup %s)\n",
  5987.                         s_conv_to_unix_format(dest));
  5988.                     cwFputs(buf, (LPSTR)-1);
  5989.                 }
  5990.                 if(!rename_as_backup(dest))
  5991.                     goto ask;
  5992.             } else {/* Changed Nide */
  5993.                 if(gg.interactive){
  5994.                 ask:
  5995.                     _snprintf(buf, sizeof(buf), "'%s' exists, move? ",
  5996.                         dest);
  5997.                     cwFputs(buf, (LPSTR)-1);
  5998.                     if(!YES_OR_NO_P()) {
  5999.                         nret = 0; goto EXIT;
  6000.                     }
  6001.                 }
  6002.                 if(remove(dest)){
  6003.                     io_error("cannot delete '%s'", dest);
  6004.                     nret = 0; goto EXIT;
  6005.                 }
  6006.             }
  6007.         }
  6008.         if(rename(source, dest)) {
  6009.             io_error("could not move '%s'", source);
  6010.         }
  6011.         setattr(dest, modes);  /* Add Nide; copy attribute */
  6012.     } else {
  6013.         /*
  6014.          * Copy, and unlink , when two files are on different
  6015.          * devices.
  6016.          */
  6017.         if(moded != (unsigned) -1){
  6018.             if(gg.backup){
  6019.                 if(gg.verbose) {
  6020.                     _snprintf(buf, sizeof(buf), "    (backup %s)\n",
  6021.                         s_conv_to_unix_format(dest));
  6022.                     cwFputs(buf, (LPSTR)-1);
  6023.                 }
  6024.                 if(!rename_as_backup(dest))
  6025.                     goto ask2;
  6026.             } else if(gg.interactive){
  6027.             ask2:
  6028.                 _snprintf(buf, sizeof(buf), "'%s' exists, move? ", dest);
  6029.                 cwFputs(buf, (LPSTR)-1);
  6030.                 if(!YES_OR_NO_P()){
  6031.                     nret = 0; goto EXIT;
  6032.                 }
  6033.             }
  6034.         }
  6035.  
  6036.          /* In previous versions fds is opened here
  6037.         if((fds = _lopen(source, OF_READ)) < 0){
  6038.             io_error("cannot open source '%s'", source);
  6039.             nret = 0; goto EXIT;
  6040.         } */
  6041.         if((fdd = _lcreat(dest, 0)) < 0){
  6042.             io_error("cannot open destination '%s'", dest);
  6043.             nret = 0; goto EXIT;
  6044.         }
  6045.  
  6046.         while((n = _lread(fds, gg.copybuf, BUFFERSIZE)) > 0) {
  6047.             if(_lwrite(fdd, gg.copybuf, n) != n){
  6048.                 io_error("'%s': write error", dest);
  6049.                 goto error;
  6050.             }
  6051.         }
  6052.         if(n < 0){
  6053.             io_error("'%s': read error", source);
  6054.         error:
  6055.             _lclose(fdd);
  6056.             unlink(dest);
  6057.             nret = 1; goto EXIT;
  6058.         }
  6059.  
  6060.         _dos_setftime(fdd, dates.d, dates.t);
  6061.         /* set_modification_time(fds, fdd); */
  6062.  
  6063.         setattr(dest, modes);  /* Add Nide; copy attribute */
  6064.         if (fds != -1) {
  6065.             _lclose(fds); fds = -1;
  6066.         }
  6067.         if(remove(source)) {
  6068.             io_error("can't delete '%s'", source);
  6069.         }
  6070.     }
  6071. EXIT:
  6072.     if (fds != -1) _lclose(fds);
  6073.     if (fdd != -1) _lclose(fdd);
  6074.     if (lfind != -1) _findclose(lfind);
  6075.     return nret;
  6076. }
  6077.  
  6078. int multifile_move(int filenum, char **filevec)
  6079. {
  6080.     char    buf[PATHNAMELENGTH];
  6081.     int i;
  6082.     for(i = 0; i < filenum - 1; i++){
  6083.         _snprintf(buf, sizeof(buf), "%s\\%s", filevec[filenum - 1],
  6084.                 strip_directory_part(filevec[i]));
  6085.         if (move_file(filevec[i], buf) != 0) return 1;
  6086.     }
  6087.     return 0;
  6088. }
  6089.  
  6090. int ends_with_pathdelimiter_p(char *f)
  6091. {
  6092.     int r = 0;
  6093.     if(isalpha(f[0]) && f[1] == ':'){
  6094.         if(f[2] == '\0')
  6095.             return 1;
  6096.         f += 2;
  6097.     }
  6098.     while(*f){
  6099.         if(iskanjipos(f))
  6100.             f += 2;
  6101.         else {
  6102.             if(f[1] == '\0' && *f == PD)
  6103.                 r = 1;
  6104.                 f++;
  6105.         }
  6106.     }
  6107.     return r;
  6108. }
  6109.  
  6110. int mv_main(int argc, char **argv)
  6111. {
  6112.     int c;
  6113.     unsigned mode;
  6114. //  extern int optind, opterr;
  6115. //  extern char *optarg;
  6116.  
  6117.     conv_char_args(argv, '/', '\\');
  6118.  
  6119.     gg.opterr = 0;
  6120.  
  6121.     {
  6122.         char    cwd[128];
  6123.         getcwd(cwd, 128);
  6124.         gg.current_disk = toupper(*cwd);
  6125.     }
  6126.     gg.force = gg.verbose = gg.interactive = gg.backup = FALSE;
  6127.  
  6128.     while((c = getopt(argc, argv, "fvibu")) != EOF){
  6129.         switch (c){
  6130.         case 'f':
  6131.             gg.force = TRUE;
  6132.             break;
  6133.         case 'v':
  6134.             gg.verbose = TRUE;
  6135.             break;
  6136.         case 'i':
  6137.             gg.interactive = TRUE;
  6138.             break;
  6139.         case 'b':
  6140.             gg.backup = TRUE;
  6141.             break;
  6142.         case 'u':
  6143.             gg.update = TRUE;
  6144.             break;
  6145.         default:
  6146.             return mv_usage();
  6147.         }
  6148.     }
  6149.  
  6150.  
  6151.     argc -= gg.optind;
  6152.     argv += gg.optind;
  6153.  
  6154.     if(argc < 2) {
  6155.         return mv_usage();
  6156.     } else {
  6157.         mode = get_file_status(argv[argc - 1]);
  6158.         if(argc >= 3){
  6159.             if(mode == (unsigned) (-1) || !(mode & 0x10)) {
  6160.                 return mv_usage();
  6161.             }
  6162.             if (multifile_move(argc, argv) != 0) {
  6163.                 return 1;
  6164.             }
  6165.         } else {    /* argc==2 */
  6166.             /* See if the last argument is directory or not. */
  6167.             if(ends_with_pathdelimiter_p(argv[argc - 1])) {
  6168.                 if (multifile_move(argc, argv) != 0) {
  6169.                     return 1;
  6170.                 }
  6171.             } else if(mode != (unsigned) (-1) && (mode & 0x10)){
  6172.                 /* 2nd pathname is found to be a directory */
  6173.                 if (multifile_move(argc, argv) != 0) {
  6174.                     return 1;
  6175.                 }
  6176.             } else {
  6177.                 /* file -> file */
  6178.                 if (move_file(argv[0], argv[1]) != 0) {
  6179.                     return 1;
  6180.                 }
  6181.             }
  6182.         }
  6183.     }
  6184.     return gg.error_code;
  6185. }
  6186.  
  6187. int mv_usage(void)
  6188. /* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
  6189. {
  6190.     static  char    *msgs[] = {
  6191.         "1. mv [-fivbu] file1 ... filen directory\n",
  6192.         "2. mv [-fivbu] file1 file2\n",
  6193.         "-f : force readonly files to be moved\n",
  6194.         "-i : query for each move\n",
  6195.         "-v : verbose message\n",
  6196.         "-b : make backup of files being removed\n",
  6197.         "-u : update (move only newer files)\n",
  6198.     };
  6199.     int i;
  6200.  
  6201.     for(i = 0; i < sizeof(msgs) / sizeof(*msgs); i++)
  6202.         cwFputs(msgs[i], (LPSTR)-1);
  6203.     return 3;
  6204. }
  6205.  
  6206. /*-----------*/
  6207. /* tail_main */
  6208. /*-----------*/
  6209. /*
  6210.  *  TAIL: Get the tail of the file.
  6211.  *      by Yasushi Saito(yasushi@is.s.u-tokyo.ac.jp).
  6212.  *
  6213.  *
  6214.  *                          April  8, 1989.
  6215.  *
  6216.  *          Support -l,-c,-h option     April 11, 1989.
  6217.  *          Support -r,-b   option      April 13, 1989.
  6218.  */
  6219.  
  6220. int tail_error(void)
  6221. {
  6222.     perror("tail");
  6223.     return 1;
  6224. }
  6225.  
  6226. int fputs_with_check(char *buf, FILE *fp)
  6227. {
  6228.     if (fp == NULL) {
  6229.         cwFputs(buf, NULL);
  6230.         return 0;
  6231.     }
  6232.     if(EOF == fputs(buf, fp)){  /* Changed Nide */
  6233.         cwFputs("tail : write error", (LPSTR)-1);
  6234.         return 1;
  6235.     }
  6236.     return 0;
  6237. }
  6238.  
  6239. int fgets_with_check(char *buf, int len, FILE *fp)
  6240. {
  6241.     int nret;
  6242.  
  6243.     if (fp == NULL) {
  6244.         nret = (int)cwFgets(buf, len, NULL);
  6245.     } else {
  6246.         nret = (int)fgets(buf, len, fp);
  6247.     }
  6248.     if(nret == 0) {
  6249.         return 0;
  6250.     }
  6251.     if(buf[0] == 'Z' - '@') {
  6252.         return 0;
  6253.     }
  6254.     return nret;
  6255. }
  6256.  
  6257. void xfseek(FILE *fp, long n, int origin)
  6258. {
  6259.     if(fseek(fp, n, origin))
  6260.         tail_error();
  6261. }
  6262.  
  6263. void *xmalloc(unsigned n)
  6264. {
  6265.     register void *m;
  6266.     if((m = malloc(n)) == 0){
  6267.         cwFputs("tail:Memory full", (LPSTR)-1);
  6268.         return NULL;
  6269.     }
  6270.     return m;
  6271. }
  6272.  
  6273. char *xstrdup(char *s)
  6274. {
  6275.     register char *m;
  6276.     if((m = strdup(s)) == 0){
  6277.         cwFputs("tail:Memory full", (LPSTR)-1);
  6278.         return NULL;
  6279.     }
  6280.     return m;
  6281. }
  6282.  
  6283. line_buffer *allocate_buffer(char *buf, int size)
  6284. {
  6285.     register line_buffer *l;
  6286.     l = xmalloc(sizeof(line_buffer));
  6287.     l->buf = xmalloc(size + 1);
  6288.     memcpy(l->buf, buf, size);
  6289.     l->buf[size] = '\0';
  6290.     return l;
  6291. }
  6292.  
  6293. /*
  6294.  * Count multibyte characters as one, and count 0d0a as one character(EOL)
  6295.  */
  6296. int string_length(char *s, int size)
  6297. {
  6298.     int     n = 0;
  6299.     while(size > 0){
  6300.         if(iskanjipos(s)){
  6301.             s += 2;
  6302.             size -= 2;
  6303.         } else if(s[0] == 0x0d && s[1] == 0x0a){
  6304.             s += 2;
  6305.             size -= 2;
  6306.         } else {
  6307.             s++;
  6308.             size--;
  6309.         }
  6310.         n++;
  6311.     }
  6312.     return n;
  6313. }
  6314.  
  6315. /*
  6316.  * -##c option Sequential device.
  6317.  */
  6318. void sequential_find_tail_character(FILE *fp)
  6319. {
  6320.     struct char_buf {
  6321.         unsigned char h, l;
  6322.     };
  6323.     struct char_buf *base, *bottom, *current;
  6324.     char    buf[BUFFER_SIZE], *bufp;
  6325.     unsigned i;
  6326.  
  6327.     /* Allocate and initialize buffer. */
  6328.     current = base = xmalloc(sizeof(struct char_buf) * gg.tail_lineno);
  6329.     bottom = base + gg.tail_lineno;
  6330.     for(i = 0; i < gg.tail_lineno; i++)
  6331.         base[i].h = base[i].l = 0;
  6332.  
  6333.     /* Read all. */
  6334.     while(fgets_with_check(buf, BUFFER_SIZE, fp)){
  6335.         for(bufp = buf; *bufp; bufp++){
  6336.             if(gg.unit == CHARACTER){
  6337.                 if(iskanjipos(bufp))
  6338.                     current->h = *(bufp++);
  6339.                 else
  6340.                     current->h = 0;
  6341.             }
  6342.             current->l = *bufp;
  6343.             current++;
  6344.             if(current >= bottom)
  6345.                 current = base;
  6346.         }
  6347.     }
  6348.  
  6349.     /* Printout. */
  6350.     for(i = 0; i < gg.tail_lineno; i++){
  6351.         char buf[2];
  6352.         if(current->h) {
  6353.             buf[0] = current->h;
  6354.             buf[1] = '\0';
  6355.             cwFputs(buf, NULL);
  6356.         }
  6357.         if(current->l) {
  6358.             buf[0] = current->l;
  6359.             buf[1] = '\0';
  6360.             cwFputs(buf, NULL);
  6361.         }
  6362.         current++;
  6363.         if(current >= bottom)
  6364.             current = base;
  6365.     }
  6366.     free(base);
  6367. }
  6368.  
  6369. /*
  6370.  * -##l or -##r(number specified) option. Sequential device.
  6371.  * 
  6372.  */
  6373. void sequential_find_tail_line(FILE *fp)
  6374. {
  6375.     char  **base, **current, **bottom;
  6376.     unsigned i;
  6377.     char    buf[BUFFER_SIZE];
  6378.  
  6379.     /* Allocate and initialize buffer. */
  6380.     base = current = (char **) xmalloc(sizeof(char *) * gg.tail_lineno);
  6381.     for(i = 0; i < gg.tail_lineno; i++)
  6382.         base[i] = 0;
  6383.     bottom = base + gg.tail_lineno;
  6384.  
  6385.     /* Read files till the end. */
  6386.     while(fgets_with_check(buf, BUFFER_SIZE, fp)){
  6387.         if(*current)
  6388.             free(*current);
  6389.         *current = xstrdup(buf);
  6390.         current++;
  6391.         if(current >= bottom)
  6392.             current = base;
  6393.     }
  6394.  
  6395.     /* Printout. */
  6396.     if(gg.mode == tail_reverse){
  6397.         current--;
  6398.         for(i = 0; i < gg.tail_lineno; i++){
  6399.             if(current < base)
  6400.                 current = bottom - 1;
  6401.             if(*current){
  6402.                 fputs_with_check(*current, NULL);
  6403.                 free(*current);
  6404.             }
  6405.             current--;
  6406.         }
  6407.     } else {
  6408.         for(i = 0; i < gg.tail_lineno; i++){
  6409.             if(*current){
  6410.                 fputs_with_check(*current, NULL);
  6411.                 free(*current);
  6412.             }
  6413.             current++;
  6414.             if(current >= bottom)
  6415.                 current = base;
  6416.         }
  6417.     }
  6418.     free(base);
  6419. }
  6420.  
  6421. /*
  6422.  * +##l or +##c options with sequential or block device. Or, +##b with
  6423.  * sequential device.
  6424.  */
  6425. void find_head(FILE *fp)
  6426. {
  6427.     char    buf[BUFFER_SIZE];
  6428.     unsigned i;
  6429.  
  6430.     /* Skip the input to the designated place. */
  6431.     if(gg.unit == LINE){
  6432.         for(i = 0; i < gg.tail_lineno; i++)
  6433.             if(!fgets_with_check(buf, BUFFER_SIZE, fp))
  6434.                 return;
  6435.     } else {
  6436.         int     c;
  6437.         for(i = 0; i < gg.tail_lineno; i++){
  6438.             if((c = getc(fp)) == EOF)
  6439.                 return;
  6440.             if(gg.unit == CHARACTER && iskanji(c) && (getc(fp) == EOF))
  6441.                 return;
  6442.         }
  6443.     }
  6444.  
  6445.     /* Printout */
  6446.     while(fgets_with_check(buf, BUFFER_SIZE, fp))
  6447.         fputs_with_check(buf, NULL);
  6448. }
  6449.  
  6450. /*
  6451.  * -##l or -##c option. Block device.
  6452.  */
  6453. int random_find_tail(FILE *fp)
  6454. {
  6455.     unsigned line;      /* Line number (in case of -l), character
  6456.                  * count (in case of -c) */
  6457.     long    file_size;  /* Size of the file */
  6458.     long    position;   /* Current file pointer FILESIZE >= POSITION
  6459.                  * always. */
  6460.     /**
  6461.             The algorithm:
  6462.     
  6463.         We utilize 2 buffers and use one as a main buffer,
  6464.         and another to hold an unprocessed portion
  6465.         (junk string before the first beginning-of-line character).
  6466.         Their roles are switched at each block-seek.
  6467.     
  6468.         1. Goto the  file end.(file_size is set here and
  6469.             not modified later.)
  6470.         2. Seek back SEEK_BLOCK bytes.
  6471.         3. Read SEEK_BLOCK bytes into READ_BUFFER.
  6472.         4. Skip the junk string before the first BOL.
  6473.            (they processed at the next repetition)
  6474.         5. Add the UNPROCESSED region at the last of READ_BUFFER.
  6475.         6. Count the lines(or characters) of the READ_BUFFER,
  6476.            and construct the TOP list.
  6477.         7. Switch READ_BUFFER and UNPROCESSED.
  6478.         8. Repeat 2,..,7 until enough lines(or characters) are read.
  6479.     
  6480.         9. Discard the lines(characters) read excess.
  6481.         10. Printout.
  6482.     
  6483.         */
  6484.  
  6485.     line_buffer *top, *last,/* Hold the top and last of the current block
  6486.                  * list */
  6487.            *list_head;  /* Global content list */
  6488.     boolean reached_top;    /* Is FP reached the beginning? */
  6489.     char   *read_buffer, *unprocessed;
  6490.     char   *read_buffer_end;/* points to the end of READ_BUFFER */
  6491.     unsigned unprocessed_size;
  6492.     char   *x;
  6493.  
  6494.     /*
  6495.      * Set to binary mode, to synchronize the fread() and fseek()
  6496.      * operation.
  6497.      */
  6498.     /* fsetbin(fp); *//* Del Nide (done by caller) */
  6499.  
  6500.     /* Set file pointer at the last */
  6501.     xfseek(fp, 0L, SEEK_END);
  6502.     file_size = position = ftell(fp);
  6503.  
  6504.     line = 0;
  6505.     list_head = 0;
  6506.     if(gg.s_buf1_0 == 0){
  6507.         gg.s_buf1_0 = xmalloc(gg.seek_block * 2);
  6508.         gg.s_buf2_0 = xmalloc(gg.seek_block * 2);
  6509.     }
  6510.     read_buffer = gg.s_buf1_0;
  6511.     unprocessed = gg.s_buf2_0;
  6512.     unprocessed_size = 0;
  6513.  
  6514.     do {
  6515.         /*
  6516.          * Seek back one block. REACHED_TOP is set TRUE if the
  6517.          * current file pointer is at the file top.
  6518.          */
  6519.  
  6520.         if(position - gg.seek_block <= 0){
  6521.             int     size;
  6522.             xfseek(fp, 0L, SEEK_SET);
  6523.             reached_top = TRUE;
  6524.  
  6525.             size = fread(read_buffer, 1, gg.seek_block, fp);
  6526.             /*
  6527.              * Copy back the unprocessed portion of the previous
  6528.              * block
  6529.              */
  6530.             memcpy(read_buffer + size, unprocessed, unprocessed_size);
  6531.             read_buffer_end = read_buffer + size + unprocessed_size;
  6532.             x = read_buffer;
  6533.             position = 0;
  6534.         } else {
  6535.             int     size;
  6536.             /* char *s; */
  6537.             xfseek(fp, -(long) gg.seek_block, SEEK_CUR);
  6538.             position = ftell(fp);
  6539.  
  6540.             /* Skip garbages before the first EOL */
  6541.             size = fread(read_buffer, 1, gg.seek_block, fp);
  6542.             xfseek(fp, (long) position, SEEK_SET);
  6543.  
  6544.             memcpy(read_buffer + size, unprocessed, unprocessed_size);
  6545.             read_buffer_end = read_buffer + size + unprocessed_size;
  6546.  
  6547.             for(x = read_buffer; *x != '\n' && x < read_buffer_end; x++);
  6548.             if(x >= read_buffer_end){
  6549.                 cwFputs("Too long input line\n", (LPSTR)-1);
  6550.                 return 1;
  6551.             }
  6552.             /*
  6553.              * Now, X holds the first beginning-of-line.
  6554.              */
  6555.             x++;
  6556.             unprocessed_size = x - read_buffer;
  6557.  
  6558.             reached_top = FALSE;
  6559.         }
  6560.  
  6561.         /*
  6562.          * Count the lines contained in READ_BUFFER and addto the TOP
  6563.          * list line-by-line.
  6564.          */
  6565.         top = 0;
  6566.         while(x < read_buffer_end){
  6567.             char   *lineend = x;
  6568.             int     size;
  6569.             /* Look for the line end. */
  6570.             while(*lineend != '\r' && *lineend != '\n'){
  6571.                 if(lineend >= read_buffer_end){
  6572.                     /*
  6573.                      * fputs("Incomplete last line\n",
  6574.                      * stderr);
  6575.                      */
  6576.                     lineend--;
  6577.                     break;
  6578.                 }
  6579.                 lineend++;
  6580.             }
  6581.             if(*lineend == '\r' && lineend[1] == '\n'){
  6582.                 lineend++;
  6583.             }
  6584.             size = lineend - x + 1;
  6585.             if(top == 0)
  6586.                 top = last = allocate_buffer(x, size);
  6587.             else {
  6588.                 last->link = allocate_buffer(x, size);
  6589.                 last = last->link;
  6590.             }
  6591.             last->link = 0;
  6592.             x = lineend + 1;
  6593.             if(gg.unit == LINE)
  6594.                 line++;
  6595.             else {  /* unit==CHARACTER */
  6596.                 last->len = string_length(last->buf, size);
  6597.                 line += last->len;
  6598.             }
  6599.         }
  6600.  
  6601.         /*
  6602.          * Update the global content list. TOP is inserted at the
  6603.          * head of the LIST_HEAD.
  6604.          */
  6605.         {
  6606.             if(list_head == 0)
  6607.                 list_head = top;
  6608.             else {
  6609.                 last->link = list_head;
  6610.                 list_head = top;
  6611.             }
  6612.         }
  6613.  
  6614.         /*
  6615.          * Switch READ_BUFFER and UNPROCESSED
  6616.          */
  6617.         {
  6618.             void   *temp = read_buffer;
  6619.             read_buffer = unprocessed;
  6620.             unprocessed = temp;
  6621.         }
  6622.  
  6623.         /*
  6624.          * Repeat the loop until enough lines are read, or the file
  6625.          * reached its top.
  6626.          */
  6627.     } while(!reached_top && line < gg.tail_lineno);
  6628.  
  6629.     /*
  6630.      * Discard the lines that was read excess.
  6631.      */
  6632.     if(gg.unit == LINE)
  6633.         while(line > gg.tail_lineno){
  6634.             line_buffer *temp;
  6635.             temp = top;
  6636.             top = top->link;
  6637.             free_buffer(temp);
  6638.             line--;
  6639.         }
  6640.     else if(gg.unit == CHARACTER){
  6641.         /* int n; */
  6642.         while(line > gg.tail_lineno){
  6643.             line_buffer *temp;
  6644.             temp = top;
  6645.             line -= temp->len;
  6646.             if(line < gg.tail_lineno){
  6647.                 int     i;
  6648.                 char   *s = temp->buf;
  6649.  
  6650.                 for(i = 0; i < (int)(temp->len-(gg.tail_lineno-line)); i++){
  6651.                     if(iskanjipos(s) || s[0] == 0x0d && s[1] == 0x0a)
  6652.                         s++;
  6653.                     s++;
  6654.                 }
  6655.                 temp->buf = s;
  6656.             } else
  6657.                 top = top->link;
  6658.             free_buffer(temp);
  6659.         }
  6660.     }
  6661.     /*
  6662.      * Printout.
  6663.      */
  6664.     while(top){
  6665.         line_buffer *temp;
  6666.         int     length;
  6667.         temp = top;
  6668.         /*
  6669.          * We shouldn't use fputs(or other stream I/O routines) here
  6670.          * since they will (1) convert EOLs to DOS format (2) they
  6671.          * will return error if they encountered ^Z. Instead use
  6672.          * write.
  6673.          */
  6674.         length = strlen(top->buf);
  6675.         if(write(1, top->buf, length) < 0){
  6676.             perror("tail-write");
  6677.             return 1;
  6678.         }
  6679.         top = top->link;
  6680.         free_buffer(temp);
  6681.     }
  6682.     return 0;
  6683. }
  6684.  
  6685. /*
  6686.  * -r option(with no numeric parameter). Sequential device.
  6687.  * 
  6688.  */
  6689. void sequential_reverse_print(FILE *fp)
  6690. {
  6691.     line_buffer *top, *temp;
  6692.     char    buf[BUFFER_SIZE];
  6693.     top = 0;
  6694.     while(fgets_with_check(buf, BUFFER_SIZE, fp)){
  6695.         temp = allocate_buffer(buf, strlen(buf));
  6696.         temp->link = top;
  6697.         top = temp;
  6698.     }
  6699.     while(top){
  6700.         fputs_with_check(top->buf, NULL);
  6701.         temp = top;
  6702.         top = top->link;
  6703.         free_buffer(temp);
  6704.     }
  6705. }
  6706.  
  6707. /*
  6708.  * -##r option. Block device.
  6709.  * 
  6710.  */
  6711. void block_reverse_print(FILE *fp)
  6712. {
  6713.     unsigned line;
  6714.     /* int c; */
  6715.     long    flast_bottom, current_top, position;
  6716.     line_buffer *list_head, *top, *last, *temp;
  6717.     int     already_top;
  6718.     char    buf[BUFFER_SIZE];
  6719.  
  6720.     /* Set file pointer at the last */
  6721.     xfseek(fp, 0L, SEEK_END);
  6722.     current_top = position = ftell(fp);
  6723.  
  6724.     list_head = 0;
  6725.     line = 0;
  6726.  
  6727.     do {
  6728.         top = last = 0;
  6729.         if(current_top - gg.seek_block < 0){
  6730.             xfseek(fp, 0L, SEEK_SET);
  6731.             already_top = 1;
  6732.         } else {
  6733.             xfseek(fp, -(gg.seek_block + position - current_top), SEEK_CUR);
  6734.             /* Skip garbages before the first EOL */
  6735.             fgets_with_check(buf, BUFFER_SIZE, fp);
  6736.             already_top = 0;
  6737.         }
  6738.  
  6739.         flast_bottom = current_top;
  6740.         current_top = ftell(fp);
  6741.  
  6742.         while(fgets_with_check(buf, BUFFER_SIZE, fp)){
  6743.             if(top == 0){
  6744.                 top = last = allocate_buffer(buf, strlen(buf));
  6745.             } else {
  6746.                 last->link = allocate_buffer(buf, strlen(buf));
  6747.                 last = last->link;
  6748.             }
  6749.             last->link = 0;
  6750.             line++;
  6751.             if((position = ftell(fp)) >= flast_bottom)
  6752.                 break;
  6753.         }
  6754.         while(line > gg.tail_lineno){
  6755.             temp = top;
  6756.             top = top->link;
  6757.             free_buffer(temp);
  6758.             line--;
  6759.         }
  6760.  
  6761.         /* (setq top (nreverse top)) */
  6762.         list_head = top;
  6763.         last = 0;
  6764.         while(top->link){
  6765.             temp = top->link;
  6766.             top->link = last;
  6767.             last = top;
  6768.             top = temp;
  6769.         }
  6770.         top->link = last;
  6771.  
  6772.         /* Printout top */
  6773.         while(top){
  6774.             temp = top;
  6775.             fputs_with_check(top->buf, NULL);
  6776.             top = top->link;
  6777.             free_buffer(temp);
  6778.         }
  6779.     } while(!already_top && line < gg.tail_lineno);
  6780. }
  6781.  
  6782. /*
  6783.  * -##b option. Block device.
  6784.  * 
  6785.  */
  6786. void block_find_tail(FILE *fp)
  6787. {
  6788.     long    fsize, position;
  6789.     char    buf[BUFFER_SIZE];
  6790.     position = (long)gg.tail_lineno;
  6791.  
  6792.     xfseek(fp, 0L, SEEK_END);
  6793.     fsize = ftell(fp);
  6794.  
  6795.     if(fsize < position)
  6796.         position = fsize;
  6797.     xfseek(fp, -position, SEEK_END);
  6798.     while(fgets_with_check(buf, BUFFER_SIZE, fp))
  6799.         fputs_with_check(buf, NULL);
  6800. }
  6801.  
  6802. /*
  6803.  * +##b option. Block device.
  6804.  */
  6805. void block_find_head(FILE *fp)
  6806. {
  6807.     long    fsize, position;
  6808.     char    buf[BUFFER_SIZE];
  6809.     position = (long)gg.tail_lineno;
  6810.  
  6811.     xfseek(fp, 0L, SEEK_END);
  6812.     fsize = ftell(fp);
  6813.  
  6814.     if(fsize < position)
  6815.         return;
  6816.     xfseek(fp, position, SEEK_SET);
  6817.     while(fgets_with_check(buf, BUFFER_SIZE, fp))
  6818.         fputs_with_check(buf, NULL);
  6819. }
  6820.  
  6821. /*
  6822.  * Toplevel dispatcher.
  6823.  * 
  6824.  */
  6825. int tail(FILE *fp)
  6826. {
  6827.     boolean is_sequential = 1; // (fp == NULL);
  6828.     /* Nide, to avoid "enum type mismatch" */
  6829.  
  6830.     if(gg.mode == tail_reverse){
  6831.         if(!is_sequential) {
  6832.             block_reverse_print(fp);
  6833.         } else if(gg.tail_lineno == (unsigned) -1) {
  6834.             sequential_reverse_print(fp);
  6835.         } else {
  6836.             sequential_find_tail_line(fp);
  6837.         }
  6838.     } else if(gg.mode == from_tail){
  6839.         if(!is_sequential){
  6840.             if(gg.unit != BLOCK){  /* Changed Nide */
  6841.                 if (random_find_tail(fp) != 0) return 1;
  6842.             } else
  6843.                 block_find_tail(fp);
  6844.         } else {
  6845.             if(gg.unit == LINE)
  6846.                 sequential_find_tail_line(fp);
  6847.             else
  6848.                 sequential_find_tail_character(fp);
  6849.         }
  6850.     } else {        /* mode==from_head */
  6851.         if(gg.unit == BLOCK && !is_sequential)
  6852.             block_find_head(fp);
  6853.         else
  6854.             find_head(fp);
  6855.     }
  6856.     return 0;
  6857. }
  6858.  
  6859. int tail_main(int argc, char **argv)
  6860. {               /* Changed Nide */
  6861.     int nret = 0;
  6862.     FILE   *fp = NULL;
  6863.     int /* c, */ i;
  6864.     char   *s;
  6865.     boolean print_filename;
  6866.     int     noheader_opt = 0;
  6867.  
  6868.     gg.tail_lineno = (unsigned)-1;/*tail_lineno==-1はtail_lineno未確定を示す */
  6869.     gg.mode = from_tail;
  6870.     gg.unit = LINE;
  6871.     print_filename = FALSE;
  6872.  
  6873.     for(i = 1; i < argc; i++){
  6874.         s = argv[i];
  6875.         if(*s == '-'){
  6876.             if(!s[1])
  6877.                 break;  /* "-"を、stdinを表す引数と解釈 */
  6878.         } else if(*s == '+')
  6879.             gg.mode = from_head;
  6880.         else
  6881.             break;
  6882.  
  6883.         s++;
  6884.         if(*s >= '0' && *s <= '9')
  6885.             gg.tail_lineno = atoi(s);
  6886.                                         /* tail_lineno == 0 である場合などは
  6887.                                            この次のチェックでひっかかるから
  6888.                                            大丈夫) */
  6889.         while(*s >= '0' && *s <= '9')
  6890.             s++;
  6891.         while(*s){
  6892.             switch (*s){    /* `tail_lineno' is checked later */
  6893.             case 'b':
  6894.                 gg.unit = BLOCK;
  6895.                 break;
  6896.             case 'c':
  6897.                 gg.unit = CHARACTER;
  6898.                 break;
  6899.             case 'l':
  6900.                 gg.unit = LINE;
  6901.                 break;
  6902.             case 'h':
  6903.                 noheader_opt = 1;
  6904.                 break;
  6905.             case 'r':
  6906.                 gg.mode = tail_reverse;
  6907.                 break;
  6908.             default:
  6909.                 return tail_usage();
  6910.             }
  6911.             s++;
  6912.         }
  6913.     }
  6914.  
  6915.     if(gg.mode == tail_reverse)
  6916.         gg.unit = LINE;
  6917.     switch (gg.unit){
  6918.     case LINE:
  6919.         if(gg.mode != tail_reverse && gg.tail_lineno == (unsigned) -1)
  6920.             gg.tail_lineno = 10;
  6921.         gg.seek_block = 2048L;
  6922.         break;
  6923.     case BLOCK:
  6924.         if(gg.tail_lineno == (unsigned) -1)
  6925.             gg.tail_lineno = BLOCK_SIZE;
  6926.         else
  6927.             gg.tail_lineno *= BLOCK_SIZE;
  6928.         break;
  6929.     case CHARACTER:
  6930.         if(gg.tail_lineno == (unsigned) -1)
  6931.             gg.tail_lineno = 10;
  6932.         gg.seek_block = (gg.tail_lineno / BUFFER_SIZE + 2) * BUFFER_SIZE;
  6933.         break;
  6934.     }
  6935.  
  6936.     if(i + 2 <= argc && !noheader_opt) {
  6937.         print_filename = TRUE;
  6938.     }
  6939.     if(i == argc) {
  6940.         tail(NULL);
  6941.     } else {
  6942.         while(i < argc){
  6943.             fp = (strcmp("-", argv[i]) ? fopen(argv[i], "r") : NULL);
  6944.             if(fp == 0) return tail_error();
  6945.             if(print_filename){
  6946.                 cwFputs("<<<", NULL);
  6947.                 cwFputs(strcmp(argv[i], "-") ? argv[i] : "(stdin)", NULL);
  6948.                 cwFputs(">>>\n", NULL);
  6949.             }
  6950.             if (tail(fp) != 0) {
  6951.                 nret = 1; goto EXIT;
  6952.             }
  6953.             if (fp != NULL) {
  6954.                 fclose(fp); fp == NULL;
  6955.             }
  6956.             i++;
  6957.         }
  6958.     }
  6959. EXIT:
  6960.     if (fp != NULL) fclose(fp);
  6961.     return 0;
  6962. }
  6963.  
  6964. int tail_usage(void)
  6965. {
  6966.     cwFputs("tail [-+][#][blcrh] [file...]\n", (LPSTR)-1);
  6967.     return -1;
  6968. }
  6969.  
  6970. /*-----------*/
  6971. /* diff_main */
  6972. /*-----------*/
  6973.  
  6974. /*
  6975.    diff.c - public domain context diff program
  6976.  
  6977.   if you want to use this command as 'diff file dir', define DIRFCMP
  6978.  
  6979.   on VOS3, define VOS3
  6980.   on MSDOS, define MSDOS ('MSDOS', 'unix' infer 'DIRFCMP')
  6981.  
  6982.   with MSC, define MSC and link ssetargv.obj
  6983.  
  6984.   on VOS3, stdout is re-opened with RECFM(VB),LRECL(255).
  6985. */
  6986.  
  6987.  /* by Nide */
  6988.  
  6989. /*
  6990.  * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
  6991.  */
  6992.  
  6993.  
  6994. #include <process.h>
  6995.  
  6996. void unlink_tmp(void) /* on MSDOS, must close TEMPFILE first */
  6997. {
  6998.     if(gg.tempfd != NULL){
  6999.         fclose(gg.tempfd);
  7000.     }
  7001. }
  7002.  
  7003. /*
  7004.  * Diff main program
  7005.  */
  7006.  
  7007. int diff_main(int argc, char **argv)
  7008. {
  7009.     int nret = 0;
  7010.     register int    i;
  7011.     register char  *ap;
  7012. //  char    *fname[2];
  7013.     char    flg = 0;
  7014.  
  7015.     while (argc > 1 && *(ap = argv[1]) == '-' && *++ap != EOS) {
  7016.         while (*ap != EOS) {
  7017.             switch ((*ap++)) {
  7018.             case 'b':
  7019.                 gg.bflag++;
  7020.                 break;
  7021.  
  7022.             case 'c':
  7023.                 if (*ap > '0' && *ap <= '9')
  7024.                     gg.cflag = *ap++ - '0';
  7025.                 else
  7026.                     gg.cflag = 3;
  7027.                 break;
  7028.  
  7029.             case 'e':
  7030.                 gg.eflag++;
  7031.                 break;
  7032.  
  7033.             case 'i':
  7034.                 gg.iflag++;
  7035.                 break;
  7036.  
  7037.             default: {
  7038.                 char buf[80];
  7039.                 _snprintf(buf, sizeof(buf),
  7040.                           "Warning, bad option '%c'\n", ap[-1]);
  7041.                 cwFputs(buf, (LPSTR)-1);
  7042.               }
  7043.             }
  7044.         }
  7045.         argc--;
  7046.         argv++;
  7047.     }
  7048.  
  7049.     if (argc != 3) {
  7050.         nret = differror("Usage: diff [-bcei] file1 file2");
  7051.         goto EXIT;
  7052.     }
  7053.     if (gg.cflag && gg.eflag) {
  7054.         cwFputs("Warning, -c and -e are incompatible, -c supressed.\n",
  7055.               (LPSTR)-1);
  7056.         gg.cflag = FALSE;
  7057.     }
  7058.     argv++;
  7059.     for (i = 0; i <= 1; i++) conv_to_unix_format(argv[i]);
  7060.     for (i = 0; i <= 1; i++) fname[i] = argv[i];
  7061.  
  7062.     if(isstdin(fname[0]) && isstdin(fname[1])) {
  7063.         nret = differror("Can't diff two things both on standard input.");
  7064.         goto EXIT;
  7065.     }
  7066.     for (i = 0; i <= 1; i++) {
  7067.         if (isstdin(fname[i])){
  7068.             gg.infd[i] = NULL;
  7069.             if ((gg.tempfd = fopen(TEMPFILE, "w")) == NULL) {
  7070.                 nret = cant(TEMPFILE, "work", 1);
  7071.                 goto EXIT;
  7072.             }
  7073.         } else {
  7074.             if(!flg && isdir(fname[i])){
  7075.                 if(i == 0 && isdir(fname[!i])){
  7076.                     nret = differror("Can't diff two directories. X-(");
  7077.                     goto EXIT;
  7078.                 } else {
  7079.                     flg++;
  7080.                 }
  7081.                 if(isstdin(fname[!i])){
  7082.                     nret = differror("Can't diff directory and stdin.");
  7083.                     goto EXIT;
  7084.                 }
  7085.                 fname[i] = dircat(fname[i], fname[!i]);
  7086.             }
  7087.             gg.infd[i] = fopen(fname[i], "r");
  7088.             if (gg.infd[i] == NULL) {
  7089.                 nret = cant(fname[i], "input", 2); /* Fatal error */
  7090.                 goto EXIT;
  7091.             }
  7092.         }
  7093.     }
  7094.  
  7095.     if (gg.infd[0] == NULL && gg.infd[1] == NULL) {
  7096.         cant(fname[0], "input", 0); /* not return */
  7097.         nret = cant(fname[1], "input", 1);
  7098.         goto EXIT;
  7099.     }
  7100.  
  7101.  
  7102.     /*
  7103.      * Read input, building hash tables. 
  7104.      */
  7105.     input(0);
  7106.     input(1);
  7107.     squish();
  7108.     sort(sfileA, slenA);
  7109.     sort(sfileB, slenB);
  7110.  
  7111.     /*
  7112.      * Build equivalence classes. 
  7113.      */
  7114.     gg.member = (short *) fileB;
  7115.     equiv();
  7116.     gg.member = (short *) compact((char *)gg.member,(slenB+2)*sizeof(int),
  7117.                        "squeezing member vector");
  7118.  
  7119.     /*
  7120.      * Reorder equivalence classes into array class[] 
  7121.      */
  7122.     gg.class = (short *) fileA;
  7123.     unsort();
  7124.     gg.class = (short *) compact((char *)gg.class, (slenA + 2) * sizeof(int),
  7125.                       "compacting class vector");
  7126.  
  7127.     /*
  7128.      * Find longest subsequences 
  7129.      */
  7130.     gg.klist = (int *) myalloc((slenA + 2) * sizeof(int), "klist");
  7131.     gg.clist = (CANDIDATE *)myalloc(gg.csize * sizeof(CANDIDATE), "clist");
  7132.     i = subseq();
  7133.     free((char *)gg.member);
  7134.     free((char *)gg.class);
  7135.     gg.match = (int *) myalloc((lenA + 2) * sizeof(int), "match");
  7136.     unravel(gg.klist[i]);
  7137.     free((char *) gg.clist);
  7138.     free((char *) gg.klist);
  7139.  
  7140.     /*
  7141.      * Check for fortuitous matches and output differences 
  7142.      */
  7143.     gg.oldseek = (long *) myalloc((lenA + 2) * sizeof(*gg.oldseek), "oldseek");
  7144.     gg.newseek = (long *) myalloc((lenB + 2) * sizeof(*gg.newseek), "newseek");
  7145.     gg.textb = myalloc(sizeof(gg.text), "textbuffer");
  7146.     if (check(fname[0], fname[1])) {
  7147.         cwFputs("Spurious match, output is not optimal\n", (LPSTR)-1);
  7148.     }
  7149.     output(fname[0], fname[1]);
  7150.  
  7151. EXIT:
  7152.     if (gg.infd[0] != NULL) gg.infd[0] = 0;
  7153.     gg.infd[0] = NULL;
  7154.     if (gg.infd[1] != NULL) gg.infd[1] = 0;
  7155.     gg.infd[1] = NULL;
  7156.     unlink_tmp();
  7157.     return nret;
  7158. }
  7159.  
  7160.  
  7161. /*
  7162.  * Read the file, building hash table
  7163.  */
  7164.  
  7165. void input(int which)
  7166. /* 0 or 1 to redefine infd[]  */
  7167. {
  7168.     register DIFF_LINE  *lentry;
  7169.     register int    linect = 0;
  7170.     FILE           *fd;
  7171. #define LSIZE_INC 200            /* # of line entries to alloc at once */
  7172.     int     lsize = LSIZE_INC;
  7173.  
  7174.     lentry = (DIFF_LINE *) myalloc(sizeof(DIFF_LINE) * (lsize + 3), "line");
  7175.     fd = gg.infd[which];
  7176.     while (!getline(fd, gg.text)) {
  7177.         if (++linect >= lsize) {
  7178.             lsize += 200;
  7179.             lentry = (DIFF_LINE *) compact((char *) lentry,
  7180.                       (lsize + 3) * sizeof(DIFF_LINE),
  7181.                       "extending line vector");
  7182.         }
  7183.         lentry[linect].hash = hash(gg.text);
  7184.     }
  7185.  
  7186.     /*
  7187.      * If input was from stdin ("-" command), finish off the temp file. 
  7188.      */
  7189.     if (fd == NULL) {
  7190.         gg.tempfd = gg.infd[which] = freopen(TEMPFILE, "r", gg.tempfd);
  7191.     }
  7192.  
  7193. /*
  7194.  * If we wanted to be stingy with memory, we could realloc lentry down to
  7195.  * its exact size (+3 for some odd reason) here.  No need?  
  7196.  */
  7197.     gg.len[which] = linect;
  7198.     gg.file[which] = lentry;
  7199. }
  7200.  
  7201.  
  7202. /*
  7203.  * Look for initial and trailing sequences that have identical hash values.
  7204.  * Don't bother building them into the candidate vector.
  7205.  */
  7206.  
  7207. void squish(void)
  7208. {
  7209.     register int    i;
  7210.     register DIFF_LINE  *ap;
  7211.     register DIFF_LINE  *bp;
  7212.     int     j;
  7213.     int     k;
  7214.  
  7215.     /*
  7216.      * prefix -> first line (from start) that doesn't hash identically 
  7217.      */
  7218.     i = 0;
  7219.     ap = &fileA[1];
  7220.     bp = &fileB[1];
  7221.     while (i < lenA && i < lenB && ap->hash == bp->hash) {
  7222.         i++;
  7223.         ap++;
  7224.         bp++;
  7225.     }
  7226.     gg.prefix = i;
  7227.  
  7228.     /*
  7229.      * suffix -> first line (from end) that doesn't hash identically 
  7230.      */
  7231.     j = lenA - i;
  7232.     k = lenB - i;
  7233.     ap = &fileA[lenA];
  7234.     bp = &fileB[lenB];
  7235.     i = 0;
  7236.     while (i < j && i < k && ap->hash == bp->hash) {
  7237.         i++;
  7238.         ap--;
  7239.         bp--;
  7240.     }
  7241.     gg.suffix = i;
  7242.  
  7243.     /*
  7244.      * Tuck the counts away 
  7245.      */
  7246.     for (k = 0; k <= 1; k++) {
  7247.         gg.sfile[k] = gg.file[k] + gg.prefix;
  7248.         j = gg.slen[k] = gg.len[k] - gg.prefix - gg.suffix;
  7249.  
  7250.         for (i = 0, ap = gg.sfile[k]; i <= gg.slen[k]; i++, ap++) {
  7251.             ap->serial = i;
  7252.         }
  7253.     }
  7254. }
  7255.  
  7256.  
  7257. /*
  7258.  * Sort hash entries
  7259.  */
  7260.  
  7261. void sort(DIFF_LINE *vector, int vecsize)
  7262. /* What to sort       */
  7263. /* How many to sort  */
  7264. {
  7265.     register int    j;
  7266.     register DIFF_LINE  *aim;
  7267.     register DIFF_LINE  *ai;
  7268.     int     mid;
  7269.     int     k;
  7270.     DIFF_LINE        work;
  7271.  
  7272.     for (j = 1; j <= vecsize; j *= 2);
  7273.     mid = (j - 1);
  7274.     while ((mid /= 2) != 0) {
  7275.         k = vecsize - mid;
  7276.         for (j = 1; j <= k; j++) {
  7277.             for (ai = &vector[j]; ai > vector; ai -= mid) {
  7278.                 aim = &ai[mid];
  7279.                 if (aim < ai)
  7280.                     break;      /* ?? Why ??     */
  7281.                 if (aim->hash > ai->hash ||
  7282.                     aim->hash == ai->hash &&
  7283.                     aim->serial > ai->serial)
  7284.                     break;
  7285.                 work.hash = ai->hash;
  7286.                 ai->hash = aim->hash;
  7287.                 aim->hash = work.hash;
  7288.                 work.serial = ai->serial;
  7289.                 ai->serial = aim->serial;
  7290.                 aim->serial = work.serial;
  7291.             }
  7292.         }
  7293.     }
  7294. }
  7295.  
  7296.  
  7297. /*
  7298.  * Build equivalence class vector
  7299.  */
  7300.  
  7301. void equiv(void)
  7302. {
  7303.     register DIFF_LINE  *ap;
  7304.     union {
  7305.         DIFF_LINE           *bp;
  7306.         short          *mp;
  7307.     }       r;
  7308.     register int    j;
  7309.     DIFF_LINE           *atop;
  7310.  
  7311.     j = 1;
  7312.     ap = &sfileA[1];
  7313.     r.bp = &sfileB[1];
  7314.     atop = &sfileA[slenA];
  7315.     while (ap <= atop && j <= slenB) {
  7316.         if (ap->hash < r.bp->hash) {
  7317.             ap->hash = 0;
  7318.             ap++;
  7319.         } else if (ap->hash == r.bp->hash) {
  7320.             ap->hash = j;
  7321.             ap++;
  7322.         } else {
  7323.             r.bp++;
  7324.             j++;
  7325.         }
  7326.     }
  7327.     while (ap <= atop) {
  7328.         ap->hash = 0;
  7329.         ap++;
  7330.     }
  7331.     sfileB[slenB + 1].hash = 0;
  7332.     ap = &sfileB[0];
  7333.     atop = &sfileB[slenB];
  7334.     r.mp = &gg.member[0];
  7335.     while (++ap <= atop) {
  7336.         r.mp++;
  7337.         *r.mp = -(ap->serial);
  7338.         while (ap[1].hash == ap->hash) {
  7339.             ap++;
  7340.             r.mp++;
  7341.             *r.mp = ap->serial;
  7342.         }
  7343.     }
  7344.     r.mp[1] = -1;
  7345. }
  7346.  
  7347.  
  7348. /*
  7349.  * Build class vector
  7350.  */
  7351.  
  7352. void unsort(void)
  7353. {
  7354.     register int   *temp;
  7355.     register int   *tp;
  7356.     union {
  7357.         DIFF_LINE           *ap;
  7358.         short          *cp;
  7359.     }       u;
  7360.     DIFF_LINE           *evec;
  7361.     short          *eclass;
  7362.  
  7363.     temp = (int *) myalloc((slenA + 1) * sizeof(int), "unsort scratch");
  7364.     u.ap = &sfileA[1];
  7365.     evec = &sfileA[slenA];
  7366.     while (u.ap <= evec) {
  7367.         temp[u.ap->serial] = u.ap->hash;
  7368.         u.ap++;
  7369.     }
  7370.  
  7371.     /*
  7372.      * Copy into class vector and free work space 
  7373.      */
  7374.     u.cp = &gg.class[1];
  7375.     eclass = &gg.class[slenA];
  7376.     tp = &temp[1];
  7377.     while (u.cp <= eclass)
  7378.         *u.cp++ = *tp++;
  7379.     free((char *) temp);
  7380. }
  7381.  
  7382.  
  7383. /*
  7384.  * Generate maximum common subsequence chain in clist[]
  7385.  */
  7386.  
  7387. int subseq(void)
  7388. {
  7389.     int     a;
  7390.     register unsigned ktop;
  7391.     register int    b;
  7392.     register int    s;
  7393.     unsigned    r;
  7394.     int     i;
  7395.     int     cand;
  7396.  
  7397.     gg.klist[0] = newcand(0, 0, -1);
  7398.     gg.klist[1] = newcand(slenA + 1, slenB + 1, -1);
  7399.     ktop = 1;                   /* -> guard entry  */
  7400.     for (a = 1; a <= slenA; a++) {
  7401.  
  7402.         /*
  7403.          * For each non-zero element in fileA ... 
  7404.          */
  7405.         if ((i = gg.class[a]) == 0)
  7406.             continue;
  7407.         cand = gg.klist[0];        /* No candidate now  */
  7408.         r = 0;              /* Current r-candidate  */
  7409.         do {
  7410.  
  7411.             /*
  7412.              * Perform the merge algorithm 
  7413.              */
  7414.             if ((b = gg.member[i]) < 0)
  7415.                 b = -b;
  7416.             if ((s = search(r, ktop, b)) != 0) {
  7417.                 if (gg.clist[gg.klist[s]].b > b) {
  7418.                     gg.klist[r] = cand;
  7419.                     r = s;
  7420.                     cand = newcand(a, b, gg.klist[s - 1]);
  7421.                 }
  7422.                 if (s >= (int)ktop) {
  7423.                     gg.klist[ktop + 1] = gg.klist[ktop];
  7424.                     ktop++;
  7425.                     break;
  7426.                 }
  7427.             }
  7428.         } while (gg.member[++i] > 0);
  7429.         gg.klist[r] = cand;
  7430.     }
  7431.     return (ktop - 1);          /* Last entry found  */
  7432. }
  7433.  
  7434.  
  7435. int newcand(int a, int b, int pred)
  7436. //    int  a;         /* Line in fileA      */
  7437. //    int  b;         /* Line in fileB      */
  7438. //   int  pred;      /* Link to predecessor, index in cand[]  */
  7439. {
  7440.     register CANDIDATE far *new;
  7441.  
  7442.     gg.clength++;
  7443.     if (++gg.clength >= gg.csize) {
  7444.         gg.csize += CSIZE_INC;
  7445.         gg.clist = (CANDIDATE *) compact((char *) gg.clist,
  7446.                           gg.csize * sizeof(CANDIDATE),
  7447.                           "extending clist");
  7448.     }
  7449.     new = &gg.clist[gg.clength - 1];
  7450.     new->a = a;
  7451.     new->b = b;
  7452.     new->link = pred;
  7453.     return (gg.clength - 1);
  7454. }
  7455.  
  7456.  
  7457. /*
  7458.  * Search klist[low..top] (inclusive) for b.  If klist[low]->b >= b,
  7459.  * return zero.  Else return s such that klist[s-1]->b < b and
  7460.  * klist[s]->b >= b.  Note that the algorithm presupposes the two
  7461.  * preset "fence" elements, (0, 0) and (slenA, slenB).
  7462.  */
  7463.  
  7464. unsigned search(unsigned low, unsigned high, int b)
  7465. {
  7466.     register int    temp;
  7467.     register unsigned mid;
  7468.  
  7469.     if (gg.clist[gg.klist[low]].b >= b)
  7470.         return (0);
  7471.     while ((mid = (low + high) / 2) > low) {
  7472.         if ((temp = gg.clist[gg.klist[mid]].b) > b)
  7473.             high = mid;
  7474.         else if (temp < b)
  7475.             low = mid;
  7476.         else {
  7477.             return (mid);
  7478.         }
  7479.     }
  7480.     return (mid + 1);
  7481. }
  7482.  
  7483.  
  7484. void unravel(int k)
  7485. {
  7486.     register int    i;
  7487.     register CANDIDATE far *cp;
  7488.     int     first_trailer;
  7489.     int     difference;
  7490.  
  7491.     first_trailer = lenA - gg.suffix;
  7492.     difference = lenB - lenA;
  7493.     for (i = 0; i <= lenA; i++) {
  7494.         gg.match[i] = (i <= gg.prefix) ? i
  7495.             : (i > first_trailer) ? i + difference
  7496.             : 0;
  7497.     }
  7498.     while (k != -1) {
  7499.         cp = &gg.clist[k];
  7500.         gg.match[cp->a + gg.prefix] = cp->b + gg.prefix;
  7501.         k = cp->link;
  7502.     }
  7503. }
  7504.  
  7505.  
  7506. /*
  7507.  * Check for hash matches (jackpots) and collect random access indices to
  7508.  * the two files.
  7509.  *
  7510.  * It should be possible to avoid doing most of the ftell's by noticing
  7511.  * that we are not doing a context diff and noticing that if a line
  7512.  * compares equal to the other file, we will not ever need to know its
  7513.  * file position.  FIXME.
  7514.  */
  7515.  
  7516. int check(char *fileAname, char *fileBname)
  7517. {
  7518.     register int    a;          /* Current line in file A  */
  7519.     register int    b;          /* Current line in file B  */
  7520.     int     jackpot;
  7521.  
  7522. /*
  7523.  * The VAX C ftell() returns the address of the CURRENT record, not the
  7524.  * next one (as in DECUS C or, effectively, other C's).  Hence, the values
  7525.  * are "off by one" in the array.  OFFSET compensates for this.
  7526.  */
  7527.  
  7528. #define OFFSET 0
  7529.  
  7530.     b = 1;
  7531.     rewind(gg.infd[0]);
  7532.     rewind(gg.infd[1]);
  7533. /*
  7534.  * See above; these would be over-written on VMS anyway.
  7535.  */
  7536.  
  7537.     gg.oldseek[0] = ftell(gg.infd[0]);
  7538.     gg.newseek[0] = ftell(gg.infd[1]);
  7539.  
  7540.     jackpot = 0;
  7541.     for (a = 1; a <= lenA; a++) {
  7542.         if (gg.match[a] == 0) {
  7543.             /* Unique line in A */
  7544.             gg.oldseek[a + OFFSET] = ftell(gg.infd[0]);
  7545.             getline(gg.infd[0], gg.text);
  7546.             continue;
  7547.         }
  7548.         while (b < gg.match[a]) {
  7549.             /* Skip over unique lines in B */
  7550.             gg.newseek[b + OFFSET] = ftell(gg.infd[1]);
  7551.             getline(gg.infd[1], gg.textb);
  7552.             b++;
  7553.         }
  7554.  
  7555.     /*
  7556.      * Compare the two, supposedly matching, lines. Unless we are going
  7557.      * to print these lines, don't bother to remember where they are.  We
  7558.      * only print matching lines if a context diff is happening, or if a
  7559.      * jackpot occurs. 
  7560.      */
  7561.         if (gg.cflag) {
  7562.             gg.oldseek[a + OFFSET] = ftell(gg.infd[0]);
  7563.             gg.newseek[b + OFFSET] = ftell(gg.infd[1]);
  7564.         }
  7565.         getline(gg.infd[0], gg.text);
  7566.         getline(gg.infd[1], gg.textb);
  7567.         if (!streq(gg.text, gg.textb)) {
  7568.             char buf[80];
  7569.  
  7570.             _snprintf(buf, sizeof(buf), "Spurious match:\n");
  7571.             cwFputs(buf, (LPSTR)-1);
  7572.             _snprintf(buf, sizeof(buf), "line %d in %s, \"%s\"\n",
  7573.                                          a, fileAname, gg.text);
  7574.             cwFputs(buf, (LPSTR)-1);
  7575.             _snprintf(buf, sizeof(buf), "line %d in %s, \"%s\"\n",
  7576.                                          b, fileBname, gg.textb);
  7577.             cwFputs(buf, (LPSTR)-1);
  7578.  
  7579.             gg.match[a] = 0;
  7580.             jackpot++;
  7581.         }
  7582.         b++;
  7583.     }
  7584.     for (; b <= lenB; b++) {
  7585.         gg.newseek[b + OFFSET] = ftell(gg.infd[1]);
  7586.         getline(gg.infd[1], gg.textb);
  7587.     }
  7588. /*
  7589.  * The logical converse to the code up above, for NON-VMS systems, to
  7590.  * store away an fseek() pointer at the beginning of the file.  For VMS,
  7591.  * we need one at EOF...
  7592.  */
  7593.  
  7594.     return (jackpot);
  7595. }
  7596.  
  7597.  
  7598. void output(char *fileAname, char *fileBname)
  7599. {
  7600.     register int    astart;
  7601.     register int    aend = 0;
  7602.     int     bstart;
  7603.     register int    bend;
  7604.  
  7605.     rewind(gg.infd[0]);
  7606.     rewind(gg.infd[1]);
  7607.     gg.match[0] = 0;
  7608.     gg.match[lenA + 1] = lenB + 1;
  7609.     if (!gg.eflag) {
  7610.         if (gg.cflag) {
  7611.  
  7612.         /*
  7613.          * Should include ctime style dates after the file names, but
  7614.          * this would be non-trivial on OSK. Perhaps there should be a
  7615.          * special case for stdin. 
  7616.          */
  7617.             char buf[80];
  7618.             _snprintf(buf, sizeof(buf), "*** %s\n--- %s\n",
  7619.                       fileAname, fileBname);
  7620.             cwFputs(buf, NULL);
  7621.         }
  7622.  
  7623.         /*
  7624.          * Normal printout 
  7625.          */
  7626.         for (astart = 1; astart <= lenA; astart = aend + 1) {
  7627.  
  7628.             /*
  7629.              * New subsequence, skip over matching stuff 
  7630.              */
  7631.             while (astart <= lenA
  7632.                    && gg.match[astart] == (gg.match[astart - 1] + 1))
  7633.                 astart++;
  7634.  
  7635.             /*
  7636.              * Found a difference, setup range and print it 
  7637.              */
  7638.             bstart = gg.match[astart - 1] + 1;
  7639.             aend = astart - 1;
  7640.             while (aend < lenA && gg.match[aend + 1] == 0)
  7641.                 aend++;
  7642.             bend = gg.match[aend + 1] - 1;
  7643.             gg.match[aend] = bend;
  7644.             change(astart, aend, bstart, bend);
  7645.         }
  7646.     } else {
  7647.  
  7648.     /*
  7649.      * Edit script output -- differences are output "backwards" for the
  7650.      * benefit of a line-oriented editor. 
  7651.      */
  7652.         for (aend = lenA; aend >= 1; aend = astart - 1) {
  7653.             while (aend >= 1
  7654.                    && gg.match[aend] == (gg.match[aend + 1] - 1)
  7655.                    && gg.match[aend] != 0)
  7656.                 aend--;
  7657.             bend = gg.match[aend + 1] - 1;
  7658.             astart = aend + 1;
  7659.             while (astart > 1 && gg.match[astart - 1] == 0)
  7660.                 astart--;
  7661.             bstart = gg.match[astart - 1] + 1;
  7662.             gg.match[astart] = bstart;
  7663.             change(astart, aend, bstart, bend);
  7664.         }
  7665.     }
  7666.     if (lenA == 0)
  7667.         change(1, 0, 1, lenB);
  7668. }
  7669.  
  7670.  
  7671. /*
  7672.  * Output a change entry: fileA[astart..aend] changed to fileB[bstart..bend]
  7673.  */
  7674.  
  7675. void change(int astart, int aend, int bstart, int bend)
  7676. {
  7677.     char        c;
  7678.  
  7679.     /*
  7680.      * This catches a "dummy" last entry 
  7681.      */
  7682.     if (astart > aend && bstart > bend)
  7683.         return;
  7684.     c = (astart > aend) ? 'a' : (bstart > bend) ? 'd' : 'c';
  7685.     if (gg.cflag)
  7686.         cwFputs("**************\n*** ", NULL);
  7687.  
  7688.     if (c == 'a' && !gg.cflag)
  7689.         range(astart - 1, astart - 1, 0); /* Addition: just print one
  7690.                                  * odd # */
  7691.     else
  7692.         range(astart, aend, 0); /* Print both, if different */
  7693.     if (!gg.cflag) {
  7694.         char buf[2];
  7695.         buf[0] = c;
  7696.         buf[1] = '\0';
  7697.         cwFputs(buf, NULL);
  7698.         if (!gg.eflag) {
  7699.             if (c == 'd')
  7700.                 range(bstart - 1, bstart - 1, 1);
  7701.                  /* Deletion: just print * one odd # */
  7702.             else
  7703.                 range(bstart, bend, 1);
  7704.                  /* Print both, if different */
  7705.         }
  7706.     }
  7707.     cwFputs("\n", NULL);
  7708.     if ((!gg.eflag && c != 'a') || gg.cflag) {
  7709.         fetch(gg.oldseek, astart, aend, lenA, gg.infd[0],
  7710.               gg.cflag ? (c == 'd' ? "- " : "! ") : "< ");
  7711.         if (gg.cflag) {
  7712.             cwFputs("--- ", NULL);
  7713.             range(bstart, bend, 1);
  7714.             cwFputs(" -----\n", NULL);
  7715.         } else if (astart <= aend && bstart <= bend)
  7716.             cwFputs("---\n", NULL);
  7717.     }
  7718.     fetch(gg.newseek, bstart, bend, lenB, gg.infd[1],
  7719.           gg.cflag ? (c == 'a' ? "+ " : "! ") : (gg.eflag ? "" : "> "));
  7720.     if (gg.eflag && bstart <= bend)
  7721.         cwFputs(".\n", NULL);
  7722. }
  7723.  
  7724.  
  7725. /*
  7726.  * Print a range
  7727.  */
  7728.  
  7729. void range(int from, int to, int w)
  7730. {
  7731.     char buf[80];
  7732.  
  7733.     if (gg.cflag) {
  7734.         if ((from -= gg.cflag) <= 0)
  7735.             from = 1;
  7736.         if ((to += gg.cflag) > gg.len[w])
  7737.             to = gg.len[w];
  7738.     }
  7739.     if (to > from) {
  7740.         _snprintf(buf, sizeof(buf), "%d,%d", from, to); cwFputs(buf, NULL);
  7741.     } else if (to < from) {
  7742.         _snprintf(buf, sizeof(buf), "%d,%d", to, from); cwFputs(buf, NULL);
  7743.     } else {
  7744.         _snprintf(buf, sizeof(buf), "%d", from); cwFputs(buf, NULL);
  7745.     }
  7746. }
  7747.  
  7748.  
  7749. /*
  7750.  * Print the appropriate text
  7751.  */
  7752.  
  7753. void fetch(long *seekvec,
  7754.            int start,
  7755.            int end,
  7756.            int trueend,
  7757.            FILE *fd,
  7758.            char *pfx)
  7759. {
  7760.     register int    i;
  7761.     register int    first;
  7762.     register int    last;
  7763.  
  7764.     if (gg.cflag) {
  7765.         if ((first = start - gg.cflag) <= 0)
  7766.             first = 1;
  7767.         if ((last = end + gg.cflag) > trueend)
  7768.             last = trueend;
  7769.     } else {
  7770.         first = start;
  7771.         last = end;
  7772.     }
  7773. /* added by Nide */
  7774.     if (first == last + 1) { /* do nothing */
  7775.     } else
  7776. /* added by Nide end */
  7777.     if (fseek(fd, seekvec[first], 0) != 0) {
  7778.         char buf[80];
  7779.         _snprintf(buf, sizeof(buf),
  7780.                   "?Can't read line %d at %08lx (hex) in file%c\n",
  7781.                    start, seekvec[first],
  7782.                    (fd == gg.infd[0]) ? 'A' : 'B');
  7783.         cwFputs(buf, NULL);
  7784.     } else {
  7785.         for (i = first; i <= last; i++) {
  7786.             if (fgetss(gg.text, sizeof(gg.text), fd) == NULL) {
  7787.                 char buf[80];
  7788.                 _snprintf(buf, sizeof(buf), "** Unexpected end of file\n");
  7789.                 cwFputs(buf, NULL);
  7790.                 break;
  7791.             }
  7792.             cwFputs((gg.cflag && (i < start || i > end)) ? "  " : pfx,
  7793.                 NULL);
  7794.             cwFputs(gg.text, NULL);
  7795.             cwFputs("\n", NULL);
  7796.         }
  7797.     }
  7798. }
  7799.  
  7800.  
  7801. /*
  7802.  * Input routine, read one line to buffer[], return TRUE on eof, else FALSE.
  7803.  * The terminating newline is always removed.  If "-b" was given, trailing
  7804.  * whitespace (blanks and tabs) are removed and strings of blanks and
  7805.  * tabs are replaced by a single blank.  Getline() does all hacking for
  7806.  * redirected input files.
  7807.  */
  7808.  
  7809. int getline(FILE *fd, char *buffer)
  7810. {
  7811.     register char  *top;
  7812.     register char  *fromp;
  7813.     register char   c;
  7814.  
  7815.     if (fgetss(buffer, sizeof(gg.text), fd) == NULL) {
  7816.         *buffer = EOS;
  7817.         return (TRUE);
  7818.     }
  7819.     if (fd == NULL)
  7820.         fputss(buffer, gg.tempfd);
  7821.     if (gg.bflag || gg.iflag) {
  7822.         top = buffer;
  7823.         fromp = buffer;
  7824.         while ((c = *fromp++) != EOS) {
  7825.             if (gg.bflag && (c == ' ' || c == '\t')) {
  7826.                 c = ' ';
  7827.                 while (*fromp == ' ' || *fromp == '\t')
  7828.                     fromp++;
  7829.             }
  7830.             if (gg.iflag)
  7831.                 c = tolower(c);
  7832.             *top++ = c;
  7833.         }
  7834.         if (gg.bflag && top[-1] == ' ')
  7835.             top--;
  7836.         *top = EOS;
  7837.     }
  7838.     return (FALSE);
  7839. }
  7840.  
  7841.  
  7842. unsigned short crc16a[] = {
  7843.                       0000000, 0140301, 0140601, 0000500,
  7844.                       0141401, 0001700, 0001200, 0141101,
  7845.                       0143001, 0003300, 0003600, 0143501,
  7846.                       0002400, 0142701, 0142201, 0002100,
  7847. };
  7848.  
  7849. unsigned short crc16b[] = {
  7850.                       0000000, 0146001, 0154001, 0012000,
  7851.                       0170001, 0036000, 0024000, 0162001,
  7852.                       0120001, 0066000, 0074000, 0132001,
  7853.                       0050000, 0116001, 0104001, 0043000,
  7854. };
  7855.  
  7856.  
  7857. /*
  7858.  * Return the CRC16 hash code for the buffer
  7859.  * Algorithm from Stu Wecker (Digital memo 130-959-002-00).
  7860.  */
  7861.  
  7862. unsigned short hash(char *buffer)
  7863. {
  7864.     register unsigned short crc;
  7865.     register char  *tp;
  7866.     register short  temp;
  7867.  
  7868.     crc = 0;
  7869.     for (tp = buffer; *tp != EOS;) {
  7870.         temp = *tp++ ^ crc;     /* XOR crc with new char  */
  7871.         crc = (crc >> 8)
  7872.             ^ crc16a[(temp & 0017)]
  7873.             ^ crc16b[(temp & 0360) >> 4];
  7874.     }
  7875.     return ((crc == 0) ? (unsigned short) 1 : crc);
  7876. }
  7877.  
  7878. /*
  7879.  * Allocate or crash.
  7880.  */
  7881.  
  7882. char *myalloc(unsigned amount, char *why)
  7883. {
  7884.     register char  *pointer;
  7885.  
  7886.     if ((pointer = malloc((unsigned) amount)) == NULL) {
  7887.         noroom(why);
  7888.         return NULL;
  7889.     }
  7890.     return (pointer);
  7891. }
  7892.  
  7893. /*
  7894.  * Reallocate pointer, compacting storage
  7895.  *
  7896.  * The "compacting storage" part is probably not relevant any more.
  7897.  * There used to be horrid code here that malloc'd one byte and freed
  7898.  * it at magic times, to cause garbage collection of the freespace
  7899.  * or something.  It's safely gone now, you didn't have to see it.
  7900.  *  -- John Gilmore, Nebula Consultants, Sept 26, 1986
  7901.  */
  7902.  
  7903. char *compact(char *pointer, unsigned new_amount, char *why)
  7904. {
  7905.     register char  *new_pointer;
  7906.  
  7907.  
  7908.     if ((new_pointer = realloc(pointer, (unsigned) new_amount)) == NULL) {
  7909.         noroom(why);
  7910.         return NULL;
  7911.     }
  7912.     return (new_pointer);
  7913. }
  7914.  
  7915.  
  7916. void noroom(char *why)
  7917. {
  7918.     char buf[80];
  7919.  
  7920.     _snprintf(buf, sizeof(buf), "?DIFF-F-out of room when %s\n", why);
  7921.     cwFputs(buf, (LPSTR)-1);
  7922.     MessageBox(NULL, "IO_ERROR", "cwtools.dll", MB_OK);
  7923.     // exit(IO_ERROR);
  7924. }
  7925.  
  7926. /*
  7927.  * Can't open file message
  7928.  */
  7929.  
  7930. int cant(char *filename,
  7931.           char *what,
  7932.           int fatalflag)
  7933. {
  7934.     char buf[80];
  7935.  
  7936.     _snprintf(buf, sizeof(buf), 
  7937.              "Can't open %s file \"%s\": ", what, filename);
  7938.     cwFputs(buf, (LPSTR)-1); cwFputs("\n", (LPSTR)-1);
  7939. //  perror("");
  7940.     if (fatalflag) {
  7941.         return fatalflag;
  7942.     }
  7943.     return 0;
  7944. }
  7945.  
  7946. /*
  7947.  * TRUE if strings are identical
  7948.  */
  7949.  
  7950. int streq(char *s1, char *s2)
  7951. {
  7952.     while (*s1++ == *s2) {
  7953.         if (*s2++ == EOS)
  7954.             return (TRUE);
  7955.     }
  7956.     return (FALSE);
  7957. }
  7958.  
  7959.  
  7960. /*
  7961.  * Error message before retiring.
  7962.  */
  7963.  
  7964. /* VARARGS */
  7965. int differror(char *format, ...)
  7966. {
  7967.     char buf[0x100];
  7968.     va_list argptr;
  7969.  
  7970.     va_start(argptr, format);
  7971.     _vsnprintf(buf, sizeof(buf), format, argptr);
  7972.     cwFputs(buf, (LPSTR)-1);
  7973.     va_end(argptr);
  7974.     cwFputs("\n", (LPSTR)-1);
  7975.     return 1;
  7976. }
  7977.  
  7978.  
  7979. /*
  7980.  * Like fput() except that it puts a newline at the end of the line.
  7981.  */
  7982.  
  7983. void fputss(char *s, FILE *iop)
  7984. {
  7985.     if (iop == NULL) {
  7986.         cwPuts(s);
  7987.     } else {
  7988.         fputs(s, iop);
  7989.         putc('\n', iop);
  7990.     }
  7991. }
  7992.  
  7993.  
  7994. /*
  7995.  * Fgetss() is like fgets() except that the terminating newline
  7996.  * is removed. 
  7997.  */
  7998.  
  7999. char *fgetss(char *s, int n, FILE *iop)
  8000. {
  8001.     register char  *cs;
  8002.  
  8003.     if (((iop == NULL) ? cwFgets(s, n, NULL) : fgets(s, n, iop)) == NULL)
  8004.         return ((char *) NULL);
  8005.     cs = s + strlen(s) - 1;
  8006.     if (*cs == '\n')
  8007.         *cs = '\0';
  8008.     return (s);
  8009. }
  8010.  
  8011.  /* From here, added by Nide */
  8012.  
  8013. int isdir(char *fnm) /* on TURBOC, which files are needed to be included? */
  8014. {
  8015.     struct  stat    statbuf;
  8016.     char    *p, *q, *r;
  8017.  
  8018.     for(p = q = NULL, r = fnm; *r;
  8019.         p = q, q = r, r += (iskanjipos(r) ? 2 : 1));
  8020.     if(q == NULL || isdelim(*q) ||
  8021.        *q == '.' && (p == NULL || isdelim(*p) || *p == '.')) return(1);
  8022.     
  8023.     return(stat(fnm, &statbuf) == 0 && (statbuf . st_mode & S_IFDIR));
  8024. }
  8025.  
  8026. char *difftmpnam(void) /* ad hoc */
  8027. {
  8028.     char    *p;
  8029.  
  8030.     sprintf(gg.s_name, "dtmp%04x.$$$", (short)getpid());
  8031.     if(NULL == (p = getenv("TMP")) &&
  8032.        NULL == (p = getenv("TEMP"))) return(gg.s_name);
  8033.     return(dircat(p, gg.s_name));
  8034. }
  8035.  
  8036. char *basefname(char *fnm)
  8037. {
  8038.     char    *p, *q;
  8039.  
  8040.     for(p = NULL, q = fnm; *q; q += (iskanjipos(q) ? 2 : 1)){
  8041.         if(isdelim(*q)) p = q;
  8042.     }
  8043.     return(p == NULL ? fnm : ++p);
  8044. }
  8045.  
  8046. char *dircat(char *dir, char *fnm)
  8047. {
  8048.     char    *buf, *p, *q;
  8049.  
  8050.     fnm = basefname(fnm);
  8051.  
  8052.     if(NULL == (buf = malloc(strlen(dir) + 1 + strlen(fnm) + 1))){
  8053.         cwFputs("diff: Memory not enough.\n", NULL);
  8054.         return NULL;
  8055.     }
  8056.     for(p = NULL, q = dir; *q; p = q, q += (iskanjipos(q) ? 2 : 1));
  8057.     sprintf(buf, (p == NULL || !isdelim(*p)) ? "%s/%s" : "%s%s",
  8058.             dir, fnm);
  8059.  
  8060.     return(buf);
  8061. }
  8062.  
  8063. /*---------*/
  8064. /* ls_main */
  8065. /*---------*/
  8066. /**
  8067.  *  UNIX like  ls  (originally for Human68k)
  8068.  *
  8069.  *     Public domain: written by Kaoru Maeda, March, 1989.
  8070.  *      Modified for MS-DOS by Yasushi Saito, April, 1989.
  8071.  *
  8072.  *  Modified by Yasushi Saito(Oct 5 1989) 'ls -ld' works good.
  8073.  */
  8074.  
  8075.  
  8076. int ls_usage(void)
  8077. /* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
  8078. {
  8079.     cwFputs("Usage: ls [-RadCxBXlrtFsU1c] <files>...\n\
  8080. -R : recursive directory search\n\
  8081. -a : print hidden files, _* files\n\
  8082. -d : do not look inside directory\n\
  8083. -C : vertical sort\n\
  8084. -x : horizontal sort\n\
  8085. -B : sort by filesize\n\
  8086. -X : sort by extention\n\
  8087. -l : long output\n\
  8088. -r : reverse sort\n\
  8089. -t : sort by file timestamp\n\
  8090. -F : display file type\n\
  8091. -s : display file size\n\
  8092. -U : no sorting\n\
  8093. -1 : 1 file per line\n\
  8094. -c : color output\n", (LPSTR)-1);
  8095.     return 2;
  8096. }
  8097.  
  8098.  
  8099. /*
  8100.  * Allocate one space for dirfile.
  8101.  * 
  8102.  */
  8103. dirfile *allocate_dir(char *name)
  8104. {
  8105.     dirfile *p;
  8106.     p = xmalloc(sizeof(dirfile));
  8107.     p->fullname = xstrdup(name);
  8108.     return p;
  8109. }
  8110. /*
  8111.  * Push the directory-chain to the directory stack.
  8112.  * 
  8113.  */
  8114. void link_dir_chain(dirfile *top, dirfile *last)
  8115. {
  8116.     last->next = gg.dirs;
  8117.     gg.dirs = top;
  8118. }
  8119. /*
  8120.  * Push one directory to the directory stack.
  8121.  */
  8122. void add_dir_list(char *name)
  8123. {
  8124.     dirfile *p;
  8125.     p = allocate_dir(name);
  8126.     link_dir_chain(p, p);
  8127. }
  8128.  
  8129. /*
  8130.  * Add one file to the output file chain.
  8131.  * 
  8132.  */
  8133. void add_file_list(char *name, bool fullname, unsigned volmask)
  8134. {
  8135.     int intended_as_directory;
  8136.     register bool c = false;
  8137.  
  8138.     if(intended_as_directory = regularize_pathname(name)) {
  8139.         volmask &= ~VOL_MASK;
  8140.     }
  8141.     /* Add Nide */
  8142.     if((volmask & VOL_MASK) && (volmask & ~VOL_MASK)){
  8143.         if(c = add_file_list_sub(name, fullname, VOL_MASK,
  8144.                       true, intended_as_directory))
  8145.             gg.filenum++;
  8146.         volmask &= ~VOL_MASK;
  8147.     }
  8148.     add_file_list_sub(name, fullname, volmask, c, intended_as_directory);
  8149. }
  8150.  
  8151. void say_noex(char *s, int dirmode)
  8152. {
  8153.     cwFputs(s_conv_to_unix_format(s), (LPSTR)-1);
  8154.     if(dirmode) cwFputs("/", (LPSTR)-1);
  8155.     cwFputs(" not exist.\n", (LPSTR)-1);
  8156. }
  8157.  
  8158. long _xfindfirst(char *p, struct _finddata_t *f)
  8159. {
  8160.     return _findfirst(p, f);
  8161. }
  8162.  
  8163. int  can_cd_there(char *s)
  8164. {
  8165.     return SetCurrentDirectory(s);
  8166. }
  8167.  
  8168. bool add_file_list_sub(char *name, 
  8169.                        bool fullname,
  8170.                        unsigned volmask,
  8171.                        bool nomsg,
  8172.                        int intended_as_directory)
  8173. /* separated from add_file_list() by Nide; これが呼ばれるとき、volmaskの
  8174.    第3ビットとそれ以外が同時に立つことはない(ようにすること) */
  8175. {
  8176.     struct  _finddata_t  fb;
  8177.     long lfind;
  8178.     diff_file    *p, *q, *r;
  8179.     int c;
  8180.     char    *rs;
  8181.  
  8182.     /* Get file status */
  8183.     memset(&fb, 0, sizeof(fb));
  8184.     fb.attrib = volmask;
  8185.     lfind = _xfindfirst(name, &fb);
  8186.     if(lfind != -1){
  8187.         _findclose(lfind);
  8188.     } else { /* Changed Nide */
  8189.         /*
  8190.          * Failed to read the NAME as normal file. is it a special
  8191.          * file:-), or root??. Check it here.
  8192.          */
  8193.         /* char buf[128]; */
  8194.         /* volmask check add Nide */
  8195.  
  8196.         if(volmask & VOL_MASK){
  8197.          /* 小文字まじりの変なvolume label対応。ああめんどくさ */
  8198.             char    tmp[10];
  8199.  
  8200.             if(is_alpha(*name) && name[1] == ':'){
  8201.                 strncpy(tmp, name, 2);
  8202.                 strcpy(tmp+2, "*.*");
  8203.             } else {
  8204.                 strcpy(tmp, "*.*");
  8205.             }
  8206.             memset(&fb, 0, sizeof(fb));
  8207.             fb.attrib = VOL_MASK;
  8208.             lfind = _findfirst(tmp, &fb);
  8209.             if (lfind != -1) {
  8210.                 goto notexist;
  8211.             } else {
  8212.                 _findclose(lfind);
  8213.             }
  8214.             if(stricmp(fb.name, strip_directory_part(name))) {
  8215.                 goto notexist;
  8216.             }
  8217.              /* そうでない場合、変ではあるがvolume labelがある */
  8218.         } else if(can_cd_there(name)){
  8219.             fb.attrib = DIR_MASK;
  8220.             strcpy(fb.name, strip_directory_part(name));
  8221.             fb.size = 0;
  8222.             dosdatetime_to_time_t(0x21, 0, &fb.time_write);
  8223.         } else {
  8224.         notexist:
  8225.             if(!nomsg) {
  8226.                 say_noex(name, 0);
  8227.             }
  8228.             return false;
  8229.         }
  8230.     }
  8231.     /*
  8232.      * Ignore the plain file, which is intended to be a directory
  8233.      * file(i.e. ends with '\').
  8234.      * 
  8235.      * By this,  LS will return error if the pathname is specified as
  8236.      * '\etc\passwd\', even if the plain file '\etc\passwd' exists.
  8237.      */
  8238.  
  8239.     if(!(fb.attrib & DIR_MASK) && intended_as_directory){
  8240.         if(!nomsg) {
  8241.             say_noex(name, 1);
  8242.         }
  8243.         return false;
  8244.     }
  8245.     if(fullname && !gg.d_opt && (fb.attrib & DIR_MASK)){
  8246.         add_dir_list(name);
  8247.         return true;
  8248.     }
  8249.     p = xmalloc(sizeof(diff_file));
  8250.     rs = strip_directory_part(name);
  8251.     if(*gg.current_directory == 0){
  8252.         /* Set current directory */
  8253.         strncpy(gg.current_directory, name, rs - name);
  8254.         gg.current_directory[rs - name] = 0;
  8255.     }
  8256.     if(fullname /* && (rs != name) */ ) {
  8257.         rs = name;
  8258.     }
  8259.     conv_to_unix_format(p->name = xstrdup(rs)); /* Nide */
  8260.     p->attr = fb.attrib;
  8261.     time_t_to_dosdatetime(&fb.time_write, &p->date.dt.d, &p->date.dt.t);
  8262.     p->size = fb.size;
  8263.  
  8264.     /* Insert the file into the proper position */
  8265.     for(r = NULL, q = gg.files; q; r = q, q = q->next){
  8266.         if(gg.t_opt){
  8267.             unsigned short pd, qd;
  8268.             pd = p->date.dt.d, qd = q->date.dt.d;
  8269.             if(qd > pd) c = 1;
  8270.             else if(qd < pd) c = -1;
  8271.             else {
  8272.                 pd = p->date.dt.t, qd = q->date.dt.t;
  8273.                 if(qd > pd) c = 1;
  8274.                 else if(qd < pd) c = -1;
  8275.                 else goto name_comparison;
  8276.             }
  8277.         } else if(gg.X_opt){
  8278.             off_t ps, qs;
  8279.             ps = p->size, qs = q->size;
  8280.             if(qs > ps) c = 1;
  8281.             else if(qs < ps) c = -1;
  8282.             else goto name_comparison;
  8283.         } else if(gg.S_opt){
  8284.             c = 1;
  8285.         } else if(gg.Sort_by_ext_opt){
  8286.             char    *pdot = strchr(p->name, '.');
  8287.             char    *qdot = strchr(q->name, '.');
  8288.             char    n = 0;
  8289.  
  8290.             if(pdot == NULL) pdot = &n;
  8291.             if(qdot == NULL) qdot = &n;
  8292.             if(!(c = strcmp(pdot, qdot))) goto name_comparison;
  8293.         } else {
  8294.     name_comparison:
  8295.             c = strcmp(p->name, q->name);
  8296.             if(!c) c = (q->attr & VOL_MASK) - (p->attr & VOL_MASK);
  8297.              /* Add Nide,
  8298.                  同名のvolume labelとfileが存在する場合に備えて */
  8299.             if(!c){
  8300.                 free(p->name);
  8301.                 free(p);
  8302.                 return false;   /* false Ok? */
  8303.             }
  8304.         }
  8305.         if(gg.r_opt) c = -c;
  8306.         if(c < 0) break;
  8307.     }
  8308.     if(r) {
  8309.         r->next = p;
  8310.     } else {
  8311.         gg.files = p;
  8312.     }
  8313.     p->next = q;
  8314.     return true;
  8315. }
  8316.  
  8317. int executable_p(diff_file *p)
  8318. {
  8319.     register char *cp;
  8320.     if(p->attr & DIR_MASK) return true;
  8321.     if(p->attr & (VOL_MASK | DEV_MASK)) return false;
  8322.     cp = p->name, cp += strlen(cp) - 4;
  8323.     return (cp >= p->name && *cp++ == '.' &&
  8324.         (!stricmp(cp, "bat") || !stricmp(cp, "exe") ||
  8325.          !stricmp(cp, "com")));
  8326. }
  8327.  
  8328. int F_char(diff_file *p)
  8329. {
  8330.     if(gg.F_opt){
  8331.         if(p->attr & DIR_MASK) return '/';
  8332.         if(executable_p(p)) return '*';
  8333.     }
  8334.     return '\0';        /* Nide */
  8335. }
  8336.  
  8337.  
  8338. void nameout(diff_file *p)
  8339. {               /* Add Nide */
  8340.     int attr = p->attr, color;
  8341.     char   *name = p->name, *ext;
  8342.     char buf[0x100];
  8343.  
  8344.     if(gg.c_opt && 0 != (color = (
  8345.         attr & VOL_MASK ? 37 :
  8346.         attr & DEV_MASK ? 34 :
  8347.         attr & DIR_MASK ? 36 :
  8348.         attr & (SYS_MASK | INV_MASK) ? 35 :
  8349.         name <= (ext = name + strlen(name) - 4) && *ext++ == '.' ? (
  8350.             !stricmp(ext, "bak") || !stricmp(ext, "old") ? 31 :
  8351.             !stricmp(ext, "bat")                 ? 33 :
  8352.             !stricmp(ext, "exe") || !stricmp(ext, "com") ? 32 :
  8353.             !stricmp(ext, "sys") || !stricmp(ext, "drv") ? 35 : 0
  8354.           ) : 0))){
  8355.         _snprintf(buf, sizeof(buf), "\033[%dm", color); cwFputs(buf, NULL);
  8356.         if(attr & VOL_MASK) cwFputs("\033[7m", NULL); /* yueno@titech */
  8357.     }
  8358.     cwFputs(s_conv_to_unix_format(name), NULL);
  8359.     if(gg.c_opt && color) cwFputs("\033[m", NULL);
  8360. }
  8361.  
  8362. void print_short(diff_file *p, int col)
  8363. {               /* Changed Nide */
  8364.     int F_ch;
  8365.     char buf[0x100];
  8366.  
  8367.     if(!p){
  8368.         gg.s_prev_sp = 0;
  8369.         cwFputs("\n", NULL);
  8370.         return;
  8371.     }
  8372.     _snprintf(buf, sizeof(buf), "%*s", gg.s_prev_sp, ""); cwFputs(buf, NULL);
  8373.     if(gg.s_opt) {
  8374.          _snprintf(buf, sizeof(buf),
  8375.                    "%4ld ", (p->size + BLOCK_SIZE - 1) / BLOCK_SIZE);
  8376.          cwFputs(buf, NULL);
  8377.     }
  8378.     nameout(p);
  8379.     if(!gg.x_opt && !gg.C_opt){
  8380.         if('\0' != (F_ch = F_char(p)))
  8381.             putchar(F_ch);
  8382.         gg.s_prev_sp = 0;
  8383.         return;
  8384.     } else {
  8385.         gg.s_prev_sp = col - strlen(p->name) - (gg.s_opt ? 5 : 0) -
  8386.             ('\0' != (F_ch = F_char(p)) ? (putchar(F_ch), 1) : 0);
  8387.     }
  8388. }
  8389.  
  8390. void multi_output(void)
  8391. {
  8392.     register diff_file *p, *q;
  8393.     int maxlen, nfil, ncol, wcol, nrow;
  8394.  
  8395.     if(!gg.files) return;
  8396.  
  8397.     maxlen = nfil = 0;
  8398.     for(p = gg.files; p; p = p->next){
  8399.         register int l = strlen(p->name);
  8400.         if(l > maxlen) maxlen = l;
  8401.         nfil++;
  8402.     }
  8403.     if(gg.s_opt) maxlen += 5;
  8404.     wcol = (maxlen + 9) & ~7;
  8405.     ncol = gg.screenwidth / wcol;
  8406.     nrow = (nfil - 1) / ncol + 1;
  8407.  
  8408.     if(gg.x_opt){ /* Changed Nide、行末に余分な空白を付けないよう */
  8409.         int j = 0;
  8410.         for(p = gg.files; p; q = p->next, free(p), p = q){
  8411.             print_short(p, wcol);
  8412.             if(++j == ncol){
  8413.                 print_short(NULL, 0);
  8414.                 j = 0;
  8415.             }
  8416.             free(p->name);
  8417.         }
  8418.         if(nfil % ncol) print_short(NULL, 0);
  8419.     } else { /* -C option */
  8420.      /* Changed Nide、行末に余分な空白を付けないよう */
  8421.         int i, j, k;
  8422.         for(i = nrow; i--;){
  8423.             p = gg.files;
  8424.             for(k = nrow - i; --k;)
  8425.                 if(p) p = p->next;
  8426.             for(j = 0; j < ncol; j++){
  8427.                 if(p && (i || nfil % ncol == 0 ||
  8428.                      j < nfil % ncol))
  8429.                     print_short(p, wcol);
  8430.                 for(k = nrow - 1; k--;)
  8431.                     if(p) p = p->next;
  8432.                 if(nfil % ncol == 0 || j < nfil % ncol)
  8433.                     if(p) p = p->next;
  8434.             }
  8435.             print_short(NULL, 0);
  8436.         }
  8437.         for(p = gg.files; p; q = p->next, free(p), p = q)
  8438.             free(p->name);
  8439.         /* Nide, avoid "q used before set" */
  8440.     }
  8441. }
  8442.  
  8443. void one_output(void)
  8444. {
  8445.     diff_file   *p, *q;
  8446.  
  8447.     for(p = gg.files; p; q = p->next, free(p), p = q){
  8448.         print_short(p, 0);
  8449.         cwFputs("\n", NULL);
  8450.         free(p->name);
  8451.         /* Nide, avoid "q used before set" */
  8452.     }
  8453. }
  8454.  
  8455. void short_output(void)
  8456. {
  8457.     if(gg.C_opt || gg.x_opt) multi_output(); else one_output();
  8458. }
  8459.  
  8460. void long_output(void)
  8461. {
  8462.     diff_file   *p, *q;
  8463.     unsigned int month;
  8464.     char buf[0x100];
  8465.  
  8466.     for(p = gg.files; p; q = p->next, free(p), p = q){
  8467.         /* Nide, to avold "q may used before set" */
  8468.         char    mode[8];
  8469.  
  8470.         if(gg.s_opt){
  8471.             _snprintf(buf, sizeof(buf), "%4ld ",
  8472.                    (p->size + BLOCK_SIZE - 1) / BLOCK_SIZE);
  8473.             cwFputs(buf, NULL);
  8474.         } /* Add Nide */
  8475.  
  8476.         mode[0] = p->attr & DEV_MASK ? 'c' :
  8477.               p->attr & DIR_MASK ? 'd' :
  8478.               p->attr & VOL_MASK ? 'v' : '-';
  8479.         mode[1] = p->attr & ARC_MASK ? 'a' : '-';
  8480.         mode[2] = p->attr & SYS_MASK ? 's' : '-';
  8481.         mode[3] = p->attr & INV_MASK ? 'h' : '-';
  8482.         mode[4] = 'r';
  8483.         mode[5] = p->attr & RDO_MASK ? '-' : 'w';
  8484.         mode[6] = executable_p(p) ? 'x' : '-';
  8485.         mode[7] = F_char(p);
  8486.         /* Nide, 非ANSIコンパイラの便のために文字列連接をやめた */
  8487.         if((month = p->date.b.bh.month) > 12) {
  8488.             month = 0;
  8489.         }
  8490.         _snprintf(buf, sizeof(buf),
  8491.                "%.7s %7ld %.3s %2d %4d %02d:%02d ",
  8492.                mode, p->size, month_name + month * 3,
  8493.                p->date.b.bh.day,
  8494.                p->date.b.bh.year + 1980,
  8495.                (p->date.dt.t / 0x0800) & 0x1F,
  8496.                (p->date.dt.t / 0x0020) & 0x3F);
  8497.         cwFputs(buf, NULL);
  8498.         nameout(p);
  8499.         _snprintf(buf, sizeof(buf), "%.1s\n", mode + 7); cwFputs(buf, NULL);
  8500.         free(p->name);
  8501.     }
  8502. }
  8503.  
  8504. void output_files(void)
  8505. {
  8506.     dirfile *top, *last;
  8507.     diff_file   *f;
  8508.     char   *fn, *strip;
  8509.     if(!gg.d_opt && gg.R_opt){
  8510.         top = last = 0;
  8511.         fn = gg.current_directory + strlen(gg.current_directory);
  8512.         for(f = gg.files; f; f = f->next){
  8513.             if(f->attr & DIR_MASK){
  8514.                 strip = strip_directory_part(f->name);
  8515.                 if(*strip != '.'){
  8516.                     strcpy(fn, strip);
  8517.                     if(top == 0)
  8518.                         top = last = allocate_dir(
  8519.                             gg.current_directory);
  8520.                     else {
  8521.                         last->next = allocate_dir(
  8522.                             gg.current_directory);
  8523.                         last = last->next;
  8524.                     }
  8525.                 }
  8526.             }
  8527.         }
  8528.         if(top)
  8529.             link_dir_chain(top, last);
  8530.     }
  8531.     if(gg.l_opt)
  8532.         long_output();
  8533.     else
  8534.         short_output();
  8535.     gg.files = NULL;
  8536.     *gg.current_directory = 0;
  8537. }
  8538.  
  8539. void output_dirs(void)
  8540. {
  8541.     dirfile *p;
  8542.     char    buf[PATHNAMELENGTH], *cp;
  8543.     struct  _finddata_t  fb;
  8544.     long lfind;
  8545.  
  8546.     while((p = gg.dirs)){
  8547.         gg.dirs = p->next;
  8548.         if(gg.disp_dir){
  8549.             /* Nide,
  8550.                非ANSIコンパイラの便のために文字列連接をやめた */
  8551.             char buf[0x100];
  8552.             _snprintf(buf, sizeof(buf),
  8553.                       "\n%s:\n", s_conv_to_unix_format(p->fullname));
  8554.             cwFputs(buf, NULL);
  8555.         }
  8556.         cp = p->fullname + strlen(p->fullname) - 1;
  8557.         {
  8558.             char   *dl = "";
  8559.             if((cp > p->fullname && iskanjipos((cp - 1))) ||
  8560.                 (cp >= p->fullname && *cp != PD && *cp != ':'))
  8561.                 dl = "\\";
  8562.             sprintf(buf, "%s%s", p->fullname, dl);
  8563.         }
  8564.         cp = buf + strlen(buf);
  8565.  
  8566.         strcpy(cp, "*.*");
  8567.  
  8568.         memset(&fb, 0, sizeof(fb));
  8569.         fb.attrib = (gg.a_opt != 0) ? 0x3F : 0x30;
  8570.         lfind = _findfirst(buf, &fb);
  8571.         if (lfind == -1) {
  8572.             continue;
  8573.         } /* Changed Nide */
  8574.         do {
  8575.             if(!gg.a_opt && (fb.name[0] == '.' || fb.name[0] == '_'))
  8576.                 continue;
  8577.             strcpy(cp, fb.name);
  8578.             add_file_list(buf, false,
  8579.                       (fb.attrib & VOL_MASK) ? VOL_MASK :
  8580.                       gg.a_opt ? 0x37 : 0x30); /* Changed Nide */
  8581.         } while(_findnext(lfind, &fb) == 0);
  8582.         _findclose(lfind);
  8583.         output_files();
  8584.         free(p->fullname);
  8585.         free(p);
  8586.     }
  8587. }
  8588.  
  8589. bool process_options(int c)
  8590. {
  8591.     switch (c){
  8592.     case 'R':
  8593.         gg.R_opt = true;   /* list directory recursively */
  8594.         gg.disp_dir = true;
  8595.         gg.d_opt = 0;
  8596.         break;
  8597.     case 'a':
  8598.         gg.a_opt = true;
  8599.         break;  /* list all files */
  8600.     case 'd':
  8601.         gg.d_opt = true;   /* list directory itself */
  8602.         gg.R_opt = 0;
  8603.         gg.disp_dir = 0;
  8604.         break;
  8605.     case 'C':
  8606.         gg.C_opt = true;
  8607.         gg.x_opt = 0;  /* multicolumn output */
  8608.         break;
  8609.     case 'x':
  8610.         gg.x_opt = true;
  8611.         gg.C_opt = 0;  /* multicolumn across */
  8612.         break;
  8613.     case 'B':   /* sort by file size */
  8614.         gg.X_opt = true;
  8615.         gg.t_opt = gg.S_opt = false;
  8616.         break;
  8617.     case 'l':
  8618.         gg.l_opt = true;
  8619.         break;  /* long listing */
  8620.     case 'r':
  8621.         gg.r_opt = !gg.r_opt;
  8622.         break;  /* reverse sort */
  8623.     case 't':
  8624.         gg.t_opt = true;
  8625.         gg.X_opt = gg.S_opt = false;
  8626.         break;  /* use timestamp to sort */
  8627.     case 'F':
  8628.         gg.F_opt = true;
  8629.         break;  /* list with / and * */
  8630.     case 's':   /* append file size in KB. */
  8631.         gg.s_opt = true;
  8632.         break;  /* output block size */
  8633.     case '1':
  8634.         gg.C_opt = 0;  /* no multicolumn */
  8635.         gg.x_opt = 0;
  8636.         break;
  8637.     case 'U':   /* no sort */
  8638.         gg.S_opt = true;
  8639.         gg.t_opt = gg.X_opt = false;
  8640.         break;
  8641.     case 'X':   /* sort by extention */
  8642.         gg.Sort_by_ext_opt = true;
  8643.         break;
  8644.     case 'c':   /* Add Nide */
  8645.         if(gg.c_opt > 0){
  8646.             if(gg.c_opt < 3)
  8647.                 gg.c_opt++;
  8648.         } else {
  8649.             if(gg.c_opt-- > -3)
  8650.                 gg.c_opt--;
  8651.         }
  8652.         break;
  8653.     default:
  8654.         return false;
  8655.     }
  8656.     return true;
  8657. }
  8658.  
  8659. int ls_main(int argc, char **argv)
  8660. {
  8661. //  extern int  opterr;
  8662. //  extern char **expand_wildcards();
  8663. //  extern void discard_wildcard();
  8664.  
  8665.     int c /* , i */ ;   /* filenum is changed to be extern */
  8666.     char    *opt;
  8667.  
  8668.     gConsoleInfo.lMode = CW_MODE_GET;
  8669.     if (cwCallConsole(glpfnIO, "", (LPLONG)&gConsoleInfo) == TRUE) {
  8670.         gg.screenwidth=min(max(8,gConsoleInfo.lColumns),gConsoleInfo.lBufMax);
  8671.     }
  8672.  
  8673.     conv_char_args(argv, '/', '\\');
  8674.  
  8675.     gg.opterr = 0;
  8676.  
  8677.     gg.c_opt = -1;
  8678.     gg.C_opt = true;
  8679.     *gg.current_directory = 0;
  8680.  
  8681.     /*
  8682.      * Process option string from LSOPTIONS and from the command line.
  8683.      */
  8684.     if((opt = getenv("LSOPTIONS"))){
  8685.         while(*opt){
  8686.             process_options(*opt);
  8687.             opt++;
  8688.         }
  8689.     }
  8690.     while((c = getopt(argc, argv, "RadCxlrtBFs1UXc")) != EOF) {
  8691.         if(process_options(c) != true) {
  8692.             return ls_usage();
  8693.         }
  8694.     }
  8695.  
  8696.     gg.c_opt = (gg.c_opt < -1 || gg.c_opt > 2);
  8697.     gg.filenum = 0;
  8698.  
  8699.     if(gg.optind == argc) {
  8700.         add_file_list(".", true, gg.a_opt ? 0x37 : 0x30);
  8701.     /* Changed Nide. In this case we must ignore volume label */
  8702.     } else {
  8703.         argv += gg.optind;
  8704.  
  8705.         /* この後、オリジナルでは引数を後ろから処理してた。なぜだ? */
  8706.         while((*argv)[0] != '\0'){
  8707.             char    *onearg; /* int len; */
  8708.  
  8709.             onearg = *argv;
  8710.             if(isalpha(*onearg) && onearg[1] == ':' && onearg[2] == '\0'){
  8711.                 gg.s_tmparg[0] = *onearg;
  8712.                 onearg = gg.s_tmparg;
  8713.             }
  8714.             add_file_list(onearg, true, !gg.a_opt ? 0x30 :
  8715.                           (*onearg && '.' == onearg[strlen(onearg)-1]) ?
  8716.                           0x37 : 0x3F);
  8717.             /*
  8718.              * Changed Nide (so that 'ls -a /volname' works).
  8719.              * '.' is not SJIS 2nd byte.
  8720.              */
  8721.  
  8722.             gg.filenum++;
  8723.             argv++;
  8724.         }
  8725.     }
  8726.     if(gg.filenum > 1) {
  8727.         gg.disp_dir = true;
  8728.     }
  8729.     output_files();
  8730.     output_dirs();
  8731.     return 0;       /* return from main() */
  8732. }
  8733.  
  8734. /*-----------*/
  8735. /* sort_main */
  8736. /*-----------*/
  8737. int rmstmp_exit(int code)
  8738. {
  8739.     int i;
  8740.  
  8741.     for(i = 0; i < 2; i++){
  8742.         if(gg.sorttmpf[i].f != NULL){
  8743.             fclose(gg.sorttmpf[i].f);
  8744.             unlink(gg.sorttmpf[i].name);
  8745.         }
  8746.     }
  8747.     return code;
  8748. }
  8749.  
  8750. void userintr(int dummy)
  8751. {
  8752.     cwFputs("sort: User interrupt\n", (LPSTR)-1);
  8753.     rmstmp_exit(1);
  8754. }
  8755.  
  8756. int sort_usage(void)
  8757. {
  8758.     cwFputs("Usage: sort [-brnf] [-t c] [-o outfile]\n", (LPSTR)-1),
  8759.     cwFputs("\t    [+n1[.m1][brnf] [-n2[.m2][b]] ...] [files...]\n", (LPSTR)-1);
  8760.     return 1;
  8761. }
  8762.  
  8763. void sort_nomem(void)
  8764. {
  8765.     _putnomemmes(), rmstmp_exit(1);
  8766. }
  8767.  
  8768. void nodisk(void)
  8769. {
  8770.     cwFputs("output error (maybe disk full) while outputting or "
  8771.           "making temporal file\n", (LPSTR)-1), rmstmp_exit(1);
  8772. }
  8773.  
  8774. int addfieldparm(char *p)
  8775. {
  8776.     char    pm;
  8777.  
  8778.     if('+' == (pm = *p++)){
  8779.         if(NULL == (gg.sortparm = (parmstr *)(realloc((char *)gg.sortparm,
  8780.                      sizeof(parmstr) * (gg.parmcnt + 1))))){
  8781.             sort_nomem();
  8782.         }
  8783.         memcpy((char *)&(gg.sortparm[gg.parmcnt]),
  8784.                (char *)&(gg.sortparm[0]), sizeof(parmstr));
  8785.          /* global optionのbeginf・c, endf・cは0 0 -1 0のはず */
  8786.  
  8787.         if(!isdigit(*p)) return sort_usage();
  8788.         gg.sortparm[gg.parmcnt].beginf = atoi(p);
  8789.          /* should be a-to-uint? */
  8790.         while(isdigit(*p)) p++;
  8791.         if(*p == '.'){
  8792.             p++; if(!isdigit(*p)) return sort_usage();
  8793.             gg.sortparm[gg.parmcnt].beginc = atoi(p);
  8794.             while(isdigit(*p)) p++;
  8795.         } else gg.sortparm[gg.parmcnt].beginc = 0;
  8796.  
  8797.         if(*p && gg.sortparm[gg.parmcnt].opt.usegopt){
  8798.             memset((char *)&gg.sortparm[gg.parmcnt] . opt, 0,
  8799.                    sizeof(optstr));
  8800.         }
  8801.         for(; *p; p++){
  8802.             switch(*p){
  8803.             case 'b':
  8804.                 gg.sortparm[gg.parmcnt].opt.pblankign = 1; break;
  8805.             case 'f':
  8806.                 gg.sortparm[gg.parmcnt].opt.foldcase = 1; break;
  8807.             case 'n':
  8808.                 gg.sortparm[gg.parmcnt].opt.numsort = 1; break;
  8809.             case 'r':
  8810.                 gg.sortparm[gg.parmcnt].opt.reverse = 1; break;
  8811.             default:
  8812.                 return sort_usage();
  8813.             }
  8814.         }
  8815.     } else {
  8816.         gg.parmcnt--;
  8817.  
  8818.         if(!isdigit(*p)) return sort_usage();
  8819.         gg.sortparm[gg.parmcnt].endf = atoi(p);
  8820.         while(isdigit(*p)) p++;
  8821.         if(*p == '.'){
  8822.             p++; if(!isdigit(*p)) return sort_usage();
  8823.             gg.sortparm[gg.parmcnt].endc = atoi(p);
  8824.             while(isdigit(*p)) p++;
  8825.         } else gg.sortparm[gg.parmcnt].endc = 0;
  8826.  
  8827.         if(*p && gg.sortparm[gg.parmcnt].opt.usegopt){
  8828.             memset((char *)&gg.sortparm[gg.parmcnt].opt,0,
  8829.                    sizeof(optstr));
  8830.         }
  8831.         for(; *p; p++){
  8832.             switch(*p){
  8833.             case 'b':
  8834.                 gg.sortparm[gg.parmcnt].opt.mblankign = 1; break;
  8835.              /* あとは+の時と一緒 */
  8836.             case 'f':
  8837.                 gg.sortparm[gg.parmcnt].opt.foldcase = 1; break;
  8838.             case 'n':
  8839.                 gg.sortparm[gg.parmcnt].opt.numsort = 1; break;
  8840.             case 'r':
  8841.                 gg.sortparm[gg.parmcnt].opt.reverse = 1; break;
  8842.             default:
  8843.                 return sort_usage();
  8844.             }
  8845.         }
  8846.     }
  8847.  
  8848.     gg.parmcnt++;
  8849. }
  8850.  
  8851. void makestmpbase(void)
  8852.  /* メモリがなくなってから一時ファイルを作るのだから、そのための
  8853.     領域をあらかじめ取っておく */
  8854. {
  8855.     char    *tmpdir, *p, yobi[5]/* "a:\\." */;
  8856.     int i;
  8857.     FILE    *opntest;
  8858.  
  8859.     if(NULL == (tmpdir = getenv("TMP")) &&  
  8860.        NULL == (tmpdir = getenv("TEMP"))){
  8861.         tmpdir = ".";
  8862.     } else
  8863.     if(*tmpdir == '\\' && !tmpdir[1] ||
  8864.        is_alpha(*tmpdir) && tmpdir[1] == ':' &&
  8865.          (!tmpdir[2] || tmpdir[2] == '\\' && !tmpdir[3])){
  8866.      /* "\\" "a:\\" "a:" の場合 */
  8867.         strcpy(yobi, tmpdir);
  8868.         strcat(tmpdir = yobi, ".");
  8869.     } else {
  8870.         for(p = tmpdir; *p; ){
  8871.             if(*p == '\\' && !p[1]){
  8872.                 *p = '\0';
  8873.                 break;
  8874.             }
  8875.             if(iskanjipos(p)) p++;
  8876.             p++;
  8877.         }
  8878.     }
  8879.     p = malloc(strlen(tmpdir) + 5); /* "\\nul" */
  8880.     if(p == NULL) sort_nomem();
  8881.     strcpy(p, tmpdir), strcat(p, "\\nul"), opntest = fopen(p, "r");
  8882.     if(opntest == NULL) tmpdir = "."; else fclose(opntest);
  8883.     free(p);
  8884.  
  8885.     for(i = 0; i < 2; i++){
  8886.         gg.sorttmpf[i].dirlen = strlen(tmpdir);
  8887.         gg.sorttmpf[i].name = malloc(gg.sorttmpf[i] . dirlen + 14);
  8888.          /* 14 for "\\xxxxxxxx.xxx\0" */
  8889.         if(NULL == gg.sorttmpf[i].name) sort_nomem();
  8890.         strcpy(gg.sorttmpf[i].name, tmpdir);
  8891.         gg.sorttmpf[i].f = NULL;
  8892.     }
  8893. }
  8894.  
  8895. #include <signal.h>
  8896.  
  8897. int sort_main(int ac, char **av)
  8898. {
  8899.     int nret = 0;
  8900.     FILE    *otf = NULL;
  8901.     char    *p;
  8902.     char    optend = 0; /* bool */
  8903.  
  8904.     makestmpbase(); /* signal設定や全rmstmp_exitより前にやること */
  8905.     signal(SIGINT, userintr);
  8906.  
  8907.     if(NULL == (gg.sortparm=(parmstr *)malloc(sizeof(parmstr)))) sort_nomem();
  8908.     memset(gg.sortparm, 0, sizeof(parmstr));
  8909.     gg.sortparm->beginf = gg.sortparm->beginc = gg.sortparm->endc = 0;
  8910.     gg.sortparm -> endf = (unsigned int)-1;
  8911.     gg.sortparm->opt.usegopt = 1;
  8912.  
  8913.     while(++av, --ac){
  8914.         p = *av;
  8915.         switch(*p){
  8916.         case '+':
  8917.             if (addfieldparm(p) != 0) {
  8918.                 nret = 1; goto EXIT;
  8919.             }
  8920.             if(ac == 1 || av[1][0] != '-' || !isdigit(av[1][1]))
  8921.                 break;
  8922.             ++av, --ac;
  8923.             if (addfieldparm(*av) != 0) {
  8924.                 nret = 1; goto EXIT;
  8925.             }
  8926.             break;
  8927.         case '-':
  8928.             if(!p[1]){optend++; break;}
  8929.             while(*++p){
  8930.                 switch(*p){
  8931.                 case 't':
  8932.                     if(!*++p){
  8933.                         if(av++, !--ac) {
  8934.                             nret = sort_usage(); goto EXIT;
  8935.                         }
  8936.                         p = *av;
  8937.                         if(!*p) {
  8938.                             nret = sort_usage(); goto EXIT;
  8939.                         }
  8940.                     }
  8941.                     gg.global_sep[0] = *p;
  8942.                     if(iskanji(*p))
  8943.                         gg.global_sep[1] = *++p;
  8944.                      else
  8945.                         gg.global_sep[1] = '\0';
  8946.                     if(p[1]) {
  8947.                         nret = sort_usage(); goto EXIT;
  8948.                     }
  8949.                     break;
  8950.                 case 'o':
  8951.                     if(!*++p){
  8952.                         if(av++, !--ac) {
  8953.                             nret = sort_usage(); goto EXIT;
  8954.                         }
  8955.                         p = *av;
  8956.                     }
  8957.                     gg.otfnm = p;
  8958.                     p = "?";
  8959.                     break;
  8960.                 case 'f':
  8961.                     gg.sortparm->opt.donormcmp = 
  8962.                     gg.sortparm->opt.foldcase = 1; break;
  8963.                 case 'n':
  8964.                     gg.sortparm->opt.donormcmp = 
  8965.                     gg.sortparm->opt.numsort = 1; break;
  8966.                 case 'b':
  8967.                     gg.sortparm->opt.donormcmp = 
  8968.                     gg.sortparm->opt.pblankign =
  8969.                     gg.sortparm->opt.mblankign = 1; break;
  8970.                 case 'r':
  8971.                     gg.sortparm->opt.reverse = 1; break;
  8972.                 default:
  8973.                     nret = sort_usage(); goto EXIT;
  8974.                 }
  8975.             }
  8976.             break;
  8977.         default:
  8978.             optend++; break;
  8979.         }
  8980.         if(optend) break;
  8981.     }
  8982.     if(gg.parmcnt > 1) gg.sortparm->opt.donormcmp = 1;
  8983.      /* field optionが1つでもあれば後で行全体の通常比較
  8984.         (その場合global optionを適用しての行全体の比較はしない)
  8985.         field optionなくても-bや-nの場合は行全体の通常比較がいる
  8986.         -rだけの場合などは改めて行全体の通常比較をする必要なし */
  8987.  
  8988.     if(NULL == (gg.lines = (char **)malloc(
  8989.         (gg.linealloc = L_1ST) * sizeof(char *)))) sort_nomem();
  8990.  
  8991.     if(!ac){
  8992.         readfile(NULL);
  8993.     } else for(; ac; ac--, av++){
  8994.         if(**av == '-' && !av[0][1]){
  8995.             readfile(NULL);
  8996.         } else {
  8997.             readfile(*av);
  8998.         }
  8999.     }
  9000.  
  9001.     do_sort();
  9002.  
  9003.     if(NULL != gg.otfnm){
  9004.         name_unixnize(gg.otfnm);
  9005.         if(NULL == (otf = fopen(gg.otfnm, "w"))){
  9006.             cwFputs(gg.otfnm, (LPSTR)-1);
  9007.             cwFputs(": Can't open\n", (LPSTR)-1);
  9008.             rmstmp_exit(1);
  9009.         }
  9010.     } else {
  9011.         otf = NULL;
  9012.     }
  9013.     join_output(otf, gg.sorttmpf[!gg.tmpfsw] . f);
  9014. EXIT:
  9015.     if (otf != NULL) fclose(otf);
  9016.     if (gg.lines != NULL) free(gg.lines);
  9017.     gg.lines = NULL;
  9018.     rmstmp_exit(0);
  9019.     return 0;
  9020. }
  9021.  
  9022. void readfile(char *fnm)
  9023. {
  9024.     int len;
  9025.     FILE    *inf;
  9026.     char    linbuf[LINMAX];
  9027.  
  9028.     if(fnm == NULL){
  9029.         inf = NULL, fnm = "(stdin)";
  9030.     } else {
  9031.         name_unixnize(fnm);
  9032.         if(NULL == (inf = fopen(fnm, "r"))){
  9033.             cwFputs(fnm, (LPSTR)-1), cwFputs(": Can't open\n", (LPSTR)-1);
  9034.         }
  9035.     }
  9036.  
  9037.     while(((inf == NULL) ? cwFgets(linbuf, LINMAX, NULL) :
  9038.                            fgets(linbuf, LINMAX, inf)) != NULL){
  9039.         if(!*linbuf){ /* nothing */
  9040.             ;
  9041.         } else if(linbuf[(len = strlen(linbuf)) - 1] != '\n'){
  9042.             cwFputs(fnm, (LPSTR)-1);
  9043.             if(len == LINMAX - 1){
  9044.                 cwFputs(": line too long\n", (LPSTR)-1);
  9045.                 rmstmp_exit(1);
  9046.             } else {
  9047.                 cwFputs(": missing line-feed character "
  9048.                       "added at the end of file\n", (LPSTR)-1);
  9049.             }
  9050.         } else {
  9051.             linbuf[len - 1] = '\0';
  9052.         }
  9053.         linereg(linbuf);
  9054.     }
  9055.     if(inf != NULL) fclose(inf);
  9056. }
  9057.  
  9058.  /* 1行の内容を保存。将来的にはフィールドの位置情報もあわせて保存 */
  9059. void linereg(char *s)
  9060. {
  9061.     char    **tmplines;
  9062.  
  9063.     if(gg.linecnt >= gg.linealloc){
  9064.         gg.linealloc += L_INC;
  9065.         if(gg.linealloc * sizeof(char *) / sizeof(char *) != gg.linealloc ||
  9066.             /* reallocだと失敗時に元の内容が保証されない */
  9067.            NULL == (tmplines = (char **)malloc(
  9068.                         gg.linealloc * sizeof(char *)))){
  9069.             midproc();
  9070.         } else {
  9071.             memcpy((char *)tmplines, (char *)gg.lines,
  9072.                    gg.linecnt * sizeof(char *));
  9073.             free((char *)gg.lines);
  9074.             gg.lines = tmplines;
  9075.         }
  9076.     }
  9077.  
  9078.     if(NULL == (gg.lines[gg.linecnt] = strsave(s))){
  9079.         midproc(); /* linecntは0になる */
  9080.         if(NULL == (gg.lines[0] = strsave(s))) sort_nomem();
  9081.     }
  9082.     gg.linecnt++;
  9083. }
  9084.  
  9085.  /* macros to move pointer */
  9086.  
  9087. void fieldcharpass(char **pp)
  9088. {
  9089.     char    *p;
  9090.  
  9091.     p = *pp;    
  9092.     if(*gg.global_sep){
  9093.         for(;; iskanjipos(p) ? (p += 2) : p++){
  9094.             if(!*p){
  9095.                 *pp = p; return;
  9096.             }
  9097.             if(*p != *gg.global_sep) continue;
  9098.             if(!gg.global_sep[1]){
  9099.                 *pp = ++p; return;
  9100.             } else {
  9101.                 if(p[1] != gg.global_sep[1]) continue;
  9102.                 *pp = p + 2; return;
  9103.             }
  9104.         }
  9105.     } else {
  9106.         spcpass(p); nonspcpass(p);
  9107.     }
  9108.     *pp = p;
  9109. }
  9110.  
  9111. int compare(const char **pp, const char **qp)
  9112. {
  9113.     char    *p, *pe, *q, *qe;
  9114.     int i;
  9115.     unsigned int    minf, u;
  9116.     int rsl = 0;
  9117.     int strnicmp(), strncmp(), stricmp(), strcmp();
  9118.  
  9119.      /* parmcntが1なら0だけ、1より大なら1~parmcnt-1を見る */
  9120.     for(i = (gg.parmcnt > 1); i < gg.parmcnt; i++){
  9121.         p = *pp, q = *qp;
  9122.  
  9123.         minf = umin(gg.sortparm[i].beginf, gg.sortparm[i].endf);
  9124.         for(u = minf; u; u--){
  9125.             fieldpass(p); fieldpass(q);
  9126.         }
  9127.         pe = p, qe = q;
  9128.          /* if endf is -1, pe and qe are not used */
  9129.  
  9130.         for(u = gg.sortparm[i].beginf-minf; u; u--){
  9131.             fieldpass(p); fieldpass(q);
  9132.         }
  9133.         if(gg.sortparm[i].opt.pblankign){
  9134.             spcpass(p); spcpass(q);
  9135.         }
  9136.         ncharpass(p, gg.sortparm[i].beginc);
  9137.         ncharpass(q, gg.sortparm[i].beginc);
  9138.  
  9139.         if(gg.sortparm[i].opt.numsort){ /* endf, endc are not used */
  9140.             gg.s_a = atof(p); gg.s_b = atof(q);
  9141.              /* atofは常に空白を飛ばす */
  9142.             rsl = (gg.s_a < gg.s_b ? -1 : gg.s_a > gg.s_b ? 1 : 0);
  9143.         } else if((unsigned int)-1 != (u = gg.sortparm[i].endf)){
  9144.             unsigned int    plen, qlen;
  9145.  
  9146.             for(u -= minf; u; u--){
  9147.                 fieldpass(pe); fieldpass(qe);
  9148.             }
  9149.             if(gg.sortparm[i].opt.mblankign){
  9150.                 spcpass(pe); spcpass(qe);
  9151.             }
  9152.             ncharpass(pe, gg.sortparm[i].endc);
  9153.             ncharpass(qe, gg.sortparm[i].endc);
  9154.  
  9155.             plen = pe - p; if(plen < 0) plen = 0;
  9156.             qlen = qe - q; if(qlen < 0) qlen = 0;
  9157.             rsl = (gg.sortparm[i].opt.foldcase ?
  9158.                     strnicmp : strncmp)(p, q, umin(plen, qlen));
  9159.             if(rsl == 0) rsl = plen - qlen;
  9160.         } else {
  9161.             rsl = (gg.sortparm[i].opt.foldcase ? stricmp : strcmp)
  9162.                                     (p, q);
  9163.         }
  9164.  
  9165.         if(rsl){
  9166.             return gg.sortparm[i].opt.reverse ? -rsl : rsl;
  9167.         }
  9168.     }
  9169.  
  9170.      /* 勝負が付かなければ行全体を普通に比較 */
  9171.     if(gg.sortparm->opt.donormcmp){
  9172.         rsl = strcmp(*pp, *qp);
  9173.         return gg.sortparm->opt.reverse ? -rsl : rsl;
  9174.     }
  9175.     return 0;
  9176. }
  9177.  
  9178. void do_sort(void)
  9179. {
  9180.     qsort((char *)gg.lines, gg.linecnt, sizeof(char *), compare);
  9181. }
  9182.  
  9183. FILE *dtmpfile(char *dir) /* dirも書き換わる */
  9184. {
  9185.     char *s;
  9186.  
  9187.     s = _mktemp(dir);
  9188.     return (s == NULL) ? NULL : fopen(dir, "w+b");
  9189. }
  9190.  
  9191. void midproc(void) /* メモリが足りなくなったので中間処理 */
  9192. {
  9193.     unsigned int    i;
  9194.     int (*thndl)(int);
  9195.  
  9196.     do_sort();
  9197.  
  9198.     thndl = (int (*)(int))signal(SIGINT, SIG_IGN);
  9199.     if(NULL ==
  9200.          (gg.sorttmpf[gg.tmpfsw].f = dtmpfile(gg.sorttmpf[gg.tmpfsw].name))){
  9201.         cwFputs("Can't open tmpfile\n", (LPSTR)-1), rmstmp_exit(1);
  9202.     }
  9203.     signal(SIGINT, (void (*)(int))thndl);
  9204.  
  9205.     join_output(gg.sorttmpf[gg.tmpfsw].f, gg.sorttmpf[!gg.tmpfsw].f);
  9206.  
  9207.     thndl = (int (*)(int))signal(SIGINT, SIG_IGN);
  9208.     rewind(gg.sorttmpf[gg.tmpfsw].f);
  9209.     gg.tmpfsw ^= 1;
  9210.     if(gg.sorttmpf[gg.tmpfsw].f != NULL){
  9211.         fclose(gg.sorttmpf[gg.tmpfsw].f);
  9212.         gg.sorttmpf[gg.tmpfsw].f = NULL;
  9213.         unlink(gg.sorttmpf[gg.tmpfsw].name);
  9214.         gg.sorttmpf[gg.tmpfsw].name[gg.sorttmpf[gg.tmpfsw].dirlen] = '\0';
  9215.     }
  9216.     signal(SIGINT, (void (*)(int))thndl);
  9217.  
  9218.     for(i = 0; i < gg.linecnt; i++) free(gg.lines[i]);
  9219.     free(gg.lines);
  9220.     if(NULL == (gg.lines = (char **)malloc(
  9221.         (gg.linealloc = L_1ST) * sizeof(char *)))) sort_nomem();
  9222.     gg.linecnt = 0;
  9223. }
  9224.  
  9225. void join_output(FILE *f, FILE *midf)
  9226. {
  9227.     unsigned int    i = 0;
  9228.     char    lbuf[LINMAX], *linbuf;
  9229.  
  9230.     linbuf = lbuf;
  9231.     if (midf != NULL) {
  9232.         while(fgets(linbuf, LINMAX, midf) != NULL) {
  9233.             linbuf[strlen(linbuf) - 1] = '\0';
  9234.             for(; i < gg.linecnt && compare(&gg.lines[i], &linbuf) < 0; i++){
  9235.                 (f == NULL) ? cwFputs(gg.lines[i], NULL) : fputs(gg.lines[i], f);
  9236.                 if (((f == NULL) ? cwFputs("\n",NULL):fputs("\n",f)) < 0) {
  9237.                     nodisk();
  9238.                 }
  9239.             }
  9240.             (f == NULL) ? cwFputs(gg.lines[i], NULL) : fputs(gg.lines[i], f);
  9241.             if (((f == NULL) ? cwFputs("\n",NULL):fputs("\n",f)) < 0) {
  9242.                 nodisk();
  9243.             }
  9244.         }
  9245.     }
  9246.     for(; i < gg.linecnt; i++){
  9247.         (f == NULL) ? cwFputs(gg.lines[i], NULL) : fputs(gg.lines[i], f);
  9248.         if (((f == NULL) ? cwFputs("\n",NULL):fputs("\n",f)) < 0) {
  9249.             nodisk();
  9250.         }
  9251.     }
  9252.     if (f != NULL) {
  9253.         if(fflush(f) == EOF || ferror(f)) nodisk();
  9254.     }
  9255. }
  9256.  
  9257. /*  future plan:
  9258.   フィールドをいちいち探さぬよう比較まわりを作り替え
  9259.   tmpfile()関係を後で作り替える(その場合intrまわりの世話も)
  9260.   文字列save関係も作り替えるか
  9261. */
  9262.  
  9263. /*---------*/
  9264. /* od_main */
  9265. /*---------*/
  9266.  
  9267. int od_usage(void)
  9268. {
  9269.     cwFputs("Usage: od [-bcdosxvCSmrnXp] [-wn] [-Wn] [-tn[CS]] [file] ",
  9270.           (LPSTR)-1);
  9271.     cwFputs("[[+][0x]offset[.][b]]\n", (LPSTR)-1);
  9272.     return 1;
  9273. }
  9274.  
  9275. void equivocal(char *s)
  9276. {
  9277.     cwFputs("Equivocal operand: ", (LPSTR)-1);
  9278.     cwFputs(s, (LPSTR)-1);
  9279. }
  9280.  
  9281. void nobuf(void)
  9282. {
  9283.     cwFputs("Can't set I/O buffer\n", (LPSTR)-1);
  9284.     MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
  9285.     exit(2);
  9286. }
  9287.  
  9288. FILE *fopen_chk(char *n, char *m)
  9289.  /* nが"-"ならmを見ずにstdinを返す。fcloseの扱いなどに注意のこと */
  9290. {
  9291.     FILE    *f;
  9292.  
  9293.     if(*n == '-' && !n[1]) return NULL;
  9294.     if(NULL == (f = fopen(n, m))){
  9295.         cwFputs(s_conv_to_unix_format(n), (LPSTR)-1);
  9296.         cwFputs(": Can't open\n", (LPSTR)-1);
  9297.         return NULL;
  9298.     }
  9299.     return f;
  9300. }
  9301.  
  9302. //#define LBUFSIZ 1024
  9303. long    setoffset(FILE *f, char *offset)
  9304.  /* offset指定の文字列を読んで、fの内容を指定された分だけ読み捨て、
  9305.     大域変数addrmodeを設定してから戻る */
  9306. {
  9307.     us_int  offsetmode = OCTADDR;
  9308.     int in_blks_shft = 0;
  9309.     us_long pass = 0, passrest;
  9310.     us_int  rsize;
  9311.     char    *strpbrk(), *p;
  9312.  
  9313.     if(gg.s_passbuf == NULL && NULL == (gg.s_passbuf = malloc(LBUFSIZ))) {
  9314.         _putnomemmes();
  9315.         MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
  9316.         exit(2);
  9317.     }
  9318.  
  9319.     offset++; /* when called, *offset is always '+' */
  9320.     if(!strncmp(offset, "0x", 2) || *offset == 'x'){
  9321.         offsetmode = HEXADDR;
  9322.         *offset++ == '0' && offset++;
  9323.     }
  9324.     if(NULL != strchr(offset, '.')){ /* 10進指定の方が優先 */
  9325.         offsetmode = DECADDR;
  9326.     }
  9327.      /* ここまででoffsetmodeの設定は終わり。
  9328.         グローバル変数addrmodeを変更しておく */
  9329.     if(gg.addrmode != NOADDR) gg.addrmode = offsetmode;
  9330.  
  9331.     if(offsetmode != HEXADDR && NULL != (p = strpbrk(offset, "bB"))){
  9332.         in_blks_shft = (*p == 'b' ? 9 : 10);
  9333.     }
  9334.  
  9335.     sscanf(offset,
  9336.         offsetmode == DECADDR ? "%lu" :
  9337.         offsetmode == HEXADDR ? "%lx" : "%lo", &pass);
  9338.     pass <<= in_blks_shft;
  9339.     if(gg.undump){
  9340.         if(pass){
  9341.             cwFputs("Warning: non-0 offset with -u option\n", (LPSTR)-1);
  9342.         }
  9343.         return 0L;
  9344.     }
  9345.     passrest = pass;
  9346.     if (f != NULL) {
  9347.         while(passrest > 0){
  9348.             rsize = (passrest > (us_long)LBUFSIZ) ?
  9349.                         LBUFSIZ : (us_int)passrest;
  9350.             if(rsize > fread(gg.s_passbuf, 1, rsize, f)){
  9351.                 cwFputs("EOF\n", (LPSTR)-1);
  9352.             }
  9353.             passrest -= (us_long)rsize;
  9354.         }
  9355.     } else {
  9356.         while (passrest > 0) {
  9357.             char *p;
  9358.             p = cwFgets(gg.s_passbuf, LBUFSIZ, NULL);
  9359.             rsize = (p != NULL) ? lstrlen(p) : 0;
  9360.             passrest -= rsize;
  9361.         }
  9362.     }
  9363.     return pass;
  9364. }
  9365.  
  9366. char    *malloc_chk_z(us_int i)
  9367. {
  9368.     char    *s;
  9369.  
  9370.     if(NULL == (s = malloc(i))){
  9371.         _putnomemmes(); 
  9372.         MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
  9373.         exit(2);
  9374.          /* od exits with code 2 when error... */
  9375.     }
  9376.     memset(s, 0, i);
  9377.     return s;
  9378. }
  9379.  
  9380. void    addpos(us_long *l, us_int d)
  9381. {
  9382.     *l += d;
  9383.     switch(gg.addrmode){
  9384.     case HEXADDR:
  9385.         *l &= 0xfffffffL; break;
  9386.     case DECADDR:
  9387.         *l %= 10000000L; break;
  9388.     case OCTADDR:
  9389.         *l &= 07777777L; break;
  9390.     }
  9391. }
  9392.  
  9393. void    putspcs(int i)
  9394. {
  9395.     char *buf;
  9396.  
  9397.     buf = malloc(i + 1); if (buf == NULL) return;
  9398.     memset(buf, ' ', i);
  9399.     buf[i] = '\0';
  9400.     cwFputs(buf, NULL);
  9401.     free(buf);
  9402. }
  9403.  
  9404. us_char special_char_disp(us_char c)
  9405. { /* ctrl chrのみ。SJISの2バイト目と重複したりはしない */
  9406.     switch(c){
  9407.     case '\n':
  9408.         return 'n';
  9409.     case '\t':
  9410.         return 't';
  9411.     case '\b':
  9412.         return 'b';
  9413.     case '\r':
  9414.         return 'r';
  9415.     case '\f':
  9416.         return 'f';
  9417.     case 0xb:
  9418.         return 'v';
  9419.     case 0x7:
  9420.         return 'a';
  9421.     case '\033':
  9422.         return 'e';
  9423.     }
  9424.     return 0;
  9425. }
  9426.  
  9427. #define is_print(c) (isascii(c) && isprint(c))
  9428.  
  9429. void byteout(us_char c) /* uses fieldb */
  9430. {
  9431.     char buf[0x100];
  9432.  
  9433.     if(is_print(c)){
  9434.         _snprintf(buf, sizeof(buf), "%*s%c", gg.fieldb-1, STRNULL, c);
  9435.         cwFputs(buf, NULL);
  9436.     } else {
  9437.         us_char d;
  9438.  
  9439.         d = (c ? special_char_disp(c) : '0');
  9440.         if(d){
  9441.             _snprintf(buf, sizeof(buf), "%*s\\%c", gg.fieldb-2, STRNULL, d);
  9442.             cwFputs(buf, NULL);
  9443.         } else {
  9444.             if (gg.hexcode) {
  9445.                 _snprintf(buf,sizeof(buf), "%*s%02x", gg.fieldb-2, STRNULL, c);
  9446.                 cwFputs(buf, NULL);
  9447.             } else {
  9448.                 _snprintf(buf,sizeof(buf), "%*s%03o", gg.fieldb-3, STRNULL, c);
  9449.                 cwFputs(buf, NULL);
  9450.             }
  9451.         }
  9452.     }
  9453. }
  9454.  
  9455. #define ADDRNGOT    0
  9456. #define ADDRGOT     1
  9457. #define ADDRSTAR    2
  9458. #define ADDREOF     3
  9459.  
  9460. void    odaddr(us_long curpos, int *flgp, int crmode)
  9461. {
  9462.     char buf[0x100];
  9463.  
  9464.     if(gg.addrmode == NOADDR) return;
  9465.      /* NOADDRの時は何も出力しない */
  9466.  
  9467.     if(*flgp){
  9468.         cwFputs("\t", NULL); putspcs(gg.hsepwidth - 1);
  9469.     } else {
  9470.         char    *p;
  9471.  
  9472.         (*flgp)++;
  9473.         switch(gg.addrmode){
  9474.         case OCTADDR:
  9475.             p = "%07lo"; break;
  9476.         case HEXADDR:
  9477.             p = "%07lx"; break;
  9478.         default: /* case DECADDR: */
  9479.             p = "%07lu"; break;
  9480.         }
  9481.         _snprintf(buf, sizeof(buf), p, curpos);
  9482.         cwFputs(buf, NULL);
  9483.         if(crmode) {
  9484.             cwFputs("\n", NULL);
  9485.         } else {
  9486.             putspcs(gg.hsepwidth);
  9487.         }
  9488.     }
  9489. }
  9490.  
  9491. void putnl(void);
  9492.  
  9493. void    od_oct(struct infile *inf, int *addrout,
  9494.                us_char *begin, us_char *end)
  9495. {
  9496.     us_char *ptr;
  9497.     us_short outs;
  9498.     char buf[0x100];
  9499.  
  9500.     odaddr(inf -> curpos, addrout, 0);
  9501.     for(ptr = begin; ;){
  9502.         outs = *(us_short *)ptr;
  9503.         if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
  9504.         _snprintf(buf, sizeof(buf), "%*s%06o", gg.fieldw - 6, STRNULL, outs);
  9505.         cwFputs(buf, NULL);
  9506.         if((ptr += sizeof(short)) < end){
  9507.             putspcs(gg.sepwidth);
  9508.         } else {
  9509.             putnl(); break;
  9510.         }
  9511.     }
  9512. }
  9513.  
  9514. void    od_dec(struct infile *inf, int *addrout,
  9515.                us_char *begin, us_char *end)
  9516. {
  9517.     us_char *ptr;
  9518.     us_short outs;
  9519.     char buf[0x100];
  9520.  
  9521.     odaddr(inf -> curpos, addrout, 0);
  9522.     for(ptr = begin; ;){
  9523.         outs = *(us_short *)ptr;
  9524.         if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
  9525.         _snprintf(buf, sizeof(buf), "%*s%05u", gg.fieldw - 5, STRNULL, outs);
  9526.         cwFputs(buf, NULL);
  9527.         if((ptr += sizeof(short)) < end){
  9528.             putspcs(gg.sepwidth);
  9529.         } else {
  9530.             putnl(); break;
  9531.         }
  9532.     }
  9533. }
  9534.  
  9535. void od_sgndec(struct infile *inf, int *addrout,
  9536.                us_char *begin, us_char *end)
  9537. {
  9538.     us_char *ptr;
  9539.     us_short outs;
  9540.     char buf[0x100];
  9541.  
  9542.      /* -32768とかに対処するのが面倒なので完全にはSysV odをまねない */
  9543.     odaddr(inf -> curpos, addrout, 0);
  9544.     for(ptr = begin; ;){
  9545.         outs = *(us_short *)ptr;
  9546.         if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
  9547.         _snprintf(buf,sizeof(buf),"%*s%6d", gg.fieldw-6, STRNULL, (short)outs);
  9548.         cwFputs(buf, NULL);
  9549.         if((ptr += sizeof(short)) < end){
  9550.             putspcs(gg.sepwidth);
  9551.         } else {
  9552.             putnl(); break;
  9553.         }
  9554.     }
  9555. }
  9556.  
  9557. void    od_hex(struct infile *inf, int *addrout,
  9558.                us_char *begin, us_char *end)
  9559. {
  9560.     us_char *ptr;
  9561.     us_short outs;
  9562.     char buf[0x100];
  9563.  
  9564.     odaddr(inf -> curpos, addrout, 0);
  9565.     for(ptr = begin; ;){
  9566.         outs = *(us_short *)ptr;
  9567.         if(gg.endianrev) outs = (outs << 8) | (outs >> 8);
  9568.         _snprintf(buf, sizeof(buf), "%*s%04x", gg.fieldw-4, STRNULL, outs);
  9569.         cwFputs(buf, NULL);
  9570.         if((ptr += sizeof(short)) < end){
  9571.             putspcs(gg.sepwidth);
  9572.         } else {
  9573.             putnl(); break;
  9574.         }
  9575.     }
  9576. }
  9577.  
  9578. void    od_char(struct infile *inf, int *addrout,
  9579.                 us_char *begin, us_char *end)
  9580. {
  9581.     us_char *ptr;
  9582.  
  9583.     odaddr(inf -> curpos, addrout, 0);
  9584.     for(ptr = begin; ;){
  9585.         byteout(*ptr);
  9586.         if(++ptr < end){
  9587.             putspcs(gg.sepwidth);
  9588.         } else {
  9589.             putnl(); break;
  9590.         }
  9591.     }
  9592. }
  9593.  
  9594. void    od_euc(struct infile *inf, int *addrout,
  9595.                us_char *begin, us_char *end, int sw)
  9596. {
  9597.     us_char *ptr;
  9598.     int cont = gg.usebuf[sw].contmode & EUCCONT;
  9599.     char buf[0x100];
  9600.  
  9601.     odaddr(inf -> curpos, addrout, 0);
  9602.     for(ptr = begin; ;){
  9603.         if(cont){
  9604.             _snprintf(buf, sizeof(buf), "%*s", gg.fieldb, "**");
  9605.             cwFputs(buf, NULL);
  9606.             cont = 0;
  9607.         } else if(!iseuc(*ptr) && !isSS2(*ptr)){
  9608.             byteout(*ptr);
  9609.         } else {
  9610.             int next;
  9611.  
  9612.             if(ptr + 1 < end){
  9613.                 next = ptr[1]; /* ptr: us_char* */
  9614.             } else {
  9615.                 next = getc(inf -> f);
  9616.                 if(next != EOF) ungetc(next, inf -> f);
  9617.                  /* EOFならungetcはしない。システムに
  9618.                     よっては入力ファイルが端末の場合、
  9619.                     EOFの後さらに読もうとすると次の
  9620.                     入力待ちで止まってしまうものも… */
  9621.             }
  9622.             if(!iseuc(next)){
  9623.                 byteout(*ptr);
  9624.             } else {
  9625.                 _snprintf(buf, sizeof(buf), "%*s%c%c",
  9626.                         gg.fieldb - (isSS2(*ptr) ? 1 : 2),
  9627.                         STRNULL, *ptr, next);
  9628.                 cwFputs(buf, NULL);
  9629.                 cont = EUCCONT;
  9630.             }
  9631.         }
  9632.         if(++ptr < end){
  9633.             putspcs(gg.sepwidth);
  9634.         } else {
  9635.             putnl(); break;
  9636.         }
  9637.     }
  9638.     sw ^= 1;
  9639.     gg.usebuf[sw].contmode &= ~EUCCONT, gg.usebuf[sw].contmode |= cont;
  9640. }
  9641.  
  9642. void    od_sjis(struct infile *inf, int *addrout,
  9643.                 us_char *begin, us_char *end, int sw)
  9644. {
  9645.     us_char *ptr;
  9646.     int cont = gg.usebuf[sw].contmode & SJISCONT;
  9647.     char buf[0x100];
  9648.  
  9649.     odaddr(inf -> curpos, addrout, 0);
  9650.     for(ptr = begin; ;){
  9651.         if(cont){
  9652.             _snprintf(buf, sizeof(buf), "%*s", gg.fieldb, "**");
  9653.             cwFputs(buf, NULL);
  9654.             cont = 0;
  9655.         } else
  9656.         if(!issjis1(*ptr)){
  9657.             if(issjiskana(*ptr)){
  9658.                 _snprintf(buf,sizeof(buf),"%*s%c", gg.fieldb-1, STRNULL, *ptr);
  9659.                 cwFputs(buf, NULL);
  9660.             } else {
  9661.                 byteout(*ptr);
  9662.             }
  9663.         } else {
  9664.             int next;
  9665.             us_short dmy;
  9666.  
  9667.             if(ptr + 1 < end){
  9668.                 next = ptr[1]; /* ptr: us_char* */
  9669.             } else {
  9670.                 next = getc(inf -> f);
  9671.                 if(next != EOF) ungetc(next, inf -> f);
  9672.                  /* od_eucの場合と同様の事項に注意 */
  9673.             }
  9674.             if(!issjis2(next) ||
  9675.                (dmy = next | (*ptr << 8),
  9676.                 0x8540 <= dmy && dmy <= 0x869e)){
  9677.              /* NECの2バイト半角文字は排除 */
  9678.                 byteout(*ptr);
  9679.             } else {
  9680.                 _snprintf(buf, sizeof(buf), "%*s%c%c", gg.fieldb-2, STRNULL,
  9681.                                 *ptr, next);
  9682.                 cwFputs(buf, NULL);
  9683.                 cont = SJISCONT;
  9684.             }
  9685.         }
  9686.         if(++ptr < end){
  9687.             putspcs(gg.sepwidth);
  9688.         } else {
  9689.             putnl(); break;
  9690.         }
  9691.     }
  9692.     sw ^= 1;
  9693.     gg.usebuf[sw].contmode &= ~SJISCONT, gg.usebuf[sw].contmode |= cont;
  9694. }
  9695.  
  9696. void    od_byte(struct infile *inf, int *addrout,
  9697.                 us_char *begin, us_char *end)
  9698. {
  9699.     us_char *ptr;
  9700.     char buf[0x100];
  9701.  
  9702.     odaddr(inf -> curpos, addrout, 0);
  9703.     for(ptr = begin; ;){
  9704.         if (gg.hexcode) {
  9705.             _snprintf(buf, sizeof(buf), "%*s%02x", gg.fieldb-2, STRNULL, *ptr);
  9706.             cwFputs(buf, NULL);
  9707.         } else {
  9708.             _snprintf(buf, sizeof(buf), "%*s%03o", gg.fieldb-3, STRNULL, *ptr);
  9709.             cwFputs(buf, NULL);
  9710.         }
  9711.         if(++ptr < end){
  9712.             putspcs(gg.sepwidth);
  9713.         } else {
  9714.             putnl(); break;
  9715.         }
  9716.     }
  9717. }
  9718.  
  9719. void    od_bm(struct infile *inf, int *addrout,
  9720.               us_char *begin, us_char *end)
  9721. {
  9722.     us_char *ptr;
  9723.  
  9724.     odaddr(inf -> curpos, addrout, 0);
  9725.     for(ptr = begin; ;){
  9726.         int i;
  9727.         char    b = *ptr;
  9728.  
  9729.         putspcs(gg.fieldb - 8);
  9730.         for(i = 0; i < 8; i++, b <<= 1){
  9731.             putchar(b & 0x80 ? '#' : '-');
  9732.         }
  9733.         if(++ptr < end){
  9734.             putspcs(gg.sepwidth);
  9735.         } else {
  9736.             putnl(); break;
  9737.         }
  9738.     }
  9739. }
  9740.  
  9741. void    od_str(struct infile *inf, us_char *begin, us_char *end)
  9742. {
  9743.     us_char *ptr, c;
  9744.     us_int  txtlen;
  9745.     void    odstrout();
  9746.     int txtchrwidth, next;
  9747.  
  9748.     txtlen = gg.txtbuf.pos;
  9749.     ptr = begin;
  9750.     if(gg.txtbuf.tcontmode) (ptr++, gg.txtbuf.tcontmode = 0);
  9751.     for(;;){
  9752.         c = *ptr;
  9753.         if(is_print(c) || special_char_disp(c) ||
  9754.            gg.stringskind == SJISSTR && issjiskana(c)){
  9755.             txtchrwidth = 1;
  9756.         } else
  9757.         if(gg.stringskind == EUCSTR && (iseuc(c) || isSS2(c)) ||
  9758.            gg.stringskind == SJISSTR && issjis1(c)){
  9759.             int tcont; /* boolean */
  9760.  
  9761.             tcont = (ptr + 1 >= end);
  9762.             if(!tcont){
  9763.                 next = ptr[1]; /* ptr: us_char* */
  9764.             } else {
  9765.                 next = getc(inf -> f);
  9766.                 if(next != EOF) ungetc(next, inf -> f);
  9767.                  /* od_eucの場合と同様の事項に注意 */
  9768.             }
  9769.             if(gg.stringskind == EUCSTR ? iseuc(next) : issjis2(next)){
  9770.                 txtchrwidth = 2;
  9771.                 gg.txtbuf.tcontmode = tcont;
  9772.             } else {
  9773.                 txtchrwidth = 0;
  9774.             }
  9775.         } else {
  9776.             txtchrwidth = 0;
  9777.         }
  9778.         
  9779.         if(txtchrwidth){
  9780.             if(!txtlen){
  9781.                 gg.txtbuf.filepos = inf -> curpos;
  9782.                 addpos(&gg.txtbuf.filepos, ptr - begin);
  9783.             }
  9784.             if(txtlen + txtchrwidth > gg.txtbuf.buflen){
  9785.                 gg.txtbuf.buf = (us_char *)realloc(
  9786.                     (void *)gg.txtbuf.buf,
  9787.                     gg.txtbuf.buflen = txtlen + 100);
  9788.                 if(gg.txtbuf.buf == NULL){
  9789.                     _putnomemmes();
  9790.                     MessageBox(NULL, ERR_MEMORY, "cwtools.dll", MB_OK);
  9791.                     exit(2);
  9792.                      /* exit code 2 when error */
  9793.                 }
  9794.             }
  9795.             gg.txtbuf.buf[txtlen++] = c;
  9796.             if(txtchrwidth > 1){
  9797.                 gg.txtbuf.buf[txtlen++] = next;
  9798.                 ptr++;
  9799.             }
  9800.         } else {
  9801.             if(txtlen >= gg.stringslen){
  9802.                 odstrout(gg.txtbuf.filepos,
  9803.                      gg.txtbuf.buf, txtlen);
  9804.             }
  9805.             txtlen = 0;
  9806.         }
  9807.         if(++ptr >= end) break;
  9808.     }
  9809.     gg.txtbuf.pos = txtlen;
  9810. }
  9811.  
  9812. void    odstrout(us_long filepos, us_char *buf, us_int n)
  9813. { /* 今のところ漢字について考慮の必要はなし */
  9814.     us_char c, d;
  9815.     us_int  dummy = 0;
  9816.     char *bufo;
  9817.     char *po;
  9818.  
  9819.     odaddr(filepos, &dummy, 0);
  9820.     bufo = malloc(2 * n + 1); if (bufo == NULL) return;
  9821.     po = bufo;
  9822.     for(; n; n--, buf++){
  9823.         d = special_char_disp(c = *buf);
  9824.         if (d) {
  9825.             *po++ = '\\'; *po++ = d;
  9826.         } else {
  9827.             *po++ = c;
  9828.         }
  9829.     }
  9830.     *po++ = '\n'; *po = '\0';
  9831.     cwFputs(bufo, NULL);
  9832.     free(bufo);
  9833. }
  9834.  
  9835. void    odsub(struct infile *inf, int sw, us_int len)
  9836. {
  9837.     us_char *begin, *end;
  9838.     int addrout = 0;
  9839.  
  9840.     if(!len){
  9841.         if(gg.outmode & ~STRINGOUT)
  9842.             odaddr(inf -> curpos, &addrout, 1);
  9843.         return;
  9844.     }
  9845.  
  9846.     end = (begin = gg.usebuf[sw].buf) + len;
  9847.  
  9848.      /* lenは少なくとも1 */ /* バイト順序はシステム依存 */
  9849.     if(gg.outmode & OCTDUMP){
  9850.         od_oct(inf, &addrout, begin, end);
  9851.     }
  9852.     if(gg.outmode & DECDUMP){
  9853.         od_dec(inf, &addrout, begin, end);
  9854.     }
  9855.     if(gg.outmode & SGNDECDUMP){
  9856.         od_sgndec(inf, &addrout, begin, end);
  9857.     }
  9858.     if(gg.outmode & HEXDUMP){
  9859.         od_hex(inf, &addrout, begin, end);
  9860.     }
  9861.     if(gg.outmode & CHARDUMP){
  9862.         od_char(inf, &addrout, begin, end);
  9863.     }
  9864.     if(gg.outmode & EUCDUMP){
  9865.         od_euc(inf, &addrout, begin, end, sw);
  9866.     }
  9867.     if(gg.outmode & SJISDUMP){
  9868.         od_sjis(inf, &addrout, begin, end, sw);
  9869.     }
  9870.     if(gg.outmode & BYTEDUMP){
  9871.         od_byte(inf, &addrout, begin, end);
  9872.     }
  9873.     if(gg.outmode & BITMAPOUT){
  9874.         od_bm(inf, &addrout, begin, end);
  9875.     }
  9876.     if(gg.outmode & STRINGOUT){
  9877.         od_str(inf, begin, end); /* &addroutは不要 */
  9878.     }
  9879. }
  9880.  
  9881. void write_err(void);
  9882.  
  9883. void putnl(void)
  9884. {
  9885.     cwFputs("\n", NULL);
  9886. }
  9887.  
  9888. void write_err(void)
  9889. {
  9890.     cwFputs("Write error\n", (LPSTR)-1), exit(2);
  9891. }
  9892.  
  9893. us_int fread_pad(char *p, us_int len, FILE *f)
  9894.  /* 最大lenバイト読み、残りを0で埋める */
  9895. {
  9896.     us_int  r;
  9897.  
  9898.     if(feof(f)) return 0;
  9899.     if(len > (r = fread(p, 1, len, f))) memset(p + r, 0, len - r);
  9900.     return r;
  9901. }
  9902.  
  9903. int chksame(FILE *f, struct bufstr *ubuf0, struct bufstr *ubuf1, us_int n)
  9904. {
  9905.     int c;
  9906.  
  9907.     if(!n || memcmp(ubuf0 -> buf, ubuf1 -> buf, n) ||
  9908.        ubuf0 -> contmode != ubuf1 -> contmode) return 0;
  9909.     if(ubuf0 -> contmode){
  9910.         if(EOF != (c = getc(f))) ungetc(c, f);
  9911.         return ubuf0 -> buf[0] == c;
  9912.     } else return 1;
  9913. }
  9914.  
  9915. void    od(struct infile *inf)
  9916. {
  9917.     us_char *p;
  9918.     us_int  n, bufsw;
  9919.  
  9920.     if (inf->f == NULL) {
  9921.         cwFputs("now can't support stdin\n", (LPSTR)-1);
  9922.         return;
  9923.     }
  9924.  
  9925.     if(gg.bytelen != gg.bytelen1){
  9926.         n = fread_pad(p = gg.usebuf[0].buf, gg.bytelen1, inf->f);
  9927.         odsub(inf, 0, n);
  9928.         if(!n) return;
  9929.         addpos(&inf -> curpos, n);
  9930.  
  9931.         memset(p, 0, /* これはbytelen1 > bytelenの場合のみ意味あり */
  9932.             (gg.bytelen1 + MAXDISPUNIT - 1) & ~(MAXDISPUNIT - 1));
  9933.     }
  9934.  
  9935.     n = fread_pad(p = gg.usebuf[1].buf, gg.bytelen, inf->f);
  9936.     odsub(inf, 1, n);
  9937.     if(!n) return;
  9938.     addpos(&inf -> curpos, n);
  9939.  
  9940.     for(bufsw = 1;;){
  9941.         n = fread_pad(p = gg.usebuf[bufsw ^= 1].buf, gg.bytelen, inf -> f);
  9942.         if(!gg.alldata && chksame(inf->f, &gg.usebuf[0], &gg.usebuf[1], n)){
  9943.             if(gg.outmode & ~STRINGOUT) (putchar('*'), putchar('\n'));
  9944.             do {
  9945.                 addpos(&inf -> curpos, n);
  9946.                 n = fread_pad(p, gg.bytelen, inf -> f);
  9947.             } while(chksame(inf -> f, &gg.usebuf[0], &gg.usebuf[1], n));
  9948.         }
  9949.         odsub(inf, bufsw, n);
  9950.         if(!n) return;
  9951.         addpos(&inf -> curpos, n);
  9952.     }
  9953. }
  9954.  
  9955. void fbufset(FILE *f)
  9956. {
  9957.     if (f == NULL) {
  9958.         return;
  9959.     }
  9960.      /* bigbufは大きさBIGBUFSIZのバッファかあるいはNULL */
  9961.     if(gg.bigbuf != NULL && 0 != setvbuf(f, gg.bigbuf, _IOFBF, BIGBUFSIZ)){
  9962.         nobuf();
  9963.     } /* fbufset()は一度しか呼ばれないので他のファイルとバッファを
  9964.          取り合ったりすることはない */
  9965.  
  9966. }
  9967.  
  9968. int od_main(int ac, char **av)
  9969. {
  9970.     int nret = 0;
  9971.     int i, c;
  9972. //  extern  int optind, opterr;
  9973. //  extern  char    *optarg;
  9974.     struct  infile  inf;
  9975.  
  9976.     inf.f = NULL;
  9977.  
  9978.     gg.opterr = 0;
  9979.  
  9980. #define asrtmax(v, n) (((int)(v) < (int)(n)) && ((int)(v) = (int)(n)))
  9981.     while(EOF != (c = getopt(ac, av, "bcdosxw:vW:CSmt:rnXpu"))){
  9982.         switch(c){
  9983.         case 'b': gg.outmode |= BYTEDUMP;   /* 後でfieldb調節 */ break;
  9984.         case 'c': gg.outmode |= CHARDUMP;   /* 後でfieldb調節 */ break;
  9985.         case 'd': gg.outmode |= DECDUMP;    asrtmax(gg.fieldw, 5); break;
  9986.         case 'o': gg.outmode |= OCTDUMP;    asrtmax(gg.fieldw, 6); break;
  9987.         case 's': gg.outmode |= SGNDECDUMP; asrtmax(gg.fieldw, 6); break;
  9988.         case 'x': gg.outmode |= HEXDUMP;    asrtmax(gg.fieldw, 4); break;
  9989.         case 'w': gg.bytelen = atoi(gg.optarg); break;
  9990.         case 'v': gg.alldata = 1; break;
  9991.          /* 以下は拡張 */
  9992.         case 'W': gg.bytelen1 = atoi(gg.optarg); break;
  9993.         case 'C': gg.outmode |= EUCDUMP;    /* 後でfieldb調節 */ break;
  9994.         case 'S': gg.outmode |= SJISDUMP;   /* 後でfieldb調節 */ break;
  9995.         case 'm': gg.outmode |= BITMAPOUT;  asrtmax(gg.fieldb, 8); break;
  9996.         case 't': gg.outmode |= STRINGOUT;  gg.stringslen = atoi(gg.optarg);
  9997.               {char *p; for(p = gg.optarg; isdigit(*p); p++);
  9998.                gg.stringskind = *p == 'S' ? SJISSTR : 
  9999.                      *p == 'C' ? EUCSTR : ASCIISTR;}
  10000.         case 'r': gg.endianrev = 1; break;
  10001.         case 'n': gg.addrmode = NOADDR; break;
  10002.         case 'X': gg.hexcode = 1; break;
  10003.         case 'p': gg.sepwidth = 0; break;
  10004.          /* \ntbrfave also treated as text */
  10005.         default: nret = od_usage(); goto EXIT;
  10006.         }
  10007.     }
  10008.      /* オプションの調整 */
  10009.     if(gg.stringslen && gg.undump){
  10010.         equivocal("-u and -t\n");
  10011.         nret = 1; goto EXIT;
  10012.     }
  10013.     if(!gg.outmode) (gg.outmode = OCTDUMP, gg.fieldw = 6);
  10014.     if(gg.outmode & (BYTEDUMP | CHARDUMP | SJISDUMP | EUCDUMP))
  10015.         asrtmax(gg.fieldb, gg.hexcode ? 2 : 3);
  10016.     if(gg.addrmode == NOADDR){ /* -nを指定したら-vも連動 */
  10017.         gg.alldata = 1;
  10018.     }
  10019.     if(!gg.bytelen) gg.bytelen = 16;
  10020.     if(!gg.bytelen1) gg.bytelen1 = gg.bytelen;
  10021.         /* bytelen1が未設定(0)のままならbytelenと同じにする */
  10022.      /* 幅の調整 */
  10023.     if(!gg.sepwidth) gg.sepwidth = 1;
  10024.             /* この後gg.sepwidthは変わりうるのでそれまでに */
  10025.     if(gg.fieldw && gg.fieldb){
  10026.         if(gg.fieldw & 1){
  10027.             if(gg.fieldb * 2 < gg.fieldw){
  10028.                 gg.sepwidth = 1;
  10029.                 gg.fieldb = gg.fieldw >> 1;
  10030.             } else gg.fieldw = gg.fieldb * 2 + gg.sepwidth;;
  10031.         } else {
  10032.             if(!gg.sepwidth){
  10033.                 if(gg.fieldb * 2 < gg.fieldw) gg.fieldb = gg.fieldw >> 1;
  10034.                  else gg.fieldw = gg.fieldb * 2;
  10035.             } else {
  10036.                 if(gg.fieldb * 2 < gg.fieldw){
  10037.                     gg.fieldb = gg.fieldw / 2 - 1;
  10038.                     gg.sepwidth = 2;
  10039.                 } else gg.fieldw = gg.fieldb * 2 + 1;
  10040.             }
  10041.         }
  10042.     }
  10043.  
  10044.      /* バッファの用意 */
  10045.     gg.usebuf[0].buflen = 
  10046.         ((gg.bytelen>gg.bytelen1?gg.bytelen:gg.bytelen1)+MAXDISPUNIT - 1) &
  10047.         ~(MAXDISPUNIT - 1);
  10048.     gg.usebuf[1].buflen = (gg.bytelen + MAXDISPUNIT - 1) & ~(MAXDISPUNIT - 1);
  10049.     for(i = 0; i < 2; i++){
  10050.         gg.usebuf[i].buf = (us_char *)malloc_chk_z(gg.usebuf[i].buflen);
  10051.         gg.usebuf[i].pos = gg.usebuf[i].contmode = 0;     
  10052.     }
  10053.     gg.bigbuf = malloc(BIGBUFSIZ); /* NULLならsetvbufしない */
  10054.     setstdoutbuf();
  10055.     gg.txtbuf.buf = (us_char *)malloc_chk_z(gg.txtbuf.buflen = 100);
  10056.     gg.txtbuf.tcontmode = gg.txtbuf.pos = 0;
  10057.  
  10058.     ac -= gg.optind, av += gg.optind;
  10059.     inf.curline = 0L;
  10060.     switch(ac){
  10061.     case 0:
  10062.         fbufset(inf.f = NULL);
  10063.         inf . curpos = 0L;
  10064.         od(&inf); break;
  10065.     case 1:
  10066.         if(**av == '+'){
  10067.             fbufset(inf.f = NULL);
  10068.             inf.curpos = setoffset(NULL, *av);
  10069.             addpos(&inf.curpos, 0);
  10070.             od(&inf);
  10071.         } else {
  10072.             fbufset(inf.f = fopen_chk(*av, "r"));
  10073.             inf.curpos = 0L;
  10074.             od(&inf);
  10075.         }
  10076.         break;
  10077.     case 2:
  10078.         if(av[1][0] != '+') {
  10079.             nret = od_usage(); goto EXIT;
  10080.         }
  10081.         fbufset(inf.f = fopen_chk(*av, "r"));
  10082.         inf.curpos = setoffset(inf.f, av[1]);
  10083.         addpos(&inf.curpos, 0);
  10084.         od(&inf);
  10085.         break;
  10086.     default:
  10087.         nret = od_usage(); goto EXIT;
  10088.     }
  10089.     if((gg.outmode & STRINGOUT) && gg.txtbuf.pos >= gg.stringslen){
  10090.       /* strings未出力分掃き出し */
  10091.         odstrout(gg.txtbuf.filepos, gg.txtbuf.buf, gg.txtbuf.pos);
  10092.     }
  10093. EXIT:
  10094.     if (inf.f != NULL) fclose(inf.f);
  10095.     return 0;
  10096. }
  10097.  
  10098. void setstdoutbuf(void)
  10099. {
  10100.     int i;
  10101.         
  10102.     i = (isatty(1) ? OBUFSIZ : BIGBUFSIZ);
  10103.     if(NULL != (gg.obigbuf = malloc(i))){
  10104.         if(0 != setvbuf(stdout, gg.obigbuf, _IOFBF, i)) nobuf();
  10105.     }
  10106. }
  10107.