From 3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 16 Jan 1998 12:13:05 +0000 Subject: Initial revision git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/Setup | 12 + ext/Setup.dj | 12 + ext/Setup.nt | 12 + ext/Setup.x68 | 12 + ext/aix_ld.rb | 73 ++ ext/curses/MANIFEST | 6 + ext/curses/curses.c | 798 ++++++++++++++++++++ ext/curses/extconf.rb | 21 + ext/curses/hello.rb | 28 + ext/curses/rain.rb | 76 ++ ext/curses/view.rb | 90 +++ ext/dbm/MANIFEST | 4 + ext/dbm/dbm.c | 515 +++++++++++++ ext/dbm/depend | 1 + ext/dbm/extconf.rb | 5 + ext/etc/MANIFEST | 5 + ext/etc/depend | 1 + ext/etc/etc.c | 266 +++++++ ext/etc/etc.doc | 73 ++ ext/etc/extconf.rb | 7 + ext/extmk.rb.in | 468 ++++++++++++ ext/extmk.rb.nt | 480 ++++++++++++ ext/fcntl/MANIFEST | 3 + ext/fcntl/depend | 1 + ext/fcntl/fcntl.c | 106 +++ ext/kconv/MANIFEST | 3 + ext/kconv/depend | 1 + ext/kconv/kconv.c | 1881 +++++++++++++++++++++++++++++++++++++++++++++++ ext/marshal/MANIFEST | 5 + ext/marshal/depend | 2 + ext/marshal/extconf.rb | 1 + ext/marshal/marshal.c | 850 +++++++++++++++++++++ ext/marshal/marshal.doc | 48 ++ ext/md5/MANIFEST | 6 + ext/md5/depend | 2 + ext/md5/md5.doc | 36 + ext/md5/md5.h | 86 +++ ext/md5/md5c.c | 337 +++++++++ ext/md5/md5init.c | 90 +++ ext/socket/MANIFEST | 4 + ext/socket/depend | 1 + ext/socket/extconf.rb | 17 + ext/socket/socket.c | 1407 +++++++++++++++++++++++++++++++++++ ext/tkutil/MANIFEST | 3 + ext/tkutil/depend | 1 + ext/tkutil/tkutil.c | 46 ++ 46 files changed, 7902 insertions(+) create mode 100644 ext/Setup create mode 100644 ext/Setup.dj create mode 100644 ext/Setup.nt create mode 100644 ext/Setup.x68 create mode 100644 ext/aix_ld.rb create mode 100644 ext/curses/MANIFEST create mode 100644 ext/curses/curses.c create mode 100644 ext/curses/extconf.rb create mode 100644 ext/curses/hello.rb create mode 100644 ext/curses/rain.rb create mode 100644 ext/curses/view.rb create mode 100644 ext/dbm/MANIFEST create mode 100644 ext/dbm/dbm.c create mode 100644 ext/dbm/depend create mode 100644 ext/dbm/extconf.rb create mode 100644 ext/etc/MANIFEST create mode 100644 ext/etc/depend create mode 100644 ext/etc/etc.c create mode 100644 ext/etc/etc.doc create mode 100644 ext/etc/extconf.rb create mode 100644 ext/extmk.rb.in create mode 100644 ext/extmk.rb.nt create mode 100644 ext/fcntl/MANIFEST create mode 100644 ext/fcntl/depend create mode 100644 ext/fcntl/fcntl.c create mode 100644 ext/kconv/MANIFEST create mode 100644 ext/kconv/depend create mode 100644 ext/kconv/kconv.c create mode 100644 ext/marshal/MANIFEST create mode 100644 ext/marshal/depend create mode 100644 ext/marshal/extconf.rb create mode 100644 ext/marshal/marshal.c create mode 100644 ext/marshal/marshal.doc create mode 100644 ext/md5/MANIFEST create mode 100644 ext/md5/depend create mode 100644 ext/md5/md5.doc create mode 100644 ext/md5/md5.h create mode 100644 ext/md5/md5c.c create mode 100644 ext/md5/md5init.c create mode 100644 ext/socket/MANIFEST create mode 100644 ext/socket/depend create mode 100644 ext/socket/extconf.rb create mode 100644 ext/socket/socket.c create mode 100644 ext/tkutil/MANIFEST create mode 100644 ext/tkutil/depend create mode 100644 ext/tkutil/tkutil.c (limited to 'ext') diff --git a/ext/Setup b/ext/Setup new file mode 100644 index 0000000000..a5dd7978c3 --- /dev/null +++ b/ext/Setup @@ -0,0 +1,12 @@ +#option nodynamic + +#GD +#curses +#dbm +#etc +#fcntl +#kconv +#marshal +#md5 +#socket +#tkutil diff --git a/ext/Setup.dj b/ext/Setup.dj new file mode 100644 index 0000000000..25adea2035 --- /dev/null +++ b/ext/Setup.dj @@ -0,0 +1,12 @@ +option nodynamic + +#GD +#curses +dbm +#etc +fcntl +kconv +marshal +md5 +#socket +#tkutil diff --git a/ext/Setup.nt b/ext/Setup.nt new file mode 100644 index 0000000000..b469709585 --- /dev/null +++ b/ext/Setup.nt @@ -0,0 +1,12 @@ +option nodynamic + +#GD +#curses +#dbm +#etc +fcntl +kconv +#marshal +md5 +socket +#tkutil diff --git a/ext/Setup.x68 b/ext/Setup.x68 new file mode 100644 index 0000000000..25adea2035 --- /dev/null +++ b/ext/Setup.x68 @@ -0,0 +1,12 @@ +option nodynamic + +#GD +#curses +dbm +#etc +fcntl +kconv +marshal +md5 +#socket +#tkutil diff --git a/ext/aix_ld.rb b/ext/aix_ld.rb new file mode 100644 index 0000000000..1058977b88 --- /dev/null +++ b/ext/aix_ld.rb @@ -0,0 +1,73 @@ +#! /usr/local/bin/ruby + +def older(file1, file2) + if !File.exist?(file1) then + return TRUE + end + if !File.exist?(file2) then + return FALSE + end + if File.mtime(file1) < File.mtime(file2) + return TRUE + end + return FALSE +end + +target = ARGV.shift +unless target =~ /\.so/ + STDERR.printf "wrong suffix specified\n" + exit 1 +end +base = File.basename(target, ".so") +entry="Init_#{base}" +ldargs = "-e#{entry} -bI:../ruby.imp -bM:SRE -T512 -H512 -lc" + +def uniq(data) + last=nil + data.delete_if do |name| + if last == name + TRUE + else + last = name + FALSE + end + end +end + +def extract(nm, out) + data = nm.readlines.collect{|line| + line = line.split + case line[1] + when "B", "D", "T" + line[2] + else + next + end + }.sort! + uniq(data) + exp = open(out, "w") + for line in data + exp.printf "%s\n", line + end + exp.close + nm.close +end +if older("../ruby.imp", "../../miniruby") +# nm = open("|/usr/ccs/bin/nm -Bex ../../*.o") +# nm = open("|/usr/ccs/bin/nm -Bex ../../*.o") + nm = open("|nm ../../*.o") + extract(nm, "../ruby.imp") +end + +objs = Dir["*.o"].join(" ") +#nm = open("|/usr/ccs/bin/nm -Bex #{objs}") +nm = open("|nm #{objs}") +extract(nm, "#{base}.exp") + +#system format("/usr/ccs/bin/ld %s %s ",ldargs,ARGV.join(' ')) +#system "/bin/rm -f #{base}.exp" +#system "chmod o-rwx ${base}.so" + +p format("/usr/ccs/bin/ld %s %s ",ldargs,ARGV.join(' ')) +p "/bin/rm -f #{base}.exp" +p "chmod o-rwx ${base}.so" diff --git a/ext/curses/MANIFEST b/ext/curses/MANIFEST new file mode 100644 index 0000000000..db5e54ffe8 --- /dev/null +++ b/ext/curses/MANIFEST @@ -0,0 +1,6 @@ +MANIFEST +curses.c +extconf.rb +hello.rb +rain.rb +view.rb diff --git a/ext/curses/curses.c b/ext/curses/curses.c new file mode 100644 index 0000000000..6e8e49684f --- /dev/null +++ b/ext/curses/curses.c @@ -0,0 +1,798 @@ +/* + * ext/curses/curses.c + * + * by MAEDA Shugo (ender@pic-internet.or.jp) + * modified by Yukihiro Matsumoto (matz@ruby.club.or.jp) + */ + +#ifdef HAVE_NCURSES_H +# include +#else +# ifdef HAVE_NCURSES_CURSES_H +# include +# else +# include +# if defined(__NetBSD__) && !defined(_maxx) +# define _maxx maxx +# endif +# if defined(__NetBSD__) && !defined(_maxy) +# define _maxy maxy +# endif +# endif +#endif + +#include "ruby.h" + +static VALUE mCurses; +static VALUE cWindow; + +VALUE rb_stdscr; + +struct windata { + WINDOW *window; +}; + +#define NUM2CHAR(x) (char)NUM2INT(x) +#define CHAR2FIX(x) INT2FIX((int)x) + +static void +no_window() +{ + Fail("already closed window"); +} + +#define GetWINDOW(obj, winp) {\ + Data_Get_Struct(obj, struct windata, winp);\ + if (winp->window == 0) no_window();\ +} + +static void +curses_err() +{ + Fail("curses error"); +} + +#define CHECK(c) if ((c)==ERR) {curses_err();} + +static void +free_window(winp) + struct windata *winp; +{ + if (winp->window && winp->window != stdscr) delwin(winp->window); + winp->window = 0; +} + +static VALUE +prep_window(class, window) + VALUE class; + WINDOW *window; +{ + VALUE obj; + struct windata *winp; + + if (window == NULL) { + Fail("failed to create window"); + } + + obj = Data_Make_Struct(class, struct windata, 0, free_window, winp); + winp->window = window; + + return obj; +} + +/*-------------------------- module Curses --------------------------*/ + +/* def init_screen */ +static VALUE +curses_init_screen() +{ + initscr(); + if (stdscr == 0) { + Fail("cannot initialize curses"); + } + clear(); + rb_stdscr = prep_window(cWindow, stdscr); + return Qnil; +} + +/* def stdscr */ +static VALUE +curses_stdscr() +{ + if (!rb_stdscr) curses_init_screen(); + return rb_stdscr; +} + +/* def close_screen */ +static VALUE +curses_close_screen() +{ + CHECK(endwin()); + return Qnil; +} + +/* def closed? */ +static VALUE +curses_closed() +{ +#ifdef HAVE_ENDWIN + if (isendwin()) { + return TRUE; + } + return FALSE; +#else + rb_notimplement(); +#endif +} + +/* def clear */ +static VALUE +curses_clear(obj) + VALUE obj; +{ + wclear(stdscr); + return Qnil; +} + +/* def refresh */ +static VALUE +curses_refresh(obj) + VALUE obj; +{ + CHECK(refresh()); + return Qnil; +} + +/* def refresh */ +static VALUE +curses_doupdate(obj) + VALUE obj; +{ + CHECK(doupdate()); + return Qnil; +} + +/* def echo */ +static VALUE +curses_echo(obj) + VALUE obj; +{ + CHECK(echo()); + return Qnil; +} + +/* def noecho */ +static VALUE +curses_noecho(obj) + VALUE obj; +{ + CHECK(noecho()); + return Qnil; +} + +/* def raw */ +static VALUE +curses_raw(obj) + VALUE obj; +{ + CHECK(raw()); + return Qnil; +} + +/* def noraw */ +static VALUE +curses_noraw(obj) + VALUE obj; +{ + CHECK(noraw()); + return Qnil; +} + +/* def cbreak */ +static VALUE +curses_cbreak(obj) + VALUE obj; +{ + CHECK(cbreak()); + return Qnil; +} + +/* def nocbreak */ +static VALUE +curses_nocbreak(obj) + VALUE obj; +{ + CHECK(nocbreak()); + return Qnil; +} + +/* def nl */ +static VALUE +curses_nl(obj) + VALUE obj; +{ + CHECK(nl()); + return Qnil; +} + +/* def nonl */ +static VALUE +curses_nonl(obj) + VALUE obj; +{ + CHECK(nonl()); + return Qnil; +} + +/* def beep */ +static VALUE +curses_beep(obj) + VALUE obj; +{ +#ifdef HAVE_BEEP + beep(); +#endif + return Qnil; +} + +/* def flash */ +static VALUE +curses_flash(obj) + VALUE obj; +{ + flash(); + return Qnil; +} + +/* def ungetch */ +static VALUE +curses_ungetch(obj, ch) + VALUE obj; + VALUE ch; +{ +#ifdef HAVE_UNGETCH + CHECK(ungetch(NUM2INT(ch))); +#else + rb_notimplement(); +#endif + return Qnil; +} + +/* def setpos(y, x) */ +static VALUE +curses_setpos(obj, y, x) + VALUE obj; + VALUE y; + VALUE x; +{ + CHECK(move(NUM2INT(y), NUM2INT(x))); + return Qnil; +} + +/* def standout */ +static VALUE +curses_standout(obj) + VALUE obj; +{ + standout(); + return Qnil; +} + +/* def standend */ +static VALUE +curses_standend(obj) + VALUE obj; +{ + standend(); + return Qnil; +} + +/* def inch */ +static VALUE +curses_inch(obj) + VALUE obj; +{ + return CHAR2FIX(inch()); +} + +/* def addch(ch) */ +static VALUE +curses_addch(obj, ch) + VALUE obj; + VALUE ch; +{ + CHECK(addch(NUM2CHAR(ch))); + return Qnil; +} + +/* def insch(ch) */ +static VALUE +curses_insch(obj, ch) + VALUE obj; + VALUE ch; +{ + CHECK(insch(NUM2CHAR(ch))); + return Qnil; +} + +/* def addstr(str) */ +static VALUE +curses_addstr(obj, str) + VALUE obj; + VALUE str; +{ + addstr(RSTRING(str)->ptr); + return Qnil; +} + +/* def getch */ +static VALUE +curses_getch(obj) + VALUE obj; +{ + return CHAR2FIX(getch()); +} + +/* def getstr */ +static VALUE +curses_getstr(obj) + VALUE obj; +{ + char rtn[1024]; /* This should be big enough.. I hope */ + CHECK(getstr(rtn)); + return str_taint(str_new2(rtn)); +} + +/* def delch */ +static VALUE +curses_delch(obj) + VALUE obj; +{ + CHECK(delch()); + return Qnil; +} + +/* def delelteln */ +static VALUE +curses_deleteln(obj) + VALUE obj; +{ + CHECK(deleteln()); + return Qnil; +} + +static VALUE +curses_lines() +{ + return INT2FIX(LINES); +} + +static VALUE +curses_cols() +{ + return INT2FIX(COLS); +} + +/*-------------------------- class Window --------------------------*/ + +/* def new(lines, cols, top, left) */ +static VALUE +window_s_new(class, lines, cols, top, left) + VALUE class; + VALUE lines; + VALUE cols; + VALUE top; + VALUE left; +{ + WINDOW *window; + + window = newwin(NUM2INT(lines), NUM2INT(cols), NUM2INT(top), NUM2INT(left)); + wclear(window); + return prep_window(class, window); +} + +/* def subwin(lines, cols, top, left) */ +static VALUE +window_subwin(obj, lines, cols, top, left) + VALUE obj; + VALUE lines; + VALUE cols; + VALUE top; + VALUE left; +{ + struct windata *winp; + WINDOW *window; + + GetWINDOW(obj, winp); + window = subwin(winp->window, NUM2INT(lines), NUM2INT(cols), + NUM2INT(top), NUM2INT(left)); + return prep_window(cWindow, window); +} + +/* def close */ +static VALUE +window_close(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + free_window(winp); + + return Qnil; +} + +/* def clear */ +static VALUE +window_clear(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + wclear(winp->window); + + return Qnil; +} + +/* def refresh */ +static VALUE +window_refresh(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(wrefresh(winp->window)); + + return Qnil; +} + +/* def box(vert, hor) */ +static VALUE +window_box(obj, vert, hor) + VALUE obj; + VALUE vert; + VALUE hor; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + box(winp->window, NUM2CHAR(vert), NUM2CHAR(hor)); + + return Qnil; +} + + +/* def move(y, x) */ +static VALUE +window_move(obj, y, x) + VALUE obj; + VALUE y; + VALUE x; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(mvwin(winp->window, NUM2INT(y), NUM2INT(x))); + + return Qnil; +} + +/* def setpos(y, x) */ +static VALUE +window_setpos(obj, y, x) + VALUE obj; + VALUE y; + VALUE x; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(wmove(winp->window, NUM2INT(y), NUM2INT(x))); + return Qnil; +} + +/* def cury */ +static VALUE +window_cury(obj) + VALUE obj; +{ + struct windata *winp; + int x, y; + + GetWINDOW(obj, winp); + getyx(winp->window, y, x); + return INT2FIX(y); +} + +/* def curx */ +static VALUE +window_curx(obj) + VALUE obj; +{ + struct windata *winp; + int x, y; + + GetWINDOW(obj, winp); + getyx(winp->window, y, x); + return INT2FIX(x); +} + +/* def maxy */ +static VALUE +window_maxy(obj) + VALUE obj; +{ + struct windata *winp; + int x, y; + + GetWINDOW(obj, winp); +#ifdef getmaxy + return INT2FIX(getmaxy(winp->window)); +#else +#ifdef getmaxyx + getmaxyx(winp->window, y, x); + return INT2FIX(y); +#else + return INT2FIX(winp->window->_maxy+1); +#endif +#endif +} + +/* def maxx */ +static VALUE +window_maxx(obj) + VALUE obj; +{ + struct windata *winp; + int x, y; + + GetWINDOW(obj, winp); +#ifdef getmaxx + return INT2FIX(getmaxx(winp->window)); +#else +#ifdef getmaxyx + getmaxyx(winp->window, y, x); + return INT2FIX(x); +#else + return INT2FIX(winp->window->_maxx+1); +#endif +#endif +} + +/* def begy */ +static VALUE +window_begy(obj) + VALUE obj; +{ + struct windata *winp; + int x, y; + + GetWINDOW(obj, winp); +#ifdef getbegyx + getbegyx(winp->window, y, x); + return INT2FIX(y); +#else + return INT2FIX(winp->window->_begy); +#endif +} + +/* def begx */ +static VALUE +window_begx(obj) + VALUE obj; +{ + struct windata *winp; + int x, y; + + GetWINDOW(obj, winp); +#ifdef getbegyx + getbegyx(winp->window, y, x); + return INT2FIX(x); +#else + return INT2FIX(winp->window->_begx); +#endif +} + +/* def standout */ +static VALUE +window_standout(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + wstandout(winp->window); + return Qnil; +} + +/* def standend */ +static VALUE +window_standend(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + wstandend(winp->window); + return Qnil; +} + +/* def inch */ +static VALUE +window_inch(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + return CHAR2FIX(winch(winp->window)); +} + +/* def addch(ch) */ +static VALUE +window_addch(obj, ch) + VALUE obj; + VALUE ch; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(waddch(winp->window, NUM2CHAR(ch))); + + return Qnil; +} + +/* def insch(ch) */ +static VALUE +window_insch(obj, ch) + VALUE obj; + VALUE ch; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(winsch(winp->window, NUM2CHAR(ch))); + + return Qnil; +} + +/* def addstr(str) */ +static VALUE +window_addstr(obj, str) + VALUE obj; + VALUE str; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(waddstr(winp->window, RSTRING(str)->ptr)); + + return Qnil; +} + +/* def <<(str) */ +static VALUE +window_addstr2(obj, str) + VALUE obj; + VALUE str; +{ + window_addstr(obj, str); + return obj; +} + +/* def getch */ +static VALUE +window_getch(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + return CHAR2FIX(wgetch(winp->window)); +} + +/* def getstr */ +static VALUE +window_getstr(obj) + VALUE obj; +{ + struct windata *winp; + char rtn[1024]; /* This should be big enough.. I hope */ + + GetWINDOW(obj, winp); + CHECK(wgetstr(winp->window, rtn)); + return str_taint(str_new2(rtn)); +} + +/* def delch */ +static VALUE +window_delch(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(wdelch(winp->window)); + return Qnil; +} + +/* def delelteln */ +static VALUE +window_deleteln(obj) + VALUE obj; +{ + struct windata *winp; + + GetWINDOW(obj, winp); + CHECK(wdeleteln(winp->window)); + return Qnil; +} + +/*------------------------- Initialization -------------------------*/ +void +Init_curses() +{ + mCurses = rb_define_module("Curses"); + rb_define_module_function(mCurses, "init_screen", curses_init_screen, 0); + rb_define_module_function(mCurses, "close_screen", curses_close_screen, 0); + rb_define_module_function(mCurses, "closed?", curses_closed, 0); + rb_define_module_function(mCurses, "stdscr", curses_stdscr, 0); + rb_define_module_function(mCurses, "refresh", curses_refresh, 0); + rb_define_module_function(mCurses, "doupdate", curses_doupdate, 0); + rb_define_module_function(mCurses, "clear", curses_clear, 0); + rb_define_module_function(mCurses, "echo", curses_echo, 0); + rb_define_module_function(mCurses, "noecho", curses_noecho, 0); + rb_define_module_function(mCurses, "raw", curses_raw, 0); + rb_define_module_function(mCurses, "noraw", curses_noraw, 0); + rb_define_module_function(mCurses, "cbreak", curses_cbreak, 0); + rb_define_module_function(mCurses, "nocbreak", curses_nocbreak, 0); + rb_define_alias(mCurses, "crmode", "cbreak"); + rb_define_alias(mCurses, "nocrmode", "nocbreak"); + rb_define_module_function(mCurses, "nl", curses_nl, 0); + rb_define_module_function(mCurses, "nonl", curses_nonl, 0); + rb_define_module_function(mCurses, "beep", curses_beep, 0); + rb_define_module_function(mCurses, "flash", curses_flash, 0); + rb_define_module_function(mCurses, "ungetch", curses_ungetch, 1); + rb_define_module_function(mCurses, "setpos", curses_setpos, 2); + rb_define_module_function(mCurses, "standout", curses_standout, 0); + rb_define_module_function(mCurses, "standend", curses_standend, 0); + rb_define_module_function(mCurses, "inch", curses_inch, 0); + rb_define_module_function(mCurses, "addch", curses_addch, 1); + rb_define_module_function(mCurses, "insch", curses_insch, 1); + rb_define_module_function(mCurses, "addstr", curses_addstr, 1); + rb_define_module_function(mCurses, "getch", curses_getch, 0); + rb_define_module_function(mCurses, "getstr", curses_getstr, 0); + rb_define_module_function(mCurses, "delch", curses_delch, 0); + rb_define_module_function(mCurses, "deleteln", curses_deleteln, 0); + rb_define_module_function(mCurses, "lines", curses_lines, 0); + rb_define_module_function(mCurses, "cols", curses_cols, 0); + + cWindow = rb_define_class_under(mCurses, "Window", cObject); + rb_define_singleton_method(cWindow, "new", window_s_new, 4); + rb_define_method(cWindow, "subwin", window_subwin, 4); + rb_define_method(cWindow, "close", window_close, 0); + rb_define_method(cWindow, "clear", window_clear, 0); + rb_define_method(cWindow, "refresh", window_refresh, 0); + rb_define_method(cWindow, "box", window_box, 2); + rb_define_method(cWindow, "move", window_move, 2); + rb_define_method(cWindow, "setpos", window_setpos, 2); + rb_define_method(cWindow, "cury", window_cury, 0); + rb_define_method(cWindow, "curx", window_curx, 0); + rb_define_method(cWindow, "maxy", window_maxy, 0); + rb_define_method(cWindow, "maxx", window_maxx, 0); + rb_define_method(cWindow, "begy", window_begy, 0); + rb_define_method(cWindow, "begx", window_begx, 0); + rb_define_method(cWindow, "standout", window_standout, 0); + rb_define_method(cWindow, "standend", window_standend, 0); + rb_define_method(cWindow, "inch", window_inch, 0); + rb_define_method(cWindow, "addch", window_addch, 1); + rb_define_method(cWindow, "insch", window_insch, 1); + rb_define_method(cWindow, "addstr", window_addstr, 1); + rb_define_method(cWindow, "<<", window_addstr2, 1); + rb_define_method(cWindow, "getch", window_getch, 0); + rb_define_method(cWindow, "getstr", window_getstr, 0); + rb_define_method(cWindow, "delch", window_delch, 0); + rb_define_method(cWindow, "deleteln", window_deleteln, 0); +} diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb new file mode 100644 index 0000000000..9b28437843 --- /dev/null +++ b/ext/curses/extconf.rb @@ -0,0 +1,21 @@ +$CFLAGS="-I/usr/include/ncurses -I/usr/local/include/ncurses" +$LDFLAGS="-L/usr/local/lib" +make=FALSE +if have_header("ncurses.h") and have_library("ncurses", "initscr") + make=TRUE +elsif have_header("ncurses/curses.h") and have_library("ncurses", "initscr") + make=TRUE +else + $CFLAGS=nil + have_library("termcap", "tgetent") + if have_library("curses", "initscr") + make=TRUE + end +end + +if make then + for f in ["isendwin", "ungetch", "beep"] + have_func(f) + end + create_makefile("curses") +end diff --git a/ext/curses/hello.rb b/ext/curses/hello.rb new file mode 100644 index 0000000000..bed7779aac --- /dev/null +++ b/ext/curses/hello.rb @@ -0,0 +1,28 @@ +#!/usr/local/bin/ruby + +require "curses" +include Curses + +def show_message(message) + width = message.length + 6 + win = Window.new(5, width, + (lines - 5) / 2, (cols - width) / 2) + win.box(?|, ?=) + win.setpos(2, 3) + win.addstr(message) + win.getch + win.close +end + +init_screen +begin + crmode +# show_message("Hit any key") + setpos (lines - 5) / 2, (cols - 10) / 2 + addstr("Hit any key") + getch + show_message("Hello, World!") + refresh +ensure + close_screen +end diff --git a/ext/curses/rain.rb b/ext/curses/rain.rb new file mode 100644 index 0000000000..36f0f84de2 --- /dev/null +++ b/ext/curses/rain.rb @@ -0,0 +1,76 @@ +#!/usr/local/bin/ruby +# rain for a curses test + +require "curses" +include Curses + +def onsig(sig) + close_screen + exit sig +end + +def ranf + rand(32767).to_f / 32767 +end + +# main # +for i in 1 .. 15 # SIGHUP .. SIGTERM + if trap(i, "SIG_IGN") != 0 then # 0 for SIG_IGN + trap(i) {|sig| onsig(sig) } + end +end + +init_screen +nl +noecho +srand + +xpos = {} +ypos = {} +r = lines - 4 +c = cols - 4 +for i in 0 .. 4 + xpos[i] = (c * ranf).to_i + 2 + ypos[i] = (r * ranf).to_i + 2 +end + +i = 0 +while TRUE + x = (c * ranf).to_i + 2 + y = (r * ranf).to_i + 2 + + + setpos(y, x); addstr(".") + + setpos(ypos[i], xpos[i]); addstr("o") + + i = if i == 0 then 4 else i - 1 end + setpos(ypos[i], xpos[i]); addstr("O") + + i = if i == 0 then 4 else i - 1 end + setpos(ypos[i] - 1, xpos[i]); addstr("-") + setpos(ypos[i], xpos[i] - 1); addstr("|.|") + setpos(ypos[i] + 1, xpos[i]); addstr("-") + + i = if i == 0 then 4 else i - 1 end + setpos(ypos[i] - 2, xpos[i]); addstr("-") + setpos(ypos[i] - 1, xpos[i] - 1); addstr("/ \\") + setpos(ypos[i], xpos[i] - 2); addstr("| O |") + setpos(ypos[i] + 1, xpos[i] - 1); addstr("\\ /") + setpos(ypos[i] + 2, xpos[i]); addstr("-") + + i = if i == 0 then 4 else i - 1 end + setpos(ypos[i] - 2, xpos[i]); addstr(" ") + setpos(ypos[i] - 1, xpos[i] - 1); addstr(" ") + setpos(ypos[i], xpos[i] - 2); addstr(" ") + setpos(ypos[i] + 1, xpos[i] - 1); addstr(" ") + setpos(ypos[i] + 2, xpos[i]); addstr(" ") + + + xpos[i] = x + ypos[i] = y + refresh + sleep(0.5) +end + +# end of main diff --git a/ext/curses/view.rb b/ext/curses/view.rb new file mode 100644 index 0000000000..e59a74ed44 --- /dev/null +++ b/ext/curses/view.rb @@ -0,0 +1,90 @@ +#!/usr/local/bin/ruby + +require "curses" +include Curses + +# +# main +# + +if ARGV.size != 1 then + printf("usage: view file\n"); + exit +end +begin + fp = open(ARGV[0], "r") +rescue + raise "cannot open file: #{ARGV[1]}" +end + +# signal(SIGINT, finish) + +init_screen +#keypad(stdscr, TRUE) +nonl +cbreak +noecho +#scrollok(stdscr, TRUE) + +# slurp the file +data_lines = [] +fp.each_line { |l| + data_lines.push(l) +} +fp.close + + +lptr = 0 +while TRUE + i = 0 + while i < lines + setpos(i, 0) + #clrtoeol + addstr(data_lines[lptr + i]) #if data_lines[lptr + i] + i += 1 + end + + explicit = FALSE + n = 0 + while TRUE + c = getch.chr + if c =~ "[0-9]" then + n = 10 * n + c.to_i + else + break + end + end + + n = 1 if !explicit && n == 0 + + case c + when "n" #when KEY_DOWN + i = 0 + while i < n + if lptr + lines < data_lines.size then + lptr += 1 + else + break + end + i += 1 + end + #wscrl(i) + + when "p" #when KEY_UP + i = 0 + while i < n + if lptr > 0 then + lptr -= 1 + else + break + end + i += 1 + end + #wscrl(-i) + + when "q" + break + end + +end +close_screen diff --git a/ext/dbm/MANIFEST b/ext/dbm/MANIFEST new file mode 100644 index 0000000000..8beec6783d --- /dev/null +++ b/ext/dbm/MANIFEST @@ -0,0 +1,4 @@ +MANIFEST +dbm.c +depend +extconf.rb diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c new file mode 100644 index 0000000000..ea0ac1930f --- /dev/null +++ b/ext/dbm/dbm.c @@ -0,0 +1,515 @@ +/************************************************ + + dbm.c - + + $Author$ + $Date$ + created at: Mon Jan 24 15:59:52 JST 1994 + + Copyright (C) 1995 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +#include +#include +#include + +VALUE cDBM; + +extern VALUE mEnumerable; + +struct dbmdata { + int di_size; + DBM *di_dbm; +}; + +static void +closed_dbm() +{ + Fail("closed DBM file"); +} + +#define GetDBM(obj, dbmp) {\ + Data_Get_Struct(obj, struct dbmdata, dbmp);\ + if (dbmp->di_dbm == 0) closed_dbm();\ +} + +static void +free_dbm(dbmp) + struct dbmdata *dbmp; +{ + if (dbmp->di_dbm) dbm_close(dbmp->di_dbm); +} + +static VALUE +fdbm_s_open(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + VALUE file, vmode; + DBM *dbm; + struct dbmdata *dbmp; + int mode; + VALUE obj; + + if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { + mode = 0666; /* default value */ + } + else if (NIL_P(vmode)) { + mode = -1; /* return nil if DB not exist */ + } + else { + mode = NUM2INT(vmode); + } + Check_SafeStr(file); + + dbm = 0; + if (mode >= 0) + dbm = dbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode); + if (!dbm) + dbm = dbm_open(RSTRING(file)->ptr, O_RDWR, mode); + if (!dbm) + dbm = dbm_open(RSTRING(file)->ptr, O_RDONLY, mode); + + if (!dbm) { + if (mode == -1) return Qnil; + rb_sys_fail(RSTRING(file)->ptr); + } + + obj = Data_Make_Struct(class,struct dbmdata,0,free_dbm,dbmp); + dbmp->di_dbm = dbm; + dbmp->di_size = -1; + + return obj; +} + +static VALUE +fdbm_close(obj) + VALUE obj; +{ + struct dbmdata *dbmp; + + Data_Get_Struct(obj, struct dbmdata, dbmp); + if (dbmp->di_dbm == 0) closed_dbm(); + dbm_close(dbmp->di_dbm); + dbmp->di_dbm = 0; + + return Qnil; +} + +static VALUE +fdbm_fetch(obj, keystr) + VALUE obj, keystr; +{ + datum key, value; + struct dbmdata *dbmp; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + value = dbm_fetch(dbm, key); + if (value.dptr == 0) { + return Qnil; + } + return str_taint(str_new(value.dptr, value.dsize)); +} + +static VALUE +fdbm_indexes(obj, args) + VALUE obj; + struct RArray *args; +{ + VALUE *p, *pend; + VALUE new; + int i = 0; + + args = (struct RArray*)rb_to_a(args); + new = ary_new2(args->len); + + p = args->ptr; pend = p + args->len; + while (p < pend) { + ary_push(new, fdbm_fetch(obj, *p++)); + } + return new; +} + +static VALUE +fdbm_delete(obj, keystr) + VALUE obj, keystr; +{ + datum key, value; + struct dbmdata *dbmp; + DBM *dbm; + + rb_secure(4); + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + value = dbm_fetch(dbm, key); + if (value.dptr == 0) { + if (iterator_p()) rb_yield(keystr); + return Qnil; + } + + if (dbm_delete(dbm, key)) { + dbmp->di_size = -1; + Fail("dbm_delete failed"); + } + else if (dbmp->di_size >= 0) { + dbmp->di_size--; + } + return obj; +} + +static VALUE +fdbm_shift(obj) + VALUE obj; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + VALUE keystr, valstr; + + rb_secure(4); + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + key = dbm_firstkey(dbm); + if (!key.dptr) return Qnil; + val = dbm_fetch(dbm, key); + dbm_delete(dbm, key); + + keystr = str_taint(str_new(key.dptr, key.dsize)); + valstr = str_taint(str_new(val.dptr, val.dsize)); + return assoc_new(keystr, valstr); +} + +static VALUE +fdbm_delete_if(obj) + VALUE obj; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + VALUE keystr, valstr; + + rb_secure(4); + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + keystr = str_taint(str_new(key.dptr, key.dsize)); + valstr = str_taint(str_new(val.dptr, val.dsize)); + if (RTEST(rb_yield(assoc_new(keystr, valstr)))) { + if (dbm_delete(dbm, key)) { + Fail("dbm_delete failed"); + } + } + } + return obj; +} + +static VALUE +fdbm_clear(obj) + VALUE obj; +{ + datum key; + struct dbmdata *dbmp; + DBM *dbm; + + rb_secure(4); + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + dbmp->di_size = -1; + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + if (dbm_delete(dbm, key)) { + Fail("dbm_delete failed"); + } + } + return obj; +} + +static VALUE +fdbm_store(obj, keystr, valstr) + VALUE obj, keystr, valstr; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + + if (valstr == Qnil) { + fdbm_delete(obj, keystr); + return Qnil; + } + + rb_secure(4); + keystr = obj_as_string(keystr); + + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + if (NIL_P(valstr)) return fdbm_delete(obj, keystr); + + valstr = obj_as_string(valstr); + val.dptr = RSTRING(valstr)->ptr; + val.dsize = RSTRING(valstr)->len; + + Data_Get_Struct(obj, struct dbmdata, dbmp); + dbmp->di_size = -1; + dbm = dbmp->di_dbm; + if (dbm_store(dbm, key, val, DBM_REPLACE)) { + dbm_clearerr(dbm); + if (errno == EPERM) rb_sys_fail(Qnil); + Fail("dbm_store failed"); + } + + return valstr; +} + +static VALUE +fdbm_length(obj) + VALUE obj; +{ + datum key; + struct dbmdata *dbmp; + DBM *dbm; + int i = 0; + + Data_Get_Struct(obj, struct dbmdata, dbmp); + if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size); + dbm = dbmp->di_dbm; + + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + i++; + } + dbmp->di_size = i; + + return INT2FIX(i); +} + +static VALUE +fdbm_empty_p(obj) + VALUE obj; +{ + datum key; + struct dbmdata *dbmp; + DBM *dbm; + int i = 0; + + Data_Get_Struct(obj, struct dbmdata, dbmp); + if (dbmp->di_size < 0) { + dbm = dbmp->di_dbm; + + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + i++; + } + } + else { + i = dbmp->di_size; + } + if (i == 0) return TRUE; + return FALSE; +} + +static VALUE +fdbm_each_value(obj) + VALUE obj; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + rb_yield(str_taint(str_new(val.dptr, val.dsize))); + } + return obj; +} + +static VALUE +fdbm_each_key(obj) + VALUE obj; +{ + datum key; + struct dbmdata *dbmp; + DBM *dbm; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + rb_yield(str_taint(str_new(key.dptr, key.dsize))); + } + return obj; +} + +static VALUE +fdbm_each_pair(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + struct dbmdata *dbmp; + VALUE keystr, valstr; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + keystr = str_taint(str_new(key.dptr, key.dsize)); + valstr = str_taint(str_new(val.dptr, val.dsize)); + rb_yield(assoc_new(keystr, valstr)); + } + + return obj; +} + +static VALUE +fdbm_keys(obj) + VALUE obj; +{ + datum key; + struct dbmdata *dbmp; + DBM *dbm; + VALUE ary; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + ary = ary_new(); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + ary_push(ary, str_taint(str_new(key.dptr, key.dsize))); + } + + return ary; +} + +static VALUE +fdbm_values(obj) + VALUE obj; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + VALUE ary; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + ary = ary_new(); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + ary_push(ary, str_taint(str_new(val.dptr, val.dsize))); + } + + return ary; +} + +static VALUE +fdbm_has_key(obj, keystr) + VALUE obj, keystr; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + val = dbm_fetch(dbm, key); + if (val.dptr) return TRUE; + return FALSE; +} + +static VALUE +fdbm_has_value(obj, valstr) + VALUE obj, valstr; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + + Check_Type(valstr, T_STRING); + val.dptr = RSTRING(valstr)->ptr; + val.dsize = RSTRING(valstr)->len; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + if (val.dsize == RSTRING(valstr)->len && + memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) + return TRUE; + } + return FALSE; +} + +static VALUE +fdbm_to_a(obj) + VALUE obj; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + VALUE ary; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + ary = ary_new(); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + ary_push(ary, assoc_new(str_taint(str_new(key.dptr, key.dsize)), + str_taint(str_new(val.dptr, val.dsize)))); + } + + return ary; +} + +Init_dbm() +{ + cDBM = rb_define_class("DBM", cObject); + rb_include_module(cDBM, mEnumerable); + + rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); + rb_define_method(cDBM, "close", fdbm_close, 0); + rb_define_method(cDBM, "[]", fdbm_fetch, 1); + rb_define_method(cDBM, "[]=", fdbm_store, 2); + rb_define_method(cDBM, "indexes", fdbm_indexes, -2); + rb_define_method(cDBM, "length", fdbm_length, 0); + rb_define_alias(cDBM, "size", "length"); + rb_define_method(cDBM, "empty?", fdbm_empty_p, 0); + rb_define_method(cDBM, "each", fdbm_each_pair, 0); + rb_define_method(cDBM, "each_value", fdbm_each_value, 0); + rb_define_method(cDBM, "each_key", fdbm_each_key, 0); + rb_define_method(cDBM, "each_pair", fdbm_each_pair, 0); + rb_define_method(cDBM, "keys", fdbm_keys, 0); + rb_define_method(cDBM, "values", fdbm_values, 0); + rb_define_method(cDBM, "shift", fdbm_shift, 1); + rb_define_method(cDBM, "delete", fdbm_delete, 1); + rb_define_method(cDBM, "delete_if", fdbm_delete_if, 0); + rb_define_method(cDBM, "clear", fdbm_clear, 0); + rb_define_method(cDBM, "include?", fdbm_has_key, 1); + rb_define_method(cDBM, "has_key?", fdbm_has_key, 1); + rb_define_method(cDBM, "has_value?", fdbm_has_value, 1); + rb_define_method(cDBM, "key?", fdbm_has_key, 1); + rb_define_method(cDBM, "value?", fdbm_has_value, 1); + + rb_define_method(cDBM, "to_a", fdbm_to_a, 0); +} diff --git a/ext/dbm/depend b/ext/dbm/depend new file mode 100644 index 0000000000..40139962a7 --- /dev/null +++ b/ext/dbm/depend @@ -0,0 +1 @@ +dbm.o: dbm.c ../../ruby.h ../../config.h ../../defines.h diff --git a/ext/dbm/extconf.rb b/ext/dbm/extconf.rb new file mode 100644 index 0000000000..4a5d41f275 --- /dev/null +++ b/ext/dbm/extconf.rb @@ -0,0 +1,5 @@ +$LDFLAGS = "-L/usr/local/lib" +have_library("gdbm", "dbm_open") or have_library("dbm", "dbm_open") +if have_func("dbm_open") + create_makefile("dbm") +end diff --git a/ext/etc/MANIFEST b/ext/etc/MANIFEST new file mode 100644 index 0000000000..a0f521b386 --- /dev/null +++ b/ext/etc/MANIFEST @@ -0,0 +1,5 @@ +MANIFEST +etc.c +etc.doc +depend +extconf.rb diff --git a/ext/etc/depend b/ext/etc/depend new file mode 100644 index 0000000000..5c95ef117a --- /dev/null +++ b/ext/etc/depend @@ -0,0 +1 @@ +etc.o : etc.c ../../ruby.h ../../config.h ../../defines.h diff --git a/ext/etc/etc.c b/ext/etc/etc.c new file mode 100644 index 0000000000..20cd9295ed --- /dev/null +++ b/ext/etc/etc.c @@ -0,0 +1,266 @@ +/************************************************ + + etc.c - + + $Author$ + $Date$ + created at: Tue Mar 22 18:39:19 JST 1994 + +************************************************/ + +#include "ruby.h" + +#ifdef HAVE_GETPWENT +#include +#endif + +#ifdef HAVE_GETGRENT +#include +#endif + +static VALUE sPasswd, sGroup; + +static VALUE +etc_getlogin(obj) + VALUE obj; +{ + char *getenv(); + char *login; + +#ifdef HAVE_GETLOGIN + char *getlogin(); + + login = getlogin(); + if (!login) login = getenv("USER"); +#else + login = getenv("USER"); +#endif + + if (login) + return str_new2(login); + return Qnil; +} + +#ifdef HAVE_GETPWENT +static VALUE +setup_passwd(pwd) + struct passwd *pwd; +{ + if (pwd == 0) rb_sys_fail("/etc/passwd"); + return struct_new(sPasswd, + str_new2(pwd->pw_name), + str_new2(pwd->pw_passwd), + INT2FIX(pwd->pw_uid), + INT2FIX(pwd->pw_gid), + str_new2(pwd->pw_gecos), + str_new2(pwd->pw_dir), + str_new2(pwd->pw_shell), +#ifdef PW_CHANGE + INT2FIX(pwd->pw_change), +#endif +#ifdef PW_QUOTA + INT2FIX(pwd->pw_quota), +#endif +#ifdef PW_AGE + INT2FIX(pwd->pw_age), +#endif +#ifdef PW_CLASS + str_new2(pwd->pw_class), +#endif +#ifdef PW_COMMENT + str_new2(pwd->pw_comment), +#endif +#ifdef PW_EXPIRE + INT2FIX(pwd->pw_expire), +#endif + 0 /*dummy*/ + ); +} +#endif + +static VALUE +etc_getpwuid(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ +#ifdef HAVE_GETPWENT + VALUE id; + int uid; + struct passwd *pwd; + + if (rb_scan_args(argc, argv, "01", &id) == 1) { + uid = NUM2INT(id); + } + else { + uid = getuid(); + } + pwd = getpwuid(uid); + if (pwd == 0) Fail("can't find user for %d", uid); + return setup_passwd(pwd); +#else + return Qnil; +#endif +} + +static VALUE +etc_getpwnam(obj, nam) + VALUE obj, nam; +{ +#ifdef HAVE_GETPWENT + struct passwd *pwd; + + Check_Type(nam, T_STRING); + pwd = getpwnam(RSTRING(nam)->ptr); + if (pwd == 0) Fail("can't find user for %s", RSTRING(nam)->ptr); + return setup_passwd(pwd); +#else + return Qnil; +#endif +} + +static VALUE +etc_passwd(obj) + VALUE obj; +{ +#if defined(HAVE_GETPWENT) && !defined(__CYGWIN32__) + struct passwd *pw; + + if (iterator_p()) { + setpwent(); + while (pw = getpwent()) { + rb_yield(setup_passwd(pw)); + } + endpwent(); + return obj; + } + pw = getpwent(); + if (pw == 0) Fail("can't fetch next -- /etc/passwd"); + return setup_passwd(pw); +#else + return Qnil; +#endif +} + +#ifdef HAVE_GETGRENT +static VALUE +setup_group(grp) + struct group *grp; +{ + VALUE mem; + char **tbl; + + mem = ary_new(); + tbl = grp->gr_mem; + while (*tbl) { + ary_push(mem, str_new2(*tbl)); + tbl++; + } + return struct_new(sGroup, + str_new2(grp->gr_name), + str_new2(grp->gr_passwd), + INT2FIX(grp->gr_gid), + mem); +} +#endif + +static VALUE +etc_getgrgid(obj, id) + VALUE obj, id; +{ +#ifdef HAVE_GETGRENT + int gid; + struct group *grp; + + gid = NUM2INT(id); + grp = getgrgid(gid); + if (grp == 0) Fail("can't find group for %d", gid); + return setup_group(grp); +#else + return Qnil; +#endif +} + +static VALUE +etc_getgrnam(obj, nam) + VALUE obj, nam; +{ +#ifdef HAVE_GETGRENT + struct group *grp; + + Check_Type(nam, T_STRING); + grp = getgrnam(RSTRING(nam)->ptr); + if (grp == 0) Fail("can't find group for %s", RSTRING(nam)->ptr); + return setup_group(grp); +#else + return Qnil; +#endif +} + +static VALUE +etc_group(obj) + VALUE obj; +{ +#ifdef HAVE_GETGRENT + struct group *grp; + + if (iterator_p()) { + setgrent(); + while (grp = getgrent()) { + rb_yield(setup_group(grp)); + } + endgrent(); + return obj; + } + return setup_group(getgrent()); +#else + return Qnil; +#endif +} + +static VALUE mEtc; + +void +Init_etc() +{ + mEtc = rb_define_module("Etc"); + + rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0); + + rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1); + rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1); + rb_define_module_function(mEtc, "passwd", etc_passwd, 0); + + rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, 1); + rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1); + rb_define_module_function(mEtc, "group", etc_group, 0); + + sPasswd = struct_define("Passwd", + "name", "passwd", "uid", "gid", + "gecos", "dir", "shell", +#ifdef PW_CHANGE + "change", +#endif +#ifdef PW_QUOTA + "quota", +#endif +#ifdef PW_AGE + "age", +#endif +#ifdef PW_CLASS + "class", +#endif +#ifdef PW_COMMENT + "comment", +#endif +#ifdef PW_EXPIRE + "expire", +#endif + 0); + rb_global_variable(&sPasswd); + +#ifdef HAVE_GETGRENT + sGroup = struct_define("Group", "name", "passwd", "gid", "mem", 0); + rb_global_variable(&sGroup); +#endif +} diff --git a/ext/etc/etc.doc b/ext/etc/etc.doc new file mode 100644 index 0000000000..2af895c9de --- /dev/null +++ b/ext/etc/etc.doc @@ -0,0 +1,73 @@ +.\" etc.doc - -*- Indented-Text -*- created at: Fri Jul 14 00:47:15 JST 1995 + +** Etc(モジュール) + +/etcディレクトリ以下の情報を得るためのモジュール.クラスにインクルード +して使うこともできる. + +Methods: +Single Methods: + + getlogin + + 自分のlogin名を返す.これが失敗した場合はgetpwuid()を用いると + 良い. + + getpwnam(name) + + /etc/passwdファイル(あるいはDBMファイルやNISデータベース)を検 + 索し,nameの名前を持つpasswdエントリを返す.戻り値はpasswd構造 + 体で以下のメンバを持つ. + + struct passwd + name # ユーザ名(文字列) + passwd # パスワード(文字列) + uid # ユーザID(整数) + gid # グループID(整数) + gecos # gecosフィールド(文字列) + dir # ホームディレクトリ(文字列) + shell # ログインシェル(文字列) + # 以降のメンバはシステムによっては提供されない. + change # パスワード変更時間(整数) + quota # クォータ(整数) + age # エージ(整数) + class # ユーザアクセスクラス(文字列) + comment # コメント(文字列) + expire # アカウント有効期限(整数) + end + + 詳細はgetpwnam(3)を参照のこと. + + getpwuid([uid]) + + uidをユーザIDとするpasswdエントリを返す.戻り値はgetpwnam()と + 同様である.引数を省略した場合にはgetuid()の値を用いる.詳細は + getpwuid(3)を参照のこと. + + getgrgid(gid) + + /etc/groupファイル(あるいは…getpwnam参照)を検索し,gidをグルー + プIDとするグループエントリを返す.戻り値はgroup構造体で以下の + メンバを持つ. + + struct group + name # グループ名(文字列) + passwd # グループのパスワード(文字列) + gid # グループID(整数) + mem # グループメンバ名の配列 + end + + 詳細はgetgrgid(3)を参照のこと. + + getgrnam(name) + + nameという名前のグループエントリを返す.戻り値はgetgrgid()と同 + 様である.詳細はgetgrnam(3)を参照. + + group + + 全てのグループエントリを順にアクセスするためのイテレータ. + + passwd + + 全てのpasswdエントリを順にアクセスするためのイテレータ. diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb new file mode 100644 index 0000000000..884de93ec8 --- /dev/null +++ b/ext/etc/extconf.rb @@ -0,0 +1,7 @@ +have_library("sun", "getpwnam") # NIS (== YP) interface for IRIX 4 +a = have_func("getlogin") +b = have_func("getpwent") +c = have_func("getgrent") +if a or b or c + create_makefile("etc") +end diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in new file mode 100644 index 0000000000..78fe3070a2 --- /dev/null +++ b/ext/extmk.rb.in @@ -0,0 +1,468 @@ +#! /usr/local/bin/ruby + +if ARGV[0] == 'static' + $force_static = TRUE + ARGV.shift +elsif ARGV[0] == 'install' + $install = TRUE + ARGV.shift +elsif ARGV[0] == 'clean' + $clean = TRUE + ARGV.shift +end + +$extlist = [] + +$cache_mod = FALSE; +$lib_cache = {} +$func_cache = {} +$hdr_cache = {} +$topdir = "@top_srcdir@" +if $topdir !~ "^/" + # get absolute path + save = Dir.pwd + Dir.chdir ".." + $topdir = Dir.pwd + Dir.chdir save +end + +if File.exist?("config.cache") then + f = open("config.cache", "r") + while f.gets + case $_ + when /^lib: ([\w_]+) (yes|no)/ + $lib_cache[$1] = $2 + when /^func: ([\w_]+) (yes|no)/ + $func_cache[$1] = $2 + when /^hdr: (.+) (yes|no)/ + $hdr_cache[$1] = $2 + end + end + f.close +end + +def older(file1, file2) + if !File.exist?(file1) then + return TRUE + end + if !File.exist?(file2) then + return FALSE + end + if File.mtime(file1) < File.mtime(file2) + return TRUE + end + return FALSE +end + +if PLATFORM == "m68k-human" +CFLAGS = "@CFLAGS@".gsub(/-c..-stack=[0-9]+ */, '') +LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c @LIBS@ %s > nul 2>&1" +CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > nul 2>&1" +else +CFLAGS = "@CFLAGS@" +LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c %s > /dev/null 2>&1" +CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > /dev/null 2>&1" +end + +def try_link(libs) + system(format(LINK, $CFLAGS, $LDFLAGS, libs)) +end + +def try_cpp + system(format(CPP, $CFLAGS)) +end + +def have_library(lib, func) + if $lib_cache[lib] + if $lib_cache[lib] == "yes" + if $libs + $libs = "-l" + lib + " " + $libs + else + $libs = "-l" + lib + end + return TRUE + else + return FALSE + end + end + + cfile = open("conftest.c", "w") + cfile.printf "\ +int main() { return 0; } +int t() { %s(); return 0; } +", func + cfile.close + + begin + if $libs + libs = "-l" + lib + " " + $libs + else + libs = "-l" + lib + end + unless try_link(libs) + $lib_cache[lib] = 'no' + $cache_mod = TRUE + return FALSE + end + ensure + system "rm -f conftest*" + end + + $libs = libs + $lib_cache[lib] = 'yes' + $cache_mod = TRUE + return TRUE +end + +def have_func(func) + if $func_cache[func] + if $func_cache[func] == "yes" + $defs.push(format("-DHAVE_%s", func.upcase)) + return TRUE + else + return FALSE + end + end + + cfile = open("conftest.c", "w") + cfile.printf "\ +char %s(); +int main() { return 0; } +int t() { %s(); return 0; } +", func, func + cfile.close + + libs = $libs + libs = "" if libs == nil + + begin + unless try_link(libs) + $func_cache[func] = 'no' + $cache_mod = TRUE + return FALSE + end + ensure + system "rm -f conftest*" + end + $defs.push(format("-DHAVE_%s", func.upcase)) + $func_cache[func] = 'yes' + $cache_mod = TRUE + return TRUE +end + +def have_header(header) + if $hdr_cache[header] + if $hdr_cache[header] == "yes" + header.tr!("a-z./\055", "A-Z___") + $defs.push(format("-DHAVE_%s", header)) + return TRUE + else + return FALSE + end + end + + cfile = open("conftest.c", "w") + cfile.printf "\ +#include <%s> +", header + cfile.close + + begin + unless try_cpp + $hdr_cache[header] = 'no' + $cache_mod = TRUE + return FALSE + end + ensure + system "rm -f conftest*" + end + $hdr_cache[header] = 'yes' + header.tr!("a-z./\055", "A-Z___") + $defs.push(format("-DHAVE_%s", header)) + $cache_mod = TRUE + return TRUE +end + +def create_header() + if $defs.length > 0 + hfile = open("extconf.h", "w") + for line in $defs + line =~ /^-D(.*)/ + hfile.printf "#define %s 1\n", $1 + end + hfile.close + end +end + +def create_makefile(target) + + if $libs and "@DLEXT@" == "o" + libs = $libs.split + for lib in libs + lib.sub!(/-l(.*)/, '"lib\1.a"') + end + $defs.push(format("-DEXTLIB='%s'", libs.join(","))) + end + $libs = "" unless $libs + + $srcdir = $topdir + "/ext/" + target + mfile = open("Makefile", "w") + mfile.printf "\ +SHELL = /bin/sh + +#### Start of system configuration section. #### + +srcdir = #{$srcdir} +VPATH = #{$srcdir} + +CC = @CC@ + +CFLAGS = %s -I#{$topdir} %s #$CFLAGS %s +DLDFLAGS = @DLDFLAGS@ #$LDFLAGS +LDSHARED = @LDSHARED@ +", if $static then "" else "@CCDLFLAGS@" end, CFLAGS, $defs.join(" ") + + mfile.printf "\ + +program_transform_name = -e @program_transform_name@ +RUBY_INSTALL_NAME = `t='$(program_transform_name)'; echo ruby | sed $$t` + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libdir = @libdir@/$(RUBY_INSTALL_NAME)/@arch@ +@SET_MAKE@ + +#### End of system configuration section. #### +" + mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs + mfile.printf "LIBS = %s\n", $libs + mfile.printf "OBJS = " + if !$objs then + $objs = Dir["#{$topdir}/ext/#{target}/*.c"] + for f in $objs + f.sub!(/\.c$/, ".o") + end + end + mfile.printf $objs.join(" ") + mfile.printf "\n" + + dots = if "@INSTALL@" =~ /^\// then "" else "#{$topdir}/ext/" end + mfile.printf "\ +TARGET = %s.%s + +INSTALL = %s@INSTALL@ + +binsuffix = @binsuffix@ + +all: $(TARGET) + +clean:; @rm -f *.o *.so *.sl + @rm -f Makefile extconf.h conftest.* + @rm -f core ruby$(binsuffix) *~ + +realclean: clean +", target, + if $static then "o" else "@DLEXT@" end, dots + + if !$static + mfile.printf "\ + +install: + @test -d $(libdir) || mkdir $(libdir) + $(INSTALL) $(TARGET) $(libdir)/$(TARGET) +" + else + mfile.printf "\ + +install:; +" + end + + if !$static && "@DLEXT@" != "o" + mfile.printf "\ +$(TARGET): $(OBJS) + $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS) +" + elsif not File.exist?(target + ".c") + if PLATFORM == "m68k-human" + mfile.printf "\ +$(TARGET): $(OBJS) + ar cru $(TARGET) $(OBJS) +" + elsif PLATFORM =~ "-nextstep" + mfile.printf "\ +$(TARGET): $(OBJS) + cc -r $(CFLAGS) -o $(TARGET) $(OBJS) +" + elsif $static + mfile.printf "\ +$(TARGET): $(OBJS) + ld -r -o $(TARGET) $(OBJS) +" + else + mfile.printf "\ +$(TARGET): $(OBJS) + ld $(DLDFLAGS) -r -o $(TARGET) $(OBJS) +" + end + end + + if File.exist?("depend") + dfile = open("depend", "r") + mfile.printf "###\n" + while line = dfile.gets() + mfile.printf "%s", line + end + dfile.close + end + mfile.close + if $static + $extlist.push [$static,target] + end +end + +def extmake(target) + if $force_static or $static_ext[target] + $static = target + else + $static = FALSE + end + + return if $nodynamic and not $static + + $local_libs = nil + $libs = nil + $objs = nil + $CFLAGS = nil + $LDFLAGS = nil + + begin + system "mkdir " + target unless File.directory?(target) + Dir.chdir target + if $static_ext.size > 0 || + !File.exist?("./Makefile") || + older("./Makefile", "#{$topdir}/ext/@setup@") || + older("./Makefile", "../extmk.rb") || + older("./Makefile", "./extconf.rb") + then + $defs = [] + if File.exist?("extconf.rb") + load "extconf.rb" + else + create_makefile(target); + end + end + if File.exist?("./Makefile") + if $install + system "make install" + elsif $clean + system "make clean" + else + system "make all" + end + end + if $static + $extlibs += " " + $LDFLAGS if $LDFLAGS + $extlibs += " " + $local_libs if $local_libs + $extlibs += " " + $libs if $libs + end + ensure + Dir.chdir ".." + end +end + +# get static-link modules +$static_ext = {} +if File.file? "#{$topdir}/ext/@setup@" + f = open("#{$topdir}/ext/@setup@") + while f.gets() + $_.chop! + sub!(/#.*$/, '') + next if /^\s*$/ + if /^option +nodynamic/ + $nodynamic = TRUE + next + end + $static_ext[$_.split[0]] = TRUE + end + f.close +end + +for d in Dir["#{$topdir}/ext/*"] + File.directory?(d) || next + File.file?(d + "/MANIFEST") || next + + d = File.basename(d) + if $install + print "installing ", d, "\n" + elsif $clean + print "cleaning ", d, "\n" + else + print "compiling ", d, "\n" + end + extmake(d) +end + +if $cache_mod + f = open("config.cache", "w") + for k,v in $lib_cache + f.printf "lib: %s %s\n", k, v + end + for k,v in $func_cache + f.printf "func: %s %s\n", k, v + end + for k,v in $hdr_cache + f.printf "hdr: %s %s\n", k, v + end + f.close +end + +exit if $install or $clean +if $extlist.size > 0 + for s,t in $extlist + f = format("%s/%s.o", s, t) + if File.exist?(f) + $extinit += format("\ +\tInit_%s();\n\ +\trb_provide(\"%s.o\");\n\ +", t, t) + $extobjs += "ext/" + $extobjs += f + $extobjs += " " + else + FALSE + end + end + + if older("extinit.c", "#{$topdir}/ext/@setup@") + f = open("extinit.c", "w") + f.printf "void Init_ext() {\n" + f.printf $extinit + f.printf "}\n" + f.close + end + if older("extinit.o", "extinit.c") + cmd = "@CC@ " + CFLAGS + " -c extinit.c" + print cmd, "\n" + system cmd or exit 1 + end + + Dir.chdir ".." + + if older("ruby@binsuffix@", "#{$topdir}/ext/@setup@") or older("ruby@binsuffix@", "miniruby@binsuffix@") + `rm -f ruby@binsuffix@` + end + + $extobjs = "ext/extinit.o " + $extobjs + system format('make ruby@binsuffix@ EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs) +else + Dir.chdir ".." + if older("ruby@binsuffix@", "miniruby@binsuffix@") + `rm -f ruby@binsuffix@` + `cp miniruby@binsuffix@ ruby@binsuffix@` + end +end + +#Local variables: +# mode: ruby +#end: diff --git a/ext/extmk.rb.nt b/ext/extmk.rb.nt new file mode 100644 index 0000000000..04b9e4071d --- /dev/null +++ b/ext/extmk.rb.nt @@ -0,0 +1,480 @@ +#! /usr/local/bin/ruby + +if ARGV[0] == 'static' + $force_static = TRUE + ARGV.shift +elsif ARGV[0] == 'install' + $install = TRUE + ARGV.shift +elsif ARGV[0] == 'clean' + $clean = TRUE + ARGV.shift +end + +$extlist = [] + +$cache_mod = FALSE; +$lib_cache = {} +$func_cache = {} +$hdr_cache = {} + +$dllopt = '-MD' + +if File.exist?("config.cache") then + f = open("config.cache", "r") + while f.gets + case $_ + when /^lib: ([\w_]+) (yes|no)/ + $lib_cache[$1] = $2 + when /^func: ([\w_]+) (yes|no)/ + $func_cache[$1] = $2 + when /^hdr: (.+) (yes|no)/ + $hdr_cache[$1] = $2 + end + end + f.close +end + +def older(file1, file2) + if !File.exist?(file1) then + return TRUE + end + if !File.exist?(file2) then + return FALSE + end + if File.mtime(file1) < File.mtime(file2) + return TRUE + end + return FALSE +end + +LINK = "cl -o conftest -I../.. -Zi -O -I. %s %s conftest.c %s > nul" +CPP = "cl -E -I../.. -I../../missing -I. -Zi -O %s conftest.c > nul" + +def try_link(libs) + system(format(LINK, $CFLAGS, $LDFLAGS, libs)) +end + +def try_cpp + system(format(CPP, $CFLAGS)) +end + +def have_library(lib, func) + if $lib_cache[lib] + if $lib_cache[lib] == "yes" + if $libs + $libs = "-l" + lib + " " + $libs + else + $libs = "-l" + lib + end + return TRUE + else + return FALSE + end + end + + cfile = open("conftest.c", "w") + cfile.printf "\ +int main() { return 0; } +int t() { %s(); return 0; } +", func + cfile.close + + begin + if $libs + libs = lib + ".lib " + $libs + else + libs = lib + ".lib" + end + unless try_link(libs) + $lib_cache[lib] = 'no' + $cache_mod = TRUE + return FALSE + end + ensure + system "rm -f conftest*" + end + + $libs = libs + $lib_cache[lib] = 'yes' + $cache_mod = TRUE + return TRUE +end + +def have_func(func) + if $func_cache[func] + if $func_cache[func] == "yes" + $defs.push(format("-DHAVE_%s", func.upcase)) + return TRUE + else + return FALSE + end + end + + cfile = open("conftest.c", "w") + cfile.printf "\ +char %s(); +int main() { return 0; } +int t() { %s(); return 0; } +", func, func + cfile.close + + libs = $libs + libs = "" if libs == nil + + begin + unless try_link(libs) + $func_cache[func] = 'no' + $cache_mod = TRUE + return FALSE + end + ensure + system "rm -f conftest*" + end + $defs.push(format("-DHAVE_%s", func.upcase)) + $func_cache[func] = 'yes' + $cache_mod = TRUE + return TRUE +end + +def have_header(header) + if $hdr_cache[header] + if $hdr_cache[header] == "yes" + header.tr!("a-z./\055", "A-Z___") + $defs.push(format("-DHAVE_%s", header)) + return TRUE + else + return FALSE + end + end + + cfile = open("conftest.c", "w") + cfile.printf "\ +#include <%s> +", header + cfile.close + + begin + unless try_cpp + $hdr_cache[header] = 'no' + $cache_mod = TRUE + return FALSE + end + ensure + system "rm -f conftest*" + end + $hdr_cache[header] = 'yes' + header.tr!("a-z./\055", "A-Z___") + $defs.push(format("-DHAVE_%s", header)) + $cache_mod = TRUE + return TRUE +end + +def create_header() + if $defs.length > 0 + hfile = open("extconf.h", "w") + for line in $defs + line =~ /^-D(.*)/ + hfile.printf "#define %s 1\n", $1 + end + hfile.close + end +end + +def create_makefile(target) + + if $libs and "obj" == "obj" + libs = $libs.split + for lib in libs + lib.sub!(/(.*)/, '"lib\1.lib"') + end + $defs.push(format("-DEXTLIB='%s'", libs.join(","))) + end + $libs = "" unless $libs + + mfile = open("Makefile", "w") + mfile.printf "\ +SHELL = $(COMPSEC) + +#### Start of system configuration section. #### + +srcdir = . +VPATH = . + +CC = cl + +CFLAGS = %s -I../.. -I../../missing -I. -O -DNT %s #$CFLAGS %s + +RUBYLIB = ../../ruby.lib +DLDFLAGS = /DLL +LDSHARED = +", if $static then "" else "-fpic" end, $dllopt, $defs.join(" ") + + if $force_static + print "static\n" + else + print "non static\n" + end + + mfile.printf "\ + +libdir = /usr/local/lib/ruby/i386-mswin32 + + +#### End of system configuration section. #### +" + mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs + mfile.printf "LIBS = %s\n", $libs + mfile.printf "OBJS = " + if !$objs then + $objs = Dir["*.c"] + for f in $objs + f.sub!(/\.c$/, ".obj") + end + end + mfile.printf $objs.join(" ") + mfile.printf "\n" + + dots = if "ginstall -c" =~ /^\// then "" else "../" end + mfile.printf "\ +TARGET = %s.%s + +INSTALL = %sginstall -c + +DEFFILE = %s.def + +all: $(TARGET) + +clean:; @rm -f *.obj *.lib *.exp *.pdb *.bak + @rm -f Makefile extconf.h conftest.* + +realclean: clean +", target, + if $force_static then "lib" else "dll" end, dots, target + + if !$static + mfile.printf "\ + +install: $(libdir)/$(TARGET) + +$(libdir)/$(TARGET): $(TARGET) + @test -d $(libdir) || mkdir $(libdir) + $(INSTALL) $(TARGET) $(libdir)/$(TARGET) +" + else + mfile.printf "\ + +install:; +" + end + + if $force_static + mfile.printf "\ +$(TARGET): $(OBJS) + lib /OUT:$(TARGET) $(OBJS) +" + else + mfile.printf "\ +$(DEFFILE): + echo $(DEFFILE) + +$(TARGET): $(OBJS) $(DEFFILE) + cl -DLL -o$(TARGET) $(OBJS) $(RUBYLIB) -link /DEF:$(DEFFILE) +" + end + + if File.exist?("depend") + dfile = open("depend", "r") + mfile.printf "###\n" + while line = dfile.gets() + mfile.printf "%s", line + end + dfile.close + end + mfile.close + if $static + printf format("push %s,%s\n", $static, target); ##debug print## + $extlist.push [$static,target] + end +end + +def extmake(target) + if $force_static or $static_ext[target] + $static = target + else + $static = FALSE + end + + return if $nodynamic and not $static + + $local_libs = nil + $libs = nil + $objs = nil + $CFLAGS = nil + $LDFLAGS = nil + + begin + Dir.chdir target + if $static_ext.size > 0 || + !File.exist?("./Makefile") || + older("./Makefile", "../Setup") || + older("./Makefile", "../extmk.rb") || + older("./Makefile", "./extconf.rb") + then + $defs = [] + if File.exist?("extconf.rb") + load "extconf.rb" + else + create_makefile(target); + end + end + if File.exist?("./Makefile") + if $install + system "nmake install" + if File.directory? "./lib" + for i in Dir["./lib/*.rb"] + system "ginstall -c #{i} /usr/local/lib/ruby/i386-mswin32" + end + end + elsif $clean + system "nmake clean" + else + system "nmake all" + end + end + if $static + $extlibs += " " + $LDFLAGS if $LDFLAGS + $extlibs += " " + $local_libs if $local_libs + $extlibs += " " + $libs if $libs + end + ensure + Dir.chdir ".." + end +end + +# get static-link modules +$static_ext = {} +if File.file? "./Setup" + f = open("./Setup") + while f.gets() + $_.chop! + sub!(/#.*$/, '') + next if /^\s*$/ + print $_, "\n" + if /^option +nodynamic/ + $nodynamic = TRUE + next + end + $static_ext[$_.split[0]] = TRUE + end + f.close +end + +for d in Dir["*"] + File.directory?(d) || next + File.file?(d + "/MANIFEST") || next + + d = $1 if d =~ /\/([\/]*)$/ + if $install + print "installing ", d, "\n" + elsif $clean + print "cleaning ", d, "\n" + else + print "compiling ", d, "\n" + end + extmake(d) +end + +if $cache_mod + f = open("config.cache", "w") + for k,v in $lib_cache + f.printf "lib: %s %s\n", k, v + end + for k,v in $func_cache + f.printf "func: %s %s\n", k, v + end + for k,v in $hdr_cache + f.printf "hdr: %s %s\n", k, v + end + f.close +end + +exit if $install or $clean +if $extlist.size > 0 + #for s,t in $extlist + for s,t in $static_ext + #f = format("%s/%s.obj", s, t) + #f = format("%s/%s.obj", s, s) + l = format("%s/%s.lib", s, s) + #print format("%s/%s.obj\n", s, s) ##debug print## + if File.exist?(l) + $extinit += format("\ +\tInit_%s();\n\ +\trb_provide(\"%s.o\");\n\ +", s, s) + $extobjs += "ext/" + #$extobjs += f # *.obj + $extobjs += l # *.lib + $extobjs += " " + else + FALSE + end + end + + if older("extinit.c", "Setup") + f = open("extinit.c", "w") + f.printf "void Init_ext() {\n" + f.printf $extinit + f.printf "}\n" + f.close + end + if older("extinit.obj", "extinit.c") + cmd = "cl -Zi -O -I. -c extinit.c" + print cmd, "\n" + system cmd or exit 1 + end + + Dir.chdir ".." + + if older("ruby.exe", "ext/Setup") or older("ruby.exe", "miniruby.exe") + `rm -f ruby.exe` + end + + $extobjs = "ext/extinit.obj " + $extobjs + $extlibs = "" + system format('nmake ruby.exe EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs) +else + Dir.chdir ".." + if older("ruby.exe", "miniruby.exe") + `rm -f ruby.exe` + `cp miniruby.exe ruby.exe` + end +end + +#template of .def file. +#LIBRARY kconv.dll +#CODE LOADONCALL +#DATA LOADONCALL +#DESCRIPTION 'win32 kconv.dll' +#EXPORTS +# +# Init_kconv +def makedef(basename) + defname = sprintf("%s.def", basename) + f = open(defname, "w") + f.printf "\ +LIBRARY %s.dll +CODE LOADONCALL +DATA LOADONCALL +DESCRIPTION 'win32 %s.dll' +EXPORTS + + Init_%s +", basename, basename + f.close + +end + +#Local variables: +# mode: ruby +#end: diff --git a/ext/fcntl/MANIFEST b/ext/fcntl/MANIFEST new file mode 100644 index 0000000000..aef7ad4ca0 --- /dev/null +++ b/ext/fcntl/MANIFEST @@ -0,0 +1,3 @@ +MANIFEST +depend +fcntl.c diff --git a/ext/fcntl/depend b/ext/fcntl/depend new file mode 100644 index 0000000000..3c7ef8485e --- /dev/null +++ b/ext/fcntl/depend @@ -0,0 +1 @@ +fcntl.o: fcntl.c ../../ruby.h ../../config.h ../../defines.h diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c new file mode 100644 index 0000000000..17aacb13c3 --- /dev/null +++ b/ext/fcntl/fcntl.c @@ -0,0 +1,106 @@ +/************************************************ + + fcntl.c - + + $Author$ + created at: Mon Apr 7 18:53:05 JST 1997 + + Copyright (C) 1997 Yukihiro Matsumoto + +************************************************/ + +/************************************************ += NAME + +fcntl - load the C fcntl.h defines + += SYNOPSIS + + require "fcntl" + m = s.fcntl(Fcntl::F_GETFL, 0) + f.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK|m) + += DESCRIPTION + +This module is just a translation of the C file. + += NOTE + +Only #define symbols get translated; you must still correctly +pack up your own arguments to pass as args for locking functions, etc. + +************************************************/ + +#include "ruby.h" +#include + +Init_fcntl() +{ + VALUE mFcntl = rb_define_module("Fcntl"); +#ifdef F_DUPFD + rb_define_const(mFcntl, "F_DUPFD", INT2NUM(F_DUPFD)); +#endif +#ifdef F_GETFD + rb_define_const(mFcntl, "F_GETFD", INT2NUM(F_GETFD)); +#endif +#ifdef F_GETLK + rb_define_const(mFcntl, "F_GETLK", INT2NUM(F_GETLK)); +#endif +#ifdef F_SETFD + rb_define_const(mFcntl, "F_SETFD", INT2NUM(F_SETFD)); +#endif +#ifdef F_GETFL + rb_define_const(mFcntl, "F_GETFL", INT2NUM(F_GETFL)); +#endif +#ifdef F_SETFL + rb_define_const(mFcntl, "F_SETFL", INT2NUM(F_SETFL)); +#endif +#ifdef F_SETLK + rb_define_const(mFcntl, "F_SETLK", INT2NUM(F_SETLK)); +#endif +#ifdef F_SETLKW + rb_define_const(mFcntl, "F_SETLKW", INT2NUM(F_SETLKW)); +#endif +#ifdef FD_CLOEXEC + rb_define_const(mFcntl, "FD_CLOEXEC", INT2NUM(FD_CLOEXEC)); +#endif +#ifdef F_RDLCK + rb_define_const(mFcntl, "F_RDLCK", INT2NUM(F_RDLCK)); +#endif +#ifdef F_UNLCK + rb_define_const(mFcntl, "F_UNLCK", INT2NUM(F_UNLCK)); +#endif +#ifdef F_WRLCK + rb_define_const(mFcntl, "F_WRLCK", INT2NUM(F_WRLCK)); +#endif +#ifdef O_CREAT + rb_define_const(mFcntl, "O_CREAT", INT2NUM(O_CREAT)); +#endif +#ifdef O_EXCL + rb_define_const(mFcntl, "O_EXCL", INT2NUM(O_EXCL)); +#endif +#ifdef O_NOCTTY + rb_define_const(mFcntl, "O_NOCTTY", INT2NUM(O_NOCTTY)); +#endif +#ifdef O_TRUNC + rb_define_const(mFcntl, "O_TRUNC", INT2NUM(O_TRUNC)); +#endif +#ifdef O_APPEND + rb_define_const(mFcntl, "O_APPEND", INT2NUM(O_APPEND)); +#endif +#ifdef O_NONBLOCK + rb_define_const(mFcntl, "O_NONBLOCK", INT2NUM(O_NONBLOCK)); +#endif +#ifdef O_NDELAY + rb_define_const(mFcntl, "O_NDELAY", INT2NUM(O_NDELAY)); +#endif +#ifdef O_RDONLY + rb_define_const(mFcntl, "O_RDONLY", INT2NUM(O_RDONLY)); +#endif +#ifdef O_RDWR + rb_define_const(mFcntl, "O_RDWR", INT2NUM(O_RDWR)); +#endif +#ifdef O_WRONLY + rb_define_const(mFcntl, "O_WRONLY", INT2NUM(O_WRONLY)); +#endif +} diff --git a/ext/kconv/MANIFEST b/ext/kconv/MANIFEST new file mode 100644 index 0000000000..cb89e8239c --- /dev/null +++ b/ext/kconv/MANIFEST @@ -0,0 +1,3 @@ +MANIFEST +depend +kconv.c diff --git a/ext/kconv/depend b/ext/kconv/depend new file mode 100644 index 0000000000..e87b1fdea7 --- /dev/null +++ b/ext/kconv/depend @@ -0,0 +1 @@ +kconv.o: kconv.c ../../ruby.h ../../config.h ../../defines.h diff --git a/ext/kconv/kconv.c b/ext/kconv/kconv.c new file mode 100644 index 0000000000..3c59cb6acf --- /dev/null +++ b/ext/kconv/kconv.c @@ -0,0 +1,1881 @@ +/** Network Kanji Filter. (PDS Version) +************************************************************************ +** Copyright (C) 1987, Fujitsu LTD. (Itaru ICHIKAWA) +** 連絡先: (株)富士通研究所 ソフト3研 市川 至 +** (E-Mail Address: ichikawa@flab.fujitsu.co.jp) +** Copyright (C) 1996 +** 連絡先: 琉球大学情報工学科 河野 真治 mine/X0208 support +** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) +** 連絡先: COW for DOS & Win16 & Win32 & OS/2 +** (E-Mail Address: GHG00637@niftyserve.or.jp) +** 営利を目的としない限り、このソースのいかなる +** 複写,改変,修正も許諾します。その際には、この部分を残すこと。 +** このプログラムについては特に何の保証もしない、悪しからず。 +** Everyone is permitted to do anything on this program +** including copying, modifying, improving +** as long as you don't try to make money off it, +** or pretend that you wrote it. +** i.e., the above copyright notice has to appear in all copies. +** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. +***********************************************************************/ + +/*********************************************************************** +** 1996/03/10 modified for Kconv - by Ikuo Nakagawa +***********************************************************************/ +/*********************************************************************** +** 1996/12/18 modified for kconv(ruby) - by matz@ruby.club.or.jp +***********************************************************************/ + +static char *CopyRight = + "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),1996 S. Kono, COW"; +static char *Version = + "1.62"; +static char *Patchlevel = + "5/9612/Shinji Kono, COW matz"; + +#include "ruby.h" + +/* +** +** +** +** USAGE: nkf [flags] [file] +** +** Flags: +** b Output is bufferred (DEFAULT) +** u Output is unbufferred +** +** t no operation +** +** j Outout code is JIS 7 bit (DEFAULT SELECT) +** s Output code is MS Kanji (DEFAULT SELECT) +** e Output code is AT&T JIS (DEFAULT SELECT) +** l Output code is JIS 7bit and ISO8859-1 Latin-1 +** +** m MIME conversion for ISO-2022-JP +** i_ Output sequence to designate JIS-kanji (DEFAULT_J) +** o_ Output sequence to designate single-byte roman characters (DEFAULT_R) +** +** r {de/en}crypt ROT13/47 +** +** v display Version +** +** T Text mode output (for MS-DOS) +** +** x Do not convert X0201 kana into X0208 +** Z Convert X0208 alphabet to ASCII +** +** f60 fold option +** +** m MIME decode +** B try to fix broken JIS, missing Escape +** B[1-9] broken level +** +** O Output to 'nkf.out' file +** d Delete \r in line feed +** c Add \r in line feed +**/ +/******************************/ +/* デフォルトの出力コード選択 */ +/* Select DEFAULT_CODE */ +#define DEFAULT_CODE_JIS +/* #define DEFAULT_CODE_SJIS */ +/* #define DEFAULT_CODE_EUC */ +/******************************/ + +/* for Kconv: _AUTO, _EUC, _SJIS, _JIS */ +#define _AUTO 0 +#define _JIS 1 +#define _EUC 2 +#define _SJIS 3 + +#if (defined(__TURBOC__) || defined(LSI_C)) && !defined(MSDOS) +#define MSDOS +#endif + +#include + +#if defined(MSDOS) || defined(__OS2__) +#include +#include +#include +#endif + +#ifdef MSDOS +#ifdef LSI_C +#define setbinmode(fp) fsetbin(fp) +#else /* Microsoft C, Turbo C */ +#define setbinmode(fp) setmode(fileno(fp), O_BINARY) +#endif +#else /* UNIX,OS/2 */ +#define setbinmode(fp) +#endif + +#ifdef _IOFBF /* SysV and MSDOS */ +#define setvbuffer(fp, buf, size) setvbuf(fp, buf, _IOFBF, size) +#else /* BSD */ +#define setvbuffer(fp, buf, size) setbuffer(fp, buf, size) +#endif + +/*Borland C++ 4.5 EasyWin*/ +#if defined(__TURBOC__) && defined(_Windows) && !defined(__WIN32__) /*Easy Win */ +#define EASYWIN +#include +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +/* state of output_mode and input_mode */ + +#define ASCII 0 +#define X0208 1 +#define X0201 2 +#define NO_X0201 3 +#define JIS_INPUT 4 +#define SJIS_INPUT 5 +#define LATIN1_INPUT 6 +#define FIXED_MIME 7 +#define DOUBLE_SPACE -2 + +#define NL 0x0a +#define ESC 0x1b +#define SP 0x20 +#define AT 0x40 +#define SSP 0xa0 +#define DEL 0x7f +#define SI 0x0f +#define SO 0x0e +#define SSO 0x8e + +#define HOLD_SIZE 32 +#define IOBUF_SIZE 16384 + +#define DEFAULT_J 'B' +#define DEFAULT_R 'B' + +#define SJ0162 0x00e1 /* 01 - 62 ku offset */ +#define SJ6394 0x0161 /* 63 - 94 ku offset */ + + +/* MIME preprocessor */ + +#define _GETC() (*inptr ? (int)(*inptr++) : EOF) +#define _UNGETC(c) (*--inptr = (c)) +#define PUTCHAR(c) (outlen + 1 < outsiz ? \ + ((outptr[outlen++] = (c)), (outptr[outlen] = '\0')) : EOF) +#define GETC() ((!mime_mode)?_GETC():mime_getc()) +#define UNGETC(c) ((!mime_mode)?_UNGETC(c):mime_ungetc(c)) + +#ifdef EASYWIN /*Easy Win */ +extern POINT _BufferSize; +#endif + +/* buffers */ + +static unsigned char hold_buf[HOLD_SIZE*2]; +static int hold_count; +static unsigned char *inptr; +static char *outptr; +static int outsiz; +static int outlen; + +/* MIME preprocessor fifo */ + +#define MIME_BUF_SIZE (1024) /* 2^n ring buffer */ +#define MIME_BUF_MASK (MIME_BUF_SIZE-1) +#define Fifo(n) mime_buf[(n)&MIME_BUF_MASK] +static unsigned char mime_buf[MIME_BUF_SIZE]; +static unsigned int mime_top = 0; +static unsigned int mime_last = 0; /* decoded */ +static unsigned int mime_input = 0; /* undecoded */ + +/* flags */ +static int unbuf_f = FALSE; +static int estab_f = FALSE; +static int rot_f = FALSE; /* rot14/43 mode */ +static int input_f = FALSE; /* non fixed input code */ +static int alpha_f = FALSE; /* convert JIx0208 alphbet to ASCII */ +static int mime_f = FALSE; /* convert MIME B base64 or Q */ +static int mimebuf_f = FALSE; /* MIME buffered input */ +static int broken_f = FALSE; /* convert ESC-less broken JIS */ +static int iso8859_f = FALSE; /* ISO8859 through */ +#if defined(MSDOS) || defined(__OS2__) +static int x0201_f = TRUE; /* Assume JISX0201 kana */ +#else +static int x0201_f = NO_X0201; /* Assume NO JISX0201 */ +#endif + +/* X0208 -> ASCII converter */ + +static int c1_return; + +/* fold parameter */ +static int line = 0; /* chars in line */ +static int prev = 0; +static int fold_f = FALSE; +static int fold_len = 0; + +/* options */ +static char kanji_intro = DEFAULT_J, + ascii_intro = DEFAULT_R; + +/* Folding */ + +#define FOLD_MARGIN 10 +#define DEFAULT_FOLD 60 + +/* Global states */ +static int output_mode = ASCII, /* output kanji mode */ + input_mode = ASCII, /* input kanji mode */ + shift_mode = FALSE; /* TRUE shift out, or X0201 */ +static int mime_mode = FALSE; /* MIME mode B base64, Q hex */ + +/* X0208 -> ASCII translation table */ +/* X0201 / X0208 conversion tables */ + +/* X0201 kana conversion table */ +/* 90-9F A0-DF */ +static unsigned char cv[]= { +0x21,0x21,0x21,0x23,0x21,0x56,0x21,0x57, +0x21,0x22,0x21,0x26,0x25,0x72,0x25,0x21, +0x25,0x23,0x25,0x25,0x25,0x27,0x25,0x29, +0x25,0x63,0x25,0x65,0x25,0x67,0x25,0x43, +0x21,0x3c,0x25,0x22,0x25,0x24,0x25,0x26, +0x25,0x28,0x25,0x2a,0x25,0x2b,0x25,0x2d, +0x25,0x2f,0x25,0x31,0x25,0x33,0x25,0x35, +0x25,0x37,0x25,0x39,0x25,0x3b,0x25,0x3d, +0x25,0x3f,0x25,0x41,0x25,0x44,0x25,0x46, +0x25,0x48,0x25,0x4a,0x25,0x4b,0x25,0x4c, +0x25,0x4d,0x25,0x4e,0x25,0x4f,0x25,0x52, +0x25,0x55,0x25,0x58,0x25,0x5b,0x25,0x5e, +0x25,0x5f,0x25,0x60,0x25,0x61,0x25,0x62, +0x25,0x64,0x25,0x66,0x25,0x68,0x25,0x69, +0x25,0x6a,0x25,0x6b,0x25,0x6c,0x25,0x6d, +0x25,0x6f,0x25,0x73,0x21,0x2b,0x21,0x2c, +0x00,0x00}; + + +/* X0201 kana conversion table for daguten */ +/* 90-9F A0-DF */ +static unsigned char dv[]= { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x25,0x2c,0x25,0x2e, +0x25,0x30,0x25,0x32,0x25,0x34,0x25,0x36, +0x25,0x38,0x25,0x3a,0x25,0x3c,0x25,0x3e, +0x25,0x40,0x25,0x42,0x25,0x45,0x25,0x47, +0x25,0x49,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x25,0x50,0x25,0x53, +0x25,0x56,0x25,0x59,0x25,0x5c,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00}; + +/* X0201 kana conversion table for han-daguten */ +/* 90-9F A0-DF */ +static unsigned char ev[]= { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x25,0x51,0x25,0x54, +0x25,0x57,0x25,0x5a,0x25,0x5d,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00}; + + +/* X0208 kigou conversion table */ +/* 0x8140 - 0x819e */ +static unsigned char fv[] = { +0x00,0x00,0x00,0x00,0x2c,0x2e,0x00,0x3a, +0x3b,0x3f,0x21,0x00,0x00,0x27,0x60,0x00, +0x5e,0x00,0x5f,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x2f, +0x5c,0x00,0x00,0x7c,0x00,0x00,0x60,0x27, +0x22,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d, +0x7b,0x7d,0x3c,0x3e,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00, +0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +} ; + + +/* This converts =?ISO-2022-JP?B?HOGE HOGE?= */ + +static unsigned char *mime_pattern[] = { + (unsigned char *)"\075?ISO-8859-1?Q?", + (unsigned char *)"\075?ISO-2022-JP?B?", + (unsigned char *)"\075?ISO-2022-JP?Q?", + NULL +}; + +static int mime_encode[] = { + 'Q', 'B', 'Q', + 0 +}; + +static int add_cr = FALSE; +static int del_cr = FALSE; + +static void (*iconv) _((register int c2,register int c1)); /* s_iconv or oconv */ +static void (*oconv) _((register int c2,register int c1)); /* [ejs]_oconv */ +static int do_kconv _((char *i, char *o, int siz, int out_code, int in_code)); +static void h_conv _((register int c2,register int c1)); +static int push_hold_buf _((int c2,int c1)); +static void s_iconv _((register int c2,register int c1)); +static void e_oconv _((register int c2,register int c1)); +static void s_oconv _((register int c2,register int c1)); +static void j_oconv _((register int c2,register int c1)); +static int fold _((register int c2,register int c1)); +static int pre_convert _((register int c1,register int c2)); +static int mime_begin _((void)); +static int mime_getc _((void)); +static int mime_ungetc _((unsigned int c)); +static int mime_integrity _((unsigned char *p)); +static int base64decode _((int c)); + +#ifdef notdef +main (argc, argv) + int argc; + char **argv; +{ + register FILE *fin; + register char *cp; + +#ifdef EASYWIN /*Easy Win */ + _BufferSize.y = 400;/*Set Scroll Buffer Size*/ +#endif +#ifdef DEFAULT_CODE_JIS + oconv = j_oconv; /* DEFAULT Code is JIS */ +#endif +#ifdef DEFAULT_CODE_SJIS + oconv = s_oconv; /* DEFAULT Code is S-JIS */ +#endif +#ifdef DEFAULT_CODE_EUC + oconv = e_oconv; /* DEFAULT Code is EUC */ +#endif + + for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) { + cp = *argv; + while (*cp) { + switch (*cp++) { + case 'b': /* buffered mode */ + unbuf_f = FALSE; + continue; + case 'u': /* non bufferd mode */ + unbuf_f = TRUE; + continue; + case 'j': /* JIS output */ + case 'n': + oconv = j_oconv; + continue; + case 'e': /* AT&T EUC output */ + oconv = e_oconv; + continue; + case 's': /* SJIS output */ + oconv = s_oconv; + continue; + case 'l': /* ISO8859 Latin-1 support, no conversion */ + iso8859_f = TRUE; /* Only compatible with ISO-2022-JP */ + input_f = LATIN1_INPUT; + continue; + case 'i': /* Kanji IN ESC-$-@/B */ + if(*cp=='@'||*cp=='B') + kanji_intro = *cp++; + continue; + case 'o': /* ASCII IN ESC-(-J/B */ + if(*cp=='J'||*cp=='B'||*cp=='H') + ascii_intro = *cp++; + continue; + case 'r': + rot_f = TRUE; + continue; +#if defined(MSDOS) || defined(__OS2__) + case 'T': + binmode_f = FALSE; + continue; +#endif + case 'v': + usage(); + exit(1); + break; + /* Input code assumption */ + case 'J': /* JIS input */ + case 'E': /* AT&T EUC input */ + input_f = JIS_INPUT; + continue; + case 'S': /* MS Kanji input */ + input_f = SJIS_INPUT; + if(x0201_f==NO_X0201) x0201_f=TRUE; + continue; + case 'Z': /* Convert X0208 alphabet to asii */ + /* bit:0 Convert X0208 + bit:1 Convert Kankaku to one space + bit:2 Convert Kankaku to two spaces + */ + if('9'>= *cp && *cp>='0') + alpha_f |= 1<<(*cp++ -'0'); + else + alpha_f |= TRUE; + continue; + case 'x': /* Convert X0201 kana to X0208 or X0201 Conversion */ + x0201_f = FALSE; /* No X0201->X0208 conversion */ + /* accept X0201 + ESC-(-I in JIS, EUC, MS Kanji + SI/SO in JIS, EUC, MS Kanji + SSO in EUC, JIS, not in MS Kanji + MS Kanji (0xa0-0xdf) + output X0201 + ESC-(-I in JIS (0x20-0x5f) + SSO in EUC (0xa0-0xdf) + 0xa0-0xd in MS Kanji (0xa0-0xdf) + */ + continue; + case 'X': /* Assume X0201 kana */ + /* Default value is NO_X0201 for EUC/MS-Kanji mix */ + x0201_f = TRUE; + continue; + case 'f': /* folding -f60 or -f */ + fold_f = TRUE; + fold_len = atoi(cp); + if(!(0= *cp && *cp>='0') + broken_f |= 1<<(*cp++ -'0'); + else + broken_f |= TRUE; + continue; + case 'O':/* for Output file */ + file_out = TRUE; + continue; + case 'c':/* add cr code */ + add_cr = TRUE; + continue; + case 'd':/* delete cr code */ + del_cr = TRUE; + continue; + default: + /* bogus option but ignored */ + continue; + } + } + } + + if(iso8859_f && (oconv != j_oconv || !x0201_f )) { + fprintf(stderr,"Mixed ISO8859/JISX0201/SJIS/EUC output is not allowed.\n"); + exit(1); + } + + if(binmode_f == TRUE) +#ifdef __OS2__ + if(freopen("","wb",stdout) == NULL) + return (-1); +#else + setbinmode(stdout); +#endif + + if(unbuf_f) + setbuf (stdout, (char *) NULL); + else + setvbuffer (stdout, stdobuf, IOBUF_SIZE); + + if(argc == 0) { + if(binmode_f == TRUE) +#ifdef __OS2__ + if(freopen("","rb",stdin) == NULL) return (-1); +#else + setbinmode(stdin); +#endif + setvbuffer (stdin, stdibuf, IOBUF_SIZE); + convert (stdin); + } else { + while (argc--) { + if((fin = fopen (*argv++, "r")) == NULL) { + perror (*--argv); + return (-1); + } else { +/* reopen file for stdout */ + if(file_out == TRUE){ + if(argc == 1 ) { + if(freopen(*argv++, "w", stdout) == NULL) { + perror (*--argv); + return (-1); + } + argc--; + } else { + if(freopen("nkf.out", "w", stdout) == NULL) { + perror (*--argv); + return (-1); + } + } + if(binmode_f == TRUE) { +#ifdef __OS2__ + if(freopen("","wb",stdout) == NULL) + return (-1); +#else + setbinmode(stdout); +#endif + } + } + if(binmode_f == TRUE) +#ifdef __OS2__ + if(freopen("","rb",fin) == NULL) + return (-1); +#else + setbinmode(fin); +#endif + setvbuffer (fin, stdibuf, IOBUF_SIZE); + convert (fin); + fclose (fin); + } + } + } +#ifdef EASYWIN /*Easy Win */ + if(file_out == FALSE) + scanf("%d",&end_check); + else + fclose(stdout); +#else /* for Other OS */ + if(file_out == TRUE) + fclose(stdout); +#endif + return (0); +} +#endif /* notdef */ + +static int +do_kconv(i, o, siz, out_code, in_code) + char *i; + char *o; + int siz, out_code, in_code; +{ + register int c1, + c2; + + c2 = 0; + + if (siz <= 0) { + return 0; + } + *o = '\0'; + + inptr = (unsigned char *)i; /* input buffer */ + outptr = o; /* output buffer */ + outsiz = siz; /* output buffer size */ + outlen = 0; /* current length of output string */ + x0201_f = FALSE; /* don't assume JISX0201 kana */ + rot_f = FALSE; /* rot14/43 mode */ + input_f = FALSE; /* non fixed input code */ + alpha_f = FALSE; /* convert JISX0208 alphbet to ASCII */ + mime_f = TRUE; /* convert MIME base64 */ + broken_f = FALSE; /* convert ESC-less broken JIS */ + + switch (out_code) { + case _SJIS: + oconv = s_oconv; + break; + case _EUC: + oconv = e_oconv; + break; + default: + oconv = j_oconv; + break; + } + + switch (in_code) { + case _SJIS: + input_f = SJIS_INPUT; + x0201_f = TRUE; + break; + case _EUC: + case _JIS: + input_f = JIS_INPUT; + break; + default: + input_f = FALSE; + break; + } + + if(input_f == JIS_INPUT || input_f == LATIN1_INPUT) { + estab_f = TRUE; iconv = oconv; + } else if(input_f == SJIS_INPUT) { + estab_f = TRUE; iconv = s_iconv; + } else { + estab_f = FALSE; iconv = oconv; + } + input_mode = ASCII; + output_mode = ASCII; + shift_mode = FALSE; + mime_mode = FALSE; + +#define NEXT continue /* no output, get next */ +#define SEND ; /* output c1 and c2, get next */ +#define LAST break /* end of loop, go closing */ + + while ((c1 = GETC()) != EOF) { + if(!c2 && !input_mode && c1 DEL) { + /* in case of 8th bit is on */ + if(!estab_f) { + /* in case of not established yet */ + if(c1 > SSP) { + /* It is still ambiguious */ + h_conv (c2, c1); + c2 = 0; + NEXT; + } else if(c1 < AT) { + /* ignore bogus code */ + c2 = 0; + NEXT; + } else { + /* established */ + /* it seems to be MS Kanji */ + estab_f = TRUE; + iconv = s_iconv; + SEND; + } + } else + /* in case of already established */ + if(c1 < AT) { + /* ignore bogus code */ + c2 = 0; + NEXT; + } else + SEND; + } else + /* 7 bit code */ + /* it might be kanji shitfted */ + if((c1 == DEL) || (c1 <= SP)) { + /* ignore bogus first code */ + c2 = 0; + NEXT; + } else + SEND; + } else { + /* first byte */ + if(c1 > DEL) { + /* 8 bit code */ + if(!estab_f && !iso8859_f) { + /* not established yet */ + if(c1 < SSP) { + /* it seems to be MS Kanji */ + estab_f = TRUE; + iconv = s_iconv; + } else if(c1 < 0xe0) { + /* it seems to be EUC */ + estab_f = TRUE; + iconv = oconv; + } else { + /* still ambiguious */ + } + c2 = c1; + NEXT; + } else { /* estab_f==TRUE */ + if(iso8859_f) { + SEND; + } else if(SSP<=c1 && c1<0xe0 && iconv == s_iconv) { + /* SJIS X0201 Case... */ + /* This is too arrogant, but ... */ + if(x0201_f==NO_X0201) { + iconv = oconv; + c2 = c1; + NEXT; + } else + if(x0201_f) { + if(dv[(c1-SSP)*2]||ev[(c1-SSP)*2]) { + /* look ahead for X0201/X0208conversion */ + if((c2 = GETC()) == EOF) { + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + LAST; + } else if(c2==(0xde)) { /* 濁点 */ + (*oconv)(dv[(c1-SSP)*2],dv[(c1-SSP)*2+1]); + c2=0; + NEXT; + } else if(c2==(0xdf)&&ev[(c1-SSP)*2]) { + /* 半濁点 */ + (*oconv)(ev[(c1-SSP)*2],ev[(c1-SSP)*2+1]); + c2=0; + NEXT; + } + UNGETC(c2); c2 = 0; + } + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + NEXT; + } else + SEND; + } else if(c1==SSO && iconv != s_iconv) { + /* EUC X0201 Case */ + /* This is too arrogant + if(x0201_f == NO_X0201) { + estab_f = FALSE; + c2 = 0; + NEXT; + } */ + c1 = GETC(); /* skip SSO */ + euc_1byte_check: + if(x0201_f && SSP<=c1 && c1<0xe0) { + if(dv[(c1-SSP)*2]||ev[(c1-SSP)*2]) { + if((c2 = GETC()) == EOF) { + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + LAST; + } + /* forward lookup 濁点/半濁点 */ + if(c2 != SSO) { + UNGETC(c2); c2 = 0; + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + NEXT; + } else if((c2 = GETC()) == EOF) { + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + (*oconv)(0,SSO); + LAST; + } else if(c2==(0xde)) { /* 濁点 */ + (*oconv)(dv[(c1-SSP)*2],dv[(c1-SSP)*2+1]); + c2=0; + NEXT; + } else if(c2==(0xdf)&&ev[(c1-SSP)*2]) { + /* 半濁点 */ + (*oconv)(ev[(c1-SSP)*2],ev[(c1-SSP)*2+1]); + c2=0; + NEXT; + } else { + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + /* we have to check this c2 */ + /* and no way to push back SSO */ + c1 = c2; c2 = 0; + goto euc_1byte_check; + } + } + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + NEXT; + } else + SEND; + } else if(c1 < SSP && iconv != s_iconv) { + /* strange code in EUC */ + iconv = s_iconv; /* try SJIS */ + c2 = c1; + NEXT; + } else { + /* already established */ + c2 = c1; + NEXT; + } + } + } else if((c1 > SP) && (c1 != DEL)) { + /* in case of Roman characters */ + if(shift_mode) { + c1 |= 0x80; + /* output 1 shifted byte */ + if(x0201_f && (!iso8859_f||input_mode==X0201) && + SSP<=c1 && c1<0xe0 ) { + if(dv[(c1-SSP)*2]||ev[(c1-SSP)*2]) { + if((c2 = GETC()) == EOF) { + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + LAST; + } else if(c2==(0xde&0x7f)) { /* 濁点 */ + (*oconv)(dv[(c1-SSP)*2],dv[(c1-SSP)*2+1]); + c2=0; + NEXT; + } else if(c2==(0xdf&0x7f)&&ev[(c1-SSP)*2]) { + /* 半濁点 */ + (*oconv)(ev[(c1-SSP)*2],ev[(c1-SSP)*2+1]); + c2=0; + NEXT; + } + UNGETC(c2); c2 = 0; + } + (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]); + NEXT; + } else + SEND; + } else if(c1 == '(' && broken_f && input_mode == X0208 + && !mime_mode ) { + /* Try to recover missing escape */ + if((c1 = GETC()) == EOF) { + (*oconv) (0, '('); + LAST; + } else { + if(c1 == 'B' || c1 == 'J' || c1 == 'H') { + input_mode = ASCII; shift_mode = FALSE; + NEXT; + } else { + (*oconv) (0, '('); + /* do not modify various input_mode */ + /* It can be vt100 sequence */ + SEND; + } + } + } else if(input_mode == X0208) { + /* in case of Kanji shifted */ + c2 = c1; + NEXT; + /* goto next_byte */ + } else if(c1 == '=' && mime_f && !mime_mode ) { + if((c1 = _GETC()) == EOF) { + (*oconv) (0, '='); + LAST; + } else if(c1 == '?') { + /* =? is mime conversion start sequence */ + if(mime_begin() == EOF) /* check in detail */ + LAST; + else + NEXT; + } else { + (*oconv) (0, '='); + _UNGETC(c1); + NEXT; + } + } else if(c1 == '$' && broken_f && !mime_mode) { + /* try to recover missing escape */ + if((c1 = GETC()) == EOF) { + (*oconv) (0, '$'); + LAST; + } else if(c1 == '@'|| c1 == 'B') { + /* in case of Kanji in ESC sequence */ + input_mode = X0208; + shift_mode = FALSE; + NEXT; + } else { + /* sorry */ + (*oconv) (0, '$'); + (*oconv) (0, c1); + NEXT; + } + } else + SEND; + } else if(c1 == SI) { + shift_mode = FALSE; + NEXT; + } else if(c1 == SO) { + shift_mode = TRUE; + NEXT; + } else if(c1 == ESC ) { + if((c1 = GETC()) == EOF) { + (*oconv) (0, ESC); + LAST; + } else if(c1 == '$') { + if((c1 = GETC()) == EOF) { + (*oconv) (0, ESC); + (*oconv) (0, '$'); + LAST; + } else if(c1 == '@'|| c1 == 'B') { + /* This is kanji introduction */ + input_mode = X0208; + shift_mode = FALSE; + NEXT; + } else if(broken_f&0x2) { + input_mode = X0208; + shift_mode = FALSE; + NEXT; + } else { + (*oconv) (0, ESC); + (*oconv) (0, '$'); + (*oconv) (0, c1); + NEXT; + } + } else if(c1 == '(') { + if((c1 = GETC()) == EOF) { + (*oconv) (0, ESC); + (*oconv) (0, '('); + LAST; + } else { + if(c1 == 'I') { + /* This is X0201 kana introduction */ + input_mode = X0201; shift_mode = X0201; + NEXT; + } else if(c1 == 'B' || c1 == 'J' || c1 == 'H') { + /* This is X0208 kanji introduction */ + input_mode = ASCII; shift_mode = FALSE; + NEXT; + } else if(broken_f&0x2) { + input_mode = ASCII; shift_mode = FALSE; + NEXT; + } else { + (*oconv) (0, ESC); + (*oconv) (0, '('); + /* maintain various input_mode here */ + SEND; + } + } + } else { + /* lonely ESC */ + (*oconv) (0, ESC); + SEND; + } + } else if(c1 == NL && broken_f&4) { + input_mode = ASCII; + SEND; + } else + SEND; + } + /* send: */ + if(input_mode == X0208) + (*oconv) (c2, c1); /* this is JIS, not SJIS/EUC case */ + else + (*iconv) (c2, c1); /* can be EUC/SJIS */ + c2 = 0; + continue; + /* goto next_word */ + } + + /* epilogue */ + (*iconv) (EOF, 0); + return outlen; +} + + +static void +h_conv (c2, c1) + register int c1, + c2; +{ + register int wc; + + + /** it must NOT be in the kanji shifte sequence */ + /** it must NOT be written in JIS7 */ + /** and it must be after 2 byte 8bit code */ + + hold_count = 0; + push_hold_buf (c2, c1); + c2 = 0; + + while ((c1 = GETC()) != EOF) { + if(c2) { + /* second byte */ + if(!estab_f) { + /* not established */ + if(c1 > SSP) { + /* it is still ambiguious yet */ + SEND; + } else if(c1 < AT) { + /* ignore bogus first byte */ + c2 = 0; + SEND; + } else { + /* now established */ + /* it seems to be MS Kanji */ + estab_f = TRUE; + iconv = s_iconv; + SEND; + } + } else + SEND; + } else { + /* First byte */ + if(c1 > DEL) { + /* 8th bit is on */ + if(c1 < SSP) { + /* it seems to be MS Kanji */ + estab_f = TRUE; + iconv = s_iconv; + } else if(c1 < 0xe0) { + /* it seems to be EUC */ + estab_f = TRUE; + iconv = oconv; + } else { + /* still ambiguious */ + } + c2 = c1; + NEXT; + } else + /* 7 bit code , then send without any process */ + SEND; + } + /* send: */ + if((push_hold_buf (c2, c1) == EOF) || estab_f) + break; + c2 = 0; + continue; + } + + /** now, + ** 1) EOF is detected, or + ** 2) Code is established, or + ** 3) Buffer is FULL (but last word is pushed) + ** + ** in 1) and 3) cases, we continue to use + ** Kanji codes by oconv and leave estab_f unchanged. + **/ + + for (wc = 0; wc < hold_count; wc += 2) { + c2 = hold_buf[wc]; + c1 = hold_buf[wc+1]; + (*iconv) (c2, c1); + } + return; +} + + + +static int +push_hold_buf (c2, c1) + int c2, + c1; +{ + if(hold_count >= HOLD_SIZE*2) + return (EOF); + hold_buf[hold_count++] = c2; + hold_buf[hold_count++] = c1; + return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count); +} + + +static void +s_iconv (c2, c1) + register int c2, + c1; +{ + if((c2 == EOF) || (c2 == 0)) { + /* NOP */ + } else { + c2 = c2 + c2 - ((c2 <= 0x9f) ? SJ0162 : SJ6394); + if(c1 < 0x9f) + c1 = c1 - ((c1 > DEL) ? SP : 0x1f); + else { + c1 = c1 - 0x7e; + c2++; + } + } + (*oconv) (c2, c1); +} + + +static void +e_oconv (c2, c1) + register int c2, + c1; +{ + c2 = pre_convert(c1,c2); c1 = c1_return; + if(fold_f) { + switch(fold(c2,c1)) { + case '\n': + if(add_cr == TRUE) { + PUTCHAR('\r'); + c1 = '\n'; + } + PUTCHAR('\n'); + break; + case 0: return; + case '\r': + c1 = '\n'; c2 = 0; + break; + case '\t': + case ' ': + c1 = ' '; c2 = 0; + break; + } + } + if(c2==DOUBLE_SPACE) { + PUTCHAR(' '); PUTCHAR(' '); + return; + } + if(c2 == EOF) + return; + else if(c2 == 0 && (c1&0x80)) { + PUTCHAR(SSO); PUTCHAR(c1); + } else if(c2 == 0) { + if(c1 == '\n' && add_cr == TRUE) + PUTCHAR('\r'); + if(c1 != '\r') + PUTCHAR(c1); + else if(del_cr == FALSE) + PUTCHAR(c1); + } else { + if((c1<0x20 || 0x7e> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1))); + PUTCHAR((c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e))); + } +} + +static void +j_oconv (c2, c1) + register int c2, + c1; +{ + c2 = pre_convert(c1,c2); c1 = c1_return; + if(fold_f) { + switch(fold(c2,c1)) { + case '\n': + if(output_mode) { + PUTCHAR(ESC); + PUTCHAR('('); + PUTCHAR(ascii_intro); + } + if(add_cr == TRUE) { + PUTCHAR('\r'); + c1 = '\n'; + } + PUTCHAR('\n'); + output_mode = ASCII; + break; + case '\r': + c1 = '\n'; c2 = 0; + break; + case '\t': + case ' ': + c1 = ' '; c2 = 0; + break; + case 0: return; + } + } + if(c2 == EOF) { + if(output_mode) { + PUTCHAR(ESC); + PUTCHAR('('); + PUTCHAR(ascii_intro); + } + } else if(c2 == 0 && (c1 & 0x80)) { + if(input_mode==X0201 || !iso8859_f) { + if(output_mode!=X0201) { + PUTCHAR(ESC); + PUTCHAR('('); + PUTCHAR('I'); + output_mode = X0201; + } + c1 &= 0x7f; + } else { + /* iso8859 introduction, or 8th bit on */ + /* Can we convert in 7bit form using ESC-'-'-A ? + Is this popular? */ + } + PUTCHAR(c1); + } else if(c2 == 0) { + if(output_mode) { + PUTCHAR(ESC); + PUTCHAR('('); + PUTCHAR(ascii_intro); + output_mode = ASCII; + } + if(c1 == '\n' && add_cr == TRUE) + PUTCHAR('\r'); + if(c1 != '\r') + PUTCHAR(c1); + else if(del_cr == FALSE) + PUTCHAR(c1); + } else if(c2 == DOUBLE_SPACE) { + if(output_mode) { + PUTCHAR(ESC); + PUTCHAR('('); + PUTCHAR(ascii_intro); + output_mode = ASCII; + } + PUTCHAR(' '); + if(c1 == '\n' && add_cr == TRUE) + PUTCHAR('\r'); + if(c1 != '\r') + PUTCHAR(c1); + else if(del_cr == FALSE) + PUTCHAR(c1); + } else { + if(output_mode != X0208) { + PUTCHAR(ESC); + PUTCHAR('$'); + PUTCHAR(kanji_intro); + output_mode = X0208; + } + if(c1<0x20 || 0x7e0x80 Japanese (X0208/X0201) + <0x80 ASCII + \n new line + ' ' space + + This fold algorthm does not preserve heading space in a line. + This is the main difference from fmt. +*/ + +static int +fold(c2,c1) +register int c2,c1; +{ + int prev0; + if(c1=='\r') + return 0; /* ignore cr */ + if(c1== 8) { + if(line>0) line--; + return 1; + } + if(c2==EOF && line != 0) /* close open last line */ + return '\n'; + /* new line */ + if(c1=='\n') { + if(prev == c1) { /* duplicate newline */ + if(line) { + line = 0; + return '\n'; /* output two newline */ + } else { + line = 0; + return 1; + } + } else { + if(prev&0x80) { /* Japanese? */ + prev = c1; + return 0; /* ignore given single newline */ + } else if(prev==' ') { + return 0; + } else { + prev = c1; + if(++line<=fold_len) + return ' '; + else { + line = 0; + return '\r'; /* fold and output nothing */ + } + } + } + } + if(c1=='\f') { + prev = '\n'; + if(line==0) + return 1; + line = 0; + return '\n'; /* output newline and clear */ + } + /* X0208 kankaku or ascii space */ + if( (c2==0&&c1==' ')|| + (c2==0&&c1=='\t')|| + (c2==DOUBLE_SPACE)|| + (c2=='!'&& c1=='!')) { + if(prev == ' ') { + return 0; /* remove duplicate spaces */ + } + prev = ' '; + if(++line<=fold_len) + return ' '; /* output ASCII space only */ + else { + prev = ' '; line = 0; + return '\r'; /* fold and output nothing */ + } + } + prev0 = prev; /* we still need this one... , but almost done */ + prev = c1; + if(c2 || (SSP<=c1 && c1<=0xdf)) + prev |= 0x80; /* this is Japanese */ + line += (c2==0)?1:2; + if(line<=fold_len) { /* normal case */ + return 1; + } + if(line>=fold_len+FOLD_MARGIN) { /* too many kinsou suspension */ + line = (c2==0)?1:2; + return '\n'; /* We can't wait, do fold now */ + } + /* simple kinsoku rules return 1 means no folding */ + if(c2==0) { + if(c1==0xde) return 1; /* ゛*/ + if(c1==0xdf) return 1; /* ゜*/ + if(c1==0xa4) return 1; /* 。*/ + if(c1==0xa3) return 1; /* ,*/ + if(c1==0xa1) return 1; /* 」*/ + if(c1==0xb0) return 1; /* - */ + if(SSP<=c1 && c1<=0xdf) { /* X0201 */ + line = 1; + return '\n';/* add one new line before this character */ + } + /* fold point in ASCII { [ ( */ + if(( c1!=')'&& + c1!=']'&& + c1!='}'&& + c1!='.'&& + c1!=','&& + c1!='!'&& + c1!='?'&& + c1!='/'&& + c1!=':'&& + c1!=';')&& + ((prev0=='\n')|| (prev0==' ')|| /* ignored new line */ + (prev0&0x80)) /* X0208 - ASCII */ + ) { + line = 1; + return '\n';/* add one new line before this character */ + } + return 1; /* default no fold in ASCII */ + } else { + if(c2=='!') { + if(c1=='"') return 1; /* 、 */ + if(c1=='#') return 1; /* 。 */ + if(c1=='$') return 1; /* , */ + if(c1=='%') return 1; /* . */ + if(c1=='\'') return 1; /* + */ + if(c1=='(') return 1; /* ; */ + if(c1==')') return 1; /* ? */ + if(c1=='*') return 1; /* ! */ + if(c1=='+') return 1; /* ゛ */ + if(c1==',') return 1; /* ゜ */ + } + line = 2; + return '\n'; /* add one new line before this character */ + } +} + +static int +pre_convert(c1,c2) +register int c1,c2; +{ + if(c2) c1 &= 0x7f; + c1_return = c1; + if(c2==EOF) return c2; + c2 &= 0x7f; + if(rot_f) { + if(c2) { + c1 = rot47(c1); + c2 = rot47(c2); + } else { + if(!(c1 & 0x80)) + c1 = rot13(c1); + } + c1_return = c1; + } + /* JISX0208 Alphabet */ + if(alpha_f && c2 == 0x23 ) return 0; + /* JISX0208 Kigou */ + if(alpha_f && c2 == 0x21 ) { + if(0x21==c1) { + if(alpha_f&0x2) { + c1_return = ' '; + return 0; + } else if(alpha_f&0x4) { + c1_return = ' '; + return DOUBLE_SPACE; + } else { + return c2; + } + } else if(0x20' ';i++) { /* start at =? */ + if( ((r[i] = c1 = _GETC())==EOF) || nkf_toupper(c1) != p[i] ) { + /* pattern fails, try next one */ + q = p; + while (p = mime_pattern[++j]) { + for(k=2;k i */ + if(p[k]!=q[k]) break; + if(k==i && nkf_toupper(c1)==p[k]) break; + } + if(p) continue; /* found next one, continue */ + /* all fails, output from recovery buffer */ + _UNGETC(c1); + for(j=0;j> 4) & 0x03); + if(c2 != '=') { + Fifo(mime_last++) = cc; + cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f); + if(c3 != '=') { + Fifo(mime_last++) = cc; + cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f); + if(c4 != '=') + Fifo(mime_last++) = cc; + } + } else { + return c1; + } + return Fifo(mime_top++); +} + +static int +mime_ungetc(c) +unsigned int c; +{ + Fifo(mime_last++) = c; + return c; +} + + +static int +mime_integrity(p) +unsigned char *p; +{ + int c,d; + unsigned int q; + /* In buffered mode, read until =? or NL or buffer full + */ + mime_input = mime_top; + mime_last = mime_top; + while(*p) Fifo(mime_input++) = *p++; + d = 0; + q = mime_input; + while((c=_GETC())!=EOF) { + if(((mime_input-mime_top)&MIME_BUF_MASK)==0) break; + if(c=='=' && d=='?') { + /* checked. skip header, start decode */ + Fifo(mime_input++) = c; + mime_input = q; + return 1; + } + if(!( (c=='+'||c=='/'|| c=='=' || c=='?' || + ('a'<=c && c<='z')||('A'<= c && c<='Z')||('0'<=c && c<='9')))) + break; + /* Should we check length mod 4? */ + Fifo(mime_input++) = c; + d=c; + } + /* In case of Incomplete MIME, no MIME decode */ + Fifo(mime_input++) = c; + mime_last = mime_input; /* point undecoded buffer */ + mime_mode = 1; /* no decode on Fifo last in mime_getc */ + return 1; +} + +static int +base64decode(c) + int c; +{ + int i; + if(c > '@') + if(c < '[') + i = c - 'A'; /* A..Z 0-25 */ + else + i = c - 'G' /* - 'a' + 26 */ ; /* a..z 26-51 */ + else if(c > '/') + i = c - '0' + '4' /* - '0' + 52 */ ; /* 0..9 52-61 */ + else if(c == '+') + i = '>' /* 62 */ ; /* + 62 */ + else + i = '?' /* 63 */ ; /* / 63 */ + return (i); +} + +#ifdef notdef +int +usage() +{ + fprintf(stderr,"USAGE: nkf(nkf32,wnkf,nkf2) -[flags] [in file] .. [out file for -O flag]\n"); + fprintf(stderr,"Flags:\n"); + fprintf(stderr,"b,u Output is bufferred (DEFAULT),Output is unbufferred\n"); +#ifdef DEFAULT_CODE_SJIS + fprintf(stderr,"j,s,e Outout code is JIS 7 bit, Shift JIS (DEFAULT), AT&T JIS (EUC)\n"); +#endif +#ifdef DEFAULT_CODE_JIS + fprintf(stderr,"j,s,e Outout code is JIS 7 bit (DEFAULT), Shift JIS, AT&T JIS (EUC)\n"); +#endif +#ifdef DEFAULT_CODE_EUC + fprintf(stderr,"j,s,e Outout code is JIS 7 bit, Shift JIS, AT&T JIS (EUC) (DEFAULT)\n"); +#endif + fprintf(stderr,"J,S,E Input assumption is JIS 7 bit , Shift JIS, AT&T JIS (EUC)\n"); + fprintf(stderr,"t no conversion\n"); + fprintf(stderr,"i_ Output sequence to designate JIS-kanji (DEFAULT B)\n"); + fprintf(stderr,"o_ Output sequence to designate ASCII (DEFAULT B)\n"); + fprintf(stderr,"r {de/en}crypt ROT13/47\n"); + fprintf(stderr,"v Show this usage\n"); + fprintf(stderr,"m[BQ] MIME decode [B:base64 stream,Q:quoted stream]\n"); + fprintf(stderr,"l ISO8859-1 (Latin-1) support\n"); + fprintf(stderr,"f Folding: -f60 or -f\n"); + fprintf(stderr,"Z[0-2] Convert X0208 alphabet to ASCII 1: Kankaku to space,2: 2 spaces\n"); + fprintf(stderr,"X,x Assume X0201 kana in MS-Kanji, -x preserves X0201\n"); + fprintf(stderr,"B[0-2] Broken input 0: missing ESC,1: any X on ESC-[($]-X,2: ASCII on NL\n"); +#ifdef MSDOS + fprintf(stderr,"T Text mode output\n"); +#endif + fprintf(stderr,"O Output to File (DEFAULT 'nkf.out')\n"); + fprintf(stderr,"d,c Delete \\r in line feed, Add \\r in line feed\n"); + fprintf(stderr,"Network Kanji Filter Version %s (%s) " +#if defined(MSDOS) && !defined(_Windows) + "for DOS" +#endif +#if !defined(__WIN32__) && defined(_Windows) + "for Win16" +#endif +#if defined(__WIN32__) && defined(_Windows) + "for Win32" +#endif +#ifdef __OS2__ + "for OS/2" +#endif + ,Version,Patchlevel); + fprintf(stderr,"\n%s\n",CopyRight); + return 0; +} +#endif /* notdef */ + +static VALUE +kconv_kconv(argc, argv) + int argc; + VALUE *argv; +{ + struct RString *src, *dst; + VALUE in, out; + int in_code, out_code; + + rb_scan_args(argc, argv, "12", &src, &out, &in); + Check_Type(src, T_STRING); + + if (NIL_P(out)) { + out_code = _JIS; + } + else { + out_code = NUM2INT(out); + } + if (NIL_P(in)) { + in_code = _AUTO; + } + else { + in_code = NUM2INT(in); + } + + dst = RSTRING(str_new(0, src->len*3+10)); /* large enough? */ + dst->len = do_kconv(src->ptr, dst->ptr, dst->len, out_code, in_code); + + return (VALUE)dst; +} + +static VALUE +kconv_tojis(obj, src) + VALUE obj; + struct RString *src; +{ + struct RString *dst; + + Check_Type(src, T_STRING); + + dst = RSTRING(str_new(0, src->len*3+10)); /* large enough? */ + dst->len = do_kconv(src->ptr, dst->ptr, dst->len, _JIS, _AUTO); + + return (VALUE)dst; +} + +static VALUE +kconv_toeuc(obj, src) + VALUE obj; + struct RString* src; +{ + struct RString *dst; + + Check_Type(src, T_STRING); + + dst = RSTRING(str_new(0, src->len*3+10)); /* large enough? */ + dst->len = do_kconv(src->ptr, dst->ptr, dst->len, _EUC, _AUTO); + + return (VALUE)dst; +} + +static VALUE +kconv_tosjis(obj, src) + VALUE obj; + struct RString* src; +{ + struct RString *dst; + + Check_Type(src, T_STRING); + + dst = RSTRING(str_new(0, src->len*3+10)); /* large enough? */ + dst->len = do_kconv(src->ptr, dst->ptr, dst->len, _SJIS, _AUTO); + + return (VALUE)dst; +} + +void +Init_kconv() +{ + VALUE mKconv = rb_define_module("Kconv"); + + rb_define_module_function(mKconv, "kconv", kconv_kconv, -1); + rb_define_module_function(mKconv, "tojis", kconv_tojis, 1); + rb_define_module_function(mKconv, "toeuc", kconv_toeuc, 1); + rb_define_module_function(mKconv, "tosjis", kconv_tosjis, 1); + + rb_define_const(mKconv, "AUTO", INT2FIX(_AUTO)); + rb_define_const(mKconv, "JIS", INT2FIX(_JIS)); + rb_define_const(mKconv, "EUC", INT2FIX(_EUC)); + rb_define_const(mKconv, "SJIS", INT2FIX(_SJIS)); +} + +/** + ** パッチ制作者 + ** void@merope.pleiades.or.jp (Kusakabe Youichi) + ** NIDE Naoyuki + ** ohta@src.ricoh.co.jp (Junn Ohta) + ** inouet@strl.nhk.or.jp (Tomoyuki Inoue) + ** kiri@pulser.win.or.jp (Tetsuaki Kiriyama) + ** Kimihiko Sato + ** a_kuroe@kuroe.aoba.yokohama.jp (Akihiko Kuroe) + ** kono@ie.u-ryukyu.ac.jp (Shinji Kono) + ** GHG00637@nifty-serve.or.jp (COW) + ** j_kuro@pluto.ai.kyutech.ac.jp (Jun Kuroda) + ** + ** 最終更新日 + ** 1996.12.18 + **/ + +/* end */ diff --git a/ext/marshal/MANIFEST b/ext/marshal/MANIFEST new file mode 100644 index 0000000000..54870ec71f --- /dev/null +++ b/ext/marshal/MANIFEST @@ -0,0 +1,5 @@ +MANIFEST +depend +extconf.rb +marshal.c +marshal.doc diff --git a/ext/marshal/depend b/ext/marshal/depend new file mode 100644 index 0000000000..c955eb2d59 --- /dev/null +++ b/ext/marshal/depend @@ -0,0 +1,2 @@ +marshal.o: marshal.c ../../ruby.h ../../config.h ../../defines.h ../../io.h \ + ../../st.h diff --git a/ext/marshal/extconf.rb b/ext/marshal/extconf.rb new file mode 100644 index 0000000000..ab30bd117b --- /dev/null +++ b/ext/marshal/extconf.rb @@ -0,0 +1 @@ +create_makefile("marshal") diff --git a/ext/marshal/marshal.c b/ext/marshal/marshal.c new file mode 100644 index 0000000000..99e87d0b5f --- /dev/null +++ b/ext/marshal/marshal.c @@ -0,0 +1,850 @@ +/************************************************ + + marshal.c - + + $Author$ + $Revision$ + $Date$ + created at: Thu Apr 27 16:30:01 JST 1995 + +************************************************/ + +#include "ruby.h" +#include "io.h" +#include "st.h" + +#define MARSHAL_MAJOR 4 +#define MARSHAL_MINOR 0 + +#define TYPE_NIL '0' +#define TYPE_TRUE 'T' +#define TYPE_FALSE 'F' +#define TYPE_FIXNUM 'i' + +#define TYPE_UCLASS 'C' +#define TYPE_OBJECT 'o' +#define TYPE_USERDEF 'u' +#define TYPE_FLOAT 'f' +#define TYPE_BIGNUM 'l' +#define TYPE_STRING '"' +#define TYPE_REGEXP '/' +#define TYPE_ARRAY '[' +#define TYPE_HASH '{' +#define TYPE_STRUCT 'S' +#define TYPE_MODULE 'M' + +#define TYPE_SYMBOL ':' +#define TYPE_SYMLINK ';' + +#define TYPE_LINK '@' + +extern VALUE cString; +extern VALUE cRegexp; +extern VALUE cArray; +extern VALUE cHash; + +VALUE rb_path2class(); + +static ID s_dump, s_load; + +struct dump_arg { + VALUE obj; + FILE *fp; + VALUE str; + st_table *symbol; + st_table *data; +}; + +struct dump_call_arg { + VALUE obj; + struct dump_arg *arg; + int limit; +}; + +static void w_long _((long, struct dump_arg*)); + +static void +w_byte(c, arg) + char c; + struct dump_arg *arg; +{ + if (arg->fp) putc(c, arg->fp); + else str_cat(arg->str, (UCHAR*)&c, 1); +} + +static void +w_bytes(s, n, arg) + char *s; + int n; + struct dump_arg *arg; +{ + w_long(n, arg); + if (arg->fp) { + fwrite(s, 1, n, arg->fp); + } + else { + str_cat(arg->str, s, n); + } +} + +static void +w_short(x, arg) + int x; + struct dump_arg *arg; +{ + int i; + + for (i=0; i> (i*8)) & 0xff, arg); + } +} + +static void +w_long(x, arg) + long x; + struct dump_arg *arg; +{ + char buf[sizeof(long)+1]; + int i, len = 0; + + if (x == 0) { + w_byte(0, arg); + return; + } + for (i=1;isymbol, id, &num)) { + w_byte(TYPE_SYMLINK, arg); + w_long(num, arg); + } + else { + w_byte(TYPE_SYMBOL, arg); + w_bytes(sym, strlen(sym), arg); + st_insert(arg->symbol, id, arg->symbol->num_entries); + } +} + +static void +w_unique(s, arg) + char *s; + struct dump_arg *arg; +{ + w_symbol(rb_intern(s), arg); +} + +static void w_object _((VALUE,struct dump_arg*,int)); +extern VALUE cIO, cBignum, cStruct; + +static int +hash_each(key, value, arg) + VALUE key, value; + struct dump_call_arg *arg; +{ + w_object(key, arg->arg, arg->limit); + w_object(value, arg->arg, arg->limit); + return ST_CONTINUE; +} + +static int +obj_each(id, value, arg) + ID id; + VALUE value; + struct dump_call_arg *arg; +{ + w_symbol(id, arg->arg); + w_object(value, arg->arg, arg->limit); + return ST_CONTINUE; +} + +static void +w_uclass(obj, class, arg) + VALUE obj, class; + struct dump_arg *arg; +{ + if (CLASS_OF(obj) != class) { + w_byte(TYPE_UCLASS, arg); + w_unique(rb_class2name(CLASS_OF(obj)), arg); + } +} + +static void +w_object(obj, arg, limit) + VALUE obj; + struct dump_arg *arg; + int limit; +{ + int n; + struct dump_call_arg c_arg; + + if (limit == 0) { + Fail("exceed depth limit"); + } + limit--; + c_arg.limit = limit; + c_arg.arg = arg; + + if (obj == Qnil) { + w_byte(TYPE_NIL, arg); + } + else if (obj == TRUE) { + w_byte(TYPE_TRUE, arg); + } + else if (obj == FALSE) { + w_byte(TYPE_FALSE, arg); + } + else if (FIXNUM_P(obj)) { +#if SIZEOF_LONG <= 4 + w_byte(TYPE_FIXNUM, arg); + w_long(FIX2INT(obj), arg); +#else + if (RSHIFT(obj, 32) == 0 || RSHIFT(obj, 32) == -1) { + w_byte(TYPE_FIXNUM, arg); + w_long(FIX2INT(obj), arg); + } + else { + obj = int2big(FIX2INT(obj)); + goto write_bignum; + } +#endif + } + else { + int num; + + if (st_lookup(arg->data, obj, &num)) { + w_byte(TYPE_LINK, arg); + w_long(num, arg); + return; + } + st_insert(arg->data, obj, arg->data->num_entries); + if (rb_respond_to(obj, s_dump)) { + VALUE v; + + w_byte(TYPE_USERDEF, arg); + w_unique(rb_class2name(CLASS_OF(obj)), arg); + v = rb_funcall(obj, s_dump, 1, limit); + if (TYPE(v) != T_STRING) { + TypeError("_dump_to must return String"); + } + w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg); + return; + } + + switch (BUILTIN_TYPE(obj)) { + case T_MODULE: + case T_CLASS: + w_byte(TYPE_MODULE, arg); + { + VALUE path = rb_class_path(obj); + w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg); + } + return; + + case T_FLOAT: + w_byte(TYPE_FLOAT, arg); + w_float(RFLOAT(obj)->value, arg); + return; + + case T_BIGNUM: + write_bignum: + w_byte(TYPE_BIGNUM, arg); + { + char sign = RBIGNUM(obj)->sign?'+':'-'; + int len = RBIGNUM(obj)->len; + USHORT *d = RBIGNUM(obj)->digits; + + w_byte(sign, arg); + w_long(len, arg); + while (len--) { + w_short(*d, arg); + d++; + } + } + return; + + case T_STRING: + w_uclass(obj, cString, arg); + w_byte(TYPE_STRING, arg); + w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, arg); + return; + + case T_REGEXP: + w_uclass(obj, cRegexp, arg); + w_byte(TYPE_REGEXP, arg); + w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, arg); + w_byte(FL_TEST(obj, FL_USER1), arg); + return; + + case T_ARRAY: + w_uclass(obj, cArray, arg); + w_byte(TYPE_ARRAY, arg); + { + int len = RARRAY(obj)->len; + VALUE *ptr = RARRAY(obj)->ptr; + + w_long(len, arg); + while (len--) { + w_object(*ptr, arg, limit); + ptr++; + } + } + break; + + case T_HASH: + w_uclass(obj, cHash, arg); + w_byte(TYPE_HASH, arg); + w_long(RHASH(obj)->tbl->num_entries, arg); + st_foreach(RHASH(obj)->tbl, hash_each, &c_arg); + break; + + case T_STRUCT: + w_byte(TYPE_STRUCT, arg); + { + int len = RSTRUCT(obj)->len; + char *path = rb_class2name(CLASS_OF(obj)); + VALUE mem; + int i; + + w_unique(path, arg); + w_long(len, arg); + mem = rb_ivar_get(CLASS_OF(obj), rb_intern("__member__")); + if (mem == Qnil) { + Fatal("non-initialized struct"); + } + for (i=0; iptr[i]), arg); + w_object(RSTRUCT(obj)->ptr[i], arg, limit); + } + } + break; + + case T_OBJECT: + w_byte(TYPE_OBJECT, arg); + { + VALUE class = CLASS_OF(obj); + char *path; + + if (FL_TEST(class, FL_SINGLETON)) { + TypeError("singleton can't be dumped"); + } + path = rb_class2name(class); + w_unique(path, arg); + if (ROBJECT(obj)->iv_tbl) { + w_long(ROBJECT(obj)->iv_tbl->num_entries, arg); + st_foreach(ROBJECT(obj)->iv_tbl, obj_each, &c_arg); + } + else { + w_long(0, arg); + } + } + break; + + default: + TypeError("can't dump %s", rb_class2name(CLASS_OF(obj))); + break; + } + } +} + +static VALUE +dump(arg) + struct dump_call_arg *arg; +{ + w_object(arg->obj, arg->arg, arg->limit); +} + +static VALUE +dump_ensure(arg) + struct dump_arg *arg; +{ + st_free_table(arg->symbol); + st_free_table(arg->data); +} + +static VALUE +marshal_dump(argc, argv) + int argc; + VALUE argv; +{ + VALUE obj, port, a1, a2; + int limit = -1; + extern VALUE cIO; + struct dump_arg arg; + struct dump_call_arg c_arg; + + port = 0; + rb_scan_args(argc, argv, "12", &obj, &a1, &a2); + if (argc == 3) { + limit = NUM2INT(a2); + port = a1; + } + else if (argc == 2) { + if (FIXNUM_P(a1)) limit = FIX2INT(a1); + else port = a1; + } + if (port) { + if (obj_is_kind_of(port, cIO)) { + OpenFile *fptr; + + io_binmode(port); + GetOpenFile(port, fptr); + io_writable(fptr); + arg.fp = (fptr->f2) ? fptr->f2 : fptr->f; + } + else { + TypeError("instance of IO needed"); + } + } + else { + arg.fp = 0; + port = str_new(0, 0); + arg.str = port; + } + + arg.symbol = st_init_numtable(); + arg.data = st_init_numtable(); + c_arg.obj = obj; + c_arg.arg = &arg; + c_arg.limit = limit; + + w_byte(MARSHAL_MAJOR, &arg); + w_byte(MARSHAL_MINOR, &arg); + + rb_ensure(dump, &c_arg, dump_ensure, &arg); + + return port; +} + +struct load_arg { + FILE *fp; + UCHAR *ptr, *end; + st_table *symbol; + st_table *data; +}; + +static int +r_byte(arg) + struct load_arg *arg; +{ + if (arg->fp) return getc(arg->fp); + if (arg->ptr < arg->end) return *arg->ptr++; + return EOF; +} + +static USHORT +r_short(arg) + struct load_arg *arg; +{ + USHORT x; + int i; + + x = 0; + for (i=0; i 0) { + if (c > sizeof(long)) long_toobig((int)c); + x = 0; + for (i=0;i sizeof(long)) long_toobig((int)c); + x = -1; + for (i=0;ifp) { + len = fread(s, 1, len, arg->fp); + } + else { + if (arg->ptr + len > arg->end) { + len = arg->end - arg->ptr; + } + memcpy(s, arg->ptr, len); + arg->ptr += len; + } + + (s)[len] = '\0'; + *sp = s; + + return len; +} + +static ID +r_symbol(arg) + struct load_arg *arg; +{ + char *buf; + ID id; + char type; + + if (r_byte(arg) == TYPE_SYMLINK) { + int num = r_long(arg); + + if (st_lookup(arg->symbol, num, &id)) { + return id; + } + TypeError("bad symbol"); + } + r_bytes(buf, arg); + id = rb_intern(buf); + st_insert(arg->symbol, arg->symbol->num_entries, id); + + return id; +} + +static char* +r_unique(arg) + struct load_arg *arg; +{ + return rb_id2name(r_symbol(arg)); +} + +static VALUE +r_string(arg) + struct load_arg *arg; +{ + char *buf; + int len = r_bytes(buf, arg); + + return str_taint(str_new(buf, len)); +} + +static VALUE +r_regist(v, arg) + VALUE v; + struct load_arg *arg; +{ + st_insert(arg->data, arg->data->num_entries, v); + return v; +} + +static VALUE +r_object(arg) + struct load_arg *arg; +{ + VALUE v; + int type = r_byte(arg); + + switch (type) { + case EOF: + eof_error(); + return Qnil; + + case TYPE_LINK: + if (st_lookup(arg->data, r_long(arg), &v)) { + return v; + } + ArgError("dump format error (unlinked)"); + break; + + case TYPE_UCLASS: + { + VALUE c = rb_path2class(r_unique(arg)); + v = r_object(arg); + if (rb_special_const_p(v)) { + ArgError("dump format error (user class)"); + } + RBASIC(v)->class = c; + return v; + } + + case TYPE_NIL: + return Qnil; + + case TYPE_TRUE: + return TRUE; + + case TYPE_FALSE: + return FALSE; + + case TYPE_FIXNUM: + { + int i = r_long(arg); + return INT2FIX(i); + } + + case TYPE_FLOAT: + { +#ifndef atof + double atof(); +#endif + char *buf; + + r_bytes(buf, arg); + v = float_new(atof(buf)); + return r_regist(v, arg); + } + + case TYPE_BIGNUM: + { + int len; + USHORT *digits; + + NEWOBJ(big, struct RBignum); + OBJSETUP(big, cBignum, T_BIGNUM); + big->sign = (r_byte(arg) == '+'); + big->len = len = r_long(arg); + big->digits = digits = ALLOC_N(USHORT, len); + while (len--) { + *digits++ = r_short(arg); + } + big = RBIGNUM(big_norm((VALUE)big)); + if (TYPE(big) == T_BIGNUM) { + r_regist(big, arg); + } + return (VALUE)big; + } + + case TYPE_STRING: + return r_regist(r_string(arg), arg); + + case TYPE_REGEXP: + { + char *buf; + int len = r_bytes(buf, arg); + int ci = r_byte(arg); + return r_regist(reg_new(buf, len, ci), arg); + } + + case TYPE_ARRAY: + { + volatile int len = r_long(arg); + v = ary_new2(len); + r_regist(v, arg); + while (len--) { + ary_push(v, r_object(arg)); + } + return v; + } + + case TYPE_HASH: + { + int len = r_long(arg); + + v = hash_new(); + r_regist(v, arg); + while (len--) { + VALUE key = r_object(arg); + VALUE value = r_object(arg); + hash_aset(v, key, value); + } + return v; + } + + case TYPE_STRUCT: + { + VALUE class, mem, values; + int i, len; + int num = arg->data->num_entries; + + class = rb_path2class(r_unique(arg)); + mem = rb_ivar_get(class, rb_intern("__member__")); + if (mem == Qnil) { + Fatal("non-initialized struct"); + } + len = r_long(arg); + + values = ary_new2(len); + for (i=0; iptr[i] != INT2FIX(slot)) + TypeError("struct not compatible"); + struct_aset(v, INT2FIX(i), r_object(arg)); + } + return v; + } + break; + + case TYPE_USERDEF: + { + VALUE class; + int len; + + class = rb_path2class(r_unique(arg)); + if (rb_respond_to(class, s_load)) { + v = rb_funcall(class, s_load, 1, r_string(arg)); + return r_regist(v, arg); + } + TypeError("class %s needs to have method `_load_from'", + rb_class2name(class)); + } + break; + + case TYPE_OBJECT: + { + VALUE class; + int len; + + class = rb_path2class(r_unique(arg)); + len = r_long(arg); + v = obj_alloc(class); + r_regist(v, arg); + if (len > 0) { + while (len--) { + ID id = r_symbol(arg); + VALUE val = r_object(arg); + rb_ivar_set(v, id, val); + } + } + return v; + } + break; + + case TYPE_MODULE: + { + char *buf; + r_bytes(buf, arg); + return rb_path2class(buf); + } + + default: + ArgError("dump format error(0x%x)", type); + break; + } +} + +static VALUE +load(arg) + struct load_arg *arg; +{ + return r_object(arg); +} + +static VALUE +load_ensure(arg) + struct load_arg *arg; +{ + st_free_table(arg->symbol); + st_free_table(arg->data); +} + +static VALUE +marshal_load(self, port) + VALUE self, port; +{ + FILE *fp; + int major; + VALUE v; + OpenFile *fptr; + struct load_arg arg; + + if (TYPE(port) == T_STRING) { + arg.fp = 0; + arg.ptr = RSTRING(port)->ptr; + arg.end = arg.ptr + RSTRING(port)->len; + } + else { + if (obj_is_kind_of(port, cIO)) { + io_binmode(port); + GetOpenFile(port, fptr); + io_readable(fptr); + arg.fp = fptr->f; + } + else { + TypeError("instance of IO needed"); + } + } + + major = r_byte(&arg); + if (major == MARSHAL_MAJOR) { + if (r_byte(&arg) != MARSHAL_MINOR) { + Warning("Old marshal file format (can be read)"); + } + arg.symbol = st_init_numtable(); + arg.data = st_init_numtable(); + v = rb_ensure(load, &arg, load_ensure, &arg); + } + else { + TypeError("Old marshal file format (can't read)"); + } + + return v; +} + +Init_marshal() +{ + VALUE mMarshal = rb_define_module("Marshal"); + + s_dump = rb_intern("_dump_to"); + s_load = rb_intern("_load_from"); + rb_define_module_function(mMarshal, "dump", marshal_dump, -1); + rb_define_module_function(mMarshal, "load", marshal_load, 1); + rb_define_module_function(mMarshal, "restore", marshal_load, 1); +} diff --git a/ext/marshal/marshal.doc b/ext/marshal/marshal.doc new file mode 100644 index 0000000000..7529e7942f --- /dev/null +++ b/ext/marshal/marshal.doc @@ -0,0 +1,48 @@ +.\" marshal.doc - -*- Indented-Text -*- created at: Tue May 16 12:18:08 JST 1995 + +** Marshal(モジュール) + +rubyオブジェクトをファイルに書き出したり,読みも度したりする機能を提供 +するモジュール.大部分のクラスのインスタンスを書き出す事ができるが,ファ +イルへの不可能なクラスも存在し(例:IO),そのようなクラスを書き出そうと +すると例外を発生させる. + +Methods: +Single Methods: + + dump(obj, port[, limit]) + + objを再帰的にファイルに書き出す.ファイルに書き出せないクラスのイ + ンスタンスをファイルに書き出そうとすると例外を発生させる.ファイル + に書き出せないクラスは以下の通り. + + Class, Module, Data + + また,これらのクラスを間接的に指すクラス(例えばIOのサブクラス)など + も書き出せない.portはIO(またはそのサブクラス)のインスタンスを指定 + する. + + 出力するオブジェクトがメソッド`_dump_to'を定義している場合には,ファ + イル出力はそのメソッドを使って行われる.メソッド`_dump_to'は引数と + して出力先のファイルオブジェクトを受け取る.インスタンスがメソッド + `_dump_to'を持つクラスは必ず同じフォーマットを読み戻す特異メソッド + `_load_from'を定義する必要がある. + + limitを指定した場合,limit段以上深くリンクしたオブジェクトをダンプ + できない(デフォルトは100レベル)。負のlimitを指定すると深さチェック + を行わない。 + + dumps(obj) + + dump()がファイルに書き出すのと同じ内容を含む文字列を返す. + + load(port) + + portからオブジェクトを読み込んで来て,元のオブジェクトと同じ状態を + もつオブジェクトを生成する.portは文字列かIO(またはそのサブクラス) + のインスタンスである. + +------------------------------------------------------- +Local variables: +fill-column: 70 +end: diff --git a/ext/md5/MANIFEST b/ext/md5/MANIFEST new file mode 100644 index 0000000000..e4f0004b4a --- /dev/null +++ b/ext/md5/MANIFEST @@ -0,0 +1,6 @@ +MANIFEST +depend +md5.doc +md5.h +md5c.c +md5init.c diff --git a/ext/md5/depend b/ext/md5/depend new file mode 100644 index 0000000000..be56da89b9 --- /dev/null +++ b/ext/md5/depend @@ -0,0 +1,2 @@ +md5c.o: md5c.c md5.h +md5init.o: md5init.c ../../ruby.h ../../config.h ../../defines.h md5.h diff --git a/ext/md5/md5.doc b/ext/md5/md5.doc new file mode 100644 index 0000000000..2203404602 --- /dev/null +++ b/ext/md5/md5.doc @@ -0,0 +1,36 @@ +.\" md5.doc - -*- Indented-Text -*- created at: Fri Aug 2 12:01:27 JST 1996 + +** MD5(クラス) + +RFC1321に記述されているRSA Data Security, Inc. の MD5 Message-Digest +Algorithmを実装するクラス. + +SuperClass: Object + +Class Methods: + + new([str]) + md5([str]) + + 新しいMD5オブジェクトを生成する.文字列引数が与えられるとそれ + を追加する(see update). + +Methods: + + clone + + MD5オブジェクトの複製を作る + + digest + + 今までに追加した文字列に対するハッシュ値を16バイト長の文字列で + 返す. + + update(str) + + keyをキーとする値を返す. + +------------------------------------------------------- +Local variables: +fill-column: 70 +end: diff --git a/ext/md5/md5.h b/ext/md5/md5.h new file mode 100644 index 0000000000..81a6d7ff36 --- /dev/null +++ b/ext/md5/md5.h @@ -0,0 +1,86 @@ +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* ========== include global.h ========== */ +/* GLOBAL.H - RSAREF types and constants + */ + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. +The following makes PROTOTYPES default to 0 if it has not already + been defined with C compiler flags. + */ +#ifdef HAVE_PROTOTYPES +#define PROTOTYPES 1 +#endif +#ifndef PROTOTYPES +#define PROTOTYPES 0 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +#ifdef HAVE_LIMITS_H +#include +#else +/* Wild guess */ +#define LONG_MAX 2147483647L +#endif + +/* UINT4 defines a four byte word */ +#if defined(INT_MAX) && INT_MAX == 2147483647 +typedef unsigned int UINT4; +#else +#if defined(LONG_MAX) && LONG_MAX == 2147483647L +typedef unsigned long int UINT4; +#endif +/* Too bad if neither is */ +#endif + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. +If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif +/* ========== End global.h; continue md5.h ========== */ + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, unsigned int)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); diff --git a/ext/md5/md5c.c b/ext/md5/md5c.c new file mode 100644 index 0000000000..d7c7e4fb27 --- /dev/null +++ b/ext/md5/md5c.c @@ -0,0 +1,337 @@ +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "md5.h" + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +unsigned int inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. +*/ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +UINT4 state[4]; +unsigned char block[64]; +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (output, input, len) +unsigned char *output; +UINT4 *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (output, input, len) +UINT4 *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy (output, input, len) +POINTER output; +POINTER input; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (output, value, len) +POINTER output; +int value; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} diff --git a/ext/md5/md5init.c b/ext/md5/md5init.c new file mode 100644 index 0000000000..47f913792f --- /dev/null +++ b/ext/md5/md5init.c @@ -0,0 +1,90 @@ +/************************************************ + + md5init.c - + + $Author$ + created at: Fri Aug 2 09:24:12 JST 1996 + + Copyright (C) 1995 Yukihiro Matsumoto + +************************************************/ +/* This module provides an interface to the RSA Data Security, + Inc. MD5 Message-Digest Algorithm, described in RFC 1321. + It requires the files md5c.c and md5.h (which are slightly changed + from the versions in the RFC to avoid the "global.h" file.) */ + +#include "ruby.h" +#include "md5.h" + +static VALUE cMD5; + +static VALUE +md5_update(obj, str) + VALUE obj; + struct RString *str; +{ + MD5_CTX *md5; + + Check_Type(str, T_STRING); + Data_Get_Struct(obj, MD5_CTX, md5); + MD5Update(md5, str->ptr, str->len); + + return Qnil; +} +static VALUE +md5_digest(obj) + VALUE obj; +{ + MD5_CTX *md5, ctx; + unsigned char digest[16]; + + Data_Get_Struct(obj, MD5_CTX, md5); + ctx = *md5; + MD5Final(digest, &ctx); + + return str_new(digest, 16); +} + +static VALUE +md5_clone(obj) + VALUE obj; +{ + VALUE clone; + MD5_CTX *md5, *md5_new; + + Data_Get_Struct(obj, MD5_CTX, md5); + obj = Data_Make_Struct(CLASS_OF(obj), MD5_CTX, 0, 0, md5_new); + *md5_new = *md5; + + return obj; +} + +static VALUE +md5_new(argc, argv, class) +{ + int i; + VALUE arg, obj; + MD5_CTX *md5; + + rb_scan_args(argc, argv, "01", &arg); + if (!NIL_P(arg)) Check_Type(arg, T_STRING); + + obj = Data_Make_Struct(class, MD5_CTX, 0, 0, md5); + MD5Init(md5); + if (!NIL_P(arg)) { + md5_update(obj, arg); + } + + return obj; +} + +Init_md5() +{ + cMD5 = rb_define_class("MD5", cObject); + + rb_define_singleton_method(cMD5, "new", md5_new, -1); + + rb_define_method(cMD5, "update", md5_update, 1); + rb_define_method(cMD5, "digest", md5_digest, 0); + rb_define_method(cMD5, "clone", md5_clone, 0); +} diff --git a/ext/socket/MANIFEST b/ext/socket/MANIFEST new file mode 100644 index 0000000000..d41d9e0b69 --- /dev/null +++ b/ext/socket/MANIFEST @@ -0,0 +1,4 @@ +MANIFEST +depend +extconf.rb +socket.c diff --git a/ext/socket/depend b/ext/socket/depend new file mode 100644 index 0000000000..e6ede5a411 --- /dev/null +++ b/ext/socket/depend @@ -0,0 +1 @@ +socket.o : socket.c ../../ruby.h ../../config.h ../../defines.h ../../io.h ../../sig.h diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb new file mode 100644 index 0000000000..bbde1a0c35 --- /dev/null +++ b/ext/socket/extconf.rb @@ -0,0 +1,17 @@ +$LDFLAGS = "-L/usr/local/lib" +have_library("wsock32", "cygwin32_socket") or have_library("socket", "socket") +have_library("inet", "gethostbyname") +have_library("nsl", "gethostbyname") +have_header("sys/un.h") +if have_func("socket") or have_func("cygwin32_socket") + have_func("hsterror") + unless have_func("gethostname") + have_func("uname") + end + if ENV["SOCKS_SERVER"] # test if SOCKSsocket needed + if have_library("socks", "Rconnect") + $CFLAGS="-DSOCKS" + end + end + create_makefile("socket") +end diff --git a/ext/socket/socket.c b/ext/socket/socket.c new file mode 100644 index 0000000000..9128e26de7 --- /dev/null +++ b/ext/socket/socket.c @@ -0,0 +1,1407 @@ +/************************************************ + + socket.c - + + $Author$ + $Date$ + created at: Thu Mar 31 12:21:29 JST 1994 + +************************************************/ + +#include "ruby.h" +#include "io.h" +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_UN_H +#include +#endif + +#if defined(THREAD) && defined(HAVE_FCNTL) +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#include +#include +#include +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + +extern VALUE cIO; +extern VALUE cInteger; + +VALUE cBasicSocket; +VALUE cTCPsocket; +VALUE cTCPserver; +#ifdef AF_UNIX +VALUE cUNIXsocket; +VALUE cUNIXserver; +#endif +VALUE cSocket; + +extern VALUE eException; +static VALUE eSocket; + +#ifdef SOCKS +VALUE cSOCKSsocket; +void SOCKSinit(); +int Rconnect(); +#endif + +FILE *rb_fdopen(); +char *strdup(); + +#define INET_CLIENT 0 +#define INET_SERVER 1 +#define INET_SOCKS 2 + +#ifdef NT +static void +sock_finalize(fptr) + OpenFile *fptr; +{ + SOCKET s = fileno(fptr->f); + free(fptr->f); + free(fptr->f2); + closesocket(s); +} +#endif + +static VALUE +sock_new(class, fd) + VALUE class; + int fd; +{ + OpenFile *fp; + NEWOBJ(sock, struct RFile); + OBJSETUP(sock, class, T_FILE); + + MakeOpenFile(sock, fp); + fp->f = rb_fdopen(fd, "r"); +#ifdef NT + fp->finalize = sock_finalize; +#else + setbuf(fp->f, NULL); +#endif + fp->f2 = rb_fdopen(fd, "w"); + fp->mode = FMODE_READWRITE; + io_unbuffered(fp); + + return (VALUE)sock; +} + +static VALUE +bsock_shutdown(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + VALUE howto; + int how; + OpenFile *fptr; + + rb_scan_args(argc, argv, "01", &howto); + if (howto == Qnil) + how = 2; + else { + how = NUM2INT(howto); + if (how < 0 && how > 2) how = 2; + } + GetOpenFile(sock, fptr); + if (shutdown(fileno(fptr->f), how) == -1) + rb_sys_fail(0); + + return INT2FIX(0); +} + +static VALUE +bsock_setsockopt(sock, lev, optname, val) + VALUE sock, lev, optname; + struct RString *val; +{ + int level, option; + OpenFile *fptr; + int i; + char *v; + int vlen; + + rb_secure(2); + level = NUM2INT(lev); + option = NUM2INT(optname); + switch (TYPE(val)) { + case T_FIXNUM: + i = FIX2INT(val); + goto numval; + case T_FALSE: + i = 0; + goto numval; + case T_TRUE: + i = 1; + numval: + v = (char*)&i; vlen = sizeof(i); + break; + default: + Check_Type(val, T_STRING); + v = val->ptr; vlen = val->len; + } + + GetOpenFile(sock, fptr); + if (setsockopt(fileno(fptr->f), level, option, v, vlen) < 0) + rb_sys_fail(fptr->path); + + return INT2FIX(0); +} + +static VALUE +bsock_getsockopt(sock, lev, optname) + VALUE sock, lev, optname; +{ + int level, option, len; + char *buf; + OpenFile *fptr; + + level = NUM2INT(lev); + option = NUM2INT(optname); + len = 256; + buf = ALLOCA_N(char,len); + + GetOpenFile(sock, fptr); + if (getsockopt(fileno(fptr->f), level, option, buf, &len) < 0) + rb_sys_fail(fptr->path); + + return str_new(buf, len); +} + +static VALUE +bsock_getsockname(sock) + VALUE sock; +{ + char buf[1024]; + int len = sizeof buf; + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (getsockname(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) + rb_sys_fail("getsockname(2)"); + return str_new(buf, len); +} + +static VALUE +bsock_getpeername(sock) + VALUE sock; +{ + char buf[1024]; + int len = sizeof buf; + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (getpeername(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) + rb_sys_fail("getpeername(2)"); + return str_new(buf, len); +} + +static VALUE +bsock_send(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + struct RString *msg, *to; + VALUE flags; + OpenFile *fptr; + FILE *f; + int fd, n; + + rb_secure(4); + rb_scan_args(argc, argv, "21", &msg, &flags, &to); + + Check_Type(msg, T_STRING); + + GetOpenFile(sock, fptr); + f = fptr->f2?fptr->f2:fptr->f; + fd = fileno(f); + retry: +#ifdef THREAD + thread_fd_writable(fd); +#endif + if (RTEST(to)) { + Check_Type(to, T_STRING); + n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags), + (struct sockaddr*)to->ptr, to->len); + } + else { + n = send(fd, msg->ptr, msg->len, NUM2INT(flags)); + } + if (n < 0) { + switch (errno) { + case EINTR: + case EWOULDBLOCK: +#if EAGAIN != EWOULDBLOCK + case EAGAIN: +#endif +#ifdef THREAD + thread_schedule(); +#endif + goto retry; + } + rb_sys_fail("send(2)"); + } + return INT2FIX(n); +} + +static VALUE tcpaddr _((struct sockaddr_in*)); +#ifdef HAVE_SYS_UN_H +static VALUE unixaddr _((struct sockaddr_un*)); +#endif + +static VALUE +s_recv(sock, argc, argv, from) + VALUE sock; + int argc; + VALUE *argv; + int from; /* 0 - recv, + 1 - TCPsocket#recvfrom, + 2 - UNIXsocket#recvfrom, + 3 - Socket#recvfrom */ +{ + OpenFile *fptr; + FILE f; + struct RString *str; + char buf[1024]; + int fd, alen = sizeof buf; + VALUE len, flg; + int flags; + + rb_scan_args(argc, argv, "11", &len, &flg); + + if (flg == Qnil) flags = 0; + else flags = NUM2INT(flg); + + str = (struct RString*)str_new(0, NUM2INT(len)); + + GetOpenFile(sock, fptr); + fd = fileno(fptr->f); +#ifdef THREAD + thread_wait_fd(fd); +#endif + TRAP_BEG; + retry: + str->len = recvfrom(fd, str->ptr, str->len, flags, + (struct sockaddr*)buf, &alen); + TRAP_END; + + if (str->len < 0) { + switch (errno) { + case EINTR: + case EWOULDBLOCK: +#if EAGAIN != EWOULDBLOCK + case EAGAIN: +#endif +#ifdef THREAD + thread_schedule(); +#endif + goto retry; + } + rb_sys_fail("recvfrom(2)"); + } + str_taint(str); + switch (from) { + case 0: + return (VALUE)str; + case 1: + if (alen != sizeof(struct sockaddr_in)) { + TypeError("sockaddr size differs - should not happen"); + } + return assoc_new(str, tcpaddr((struct sockaddr_in *)buf)); +#ifdef HAVE_SYS_UN_H + case 2: + if (alen != sizeof(struct sockaddr_un)) { + TypeError("sockaddr size differs - should not happen"); + } + return assoc_new(str, unixaddr((struct sockaddr_un *)buf)); +#endif + case 3: + return assoc_new(str, str_new(buf, alen)); + } +} + +static VALUE +bsock_recv(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + return s_recv(sock, argc, argv, 0); +} + +#if defined(THREAD) && defined(HAVE_FCNTL) +static int +thread_connect(fd, sockaddr, len, type) + int fd; + struct sockaddr *sockaddr; + int len; + int type; +{ + int status; + int mode; + fd_set fds; + + mode = fcntl(fd, F_GETFL, 0); + +#ifdef O_NDELAY +# define NONBLOCKING O_NDELAY +#else +#ifdef O_NBIO +# define NONBLOCKING O_NBIO +#else +# define NONBLOCKING O_NONBLOCK +#endif +#endif + fcntl(fd, F_SETFL, mode|NONBLOCKING); + for (;;) { +#ifdef SOCKS + if (type == INET_SOCKS) { + status = Rconnect(fd, sockaddr, len); + } + else +#endif + { + status = connect(fd, sockaddr, len); + } + if (status < 0) { + switch (errno) { +#ifdef EINPROGRESS + case EINPROGRESS: +#ifdef EAGAIN + case EAGAIN: +#endif + FD_ZERO(&fds); + FD_SET(fd, &fds); + thread_select(fd+1, 0, &fds, 0, 0, 0); + continue; +#endif + +#ifdef EISCONN + case EISCONN: +#endif +#ifdef EALREADY + case EALREADY: +#endif +#if defined(EISCONN) || defined(EALREADY) + status = 0; + errno = 0; + break; +#endif + } + } + mode &= ~NONBLOCKING; + fcntl(fd, F_SETFL, mode); + return status; + } +} +#endif + +static VALUE +open_inet(class, h, serv, type) + VALUE class, h, serv; + int type; +{ + char *host; + struct hostent *hostent, _hostent; + struct servent *servent, _servent; + struct protoent *protoent; + struct sockaddr_in sockaddr; + int fd, status; + int hostaddr, hostaddrPtr[2]; + int servport; + char *syscall; + VALUE sock; + + if (h) { + Check_SafeStr(h); + host = RSTRING(h)->ptr; + hostent = gethostbyname(host); + if (hostent == NULL) { + hostaddr = inet_addr(host); + if (hostaddr == -1) { + if (type == INET_SERVER && !strlen(host)) + hostaddr = INADDR_ANY; + else { +#ifdef HAVE_HSTRERROR + extern int h_errno; + Raise(eSocket, (char *)hstrerror(h_errno)); +#else + Raise(eSocket, "host not found"); +#endif + } + } + _hostent.h_addr_list = (char **)hostaddrPtr; + _hostent.h_addr_list[0] = (char *)&hostaddr; + _hostent.h_addr_list[1] = NULL; + _hostent.h_length = sizeof(hostaddr); + _hostent.h_addrtype = AF_INET; + hostent = &_hostent; + } + } + servent = NULL; + if (FIXNUM_P(serv)) { + servport = FIX2UINT(serv); + goto setup_servent; + } + Check_Type(serv, T_STRING); + servent = getservbyname(RSTRING(serv)->ptr, "tcp"); + if (servent == NULL) { + servport = strtoul(RSTRING(serv)->ptr, 0, 0); + if (servport == -1) { + Raise(eSocket, "no such servce %s", RSTRING(serv)->ptr); + } + setup_servent: + _servent.s_port = htons(servport); + _servent.s_proto = "tcp"; + servent = &_servent; + } + protoent = getprotobyname(servent->s_proto); + if (protoent == NULL) { + Raise(eSocket, "no such proto %s", servent->s_proto); + } + + fd = socket(PF_INET, SOCK_STREAM, protoent->p_proto); + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + if (h) { + memcpy((char *)&(sockaddr.sin_addr.s_addr), + (char *) hostent->h_addr_list[0], + (size_t) hostent->h_length); + } + else { + sockaddr.sin_addr.s_addr = INADDR_ANY; + } + sockaddr.sin_port = servent->s_port; + + if (type == INET_SERVER) { + status = 1; + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&status,sizeof(status)); + status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "bind(2)"; + } + else { +#if defined(THREAD) && defined(HAVE_FCNTL) + status = thread_connect(fd, (struct sockaddr*)&sockaddr, + sizeof(sockaddr), type); +#else +#ifdef SOCKS + if (type == INET_SOCKS) { + status = Rconnect(fd, &sockaddr, sizeof(sockaddr)); + } + else +#endif + { + status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + } +#endif + syscall = "connect(2)"; + } + + if (status < 0) { + close (fd); + rb_sys_fail(syscall); + } + if (type == INET_SERVER) listen(fd, 5); + + /* create new instance */ + sock = sock_new(class, fd); + + return sock; +} + +static VALUE +tcp_s_open(class, host, serv) + VALUE class, host, serv; +{ + Check_SafeStr(host); + return open_inet(class, host, serv, INET_CLIENT); +} + +#ifdef SOCKS +static VALUE +socks_s_open(class, host, serv) + VALUE class, host, serv; +{ + static init = 0; + + if (init == 0) { + SOCKSinit("ruby"); + init = 1; + } + + Check_SafeStr(host); + return open_inet(class, host, serv, INET_SOCKS); +} +#endif + +static VALUE +tcp_svr_s_open(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + VALUE arg1, arg2; + + if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) + return open_inet(class, arg1, arg2, INET_SERVER); + else + return open_inet(class, 0, arg1, INET_SERVER); +} + +static VALUE +s_accept(class, fd, sockaddr, len) + VALUE class; + int fd; + struct sockaddr *sockaddr; + int *len; +{ + int fd2; + + retry: +#ifdef THREAD + thread_wait_fd(fd); +#endif + TRAP_BEG; + fd2 = accept(fd, sockaddr, len); + TRAP_END; + if (fd2 < 0) { + switch (errno) { + case EINTR: + case EWOULDBLOCK: +#if EAGAIN != EWOULDBLOCK + case EAGAIN: +#endif +#ifdef THREAD + thread_schedule(); +#endif + goto retry; + } + rb_sys_fail(0); + } + return sock_new(class, fd2); +} + +static VALUE +tcp_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in from; + int fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(struct sockaddr_in); + return s_accept(cTCPsocket, fileno(fptr->f), + (struct sockaddr*)&from, &fromlen); +} + +#ifdef HAVE_SYS_UN_H +static VALUE +open_unix(class, path, server) + VALUE class; + struct RString *path; + int server; +{ + struct sockaddr_un sockaddr; + int fd, status; + VALUE sock; + OpenFile *fptr; + + Check_SafeStr(path); + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) rb_sys_fail("socket(2)"); + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sun_family = AF_UNIX; + strncpy(sockaddr.sun_path, path->ptr, sizeof(sockaddr.sun_path)-1); + sockaddr.sun_path[sizeof(sockaddr.sun_path)-1] = '\0'; + + if (server) { + status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + } + else { + status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + } + + if (status < 0) { + close(fd); + rb_sys_fail(sockaddr.sun_path); + } + + if (server) listen(fd, 5); + + sock = sock_new(class, fd); + GetOpenFile(sock, fptr); + fptr->path = strdup(path->ptr); + + return sock; +} +#endif + +static void +setipaddr(name, addr) + char *name; + struct sockaddr_in *addr; +{ + int d1, d2, d3, d4; + char ch; + struct hostent *hp; + long x; + + if (name[0] == 0) { + addr->sin_addr.s_addr = INADDR_ANY; + } + else if (name[0] == '<' && strcmp(name, "") == 0) { + addr->sin_addr.s_addr = INADDR_BROADCAST; + } + else if (sscanf(name, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 && + 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 && + 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) { + addr->sin_addr.s_addr = htonl( + ((long) d1 << 24) | ((long) d2 << 16) | + ((long) d3 << 8) | ((long) d4 << 0)); + } + else { + hp = gethostbyname(name); + if (!hp) { +#ifdef HAVE_HSTRERROR + extern int h_errno; + Raise(eSocket, (char *)hstrerror(h_errno)); +#else + Raise(eSocket, "host not found"); +#endif + } + memcpy((char *) &addr->sin_addr, hp->h_addr, hp->h_length); + } +} + +static VALUE +mkipaddr(x) + unsigned long x; +{ + char buf[16]; + + x = ntohl(x); + sprintf(buf, "%d.%d.%d.%d", + (int) (x>>24) & 0xff, (int) (x>>16) & 0xff, + (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff); + return str_new2(buf); +} + +static VALUE +tcpaddr(sockaddr) + struct sockaddr_in *sockaddr; +{ + VALUE family, port, addr1, addr2; + VALUE ary; + struct hostent *hostent; + + family = str_new2("AF_INET"); + hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr, + sizeof(sockaddr->sin_addr), + AF_INET); + addr1 = 0; + if (hostent) { + addr1 = str_new2(hostent->h_name); + } + addr2 = mkipaddr(sockaddr->sin_addr.s_addr); + if (!addr1) addr1 = addr2; + + port = INT2FIX(ntohs(sockaddr->sin_port)); + ary = ary_new3(4, family, port, addr1, addr2); + + return ary; +} + +static VALUE +tcp_addr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return tcpaddr(&addr); +} + +static VALUE +tcp_peeraddr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getpeername(2)"); + return tcpaddr(&addr); +} + +static VALUE +tcp_recvfrom(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + return s_recv(sock, argc, argv, 1); +} + +static VALUE +tcp_s_getaddress(obj, host) + VALUE obj, host; +{ + struct sockaddr_in addr; + struct hostent *h; + + if (obj_is_kind_of(host, cInteger)) { + int i = NUM2INT(host); + addr.sin_addr.s_addr = htonl(i); + } + else { + Check_Type(host, T_STRING); + setipaddr(RSTRING(host)->ptr, &addr); + } + + return mkipaddr(addr.sin_addr.s_addr); +} + +#ifdef HAVE_SYS_UN_H +static VALUE +unix_s_sock_open(sock, path) + VALUE sock, path; +{ + return open_unix(sock, path, 0); +} + +static VALUE +unix_path(sock) + VALUE sock; +{ + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (fptr->path == 0) { + struct sockaddr_un addr; + int len = sizeof(addr); + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail(0); + fptr->path = strdup(addr.sun_path); + } + return str_new2(fptr->path); +} + +static VALUE +unix_svr_s_open(class, path) + VALUE class, path; +{ + return open_unix(class, path, 1); +} + +static VALUE +unix_recvfrom(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + return s_recv(sock, argc, argv, 2); +} + +static VALUE +unix_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un from; + int fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(struct sockaddr_un); + return s_accept(cUNIXsocket, fileno(fptr->f), + (struct sockaddr*)&from, &fromlen); +} + +static VALUE +unixaddr(sockaddr) + struct sockaddr_un *sockaddr; +{ + return assoc_new(str_new2("AF_UNIX"),str_new2(sockaddr->sun_path)); +} + +static VALUE +unix_addr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return unixaddr(&addr); +} + +static VALUE +unix_peeraddr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return unixaddr(&addr); +} +#endif + +static void +setup_domain_and_type(domain, dv, type, tv) + VALUE domain, type; + int *dv, *tv; +{ + char *ptr; + + if (TYPE(domain) == T_STRING) { + ptr = RSTRING(domain)->ptr; + if (strcmp(ptr, "PF_INET") == 0) + *dv = PF_INET; +#ifdef PF_UNIX + else if (strcmp(ptr, "PF_UNIX") == 0) + *dv = PF_UNIX; +#endif +#ifdef PF_IMPLINK + else if (strcmp(ptr, "PF_IMPLINK") == 0) + *dv = PF_IMPLINK; +#endif +#ifdef PF_AX25 + else if (strcmp(ptr, "PF_AX25") == 0) + *dv = PF_AX25; +#endif +#ifdef PF_IPX + else if (strcmp(ptr, "PF_IPX") == 0) + *dv = PF_IPX; +#endif + else + Raise(eSocket, "Unknown socket domain %s", ptr); + } + else { + *dv = NUM2INT(domain); + } + if (TYPE(type) == T_STRING) { + ptr = RSTRING(type)->ptr; + if (strcmp(ptr, "SOCK_STREAM") == 0) + *tv = SOCK_STREAM; + else if (strcmp(ptr, "SOCK_DGRAM") == 0) + *tv = SOCK_DGRAM; +#ifdef SOCK_RAW + else if (strcmp(ptr, "SOCK_RAW") == 0) + *tv = SOCK_RAW; +#endif +#ifdef SOCK_SEQPACKET + else if (strcmp(ptr, "SOCK_SEQPACKET") == 0) + *tv = SOCK_SEQPACKET; +#endif +#ifdef SOCK_RDM + else if (strcmp(ptr, "SOCK_RDM") == 0) + *tv = SOCK_RDM; +#endif +#ifdef SOCK_PACKET + else if (strcmp(ptr, "SOCK_PACKET") == 0) + *tv = SOCK_PACKET; +#endif + else + Raise(eSocket, "Unknown socket type %s", ptr); + } + else { + *tv = NUM2INT(type); + } +} + +static VALUE +sock_s_open(class, domain, type, protocol) + VALUE class, domain, type, protocol; +{ + int fd; + int d, t; + + setup_domain_and_type(domain, &d, type, &t); + fd = socket(d, t, NUM2INT(protocol)); + if (fd < 0) rb_sys_fail("socket(2)"); + return sock_new(class, fd); +} + +static VALUE +sock_s_for_fd(class, fd) + VALUE class, fd; +{ + return sock_new(class, NUM2INT(fd)); +} + +static VALUE +sock_s_socketpair(class, domain, type, protocol) + VALUE class, domain, type, protocol; +{ +#if !defined(__CYGWIN32__) && !defined(NT) + int fd; + int d, t, sp[2]; + + setup_domain_and_type(domain, &d, type, &t); + if (socketpair(d, t, NUM2INT(protocol), sp) < 0) + rb_sys_fail("socketpair(2)"); + + return assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1])); +#else + rb_notimplement(); +#endif +} + +static VALUE +sock_connect(sock, addr) + VALUE sock; + struct RString *addr; +{ + OpenFile *fptr; + + Check_Type(addr, T_STRING); + str_modify(addr); + + GetOpenFile(sock, fptr); + retry: + if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) { + switch (errno) { + case EINTR: + case EWOULDBLOCK: +#if EAGAIN != EWOULDBLOCK + case EAGAIN: +#endif +#ifdef THREAD + thread_schedule(); +#endif + goto retry; + } + rb_sys_fail("connect(2)"); + } + + return INT2FIX(0); +} + +static VALUE +sock_bind(sock, addr) + VALUE sock; + struct RString *addr; +{ + OpenFile *fptr; + + Check_Type(addr, T_STRING); + str_modify(addr); + + GetOpenFile(sock, fptr); + if (bind(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) + rb_sys_fail("bind(2)"); + + return INT2FIX(0); +} + +static VALUE +sock_listen(sock, log) + VALUE sock, log; +{ + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (listen(fileno(fptr->f), NUM2INT(log)) < 0) + rb_sys_fail("listen(2)"); + + return INT2FIX(0); +} + +static VALUE +sock_recvfrom(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + return s_recv(sock, argc, argv, 3); +} + +static VALUE +sock_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + VALUE addr, sock2; + char buf[1024]; + int len = sizeof buf; + + GetOpenFile(sock, fptr); + sock2 = s_accept(cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len); + + return assoc_new(sock2, str_new(buf, len)); +} + +#ifdef HAVE_GETHOSTNAME +static VALUE +sock_gethostname(obj) + VALUE obj; +{ + char buf[1024]; + + if (gethostname(buf, (int)sizeof buf - 1) < 0) + rb_sys_fail("gethostname"); + + buf[sizeof buf - 1] = '\0'; + return str_new2(buf); +} +#else +#ifdef HAVE_UNAME + +#include + +static VALUE +sock_gethostname(obj) + VALUE obj; +{ + struct utsname un; + + uname(&un); + return str_new2(un.nodename); +} +#else +static VALUE +sock_gethostname(obj) + VALUE obj; +{ + rb_notimplement(); +} +#endif +#endif + +static VALUE +mkhostent(h) + struct hostent *h; +{ + struct sockaddr_in addr; + char **pch; + VALUE ary, names; + + if (h == NULL) { +#ifdef HAVE_HSTRERROR + extern int h_errno; + Raise(eSocket, (char *)hstrerror(h_errno)); +#else + Raise(eSocket, "host not found"); +#endif + } + ary = ary_new(); + ary_push(ary, str_new2(h->h_name)); + names = ary_new(); + ary_push(ary, names); + for (pch = h->h_aliases; *pch; pch++) { + ary_push(names, str_new2(*pch)); + } + ary_push(ary, INT2FIX(h->h_length)); +#ifdef h_addr + for (pch = h->h_addr_list; *pch; pch++) { + ary_push(ary, str_new(*pch, h->h_length)); + } +#else + ary_push(ary, str_new(h->h_addr, h->h_length)); +#endif + + return ary; +} + +static VALUE +sock_s_gethostbyname(obj, host) + VALUE obj, host; +{ + struct sockaddr_in addr; + struct hostent *h; + + if (obj_is_kind_of(host, cInteger)) { + int i = NUM2INT(host); + addr.sin_addr.s_addr = htonl(i); + } + else { + Check_Type(host, T_STRING); + setipaddr(RSTRING(host)->ptr, &addr); + } + h = gethostbyaddr((char *)&addr.sin_addr, + sizeof(addr.sin_addr), + AF_INET); + + return mkhostent(h); +} + +static VALUE +sock_s_gethostbyaddr(argc, argv) + int argc; + VALUE *argv; +{ + VALUE vaddr, vtype; + int type; + + struct sockaddr_in *addr; + struct hostent *h; + + rb_scan_args(argc, argv, "11", &addr, &type); + Check_Type(addr, T_STRING); + if (!NIL_P(type)) { + type = NUM2INT(vtype); + } + else { + type = AF_INET; + } + + h = gethostbyaddr(RSTRING(addr)->ptr, RSTRING(addr)->len, type); + + return mkhostent(h); +} + +static VALUE +sock_s_getservbyaname(argc, argv) + int argc; + VALUE *argv; +{ + VALUE service, protocol; + char *name, *proto; + struct servent *sp; + int port; + + rb_scan_args(argc, argv, "11", &service, &protocol); + Check_Type(service, T_STRING); + if (NIL_P(protocol)) proto = "tcp"; + else proto = RSTRING(protocol)->ptr; + + sp = getservbyname(RSTRING(service)->ptr, proto); + if (!sp) { + Raise(eSocket, "service/proto not found"); + } + port = ntohs(sp->s_port); + + return INT2FIX(port); +} + +Init_socket() +{ + eSocket = rb_define_class("SocketError", eException); + + cBasicSocket = rb_define_class("BasicSocket", cIO); + rb_undef_method(CLASS_OF(cBasicSocket), "new"); + rb_define_method(cBasicSocket, "shutdown", bsock_shutdown, -1); + rb_define_method(cBasicSocket, "setsockopt", bsock_setsockopt, 3); + rb_define_method(cBasicSocket, "getsockopt", bsock_getsockopt, 2); + rb_define_method(cBasicSocket, "getsockname", bsock_getsockname, 0); + rb_define_method(cBasicSocket, "getpeername", bsock_getpeername, 0); + rb_define_method(cBasicSocket, "send", bsock_send, -1); + rb_define_method(cBasicSocket, "recv", bsock_recv, -1); + + cTCPsocket = rb_define_class("TCPsocket", cBasicSocket); + rb_define_singleton_method(cTCPsocket, "open", tcp_s_open, 2); + rb_define_singleton_method(cTCPsocket, "new", tcp_s_open, 2); + rb_define_method(cTCPsocket, "addr", tcp_addr, 0); + rb_define_method(cTCPsocket, "peeraddr", tcp_peeraddr, 0); + rb_define_singleton_method(cTCPsocket, "getaddress", tcp_s_getaddress, 1); + rb_define_method(cTCPsocket, "recvfrom", tcp_recvfrom, -1); + +#ifdef SOCKS + cSOCKSsocket = rb_define_class("SOCKSsocket", cTCPsocket); + rb_define_singleton_method(cSOCKSsocket, "open", socks_s_open, 2); + rb_define_singleton_method(cSOCKSsocket, "new", socks_s_open, 2); +#endif + + cTCPserver = rb_define_class("TCPserver", cTCPsocket); + rb_define_singleton_method(cTCPserver, "open", tcp_svr_s_open, -1); + rb_define_singleton_method(cTCPserver, "new", tcp_svr_s_open, -1); + rb_define_method(cTCPserver, "accept", tcp_accept, 0); + +#ifdef HAVE_SYS_UN_H + cUNIXsocket = rb_define_class("UNIXsocket", cBasicSocket); + rb_define_singleton_method(cUNIXsocket, "open", unix_s_sock_open, 1); + rb_define_singleton_method(cUNIXsocket, "new", unix_s_sock_open, 1); + rb_define_method(cUNIXsocket, "path", unix_path, 0); + rb_define_method(cUNIXsocket, "addr", unix_addr, 0); + rb_define_method(cUNIXsocket, "peeraddr", unix_peeraddr, 0); + rb_define_method(cUNIXsocket, "recvfrom", unix_recvfrom, -1); + + cUNIXserver = rb_define_class("UNIXserver", cUNIXsocket); + rb_define_singleton_method(cUNIXserver, "open", unix_svr_s_open, 1); + rb_define_singleton_method(cUNIXserver, "new", unix_svr_s_open, 1); + rb_define_method(cUNIXserver, "accept", unix_accept, 0); +#endif + + cSocket = rb_define_class("Socket", cBasicSocket); + rb_define_singleton_method(cSocket, "open", sock_s_open, 3); + rb_define_singleton_method(cSocket, "new", sock_s_open, 3); + rb_define_singleton_method(cSocket, "for_fd", sock_s_for_fd, 1); + + rb_define_method(cSocket, "connect", sock_connect, 1); + rb_define_method(cSocket, "bind", sock_bind, 1); + rb_define_method(cSocket, "listen", sock_listen, 1); + rb_define_method(cSocket, "accept", sock_accept, 0); + + rb_define_method(cSocket, "recvfrom", sock_recvfrom, -1); + + rb_define_singleton_method(cSocket, "socketpair", sock_s_socketpair, 3); + rb_define_singleton_method(cSocket, "pair", sock_s_socketpair, 3); + rb_define_singleton_method(cSocket, "gethostname", sock_gethostname, 0); + rb_define_singleton_method(cSocket, "gethostbyname", sock_s_gethostbyname, 1); + rb_define_singleton_method(cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1); + rb_define_singleton_method(cSocket, "getservbyname", sock_s_getservbyaname, -1); + + /* constants */ + rb_define_const(cSocket, "SOCK_STREAM", INT2FIX(SOCK_STREAM)); + rb_define_const(cSocket, "SOCK_DGRAM", INT2FIX(SOCK_DGRAM)); + rb_define_const(cSocket, "SOCK_RAW", INT2FIX(SOCK_RAW)); +#ifdef SOCK_RDM + rb_define_const(cSocket, "SOCK_RDM", INT2FIX(SOCK_RDM)); +#endif +#ifdef SOCK_SEQPACKET + rb_define_const(cSocket, "SOCK_SEQPACKET", INT2FIX(SOCK_SEQPACKET)); +#endif +#ifdef SOCK_PACKET + rb_define_const(cSocket, "SOCK_PACKET", INT2FIX(SOCK_PACKET)); +#endif + + rb_define_const(cSocket, "AF_INET", INT2FIX(AF_INET)); + rb_define_const(cSocket, "PF_INET", INT2FIX(PF_INET)); +#ifdef AF_UNIX + rb_define_const(cSocket, "AF_UNIX", INT2FIX(AF_UNIX)); + rb_define_const(cSocket, "PF_UNIX", INT2FIX(PF_UNIX)); +#endif +#ifdef AF_AX25 + rb_define_const(cSocket, "AF_AX25", INT2FIX(AF_AX25)); + rb_define_const(cSocket, "PF_AX25", INT2FIX(PF_AX25)); +#endif +#ifdef AF_IPX + rb_define_const(cSocket, "AF_IPX", INT2FIX(AF_IPX)); + rb_define_const(cSocket, "PF_IPX", INT2FIX(PF_IPX)); +#endif +#ifdef AF_APPLETALK + rb_define_const(cSocket, "AF_APPLETALK", INT2FIX(AF_APPLETALK)); + rb_define_const(cSocket, "PF_APPLETALK", INT2FIX(PF_APPLETALK)); +#endif + + rb_define_const(cSocket, "MSG_OOB", INT2FIX(MSG_OOB)); + rb_define_const(cSocket, "MSG_PEEK", INT2FIX(MSG_PEEK)); + rb_define_const(cSocket, "MSG_DONTROUTE", INT2FIX(MSG_DONTROUTE)); + + rb_define_const(cSocket, "SOL_SOCKET", INT2FIX(SOL_SOCKET)); +#ifdef SOL_IP + rb_define_const(cSocket, "SOL_IP", INT2FIX(SOL_IP)); +#endif +#ifdef SOL_IPX + rb_define_const(cSocket, "SOL_IPX", INT2FIX(SOL_IPX)); +#endif +#ifdef SOL_AX25 + rb_define_const(cSocket, "SOL_AX25", INT2FIX(SOL_AX25)); +#endif +#ifdef SOL_ATALK + rb_define_const(cSocket, "SOL_ATALK", INT2FIX(SOL_ATALK)); +#endif +#ifdef SOL_TCP + rb_define_const(cSocket, "SOL_TCP", INT2FIX(SOL_TCP)); +#endif +#ifdef SOL_UDP + rb_define_const(cSocket, "SOL_UDP", INT2FIX(SOL_UDP)); +#endif + +#ifdef SO_DEBUG + rb_define_const(cSocket, "SO_DEBUG", INT2FIX(SO_DEBUG)); +#endif + rb_define_const(cSocket, "SO_REUSEADDR", INT2FIX(SO_REUSEADDR)); +#ifdef SO_TYPE + rb_define_const(cSocket, "SO_TYPE", INT2FIX(SO_TYPE)); +#endif +#ifdef SO_ERROR + rb_define_const(cSocket, "SO_ERROR", INT2FIX(SO_ERROR)); +#endif +#ifdef SO_DONTROUTE + rb_define_const(cSocket, "SO_DONTROUTE", INT2FIX(SO_DONTROUTE)); +#endif +#ifdef SO_BROADCAST + rb_define_const(cSocket, "SO_BROADCAST", INT2FIX(SO_BROADCAST)); +#endif +#ifdef SO_SNDBUF + rb_define_const(cSocket, "SO_SNDBUF", INT2FIX(SO_SNDBUF)); +#endif +#ifdef SO_RCVBUF + rb_define_const(cSocket, "SO_RCVBUF", INT2FIX(SO_RCVBUF)); +#endif + rb_define_const(cSocket, "SO_KEEPALIVE", INT2FIX(SO_KEEPALIVE)); +#ifdef SO_OOBINLINE + rb_define_const(cSocket, "SO_OOBINLINE", INT2FIX(SO_OOBINLINE)); +#endif +#ifdef SO_NO_CHECK + rb_define_const(cSocket, "SO_NO_CHECK", INT2FIX(SO_NO_CHECK)); +#endif +#ifdef SO_PRIORITY + rb_define_const(cSocket, "SO_PRIORITY", INT2FIX(SO_PRIORITY)); +#endif + rb_define_const(cSocket, "SO_LINGER", INT2FIX(SO_LINGER)); + +#ifdef SOPRI_INTERACTIVE + rb_define_const(cSocket, "SOPRI_INTERACTIVE", INT2FIX(SOPRI_INTERACTIVE)); +#endif +#ifdef SOPRI_NORMAL + rb_define_const(cSocket, "SOPRI_NORMAL", INT2FIX(SOPRI_NORMAL)); +#endif +#ifdef SOPRI_BACKGROUND + rb_define_const(cSocket, "SOPRI_BACKGROUND", INT2FIX(SOPRI_BACKGROUND)); +#endif + +#ifdef IP_MULTICAST_IF + rb_define_const(cSocket, "IP_MULTICAST_IF", INT2FIX(IP_MULTICAST_IF)); +#endif +#ifdef IP_MULTICAST_TTL + rb_define_const(cSocket, "IP_MULTICAST_TTL", INT2FIX(IP_MULTICAST_TTL)); +#endif +#ifdef IP_MULTICAST_LOOP + rb_define_const(cSocket, "IP_MULTICAST_LOOP", INT2FIX(IP_MULTICAST_LOOP)); +#endif +#ifdef IP_ADD_MEMBERSHIP + rb_define_const(cSocket, "IP_ADD_MEMBERSHIP", INT2FIX(IP_ADD_MEMBERSHIP)); +#endif + +#ifdef IP_DEFAULT_MULTICAST_TTL + rb_define_const(cSocket, "IP_DEFAULT_MULTICAST_TTL", INT2FIX(IP_DEFAULT_MULTICAST_TTL)); +#endif +#ifdef IP_DEFAULT_MULTICAST_LOOP + rb_define_const(cSocket, "IP_DEFAULT_MULTICAST_LOOP", INT2FIX(IP_DEFAULT_MULTICAST_LOOP)); +#endif +#ifdef IP_MAX_MEMBERSHIPS + rb_define_const(cSocket, "IP_MAX_MEMBERSHIPS", INT2FIX(IP_MAX_MEMBERSHIPS)); +#endif + +#ifdef IPX_TYPE + rb_define_const(cSocket, "IPX_TYPE", INT2FIX(IPX_TYPE)); +#endif + +#ifdef TCP_NODELAY + rb_define_const(cSocket, "TCP_NODELAY", INT2FIX(TCP_NODELAY)); +#endif +#ifdef TCP_MAXSEG + rb_define_const(cSocket, "TCP_MAXSEG", INT2FIX(TCP_MAXSEG)); +#endif +} diff --git a/ext/tkutil/MANIFEST b/ext/tkutil/MANIFEST new file mode 100644 index 0000000000..870e04b586 --- /dev/null +++ b/ext/tkutil/MANIFEST @@ -0,0 +1,3 @@ +MANIFEST +tkutil.c +depend diff --git a/ext/tkutil/depend b/ext/tkutil/depend new file mode 100644 index 0000000000..ead83eda57 --- /dev/null +++ b/ext/tkutil/depend @@ -0,0 +1 @@ +tkutil.o: tkutil.c ../../ruby.h ../../config.h ../../defines.h diff --git a/ext/tkutil/tkutil.c b/ext/tkutil/tkutil.c new file mode 100644 index 0000000000..540995eb82 --- /dev/null +++ b/ext/tkutil/tkutil.c @@ -0,0 +1,46 @@ +/************************************************ + + tk.c - + + $Author$ + $Date$ + created at: Fri Nov 3 00:47:54 JST 1995 + +************************************************/ + +#include "ruby.h" + +static VALUE +tk_eval_cmd(argc, argv) + int argc; + VALUE argv[]; +{ + VALUE cmd, rest; + + rb_scan_args(argc, argv, "1*", &cmd, &rest); + rb_eval_cmd(cmd, rest); + return Qnil; +} + +static VALUE +tk_s_new(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + VALUE obj = obj_alloc(class); + + rb_funcall2(obj, rb_intern("initialize"), argc, argv); + if (iterator_p()) rb_yield_0(obj, obj); + return obj; +} + +Init_tkutil() +{ + VALUE mTK = rb_define_module("TkUtil"); + VALUE cTK = rb_define_class("TkKernel", cObject); + + rb_define_singleton_method(mTK, "eval_cmd", tk_eval_cmd, -1); + + rb_define_singleton_method(cTK, "new", tk_s_new, -1); +} -- cgit v1.2.3