home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 4 / AACD04.ISO / AACD / Programming / Python / Source / Modules / amigamodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-18  |  27.7 KB  |  1,274 lines

  1. /**************************************************************\
  2. **                                                            **
  3. **  AMIGA module implementation, for SAS/C version 6.58       **
  4. **                                                            **
  5. **  Made by Irmen de Jong (irmen@bigfoot.com)                 **
  6. **                                                            **
  7. **  27-mar-96: Added a lot of AmiTCP functions!               **
  8. **   2-apr-96: Many small fixes & enhancements.               **
  9. **  11-apr-96: Totally rewritten the environment handling.    **
  10. **             Now creates 4 separate dictionaries.           **
  11. **             Fixed link(), added symlink() and readlink().  **
  12. **  29-may-96: Added filenote() and fullpath()                **
  13. **  11-jun-96: Moved filenote() to doslib/SetComment          **
  14. **  12-jun-96: Removed execv                                  **
  15. **  29-Aug-96: fixed getcwd(), some minor errno fixes         **
  16. **  26-Dec-96: upgraded to 1.4: added putenv(), remove()      **
  17. **             fixed mkdir: default protbits (0777)           **
  18. **   6-Apr-97: fixed bug in readlink (lock was incorrect)     **
  19. **   6-Nov-97: added uname()                                  **
  20. **  12-Jan-98: upgraded to 1.5: fixed includes, new names,    **
  21. **             uses new Amiga/.../unixemul.c                  **
  22. **  28-Mar-98: fixed buffer overflow bug in convertenviron()  **
  23. **  27-Sep-98: added crc32 function                           **
  24. **  24-Dec-98: moved bunch of #defines to config.h            **
  25. **  25-Dec-98: added I-Net 225 support                        **
  26. **                                                            **
  27. **  Adapted from posixmodule.c; implements as much of the     **
  28. **  functionality of this module as possible.                 **
  29. **                                                            **
  30. **                                                            **
  31. **  TO DO: Implement execv(e) and threads (if possible).      **
  32. **                                                            **
  33. **  NOTE: Don't forget __io2errno conversion!!!!!!!!!!!!!!!!  **
  34. **                                                            **
  35. \**************************************************************/
  36.  
  37.  
  38. #include "Python.h"
  39. #include "osdefs.h"
  40.  
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <errno.h>
  44. #include <stat.h>
  45. #ifndef INET225
  46. #include <dos.h>
  47. #endif
  48. #include <proto/dos.h>
  49. #include <proto/exec.h>
  50. #include <dos/dosextens.h>
  51. #include <dos/var.h>
  52. #include <dos/dostags.h>
  53. #include <exec/execbase.h>
  54.  
  55. #include "mytime.h"     /* For clock_t on some systems */
  56.  
  57. #ifdef HAVE_UTIME_H
  58. #include <utime.h>
  59. #endif
  60.  
  61. #include <dirent.h>
  62. #define NAMLEN(dirent) strlen((dirent)->d_name)
  63.  
  64. #ifdef AMITCP
  65. #include <clib/netlib_protos.h>
  66. #endif
  67.  
  68. #ifdef INET225
  69. #include <proto/socket.h>
  70. static int _OSERR;
  71. #define getegid() getgid()
  72. #define geteuid() getuid()
  73. static __inline int dup(int oldsd) { return s_dup(oldsd); }
  74. static __inline int dup2(int oldsd, int newsd) { return s_dup2(oldsd, newsd); }
  75. #endif
  76.  
  77. #include "protos.h"
  78.  
  79. /* Return a dictionary corresponding to the AmigaDOS environment table. */
  80. /* That is, scan ENV: for global environment variables.                 */
  81. /* The local shell environment variables are put into another table.    */
  82.  
  83. static int
  84. convertenviron(PyObject **glob, PyObject **loc,
  85.                PyObject **both, PyObject **aliases)
  86. {
  87.     BPTR dlok;
  88.     struct FileInfoBlock __aligned fib;
  89.     PyObject *v;
  90.     char *dynbuf;
  91.     struct LocalVar *lvar;
  92.     struct List *localvars;
  93.  
  94.     *glob=PyDict_New();
  95.     *loc=PyDict_New();
  96.     *both=PyDict_New();
  97.     *aliases=PyDict_New();
  98.  
  99.     if(!*glob || !*loc || !*both || !*aliases)
  100.     {
  101.         if(*glob) Py_DECREF(*glob);
  102.         if(*loc) Py_DECREF(*loc);
  103.         if(*both) Py_DECREF(*both);
  104.         if(*aliases) Py_DECREF(*aliases);
  105.         return 0;
  106.     }
  107.  
  108.     /* Read global vars from ENV: */
  109.     /* Put them in 'glob' and in 'both'. */
  110.  
  111.     if(dlok=Lock("ENV:",ACCESS_READ))
  112.     {
  113.         if(Examine(dlok,&fib))
  114.         {
  115.             while(ExNext(dlok,&fib))
  116.             {
  117.                 if(fib.fib_DirEntryType<0)
  118.                 {
  119.                     if(dynbuf=malloc(fib.fib_Size+1))
  120.                     {
  121.                         int len=GetVar(fib.fib_FileName,dynbuf,fib.fib_Size+1,GVF_GLOBAL_ONLY);
  122.                         if(len>=0 && (v=PyString_FromString(dynbuf)))
  123.                         {
  124.                             PyDict_SetItemString(*glob,fib.fib_FileName,v);
  125.                             PyDict_SetItemString(*both,fib.fib_FileName,v);
  126.                             Py_DECREF(v);
  127.                         }
  128.                         free(dynbuf);
  129.                     }
  130.                 }
  131.             }
  132.         }
  133.     }
  134.  
  135.     if(dlok) UnLock(dlok);
  136.  
  137.     /* Scan the local shell environment, including "RC" and "Result2"!   */
  138.     /* Put shell vars in 'loc' and 'both', and aliases in 'aliases'. */
  139.     /* Because of the fact that the inserting of local vars into 'both' */
  140.     /* happens AFTER the insertion of global vars, the formor overwrite */
  141.     /* the latter, and thus have higher priority (as it should be). */
  142.  
  143.     localvars = (struct List*) &((struct Process*)FindTask(0))->pr_LocalVars;
  144.  
  145.     if(!IsListEmpty(localvars))
  146.     {
  147.         lvar = (struct LocalVar*) localvars->lh_Head;
  148.         do {
  149.             if(dynbuf=malloc(lvar->lv_Len+1))
  150.             {
  151.                 strncpy(dynbuf,lvar->lv_Value,lvar->lv_Len);
  152.                 dynbuf[lvar->lv_Len]=0;
  153.  
  154.                 if(v=PyString_FromString(dynbuf))
  155.                 {
  156.                     if(lvar->lv_Node.ln_Type==LV_VAR)
  157.                     {
  158.                         PyDict_SetItemString(*loc,lvar->lv_Node.ln_Name,v);
  159.                         PyDict_SetItemString(*both,lvar->lv_Node.ln_Name,v);
  160.                     }
  161.                     else if(lvar->lv_Node.ln_Type==LV_ALIAS)
  162.                         PyDict_SetItemString(*aliases,lvar->lv_Node.ln_Name,v);
  163.  
  164.                     Py_DECREF(v);
  165.                 }
  166.                 free(dynbuf);
  167.             }
  168.         } while((lvar=(struct LocalVar*)lvar->lv_Node.ln_Succ)->lv_Node.ln_Succ);
  169.     }
  170.  
  171.  
  172.     return 1;
  173. }
  174.  
  175.  
  176. /* Set a Amiga-specific error from errno, and return NULL */
  177.  
  178. static PyObject * amiga_error(void)
  179. {
  180.     return PyErr_SetFromErrno(PyExc_OSError);
  181. }
  182. static PyObject * amiga_error_with_filename(char *name)
  183. {
  184.     return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
  185. }
  186.  
  187.  
  188. /* AMIGA generic methods */
  189.  
  190. static PyObject *
  191. amiga_1str(PyObject *args, int (*func)(const char *))
  192. {
  193.     char *path1;
  194.     int res;
  195.     if (!PyArg_Parse(args, "s", &path1))
  196.         return NULL;
  197.     Py_BEGIN_ALLOW_THREADS
  198.     res = (*func)(path1);
  199.     Py_END_ALLOW_THREADS
  200.     if (res < 0)
  201.         return amiga_error_with_filename(path1);
  202.     Py_INCREF(Py_None);
  203.     return Py_None;
  204. }
  205.  
  206. static PyObject *
  207. amiga_2str(PyObject *args, int (*func)(const char *, const char *))
  208. {
  209.     char *path1, *path2;
  210.     int res;
  211.     if (!PyArg_Parse(args, "(ss)", &path1, &path2))
  212.         return NULL;
  213.     Py_BEGIN_ALLOW_THREADS
  214.     res = (*func)(path1, path2);
  215.     Py_END_ALLOW_THREADS
  216.     if (res < 0)
  217.         return amiga_error();
  218.     Py_INCREF(Py_None);
  219.     return Py_None;
  220. }
  221.  
  222. static PyObject *
  223. amiga_strint(PyObject *args, int (*func)(const char *, int))
  224. {
  225.     char *path;
  226.     int i;
  227.     int res;
  228.     if (!PyArg_Parse(args, "(si)", &path, &i))
  229.         return NULL;
  230.     Py_BEGIN_ALLOW_THREADS
  231.     res = (*func)(path, i);
  232.     Py_END_ALLOW_THREADS
  233.     if (res < 0)
  234.         return amiga_error_with_filename(path);
  235.     Py_INCREF(Py_None);
  236.     return Py_None;
  237. }
  238.  
  239. static PyObject *
  240. amiga_strintint(PyObject *args, int (*func)(const char *, int, int))
  241. {
  242.     char *path;
  243.     int i,i2;
  244.     int res;
  245.     if (!PyArg_Parse(args, "(sii)", &path, &i, &i2))
  246.         return NULL;
  247.     Py_BEGIN_ALLOW_THREADS
  248.     res = (*func)(path, i, i2);
  249.     Py_END_ALLOW_THREADS
  250.     if (res < 0)
  251.         return amiga_error_with_filename(path);
  252.     Py_INCREF(Py_None);
  253.     return Py_None;
  254. }
  255.  
  256. static PyObject *
  257. amiga_do_stat(PyObject *self, PyObject *args, int (*statfunc)(const char *, struct stat *))
  258. {
  259.     struct stat st;
  260.     char *path;
  261.     int res;
  262.     if (!PyArg_Parse(args, "s", &path))
  263.         return NULL;
  264.     Py_BEGIN_ALLOW_THREADS
  265.     res = (*statfunc)(path, &st);
  266.     Py_END_ALLOW_THREADS
  267.     if (res != 0)
  268.         return amiga_error_with_filename(path);
  269.     return Py_BuildValue("(llllllllll)",
  270.             (long)st.st_mode,
  271.             (long)st.st_ino,
  272.             (long)st.st_dev,
  273.             (long)st.st_nlink,
  274.             (long)st.st_uid,
  275.             (long)st.st_gid,
  276.             (long)st.st_size,
  277.             (long)st.st_atime,
  278.             (long)st.st_mtime,
  279.             (long)st.st_ctime);
  280. }
  281.  
  282.  
  283. /* AMIGA methods */
  284.  
  285. static PyObject *
  286. amiga_chdir(PyObject *self, PyObject *args)
  287. {
  288.     return amiga_1str(args, chdir);
  289. }
  290.  
  291. static PyObject *
  292. amiga_chmod(PyObject *self, PyObject *args)
  293. {
  294.     return amiga_strint(args, chmod);
  295. }
  296.  
  297. #ifdef HAVE_CHOWN
  298. static PyObject *
  299. amiga_chown(PyObject *self, PyObject *args)
  300. {
  301.     return amiga_strintint(args, chown);
  302. }
  303. #endif /* HAVE_CHOWN */
  304.  
  305. #ifdef HAVE_GETCWD
  306. static PyObject *
  307. amiga_getcwd(PyObject *self, PyObject *args)
  308. {
  309.     char buf[MAXPATHLEN];
  310.     char *res;
  311.     if (!PyArg_Parse(args,""))
  312.             return NULL;
  313.     Py_BEGIN_ALLOW_THREADS
  314.     res = getcwd(buf, sizeof buf);
  315.     Py_END_ALLOW_THREADS
  316.     if (res == NULL)
  317.             return amiga_error();
  318.     return PyString_FromString(buf);
  319. }
  320. #endif
  321.  
  322. #ifdef HAVE_LINK
  323. static PyObject *
  324. amiga_link(PyObject *self, PyObject *args)
  325. {
  326.     return amiga_2str(args, link);
  327. }
  328. #endif
  329.  
  330. static PyObject *
  331. amiga_listdir(PyObject *self, PyObject *args)
  332. {
  333.     BPTR dlok;
  334.     char *name;
  335.     struct FileInfoBlock __aligned fib;
  336.     PyObject *d;
  337.  
  338.     if (!PyArg_Parse(args, "s", &name)) return NULL;
  339.  
  340.     if ((d = PyList_New(0)) == NULL) return NULL;
  341.  
  342.     if(dlok=Lock(name,ACCESS_READ))
  343.     {
  344.         if(Examine(dlok,&fib))
  345.         {
  346.             while(ExNext(dlok,&fib))
  347.             {
  348.                 PyObject *v = PyString_FromString(fib.fib_FileName);
  349.                 if(v==NULL)
  350.                 {
  351.                     Py_DECREF(d); d=NULL; break;
  352.                 }
  353.  
  354.                 if(PyList_Append(d,v)!=0)
  355.                 {
  356.                     Py_DECREF(v); Py_DECREF(d); d=NULL; break;
  357.                 }
  358.                 Py_DECREF(v);
  359.             }
  360.         }
  361.         UnLock(dlok);
  362.     }
  363.  
  364.     if(IoErr()==ERROR_NO_MORE_ENTRIES) return d;
  365.  
  366.     Py_DECREF(d);
  367.     errno=__io2errno(_OSERR=IoErr());
  368.     return amiga_error();
  369. }
  370.  
  371. static PyObject *
  372. amiga_mkdir(PyObject *self, PyObject *args)
  373. {
  374.     int res;
  375.     char *path;
  376.     int mode = 0777;
  377.     if (!PyArg_ParseTuple(args, "s|i", &path, &mode)) return NULL;
  378.     Py_BEGIN_ALLOW_THREADS
  379. #ifdef INET225
  380.     res = mkdir(path, mode);
  381. #else
  382.     res = my_mkdir(path, mode);
  383. #endif
  384.     Py_END_ALLOW_THREADS
  385.     if (res < 0) return amiga_error_with_filename(path);
  386.     Py_INCREF(Py_None); return Py_None;
  387. }
  388.  
  389. static PyObject *
  390. amiga_rename(PyObject *self, PyObject *args)
  391. {
  392.     return amiga_2str(args, rename);
  393. }
  394.  
  395. static PyObject *
  396. amiga_rmdir(PyObject *self, PyObject *args)
  397. {
  398.     return amiga_1str(args, rmdir);
  399. }
  400.  
  401. static PyObject *
  402. amiga_stat(PyObject *self, PyObject *args)
  403. {
  404.     return amiga_do_stat(self, args, stat);
  405. }
  406.  
  407. #ifdef HAVE_SYSTEM
  408. static PyObject *
  409. amiga_system(PyObject *self, PyObject *args)
  410. {
  411.     char *command;
  412.     long sts;
  413.     if (!PyArg_Parse(args, "s", &command))
  414.         return NULL;
  415.     Py_BEGIN_ALLOW_THREADS
  416.     sts = system(command);
  417.     Py_END_ALLOW_THREADS
  418.     return PyInt_FromLong(sts);
  419. }
  420. #endif
  421.  
  422. #if defined(AMITCP) || defined(INET225)
  423. static PyObject *
  424. amiga_umask(PyObject *self, PyObject *args)
  425. {
  426.     int i;
  427. #ifdef AMITCP
  428.     if (!checkusergrouplib()) return NULL;
  429. #else
  430.     if (!checksocketlib()) return NULL;
  431. #endif
  432.     if (!PyArg_Parse(args,"i",&i))
  433.         return NULL;
  434.     i = umask(i);
  435.     if (i < 0)
  436.         return amiga_error();
  437.     return PyInt_FromLong((long)i);
  438. }
  439. #endif
  440.  
  441. #ifdef HAVE_UNAME
  442. static PyObject *
  443. amiga_uname(PyObject *self, PyObject *args)
  444. {
  445.         struct utsname u;
  446.         int res;
  447.         if (!PyArg_NoArgs(args))
  448.                 return NULL;
  449.         Py_BEGIN_ALLOW_THREADS
  450.         res = uname(&u);
  451.         Py_END_ALLOW_THREADS
  452.         if (res < 0)
  453.                 return amiga_error();
  454.         return Py_BuildValue("(sssss)",
  455.                              u.sysname,
  456.                              u.nodename,
  457.                              u.release,
  458.                              u.version,
  459.                              u.machine);
  460. }
  461. #endif
  462.  
  463. static PyObject *
  464. amiga_unlink(PyObject *self, PyObject *args)
  465. {
  466.     return amiga_1str(args, unlink);
  467. }
  468.  
  469. #if defined(AMITCP) || defined(INET225)
  470. static PyObject *
  471. amiga_utime(PyObject *self, PyObject *args)
  472. {
  473.     char *path;
  474.     long atime, mtime;
  475.     int res;
  476.  
  477. #ifdef HAVE_UTIME_H
  478.     struct utimbuf buf;
  479. #define ATIME buf.actime
  480. #define MTIME buf.modtime
  481. #define UTIME_ARG &buf
  482. #else /* HAVE_UTIME_H */
  483.     time_t buf[2];
  484. #define ATIME buf[0]
  485. #define MTIME buf[1]
  486. #define UTIME_ARG buf
  487. #endif /* HAVE_UTIME_H */
  488.  
  489.     if (!PyArg_Parse(args, "(s(ll))", &path, &atime, &mtime))
  490.         return NULL;
  491.     ATIME = atime;
  492.     MTIME = mtime;
  493.     Py_BEGIN_ALLOW_THREADS
  494.     res = utime(path, UTIME_ARG);
  495.     Py_END_ALLOW_THREADS
  496.     if (res < 0)
  497.         return amiga_error_with_filename(path);
  498.     Py_INCREF(Py_None);
  499.     return Py_None;
  500. #undef UTIME_ARG
  501. #undef ATIME
  502. #undef MTIME
  503. }
  504. #endif
  505.  
  506.  
  507. /* Process operations */
  508.  
  509. /* XXX Removed _exit. You are VERY STUPID if you used this. (2-apr-96) */
  510.  
  511. /* XXX Removed execv. You must use system/exit combination instead. */
  512. /*     Maybe one day I'll implement a REAL execv ?? */
  513.  
  514.  
  515.  
  516. #ifdef HAVE_GETEGID
  517. static PyObject *
  518. amiga_getegid(PyObject *self, PyObject *args)
  519. {
  520. #ifdef AMITCP
  521.     if (!checkusergrouplib()) return NULL;
  522. #else
  523.     if (!checksocketlib()) return NULL;
  524. #endif
  525.     if (!PyArg_Parse(args,""))
  526.         return NULL;
  527.     return PyInt_FromLong((long)getegid());
  528. }
  529. #endif
  530.  
  531. #ifdef HAVE_GETEUID
  532. static PyObject *
  533. amiga_geteuid(PyObject *self, PyObject *args)
  534. {
  535. #ifdef AMITCP
  536.     if (!checkusergrouplib()) return NULL;
  537. #else
  538.     if (!checksocketlib()) return NULL;
  539. #endif
  540.     if (!PyArg_Parse(args,""))
  541.         return NULL;
  542.     return PyInt_FromLong((long)geteuid());
  543. }
  544. #endif
  545.  
  546. #ifdef HAVE_GETGID
  547. static PyObject *
  548. amiga_getgid(PyObject *self, PyObject *args)
  549. {
  550. #ifdef AMITCP
  551.     if (!checkusergrouplib()) return NULL;
  552. #else
  553.     if (!checksocketlib()) return NULL;
  554. #endif
  555.     if (!PyArg_Parse(args,""))
  556.         return NULL;
  557.     return PyInt_FromLong((long)getgid());
  558. }
  559. #endif
  560.  
  561. static PyObject *
  562. amiga_getpid(PyObject *self, PyObject *args)
  563. {
  564.     if (!PyArg_Parse(args,""))
  565.         return NULL;
  566.     return PyInt_FromLong((long)FindTask(0));
  567. }
  568.  
  569. #ifdef HAVE_GETPGRP
  570. static PyObject *
  571. amiga_getpgrp(PyObject *self, PyObject *args)
  572. {
  573. #ifdef AMITCP
  574.     if (!checkusergrouplib()) return NULL;
  575. #else
  576.     if (!checksocketlib()) return NULL;
  577. #endif
  578.     if (!PyArg_Parse(args,""))
  579.         return NULL;
  580. #ifdef GETPGRP_HAVE_ARG
  581.     return PyInt_FromLong((long)getpgrp(0));
  582. #else /* GETPGRP_HAVE_ARG */
  583.     return PyInt_FromLong((long)getpgrp());
  584. #endif /* GETPGRP_HAVE_ARG */
  585. }
  586. #endif /* HAVE_GETPGRP */
  587.  
  588. #ifdef HAVE_SETPGRP
  589. static PyObject *
  590. amiga_setpgrp(PyObject *self, PyObject *args)
  591. {
  592. #ifdef AMITCP
  593.     if (!checkusergrouplib()) return NULL;
  594. #else
  595.     if (!checksocketlib()) return NULL;
  596. #endif
  597.     if (!PyArg_Parse(args,""))
  598.         return NULL;
  599. #ifdef SETPGRP_HAVE_ARG
  600.     if (setpgrp(0, 0) < 0)
  601. #else /* SETPGRP_HAVE_ARG */
  602.     if (setpgrp() < 0)
  603. #endif /* SETPGRP_HAVE_ARG */
  604.         return amiga_error();
  605.     Py_INCREF(Py_None);
  606.     return Py_None;
  607. }
  608.  
  609. #endif /* HAVE_SETPGRP */
  610.  
  611. #ifdef HAVE_GETPPID
  612. static PyObject *
  613. amiga_getppid(PyObject *self, PyObject *args)
  614. {
  615.     if (!PyArg_Parse(args,""))
  616.         return NULL;
  617.     return PyInt_FromLong((long)getppid());
  618. }
  619. #endif
  620.  
  621. #ifdef HAVE_GETUID
  622. static PyObject *
  623. amiga_getuid(PyObject *self, PyObject *args)
  624. {
  625. #ifdef AMITCP
  626.     if (!checkusergrouplib()) return NULL;
  627. #else
  628.     if (!checksocketlib()) return NULL;
  629. #endif
  630.     if (!PyArg_Parse(args,""))
  631.         return NULL;
  632.     return PyInt_FromLong((long)getuid());
  633. }
  634. #endif
  635.  
  636. #ifdef HAVE_POPEN
  637. static PyObject *
  638. amiga_popen(PyObject *self, PyObject *args)
  639. {
  640.     char *name;
  641.     char *mode = "r";
  642.     int bufsize = -1;
  643.     FILE *fp;
  644.     PyObject *f;
  645.     if (!PyArg_ParseTuple(args, "s|si", &name, &mode, &bufsize))
  646.         return NULL;
  647.     Py_BEGIN_ALLOW_THREADS
  648.     fp = popen(name, mode);
  649.     Py_END_ALLOW_THREADS
  650.     if (fp == NULL)
  651.         return amiga_error();
  652.     f = PyFile_FromFile(fp, name, mode, pclose);
  653.     if (f != NULL)
  654.         PyFile_SetBufSize(f, bufsize);
  655.     return f;
  656. }
  657. #endif
  658.  
  659. #ifdef HAVE_SETUID
  660. static PyObject *
  661. amiga_setuid(PyObject *self, PyObject *args)
  662. {
  663.     int uid;
  664. #ifdef AMITCP
  665.     if (!checkusergrouplib()) return NULL;
  666. #else
  667.     if (!checksocketlib()) return NULL;
  668. #endif
  669.     if (!PyArg_Parse(args, "i", &uid))
  670.         return NULL;
  671.     if (setuid(uid) < 0)
  672.         return amiga_error();
  673.     Py_INCREF(Py_None);
  674.     return Py_None;
  675. }
  676. #endif /* HAVE_SETUID */
  677.  
  678. #ifdef HAVE_SETGID
  679. static PyObject *
  680. amiga_setgid(PyObject *self, PyObject *args)
  681. {
  682.     int gid;
  683. #ifdef AMITCP
  684.     if (!checkusergrouplib()) return NULL;
  685. #else
  686.     if (!checksocketlib()) return NULL;
  687. #endif
  688.     if (!PyArg_Parse(args, "i", &gid))
  689.         return NULL;
  690.     if (setgid(gid) < 0)
  691.         return amiga_error();
  692.     Py_INCREF(Py_None);
  693.     return Py_None;
  694. }
  695. #endif /* HAVE_SETGID */
  696.  
  697. static PyObject *
  698. amiga_lstat(PyObject *self, PyObject *args)
  699. {
  700. #ifdef HAVE_LSTAT
  701.     return amiga_do_stat(self, args, lstat);
  702. #else /* !HAVE_LSTAT */
  703.     return amiga_do_stat(self, args, stat);
  704. #endif /* !HAVE_LSTAT */
  705. }
  706.  
  707. #ifdef HAVE_READLINK
  708. static PyObject *
  709. amiga_readlink(PyObject *self, PyObject *args)
  710. {
  711.     char buf[MAXPATHLEN];
  712.     char *path;
  713.     int n;
  714.     if (!PyArg_Parse(args, "s", &path))
  715.             return NULL;
  716.     Py_BEGIN_ALLOW_THREADS
  717.     n = readlink(path, buf, (int) sizeof buf);
  718.     Py_END_ALLOW_THREADS
  719.     if (n < 0)
  720.             return amiga_error_with_filename(path);
  721.     return PyString_FromStringAndSize(buf, n);
  722. }
  723. #endif
  724.  
  725. #ifdef HAVE_SYMLINK
  726. static PyObject *
  727. amiga_symlink(PyObject *self, PyObject *args)
  728. {
  729.     return amiga_2str(args, symlink);
  730. }
  731. #endif
  732.  
  733. #ifdef HAVE_SETSID
  734. static PyObject *
  735. amiga_setsid(PyObject *self, PyObject *args)
  736. {
  737. #ifdef AMITCP
  738.     if (!checkusergrouplib()) return NULL;
  739. #else
  740.     if (!checksocketlib()) return NULL;
  741. #endif
  742.     if (!PyArg_Parse(args,""))
  743.         return NULL;
  744.     if ((int)setsid() < 0)
  745.         return amiga_error();
  746.     Py_INCREF(Py_None);
  747.     return Py_None;
  748. }
  749. #endif /* HAVE_SETSID */
  750.  
  751. #ifdef HAVE_SETPGID
  752. static PyObject *
  753. amiga_setpgid(PyObject *self, PyObject *args)
  754. {
  755.     int pid, pgrp;
  756.     if (!PyArg_Parse(args, "(ii)", &pid, &pgrp))
  757.         return NULL;
  758.     if (setpgid(pid, pgrp) < 0)
  759.         return amiga_error();
  760.     Py_INCREF(Py_None);
  761.     return Py_None;
  762. }
  763. #endif /* HAVE_SETPGID */
  764.  
  765. /* Functions acting on file descriptors */
  766.  
  767. static PyObject *
  768. amiga_open(PyObject *self, PyObject *args)
  769. {
  770.     char *file;
  771.     int flag;
  772.     int mode = 0777;
  773.     int fd;
  774.     if (!PyArg_Parse(args, "(si)", &file, &flag)) {
  775.         PyErr_Clear();
  776.         if (!PyArg_Parse(args, "(sii)", &file, &flag, &mode))
  777.             return NULL;
  778.     }
  779.     Py_BEGIN_ALLOW_THREADS
  780.     fd = open(file, flag, mode);
  781.     Py_END_ALLOW_THREADS
  782.     if (fd < 0)
  783.         return amiga_error_with_filename(file);
  784.     return PyInt_FromLong((long)fd);
  785. }
  786.  
  787. static PyObject *
  788. amiga_close(PyObject *self, PyObject *args)
  789. {
  790.     int fd, res;
  791.     if (!PyArg_Parse(args, "i", &fd))
  792.         return NULL;
  793.     Py_BEGIN_ALLOW_THREADS
  794.     res = close(fd);
  795.     Py_END_ALLOW_THREADS
  796.     if (res < 0)
  797.         return amiga_error();
  798.     Py_INCREF(Py_None);
  799.     return Py_None;
  800. }
  801.  
  802. #if defined(AMITCP) || defined(INET225)
  803. static PyObject *
  804. amiga_dup(PyObject *self, PyObject *args)
  805. {
  806.     int fd;
  807.     if (!checksocketlib()) { PyErr_Clear(); errno=EIO; return amiga_error(); }
  808.     if (!PyArg_Parse(args, "i", &fd))
  809.         return NULL;
  810.     Py_BEGIN_ALLOW_THREADS
  811.     fd = dup(fd);
  812.     Py_END_ALLOW_THREADS
  813.     if (fd < 0)
  814.         return amiga_error();
  815.     return PyInt_FromLong((long)fd);
  816. }
  817.  
  818. static PyObject *
  819. amiga_dup2(PyObject *self, PyObject *args)
  820. {
  821.     int fd, fd2, res;
  822.     if (!checksocketlib()) { PyErr_Clear(); errno=EIO; return amiga_error(); }
  823.     if (!PyArg_Parse(args, "(ii)", &fd, &fd2))
  824.         return NULL;
  825.     Py_BEGIN_ALLOW_THREADS
  826.     res = dup2(fd, fd2);
  827.     Py_END_ALLOW_THREADS
  828.     if (res < 0)
  829.         return amiga_error();
  830.     Py_INCREF(Py_None);
  831.     return Py_None;
  832. }
  833. #endif
  834.  
  835. static PyObject *
  836. amiga_lseek(PyObject *self, PyObject *args)
  837. {
  838.     int fd, how;
  839.     long pos, res;
  840.     if (!PyArg_Parse(args, "(ili)", &fd, &pos, &how))
  841.         return NULL;
  842. #ifdef SEEK_SET
  843.     /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
  844.     switch (how) {
  845.     case 0: how = SEEK_SET; break;
  846.     case 1: how = SEEK_CUR; break;
  847.     case 2: how = SEEK_END; break;
  848.     }
  849. #endif /* SEEK_END */
  850.     Py_BEGIN_ALLOW_THREADS
  851.     res = lseek(fd, pos, how);
  852.     Py_END_ALLOW_THREADS
  853.     if (res < 0)
  854.         return amiga_error();
  855.     return PyInt_FromLong(res);
  856. }
  857.  
  858. static PyObject *
  859. amiga_read(PyObject *self, PyObject *args)
  860. {
  861.     int fd, size;
  862.     PyObject *buffer;
  863.     if (!PyArg_Parse(args, "(ii)", &fd, &size))
  864.         return NULL;
  865.     buffer = PyString_FromStringAndSize((char *)NULL, size);
  866.     if (buffer == NULL)
  867.         return NULL;
  868.     Py_BEGIN_ALLOW_THREADS
  869.     size = read(fd, PyString_AsString(buffer), size);
  870.     Py_END_ALLOW_THREADS
  871.     if (size < 0) {
  872.         Py_DECREF(buffer);
  873.         return amiga_error();
  874.     }
  875.     _PyString_Resize(&buffer, size);
  876.     return buffer;
  877. }
  878.  
  879. static PyObject *
  880. amiga_write(PyObject *self, PyObject *args)
  881. {
  882.     int fd, size;
  883.     char *buffer;
  884.     if (!PyArg_Parse(args, "(is#)", &fd, &buffer, &size))
  885.         return NULL;
  886.     Py_BEGIN_ALLOW_THREADS
  887.     size = write(fd, buffer, size);
  888.     Py_END_ALLOW_THREADS
  889.     if (size < 0)
  890.         return amiga_error();
  891.     return PyInt_FromLong((long)size);
  892. }
  893.  
  894. static PyObject *
  895. amiga_fstat(PyObject *self, PyObject *args)
  896. {
  897.     int fd;
  898.     struct stat st;
  899.     int res;
  900.     if (!PyArg_Parse(args, "i", &fd))
  901.         return NULL;
  902.     Py_BEGIN_ALLOW_THREADS
  903.     res = fstat(fd, &st);
  904.     Py_END_ALLOW_THREADS
  905.     if (res != 0)
  906.         return amiga_error();
  907.     return Py_BuildValue("(llllllllll)",
  908.             (long)st.st_mode,
  909.             (long)st.st_ino,
  910.             (long)st.st_dev,
  911.             (long)st.st_nlink,
  912.             (long)st.st_uid,
  913.             (long)st.st_gid,
  914.             (long)st.st_size,
  915.             (long)st.st_atime,
  916.             (long)st.st_mtime,
  917.             (long)st.st_ctime);
  918. }
  919.  
  920. static PyObject *
  921. amiga_fdopen(PyObject *self, PyObject *args)
  922. {
  923.     int fd;
  924.     char *mode = "r";
  925.     int bufsize = -1;
  926.     FILE *fp;
  927.     PyObject *f;
  928.     if (!PyArg_ParseTuple(args, "i|si", &fd, &mode, &bufsize))
  929.         return NULL;
  930.     Py_BEGIN_ALLOW_THREADS
  931.     fp = fdopen(fd, mode);
  932.     Py_END_ALLOW_THREADS
  933.     if (fp == NULL)
  934.         return amiga_error();
  935.     f = PyFile_FromFile(fp, "(fdopen)", mode, fclose);
  936.     if (f != NULL)
  937.         PyFile_SetBufSize(f, bufsize);
  938.     return f;
  939. }
  940.  
  941. #if 0
  942. /*** XXX pipe() is useless without fork() or threads ***/
  943. /***     TODO: guess what.. implement threads! ***/
  944. static int pipe(int *fildes)
  945. {
  946.     /* 0=ok, -1=err, errno=EMFILE,ENFILE,EFAULT */
  947.     char buf[50];
  948.     static int num = 1;
  949.     
  950.     sprintf(buf,"PIPE:Py%ld_%ld",FindTask(0),num++);
  951.     fildes[0]=open(buf,O_RDONLY,0);
  952.     if(fildes[0]>0)
  953.     {
  954.         fildes[1]=open(buf,O_WRONLY|O_CREAT,FIBF_OTR_READ|FIBF_OTR_WRITE);
  955.         if(fildes[1]>0)
  956.         {
  957.             return 0;
  958.         }
  959.         close(fildes[0]);
  960.     }
  961.     return -1;
  962. }
  963.  
  964. static PyObject *
  965. amiga_pipe(PyObject *self, PyObject *args)
  966. {
  967.     int fds[2];
  968.     int res;
  969.     if (!PyArg_Parse(args, ""))
  970.         return NULL;
  971.     Py_BEGIN_ALLOW_THREADS
  972.     res = pipe(fds);
  973.     Py_END_ALLOW_THREADS
  974.     if (res != 0)
  975.         return amiga_error();
  976.     return Py_BuildValue("(ii)", fds[0], fds[1]);
  977. }
  978. #endif
  979.  
  980.  
  981. static PyObject *
  982. amiga_fullpath(PyObject *self, PyObject *args)
  983. {
  984.     BOOL ok=FALSE;
  985.     BPTR lk;
  986.     char *path;
  987.     char buf[MAXPATHLEN];
  988.  
  989.     if (!PyArg_ParseTuple(args, "s", &path)) return NULL;
  990.  
  991.     Py_BEGIN_ALLOW_THREADS
  992.     if(lk=Lock(path,SHARED_LOCK))
  993.     {
  994.         ok=NameFromLock(lk,buf,sizeof(buf));
  995.         UnLock(lk);
  996.     }
  997.     Py_END_ALLOW_THREADS
  998.  
  999.     if(!ok)
  1000.     {
  1001.         errno=__io2errno(_OSERR=IoErr());
  1002.         return amiga_error();
  1003.     }
  1004.     else return PyString_FromString(buf);
  1005. }
  1006.  
  1007. static PyObject *amiga_putenv(PyObject *self, PyObject *args)
  1008. {
  1009.     char *s1, *s2;
  1010.  
  1011.     if (!PyArg_ParseTuple(args, "ss", &s1, &s2)) return NULL;
  1012.     if(setenv(s1,s2,1))
  1013.     {
  1014.         amiga_error(); return NULL;
  1015.     }
  1016.     
  1017.     Py_INCREF(Py_None); return Py_None;
  1018. }
  1019.  
  1020. #ifdef HAVE_STRERROR
  1021. static char posix_strerror__doc__[] =
  1022. "strerror(code) -> string\n\
  1023. Translate an error code to a message string.";
  1024.  
  1025. PyObject *
  1026. amiga_strerror(PyObject *self, PyObject *args)
  1027. {
  1028.     int code;
  1029.     char *message;
  1030.     if (!PyArg_ParseTuple(args, "i", &code))
  1031.         return NULL;
  1032.     message = strerror(code);
  1033.     if (message == NULL) {
  1034.         PyErr_SetString(PyExc_ValueError,
  1035.                 "strerror code out of range");
  1036.         return NULL;
  1037.     }
  1038.     return PyString_FromString(message);
  1039. }
  1040. #endif /* strerror */
  1041.  
  1042. // external function prototype:
  1043. unsigned long __asm CalcCRC32(register __d0 ULONG startcrc, register __a0 const void *data, register __d1 unsigned long size);
  1044.  
  1045. PyObject *
  1046. amiga_crc32(PyObject *self, PyObject *args)
  1047. {
  1048.     PyObject *py_str;
  1049.     int startcrc = 0;
  1050.     if(!PyArg_ParseTuple(args,"S|i",&py_str,&startcrc)) return NULL;
  1051.     return PyInt_FromLong(CalcCRC32(startcrc,PyString_AsString(py_str), PyString_Size(py_str)));
  1052. }
  1053.  
  1054.  
  1055. static struct PyMethodDef amiga_methods[] = {
  1056.     {"chdir",   amiga_chdir},
  1057.     {"chmod",   amiga_chmod},
  1058. #ifdef HAVE_CHOWN
  1059.     {"chown",   amiga_chown},
  1060. #endif
  1061. #ifdef HAVE_GETCWD
  1062.     {"getcwd",  amiga_getcwd},
  1063. #endif
  1064.     {"fullpath", amiga_fullpath,1},
  1065. #ifdef HAVE_LINK
  1066.     {"link",    amiga_link},
  1067. #endif
  1068.     {"listdir", amiga_listdir},
  1069.     {"lstat",   amiga_lstat},
  1070.     {"mkdir",   amiga_mkdir , 1},
  1071. #ifdef HAVE_READLINK
  1072.     {"readlink",    amiga_readlink},
  1073. #endif
  1074.     {"rename",  amiga_rename},
  1075.     {"rmdir",   amiga_rmdir},
  1076.     {"stat",    amiga_stat},
  1077. #ifdef HAVE_SYMLINK
  1078.     {"symlink", amiga_symlink},
  1079. #endif
  1080. #ifdef HAVE_SYSTEM
  1081.     {"system",  amiga_system},
  1082. #endif
  1083. #if defined(AMITCP) || defined(INET225)
  1084.     {"umask",   amiga_umask},
  1085. #endif
  1086. #ifdef HAVE_UNAME
  1087.     {"uname",   amiga_uname},
  1088. #endif
  1089.     {"unlink",  amiga_unlink},
  1090.     {"remove",  amiga_unlink},
  1091. #if defined(AMITCP) || defined(INET225)
  1092.     {"utime",   amiga_utime},
  1093. #endif
  1094. #ifdef HAVE_TIMES
  1095.     {"times",   amiga_times},
  1096. #endif
  1097. #ifdef HAVE_EXECV
  1098.     {"execv",    amiga_execv},
  1099.     {"execve",    amiga_execve},
  1100. #endif /* HAVE_EXECV */
  1101. #ifdef HAVE_GETEGID
  1102.     {"getegid", amiga_getegid},
  1103. #endif
  1104. #ifdef HAVE_GETEUID
  1105.     {"geteuid", amiga_geteuid},
  1106. #endif
  1107. #ifdef HAVE_GETGID
  1108.     {"getgid",  amiga_getgid},
  1109. #endif
  1110.     {"getpid",  amiga_getpid},
  1111. #ifdef HAVE_GETPGRP
  1112.     {"getpgrp", amiga_getpgrp},
  1113. #endif
  1114. #ifdef HAVE_GETPPID
  1115.     {"getppid", amiga_getppid},
  1116. #endif
  1117. #ifdef HAVE_GETUID
  1118.     {"getuid",  amiga_getuid},
  1119. #endif
  1120. #ifdef HAVE_POPEN
  1121.     {"popen",   amiga_popen,    1},
  1122. #endif
  1123. #ifdef HAVE_SETUID
  1124.     {"setuid",  amiga_setuid},
  1125. #endif
  1126. #ifdef HAVE_SETGID
  1127.     {"setgid",  amiga_setgid},
  1128. #endif
  1129. #ifdef HAVE_SETPGRP
  1130.     {"setpgrp", amiga_setpgrp},
  1131. #endif
  1132. #ifdef HAVE_SETSID
  1133.     {"setsid",  amiga_setsid},
  1134. #endif
  1135. #ifdef HAVE_SETPGID
  1136.     {"setpgid", amiga_setpgid},
  1137. #endif
  1138. #ifdef HAVE_TCGETPGRP
  1139.     {"tcgetpgrp",   amiga_tcgetpgrp},
  1140. #endif
  1141. #ifdef HAVE_TCSETPGRP
  1142.     {"tcsetpgrp",   amiga_tcsetpgrp},
  1143. #endif
  1144.     {"open",    amiga_open},
  1145.     {"close",   amiga_close},
  1146. #if defined(AMITCP) || defined(INET225)
  1147.     {"dup",     amiga_dup},
  1148.     {"dup2",    amiga_dup2},
  1149. #endif
  1150.     {"lseek",   amiga_lseek},
  1151.     {"read",    amiga_read},
  1152.     {"write",   amiga_write},
  1153.     {"fstat",   amiga_fstat},
  1154.     {"fdopen",  amiga_fdopen,   1},
  1155. #ifdef HAVE_MKFIFO
  1156.     {"mkfifo",    amiga_mkfifo, 1},
  1157. #endif
  1158. #ifdef HAVE_FTRUNCATE
  1159.     {"ftruncate",    amiga_ftruncate, 1},
  1160. #endif
  1161. #ifdef HAVE_PUTENV
  1162.     {"putenv", amiga_putenv, 1},
  1163. #endif
  1164. #ifdef HAVE_STRERROR
  1165.     {"strerror",    amiga_strerror, 1},
  1166. #endif
  1167. #if 0
  1168.     /* XXX TODO: implement threads. Otherwise pipe() is useless. */
  1169.     {"pipe",    amiga_pipe},
  1170. #endif
  1171.     {"crc32",    amiga_crc32, 1},
  1172.     {NULL,      NULL}        /* Sentinel */
  1173. };
  1174.  
  1175.  
  1176. static int
  1177. ins(PyObject *d, char *symbol, long value)
  1178. {
  1179.         PyObject* v = PyInt_FromLong(value);
  1180.         if (!v || PyDict_SetItemString(d, symbol, v) < 0)
  1181.                 return -1;                   /* triggers fatal error */
  1182.  
  1183.         Py_DECREF(v);
  1184.         return 0;
  1185. }
  1186.  
  1187. static int all_ins(PyObject *d)
  1188. {
  1189. #ifdef WNOHANG
  1190.         if (ins(d, "WNOHANG", (long)WNOHANG)) return -1;
  1191. #endif        
  1192. #ifdef O_RDONLY
  1193.         if (ins(d, "O_RDONLY", (long)O_RDONLY)) return -1;
  1194. #endif
  1195. #ifdef O_WRONLY
  1196.         if (ins(d, "O_WRONLY", (long)O_WRONLY)) return -1;
  1197. #endif
  1198. #ifdef O_RDWR
  1199.         if (ins(d, "O_RDWR", (long)O_RDWR)) return -1;
  1200. #endif
  1201. #ifdef O_NDELAY
  1202.         if (ins(d, "O_NDELAY", (long)O_NDELAY)) return -1;
  1203. #endif
  1204. #ifdef O_NONBLOCK
  1205.         if (ins(d, "O_NONBLOCK", (long)O_NONBLOCK)) return -1;
  1206. #endif
  1207. #ifdef O_APPEND
  1208.         if (ins(d, "O_APPEND", (long)O_APPEND)) return -1;
  1209. #endif
  1210. #ifdef O_DSYNC
  1211.         if (ins(d, "O_DSYNC", (long)O_DSYNC)) return -1;
  1212. #endif
  1213. #ifdef O_RSYNC
  1214.         if (ins(d, "O_RSYNC", (long)O_RSYNC)) return -1;
  1215. #endif
  1216. #ifdef O_SYNC
  1217.         if (ins(d, "O_SYNC", (long)O_SYNC)) return -1;
  1218. #endif
  1219. #ifdef O_NOCTTY
  1220.         if (ins(d, "O_NOCTTY", (long)O_NOCTTY)) return -1;
  1221. #endif
  1222. #ifdef O_CREAT
  1223.         if (ins(d, "O_CREAT", (long)O_CREAT)) return -1;
  1224. #endif
  1225. #ifdef O_EXCL
  1226.         if (ins(d, "O_EXCL", (long)O_EXCL)) return -1;
  1227. #endif
  1228. #ifdef O_TRUNC
  1229.         if (ins(d, "O_TRUNC", (long)O_TRUNC)) return -1;
  1230. #endif
  1231. #ifdef O_BINARY
  1232.         if (ins(d, "O_BINARY", (long)O_BINARY)) return -1;
  1233. #endif
  1234. #ifdef O_TEXT
  1235.         if (ins(d, "O_TEXT", (long)O_TEXT)) return -1;
  1236. #endif
  1237.  
  1238. #if defined(PYOS_OS2)
  1239.         if (insertvalues(d)) return -1;
  1240. #endif
  1241.         return 0;
  1242. }
  1243.  
  1244. void
  1245. initamiga(void)
  1246. {
  1247.     PyObject *m, *d, *globv, *locv, *bothv, *aliases;
  1248.  
  1249.     m = Py_InitModule("amiga", amiga_methods);
  1250.     d = PyModule_GetDict(m);
  1251.     
  1252.     /* Initialize amiga.environ dictionary */
  1253.     if(!convertenviron(&globv, &locv, &bothv, &aliases))
  1254.         Py_FatalError("can't read environment");
  1255.  
  1256.     if (PyDict_SetItemString(d, "environ", bothv) != 0)
  1257.         Py_FatalError("can't define amiga.environ");
  1258.     Py_DECREF(bothv);
  1259.     if (PyDict_SetItemString(d, "globalvars", globv) != 0)
  1260.         Py_FatalError("can't define amiga.globalvars");
  1261.     Py_DECREF(globv);
  1262.     if (PyDict_SetItemString(d, "shellvars", locv) != 0)
  1263.         Py_FatalError("can't define amiga.shellvars");
  1264.     Py_DECREF(locv);
  1265.     if (PyDict_SetItemString(d, "shellaliases", aliases ) != 0)
  1266.         Py_FatalError("can't define amiga.shellaliases");
  1267.     Py_DECREF(aliases);
  1268.  
  1269.     if(all_ins(d)) return;
  1270.  
  1271.     /* Initialize exception */
  1272.     PyDict_SetItemString(d, "error", PyExc_OSError);
  1273. }
  1274.